<feed xmlns='http://www.w3.org/2005/Atom'>
<title>linux.git/fs/fscache/object.c, branch v4.19</title>
<subtitle>Linux kernel source tree</subtitle>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/'/>
<entry>
<title>fscache: Fix reference overput in fscache_attach_object() error handling</title>
<updated>2018-07-25T13:49:00+00:00</updated>
<author>
<name>Kiran Kumar Modukuri</name>
<email>kiran.modukuri@gmail.com</email>
</author>
<published>2018-06-21T20:31:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=f29507ce66701084c39aeb1b0ae71690cbff3554'/>
<id>f29507ce66701084c39aeb1b0ae71690cbff3554</id>
<content type='text'>
When a cookie is allocated that causes fscache_object structs to be
allocated, those objects are initialised with the cookie pointer, but
aren't blessed with a ref on that cookie unless the attachment is
successfully completed in fscache_attach_object().

If attachment fails because the parent object was dying or there was a
collision, fscache_attach_object() returns without incrementing the cookie
counter - but upon failure of this function, the object is released which
then puts the cookie, whether or not a ref was taken on the cookie.

Fix this by taking a ref on the cookie when it is assigned in
fscache_object_init(), even when we're creating a root object.


Analysis from Kiran Kumar:

This bug has been seen in 4.4.0-124-generic #148-Ubuntu kernel

BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1776277

fscache cookie ref count updated incorrectly during fscache object
allocation resulting in following Oops.

kernel BUG at /build/linux-Y09MKI/linux-4.4.0/fs/fscache/internal.h:321!
kernel BUG at /build/linux-Y09MKI/linux-4.4.0/fs/fscache/cookie.c:639!

[Cause]
Two threads are trying to do operate on a cookie and two objects.

(1) One thread tries to unmount the filesystem and in process goes over a
    huge list of objects marking them dead and deleting the objects.
    cookie-&gt;usage is also decremented in following path:

      nfs_fscache_release_super_cookie
       -&gt; __fscache_relinquish_cookie
        -&gt;__fscache_cookie_put
        -&gt;BUG_ON(atomic_read(&amp;cookie-&gt;usage) &lt;= 0);

(2) A second thread tries to lookup an object for reading data in following
    path:

    fscache_alloc_object
    1) cachefiles_alloc_object
        -&gt; fscache_object_init
           -&gt; assign cookie, but usage not bumped.
    2) fscache_attach_object -&gt; fails in cant_attach_object because the
         cookie's backing object or cookie's-&gt;parent object are going away
    3) fscache_put_object
        -&gt; cachefiles_put_object
          -&gt;fscache_object_destroy
            -&gt;fscache_cookie_put
               -&gt;BUG_ON(atomic_read(&amp;cookie-&gt;usage) &lt;= 0);

[NOTE from dhowells] It's unclear as to the circumstances in which (2) can
take place, given that thread (1) is in nfs_kill_super(), however a
conflicting NFS mount with slightly different parameters that creates a
different superblock would do it.  A backtrace from Kiran seems to show
that this is a possibility:

    kernel BUG at/build/linux-Y09MKI/linux-4.4.0/fs/fscache/cookie.c:639!
    ...
    RIP: __fscache_cookie_put+0x3a/0x40 [fscache]
    Call Trace:
     __fscache_relinquish_cookie+0x87/0x120 [fscache]
     nfs_fscache_release_super_cookie+0x2d/0xb0 [nfs]
     nfs_kill_super+0x29/0x40 [nfs]
     deactivate_locked_super+0x48/0x80
     deactivate_super+0x5c/0x60
     cleanup_mnt+0x3f/0x90
     __cleanup_mnt+0x12/0x20
     task_work_run+0x86/0xb0
     exit_to_usermode_loop+0xc2/0xd0
     syscall_return_slowpath+0x4e/0x60
     int_ret_from_sys_call+0x25/0x9f

[Fix] Bump up the cookie usage in fscache_object_init, when it is first
being assigned a cookie atomically such that the cookie is added and bumped
up if its refcount is not zero.  Remove the assignment in
fscache_attach_object().

[Testcase]
I have run ~100 hours of NFS stress tests and not seen this bug recur.

[Regression Potential]
 - Limited to fscache/cachefiles.

Fixes: ccc4fc3d11e9 ("FS-Cache: Implement the cookie management part of the netfs API")
Signed-off-by: Kiran Kumar Modukuri &lt;kiran.modukuri@gmail.com&gt;
Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When a cookie is allocated that causes fscache_object structs to be
allocated, those objects are initialised with the cookie pointer, but
aren't blessed with a ref on that cookie unless the attachment is
successfully completed in fscache_attach_object().

If attachment fails because the parent object was dying or there was a
collision, fscache_attach_object() returns without incrementing the cookie
counter - but upon failure of this function, the object is released which
then puts the cookie, whether or not a ref was taken on the cookie.

Fix this by taking a ref on the cookie when it is assigned in
fscache_object_init(), even when we're creating a root object.


Analysis from Kiran Kumar:

This bug has been seen in 4.4.0-124-generic #148-Ubuntu kernel

BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1776277

fscache cookie ref count updated incorrectly during fscache object
allocation resulting in following Oops.

kernel BUG at /build/linux-Y09MKI/linux-4.4.0/fs/fscache/internal.h:321!
kernel BUG at /build/linux-Y09MKI/linux-4.4.0/fs/fscache/cookie.c:639!

