Re: [Linux-cachefs] [PATCH 06/12] fscache: Detect multiple relinquishment of a cookie

2018-04-04 Thread Linus Torvalds
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

2018-04-04 Thread David Howells
> 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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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()

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells
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

2018-04-04 Thread David Howells

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

2018-04-04 Thread David Howells
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