lkml.org 
[lkml]   [2021]   [Dec]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC 18/19] cachefiles: support on demand read
    Date
    fs can call cachefiles_demand_read() helper function to enqueue read
    request for demand reading.

    Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
    ---
    fs/cachefiles/daemon.c | 148 +++++++++++++++++++++++++++------------
    fs/cachefiles/internal.h | 16 +++++
    fs/cachefiles/io.c | 56 +++++++++++++++
    3 files changed, 175 insertions(+), 45 deletions(-)

    diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c
    index 951963e72b44..7d174a39cd1c 100644
    --- a/fs/cachefiles/daemon.c
    +++ b/fs/cachefiles/daemon.c
    @@ -44,6 +44,7 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *, char *);
    static int cachefiles_daemon_mode(struct cachefiles_cache *, char *);
    static int cachefiles_daemon_bind(struct cachefiles_cache *, char *);
    static void cachefiles_daemon_unbind(struct cachefiles_cache *);
    +static int cachefiles_daemon_done(struct cachefiles_cache *, char *);

    static unsigned long cachefiles_open;

    @@ -77,6 +78,7 @@ static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = {
    { "secctx", cachefiles_daemon_secctx },
    { "tag", cachefiles_daemon_tag },
    { "mode", cachefiles_daemon_mode },
    + { "done", cachefiles_daemon_done },
    { "", NULL }
    };

    @@ -110,6 +112,8 @@ static int cachefiles_daemon_open(struct inode *inode, struct file *file)
    INIT_LIST_HEAD(&cache->volumes);
    INIT_LIST_HEAD(&cache->object_list);
    spin_lock_init(&cache->object_list_lock);
    + idr_init(&cache->reqs);
    + spin_lock_init(&cache->reqs_lock);

    /* set default caching limits
    * - limit at 1% free space and/or free files
    @@ -144,6 +148,7 @@ static int cachefiles_daemon_release(struct inode *inode, struct file *file)
    cachefiles_daemon_unbind(cache);

    /* clean up the control file interface */
    + idr_destroy(&cache->reqs);
    cache->cachefilesd = NULL;
    file->private_data = NULL;
    cachefiles_open = 0;
    @@ -164,6 +169,7 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
    unsigned long long b_released;
    unsigned f_released;
    char buffer[256];
    + void *buf;
    int n;

    //_enter(",,%zu,", buflen);
    @@ -171,38 +177,53 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
    if (!test_bit(CACHEFILES_READY, &cache->flags))
    return 0;

    - /* check how much space the cache has */
    - cachefiles_has_space(cache, 0, 0, cachefiles_has_space_check);
    -
    - /* summarise */
    - f_released = atomic_xchg(&cache->f_released, 0);
    - b_released = atomic_long_xchg(&cache->b_released, 0);
    - clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
    -
    - n = snprintf(buffer, sizeof(buffer),
    - "cull=%c"
    - " frun=%llx"
    - " fcull=%llx"
    - " fstop=%llx"
    - " brun=%llx"
    - " bcull=%llx"
    - " bstop=%llx"
    - " freleased=%x"
    - " breleased=%llx",
    - test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0',
    - (unsigned long long) cache->frun,
    - (unsigned long long) cache->fcull,
    - (unsigned long long) cache->fstop,
    - (unsigned long long) cache->brun,
    - (unsigned long long) cache->bcull,
    - (unsigned long long) cache->bstop,
    - f_released,
    - b_released);
    + if (cache->mode == CACHEFILES_MODE_CACHE) {
    + /* check how much space the cache has */
    + cachefiles_has_space(cache, 0, 0, cachefiles_has_space_check);
    +
    + /* summarise */
    + f_released = atomic_xchg(&cache->f_released, 0);
    + b_released = atomic_long_xchg(&cache->b_released, 0);
    + clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
    +
    + n = snprintf(buffer, sizeof(buffer),
    + "cull=%c"
    + " frun=%llx"
    + " fcull=%llx"
    + " fstop=%llx"
    + " brun=%llx"
    + " bcull=%llx"
    + " bstop=%llx"
    + " freleased=%x"
    + " breleased=%llx",
    + test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0',
    + (unsigned long long) cache->frun,
    + (unsigned long long) cache->fcull,
    + (unsigned long long) cache->fstop,
    + (unsigned long long) cache->brun,
    + (unsigned long long) cache->bcull,
    + (unsigned long long) cache->bstop,
    + f_released,
    + b_released);
    + buf = buffer;
    + } else {
    + struct cachefiles_req *req;
    + int id = 0;
    +
    + spin_lock(&cache->reqs_lock);
    + req = idr_get_next(&cache->reqs, &id);
    + spin_unlock(&cache->reqs_lock);
    + if (!req)
    + return 0;
    +
    + buf = &req->req_in;
    + n = sizeof(req->req_in);
    + }

    if (n > buflen)
    return -EMSGSIZE;

    - if (copy_to_user(_buffer, buffer, n) != 0)
    + if (copy_to_user(_buffer, buf, n) != 0)
    return -EFAULT;

    return n;
    @@ -291,7 +312,7 @@ static ssize_t cachefiles_daemon_write(struct file *file,
    * - use EPOLLOUT to indicate culling state
    */
    static __poll_t cachefiles_daemon_poll(struct file *file,
    - struct poll_table_struct *poll)
    + struct poll_table_struct *poll)
    {
    struct cachefiles_cache *cache = file->private_data;
    __poll_t mask;
    @@ -299,11 +320,16 @@ static __poll_t cachefiles_daemon_poll(struct file *file,
    poll_wait(file, &cache->daemon_pollwq, poll);
    mask = 0;

    - if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags))
    - mask |= EPOLLIN;
    + if (cache->mode == CACHEFILES_MODE_CACHE) {
    + if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags))
    + mask |= EPOLLIN;

    - if (test_bit(CACHEFILES_CULLING, &cache->flags))
    - mask |= EPOLLOUT;
    + if (test_bit(CACHEFILES_CULLING, &cache->flags))
    + mask |= EPOLLOUT;
    + } else {
    + if(!idr_is_empty(&cache->reqs))
    + mask |= EPOLLIN;
    + }

    return mask;
    }
    @@ -313,7 +339,7 @@ static __poll_t cachefiles_daemon_poll(struct file *file,
    * - can be tail-called
    */
    static int cachefiles_daemon_range_error(struct cachefiles_cache *cache,
    - char *args)
    + char *args)
    {
    pr_err("Free space limits must be in range 0%%<=stop<cull<run<100%%\n");

    @@ -546,6 +572,38 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args)
    return 0;
    }

    +/*
    + * Request completion
    + * - command: "done <id>"
    + */
    +static int cachefiles_daemon_done(struct cachefiles_cache *cache, char *args)
    +{
    + unsigned long id;
    + int ret;
    + struct cachefiles_req *req;
    +
    + _enter(",%s", args);
    +
    + if (!*args) {
    + pr_err("Empty id specified\n");
    + return -EINVAL;
    + }
    +
    + ret = kstrtoul(args, 0, &id);
    + if (ret)
    + return ret;
    +
    + spin_lock(&cache->reqs_lock);
    + req = idr_remove(&cache->reqs, id);
    + spin_unlock(&cache->reqs_lock);
    + if (!req)
    + return -EINVAL;
    +
    + complete(&req->done);
    +
    + return 0;
    +}
    +
    /*
    * Request a node in the cache be culled from the current working directory
    * - command: "cull <name>"
    @@ -704,22 +762,22 @@ static int cachefiles_daemon_mode(struct cachefiles_cache *cache, char *args)
    static int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args)
    {
    _enter("{%u,%u,%u,%u,%u,%u},%s",
    - cache->frun_percent,
    - cache->fcull_percent,
    - cache->fstop_percent,
    - cache->brun_percent,
    - cache->bcull_percent,
    - cache->bstop_percent,
    - args);
    + cache->frun_percent,
    + cache->fcull_percent,
    + cache->fstop_percent,
    + cache->brun_percent,
    + cache->bcull_percent,
    + cache->bstop_percent,
    + args);

    if (cache->fstop_percent >= cache->fcull_percent ||
    - cache->fcull_percent >= cache->frun_percent ||
    - cache->frun_percent >= 100)
    + cache->fcull_percent >= cache->frun_percent ||
    + cache->frun_percent >= 100)
    return -ERANGE;

    if (cache->bstop_percent >= cache->bcull_percent ||
    - cache->bcull_percent >= cache->brun_percent ||
    - cache->brun_percent >= 100)
    + cache->bcull_percent >= cache->brun_percent ||
    + cache->brun_percent >= 100)
    return -ERANGE;

    if (*args) {
    diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
    index 1366e4319b4e..72e6e8744788 100644
    --- a/fs/cachefiles/internal.h
    +++ b/fs/cachefiles/internal.h
    @@ -15,6 +15,7 @@
    #include <linux/fscache-cache.h>
    #include <linux/cred.h>
    #include <linux/security.h>
    +#include <linux/idr.h>

    #define CACHEFILES_DIO_BLOCK_SIZE 4096

    @@ -65,6 +66,18 @@ enum cachefiles_mode {
    CACHEFILES_MODE_DEMAND, /* demand read for read-only fs */
    };

    +struct cachefiles_req_in {
    + uint64_t id;
    + uint64_t off;
    + uint64_t len;
    + char path[NAME_MAX];
    +};
    +
    +struct cachefiles_req {
    + struct completion done;
    + struct cachefiles_req_in req_in;
    +};
    +
    /*
    * Cache files cache definition
    */
    @@ -107,6 +120,9 @@ struct cachefiles_cache {
    char *rootdirname; /* name of cache root directory */
    char *secctx; /* LSM security context */
    char *tag; /* cache binding tag */
    +
    + struct idr reqs;
    + spinlock_t reqs_lock;
    };

    #include <trace/events/cachefiles.h>
    diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c
    index 95e9107dc3bb..b4f6187f4022 100644
    --- a/fs/cachefiles/io.c
    +++ b/fs/cachefiles/io.c
    @@ -540,12 +540,68 @@ static void cachefiles_end_operation(struct netfs_cache_resources *cres)
    fscache_end_cookie_access(fscache_cres_cookie(cres), fscache_access_io_end);
    }

    +static struct cachefiles_req *cachefiles_alloc_req(struct cachefiles_object *object,
    + loff_t start_pos,
    + size_t len)
    +{
    + struct cachefiles_req *req;
    + struct cachefiles_req_in *req_in;
    +
    + req = kzalloc(sizeof(*req), GFP_KERNEL);
    + if (!req)
    + return NULL;
    +
    + req_in = &req->req_in;
    +
    + req_in->off = start_pos;
    + req_in->len = len;
    + strncpy(req_in->path, object->d_name, sizeof(req_in->path));
    +
    + init_completion(&req->done);
    +
    + return req;
    +}
    +
    +int cachefiles_demand_read(struct netfs_cache_resources *cres,
    + loff_t start_pos, size_t len)
    +{
    + struct cachefiles_object *object;
    + struct cachefiles_cache *cache;
    + struct cachefiles_req *req;
    + int ret;
    +
    + object = cachefiles_cres_object(cres);
    + cache = object->volume->cache;
    +
    + req = cachefiles_alloc_req(object, start_pos, len);
    + if (!req)
    + return -ENOMEM;
    +
    + spin_lock(&cache->reqs_lock);
    + ret = idr_alloc(&cache->reqs, req, 0, 0, GFP_KERNEL);
    + if (ret >= 0)
    + req->req_in.id = ret;
    + spin_unlock(&cache->reqs_lock);
    + if (ret < 0) {
    + kfree(req);
    + return -ENOMEM;
    + }
    +
    + wake_up_all(&cache->daemon_pollwq);
    +
    + wait_for_completion(&req->done);
    + kfree(req);
    +
    + return 0;
    +}
    +
    static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
    .end_operation = cachefiles_end_operation,
    .read = cachefiles_read,
    .write = cachefiles_write,
    .prepare_read = cachefiles_prepare_read,
    .prepare_write = cachefiles_prepare_write,
    + .demand_read = cachefiles_demand_read,
    };

    /*
    --
    2.27.0
    \
     
     \ /
      Last update: 2021-12-10 08:38    [W:4.253 / U:0.092 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site