08 Jul, 2011

1 commit

  • Add an FS-Cache helper to bulk uncache pages on an inode. This will
    only work for the circumstance where the pages in the cache correspond
    1:1 with the pages attached to an inode's page cache.

    This is required for CIFS and NFS: When disabling inode cookie, we were
    returning the cookie and setting cifsi->fscache to NULL but failed to
    invalidate any previously mapped pages. This resulted in "Bad page
    state" errors and manifested in other kind of errors when running
    fsstress. Fix it by uncaching mapped pages when we disable the inode
    cookie.

    This patch should fix the following oops and "Bad page state" errors
    seen during fsstress testing.

    ------------[ cut here ]------------
    kernel BUG at fs/cachefiles/namei.c:201!
    invalid opcode: 0000 [#1] SMP
    Pid: 5, comm: kworker/u:0 Not tainted 2.6.38.7-30.fc15.x86_64 #1 Bochs Bochs
    RIP: 0010: cachefiles_walk_to_object+0x436/0x745 [cachefiles]
    RSP: 0018:ffff88002ce6dd00 EFLAGS: 00010282
    RAX: ffff88002ef165f0 RBX: ffff88001811f500 RCX: 0000000000000000
    RDX: 0000000000000000 RSI: 0000000000000100 RDI: 0000000000000282
    RBP: ffff88002ce6dda0 R08: 0000000000000100 R09: ffffffff81b3a300
    R10: 0000ffff00066c0a R11: 0000000000000003 R12: ffff88002ae54840
    R13: ffff88002ae54840 R14: ffff880029c29c00 R15: ffff88001811f4b0
    FS: 00007f394dd32720(0000) GS:ffff88002ef00000(0000) knlGS:0000000000000000
    CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
    CR2: 00007fffcb62ddf8 CR3: 000000001825f000 CR4: 00000000000006e0
    DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
    DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
    Process kworker/u:0 (pid: 5, threadinfo ffff88002ce6c000, task ffff88002ce55cc0)
    Stack:
    0000000000000246 ffff88002ce55cc0 ffff88002ce6dd58 ffff88001815dc00
    ffff8800185246c0 ffff88001811f618 ffff880029c29d18 ffff88001811f380
    ffff88002ce6dd50 ffffffff814757e4 ffff88002ce6dda0 ffffffff8106ac56
    Call Trace:
    cachefiles_lookup_object+0x78/0xd4 [cachefiles]
    fscache_lookup_object+0x131/0x16d [fscache]
    fscache_object_work_func+0x1bc/0x669 [fscache]
    process_one_work+0x186/0x298
    worker_thread+0xda/0x15d
    kthread+0x84/0x8c
    kernel_thread_helper+0x4/0x10
    RIP cachefiles_walk_to_object+0x436/0x745 [cachefiles]
    ---[ end trace 1d481c9af1804caa ]---

    I tested the uncaching by the following means:

    (1) Create a big file on my NFS server (104857600 bytes).

    (2) Read the file into the cache with md5sum on the NFS client. Look in
    /proc/fs/fscache/stats:

    Pages : mrk=25601 unc=0

    (3) Open the file for read/write ("bash 5<>/warthog/bigfile"). Look in proc
    again:

    Pages : mrk=25601 unc=25601

    Reported-by: Jeff Layton
    Signed-off-by: David Howells
    Reviewed-and-Tested-by: Suresh Jayaraman
    cc: stable@kernel.org
    Signed-off-by: Linus Torvalds

    David Howells
     

31 Mar, 2011

1 commit


12 Jul, 2010

2 commits


20 Nov, 2009

1 commit

  • Handle netfs pages that the vmscan algorithm wants to evict from the pagecache
    under OOM conditions, but that are waiting for write to the cache. Under these
    conditions, vmscan calls the releasepage() function of the netfs, asking if a
    page can be discarded.

    The problem is typified by the following trace of a stuck process:

    kslowd005 D 0000000000000000 0 4253 2 0x00000080
    ffff88001b14f370 0000000000000046 ffff880020d0d000 0000000000000007
    0000000000000006 0000000000000001 ffff88001b14ffd8 ffff880020d0d2a8
    000000000000ddf0 00000000000118c0 00000000000118c0 ffff880020d0d2a8
    Call Trace:
    [] __fscache_wait_on_page_write+0x8b/0xa7 [fscache]
    [] ? autoremove_wake_function+0x0/0x34
    [] ? __fscache_check_page_write+0x63/0x70 [fscache]
    [] nfs_fscache_release_page+0x4e/0xc4 [nfs]
    [] nfs_release_page+0x3c/0x41 [nfs]
    [] try_to_release_page+0x32/0x3b
    [] shrink_page_list+0x316/0x4ac
    [] shrink_inactive_list+0x392/0x67c
    [] ? __mutex_unlock_slowpath+0x100/0x10b
    [] ? trace_hardirqs_on_caller+0x10c/0x130
    [] ? mutex_unlock+0x9/0xb
    [] 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
    [] grab_cache_page_write_begin+0x65/0xaa
    [] ext3_write_begin+0x78/0x1eb
    [] generic_file_buffered_write+0x109/0x28c
    [] ? current_fs_time+0x22/0x29
    [] __generic_file_aio_write+0x350/0x385
    [] ? generic_file_aio_write+0x4a/0xae
    [] generic_file_aio_write+0x60/0xae
    [] do_sync_write+0xe3/0x120
    [] ? autoremove_wake_function+0x0/0x34
    [] ? __dentry_open+0x1a5/0x2b8
    [] ? dentry_open+0x82/0x89
    [] cachefiles_write_page+0x298/0x335 [cachefiles]
    [] fscache_write_op+0x178/0x2c2 [fscache]
    [] fscache_op_execute+0x7a/0xd1 [fscache]
    [] slow_work_execute+0x18f/0x2d1
    [] slow_work_thread+0x1c5/0x308
    [] ? autoremove_wake_function+0x0/0x34
    [] ? slow_work_thread+0x0/0x308
    [] kthread+0x7a/0x82
    [] child_rip+0xa/0x20
    [] ? restore_args+0x0/0x30
    [] ? tg_shares_up+0x171/0x227
    [] ? kthread+0x0/0x82
    [] ? child_rip+0x0/0x20

    In the above backtrace, the following is happening:

    (1) A page storage operation is being executed by a slow-work thread
    (fscache_write_op()).

    (2) FS-Cache farms the operation out to the cache to perform
    (cachefiles_write_page()).

    (3) CacheFiles is then calling Ext3 to perform the actual write, using Ext3's
    standard write (do_sync_write()) under KERNEL_DS directly from the netfs
    page.

    (4) However, for Ext3 to perform the write, it must allocate some memory, in
    particular, it must allocate at least one page cache page into which it
    can copy the data from the netfs page.

    (5) Under OOM conditions, the memory allocator can't immediately come up with
    a page, so it uses vmscan to find something to discard
    (try_to_free_pages()).

    (6) vmscan finds a clean netfs page it might be able to discard (possibly the
    one it's trying to write out).

    (7) The netfs is called to throw the page away (nfs_release_page()) - but it's
    called with __GFP_WAIT, so the netfs decides to wait for the store to
    complete (__fscache_wait_on_page_write()).

    (8) This blocks a slow-work processing thread - possibly against itself.

    The system ends up stuck because it can't write out any netfs pages to the
    cache without allocating more memory.

    To avoid this, we make FS-Cache cancel some writes that aren't in the middle of
    actually being performed. This means that some data won't make it into the
    cache this time. To support this, a new FS-Cache function is added
    fscache_maybe_release_page() that replaces what the netfs releasepage()
    functions used to do with respect to the cache.

    The decisions fscache_maybe_release_page() makes are counted and displayed
    through /proc/fs/fscache/stats on a line labelled "VmScan". There are four
    counters provided: "nos=N" - pages that weren't pending storage; "gon=N" -
    pages that were pending storage when we first looked, but weren't by the time
    we got the object lock; "bsy=N" - pages that we ignored as they were actively
    being written when we looked; and "can=N" - pages that we cancelled the storage
    of.

    What I'd really like to do is alter the behaviour of the cancellation
    heuristics, depending on how necessary it is to expel pages. If there are
    plenty of other pages that aren't waiting to be written to the cache that
    could be ejected first, then it would be nice to hold up on immediate
    cancellation of cache writes - but I don't see a way of doing that.

    Signed-off-by: David Howells

    David Howells
     

03 Apr, 2009

5 commits

  • Implement the data I/O part of the FS-Cache netfs API. The documentation and
    API header file were added in a previous patch.

    This patch implements the following functions for the netfs to call:

    (*) fscache_attr_changed().

    Indicate that the object has changed its attributes. The only attribute
    currently recorded is the file size. Only pages within the set file size
    will be stored in the cache.

    This operation is submitted for asynchronous processing, and will return
    immediately. It will return -ENOMEM if an out of memory error is
    encountered, -ENOBUFS if the object is not actually cached, or 0 if the
    operation is successfully queued.

    (*) fscache_read_or_alloc_page().
    (*) fscache_read_or_alloc_pages().

    Request data be fetched from the disk, and allocate internal metadata to
    track the netfs pages and reserve disk space for unknown pages.

    These operations perform semi-asynchronous data reads. Upon returning
    they will indicate which pages they think can be retrieved from disk, and
    will have set in progress attempts to retrieve those pages.

    These will return, in order of preference, -ENOMEM on memory allocation
    error, -ERESTARTSYS if a signal interrupted proceedings, -ENODATA if one
    or more requested pages are not yet cached, -ENOBUFS if the object is not
    actually cached or if there isn't space for future pages to be cached on
    this object, or 0 if successful.

    In the case of the multipage function, the pages for which reads are set
    in progress will be removed from the list and the page count decreased
    appropriately.

    If any read operations should fail, the completion function will be given
    an error, and will also be passed contextual information to allow the
    netfs to fall back to querying the server for the absent pages.

    For each successful read, the page completion function will also be
    called.

    Any pages subsequently tracked by the cache will have PG_fscache set upon
    them on return. fscache_uncache_page() must be called for such pages.

    If supplied by the netfs, the mark_pages_cached() cookie op will be
    invoked for any pages now tracked.

    (*) fscache_alloc_page().

    Allocate internal metadata to track a netfs page and reserve disk space.

    This will return -ENOMEM on memory allocation error, -ERESTARTSYS on
    signal, -ENOBUFS if the object isn't cached, or there isn't enough space
    in the cache, or 0 if successful.

    Any pages subsequently tracked by the cache will have PG_fscache set upon
    them on return. fscache_uncache_page() must be called for such pages.

    If supplied by the netfs, the mark_pages_cached() cookie op will be
    invoked for any pages now tracked.

    (*) fscache_write_page().

    Request data be stored to disk. This may only be called on pages that
    have been read or alloc'd by the above three functions and have not yet
    been uncached.

    This will return -ENOMEM on memory allocation error, -ERESTARTSYS on
    signal, -ENOBUFS if the object isn't cached, or there isn't immediately
    enough space in the cache, or 0 if successful.

    On a successful return, this operation will have queued the page for
    asynchronous writing to the cache. The page will be returned with
    PG_fscache_write set until the write completes one way or another. The
    caller will not be notified if the write fails due to an I/O error. If
    that happens, the object will become available and all pending writes will
    be aborted.

    Note that the cache may batch up page writes, and so it may take a while
    to get around to writing them out.

    The caller must assume that until PG_fscache_write is cleared the page is
    use by the cache. Any changes made to the page may be reflected on disk.
    The page may even be under DMA.

    (*) fscache_uncache_page().

    Indicate that the cache should stop tracking a page previously read or
    alloc'd from the cache. If the page was alloc'd only, but unwritten, it
    will not appear on disk.

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

    David Howells
     
  • 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
     
  • Add functions to register and unregister a network filesystem or other client
    of the FS-Cache service. This allocates and releases the cookie representing
    the top-level index for a netfs, and makes it available to the netfs.

    If the FS-Cache facility is disabled, then the calls are optimised away at
    compile time.

    Note that whilst this patch may appear to work with FS-Cache enabled and a
    netfs attempting to use it, it will leak the cookie it allocates for the netfs
    as fscache_relinquish_cookie() is implemented in a later patch. This will
    cause the slab code to emit a warning when the module is removed.

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

    David Howells
     
  • Implement two features of FS-Cache:

    (1) The ability to request and release cache tags - names by which a cache may
    be known to a netfs, and thus selected for use.

    (2) An internal function by which a cache is selected by consulting the netfs,
    if the netfs wishes to be consulted.

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

    David Howells
     
  • Add the API for a generic facility (FS-Cache) by which filesystems (such as AFS
    or NFS) may call on local caching capabilities without having to know anything
    about how the cache works, or even if there is a cache:

    +---------+
    | | +--------------+
    | NFS |--+ | |
    | | | +-->| CacheFS |
    +---------+ | +----------+ | | /dev/hda5 |
    | | | | +--------------+
    +---------+ +-->| | |
    | | | |--+
    | AFS |----->| FS-Cache |
    | | | |--+
    +---------+ +-->| | |
    | | | | +--------------+
    +---------+ | +----------+ | | |
    | | | +-->| CacheFiles |
    | ISOFS |--+ | /var/cache |
    | | +--------------+
    +---------+

    General documentation and documentation of the netfs specific API are provided
    in addition to the header files.

    As this patch stands, it is possible to build a filesystem against the facility
    and attempt to use it. All that will happen is that all requests will be
    immediately denied as if no cache is present.

    Further patches will implement the core of the facility. The facility will
    transfer requests from networking filesystems to appropriate caches if
    possible, or else gracefully deny them.

    If this facility is disabled in the kernel configuration, then all its
    operations will trivially reduce to nothing during compilation.

    WHY NOT I_MAPPING?
    ==================

    I have added my own API to implement caching rather than using i_mapping to do
    this for a number of reasons. These have been discussed a lot on the LKML and
    CacheFS mailing lists, but to summarise the basics:

    (1) Most filesystems don't do hole reportage. Holes in files are treated as
    blocks of zeros and can't be distinguished otherwise, making it difficult
    to distinguish blocks that have been read from the network and cached from
    those that haven't.

    (2) The backing inode must be fully populated before being exposed to
    userspace through the main inode because the VM/VFS goes directly to the
    backing inode and does not interrogate the front inode's VM ops.

    Therefore:

    (a) The backing inode must fit entirely within the cache.

    (b) All backed files currently open must fit entirely within the cache at
    the same time.

    (c) A working set of files in total larger than the cache may not be
    cached.

    (d) A file may not grow larger than the available space in the cache.

    (e) A file that's open and cached, and remotely grows larger than the
    cache is potentially stuffed.

    (3) Writes go to the backing filesystem, and can only be transferred to the
    network when the file is closed.

    (4) There's no record of what changes have been made, so the whole file must
    be written back.

    (5) The pages belong to the backing filesystem, and all metadata associated
    with that page are relevant only to the backing filesystem, and not
    anything stacked atop it.

    OVERVIEW
    ========

    FS-Cache provides (or will provide) the following facilities:

    (1) Caches can be added / removed at any time, even whilst in use.

    (2) Adds a facility by which tags can be used to refer to caches, even if
    they're not available yet.

    (3) More than one cache can be used at once. Caches can be selected
    explicitly by use of tags.

    (4) The netfs is provided with an interface that allows either party to
    withdraw caching facilities from a file (required for (1)).

    (5) A netfs may annotate cache objects that belongs to it. This permits the
    storage of coherency maintenance data.

    (6) Cache objects will be pinnable and space reservations will be possible.

    (7) The interface to the netfs returns as few errors as possible, preferring
    rather to let the netfs remain oblivious.

    (8) Cookies are used to represent indices, files and other objects to the
    netfs. The simplest cookie is just a NULL pointer - indicating nothing
    cached there.

    (9) The netfs is allowed to propose - dynamically - any index hierarchy it
    desires, though it must be aware that the index search function is
    recursive, stack space is limited, and indices can only be children of
    indices.

    (10) Indices can be used to group files together to reduce key size and to make
    group invalidation easier. The use of indices may make lookup quicker,
    but that's cache dependent.

    (11) Data I/O is effectively done directly to and from the netfs's pages. The
    netfs indicates that page A is at index B of the data-file represented by
    cookie C, and that it should be read or written. The cache backend may or
    may not start I/O on that page, but if it does, a netfs callback will be
    invoked to indicate completion. The I/O may be either synchronous or
    asynchronous.

    (12) Cookies can be "retired" upon release. At this point FS-Cache will mark
    them as obsolete and the index hierarchy rooted at that point will get
    recycled.

    (13) The netfs provides a "match" function for index searches. In addition to
    saying whether a match was made or not, this can also specify that an
    entry should be updated or deleted.

    FS-Cache maintains a virtual index tree in which all indices, files, objects
    and pages are kept. Bits of this tree may actually reside in one or more
    caches.

    FSDEF
    |
    +------------------------------------+
    | |
    NFS AFS
    | |
    +--------------------------+ +-----------+
    | | | |
    homedir mirror afs.org redhat.com
    | | |
    +------------+ +---------------+ +----------+
    | | | | | |
    00001 00002 00007 00125 vol00001 vol00002
    | | | | |
    +---+---+ +-----+ +---+ +------+------+ +-----+----+
    | | | | | | | | | | | | |
    PG0 PG1 PG2 PG0 XATTR PG0 PG1 DIRENT DIRENT DIRENT R/W R/O Bak
    | |
    PG0 +-------+
    | |
    00001 00003
    |
    +---+---+
    | | |
    PG0 PG1 PG2

    In the example above, two netfs's can be seen to be backed: NFS and AFS. These
    have different index hierarchies:

    (*) The NFS primary index will probably contain per-server indices. Each
    server index is indexed by NFS file handles to get data file objects.
    Each data file objects can have an array of pages, but may also have
    further child objects, such as extended attributes and directory entries.
    Extended attribute objects themselves have page-array contents.

    (*) The AFS primary index contains per-cell indices. Each cell index contains
    per-logical-volume indices. Each of volume index contains up to three
    indices for the read-write, read-only and backup mirrors of those volumes.
    Each of these contains vnode data file objects, each of which contains an
    array of pages.

    The very top index is the FS-Cache master index in which individual netfs's
    have entries.

    Any index object may reside in more than one cache, provided it only has index
    children. Any index with non-index object children will be assumed to only
    reside in one cache.

    The FS-Cache overview can be found in:

    Documentation/filesystems/caching/fscache.txt

    The netfs API to FS-Cache can be found in:

    Documentation/filesystems/caching/netfs-api.txt

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

    David Howells