diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-30 09:22:00 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-30 09:22:00 -0700 |
| commit | 034dd340b08be1f2f0477ad16131d609f9dbd53c (patch) | |
| tree | 2536f4b2d7893ccd916b5abdf3c454ad6edc03c2 /Documentation/filesystems/caching/netfs-api.rst | |
| download | linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.tar.gz linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.zip | |
Merge tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-tracegrafted
Pull tracing fixes from Steven Rostedt:
- Fix error output of boot instance creation failure
Currently if a boot instance creation fails, instead of printing out
the name of the instance that failed, it prints "(null)". That is
because it prints "cur_str" that had already been processed by
strsep(). Print the saved name instead.
While at it, print the error code of the failure.
- Fix use-after-free for same named historgrams
Histograms can be named so that they can be used in multiple events.
But if the named histogram has a variable attached, the second event
that uses the named histogram which duplicates it and needs to free
the original after duplication leaves the old variable in place and
still visible. If another histogram uses than variable, it will use
the stale one which will try to reference the freed duplicate
histogram and crash the kernel.
Free the duplicate variables along with the duplicated histogram
data.
- Check return value of kthread_run() in event self test
The events self tests uses a kthread for testing but does not check
if it succeeded in creating a kthread. If the kthread creation were
to fail, the code will still try to call kthread_stop() on the error
returned.
- Fix race between reading trace_pipe and updating subbuffer size
If a user is reading the trace_pipe file at the same time they update
the ring buffer sub-buffer size, can cause the trace_pipe read to
read stale data. Add trace_access_lock() around updating the ring
buffer sub-buffer size.
- Fix eventfs_inode on failure path in creation of the events directory
In the creation of the "events" directory, if after allocating the
eventfs_inode a failure is detected, it calls cleanup_ei() which
calls free_ei(). The free_ei() will test if eventfs_inode being freed
has no children. It is a bug if it does. But on the failure case of
the creation of the "events" directory, the children lists have not
yet been initialized and the free will trigger a warning because
list_empty() on an uninitialized list returns false.
Move the initialization into init_ei() where it makes more sense and
makes sure that a created eventfs_inode has its lists initialized
upon creation.
- Check return value of kthread_run() in ftrace direct sample code
The sample code that shows how to use the ftrace direct calls does
not test the return of kthread_run() to see if it succeeds. Return a
failure if the kthread_run() doesn't succeed.
- Clear user events state on fork in case of alloc failure
On fork, the child gets a pointer to the parent's user events state.
It makes a copy of it then updates the child's pointer to it. But if
the allocation fails, the duplication function leaves the child with
a pointer to its parent's descriptor. When the child cleans up its
data, it will free the parent's descriptor while the parent is still
using it.
In the duplication function, set the child's user_event_mm to NULL
before testing if the allocation succeeded, and when it exits it will
not free the parent's descriptor.
- Fix retry exhaustion in simple ring buffer reader swap
simple_ring_buffer_swap_reader_page() starts with retry set to 8 and
post-decrements it only after a failed link replacement. On the final
attempt, a successful replacement leaves retry at zero, while a
failed replacement leaves it at -1.
But the check for success expects the retry value to be non-zero and
exits with an error on zero. This is the opposite result. Fix it.
- Fail nicely when the remote swap_reader_page() returns an error
Currently, if the swap_reader_page() of a remote buffer fails, it
triggers a WARN_ON_ONCE() and continues normally. Instead, have it
exit with an error and a pr_warn() print instead of a full WARNING.
* tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
ring-buffer: Stop remote reader update when page swap fails
tracing: Fix retry exhaustion in simple ring buffer reader swap
tracing/user_events: Clear copied tracing state before fork duplication
samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-multi-modify
samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-modify
eventfs: Initialize ei->children and ei->list in init_ei()
tracing: Fix use-after-free in trace_pipe read on sub-buffer order change
tracing: Fix crash passing ERR_PTR to kthread_stop()
tracing: Fix use-after-free with same-name named triggers
tracing: Fix logged instance name on creation failure
Diffstat (limited to 'Documentation/filesystems/caching/netfs-api.rst')
| -rw-r--r-- | Documentation/filesystems/caching/netfs-api.rst | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/Documentation/filesystems/caching/netfs-api.rst b/Documentation/filesystems/caching/netfs-api.rst new file mode 100644 index 000000000..665b27f15 --- /dev/null +++ b/Documentation/filesystems/caching/netfs-api.rst @@ -0,0 +1,452 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================== +Network Filesystem Caching API +============================== + +Fscache provides an API by which a network filesystem can make use of local +caching facilities. The API is arranged around a number of principles: + + (1) A cache is logically organised into volumes and data storage objects + within those volumes. + + (2) Volumes and data storage objects are represented by various types of + cookie. + + (3) Cookies have keys that distinguish them from their peers. + + (4) Cookies have coherency data that allows a cache to determine if the + cached data is still valid. + + (5) I/O is done asynchronously where possible. + +This API is used by:: + + #include <linux/fscache.h>. + +.. This document contains the following sections: + + (1) Overview + (2) Volume registration + (3) Data file registration + (4) Declaring a cookie to be in use + (5) Resizing a data file (truncation) + (6) Data I/O API + (7) Data file coherency + (8) Data file invalidation + (9) Write back resource management + (10) Caching of local modifications + (11) Page release and invalidation + + +Overview +======== + +The fscache hierarchy is organised on two levels from a network filesystem's +point of view. The upper level represents "volumes" and the lower level +represents "data storage objects". These are represented by two types of +cookie, hereafter referred to as "volume cookies" and "cookies". + +A network filesystem acquires a volume cookie for a volume using a volume key, +which represents all the information that defines that volume (e.g. cell name +or server address, volume ID or share name). This must be rendered as a +printable string that can be used as a directory name (ie. no '/' characters +and shouldn't begin with a '.'). The maximum name length is one less than the +maximum size of a filename component (allowing the cache backend one char for +its own purposes). + +A filesystem would typically have a volume cookie for each superblock. + +The filesystem then acquires a cookie for each file within that volume using an +object key. Object keys are binary blobs and only need to be unique within +their parent volume. The cache backend is responsible for rendering the binary +blob into something it can use and may employ hash tables, trees or whatever to +improve its ability to find an object. This is transparent to the network +filesystem. + +A filesystem would typically have a cookie for each inode, and would acquire it +in iget and relinquish it when evicting the cookie. + +Once it has a cookie, the filesystem needs to mark the cookie as being in use. +This causes fscache to send the cache backend off to look up/create resources +for the cookie in the background, to check its coherency and, if necessary, to +mark the object as being under modification. + +A filesystem would typically "use" the cookie in its file open routine and +unuse it in file release and it needs to use the cookie around calls to +truncate the cookie locally. It *also* needs to use the cookie when the +pagecache becomes dirty and unuse it when writeback is complete. This is +slightly tricky, and provision is made for it. + +When performing a read, write or resize on a cookie, the filesystem must first +begin an operation. This copies the resources into a holding struct and puts +extra pins into the cache to stop cache withdrawal from tearing down the +structures being used. The actual operation can then be issued and conflicting +invalidations can be detected upon completion. + +The filesystem is expected to use netfslib to access the cache, but that's not +actually required and it can use the fscache I/O API directly. + + +Volume Registration +=================== + +The first step for a network filesystem is to acquire a volume cookie for the +volume it wants to access:: + + struct fscache_volume * + fscache_acquire_volume(const char *volume_key, + const char *cache_name, + const void *coherency_data, + size_t coherency_len); + +This function creates a volume cookie with the specified volume key as its name +and notes the coherency data. + +The volume key must be a printable string with no '/' characters in it. It +should begin with the name of the filesystem and should be no longer than 254 +characters. It should uniquely represent the volume and will be matched with +what's stored in the cache. + +The caller may also specify the name of the cache to use. If specified, +fscache will look up or create a cache cookie of that name and will use a cache +of that name if it is online or comes online. If no cache name is specified, +it will use the first cache that comes to hand and set the name to that. + +The specified coherency data is stored in the cookie and will be matched +against coherency data stored on disk. The data pointer may be NULL if no data +is provided. If the coherency data doesn't match, the entire cache volume will +be invalidated. + +This function can return errors such as EBUSY if the volume key is already in +use by an acquired volume or ENOMEM if an allocation failure occurred. It may +also return a NULL volume cookie if fscache is not enabled. It is safe to +pass a NULL cookie to any function that takes a volume cookie. This will +cause that function to do nothing. + + +When the network filesystem has finished with a volume, it should relinquish it +by calling:: + + void fscache_relinquish_volume(struct fscache_volume *volume, + const void *coherency_data, + bool invalidate); + +This will cause the volume to be committed or removed, and if sealed the +coherency data will be set to the value supplied. The amount of coherency data +must match the length specified when the volume was acquired. Note that all +data cookies obtained in this volume must be relinquished before the volume is +relinquished. + + +Data File Registration +====================== + +Once it has a volume cookie, a network filesystem can use it to acquire a +cookie for data storage:: + + struct fscache_cookie * + fscache_acquire_cookie(struct fscache_volume *volume, + u8 advice, + const void *index_key, + size_t index_key_len, + const void *aux_data, + size_t aux_data_len, + loff_t object_size) + +This creates the cookie in the volume using the specified index key. The index +key is a binary blob of the given length and must be unique for the volume. +This is saved into the cookie. There are no restrictions on the content, but +its length shouldn't exceed about three quarters of the maximum filename length +to allow for encoding. + +The caller should also pass in a piece of coherency data in aux_data. A buffer +of size aux_data_len will be allocated and the coherency data copied in. It is +assumed that the size is invariant over time. The coherency data is used to +check the validity of data in the cache. Functions are provided by which the +coherency data can be updated. + +The file size of the object being cached should also be provided. This may be +used to trim the data and will be stored with the coherency data. + +This function never returns an error, though it may return a NULL cookie on +allocation failure or if fscache is not enabled. It is safe to pass in a NULL +volume cookie and pass the NULL cookie returned to any function that takes it. +This will cause that function to do nothing. + + +When the network filesystem has finished with a cookie, it should relinquish it +by calling:: + + void fscache_relinquish_cookie(struct fscache_cookie *cookie, + bool retire); + +This will cause fscache to either commit the storage backing the cookie or +delete it. + + +Marking A Cookie In-Use +======================= + +Once a cookie has been acquired by a network filesystem, the filesystem should +tell fscache when it intends to use the cookie (typically done on file open) +and should say when it has finished with it (typically on file close):: + + void fscache_use_cookie(struct fscache_cookie *cookie, + bool will_modify); + void fscache_unuse_cookie(struct fscache_cookie *cookie, + const void *aux_data, + const loff_t *object_size); + +The *use* function tells fscache that it will use the cookie and, additionally, +indicate if the user is intending to modify the contents locally. If not yet +done, this will trigger the cache backend to go and gather the resources it +needs to access/store data in the cache. This is done in the background, and +so may not be complete by the time the function returns. + +The *unuse* function indicates that a filesystem has finished using a cookie. +It optionally updates the stored coherency data and object size and then +decreases the in-use counter. When the last user unuses the cookie, it is +scheduled for garbage collection. If not reused within a short time, the +resources will be released to reduce system resource consumption. + +A cookie must be marked in-use before it can be accessed for read, write or +resize - and an in-use mark must be kept whilst there is dirty data in the +pagecache in order to avoid an oops due to trying to open a file during process +exit. + +Note that in-use marks are cumulative. For each time a cookie is marked +in-use, it must be unused. + + +Resizing A Data File (Truncation) +================================= + +If a network filesystem file is resized locally by truncation, the following +should be called to notify the cache:: + + void fscache_resize_cookie(struct fscache_cookie *cookie, + loff_t new_size); + +The caller must have first marked the cookie in-use. The cookie and the new +size are passed in and the cache is synchronously resized. This is expected to +be called from ``->setattr()`` inode operation under the inode lock. + + +Data I/O API +============ + +To do data I/O operations directly through a cookie, the following functions +are available:: + + int fscache_begin_read_operation(struct netfs_cache_resources *cres, + struct fscache_cookie *cookie); + int fscache_read(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + enum netfs_read_from_hole read_hole, + netfs_io_terminated_t term_func, + void *term_func_priv); + int fscache_write(struct netfs_cache_resources *cres, + loff_t start_pos, + struct iov_iter *iter, + netfs_io_terminated_t term_func, + void *term_func_priv); + +The *begin* function sets up an operation, attaching the resources required to +the cache resources block from the cookie. Assuming it doesn't return an error +(for instance, it will return -ENOBUFS if given a NULL cookie, but otherwise do +nothing), then one of the other two functions can be issued. + +The *read* and *write* functions initiate a direct-IO operation. Both take the +previously set up cache resources block, an indication of the start file +position, and an I/O iterator that describes buffer and indicates the amount of +data. + +The read function also takes a parameter to indicate how it should handle a +partially populated region (a hole) in the disk content. This may be to ignore +it, skip over an initial hole and place zeros in the buffer or give an error. + +The read and write functions can be given an optional termination function that +will be run on completion:: + + typedef + void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error, + bool was_async); + +If a termination function is given, the operation will be run asynchronously +and the termination function will be called upon completion. If not given, the +operation will be run synchronously. Note that in the asynchronous case, it is +possible for the operation to complete before the function returns. + +Both the read and write functions end the operation when they complete, +detaching any pinned resources. + +The read operation will fail with ESTALE if invalidation occurred whilst the +operation was ongoing. + + +Data File Coherency +=================== + +To request an update of the coherency data and file size on a cookie, the +following should be called:: + + void fscache_update_cookie(struct fscache_cookie *cookie, + const void *aux_data, + const loff_t *object_size); + +This will update the cookie's coherency data and/or file size. + + +Data File Invalidation +====================== + +Sometimes it will be necessary to invalidate an object that contains data. +Typically this will be necessary when the server informs the network filesystem +of a remote third-party change - at which point the filesystem has to throw +away the state and cached data that it had for an file and reload from the +server. + +To indicate that a cache object should be invalidated, the following should be +called:: + + void fscache_invalidate(struct fscache_cookie *cookie, + const void *aux_data, + loff_t size, + unsigned int flags); + +This increases the invalidation counter in the cookie to cause outstanding +reads to fail with -ESTALE, sets the coherency data and file size from the +information supplied, blocks new I/O on the cookie and dispatches the cache to +go and get rid of the old data. + +Invalidation runs asynchronously in a worker thread so that it doesn't block +too much. + + +Write-Back Resource Management +============================== + +To write data to the cache from network filesystem writeback, the cache +resources required need to be pinned at the point the modification is made (for +instance when the page is marked dirty) as it's not possible to open a file in +a thread that's exiting. + +The following facilities are provided to manage this: + + * An inode flag, ``I_PINNING_FSCACHE_WB``, is provided to indicate that an + in-use is held on the cookie for this inode. It can only be changed if the + the inode lock is held. + + * A flag, ``unpinned_fscache_wb`` is placed in the ``writeback_control`` + struct that gets set if ``__writeback_single_inode()`` clears + ``I_PINNING_FSCACHE_WB`` because all the dirty pages were cleared. + +To support this, the following functions are provided:: + + bool fscache_dirty_folio(struct address_space *mapping, + struct folio *folio, + struct fscache_cookie *cookie); + void fscache_unpin_writeback(struct writeback_control *wbc, + struct fscache_cookie *cookie); + void fscache_clear_inode_writeback(struct fscache_cookie *cookie, + struct inode *inode, + const void *aux); + +The *set* function is intended to be called from the filesystem's +``dirty_folio`` address space operation. If ``I_PINNING_FSCACHE_WB`` is not +set, it sets that flag and increments the use count on the cookie (the caller +must already have called ``fscache_use_cookie()``). + +The *unpin* function is intended to be called from the filesystem's +``write_inode`` superblock operation. It cleans up after writing by unusing +the cookie if unpinned_fscache_wb is set in the writeback_control struct. + +The *clear* function is intended to be called from the netfs's ``evict_inode`` +superblock operation. It must be called *after* +``truncate_inode_pages_final()``, but *before* ``clear_inode()``. This cleans +up any hanging ``I_PINNING_FSCACHE_WB``. It also allows the coherency data to +be updated. + + +Caching of Local Modifications +============================== + +If a network filesystem has locally modified data that it wants to write to the +cache, it needs to mark the pages to indicate that a write is in progress, and +if the mark is already present, it needs to wait for it to be removed first +(presumably due to an already in-progress operation). This prevents multiple +competing DIO writes to the same storage in the cache. + +Firstly, the netfs should determine if caching is available by doing something +like:: + + bool caching = fscache_cookie_enabled(cookie); + +If caching is to be attempted, pages should be waited for and then marked using +the following functions provided by the netfs helper library:: + + void set_page_fscache(struct page *page); + void wait_on_page_fscache(struct page *page); + int wait_on_page_fscache_killable(struct page *page); + +Once all the pages in the span are marked, the netfs can ask fscache to +schedule a write of that region:: + + void fscache_write_to_cache(struct fscache_cookie *cookie, + struct address_space *mapping, + loff_t start, size_t len, loff_t i_size, + netfs_io_terminated_t term_func, + void *term_func_priv, + bool caching) + +And if an error occurs before that point is reached, the marks can be removed +by calling:: + + void fscache_clear_page_bits(struct address_space *mapping, + loff_t start, size_t len, + bool caching) + +In these functions, a pointer to the mapping to which the source pages are +attached is passed in and start and len indicate the size of the region that's +going to be written (it doesn't have to align to page boundaries necessarily, +but it does have to align to DIO boundaries on the backing filesystem). The +caching parameter indicates if caching should be skipped, and if false, the +functions do nothing. + +The write function takes some additional parameters: the cookie representing +the cache object to be written to, i_size indicates the size of the netfs file +and term_func indicates an optional completion function, to which +term_func_priv will be passed, along with the error or amount written. + +Note that the write function will always run asynchronously and will unmark all +the pages upon completion before calling term_func. + + +Page Release and Invalidation +============================= + +Fscache keeps track of whether we have any data in the cache yet for a cache +object we've just created. It knows it doesn't have to do any reading until it +has done a write and then the page it wrote from has been released by the VM, +after which it *has* to look in the cache. + +To inform fscache that a page might now be in the cache, the following function +should be called from the ``release_folio`` address space op:: + + void fscache_note_page_release(struct fscache_cookie *cookie); + +if the page has been released (ie. release_folio returned true). + +Page release and page invalidation should also wait for any mark left on the +page to say that a DIO write is underway from that page:: + + void wait_on_page_fscache(struct page *page); + int wait_on_page_fscache_killable(struct page *page); + + +API Function Reference +====================== + +.. kernel-doc:: include/linux/fscache.h |