[Cause]
Two threads are trying to do operate on a cookie and two objects.

(1) One thread tries to unmount the filesystem and in process goes over a
    huge list of objects marking them dead and deleting the objects.
    cookie-&gt;usage is also decremented in following path:

      nfs_fscache_release_super_cookie
       -&gt; __fscache_relinquish_cookie
        -&gt;__fscache_cookie_put
        -&gt;BUG_ON(atomic_read(&amp;cookie-&gt;usage) &lt;= 0);

(2) A second thread tries to lookup an object for reading data in following
    path:

    fscache_alloc_object
    1) cachefiles_alloc_object
        -&gt; fscache_object_init
           -&gt; assign cookie, but usage not bumped.
    2) fscache_attach_object -&gt; fails in cant_attach_object because the
         cookie's backing object or cookie's-&gt;parent object are going away
    3) fscache_put_object
        -&gt; cachefiles_put_object
          -&gt;fscache_object_destroy
            -&gt;fscache_cookie_put
               -&gt;BUG_ON(atomic_read(&amp;cookie-&gt;usage) &lt;= 0);

[NOTE from dhowells] It's unclear as to the circumstances in which (2) can
take place, given that thread (1) is in nfs_kill_super(), however a
conflicting NFS mount with slightly different parameters that creates a
different superblock would do it.  A backtrace from Kiran seems to show
that this is a possibility:

    kernel BUG at/build/linux-Y09MKI/linux-4.4.0/fs/fscache/cookie.c:639!
    ...
    RIP: __fscache_cookie_put+0x3a/0x40 [fscache]
    Call Trace:
     __fscache_relinquish_cookie+0x87/0x120 [fscache]
     nfs_fscache_release_super_cookie+0x2d/0xb0 [nfs]
     nfs_kill_super+0x29/0x40 [nfs]
     deactivate_locked_super+0x48/0x80
     deactivate_super+0x5c/0x60
     cleanup_mnt+0x3f/0x90
     __cleanup_mnt+0x12/0x20
     task_work_run+0x86/0xb0
     exit_to_usermode_loop+0xc2/0xd0
     syscall_return_slowpath+0x4e/0x60
     int_ret_from_sys_call+0x25/0x9f

[Fix] Bump up the cookie usage in fscache_object_init, when it is first
being assigned a cookie atomically such that the cookie is added and bumped
up if its refcount is not zero.  Remove the assignment in
fscache_attach_object().

[Testcase]
I have run ~100 hours of NFS stress tests and not seen this bug recur.

[Regression Potential]
 - Limited to fscache/cachefiles.

Fixes: ccc4fc3d11e9 ("FS-Cache: Implement the cookie management part of the netfs API")
Signed-off-by: Kiran Kumar Modukuri &lt;kiran.modukuri@gmail.com&gt;
Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: use appropriate radix tree accessors</title>
<updated>2018-04-11T17:28:39+00:00</updated>
<author>
<name>Matthew Wilcox</name>
<email>mawilcox@microsoft.com</email>
</author>
<published>2018-04-10T23:36:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=e5a955419642e0842fd26e1ada6ab3328018ca16'/>
<id>e5a955419642e0842fd26e1ada6ab3328018ca16</id>
<content type='text'>
Don't open-code accesses to data structure internals.

Link: http://lkml.kernel.org/r/20180313132639.17387-7-willy@infradead.org
Signed-off-by: Matthew Wilcox &lt;mawilcox@microsoft.com&gt;
Reviewed-by: Jeff Layton &lt;jlayton@redhat.com&gt;
Cc: Darrick J. Wong &lt;darrick.wong@oracle.com&gt;
Cc: Dave Chinner &lt;david@fromorbit.com&gt;
Cc: Ryusuke Konishi &lt;konishi.ryusuke@lab.ntt.co.jp&gt;
Cc: Will Deacon &lt;will.deacon@arm.com&gt;
Signed-off-by: Andrew Morton &lt;akpm@linux-foundation.org&gt;
Signed-off-by: Linus Torvalds &lt;torvalds@linux-foundation.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Don't open-code accesses to data structure internals.

