Re: [Linux-cachefs] [PATCH 06/12] fscache: Detect multiple relinquishment of a cookie
On Wed, Apr 4, 2018 at 3:07 PM, David Howells wrote: > Report if an fscache cookie is relinquished multiple times by the netfs. > > - set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); > + if (test_and_set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) > + BUG(); Ugh. Please try to avoid adding BUG() calls for reporting. They can often cause the machine to be basically dead. This one seem fairly ok, simply because it looks like the only caller doesn't really hold a lot of locks (the superblock s_umount lock, but that may be all). So I'll pull this change, I just wanted people to realize that if this is a "help make sure we notice if things go wrong", then "WARN_ON_ONCE()" or something is usually a better choice than "potentially kill the machine and make it harder to actually see the error". Linus -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
Re: [Linux-cachefs] [PATCH net-next 00/12] fscache: Fixes, traces and development
> Subject: [PATCH net-next 00/12] fscache: Fixes, traces and development Apologies: that shouldn't say net-next in there. Cut'n'paste error. David -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH 11/12] fscache: Pass object size in rather than calling back for it
Pass the object size in to fscache_acquire_cookie() and fscache_write_page() rather than the netfs providing a callback by which it can be received. This makes it easier to update the size of the object when a new page is written that extends the object. The current object size is also passed by fscache to the check_aux function, obviating the need to store it in the aux data. Signed-off-by: David Howells Acked-by: Anna Schumaker Tested-by: Steve Dickson --- Documentation/filesystems/caching/netfs-api.txt | 61 --- fs/9p/cache.c | 27 -- fs/afs/cache.c | 24 ++--- fs/afs/cell.c |2 - fs/afs/file.c |6 ++ fs/afs/inode.c |2 - fs/afs/volume.c |2 - fs/cachefiles/interface.c |5 +- fs/cachefiles/xattr.c |6 ++ fs/ceph/cache.c | 26 +++--- fs/cifs/cache.c | 15 ++ fs/cifs/fscache.c | 14 +++-- fs/fscache/cookie.c | 18 +++ fs/fscache/fsdef.c |6 ++ fs/fscache/object.c |5 +- fs/fscache/page.c |5 ++ fs/nfs/fscache-index.c | 19 +-- fs/nfs/fscache.c| 14 ++--- fs/nfs/fscache.h|1 include/linux/fscache-cache.h |3 + include/linux/fscache.h | 32 ++-- 21 files changed, 127 insertions(+), 166 deletions(-) diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index 332840ad4151..2a6f7399c1f3 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt @@ -129,12 +129,10 @@ To define an object, a structure of the following type should be filled out: const void *parent_netfs_data, const void *cookie_netfs_data); - void (*get_attr)(const void *cookie_netfs_data, -uint64_t *size); - enum fscache_checkaux (*check_aux)(void *cookie_netfs_data, const void *data, - uint16_t datalen); + uint16_t datalen, + loff_t object_size); void (*get_context)(void *cookie_netfs_data, void *context); @@ -179,16 +177,7 @@ This has the following fields: cache in the parent's list will be chosen, or failing that, the first cache in the master list. - (4) A function to retrieve attribute data from the netfs [optional]. - - This function will be called with the netfs data that was passed to the - cookie acquisition function. It should return the size of the file if - this is a data file. The size may be used to govern how much cache must - be reserved for this file in the cache. - - If the function is absent, a file size of 0 is assumed. - - (5) A function to check the auxiliary data [optional]. + (4) A function to check the auxiliary data [optional]. This function will be called to check that a match found in the cache for this object is valid. For instance with AFS it could check the auxiliary @@ -198,6 +187,9 @@ This has the following fields: If this function is absent, it will be assumed that matching objects in a cache are always valid. + The function is also passed the cache's idea of the object size and may + use this to manage coherency also. + If present, the function should return one of the following values: (*) FSCACHE_CHECKAUX_OKAY - the entry is okay as is @@ -207,7 +199,7 @@ This has the following fields: This function can also be used to extract data from the auxiliary data in the cache and copy it into the netfs's structures. - (6) A pair of functions to manage contexts for the completion callback + (5) A pair of functions to manage contexts for the completion callback [optional]. The cache read/write functions are passed a context which is then passed @@ -221,7 +213,7 @@ This has the following fields: required for indices as indices may not contain data. These functions may be called in interrupt context and so may not sleep. - (7) A function to mark a page as retaining cache metadata [optional]. + (6) A function to mark a page as retaining cache metadata [optional]. This is called by the cache to indicate that it is retaining in-memor
[Linux-cachefs] [PATCH 12/12] fscache: Maintain a catalogue of allocated cookies
Maintain a catalogue of allocated cookies so that cookie collisions can be handled properly. For the moment, this just involves printing a warning and returning a NULL cookie to the caller of fscache_acquire_cookie(), but in future it might make sense to wait for the old cookie to finish being cleaned up. This requires the cookie key to be stored attached to the cookie so that we still have the key available if the netfs relinquishes the cookie. This is done by an earlier patch. Signed-off-by: David Howells Acked-by: Anna Schumaker Tested-by: Steve Dickson --- fs/fscache/cookie.c| 294 fs/fscache/internal.h |6 + fs/fscache/netfs.c | 36 + include/linux/fscache.h|7 + include/trace/events/fscache.h |6 + 5 files changed, 262 insertions(+), 87 deletions(-) diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 8ca9a932d225..62b1f0f46b11 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -21,6 +21,9 @@ struct kmem_cache *fscache_cookie_jar; static atomic_t fscache_object_debug_id = ATOMIC_INIT(0); +#define fscache_cookie_hash_shift 15 +static struct hlist_bl_head fscache_cookie_hash[1 << fscache_cookie_hash_shift]; + static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie, loff_t object_size); static int fscache_alloc_object(struct fscache_cache *cache, @@ -28,6 +31,44 @@ static int fscache_alloc_object(struct fscache_cache *cache, static int fscache_attach_object(struct fscache_cookie *cookie, struct fscache_object *object); +static void fscache_print_cookie(struct fscache_cookie *cookie, char prefix) +{ + struct hlist_node *object; + const u8 *k; + unsigned loop; + + pr_err("%c-cookie c=%p [p=%p fl=%lx nc=%u na=%u]\n", + prefix, cookie, cookie->parent, cookie->flags, + atomic_read(&cookie->n_children), + atomic_read(&cookie->n_active)); + pr_err("%c-cookie d=%p n=%p\n", + prefix, cookie->def, cookie->netfs_data); + + object = READ_ONCE(cookie->backing_objects.first); + if (object) + pr_err("%c-cookie o=%p\n", + prefix, hlist_entry(object, struct fscache_object, cookie_link)); + + pr_err("%c-key=[%u] '", prefix, cookie->key_len); + k = (cookie->key_len <= sizeof(cookie->inline_key)) ? + cookie->inline_key : cookie->key; + for (loop = 0; loop < cookie->key_len; loop++) + pr_cont("%02x", k[loop]); + pr_cont("'\n"); +} + +void fscache_free_cookie(struct fscache_cookie *cookie) +{ + if (cookie) { + BUG_ON(!hlist_empty(&cookie->backing_objects)); + if (cookie->aux_len > sizeof(cookie->inline_aux)) + kfree(cookie->aux); + if (cookie->key_len > sizeof(cookie->inline_key)) + kfree(cookie->key); + kmem_cache_free(fscache_cookie_jar, cookie); + } +} + /* * initialise an cookie jar slab element prior to any use */ @@ -41,6 +82,170 @@ void fscache_cookie_init_once(void *_cookie) INIT_HLIST_HEAD(&cookie->backing_objects); } +/* + * Set the index key in a cookie. The cookie struct has space for a 12-byte + * key plus length and hash, but if that's not big enough, it's instead a + * pointer to a buffer containing 3 bytes of hash, 1 byte of length and then + * the key data. + */ +static int fscache_set_key(struct fscache_cookie *cookie, + const void *index_key, size_t index_key_len) +{ + unsigned long long h; + u32 *buf; + int i; + + cookie->key_len = index_key_len; + + if (index_key_len > sizeof(cookie->inline_key)) { + buf = kzalloc(index_key_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + cookie->key = buf; + } else { + buf = (u32 *)cookie->inline_key; + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + } + + memcpy(buf, index_key, index_key_len); + + /* Calculate a hash and combine this with the length in the first word +* or first half word +*/ + h = (unsigned long)cookie->parent; + h += index_key_len + cookie->type; + for (i = 0; i < (index_key_len + sizeof(u32) - 1) / sizeof(u32); i++) + h += buf[i]; + + cookie->key_hash = h ^ (h >> 32); + return 0; +} + +static long fscache_compare_cookie(const struct fscache_cookie *a, + const struct fscache_cookie *b) +{ + const void *ka, *kb; + + if (a->key_hash != b->key_hash) + return (long)a->key_hash - (long)b->key_hash; + if (a->parent != b->parent) + return (long)a->parent - (long)b->parent; + if (a->key_le
[Linux-cachefs] [PATCH 09/12] fscache: Add more tracepoints
Add more tracepoints to fscache, including: (*) fscache_page - Tracks netfs pages known to fscache. (*) fscache_check_page - Tracks the netfs querying whether a page is pending storage. (*) fscache_wake_cookie - Tracks cookies being woken up after a page completes/aborts storage in the cache. (*) fscache_op - Tracks operations being initialised. (*) fscache_wrote_page - Tracks return of the backend write_page op. (*) fscache_gang_lookup - Tracks lookup of pages to be stored in the write operation. Signed-off-by: David Howells --- fs/fscache/cookie.c|3 fs/fscache/object.c|3 fs/fscache/operation.c | 26 fs/fscache/page.c | 51 +++- include/linux/fscache-cache.h |3 include/trace/events/fscache.h | 252 6 files changed, 330 insertions(+), 8 deletions(-) diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 20bc3341f113..ea1f80daaff4 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -691,10 +691,11 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) if (!op) return -ENOMEM; - fscache_operation_init(op, NULL, NULL, NULL); + fscache_operation_init(cookie, op, NULL, NULL, NULL); op->flags = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING) | (1 << FSCACHE_OP_UNUSE_COOKIE); + trace_fscache_page_op(cookie, NULL, op, fscache_page_op_check_consistency); spin_lock(&cookie->lock); diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 99afe64352a5..7c0ddb7ae29a 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -982,11 +982,12 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj if (!op) goto nomem; - fscache_operation_init(op, object->cache->ops->invalidate_object, + fscache_operation_init(cookie, op, object->cache->ops->invalidate_object, NULL, NULL); op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE) | (1 << FSCACHE_OP_UNUSE_COOKIE); + trace_fscache_page_op(cookie, NULL, op, fscache_page_op_invalidate); spin_lock(&cookie->lock); if (fscache_submit_exclusive_op(object, op) < 0) diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index de67745e1cd7..7a071e1e952d 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -32,7 +32,8 @@ static void fscache_operation_dummy_cancel(struct fscache_operation *op) * Do basic initialisation of an operation. The caller must still set flags, * object and processor if needed. */ -void fscache_operation_init(struct fscache_operation *op, +void fscache_operation_init(struct fscache_cookie *cookie, + struct fscache_operation *op, fscache_operation_processor_t processor, fscache_operation_cancel_t cancel, fscache_operation_release_t release) @@ -46,6 +47,7 @@ void fscache_operation_init(struct fscache_operation *op, op->release = release; INIT_LIST_HEAD(&op->pend_link); fscache_stat(&fscache_n_op_initialised); + trace_fscache_op(cookie, op, fscache_op_init); } EXPORT_SYMBOL(fscache_operation_init); @@ -59,6 +61,8 @@ EXPORT_SYMBOL(fscache_operation_init); */ void fscache_enqueue_operation(struct fscache_operation *op) { + struct fscache_cookie *cookie = op->object->cookie; + _enter("{OBJ%x OP%x,%u}", op->object->debug_id, op->debug_id, atomic_read(&op->usage)); @@ -71,12 +75,14 @@ void fscache_enqueue_operation(struct fscache_operation *op) fscache_stat(&fscache_n_op_enqueue); switch (op->flags & FSCACHE_OP_TYPE) { case FSCACHE_OP_ASYNC: + trace_fscache_op(cookie, op, fscache_op_enqueue_async); _debug("queue async"); atomic_inc(&op->usage); if (!queue_work(fscache_op_wq, &op->work)) fscache_put_operation(op); break; case FSCACHE_OP_MYTHREAD: + trace_fscache_op(cookie, op, fscache_op_enqueue_mythread); _debug("queue for caller's attention"); break; default: @@ -101,6 +107,8 @@ static void fscache_run_op(struct fscache_object *object, wake_up_bit(&op->flags, FSCACHE_OP_WAITING); if (op->processor) fscache_enqueue_operation(op); + else + trace_fscache_op(object->cookie, op, fscache_op_run); fscache_stat(&fscache_n_op_run); } @@ -155,6 +163,8 @@ int fscache_submit_exclusive_op(struct fscache_object *object, _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); + trace_fscache_op(object->cookie, op, fscache_op_submit_ex); + ASSERTCMP(op-
[Linux-cachefs] [PATCH 10/12] fscache: Attach the index key and aux data to the cookie
Attach copies of the index key and auxiliary data to the fscache cookie so that: (1) The callbacks to the netfs for this stuff can be eliminated. This can simplify things in the cache as the information is still available, even after the cache has relinquished the cookie. (2) Simplifies the locking requirements of accessing the information as we don't have to worry about the netfs object going away on us. (3) The cache can do lazy updating of the coherency information on disk. As long as the cache is flushed before reboot/poweroff, there's no need to update the coherency info on disk every time it changes. (4) Cookies can be hashed or put in a tree as the index key is easily available. This allows: (a) Checks for duplicate cookies can be made at the top fscache layer rather than down in the bowels of the cache backend. (b) Caching can be added to a netfs object that has a cookie if the cache is brought online after the netfs object is allocated. A certain amount of space is made in the cookie for inline copies of the data, but if it won't fit there, extra memory will be allocated for it. The downside of this is that live cache operation requires more memory. Signed-off-by: David Howells Acked-by: Anna Schumaker Tested-by: Steve Dickson --- Documentation/filesystems/caching/netfs-api.txt | 106 fs/9p/cache.c | 73 +++ fs/afs/cache.c | 120 +- fs/afs/cell.c |4 - fs/afs/inode.c | 46 ++- fs/afs/internal.h |7 + fs/afs/volume.c |4 - fs/cachefiles/interface.c | 38 -- fs/cachefiles/namei.c | 33 ++--- fs/cachefiles/xattr.c |2 fs/ceph/cache.c | 93 -- fs/cifs/cache.c | 153 --- fs/cifs/fscache.c | 122 -- fs/cifs/fscache.h | 13 ++ fs/fscache/cache.c |2 fs/fscache/cookie.c | 88 ++--- fs/fscache/fsdef.c | 49 --- fs/fscache/internal.h | 21 +++ fs/fscache/netfs.c | 17 ++- fs/fscache/object-list.c| 28 ++-- fs/fscache/object.c | 22 +++ fs/fscache/operation.c |2 fs/nfs/fscache-index.c | 140 - fs/nfs/fscache.c| 83 fs/nfs/fscache.h| 16 ++ include/linux/fscache.h | 110 ++--- 26 files changed, 606 insertions(+), 786 deletions(-) diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index 0eb31de3a2c1..332840ad4151 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt @@ -129,17 +129,9 @@ To define an object, a structure of the following type should be filled out: const void *parent_netfs_data, const void *cookie_netfs_data); - uint16_t (*get_key)(const void *cookie_netfs_data, - void *buffer, - uint16_t bufmax); - void (*get_attr)(const void *cookie_netfs_data, uint64_t *size); - uint16_t (*get_aux)(const void *cookie_netfs_data, - void *buffer, - uint16_t bufmax); - enum fscache_checkaux (*check_aux)(void *cookie_netfs_data, const void *data, uint16_t datalen); @@ -187,14 +179,7 @@ This has the following fields: cache in the parent's list will be chosen, or failing that, the first cache in the master list. - (4) A function to retrieve an object's key from the netfs [mandatory]. - - This function will be called with the netfs data that was passed to the - cookie acquisition function and the maximum length of key data that it may - provide. It should write the required key data into the given buffer and - return the quantity it wrote. - - (5) A function to retrieve attribute data from the netfs [optional]. + (4) A function to retrieve attribute data from the netfs [optional]. This function will be called with the netfs data that was passed to the cookie acquisition functi
[Linux-cachefs] [PATCH 04/12] fscache, cachefiles: Fix checker warnings
Fix a couple of checker warnings in fscache and cachefiles: (1) fscache_n_op_requeue is never used, so get rid of it. (2) cachefiles_uncache_page() is passed in a lock that it releases, so this needs annotating. Signed-off-by: David Howells --- fs/cachefiles/rdwr.c |1 + fs/fscache/stats.c |1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index 883bc7bb12c5..5082c8a49686 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c @@ -952,6 +952,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page) * - cache withdrawal is prevented by the caller */ void cachefiles_uncache_page(struct fscache_object *_object, struct page *page) + __releases(&object->fscache.cookie->lock) { struct cachefiles_object *object; struct cachefiles_cache *cache; diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 7ac6e839b065..fcc8c2f2690e 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c @@ -21,7 +21,6 @@ atomic_t fscache_n_op_pend; atomic_t fscache_n_op_run; atomic_t fscache_n_op_enqueue; -atomic_t fscache_n_op_requeue; atomic_t fscache_n_op_deferred_release; atomic_t fscache_n_op_initialised; atomic_t fscache_n_op_release; -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH 07/12] fscache: Fix hanging wait on page discarded by writeback
If the fscache asynchronous write operation elects to discard a page that's pending storage to the cache because the page would be over the store limit then it needs to wake the page as someone may be waiting on completion of the write. The problem is that the store limit may be updated by a different asynchronous operation - and so may miss the write - and that the store limit may not even get updated until later by the netfs. Fix the kernel hang by making fscache_write_op() mark as written any pages that are over the limit. Signed-off-by: David Howells --- fs/fscache/page.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/fscache/page.c b/fs/fscache/page.c index adc39c0c62df..b9f18bf4227d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -778,6 +778,7 @@ static void fscache_write_op(struct fscache_operation *_op) _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); +again: spin_lock(&object->lock); cookie = object->cookie; @@ -819,10 +820,6 @@ static void fscache_write_op(struct fscache_operation *_op) goto superseded; page = results[0]; _debug("gang %d [%lx]", n, page->index); - if (page->index >= op->store_limit) { - fscache_stat(&fscache_n_store_pages_over_limit); - goto superseded; - } radix_tree_tag_set(&cookie->stores, page->index, FSCACHE_COOKIE_STORING_TAG); @@ -832,6 +829,9 @@ static void fscache_write_op(struct fscache_operation *_op) spin_unlock(&cookie->stores_lock); spin_unlock(&object->lock); + if (page->index >= op->store_limit) + goto discard_page; + fscache_stat(&fscache_n_store_pages); fscache_stat(&fscache_n_cop_write_page); ret = object->cache->ops->write_page(op, page); @@ -847,6 +847,11 @@ static void fscache_write_op(struct fscache_operation *_op) _leave(""); return; +discard_page: + fscache_stat(&fscache_n_store_pages_over_limit); + fscache_end_page_write(object, page); + goto again; + superseded: /* this writer is going away and there aren't any more things to * write */ -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH 08/12] fscache: Add tracepoints
Add some tracepoints to fscache: (*) fscache_cookie - Tracks a cookie's usage count. (*) fscache_netfs - Logs registration of a network filesystem, including the pointer to the cookie allocated. (*) fscache_acquire - Logs cookie acquisition. (*) fscache_relinquish - Logs cookie relinquishment. (*) fscache_enable - Logs enablement of a cookie. (*) fscache_disable - Logs disablement of a cookie. (*) fscache_osm - Tracks execution of states in the object state machine. and cachefiles: (*) cachefiles_ref - Tracks a cachefiles object's usage count. (*) cachefiles_lookup - Logs result of lookup_one_len(). (*) cachefiles_mkdir - Logs result of vfs_mkdir(). (*) cachefiles_create - Logs result of vfs_create(). (*) cachefiles_unlink - Logs calls to vfs_unlink(). (*) cachefiles_rename - Logs calls to vfs_rename(). (*) cachefiles_mark_active - Logs an object becoming active. (*) cachefiles_wait_active - Logs a wait for an old object to be destroyed. (*) cachefiles_mark_inactive - Logs an object becoming inactive. (*) cachefiles_mark_buried - Logs the burial of an object. Signed-off-by: David Howells --- fs/cachefiles/interface.c | 18 ++ fs/cachefiles/internal.h |2 fs/cachefiles/main.c |1 fs/cachefiles/namei.c | 42 - fs/fscache/cookie.c | 46 +++-- fs/fscache/internal.h | 16 +- fs/fscache/main.c |1 fs/fscache/netfs.c|3 fs/fscache/object.c | 36 +++- include/linux/fscache-cache.h | 18 ++ include/trace/events/cachefiles.h | 325 + include/trace/events/fscache.h| 277 12 files changed, 731 insertions(+), 54 deletions(-) create mode 100644 include/trace/events/cachefiles.h create mode 100644 include/trace/events/fscache.h diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index e7f16a77a22a..405ebc3932c2 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c @@ -177,10 +177,12 @@ static void cachefiles_lookup_complete(struct fscache_object *_object) * increment the usage count on an inode object (may fail if unmounting) */ static -struct fscache_object *cachefiles_grab_object(struct fscache_object *_object) +struct fscache_object *cachefiles_grab_object(struct fscache_object *_object, + enum fscache_obj_ref_trace why) { struct cachefiles_object *object = container_of(_object, struct cachefiles_object, fscache); + int u; _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage)); @@ -188,7 +190,9 @@ struct fscache_object *cachefiles_grab_object(struct fscache_object *_object) ASSERT((atomic_read(&object->usage) & 0x) != 0x6b6b); #endif - atomic_inc(&object->usage); + u = atomic_inc_return(&object->usage); + trace_cachefiles_ref(object, _object->cookie, +(enum cachefiles_obj_ref_trace)why, u); return &object->fscache; } @@ -309,10 +313,12 @@ static void cachefiles_drop_object(struct fscache_object *_object) /* * dispose of a reference to an object */ -static void cachefiles_put_object(struct fscache_object *_object) +static void cachefiles_put_object(struct fscache_object *_object, + enum fscache_obj_ref_trace why) { struct cachefiles_object *object; struct fscache_cache *cache; + int u; ASSERT(_object); @@ -328,7 +334,11 @@ static void cachefiles_put_object(struct fscache_object *_object) ASSERTIFCMP(object->fscache.parent, object->fscache.parent->n_children, >, 0); - if (atomic_dec_and_test(&object->usage)) { + u = atomic_dec_return(&object->usage); + trace_cachefiles_ref(object, _object->cookie, +(enum cachefiles_obj_ref_trace)why, u); + ASSERTCMP(u, !=, -1); + if (u == 0) { _debug("- kill object OBJ%x", object->fscache.debug_id); ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index bb3a02ca9da4..d2f6f996e65a 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -124,6 +124,8 @@ struct cachefiles_xattr { uint8_t data[]; }; +#include + /* * note change of state for daemon */ diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c index 711f13d8c2de..f54d3f5b2e40 100644 --- a/fs/cachefiles/main.c +++ b/fs/cachefiles/main.c @@ -22,6 +22,7 @@ #include #include #include +#define CREATE_TRACE_POINTS #include "internal.h" unsigned cachefiles_debug; diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 3978b324cbca..5fc214256316 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/na
[Linux-cachefs] [PATCH 05/12] fscache: Pass the correct cancelled indications to fscache_op_complete()
The last parameter to fscache_op_complete() is a bool indicating whether or not the operation was cancelled. A lot of the time the inverse value is given or no differentiation is made. Fix this. Signed-off-by: David Howells --- fs/fscache/page.c | 15 +-- include/linux/fscache-cache.h |2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 961029e04027..adc39c0c62df 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -185,9 +185,11 @@ static void fscache_attr_changed_op(struct fscache_operation *op) fscache_stat_d(&fscache_n_cop_attr_changed); if (ret < 0) fscache_abort_object(object); + fscache_op_complete(op, ret < 0); + } else { + fscache_op_complete(op, true); } - fscache_op_complete(op, true); _leave(""); } @@ -780,11 +782,12 @@ static void fscache_write_op(struct fscache_operation *_op) cookie = object->cookie; if (!fscache_object_is_active(object)) { - /* If we get here, then the on-disk cache object likely longer -* exists, so we should just cancel this write operation. + /* If we get here, then the on-disk cache object likely no +* longer exists, so we should just cancel this write +* operation. */ spin_unlock(&object->lock); - fscache_op_complete(&op->op, false); + fscache_op_complete(&op->op, true); _leave(" [inactive]"); return; } @@ -797,7 +800,7 @@ static void fscache_write_op(struct fscache_operation *_op) * cancel this write operation. */ spin_unlock(&object->lock); - fscache_op_complete(&op->op, false); + fscache_op_complete(&op->op, true); _leave(" [cancel] op{f=%lx s=%u} obj{s=%s f=%lx}", _op->flags, _op->state, object->state->short_name, object->flags); @@ -851,7 +854,7 @@ static void fscache_write_op(struct fscache_operation *_op) spin_unlock(&cookie->stores_lock); clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); spin_unlock(&object->lock); - fscache_op_complete(&op->op, true); + fscache_op_complete(&op->op, false); _leave(""); } diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 3b03e29e2f1a..b19fa8592fc2 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -185,7 +185,7 @@ static inline void fscache_retrieval_complete(struct fscache_retrieval *op, { atomic_sub(n_pages, &op->n_pages); if (atomic_read(&op->n_pages) <= 0) - fscache_op_complete(&op->op, true); + fscache_op_complete(&op->op, false); } /** -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH 06/12] fscache: Detect multiple relinquishment of a cookie
Report if an fscache cookie is relinquished multiple times by the netfs. Signed-off-by: David --- fs/fscache/cookie.c |3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index d705125665f0..98d22f495cd8 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -602,7 +602,8 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) atomic_read(&cookie->n_active), retire); /* No further netfs-accessing operations on this cookie permitted */ - set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); + if (test_and_set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) + BUG(); __fscache_disable_cookie(cookie, retire); -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH 02/12] afs: Use the vnode ID uniquifier in the cache key not the aux data
AFS vnodes (files) are referenced by a triplet of { volume ID, vnode ID, uniquifier }. Currently, kafs is only using the vnode ID as the file key in the volume fscache index and checking the uniquifier on cookie acquisition against the contents of the auxiliary data stored in the cache. Unfortunately, this is subject to a race in which an FS.RemoveFile or FS.RemoveDir op is issued against the server but the local afs inode isn't torn down and disposed off before another thread issues something like FS.CreateFile. The latter then gets given the vnode ID that just got removed, but with a new uniquifier and a cookie collision occurs in the cache because the cookie is only keyed on the vnode ID whereas the inode is keyed on the vnode ID plus the uniquifier. Fix this by keying the cookie on the uniquifier in addition to the vnode ID and dropping the uniquifier from the auxiliary data supplied. Signed-off-by: David Howells --- fs/afs/cache.c | 22 -- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/fs/afs/cache.c b/fs/afs/cache.c index f62ff71d28c9..cd857db9b112 100644 --- a/fs/afs/cache.c +++ b/fs/afs/cache.c @@ -29,7 +29,7 @@ static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, struct fscache_netfs afs_cache_netfs = { .name = "afs", - .version= 1, + .version= 2, }; struct fscache_cookie_def afs_cell_cache_index_def = { @@ -103,7 +103,9 @@ static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data, { const struct afs_vnode *vnode = cookie_netfs_data; struct { - u32 vnode_id[3]; + u32 vnode_id; + u32 unique; + u32 vnode_id_ext[2];/* Allow for a 96-bit key */ } __packed key; _enter("{%x,%x,%llx},%p,%u", @@ -112,9 +114,10 @@ static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data, /* Allow for a 96-bit key */ memset(&key, 0, sizeof(key)); - key.vnode_id[0] = vnode->fid.vnode; - key.vnode_id[1] = 0; - key.vnode_id[2] = 0; + key.vnode_id= vnode->fid.vnode; + key.unique = vnode->fid.unique; + key.vnode_id_ext[0] = 0; + key.vnode_id_ext[1] = 0; if (sizeof(key) > bufmax) return 0; @@ -140,7 +143,6 @@ static void afs_vnode_cache_get_attr(const void *cookie_netfs_data, struct afs_vnode_cache_aux { u64 data_version; - u32 fid_unique; } __packed; /* @@ -156,9 +158,7 @@ static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data, vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version, buffer, bufmax); - memset(&aux, 0, sizeof(aux)); aux.data_version = vnode->status.data_version; - aux.fid_unique = vnode->fid.unique; if (bufmax < sizeof(aux)) return 0; @@ -189,12 +189,6 @@ static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data, return FSCACHE_CHECKAUX_OBSOLETE; } - if (vnode->fid.unique != aux.fid_unique) { - _leave(" = OBSOLETE [uniq %x != %x]", - aux.fid_unique, vnode->fid.unique); - return FSCACHE_CHECKAUX_OBSOLETE; - } - if (vnode->status.data_version != aux.data_version) { _leave(" = OBSOLETE [vers %llx != %llx]", aux.data_version, vnode->status.data_version); -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH 03/12] afs: Be more aggressive in retiring cached vnodes
When relinquishing cookies, either due to iget failure or to inode eviction, retire a cookie if we think the corresponding vnode got deleted on the server rather than just letting it lie in the cache. Signed-off-by: David Howells --- fs/afs/inode.c |5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 42f83fd5a896..c942c79fc5f0 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -327,7 +327,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, /* failure */ bad_inode: #ifdef CONFIG_AFS_FSCACHE - fscache_relinquish_cookie(vnode->cache, 0); + fscache_relinquish_cookie(vnode->cache, ret == -ENOENT); vnode->cache = NULL; #endif iget_failed(inode); @@ -511,7 +511,8 @@ void afs_evict_inode(struct inode *inode) } #ifdef CONFIG_AFS_FSCACHE - fscache_relinquish_cookie(vnode->cache, 0); + fscache_relinquish_cookie(vnode->cache, + test_bit(AFS_VNODE_DELETED, &vnode->flags)); vnode->cache = NULL; #endif -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs
[Linux-cachefs] [PATCH net-next 00/12] fscache: Fixes, traces and development
Hi Linus, Here are some patches that fix some AFS's usage of fscache, two of which conflict with later patches in this series, so I've included them here: (1) Need to invalidate the cache if a foreign data change is detected on the server. (2) Move the vnode ID uniquifier (equivalent to i_generation) from the auxiliary data to the index key to prevent a race between file delete and a subsequent file create seeing the same index key. (3) Need to retire cookies that correspond to files that we think got deleted on the server. There are some patches to fix some things in fscache and cachefiles: (4) Fix a couple of checker warnings. (5) Correctly indicate to the end-of-operation callback whether an operation completed or was cancelled. (6) Add a check for multiple cookie relinquishment. (7) Fix a path through the asynchronous write that doesn't wake up a waiter for a page if the cache decides not to write that page, but discards it instead. There a couple of patches to add tracepoints to fscache and cachefiles: (8) Add tracepoints for cookie operators, object state machine execution, cachefiles object management and cachefiles VFS operations. (9) Add tracepoints for fscache operation management and page wrangling. And then three development patches: (10) Attach the index key and auxiliary data to the cookie, pass this information through various fscache-netfs API functions and get rid of the callbacks to the netfs to get it. This means that the cache can get at this information, even if the netfs goes away. It also means that the cache can be lazy in updating the coherency data. (11) Pass the object data size through various fscache-netfs API rather than calling back to the netfs for it, and store the value in the object. This makes it easier to correctly resize the object, as the size is updated on writes to the cache, rather than calling back out to the netfs. (12) Maintain a catalogue of allocated cookies. This makes it possible to catch cookie collision up front rather than down in the bowels of the cache being run from a service thread from the object state machine. This will also make it possible in the future to reconnect to a cookie that's not gone dead yet because it's waiting for finalisation of the storage and also make it possible to bring cookies online if the cache is added after the cookie has been obtained. The patches are tagged here: git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git tags/fscache-next-20180404 and can also be found on this branch: http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=fscache-next David --- David Howells (12): afs: Invalidate cache on server data change afs: Use the vnode ID uniquifier in the cache key not the aux data afs: Be more aggressive in retiring cached vnodes fscache, cachefiles: Fix checker warnings fscache: Pass the correct cancelled indications to fscache_op_complete() fscache: Detect multiple relinquishment of a cookie fscache: Fix hanging wait on page discarded by writeback fscache: Add tracepoints fscache: Add more tracepoints fscache: Attach the index key and aux data to the cookie fscache: Pass object size in rather than calling back for it fscache: Maintain a catalogue of allocated cookies Documentation/filesystems/caching/netfs-api.txt | 157 +++ fs/9p/cache.c | 100 +--- fs/afs/cache.c | 150 -- fs/afs/cell.c |6 fs/afs/file.c |6 fs/afs/inode.c | 49 ++ fs/afs/internal.h |7 fs/afs/volume.c |6 fs/cachefiles/interface.c | 61 ++- fs/cachefiles/internal.h|2 fs/cachefiles/main.c|1 fs/cachefiles/namei.c | 75 ++- fs/cachefiles/rdwr.c|1 fs/cachefiles/xattr.c |8 fs/ceph/cache.c | 113 + fs/cifs/cache.c | 168 --- fs/cifs/fscache.c | 130 +- fs/cifs/fscache.h | 13 + fs/fscache/cache.c |2 fs/fscache/cookie.c | 386 ++--- fs/fscache/fsdef.c | 55 -- fs/fscache/internal.h | 43 ++ fs/fscache/main.c |1 fs/fscache/netfs.c | 26 - fs/fscache/object-list.c
[Linux-cachefs] [PATCH 01/12] afs: Invalidate cache on server data change
Invalidate any data stored in fscache for a vnode that changes on the server so that we don't end up with the cache in a bad state locally. Signed-off-by: David Howells --- fs/afs/inode.c |4 1 file changed, 4 insertions(+) diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 6b39d0255b72..42f83fd5a896 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -343,6 +343,10 @@ void afs_zap_data(struct afs_vnode *vnode) { _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); +#ifdef CONFIG_AFS_FSCACHE + fscache_invalidate(vnode->cache); +#endif + /* nuke all the non-dirty pages that aren't locked, mapped or being * written back in a regular file and completely discard the pages in a * directory or symlink */ -- Linux-cachefs mailing list Linux-cachefs@redhat.com https://www.redhat.com/mailman/listinfo/linux-cachefs