aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-02-01 11:43:04 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2016-02-01 12:30:10 -0500
commita5b3a80b899bda0f456f1246c4c5a1191ea01519 (patch)
treeb83e19613c5b5dfcf0311afef7d25e61b727bf74
parent92e963f50fc74041b5e9e744c330dca48e04f08d (diff)
CacheFiles: Provide read-and-reset release counters for cachefilesd
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@redhat.com> Reviewed-by: Steve Dickson <steved@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/cachefiles/daemon.c13
-rw-r--r--fs/cachefiles/interface.c11
-rw-r--r--fs/cachefiles/internal.h4
-rw-r--r--fs/cachefiles/namei.c28
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,
162 size_t buflen, loff_t *pos) 162 size_t buflen, loff_t *pos)
163{ 163{
164 struct cachefiles_cache *cache = file->private_data; 164 struct cachefiles_cache *cache = file->private_data;
165 unsigned long long b_released;
166 unsigned f_released;
165 char buffer[256]; 167 char buffer[256];
166 int n; 168 int n;
167 169
@@ -174,6 +176,8 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
174 cachefiles_has_space(cache, 0, 0); 176 cachefiles_has_space(cache, 0, 0);
175 177
176 /* summarise */ 178 /* summarise */
179 f_released = atomic_xchg(&cache->f_released, 0);
180 b_released = atomic_long_xchg(&cache->b_released, 0);
177 clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags); 181 clear_bit(CACHEFILES_STATE_CHANGED, &cache->flags);
178 182
179 n = snprintf(buffer, sizeof(buffer), 183 n = snprintf(buffer, sizeof(buffer),
@@ -183,15 +187,18 @@ static ssize_t cachefiles_daemon_read(struct file *file, char __user *_buffer,
183 " fstop=%llx" 187 " fstop=%llx"
184 " brun=%llx" 188 " brun=%llx"
185 " bcull=%llx" 189 " bcull=%llx"
186 " bstop=%llx", 190 " bstop=%llx"
191 " freleased=%x"
192 " breleased=%llx",
187 test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0', 193 test_bit(CACHEFILES_CULLING, &cache->flags) ? '1' : '0',
188 (unsigned long long) cache->frun, 194 (unsigned long long) cache->frun,
189 (unsigned long long) cache->fcull, 195 (unsigned long long) cache->fcull,
190 (unsigned long long) cache->fstop, 196 (unsigned long long) cache->fstop,
191 (unsigned long long) cache->brun, 197 (unsigned long long) cache->brun,
192 (unsigned long long) cache->bcull, 198 (unsigned long long) cache->bcull,
193 (unsigned long long) cache->bstop 199 (unsigned long long) cache->bstop,
194 ); 200 f_released,
201 b_released);
195 202
196 if (n > buflen) 203 if (n > buflen)
197 return -EMSGSIZE; 204 return -EMSGSIZE;
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index 675a3332d72f..861d611b8c05 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -291,15 +291,8 @@ static void cachefiles_drop_object(struct fscache_object *_object)
291 } 291 }
292 292
293 /* note that the object is now inactive */ 293 /* note that the object is now inactive */
294 if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { 294 if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags))
295 write_lock(&cache->active_lock); 295 cachefiles_mark_object_inactive(cache, object);
296 if (!test_and_clear_bit(CACHEFILES_OBJECT_ACTIVE,
297 &object->flags))
298 BUG();
299 rb_erase(&object->active_node, &cache->active_nodes);
300 wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
301 write_unlock(&cache->active_lock);
302 }
303 296
304 dput(object->dentry); 297 dput(object->dentry);
305 object->dentry = NULL; 298 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 {
66 struct rb_root active_nodes; /* active nodes (can't be culled) */ 66 struct rb_root active_nodes; /* active nodes (can't be culled) */
67 rwlock_t active_lock; /* lock for active_nodes */ 67 rwlock_t active_lock; /* lock for active_nodes */
68 atomic_t gravecounter; /* graveyard uniquifier */ 68 atomic_t gravecounter; /* graveyard uniquifier */
69 atomic_t f_released; /* number of objects released lately */
70 atomic_long_t b_released; /* number of blocks released lately */
69 unsigned frun_percent; /* when to stop culling (% files) */ 71 unsigned frun_percent; /* when to stop culling (% files) */
70 unsigned fcull_percent; /* when to start culling (% files) */ 72 unsigned fcull_percent; /* when to start culling (% files) */
71 unsigned fstop_percent; /* when to stop allocating (% files) */ 73 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);
157/* 159/*
158 * namei.c 160 * namei.c
159 */ 161 */
162extern void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
163 struct cachefiles_object *object);
160extern int cachefiles_delete_object(struct cachefiles_cache *cache, 164extern int cachefiles_delete_object(struct cachefiles_cache *cache,
161 struct cachefiles_object *object); 165 struct cachefiles_object *object);
162extern int cachefiles_walk_to_object(struct cachefiles_object *parent, 166extern int cachefiles_walk_to_object(struct cachefiles_object *parent,
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 1c2334c163dd..4ae75006e73b 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -258,6 +258,28 @@ requeue:
258} 258}
259 259
260/* 260/*
261 * Mark an object as being inactive.
262 */
263void cachefiles_mark_object_inactive(struct cachefiles_cache *cache,
264 struct cachefiles_object *object)
265{
266 write_lock(&cache->active_lock);
267 rb_erase(&object->active_node, &cache->active_nodes);
268 clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
269 write_unlock(&cache->active_lock);
270
271 wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
272
273 /* This object can now be culled, so we need to let the daemon know
274 * that there is something it can remove if it needs to.
275 */
276 atomic_long_add(d_backing_inode(object->dentry)->i_blocks,
277 &cache->b_released);
278 if (atomic_inc_return(&cache->f_released))
279 cachefiles_state_changed(cache);
280}
281
282/*
261 * delete an object representation from the cache 283 * delete an object representation from the cache
262 * - file backed objects are unlinked 284 * - file backed objects are unlinked
263 * - directory backed objects are stuffed into the graveyard for userspace to 285 * - directory backed objects are stuffed into the graveyard for userspace to
@@ -684,11 +706,7 @@ mark_active_timed_out:
684 706
685check_error: 707check_error:
686 _debug("check error %d", ret); 708 _debug("check error %d", ret);
687 write_lock(&cache->active_lock); 709 cachefiles_mark_object_inactive(cache, object);
688 rb_erase(&object->active_node, &cache->active_nodes);
689 clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags);
690 wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
691 write_unlock(&cache->active_lock);
692release_dentry: 710release_dentry:
693 dput(object->dentry); 711 dput(object->dentry);
694 object->dentry = NULL; 712 object->dentry = NULL;