/* * find out whether an object in the current working directory is in use or not * - command: "inuse <name>" */ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) { struct fs_struct *fs; struct dentry *dir; const struct cred *saved_cred; int ret; //_enter(",%s", args); if (strchr(args, '/')) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { kerror("inuse applied to unready cache"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { kerror("inuse applied to dead cache"); return -EIO; } /* extract the directory dentry from the cwd */ fs = current->fs; read_lock(&fs->lock); dir = dget(fs->pwd.dentry); read_unlock(&fs->lock); if (!S_ISDIR(dir->d_inode->i_mode)) goto notdir; cachefiles_begin_secure(cache, &saved_cred); ret = cachefiles_check_in_use(cache, dir, args); cachefiles_end_secure(cache, saved_cred); dput(dir); //_leave(" = %d", ret); return ret; notdir: dput(dir); kerror("inuse command requires dirfd to be a directory"); return -ENOTDIR; inval: kerror("inuse command requires dirfd and filename"); return -EINVAL; }
/* * find out whether an object in the current working directory is in use or not * - command: "inuse <name>" */ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) { struct path path; const struct cred *saved_cred; int ret; //_enter(",%s", args); if (strchr(args, '/')) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { kerror("inuse applied to unready cache"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { kerror("inuse applied to dead cache"); return -EIO; } /* extract the directory dentry from the cwd */ get_fs_pwd(current->fs, &path); if (!S_ISDIR(path.dentry->d_inode->i_mode)) goto notdir; cachefiles_begin_secure(cache, &saved_cred); ret = cachefiles_check_in_use(cache, path.dentry, args); cachefiles_end_secure(cache, saved_cred); path_put(&path); //_leave(" = %d", ret); return ret; notdir: path_put(&path); kerror("inuse command requires dirfd to be a directory"); return -ENOTDIR; inval: kerror("inuse command requires dirfd and filename"); return -EINVAL; }
/* * request a node in the cache be culled from the current working directory * - command: "cull <name>" */ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) { struct path path; const struct cred *saved_cred; int ret; _enter(",%s", args); if (strchr(args, '/')) goto inval; if (!test_bit(CACHEFILES_READY, &cache->flags)) { pr_err("cull applied to unready cache\n"); return -EIO; } if (test_bit(CACHEFILES_DEAD, &cache->flags)) { pr_err("cull applied to dead cache\n"); return -EIO; } /* extract the directory dentry from the cwd */ get_fs_pwd(current->fs, &path); if (!d_can_lookup(path.dentry)) goto notdir; cachefiles_begin_secure(cache, &saved_cred); ret = cachefiles_cull(cache, path.dentry, args); cachefiles_end_secure(cache, saved_cred); path_put(&path); _leave(" = %d", ret); return ret; notdir: path_put(&path); pr_err("cull command requires dirfd to be a directory\n"); return -ENOTDIR; inval: pr_err("cull command requires dirfd and filename\n"); return -EINVAL; }
/* * add a cache */ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) { struct cachefiles_object *fsdef; struct path path; struct kstatfs stats; struct dentry *graveyard, *cachedir, *root; const struct cred *saved_cred; int ret; _enter(""); /* we want to work under the module's security ID */ ret = cachefiles_get_security_ID(cache); if (ret < 0) return ret; cachefiles_begin_secure(cache, &saved_cred); /* allocate the root index object */ ret = -ENOMEM; fsdef = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL); if (!fsdef) goto error_root_object; ASSERTCMP(fsdef->backer, ==, NULL); atomic_set(&fsdef->usage, 1); fsdef->type = FSCACHE_COOKIE_TYPE_INDEX; _debug("- fsdef %p", fsdef); /* look up the directory at the root of the cache */ ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path); if (ret < 0) goto error_open_root; cache->mnt = path.mnt; root = path.dentry; /* check parameters */ ret = -EOPNOTSUPP; if (!root->d_inode || !root->d_inode->i_op->lookup || !root->d_inode->i_op->mkdir || !root->d_inode->i_op->setxattr || !root->d_inode->i_op->getxattr || !root->d_sb->s_op->statfs || !root->d_sb->s_op->sync_fs) goto error_unsupported; ret = -EROFS; if (root->d_sb->s_flags & MS_RDONLY) goto error_unsupported; /* determine the security of the on-disk cache as this governs * security ID of files we create */ ret = cachefiles_determine_cache_security(cache, root, &saved_cred); if (ret < 0) goto error_unsupported; /* get the cache size and blocksize */ ret = vfs_statfs(&path, &stats); if (ret < 0) goto error_unsupported; ret = -ERANGE; if (stats.f_bsize <= 0) goto error_unsupported; ret = -EOPNOTSUPP; if (stats.f_bsize > PAGE_SIZE) goto error_unsupported; cache->bsize = stats.f_bsize; cache->bshift = 0; if (stats.f_bsize < PAGE_SIZE) cache->bshift = PAGE_SHIFT - ilog2(stats.f_bsize); _debug("blksize %u (shift %u)", cache->bsize, cache->bshift); _debug("size %llu, avail %llu", (unsigned long long) stats.f_blocks, (unsigned long long) stats.f_bavail); /* set up caching limits */ do_div(stats.f_files, 100); cache->fstop = stats.f_files * cache->fstop_percent; cache->fcull = stats.f_files * cache->fcull_percent; cache->frun = stats.f_files * cache->frun_percent; _debug("limits {%llu,%llu,%llu} files", (unsigned long long) cache->frun, (unsigned long long) cache->fcull, (unsigned long long) cache->fstop); stats.f_blocks >>= cache->bshift; do_div(stats.f_blocks, 100); cache->bstop = stats.f_blocks * cache->bstop_percent; cache->bcull = stats.f_blocks * cache->bcull_percent; cache->brun = stats.f_blocks * cache->brun_percent; _debug("limits {%llu,%llu,%llu} blocks", (unsigned long long) cache->brun, (unsigned long long) cache->bcull, (unsigned long long) cache->bstop); /* get the cache directory and check its type */ cachedir = cachefiles_get_directory(cache, root, "cache"); if (IS_ERR(cachedir)) { ret = PTR_ERR(cachedir); goto error_unsupported; } fsdef->dentry = cachedir; fsdef->fscache.cookie = NULL; ret = cachefiles_check_object_type(fsdef); if (ret < 0) goto error_unsupported; /* get the graveyard directory */ graveyard = cachefiles_get_directory(cache, root, "graveyard"); if (IS_ERR(graveyard)) { ret = PTR_ERR(graveyard); goto error_unsupported; } cache->graveyard = graveyard; /* publish the cache */ fscache_init_cache(&cache->cache, &cachefiles_cache_ops, "%s", fsdef->dentry->d_sb->s_id); fscache_object_init(&fsdef->fscache, NULL, &cache->cache); ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag); if (ret < 0) goto error_add_cache; /* done */ set_bit(CACHEFILES_READY, &cache->flags); dput(root); pr_info("File cache on %s registered\n", cache->cache.identifier); /* check how much space the cache has */ cachefiles_has_space(cache, 0, 0); cachefiles_end_secure(cache, saved_cred); return 0; error_add_cache: dput(cache->graveyard); cache->graveyard = NULL; error_unsupported: mntput(cache->mnt); cache->mnt = NULL; dput(fsdef->dentry); fsdef->dentry = NULL; dput(root); error_open_root: kmem_cache_free(cachefiles_object_jar, fsdef); error_root_object: cachefiles_end_secure(cache, saved_cred); pr_err("Failed to register: %d\n", ret); return ret; }