Link: http://lkml.kernel.org/r/20180313132639.17387-7-willy@infradead.org
Signed-off-by: Matthew Wilcox &lt;mawilcox@microsoft.com&gt;
Reviewed-by: Jeff Layton &lt;jlayton@redhat.com&gt;
Cc: Darrick J. Wong &lt;darrick.wong@oracle.com&gt;
Cc: Dave Chinner &lt;david@fromorbit.com&gt;
Cc: Ryusuke Konishi &lt;konishi.ryusuke@lab.ntt.co.jp&gt;
Cc: Will Deacon &lt;will.deacon@arm.com&gt;
Signed-off-by: Andrew Morton &lt;akpm@linux-foundation.org&gt;
Signed-off-by: Linus Torvalds &lt;torvalds@linux-foundation.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: Pass object size in rather than calling back for it</title>
<updated>2018-04-06T13:05:14+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2018-04-04T12:41:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=ee1235a9a06813429c201bf186397a6feeea07bf'/>
<id>ee1235a9a06813429c201bf186397a6feeea07bf</id>
<content type='text'>
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 &lt;dhowells@redhat.com&gt;
Acked-by: Anna Schumaker &lt;anna.schumaker@netapp.com&gt;
Tested-by: Steve Dickson &lt;steved@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;dhowells@redhat.com&gt;
Acked-by: Anna Schumaker &lt;anna.schumaker@netapp.com&gt;
Tested-by: Steve Dickson &lt;steved@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: Attach the index key and aux data to the cookie</title>
<updated>2018-04-04T12:41:28+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2018-04-04T12:41:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=402cb8dda949d9b8c0df20ad2527d139faad7ca1'/>
<id>402cb8dda949d9b8c0df20ad2527d139faad7ca1</id>
<content type='text'>
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 &lt;dhowells@redhat.com&gt;
Acked-by: Anna Schumaker &lt;anna.schumaker@netapp.com&gt;
Tested-by: Steve Dickson &lt;steved@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;dhowells@redhat.com&gt;
Acked-by: Anna Schumaker &lt;anna.schumaker@netapp.com&gt;
Tested-by: Steve Dickson &lt;steved@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: Add more tracepoints</title>
<updated>2018-04-04T12:41:27+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2018-04-04T12:41:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=08c2e3d087840cd1e7141b62d92f3dc897147984'/>
<id>08c2e3d087840cd1e7141b62d92f3dc897147984</id>
<content type='text'>
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 &lt;dhowells@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;dhowells@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: Add tracepoints</title>
<updated>2018-04-04T12:41:27+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2018-04-04T12:41:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=a18feb55769b705a44c4107786c4045eae2e87b6'/>
<id>a18feb55769b705a44c4107786c4045eae2e87b6</id>
<content type='text'>
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 &lt;dhowells@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;dhowells@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: Fix dead object requeue</title>
<updated>2017-01-31T18:23:09+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2017-01-31T09:45:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=e26bfebdfc0d212d366de9990a096665d5c0209a'/>
<id>e26bfebdfc0d212d366de9990a096665d5c0209a</id>
<content type='text'>
Under some circumstances, an fscache object can become queued such that it
fscache_object_work_func() can be called once the object is in the
OBJECT_DEAD state.  This results in the kernel oopsing when it tries to
invoke the handler for the state (which is hard coded to 0x2).

The way this comes about is something like the following:

 (1) The object dispatcher is processing a work state for an object.  This
     is done in workqueue context.

 (2) An out-of-band event comes in that isn't masked, causing the object to
     be queued, say EV_KILL.

 (3) The object dispatcher finishes processing the current work state on
     that object and then sees there's another event to process, so,
     without returning to the workqueue core, it processes that event too.
     It then follows the chain of events that initiates until we reach
     OBJECT_DEAD without going through a wait state (such as
     WAIT_FOR_CLEARANCE).

     At this point, object-&gt;events may be 0, object-&gt;event_mask will be 0
     and oob_event_mask will be 0.

 (4) The object dispatcher returns to the workqueue processor, and in due
     course, this sees that the object's work item is still queued and
     invokes it again.

 (5) The current state is a work state (OBJECT_DEAD), so the dispatcher
     jumps to it - resulting in an OOPS.

When I'm seeing this, the work state in (1) appears to have been either
LOOK_UP_OBJECT or CREATE_OBJECT (object-&gt;oob_table is
fscache_osm_lookup_oob).

The window for (2) is very small:

 (A) object-&gt;event_mask is cleared whilst the event dispatch process is
     underway - though there's no memory barrier to force this to the top
     of the function.

     The window, therefore is from the time the object was selected by the
     workqueue processor and made requeueable to the time the mask was
     cleared.

 (B) fscache_raise_event() will only queue the object if it manages to set
     the event bit and the corresponding event_mask bit was set.

     The enqueuement is then deferred slightly whilst we get a ref on the
     object and get the per-CPU variable for workqueue congestion.  This
     slight deferral slightly increases the probability by allowing extra
     time for the workqueue to make the item requeueable.

Handle this by giving the dead state a processor function and checking the
for the dead state address rather than seeing if the processor function is
address 0x2.  The dead state processor function can then set a flag to
indicate that it's occurred and give a warning if it occurs more than once
per object.

If this race occurs, an oops similar to the following is seen (note the RIP
value):

