[Linux-cachefs] [PATCH] CacheFiles: Provide read-and-reset release counters for cachefilesd
Steve Dickson
SteveD at redhat.com
Wed Jan 27 16:39:34 UTC 2016
On 01/25/2016 11:41 AM, David Howells wrote:
> Provide read-and-reset objects- and blocks-released counters for cachefilesd
> to use to work out whether there's anything new that can be culled.
>
> One of the problems cachefilesd has is that if all the objects in the cache
> are pinned by inodes lying dormant in the kernel inode cache, there isn't
> anything for it to cull. In such a case, it just spins around walking the
> filesystem tree and scanning for something to cull. This eats up a lot of
> CPU time.
>
> By telling cachefilesd if there have been any releases, the daemon can
> sleep until there is the possibility of something to do.
>
> cachefilesd finds this information by the following means:
>
> (1) When the control fd is read, the kernel presents a list of values of
> interest. "freleased=N" and "breleased=N" are added to this list to
> indicate the number of files released and number of blocks released
> since the last read call. At this point the counters are reset.
>
> (2) POLLIN is signalled if the number of files released becomes greater
> than 0.
>
> Note that by 'released' it just means that the kernel has released its
> interest in those files for the moment, not necessarily that the files
> should be deleted from the cache.
>
> Signed-off-by: David Howells <dhowells at redhat.com>
Reviewed-by: Steve Dickson <steved at redhat.com>
steved.
> ---
>
> fs/cachefiles/daemon.c | 13 ++++++++++---
> fs/cachefiles/interface.c | 11 ++---------
> fs/cachefiles/internal.h | 4 ++++
> fs/cachefiles/namei.c | 28 +++++++++++++++++++++++-----
> 4 files changed, 39 insertions(+), 17 deletions(-)
>
> diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c
> index 452e98dd7560..1ee54ffd3a24 100644
> --- a/fs/cachefiles/daemon.c
> +++ b/fs/cachefiles/daemon.c
> @@ -162,6 +162,8 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
> size_t buflen, loff_t *pos)
> {
> struct cachefiles_cache *cache = file->private_data;
> + unsigned long long b_released;
> + unsigned f_released;
> char buffer[256];
> int n;
>
> @@ -174,6 +176,8 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
> cachefiles_has_space(cache, 0, 0);
>
> /* 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),
> @@ -183,15 +187,18 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
> " fstop=%llx"
> " brun=%llx"
> " bcull=%llx"
> - " bstop=%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
> - );
> + (unsigned long long) cache->bstop,
> + f_released,
> + b_released);
>
> if (n > buflen)
> return -EMSGSIZE;
> diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
> index afa023dded5b..ee0cb116ff40 100644
> --- a/fs/cachefiles/interface.c
> +++ b/fs/cachefiles/interface.c
> @@ -291,15 +291,8 @@ static void cachefiles_drop_object(struct fscache_object *_object)
> }
>
> /* note that the object is now inactive */
> - if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) {
> - write_lock(&cache->active_lock);
> - if (!test_and_clear_bit(CACHEFILES_OBJECT_ACTIVE,
> - &object->flags))
> - BUG();
> - rb_erase(&object->active_node, &cache->active_nodes);
> - wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
> - write_unlock(&cache->active_lock);
> - }
> + if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags))
> + cachefiles_mark_object_inactive(cache, object);
>
> dput(object->dentry);
> object->dentry = NULL;
> diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
> index 9c4b737a54df..2fcde1a34b7c 100644
> --- a/fs/cachefiles/internal.h
> +++ b/fs/cachefiles/internal.h
> @@ -66,6 +66,8 @@ struct cachefiles_cache {
> struct rb_root active_nodes; /* active nodes (can't be culled) */
> rwlock_t active_lock; /* lock for active_nodes */
> atomic_t gravecounter; /* graveyard uniquifier */
> + atomic_t f_released; /* number of objects released lately */
> + atomic_long_t b_released; /* number of blocks released lately */
> unsigned frun_percent; /* when to stop culling (% files) */
> unsigned fcull_percent; /* when to start culling (% files) */
> unsigned fstop_percent; /* when to stop allocating (% files) */
> @@ -157,6 +159,8 @@ extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type);
> /*
> * namei.c
> */
> +extern void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
> + struct cachefiles_object *object);
> extern int cachefiles_delete_object(struct cachefiles_cache *cache,
> struct cachefiles_object *object);
> extern int cachefiles_walk_to_object(struct cachefiles_object *parent,
> diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
> index c4b893453e0e..1ad16ae7ab96 100644
> --- a/fs/cachefiles/namei.c
> +++ b/fs/cachefiles/namei.c
> @@ -258,6 +258,28 @@ requeue:
> }
>
> /*
> + * Mark an object as being inactive.
> + */
> +void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
> + struct cachefiles_object *object)
> +{
> + write_lock(&cache->active_lock);
> + rb_erase(&object->active_node, &cache->active_nodes);
> + clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
> + write_unlock(&cache->active_lock);
> +
> + wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
> +
> + /* This object can now be culled, so we need to let the daemon know
> + * that there is something it can remove if it needs to.
> + */
> + atomic_long_add(d_backing_inode(object->dentry)->i_blocks,
> + &cache->b_released);
> + if (atomic_inc_return(&cache->f_released))
> + cachefiles_state_changed(cache);
> +}
> +
> +/*
> * delete an object representation from the cache
> * - file backed objects are unlinked
> * - directory backed objects are stuffed into the graveyard for userspace to
> @@ -684,11 +706,7 @@ mark_active_timed_out:
>
> check_error:
> _debug("check error %d", ret);
> - write_lock(&cache->active_lock);
> - rb_erase(&object->active_node, &cache->active_nodes);
> - clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
> - wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
> - write_unlock(&cache->active_lock);
> + cachefiles_mark_object_inactive(cache, object);
> release_dentry:
> dput(object->dentry);
> object->dentry = NULL;
>
More information about the Linux-cachefs
mailing list