1 /* cf-bind.c: bind and unbind a cache from the filesystem backing it
3 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include <linux/completion.h>
16 #include <linux/slab.h>
18 #include <linux/file.h>
19 #include <linux/namei.h>
20 #include <linux/mount.h>
21 #include <linux/namespace.h>
22 #include <linux/statfs.h>
23 #include <linux/proc_fs.h>
24 #include <linux/ctype.h>
27 static int cachefiles_proc_add_cache(struct cachefiles_cache *cache,
28 struct vfsmount *mnt);
30 /*****************************************************************************/
32 * bind a directory as a cache
34 int cachefiles_proc_bind(struct cachefiles_cache *cache, char *args)
36 _enter("{%u,%u,%u},%s",
42 /* start by checking things over */
43 ASSERT(cache->bstop_percent >= 0 &&
44 cache->bstop_percent < cache->bcull_percent &&
45 cache->bcull_percent < cache->brun_percent &&
46 cache->brun_percent < 100);
49 kerror("'bind' command doesn't take an argument");
53 if (!cache->rootdirname) {
54 kerror("No cache directory specified");
58 /* don't permit already bound caches to be re-bound */
59 if (test_bit(CACHEFILES_READY, &cache->flags)) {
60 kerror("Cache already bound");
64 /* make sure we have copies of the tag and dirname strings */
66 /* the tag string is released by the fops->release()
67 * function, so we don't release it on error here */
68 cache->tag = kstrdup("CacheFiles", GFP_KERNEL);
74 return cachefiles_proc_add_cache(cache, NULL);
77 /*****************************************************************************/
81 static int cachefiles_proc_add_cache(struct cachefiles_cache *cache,
84 struct cachefiles_object *fsdef;
87 struct dentry *graveyard, *cachedir, *root;
92 /* allocate the root index object */
95 fsdef = kmem_cache_alloc(cachefiles_object_jar, SLAB_KERNEL);
97 goto error_root_object;
99 atomic_set(&fsdef->usage, 1);
100 atomic_set(&fsdef->fscache_usage, 1);
101 fsdef->type = FSCACHE_COOKIE_TYPE_INDEX;
103 _debug("- fsdef %p", fsdef);
105 /* look up the directory at the root of the cache */
106 memset(&nd, 0, sizeof(nd));
108 ret = path_lookup(cache->rootdirname, LOOKUP_DIRECTORY, &nd);
110 goto error_open_root;
112 /* bind to the special mountpoint we've prepared */
114 atomic_inc(&nd.mnt->mnt_sb->s_active);
115 mnt->mnt_sb = nd.mnt->mnt_sb;
116 mnt->mnt_flags = nd.mnt->mnt_flags;
117 mnt->mnt_flags |= MNT_NOSUID | MNT_NOEXEC | MNT_NODEV;
118 mnt->mnt_root = dget(nd.dentry);
119 mnt->mnt_mountpoint = mnt->mnt_root;
121 /* copy the name, but ignore kstrdup() failing ENOMEM - we'll
122 * just end up with an devicenameless mountpoint */
123 mnt->mnt_devname = kstrdup(nd.mnt->mnt_devname, GFP_KERNEL);
126 cache->mnt = mntget(mnt);
127 root = dget(mnt->mnt_root);
137 /* check parameters */
139 if (!root->d_inode ||
140 !root->d_inode->i_op ||
141 !root->d_inode->i_op->lookup ||
142 !root->d_inode->i_op->mkdir ||
143 !root->d_inode->i_op->setxattr ||
144 !root->d_inode->i_op->getxattr ||
147 !root->d_sb->s_op->statfs ||
148 !root->d_sb->s_op->sync_fs)
149 goto error_unsupported;
152 if (root->d_sb->s_flags & MS_RDONLY)
153 goto error_unsupported;
155 /* get the cache size and blocksize */
156 ret = root->d_sb->s_op->statfs(root, &stats);
158 goto error_unsupported;
161 if (stats.f_bsize <= 0)
162 goto error_unsupported;
165 if (stats.f_bsize > PAGE_SIZE)
166 goto error_unsupported;
168 cache->bsize = stats.f_bsize;
170 if (stats.f_bsize < PAGE_SIZE)
171 cache->bshift = PAGE_SHIFT - long_log2(stats.f_bsize);
173 _debug("blksize %u (shift %u)",
174 cache->bsize, cache->bshift);
176 _debug("size %llu, avail %llu", stats.f_blocks, stats.f_bavail);
178 /* set up caching limits */
179 stats.f_blocks >>= cache->bshift;
180 do_div(stats.f_blocks, 100);
181 cache->bstop = stats.f_blocks * cache->bstop_percent;
182 cache->bcull = stats.f_blocks * cache->bcull_percent;
183 cache->brun = stats.f_blocks * cache->brun_percent;
185 _debug("limits {%llu,%llu,%llu}",
190 /* get the cache directory and check its type */
191 cachedir = cachefiles_get_directory(cache, root, "cache");
192 if (IS_ERR(cachedir)) {
193 ret = PTR_ERR(cachedir);
194 goto error_unsupported;
197 fsdef->dentry = cachedir;
199 ret = cachefiles_check_object_type(fsdef);
201 goto error_unsupported;
203 /* get the graveyard directory */
204 graveyard = cachefiles_get_directory(cache, root, "graveyard");
205 if (IS_ERR(graveyard)) {
206 ret = PTR_ERR(graveyard);
207 goto error_unsupported;
210 cache->graveyard = graveyard;
212 /* publish the cache */
213 fscache_init_cache(&cache->cache,
214 &cachefiles_cache_ops,
216 MAJOR(fsdef->dentry->d_sb->s_dev),
217 MINOR(fsdef->dentry->d_sb->s_dev)
220 ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag);
222 goto error_add_cache;
225 set_bit(CACHEFILES_READY, &cache->flags);
228 printk(KERN_INFO "CacheFiles:"
229 " File cache on %s registered\n",
230 cache->cache.identifier);
232 /* check how much space the cache has */
233 cachefiles_has_space(cache, 0);
238 dput(cache->graveyard);
239 cache->graveyard = NULL;
244 fsdef->dentry = NULL;
247 kmem_cache_free(cachefiles_object_jar, fsdef);
249 kerror("Failed to register: %d", ret);
253 /*****************************************************************************/
255 * unbind a cache on fd release
257 void cachefiles_proc_unbind(struct cachefiles_cache *cache)
261 if (test_bit(CACHEFILES_READY, &cache->flags)) {
262 printk(KERN_INFO "CacheFiles:"
263 " File cache on %s unregistering\n",
264 cache->cache.identifier);
266 fscache_withdraw_cache(&cache->cache);
269 if (cache->cache.fsdef)
270 cache->cache.ops->put_object(cache->cache.fsdef);
272 dput(cache->graveyard);
275 kfree(cache->rootdirname);