162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Daemon interface 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007, 2021 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/completion.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/fs.h> 1462306a36Sopenharmony_ci#include <linux/file.h> 1562306a36Sopenharmony_ci#include <linux/namei.h> 1662306a36Sopenharmony_ci#include <linux/poll.h> 1762306a36Sopenharmony_ci#include <linux/mount.h> 1862306a36Sopenharmony_ci#include <linux/statfs.h> 1962306a36Sopenharmony_ci#include <linux/ctype.h> 2062306a36Sopenharmony_ci#include <linux/string.h> 2162306a36Sopenharmony_ci#include <linux/fs_struct.h> 2262306a36Sopenharmony_ci#include "internal.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int cachefiles_daemon_open(struct inode *, struct file *); 2562306a36Sopenharmony_cistatic int cachefiles_daemon_release(struct inode *, struct file *); 2662306a36Sopenharmony_cistatic ssize_t cachefiles_daemon_read(struct file *, char __user *, size_t, 2762306a36Sopenharmony_ci loff_t *); 2862306a36Sopenharmony_cistatic ssize_t cachefiles_daemon_write(struct file *, const char __user *, 2962306a36Sopenharmony_ci size_t, loff_t *); 3062306a36Sopenharmony_cistatic __poll_t cachefiles_daemon_poll(struct file *, 3162306a36Sopenharmony_ci struct poll_table_struct *); 3262306a36Sopenharmony_cistatic int cachefiles_daemon_frun(struct cachefiles_cache *, char *); 3362306a36Sopenharmony_cistatic int cachefiles_daemon_fcull(struct cachefiles_cache *, char *); 3462306a36Sopenharmony_cistatic int cachefiles_daemon_fstop(struct cachefiles_cache *, char *); 3562306a36Sopenharmony_cistatic int cachefiles_daemon_brun(struct cachefiles_cache *, char *); 3662306a36Sopenharmony_cistatic int cachefiles_daemon_bcull(struct cachefiles_cache *, char *); 3762306a36Sopenharmony_cistatic int cachefiles_daemon_bstop(struct cachefiles_cache *, char *); 3862306a36Sopenharmony_cistatic int cachefiles_daemon_cull(struct cachefiles_cache *, char *); 3962306a36Sopenharmony_cistatic int cachefiles_daemon_debug(struct cachefiles_cache *, char *); 4062306a36Sopenharmony_cistatic int cachefiles_daemon_dir(struct cachefiles_cache *, char *); 4162306a36Sopenharmony_cistatic int cachefiles_daemon_inuse(struct cachefiles_cache *, char *); 4262306a36Sopenharmony_cistatic int cachefiles_daemon_secctx(struct cachefiles_cache *, char *); 4362306a36Sopenharmony_cistatic int cachefiles_daemon_tag(struct cachefiles_cache *, char *); 4462306a36Sopenharmony_cistatic int cachefiles_daemon_bind(struct cachefiles_cache *, char *); 4562306a36Sopenharmony_cistatic void cachefiles_daemon_unbind(struct cachefiles_cache *); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic unsigned long cachefiles_open; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciconst struct file_operations cachefiles_daemon_fops = { 5062306a36Sopenharmony_ci .owner = THIS_MODULE, 5162306a36Sopenharmony_ci .open = cachefiles_daemon_open, 5262306a36Sopenharmony_ci .release = cachefiles_daemon_release, 5362306a36Sopenharmony_ci .read = cachefiles_daemon_read, 5462306a36Sopenharmony_ci .write = cachefiles_daemon_write, 5562306a36Sopenharmony_ci .poll = cachefiles_daemon_poll, 5662306a36Sopenharmony_ci .llseek = noop_llseek, 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct cachefiles_daemon_cmd { 6062306a36Sopenharmony_ci char name[8]; 6162306a36Sopenharmony_ci int (*handler)(struct cachefiles_cache *cache, char *args); 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = { 6562306a36Sopenharmony_ci { "bind", cachefiles_daemon_bind }, 6662306a36Sopenharmony_ci { "brun", cachefiles_daemon_brun }, 6762306a36Sopenharmony_ci { "bcull", cachefiles_daemon_bcull }, 6862306a36Sopenharmony_ci { "bstop", cachefiles_daemon_bstop }, 6962306a36Sopenharmony_ci { "cull", cachefiles_daemon_cull }, 7062306a36Sopenharmony_ci { "debug", cachefiles_daemon_debug }, 7162306a36Sopenharmony_ci { "dir", cachefiles_daemon_dir }, 7262306a36Sopenharmony_ci { "frun", cachefiles_daemon_frun }, 7362306a36Sopenharmony_ci { "fcull", cachefiles_daemon_fcull }, 7462306a36Sopenharmony_ci { "fstop", cachefiles_daemon_fstop }, 7562306a36Sopenharmony_ci { "inuse", cachefiles_daemon_inuse }, 7662306a36Sopenharmony_ci { "secctx", cachefiles_daemon_secctx }, 7762306a36Sopenharmony_ci { "tag", cachefiles_daemon_tag }, 7862306a36Sopenharmony_ci#ifdef CONFIG_CACHEFILES_ONDEMAND 7962306a36Sopenharmony_ci { "copen", cachefiles_ondemand_copen }, 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci { "", NULL } 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Prepare a cache for caching. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic int cachefiles_daemon_open(struct inode *inode, struct file *file) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct cachefiles_cache *cache; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci _enter(""); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* only the superuser may do this */ 9562306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 9662306a36Sopenharmony_ci return -EPERM; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* the cachefiles device may only be open once at a time */ 9962306a36Sopenharmony_ci if (xchg(&cachefiles_open, 1) == 1) 10062306a36Sopenharmony_ci return -EBUSY; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* allocate a cache record */ 10362306a36Sopenharmony_ci cache = kzalloc(sizeof(struct cachefiles_cache), GFP_KERNEL); 10462306a36Sopenharmony_ci if (!cache) { 10562306a36Sopenharmony_ci cachefiles_open = 0; 10662306a36Sopenharmony_ci return -ENOMEM; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci mutex_init(&cache->daemon_mutex); 11062306a36Sopenharmony_ci init_waitqueue_head(&cache->daemon_pollwq); 11162306a36Sopenharmony_ci INIT_LIST_HEAD(&cache->volumes); 11262306a36Sopenharmony_ci INIT_LIST_HEAD(&cache->object_list); 11362306a36Sopenharmony_ci spin_lock_init(&cache->object_list_lock); 11462306a36Sopenharmony_ci refcount_set(&cache->unbind_pincount, 1); 11562306a36Sopenharmony_ci xa_init_flags(&cache->reqs, XA_FLAGS_ALLOC); 11662306a36Sopenharmony_ci xa_init_flags(&cache->ondemand_ids, XA_FLAGS_ALLOC1); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* set default caching limits 11962306a36Sopenharmony_ci * - limit at 1% free space and/or free files 12062306a36Sopenharmony_ci * - cull below 5% free space and/or free files 12162306a36Sopenharmony_ci * - cease culling above 7% free space and/or free files 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci cache->frun_percent = 7; 12462306a36Sopenharmony_ci cache->fcull_percent = 5; 12562306a36Sopenharmony_ci cache->fstop_percent = 1; 12662306a36Sopenharmony_ci cache->brun_percent = 7; 12762306a36Sopenharmony_ci cache->bcull_percent = 5; 12862306a36Sopenharmony_ci cache->bstop_percent = 1; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci file->private_data = cache; 13162306a36Sopenharmony_ci cache->cachefilesd = file; 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void cachefiles_flush_reqs(struct cachefiles_cache *cache) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct xarray *xa = &cache->reqs; 13862306a36Sopenharmony_ci struct cachefiles_req *req; 13962306a36Sopenharmony_ci unsigned long index; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * Make sure the following two operations won't be reordered. 14362306a36Sopenharmony_ci * 1) set CACHEFILES_DEAD bit 14462306a36Sopenharmony_ci * 2) flush requests in the xarray 14562306a36Sopenharmony_ci * Otherwise the request may be enqueued after xarray has been 14662306a36Sopenharmony_ci * flushed, leaving the orphan request never being completed. 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * CPU 1 CPU 2 14962306a36Sopenharmony_ci * ===== ===== 15062306a36Sopenharmony_ci * flush requests in the xarray 15162306a36Sopenharmony_ci * test CACHEFILES_DEAD bit 15262306a36Sopenharmony_ci * enqueue the request 15362306a36Sopenharmony_ci * set CACHEFILES_DEAD bit 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci smp_mb(); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci xa_lock(xa); 15862306a36Sopenharmony_ci xa_for_each(xa, index, req) { 15962306a36Sopenharmony_ci req->error = -EIO; 16062306a36Sopenharmony_ci complete(&req->done); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci xa_unlock(xa); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci xa_destroy(&cache->reqs); 16562306a36Sopenharmony_ci xa_destroy(&cache->ondemand_ids); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_civoid cachefiles_put_unbind_pincount(struct cachefiles_cache *cache) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci if (refcount_dec_and_test(&cache->unbind_pincount)) { 17162306a36Sopenharmony_ci cachefiles_daemon_unbind(cache); 17262306a36Sopenharmony_ci cachefiles_open = 0; 17362306a36Sopenharmony_ci kfree(cache); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid cachefiles_get_unbind_pincount(struct cachefiles_cache *cache) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci refcount_inc(&cache->unbind_pincount); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* 18362306a36Sopenharmony_ci * Release a cache. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistatic int cachefiles_daemon_release(struct inode *inode, struct file *file) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct cachefiles_cache *cache = file->private_data; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci _enter(""); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci ASSERT(cache); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci set_bit(CACHEFILES_DEAD, &cache->flags); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (cachefiles_in_ondemand_mode(cache)) 19662306a36Sopenharmony_ci cachefiles_flush_reqs(cache); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* clean up the control file interface */ 19962306a36Sopenharmony_ci cache->cachefilesd = NULL; 20062306a36Sopenharmony_ci file->private_data = NULL; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci cachefiles_put_unbind_pincount(cache); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci _leave(""); 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic ssize_t cachefiles_do_daemon_read(struct cachefiles_cache *cache, 20962306a36Sopenharmony_ci char __user *_buffer, size_t buflen) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci unsigned long long b_released; 21262306a36Sopenharmony_ci unsigned f_released; 21362306a36Sopenharmony_ci char buffer[256]; 21462306a36Sopenharmony_ci int n; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* check how much space the cache has */ 21762306a36Sopenharmony_ci cachefiles_has_space(cache, 0, 0, cachefiles_has_space_check); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* summarise */ 22062306a36Sopenharmony_ci f_released = atomic_xchg(&cache->f_released, 0); 22162306a36Sopenharmony_ci b_released = atomic_long_xchg(&cache->b_released, 0); 22262306a36Sopenharmony_ci clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci n = snprintf(buffer, sizeof(buffer), 22562306a36Sopenharmony_ci "cull=%c" 22662306a36Sopenharmony_ci " frun=%llx" 22762306a36Sopenharmony_ci " fcull=%llx" 22862306a36Sopenharmony_ci " fstop=%llx" 22962306a36Sopenharmony_ci " brun=%llx" 23062306a36Sopenharmony_ci " bcull=%llx" 23162306a36Sopenharmony_ci " bstop=%llx" 23262306a36Sopenharmony_ci " freleased=%x" 23362306a36Sopenharmony_ci " breleased=%llx", 23462306a36Sopenharmony_ci test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', 23562306a36Sopenharmony_ci (unsigned long long) cache->frun, 23662306a36Sopenharmony_ci (unsigned long long) cache->fcull, 23762306a36Sopenharmony_ci (unsigned long long) cache->fstop, 23862306a36Sopenharmony_ci (unsigned long long) cache->brun, 23962306a36Sopenharmony_ci (unsigned long long) cache->bcull, 24062306a36Sopenharmony_ci (unsigned long long) cache->bstop, 24162306a36Sopenharmony_ci f_released, 24262306a36Sopenharmony_ci b_released); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (n > buflen) 24562306a36Sopenharmony_ci return -EMSGSIZE; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (copy_to_user(_buffer, buffer, n) != 0) 24862306a36Sopenharmony_ci return -EFAULT; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return n; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* 25462306a36Sopenharmony_ci * Read the cache state. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_cistatic ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer, 25762306a36Sopenharmony_ci size_t buflen, loff_t *pos) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct cachefiles_cache *cache = file->private_data; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci //_enter(",,%zu,", buflen); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!test_bit(CACHEFILES_READY, &cache->flags)) 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (cachefiles_in_ondemand_mode(cache)) 26762306a36Sopenharmony_ci return cachefiles_ondemand_daemon_read(cache, _buffer, buflen); 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci return cachefiles_do_daemon_read(cache, _buffer, buflen); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * Take a command from cachefilesd, parse it and act on it. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_cistatic ssize_t cachefiles_daemon_write(struct file *file, 27662306a36Sopenharmony_ci const char __user *_data, 27762306a36Sopenharmony_ci size_t datalen, 27862306a36Sopenharmony_ci loff_t *pos) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci const struct cachefiles_daemon_cmd *cmd; 28162306a36Sopenharmony_ci struct cachefiles_cache *cache = file->private_data; 28262306a36Sopenharmony_ci ssize_t ret; 28362306a36Sopenharmony_ci char *data, *args, *cp; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci //_enter(",,%zu,", datalen); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci ASSERT(cache); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (test_bit(CACHEFILES_DEAD, &cache->flags)) 29062306a36Sopenharmony_ci return -EIO; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (datalen > PAGE_SIZE - 1) 29362306a36Sopenharmony_ci return -EOPNOTSUPP; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* drag the command string into the kernel so we can parse it */ 29662306a36Sopenharmony_ci data = memdup_user_nul(_data, datalen); 29762306a36Sopenharmony_ci if (IS_ERR(data)) 29862306a36Sopenharmony_ci return PTR_ERR(data); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = -EINVAL; 30162306a36Sopenharmony_ci if (memchr(data, '\0', datalen)) 30262306a36Sopenharmony_ci goto error; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* strip any newline */ 30562306a36Sopenharmony_ci cp = memchr(data, '\n', datalen); 30662306a36Sopenharmony_ci if (cp) { 30762306a36Sopenharmony_ci if (cp == data) 30862306a36Sopenharmony_ci goto error; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci *cp = '\0'; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* parse the command */ 31462306a36Sopenharmony_ci ret = -EOPNOTSUPP; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci for (args = data; *args; args++) 31762306a36Sopenharmony_ci if (isspace(*args)) 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci if (*args) { 32062306a36Sopenharmony_ci if (args == data) 32162306a36Sopenharmony_ci goto error; 32262306a36Sopenharmony_ci *args = '\0'; 32362306a36Sopenharmony_ci args = skip_spaces(++args); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* run the appropriate command handler */ 32762306a36Sopenharmony_ci for (cmd = cachefiles_daemon_cmds; cmd->name[0]; cmd++) 32862306a36Sopenharmony_ci if (strcmp(cmd->name, data) == 0) 32962306a36Sopenharmony_ci goto found_command; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cierror: 33262306a36Sopenharmony_ci kfree(data); 33362306a36Sopenharmony_ci //_leave(" = %zd", ret); 33462306a36Sopenharmony_ci return ret; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cifound_command: 33762306a36Sopenharmony_ci mutex_lock(&cache->daemon_mutex); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ret = -EIO; 34062306a36Sopenharmony_ci if (!test_bit(CACHEFILES_DEAD, &cache->flags)) 34162306a36Sopenharmony_ci ret = cmd->handler(cache, args); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci mutex_unlock(&cache->daemon_mutex); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (ret == 0) 34662306a36Sopenharmony_ci ret = datalen; 34762306a36Sopenharmony_ci goto error; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * Poll for culling state 35262306a36Sopenharmony_ci * - use EPOLLOUT to indicate culling state 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_cistatic __poll_t cachefiles_daemon_poll(struct file *file, 35562306a36Sopenharmony_ci struct poll_table_struct *poll) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct cachefiles_cache *cache = file->private_data; 35862306a36Sopenharmony_ci __poll_t mask; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci poll_wait(file, &cache->daemon_pollwq, poll); 36162306a36Sopenharmony_ci mask = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (cachefiles_in_ondemand_mode(cache)) { 36462306a36Sopenharmony_ci if (!xa_empty(&cache->reqs)) 36562306a36Sopenharmony_ci mask |= EPOLLIN; 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags)) 36862306a36Sopenharmony_ci mask |= EPOLLIN; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (test_bit(CACHEFILES_CULLING, &cache->flags)) 37262306a36Sopenharmony_ci mask |= EPOLLOUT; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return mask; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* 37862306a36Sopenharmony_ci * Give a range error for cache space constraints 37962306a36Sopenharmony_ci * - can be tail-called 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_cistatic int cachefiles_daemon_range_error(struct cachefiles_cache *cache, 38262306a36Sopenharmony_ci char *args) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%\n"); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return -EINVAL; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/* 39062306a36Sopenharmony_ci * Set the percentage of files at which to stop culling 39162306a36Sopenharmony_ci * - command: "frun <N>%" 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_cistatic int cachefiles_daemon_frun(struct cachefiles_cache *cache, char *args) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci unsigned long frun; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci _enter(",%s", args); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (!*args) 40062306a36Sopenharmony_ci return -EINVAL; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci frun = simple_strtoul(args, &args, 10); 40362306a36Sopenharmony_ci if (args[0] != '%' || args[1] != '\0') 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (frun <= cache->fcull_percent || frun >= 100) 40762306a36Sopenharmony_ci return cachefiles_daemon_range_error(cache, args); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci cache->frun_percent = frun; 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/* 41462306a36Sopenharmony_ci * Set the percentage of files at which to start culling 41562306a36Sopenharmony_ci * - command: "fcull <N>%" 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_cistatic int cachefiles_daemon_fcull(struct cachefiles_cache *cache, char *args) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci unsigned long fcull; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci _enter(",%s", args); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (!*args) 42462306a36Sopenharmony_ci return -EINVAL; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci fcull = simple_strtoul(args, &args, 10); 42762306a36Sopenharmony_ci if (args[0] != '%' || args[1] != '\0') 42862306a36Sopenharmony_ci return -EINVAL; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (fcull <= cache->fstop_percent || fcull >= cache->frun_percent) 43162306a36Sopenharmony_ci return cachefiles_daemon_range_error(cache, args); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci cache->fcull_percent = fcull; 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* 43862306a36Sopenharmony_ci * Set the percentage of files at which to stop allocating 43962306a36Sopenharmony_ci * - command: "fstop <N>%" 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_cistatic int cachefiles_daemon_fstop(struct cachefiles_cache *cache, char *args) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci unsigned long fstop; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci _enter(",%s", args); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!*args) 44862306a36Sopenharmony_ci return -EINVAL; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci fstop = simple_strtoul(args, &args, 10); 45162306a36Sopenharmony_ci if (args[0] != '%' || args[1] != '\0') 45262306a36Sopenharmony_ci return -EINVAL; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (fstop >= cache->fcull_percent) 45562306a36Sopenharmony_ci return cachefiles_daemon_range_error(cache, args); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci cache->fstop_percent = fstop; 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/* 46262306a36Sopenharmony_ci * Set the percentage of blocks at which to stop culling 46362306a36Sopenharmony_ci * - command: "brun <N>%" 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_cistatic int cachefiles_daemon_brun(struct cachefiles_cache *cache, char *args) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci unsigned long brun; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci _enter(",%s", args); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (!*args) 47262306a36Sopenharmony_ci return -EINVAL; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci brun = simple_strtoul(args, &args, 10); 47562306a36Sopenharmony_ci if (args[0] != '%' || args[1] != '\0') 47662306a36Sopenharmony_ci return -EINVAL; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (brun <= cache->bcull_percent || brun >= 100) 47962306a36Sopenharmony_ci return cachefiles_daemon_range_error(cache, args); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci cache->brun_percent = brun; 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* 48662306a36Sopenharmony_ci * Set the percentage of blocks at which to start culling 48762306a36Sopenharmony_ci * - command: "bcull <N>%" 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_cistatic int cachefiles_daemon_bcull(struct cachefiles_cache *cache, char *args) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci unsigned long bcull; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci _enter(",%s", args); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (!*args) 49662306a36Sopenharmony_ci return -EINVAL; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci bcull = simple_strtoul(args, &args, 10); 49962306a36Sopenharmony_ci if (args[0] != '%' || args[1] != '\0') 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (bcull <= cache->bstop_percent || bcull >= cache->brun_percent) 50362306a36Sopenharmony_ci return cachefiles_daemon_range_error(cache, args); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci cache->bcull_percent = bcull; 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/* 51062306a36Sopenharmony_ci * Set the percentage of blocks at which to stop allocating 51162306a36Sopenharmony_ci * - command: "bstop <N>%" 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_cistatic int cachefiles_daemon_bstop(struct cachefiles_cache *cache, char *args) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci unsigned long bstop; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci _enter(",%s", args); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (!*args) 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci bstop = simple_strtoul(args, &args, 10); 52362306a36Sopenharmony_ci if (args[0] != '%' || args[1] != '\0') 52462306a36Sopenharmony_ci return -EINVAL; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (bstop >= cache->bcull_percent) 52762306a36Sopenharmony_ci return cachefiles_daemon_range_error(cache, args); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci cache->bstop_percent = bstop; 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/* 53462306a36Sopenharmony_ci * Set the cache directory 53562306a36Sopenharmony_ci * - command: "dir <name>" 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_cistatic int cachefiles_daemon_dir(struct cachefiles_cache *cache, char *args) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci char *dir; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci _enter(",%s", args); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (!*args) { 54462306a36Sopenharmony_ci pr_err("Empty directory specified\n"); 54562306a36Sopenharmony_ci return -EINVAL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (cache->rootdirname) { 54962306a36Sopenharmony_ci pr_err("Second cache directory specified\n"); 55062306a36Sopenharmony_ci return -EEXIST; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci dir = kstrdup(args, GFP_KERNEL); 55462306a36Sopenharmony_ci if (!dir) 55562306a36Sopenharmony_ci return -ENOMEM; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci cache->rootdirname = dir; 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* 56262306a36Sopenharmony_ci * Set the cache security context 56362306a36Sopenharmony_ci * - command: "secctx <ctx>" 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic int cachefiles_daemon_secctx(struct cachefiles_cache *cache, char *args) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci char *secctx; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci _enter(",%s", args); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (!*args) { 57262306a36Sopenharmony_ci pr_err("Empty security context specified\n"); 57362306a36Sopenharmony_ci return -EINVAL; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (cache->secctx) { 57762306a36Sopenharmony_ci pr_err("Second security context specified\n"); 57862306a36Sopenharmony_ci return -EINVAL; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci secctx = kstrdup(args, GFP_KERNEL); 58262306a36Sopenharmony_ci if (!secctx) 58362306a36Sopenharmony_ci return -ENOMEM; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci cache->secctx = secctx; 58662306a36Sopenharmony_ci return 0; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/* 59062306a36Sopenharmony_ci * Set the cache tag 59162306a36Sopenharmony_ci * - command: "tag <name>" 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_cistatic int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci char *tag; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci _enter(",%s", args); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (!*args) { 60062306a36Sopenharmony_ci pr_err("Empty tag specified\n"); 60162306a36Sopenharmony_ci return -EINVAL; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (cache->tag) 60562306a36Sopenharmony_ci return -EEXIST; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci tag = kstrdup(args, GFP_KERNEL); 60862306a36Sopenharmony_ci if (!tag) 60962306a36Sopenharmony_ci return -ENOMEM; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci cache->tag = tag; 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * Request a node in the cache be culled from the current working directory 61762306a36Sopenharmony_ci * - command: "cull <name>" 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_cistatic int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct path path; 62262306a36Sopenharmony_ci const struct cred *saved_cred; 62362306a36Sopenharmony_ci int ret; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci _enter(",%s", args); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (strchr(args, '/')) 62862306a36Sopenharmony_ci goto inval; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!test_bit(CACHEFILES_READY, &cache->flags)) { 63162306a36Sopenharmony_ci pr_err("cull applied to unready cache\n"); 63262306a36Sopenharmony_ci return -EIO; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (test_bit(CACHEFILES_DEAD, &cache->flags)) { 63662306a36Sopenharmony_ci pr_err("cull applied to dead cache\n"); 63762306a36Sopenharmony_ci return -EIO; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci get_fs_pwd(current->fs, &path); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (!d_can_lookup(path.dentry)) 64362306a36Sopenharmony_ci goto notdir; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 64662306a36Sopenharmony_ci ret = cachefiles_cull(cache, path.dentry, args); 64762306a36Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci path_put(&path); 65062306a36Sopenharmony_ci _leave(" = %d", ret); 65162306a36Sopenharmony_ci return ret; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cinotdir: 65462306a36Sopenharmony_ci path_put(&path); 65562306a36Sopenharmony_ci pr_err("cull command requires dirfd to be a directory\n"); 65662306a36Sopenharmony_ci return -ENOTDIR; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciinval: 65962306a36Sopenharmony_ci pr_err("cull command requires dirfd and filename\n"); 66062306a36Sopenharmony_ci return -EINVAL; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci/* 66462306a36Sopenharmony_ci * Set debugging mode 66562306a36Sopenharmony_ci * - command: "debug <mask>" 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_cistatic int cachefiles_daemon_debug(struct cachefiles_cache *cache, char *args) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci unsigned long mask; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci _enter(",%s", args); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci mask = simple_strtoul(args, &args, 0); 67462306a36Sopenharmony_ci if (args[0] != '\0') 67562306a36Sopenharmony_ci goto inval; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci cachefiles_debug = mask; 67862306a36Sopenharmony_ci _leave(" = 0"); 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ciinval: 68262306a36Sopenharmony_ci pr_err("debug command requires mask\n"); 68362306a36Sopenharmony_ci return -EINVAL; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci/* 68762306a36Sopenharmony_ci * Find out whether an object in the current working directory is in use or not 68862306a36Sopenharmony_ci * - command: "inuse <name>" 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_cistatic int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct path path; 69362306a36Sopenharmony_ci const struct cred *saved_cred; 69462306a36Sopenharmony_ci int ret; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci //_enter(",%s", args); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (strchr(args, '/')) 69962306a36Sopenharmony_ci goto inval; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (!test_bit(CACHEFILES_READY, &cache->flags)) { 70262306a36Sopenharmony_ci pr_err("inuse applied to unready cache\n"); 70362306a36Sopenharmony_ci return -EIO; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (test_bit(CACHEFILES_DEAD, &cache->flags)) { 70762306a36Sopenharmony_ci pr_err("inuse applied to dead cache\n"); 70862306a36Sopenharmony_ci return -EIO; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci get_fs_pwd(current->fs, &path); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (!d_can_lookup(path.dentry)) 71462306a36Sopenharmony_ci goto notdir; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 71762306a36Sopenharmony_ci ret = cachefiles_check_in_use(cache, path.dentry, args); 71862306a36Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci path_put(&path); 72162306a36Sopenharmony_ci //_leave(" = %d", ret); 72262306a36Sopenharmony_ci return ret; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cinotdir: 72562306a36Sopenharmony_ci path_put(&path); 72662306a36Sopenharmony_ci pr_err("inuse command requires dirfd to be a directory\n"); 72762306a36Sopenharmony_ci return -ENOTDIR; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciinval: 73062306a36Sopenharmony_ci pr_err("inuse command requires dirfd and filename\n"); 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci/* 73562306a36Sopenharmony_ci * Bind a directory as a cache 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_cistatic int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci _enter("{%u,%u,%u,%u,%u,%u},%s", 74062306a36Sopenharmony_ci cache->frun_percent, 74162306a36Sopenharmony_ci cache->fcull_percent, 74262306a36Sopenharmony_ci cache->fstop_percent, 74362306a36Sopenharmony_ci cache->brun_percent, 74462306a36Sopenharmony_ci cache->bcull_percent, 74562306a36Sopenharmony_ci cache->bstop_percent, 74662306a36Sopenharmony_ci args); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (cache->fstop_percent >= cache->fcull_percent || 74962306a36Sopenharmony_ci cache->fcull_percent >= cache->frun_percent || 75062306a36Sopenharmony_ci cache->frun_percent >= 100) 75162306a36Sopenharmony_ci return -ERANGE; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (cache->bstop_percent >= cache->bcull_percent || 75462306a36Sopenharmony_ci cache->bcull_percent >= cache->brun_percent || 75562306a36Sopenharmony_ci cache->brun_percent >= 100) 75662306a36Sopenharmony_ci return -ERANGE; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (!cache->rootdirname) { 75962306a36Sopenharmony_ci pr_err("No cache directory specified\n"); 76062306a36Sopenharmony_ci return -EINVAL; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Don't permit already bound caches to be re-bound */ 76462306a36Sopenharmony_ci if (test_bit(CACHEFILES_READY, &cache->flags)) { 76562306a36Sopenharmony_ci pr_err("Cache already bound\n"); 76662306a36Sopenharmony_ci return -EBUSY; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CACHEFILES_ONDEMAND)) { 77062306a36Sopenharmony_ci if (!strcmp(args, "ondemand")) { 77162306a36Sopenharmony_ci set_bit(CACHEFILES_ONDEMAND_MODE, &cache->flags); 77262306a36Sopenharmony_ci } else if (*args) { 77362306a36Sopenharmony_ci pr_err("Invalid argument to the 'bind' command\n"); 77462306a36Sopenharmony_ci return -EINVAL; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci } else if (*args) { 77762306a36Sopenharmony_ci pr_err("'bind' command doesn't take an argument\n"); 77862306a36Sopenharmony_ci return -EINVAL; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* Make sure we have copies of the tag string */ 78262306a36Sopenharmony_ci if (!cache->tag) { 78362306a36Sopenharmony_ci /* 78462306a36Sopenharmony_ci * The tag string is released by the fops->release() 78562306a36Sopenharmony_ci * function, so we don't release it on error here 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci cache->tag = kstrdup("CacheFiles", GFP_KERNEL); 78862306a36Sopenharmony_ci if (!cache->tag) 78962306a36Sopenharmony_ci return -ENOMEM; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return cachefiles_add_cache(cache); 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/* 79662306a36Sopenharmony_ci * Unbind a cache. 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_cistatic void cachefiles_daemon_unbind(struct cachefiles_cache *cache) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci _enter(""); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (test_bit(CACHEFILES_READY, &cache->flags)) 80362306a36Sopenharmony_ci cachefiles_withdraw_cache(cache); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci cachefiles_put_directory(cache->graveyard); 80662306a36Sopenharmony_ci cachefiles_put_directory(cache->store); 80762306a36Sopenharmony_ci mntput(cache->mnt); 80862306a36Sopenharmony_ci put_cred(cache->cache_cred); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci kfree(cache->rootdirname); 81162306a36Sopenharmony_ci kfree(cache->secctx); 81262306a36Sopenharmony_ci kfree(cache->tag); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci _leave(""); 81562306a36Sopenharmony_ci} 816