20 Nov, 2009

6 commits

  • Add a stat counter to count retirement events rather than ordinary release
    events (the retire argument to fscache_relinquish_cookie()).

    Signed-off-by: David Howells

    David Howells
     
  • FS-Cache has two structs internally for keeping track of the internal state of
    a cached file: the fscache_cookie struct, which represents the netfs's state,
    and fscache_object struct, which represents the cache's state. Each has a
    pointer that points to the other (when both are in existence), and each has a
    spinlock for pointer maintenance.

    Since netfs operations approach these structures from the cookie side, they get
    the cookie lock first, then the object lock. Cache operations, on the other
    hand, approach from the object side, and get the object lock first. It is not
    then permitted for a cache operation to get the cookie lock whilst it is
    holding the object lock lest deadlock occur; instead, it must do one of two
    things:

    (1) increment the cookie usage counter, drop the object lock and then get both
    locks in order, or

    (2) simply hold the object lock as certain parts of the cookie may not be
    altered whilst the object lock is held.

    It is also not permitted to follow either pointer without holding the lock at
    the end you start with. To break the pointers between the cookie and the
    object, both locks must be held.

    fscache_write_op(), however, violates the locking rules: It attempts to get the
    cookie lock without (a) checking that the cookie pointer is a valid pointer,
    and (b) holding the object lock to protect the cookie pointer whilst it follows
    it. This is so that it can access the pending page store tree without
    interference from __fscache_write_page().

    This is fixed by splitting the cookie lock, such that the page store tracking
    tree is protected by its own lock, and checking that the cookie pointer is
    non-NULL before we attempt to follow it whilst holding the object lock.

    The new lock is subordinate to both the cookie lock and the object lock, and so
    should be taken after those.

    Signed-off-by: David Howells

    David Howells
     
  • __fscache_write_page() attempts to load the radix tree preallocation pool for
    the CPU it is on before calling radix_tree_insert(), as the insertion must be
    done inside a pair of spinlocks.

    Use of the preallocation pool, however, is contingent on the radix tree being
    initialised without __GFP_WAIT specified. __fscache_acquire_cookie() was
    passing GFP_NOFS to INIT_RADIX_TREE() - but that includes __GFP_WAIT.

    The solution is to AND out __GFP_WAIT.

    Additionally, the banner comment to radix_tree_preload() is altered to make
    note of this prerequisite. Possibly there should be a WARN_ON() too.

    Without this fix, I have seen the following recursive deadlock caused by
    radix_tree_insert() attempting to allocate memory inside the spinlocked
    region, which resulted in FS-Cache being called back into to release memory -
    which required the spinlock already held.

    =============================================
    [ INFO: possible recursive locking detected ]
    2.6.32-rc6-cachefs #24
    ---------------------------------------------
    nfsiod/7916 is trying to acquire lock:
    (&cookie->lock){+.+.-.}, at: [] __fscache_uncache_page+0xdb/0x160 [fscache]

    but task is already holding lock:
    (&cookie->lock){+.+.-.}, at: [] __fscache_write_page+0x15c/0x3f3 [fscache]

    other info that might help us debug this:
    5 locks held by nfsiod/7916:
    #0: (nfsiod){+.+.+.}, at: [] worker_thread+0x19a/0x2e2
    #1: (&task->u.tk_work#2){+.+.+.}, at: [] worker_thread+0x19a/0x2e2
    #2: (&cookie->lock){+.+.-.}, at: [] __fscache_write_page+0x15c/0x3f3 [fscache]
    #3: (&object->lock#2){+.+.-.}, at: [] __fscache_write_page+0x197/0x3f3 [fscache]
    #4: (&cookie->stores_lock){+.+...}, at: [] __fscache_write_page+0x19f/0x3f3 [fscache]

    stack backtrace:
    Pid: 7916, comm: nfsiod Not tainted 2.6.32-rc6-cachefs #24
    Call Trace:
    [] __lock_acquire+0x1649/0x16e3
    [] ? __lock_acquire+0x7b7/0x16e3
    [] ? dump_trace+0x248/0x257
    [] lock_acquire+0x57/0x6d
    [] ? __fscache_uncache_page+0xdb/0x160 [fscache]
    [] _spin_lock+0x2c/0x3b
    [] ? __fscache_uncache_page+0xdb/0x160 [fscache]
    [] __fscache_uncache_page+0xdb/0x160 [fscache]
    [] ? __fscache_check_page_write+0x0/0x71 [fscache]
    [] nfs_fscache_release_page+0x86/0xc4 [nfs]
    [] nfs_release_page+0x3c/0x41 [nfs]
    [] try_to_release_page+0x32/0x3b
    [] shrink_page_list+0x316/0x4ac
    [] ? mark_held_locks+0x52/0x70
    [] ? _spin_unlock_irq+0x2b/0x31
    [] shrink_inactive_list+0x392/0x67c
    [] ? mark_held_locks+0x52/0x70
    [] shrink_list+0x8d/0x8f
    [] shrink_zone+0x278/0x33c
    [] ? ktime_get_ts+0xad/0xba
    [] try_to_free_pages+0x22e/0x392
    [] ? isolate_pages_global+0x0/0x212
    [] __alloc_pages_nodemask+0x3dc/0x5cf
    [] cache_alloc_refill+0x34d/0x6c1
    [] ? radix_tree_node_alloc+0x52/0x5c
    [] kmem_cache_alloc+0xb2/0x118
    [] radix_tree_node_alloc+0x52/0x5c
    [] radix_tree_insert+0x57/0x19c
    [] __fscache_write_page+0x1e3/0x3f3 [fscache]
    [] __nfs_readpage_to_fscache+0x58/0x11e [nfs]
    [] nfs_readpage_release+0x34/0x9b [nfs]
    [] nfs_readpage_release_full+0x32/0x4b [nfs]
    [] rpc_release_calldata+0x12/0x14 [sunrpc]
    [] rpc_free_task+0x59/0x61 [sunrpc]
    [] rpc_async_release+0x10/0x12 [sunrpc]
    [] worker_thread+0x1ef/0x2e2
    [] ? worker_thread+0x19a/0x2e2
    [] ? thread_return+0x3e/0x101
    [] ? rpc_async_release+0x0/0x12 [sunrpc]
    [] ? autoremove_wake_function+0x0/0x34
    [] ? trace_hardirqs_on+0xd/0xf
    [] ? worker_thread+0x0/0x2e2
    [] kthread+0x7a/0x82
    [] child_rip+0xa/0x20
    [] ? restore_args+0x0/0x30
    [] ? add_wait_queue+0x15/0x44
    [] ? kthread+0x0/0x82
    [] ? child_rip+0x0/0x20

    Signed-off-by: David Howells

    David Howells
     
  • Clear the pointers from the fscache_cookie struct to netfs private data after
    clearing the pointer to the cookie from the fscache_object struct and
    releasing the object lock, rather than before.

    This allows the netfs private data pointers to be relied on simply by holding
    the object lock, rather than having to hold the cookie lock. This is makes
    things simpler as the cookie lock has to be taken before the object lock, but
    sometimes the object pointer is all that the code has.

    Signed-off-by: David Howells

    David Howells
     
  • Count entries to and exits from cache operation table functions. Maintain
    these as a single counter that's added to or removed from as appropriate.

    Signed-off-by: David Howells

    David Howells
     
  • Allow the current state of all fscache objects to be dumped by doing:

    cat /proc/fs/fscache/objects

    By default, all objects and all fields will be shown. This can be restricted
    by adding a suitable key to one of the caller's keyrings (such as the session
    keyring):

    keyctl add user fscache:objlist "" @s

    The are:

    K Show hexdump of object key (don't show if not given)
    A Show hexdump of object aux data (don't show if not given)

    And paired restrictions:

    C Show objects that have a cookie
    c Show objects that don't have a cookie
    B Show objects that are busy
    b Show objects that aren't busy
    W Show objects that have pending writes
    w Show objects that don't have pending writes
    R Show objects that have outstanding reads
    r Show objects that don't have outstanding reads
    S Show objects that have slow work queued
    s Show objects that don't have slow work queued

    If neither side of a restriction pair is given, then both are implied. For
    example:

    keyctl add user fscache:objlist KB @s

    shows objects that are busy, and lists their object keys, but does not dump
    their auxiliary data. It also implies "CcWwRrSs", but as 'B' is given, 'b' is
    not implied.

    Signed-off-by: David Howells

    David Howells
     

03 Apr, 2009

2 commits

  • Implement the cookie management part of the FS-Cache netfs client API. The
    documentation and API header file were added in a previous patch.

    This patch implements the following three functions:

    (1) fscache_acquire_cookie().

    Acquire a cookie to represent an object to the netfs. If the object in
    question is a non-index object, then that object and its parent indices
    will be created on disk at this point if they don't already exist. Index
    creation is deferred because an index may reside in multiple caches.

    (2) fscache_relinquish_cookie().

    Retire or release a cookie previously acquired. At this point, the
    object on disk may be destroyed.

    (3) fscache_update_cookie().

    Update the in-cache representation of a cookie. This is used to update
    the auxiliary data for coherency management purposes.

    With this patch it is possible to have a netfs instruct a cache backend to
    look up, validate and create metadata on disk and to destroy it again.
    The ability to actually store and retrieve data in the objects so created is
    added in later patches.

    Note that these functions will never return an error. _All_ errors are
    handled internally to FS-Cache.

    The worst that can happen is that fscache_acquire_cookie() may return a NULL
    pointer - which is considered a negative cookie pointer and can be passed back
    to any function that takes a cookie without harm. A negative cookie pointer
    merely suppresses caching at that level.

    The stub in linux/fscache.h will detect inline the negative cookie pointer and
    abort the operation as fast as possible. This means that the compiler doesn't
    have to set up for a call in that case.

    See the documentation in Documentation/filesystems/caching/netfs-api.txt for
    more information.

    Signed-off-by: David Howells
    Acked-by: Steve Dickson
    Acked-by: Trond Myklebust
    Acked-by: Al Viro
    Tested-by: Daire Byrne

    David Howells
     
  • Provide a slab from which can be allocated the FS-Cache cookies that will be
    presented to the netfs.

    Also provide a slab constructor and a function to recursively discard a cookie
    and its ancestor chain.

    Signed-off-by: David Howells
    Acked-by: Steve Dickson
    Acked-by: Trond Myklebust
    Acked-by: Al Viro
    Tested-by: Daire Byrne

    David Howells