BUG: unable to handle kernel NULL pointer dereference at 0000000000000002
IP: [&lt;0000000000000002&gt;] 0x1
PGD 0
Oops: 0010 [#1] SMP
Modules linked in: ...
CPU: 17 PID: 16077 Comm: kworker/u48:9 Not tainted 3.10.0-327.18.2.el7.x86_64 #1
Hardware name: HP ProLiant DL380 Gen9/ProLiant DL380 Gen9, BIOS P89 12/27/2015
Workqueue: fscache_object fscache_object_work_func [fscache]
task: ffff880302b63980 ti: ffff880717544000 task.ti: ffff880717544000
RIP: 0010:[&lt;0000000000000002&gt;]  [&lt;0000000000000002&gt;] 0x1
RSP: 0018:ffff880717547df8  EFLAGS: 00010202
RAX: ffffffffa0368640 RBX: ffff880edf7a4480 RCX: dead000000200200
RDX: 0000000000000002 RSI: 00000000ffffffff RDI: ffff880edf7a4480
RBP: ffff880717547e18 R08: 0000000000000000 R09: dfc40a25cb3a4510
R10: dfc40a25cb3a4510 R11: 0000000000000400 R12: 0000000000000000
R13: ffff880edf7a4510 R14: ffff8817f6153400 R15: 0000000000000600
FS:  0000000000000000(0000) GS:ffff88181f420000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000002 CR3: 000000000194a000 CR4: 00000000001407e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Stack:
 ffffffffa0363695 ffff880edf7a4510 ffff88093f16f900 ffff8817faa4ec00
 ffff880717547e60 ffffffff8109d5db 00000000faa4ec18 0000000000000000
 ffff8817faa4ec18 ffff88093f16f930 ffff880302b63980 ffff88093f16f900
Call Trace:
 [&lt;ffffffffa0363695&gt;] ? fscache_object_work_func+0xa5/0x200 [fscache]
 [&lt;ffffffff8109d5db&gt;] process_one_work+0x17b/0x470
 [&lt;ffffffff8109e4ac&gt;] worker_thread+0x21c/0x400
 [&lt;ffffffff8109e290&gt;] ? rescuer_thread+0x400/0x400
 [&lt;ffffffff810a5acf&gt;] kthread+0xcf/0xe0
 [&lt;ffffffff810a5a00&gt;] ? kthread_create_on_node+0x140/0x140
 [&lt;ffffffff816460d8&gt;] ret_from_fork+0x58/0x90
 [&lt;ffffffff810a5a00&gt;] ? kthread_create_on_node+0x140/0x140

Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Acked-by: Jeremy McNicoll &lt;jeremymc@redhat.com&gt;
Tested-by: Frank Sorenson &lt;sorenson@redhat.com&gt;
Tested-by: Benjamin Coddington &lt;bcodding@redhat.com&gt;
Reviewed-by: Benjamin Coddington &lt;bcodding@redhat.com&gt;
Signed-off-by: Al Viro &lt;viro@zeniv.linux.org.uk&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Under some circumstances, an fscache object can become queued such that it
fscache_object_work_func() can be called once the object is in the
OBJECT_DEAD state.  This results in the kernel oopsing when it tries to
invoke the handler for the state (which is hard coded to 0x2).

The way this comes about is something like the following:

 (1) The object dispatcher is processing a work state for an object.  This
     is done in workqueue context.

 (2) An out-of-band event comes in that isn't masked, causing the object to
     be queued, say EV_KILL.

 (3) The object dispatcher finishes processing the current work state on
     that object and then sees there's another event to process, so,
     without returning to the workqueue core, it processes that event too.
     It then follows the chain of events that initiates until we reach
     OBJECT_DEAD without going through a wait state (such as
     WAIT_FOR_CLEARANCE).

     At this point, object-&gt;events may be 0, object-&gt;event_mask will be 0
     and oob_event_mask will be 0.

 (4) The object dispatcher returns to the workqueue processor, and in due
     course, this sees that the object's work item is still queued and
     invokes it again.

 (5) The current state is a work state (OBJECT_DEAD), so the dispatcher
     jumps to it - resulting in an OOPS.

When I'm seeing this, the work state in (1) appears to have been either
LOOK_UP_OBJECT or CREATE_OBJECT (object-&gt;oob_table is
fscache_osm_lookup_oob).

The window for (2) is very small:

 (A) object-&gt;event_mask is cleared whilst the event dispatch process is
     underway - though there's no memory barrier to force this to the top
     of the function.

     The window, therefore is from the time the object was selected by the
     workqueue processor and made requeueable to the time the mask was
     cleared.

 (B) fscache_raise_event() will only queue the object if it manages to set
     the event bit and the corresponding event_mask bit was set.

     The enqueuement is then deferred slightly whilst we get a ref on the
     object and get the per-CPU variable for workqueue congestion.  This
     slight deferral slightly increases the probability by allowing extra
     time for the workqueue to make the item requeueable.

Handle this by giving the dead state a processor function and checking the
for the dead state address rather than seeing if the processor function is
address 0x2.  The dead state processor function can then set a flag to
indicate that it's occurred and give a warning if it occurs more than once
per object.

If this race occurs, an oops similar to the following is seen (note the RIP
value):

BUG: unable to handle kernel NULL pointer dereference at 0000000000000002
IP: [&lt;0000000000000002&gt;] 0x1
PGD 0
Oops: 0010 [#1] SMP
Modules linked in: ...
CPU: 17 PID: 16077 Comm: kworker/u48:9 Not tainted 3.10.0-327.18.2.el7.x86_64 #1
Hardware name: HP ProLiant DL380 Gen9/ProLiant DL380 Gen9, BIOS P89 12/27/2015
Workqueue: fscache_object fscache_object_work_func [fscache]
task: ffff880302b63980 ti: ffff880717544000 task.ti: ffff880717544000
RIP: 0010:[&lt;0000000000000002&gt;]  [&lt;0000000000000002&gt;] 0x1
RSP: 0018:ffff880717547df8  EFLAGS: 00010202
RAX: ffffffffa0368640 RBX: ffff880edf7a4480 RCX: dead000000200200
RDX: 0000000000000002 RSI: 00000000ffffffff RDI: ffff880edf7a4480
RBP: ffff880717547e18 R08: 0000000000000000 R09: dfc40a25cb3a4510
R10: dfc40a25cb3a4510 R11: 0000000000000400 R12: 0000000000000000
R13: ffff880edf7a4510 R14: ffff8817f6153400 R15: 0000000000000600
FS:  0000000000000000(0000) GS:ffff88181f420000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000002 CR3: 000000000194a000 CR4: 00000000001407e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Stack:
 ffffffffa0363695 ffff880edf7a4510 ffff88093f16f900 ffff8817faa4ec00
 ffff880717547e60 ffffffff8109d5db 00000000faa4ec18 0000000000000000
 ffff8817faa4ec18 ffff88093f16f930 ffff880302b63980 ffff88093f16f900
Call Trace:
 [&lt;ffffffffa0363695&gt;] ? fscache_object_work_func+0xa5/0x200 [fscache]
 [&lt;ffffffff8109d5db&gt;] process_one_work+0x17b/0x470
 [&lt;ffffffff8109e4ac&gt;] worker_thread+0x21c/0x400
 [&lt;ffffffff8109e290&gt;] ? rescuer_thread+0x400/0x400
 [&lt;ffffffff810a5acf&gt;] kthread+0xcf/0xe0
 [&lt;ffffffff810a5a00&gt;] ? kthread_create_on_node+0x140/0x140
 [&lt;ffffffff816460d8&gt;] ret_from_fork+0x58/0x90
 [&lt;ffffffff810a5a00&gt;] ? kthread_create_on_node+0x140/0x140

Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Acked-by: Jeremy McNicoll &lt;jeremymc@redhat.com&gt;
Tested-by: Frank Sorenson &lt;sorenson@redhat.com&gt;
Tested-by: Benjamin Coddington &lt;bcodding@redhat.com&gt;
Reviewed-by: Benjamin Coddington &lt;bcodding@redhat.com&gt;
Signed-off-by: Al Viro &lt;viro@zeniv.linux.org.uk&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fscache: Clear outstanding writes when disabling a cookie</title>
<updated>2017-01-31T18:23:09+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2017-01-18T14:29:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=6bdded59c8933940ac7e5b416448276ac89d1144'/>
<id>6bdded59c8933940ac7e5b416448276ac89d1144</id>
<content type='text'>
fscache_disable_cookie() needs to clear the outstanding writes on the
cookie it's disabling because they cannot be completed after.

Without this, fscache_nfs_open_file() gets stuck because it disables the
cookie when the file is opened for writing but can't uncache the pages till
afterwards - otherwise there's a race between the open routine and anyone
who already has it open R/O and is still reading from it.

Looking in /proc/pid/stack of the offending process shows:

[&lt;ffffffffa0142883&gt;] __fscache_wait_on_page_write+0x82/0x9b [fscache]
[&lt;ffffffffa014336e&gt;] __fscache_uncache_all_inode_pages+0x91/0xe1 [fscache]
[&lt;ffffffffa01740fa&gt;] nfs_fscache_open_file+0x59/0x9e [nfs]
[&lt;ffffffffa01ccf41&gt;] nfs4_file_open+0x17f/0x1b8 [nfsv4]
[&lt;ffffffff8117350e&gt;] do_dentry_open+0x16d/0x2b7
[&lt;ffffffff811743ac&gt;] vfs_open+0x5c/0x65
[&lt;ffffffff81184185&gt;] path_openat+0x785/0x8fb
[&lt;ffffffff81184343&gt;] do_filp_open+0x48/0x9e
[&lt;ffffffff81174710&gt;] do_sys_open+0x13b/0x1cb
[&lt;ffffffff811747b9&gt;] SyS_open+0x19/0x1b
[&lt;ffffffff81001c44&gt;] do_syscall_64+0x80/0x17a
[&lt;ffffffff8165c2da&gt;] return_from_SYSCALL_64+0x0/0x7a
[&lt;ffffffffffffffff&gt;] 0xffffffffffffffff

Reported-by: Jianhong Yin &lt;jiyin@redhat.com&gt;
Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Acked-by: Jeff Layton &lt;jlayton@redhat.com&gt;
Acked-by: Steve Dickson &lt;steved@redhat.com&gt;
Signed-off-by: Al Viro &lt;viro@zeniv.linux.org.uk&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
fscache_disable_cookie() needs to clear the outstanding writes on the
cookie it's disabling because they cannot be completed after.

Without this, fscache_nfs_open_file() gets stuck because it disables the
cookie when the file is opened for writing but can't uncache the pages till
afterwards - otherwise there's a race between the open routine and anyone
who already has it open R/O and is still reading from it.

Looking in /proc/pid/stack of the offending process shows:

[&lt;ffffffffa0142883&gt;] __fscache_wait_on_page_write+0x82/0x9b [fscache]
[&lt;ffffffffa014336e&gt;] __fscache_uncache_all_inode_pages+0x91/0xe1 [fscache]
[&lt;ffffffffa01740fa&gt;] nfs_fscache_open_file+0x59/0x9e [nfs]
[&lt;ffffffffa01ccf41&gt;] nfs4_file_open+0x17f/0x1b8 [nfsv4]
[&lt;ffffffff8117350e&gt;] do_dentry_open+0x16d/0x2b7
[&lt;ffffffff811743ac&gt;] vfs_open+0x5c/0x65
[&lt;ffffffff81184185&gt;] path_openat+0x785/0x8fb
[&lt;ffffffff81184343&gt;] do_filp_open+0x48/0x9e
[&lt;ffffffff81174710&gt;] do_sys_open+0x13b/0x1cb
[&lt;ffffffff811747b9&gt;] SyS_open+0x19/0x1b
[&lt;ffffffff81001c44&gt;] do_syscall_64+0x80/0x17a
[&lt;ffffffff8165c2da&gt;] return_from_SYSCALL_64+0x0/0x7a
[&lt;ffffffffffffffff&gt;] 0xffffffffffffffff

Reported-by: Jianhong Yin &lt;jiyin@redhat.com&gt;
Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Acked-by: Jeff Layton &lt;jlayton@redhat.com&gt;
Acked-by: Steve Dickson &lt;steved@redhat.com&gt;
Signed-off-by: Al Viro &lt;viro@zeniv.linux.org.uk&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>FS-Cache: The operation cancellation method needs calling in more places</title>
<updated>2015-04-02T13:28:53+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2015-02-24T10:05:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=d3b97ca4a99e4e6c78f5a21c968eadf5c8ba9971'/>
<id>d3b97ca4a99e4e6c78f5a21c968eadf5c8ba9971</id>
<content type='text'>
Any time an incomplete operation is cancelled, the operation cancellation
function needs to be called to clean up.  This is currently being passed
directly to some of the functions that might want to call it, but not all.

Instead, pass the cancellation method pointer to the fscache_operation_init()
and have that cache it in the operation struct.  Further, plug in a dummy
cancellation handler if the caller declines to set one as this allows us to
call the function unconditionally (the extra overhead isn't worth bothering
about as we don't expect to be calling this typically).

The cancellation method must thence be called everywhere the CANCELLED state
is set.  Note that we call it *before* setting the CANCELLED state such that
the method can use the old state value to guide its operation.

fscache_do_cancel_retrieval() needs moving higher up in the sources so that
the init function can use it now.

Without this, the following oops may be seen:

	FS-Cache: Assertion failed
	FS-Cache: 3 == 0 is false
	------------[ cut here ]------------
	kernel BUG at ../fs/fscache/page.c:261!
	...
	RIP: 0010:[&lt;ffffffffa0089c1b&gt;]  fscache_release_retrieval_op+0x77/0x100
	 [&lt;ffffffffa008853d&gt;] fscache_put_operation+0x114/0x2da
	 [&lt;ffffffffa008b8c2&gt;] __fscache_read_or_alloc_pages+0x358/0x3b3
	 [&lt;ffffffffa00b761f&gt;] __nfs_readpages_from_fscache+0x59/0xbf [nfs]
	 [&lt;ffffffffa00b06c5&gt;] nfs_readpages+0x10c/0x185 [nfs]
	 [&lt;ffffffff81124925&gt;] ? alloc_pages_current+0x119/0x13e
	 [&lt;ffffffff810ee5fd&gt;] ? __page_cache_alloc+0xfb/0x10a
	 [&lt;ffffffff810f87f8&gt;] __do_page_cache_readahead+0x188/0x22c
	 [&lt;ffffffff810f8b3a&gt;] ondemand_readahead+0x29e/0x2af
	 [&lt;ffffffff810f8c92&gt;] page_cache_sync_readahead+0x38/0x3a
	 [&lt;ffffffff810ef337&gt;] generic_file_read_iter+0x1a2/0x55a
	 [&lt;ffffffffa00a9dff&gt;] ? nfs_revalidate_mapping+0xd6/0x288 [nfs]
	 [&lt;ffffffffa00a6a23&gt;] nfs_file_read+0x49/0x70 [nfs]
	 [&lt;ffffffff811363be&gt;] new_sync_read+0x78/0x9c
	 [&lt;ffffffff81137164&gt;] __vfs_read+0x13/0x38
	 [&lt;ffffffff8113721e&gt;] vfs_read+0x95/0x121
	 [&lt;ffffffff811372f6&gt;] SyS_read+0x4c/0x8a
	 [&lt;ffffffff81557a52&gt;] system_call_fastpath+0x12/0x17

The assertion is showing that the remaining number of pages (n_pages) is not 0
when the operation is being released.

Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Reviewed-by: Steve Dickson &lt;steved@redhat.com&gt;
Acked-by: Jeff Layton &lt;jeff.layton@primarydata.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Any time an incomplete operation is cancelled, the operation cancellation
function needs to be called to clean up.  This is currently being passed
directly to some of the functions that might want to call it, but not all.

Instead, pass the cancellation method pointer to the fscache_operation_init()
and have that cache it in the operation struct.  Further, plug in a dummy
cancellation handler if the caller declines to set one as this allows us to
call the function unconditionally (the extra overhead isn't worth bothering
about as we don't expect to be calling this typically).

The cancellation method must thence be called everywhere the CANCELLED state
is set.  Note that we call it *before* setting the CANCELLED state such that
the method can use the old state value to guide its operation.

fscache_do_cancel_retrieval() needs moving higher up in the sources so that
the init function can use it now.

Without this, the following oops may be seen:

	FS-Cache: Assertion failed
	FS-Cache: 3 == 0 is false
	------------[ cut here ]------------
	kernel BUG at ../fs/fscache/page.c:261!
	...
	RIP: 0010:[&lt;ffffffffa0089c1b&gt;]  fscache_release_retrieval_op+0x77/0x100
	 [&lt;ffffffffa008853d&gt;] fscache_put_operation+0x114/0x2da
	 [&lt;ffffffffa008b8c2&gt;] __fscache_read_or_alloc_pages+0x358/0x3b3
	 [&lt;ffffffffa00b761f&gt;] __nfs_readpages_from_fscache+0x59/0xbf [nfs]
	 [&lt;ffffffffa00b06c5&gt;] nfs_readpages+0x10c/0x185 [nfs]
	 [&lt;ffffffff81124925&gt;] ? alloc_pages_current+0x119/0x13e
	 [&lt;ffffffff810ee5fd&gt;] ? __page_cache_alloc+0xfb/0x10a
	 [&lt;ffffffff810f87f8&gt;] __do_page_cache_readahead+0x188/0x22c
	 [&lt;ffffffff810f8b3a&gt;] ondemand_readahead+0x29e/0x2af
	 [&lt;ffffffff810f8c92&gt;] page_cache_sync_readahead+0x38/0x3a
	 [&lt;ffffffff810ef337&gt;] generic_file_read_iter+0x1a2/0x55a
	 [&lt;ffffffffa00a9dff&gt;] ? nfs_revalidate_mapping+0xd6/0x288 [nfs]
	 [&lt;ffffffffa00a6a23&gt;] nfs_file_read+0x49/0x70 [nfs]
	 [&lt;ffffffff811363be&gt;] new_sync_read+0x78/0x9c
	 [&lt;ffffffff81137164&gt;] __vfs_read+0x13/0x38
	 [&lt;ffffffff8113721e&gt;] vfs_read+0x95/0x121
	 [&lt;ffffffff811372f6&gt;] SyS_read+0x4c/0x8a
	 [&lt;ffffffff81557a52&gt;] system_call_fastpath+0x12/0x17

The assertion is showing that the remaining number of pages (n_pages) is not 0
when the operation is being released.

Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Reviewed-by: Steve Dickson &lt;steved@redhat.com&gt;
Acked-by: Jeff Layton &lt;jeff.layton@primarydata.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>FS-Cache: Synchronise object death state change vs operation submission</title>
<updated>2015-04-02T13:28:53+00:00</updated>
<author>
<name>David Howells</name>
<email>dhowells@redhat.com</email>
</author>
<published>2015-02-24T10:05:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.tavy.me/linux.git/commit/?id=f09b443d0e09f37121c55d7f83056f6ebff6ab4f'/>
<id>f09b443d0e09f37121c55d7f83056f6ebff6ab4f</id>
<content type='text'>
When an object is being marked as no longer live, do this under the object
spinlock to prevent a race with operation submission targeted on that object.

The problem occurs due to the following pair of intertwined sequences when the
cache tries to create an object that would take it over the hard available
space limit:

 NETFS INTERFACE
 ===============
 (A) The netfs calls fscache_acquire_cookie().  object creation is deferred to
     the object state machine and the netfs is allowed to continue.

	OBJECT STATE MACHINE KTHREAD
	============================
	(1) The object is looked up on disk by fscache_look_up_object()
	    calling cachefiles_walk_to_object().  The latter finds that the
	    object is not yet represented on disk and calls
	    fscache_object_lookup_negative().

	(2) fscache_object_lookup_negative() sets FSCACHE_COOKIE_NO_DATA_YET
	    and clears FSCACHE_COOKIE_LOOKING_UP, thus allowing the netfs to
	    start queuing read operations.

 (B) The netfs calls fscache_read_or_alloc_pages().  This calls
     fscache_wait_for_deferred_lookup() which sees FSCACHE_COOKIE_LOOKING_UP
     become clear, allowing the read to begin.

 (C) A read operation is set up and passed to fscache_submit_op() to deal
     with.

	(3) cachefiles_walk_to_object() calls cachefiles_has_space(), which
	    fails (or one of the file operations to create stuff fails).
	    cachefiles returns an error to fscache.

	(4) fscache_look_up_object() transits to the LOOKUP_FAILURE state,

	(5) fscache_lookup_failure() sets FSCACHE_OBJECT_LOOKED_UP and
	    FSCACHE_COOKIE_UNAVAILABLE and clears FSCACHE_COOKIE_LOOKING_UP
	    then transits to the KILL_OBJECT state.

	(6) fscache_kill_object() clears FSCACHE_OBJECT_IS_LIVE in an attempt
	    to reject any further requests from the netfs.

	(7) object-&gt;n_ops is examined and found to be 0.
	    fscache_kill_object() transits to the DROP_OBJECT state.

 (D) fscache_submit_op() locks the object spinlock, sees if it can dispatch
     the op immediately by calling fscache_object_is_active() - which fails
     since FSCACHE_OBJECT_IS_AVAILABLE has not yet been set.

 (E) fscache_submit_op() then tests FSCACHE_OBJECT_LOOKED_UP - which is set.
     It then queues the object and increments object-&gt;n_ops.

	(8) fscache_drop_object() releases the object and eventually
	    fscache_put_object() calls cachefiles_put_object() which suffers
	    an assertion failure here:

		ASSERTCMP(object-&gt;fscache.n_ops, ==, 0);

Locking the object spinlock in step (6) around the clearance of
FSCACHE_OBJECT_IS_LIVE ensures that the the decision trees in
fscache_submit_op() and fscache_submit_exclusive_op() don't see the IS_LIVE
flag being cleared mid-decision: either the op is queued before step (7) - in
which case fscache_kill_object() will see n_ops&gt;0 and will deal with the op -
or the op will be rejected.

This, combined with rejecting op submission if the target object is dying, fix
the problem.

The problem shows up as the following oops:

CacheFiles: Assertion failed
CacheFiles: 1 == 0 is false
------------[ cut here ]------------
kernel BUG at ../fs/cachefiles/interface.c:339!
...
RIP: 0010:[&lt;ffffffffa014fd9c&gt;]  [&lt;ffffffffa014fd9c&gt;] cachefiles_put_object+0x2a4/0x301 [cachefiles]
...
Call Trace:
 [&lt;ffffffffa008674b&gt;] fscache_put_object+0x18/0x21 [fscache]
 [&lt;ffffffffa00883e6&gt;] fscache_object_work_func+0x3ba/0x3c9 [fscache]
 [&lt;ffffffff81054dad&gt;] process_one_work+0x226/0x441
 [&lt;ffffffff81055d91&gt;] worker_thread+0x273/0x36b
 [&lt;ffffffff81055b1e&gt;] ? rescuer_thread+0x2e1/0x2e1
 [&lt;ffffffff81059b9d&gt;] kthread+0x10e/0x116
 [&lt;ffffffff81059a8f&gt;] ? kthread_create_on_node+0x1bb/0x1bb
 [&lt;ffffffff815579ac&gt;] ret_from_fork+0x7c/0xb0
 [&lt;ffffffff81059a8f&gt;] ? kthread_create_on_node+0x1bb/0x1bb

Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Reviewed-by: Steve Dickson &lt;steved@redhat.com&gt;
Acked-by: Jeff Layton &lt;jeff.layton@primarydata.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When an object is being marked as no longer live, do this under the object
spinlock to prevent a race with operation submission targeted on that object.

The problem occurs due to the following pair of intertwined sequences when the
cache tries to create an object that would take it over the hard available
space limit:

 NETFS INTERFACE
 ===============
 (A) The netfs calls fscache_acquire_cookie().  object creation is deferred to
     the object state machine and the netfs is allowed to continue.

	OBJECT STATE MACHINE KTHREAD
	============================
	(1) The object is looked up on disk by fscache_look_up_object()
	    calling cachefiles_walk_to_object().  The latter finds that the
	    object is not yet represented on disk and calls
	    fscache_object_lookup_negative().

	(2) fscache_object_lookup_negative() sets FSCACHE_COOKIE_NO_DATA_YET
	    and clears FSCACHE_COOKIE_LOOKING_UP, thus allowing the netfs to
	    start queuing read operations.

 (B) The netfs calls fscache_read_or_alloc_pages().  This calls
     fscache_wait_for_deferred_lookup() which sees FSCACHE_COOKIE_LOOKING_UP
     become clear, allowing the read to begin.

 (C) A read operation is set up and passed to fscache_submit_op() to deal
     with.

	(3) cachefiles_walk_to_object() calls cachefiles_has_space(), which
	    fails (or one of the file operations to create stuff fails).
	    cachefiles returns an error to fscache.

	(4) fscache_look_up_object() transits to the LOOKUP_FAILURE state,

	(5) fscache_lookup_failure() sets FSCACHE_OBJECT_LOOKED_UP and
	    FSCACHE_COOKIE_UNAVAILABLE and clears FSCACHE_COOKIE_LOOKING_UP
	    then transits to the KILL_OBJECT state.

	(6) fscache_kill_object() clears FSCACHE_OBJECT_IS_LIVE in an attempt
	    to reject any further requests from the netfs.

	(7) object-&gt;n_ops is examined and found to be 0.
	    fscache_kill_object() transits to the DROP_OBJECT state.

 (D) fscache_submit_op() locks the object spinlock, sees if it can dispatch
     the op immediately by calling fscache_object_is_active() - which fails
     since FSCACHE_OBJECT_IS_AVAILABLE has not yet been set.

 (E) fscache_submit_op() then tests FSCACHE_OBJECT_LOOKED_UP - which is set.
     It then queues the object and increments object-&gt;n_ops.

	(8) fscache_drop_object() releases the object and eventually
	    fscache_put_object() calls cachefiles_put_object() which suffers
	    an assertion failure here:

		ASSERTCMP(object-&gt;fscache.n_ops, ==, 0);

Locking the object spinlock in step (6) around the clearance of
FSCACHE_OBJECT_IS_LIVE ensures that the the decision trees in
fscache_submit_op() and fscache_submit_exclusive_op() don't see the IS_LIVE
flag being cleared mid-decision: either the op is queued before step (7) - in
which case fscache_kill_object() will see n_ops&gt;0 and will deal with the op -
or the op will be rejected.

This, combined with rejecting op submission if the target object is dying, fix
the problem.

The problem shows up as the following oops:

CacheFiles: Assertion failed
CacheFiles: 1 == 0 is false
------------[ cut here ]------------
kernel BUG at ../fs/cachefiles/interface.c:339!
...
RIP: 0010:[&lt;ffffffffa014fd9c&gt;]  [&lt;ffffffffa014fd9c&gt;] cachefiles_put_object+0x2a4/0x301 [cachefiles]
...
Call Trace:
 [&lt;ffffffffa008674b&gt;] fscache_put_object+0x18/0x21 [fscache]
 [&lt;ffffffffa00883e6&gt;] fscache_object_work_func+0x3ba/0x3c9 [fscache]
 [&lt;ffffffff81054dad&gt;] process_one_work+0x226/0x441
 [&lt;ffffffff81055d91&gt;] worker_thread+0x273/0x36b
 [&lt;ffffffff81055b1e&gt;] ? rescuer_thread+0x2e1/0x2e1
 [&lt;ffffffff81059b9d&gt;] kthread+0x10e/0x116
 [&lt;ffffffff81059a8f&gt;] ? kthread_create_on_node+0x1bb/0x1bb
 [&lt;ffffffff815579ac&gt;] ret_from_fork+0x7c/0xb0
 [&lt;ffffffff81059a8f&gt;] ? kthread_create_on_node+0x1bb/0x1bb

Signed-off-by: David Howells &lt;dhowells@redhat.com&gt;
Reviewed-by: Steve Dickson &lt;steved@redhat.com&gt;
Acked-by: Jeff Layton &lt;jeff.layton@primarydata.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
