Cache Backend API¶
The FS-Cache system provides an API by which actual caches can be supplied to FS-Cache for it to then serve out to network filesystems and other interested parties. This API is used by:
#include <linux/fscache-cache.h>.
Overview¶
Interaction with the API is handled on three levels: cache, volume and data storage, and each level has its own type of cookie object:
COOKIE
C TYPE
Cache cookie
struct fscache_cache
Volume cookie
struct fscache_volume
Data storage cookie
struct fscache_cookie
Cookies are used to provide some filesystem data to the cache, manage state and pin the cache during access in addition to acting as reference points for the API functions. Each cookie has a debugging ID that is included in trace points to make it easier to correlate traces. Note, though, that debugging IDs are simply allocated from incrementing counters and will eventually wrap.
The cache backend and the network filesystem can both ask for cache cookies - and if they ask for one of the same name, they’ll get the same cookie. Volume and data cookies, however, are created at the behest of the filesystem only.
Registering a Cache¶
When a cache backend wants to bring a cache online, it should first register the cache name and that will get it a cache cookie. This is done with:
struct fscache_cache *fscache_acquire_cache(const char *name);
This will look up and potentially create a cache cookie. The cache cookie may have already been created by a network filesystem looking for it, in which case that cache cookie will be used. If the cache cookie is not in use by another cache, it will be moved into the preparing state, otherwise it will return busy.
If successful, the cache backend can then start setting up the cache. In the event that the initialisation fails, the cache backend should call:
void fscache_relinquish_cache(struct fscache_cache *cache);
to reset and discard the cookie.
Bringing a Cache Online¶
Once the cache is set up, it can be brought online by calling:
int fscache_add_cache(struct fscache_cache *cache,
const struct fscache_cache_ops *ops,
void *cache_priv);
This stores the cache operations table pointer and cache private data into the cache cookie and moves the cache to the active state, thereby allowing accesses to take place.
Withdrawing a Cache From Service¶
The cache backend can withdraw a cache from service by calling this function:
void fscache_withdraw_cache(struct fscache_cache *cache);
This moves the cache to the withdrawn state to prevent new cache- and volume-level accesses from starting and then waits for outstanding cache-level accesses to complete.
The cache must then go through the data storage objects it has and tell fscache to withdraw them, calling:
void fscache_withdraw_cookie(struct fscache_cookie *cookie);
on the cookie that each object belongs to. This schedules the specified cookie for withdrawal. This gets offloaded to a workqueue. The cache backend can wait for completion by calling:
void fscache_wait_for_objects(struct fscache_cache *cache);
Once all the cookies are withdrawn, a cache backend can withdraw all the volumes, calling:
void fscache_withdraw_volume(struct fscache_volume *volume);
to tell fscache that a volume has been withdrawn. This waits for all outstanding accesses on the volume to complete before returning.
When the cache is completely withdrawn, fscache should be notified by calling:
void fscache_relinquish_cache(struct fscache_cache *cache);
to clear fields in the cookie and discard the caller’s ref on it.
Cache Management API¶
The cache backend implements the cache management API by providing a table of operations that fscache can use to manage various aspects of the cache. These are held in a structure of type:
struct fscache_cache_ops {
const char *name;
...
};
This contains a printable name for the cache backend driver plus a number of pointers to methods to allow fscache to request management of the cache:
Set up a volume cookie [optional]:
void (*acquire_volume)(struct fscache_volume *volume);This method is called when a volume cookie is being created. The caller holds a cache-level access pin to prevent the cache from going away for the duration. This method should set up the resources to access a volume in the cache and should not return until it has done so.
If successful, it can set
cache_priv
to its own data.Clean up volume cookie [optional]:
void (*free_volume)(struct fscache_volume *volume);This method is called when a volume cookie is being released if
cache_priv
is set.Look up a cookie in the cache [mandatory]:
bool (*lookup_cookie)(struct fscache_cookie *cookie);This method is called to look up/create the resources needed to access the data storage for a cookie. It is called from a worker thread with a volume-level access pin in the cache to prevent it from being withdrawn.
True should be returned if successful and false otherwise. If false is returned, the withdraw_cookie op (see below) will be called.
If lookup fails, but the object could still be created (e.g. it hasn’t been cached before), then:
void fscache_cookie_lookup_negative( struct fscache_cookie *cookie);can be called to let the network filesystem proceed and start downloading stuff whilst the cache backend gets on with the job of creating things.
If successful,
cookie->cache_priv
can be set.Withdraw an object without any cookie access counts held [mandatory]:
void (*withdraw_cookie)(struct fscache_cookie *cookie);This method is called to withdraw a cookie from service. It will be called when the cookie is relinquished by the netfs, withdrawn or culled by the cache backend or closed after a period of non-use by fscache.
The caller doesn’t hold any access pins, but it is called from a non-reentrant work item to manage races between the various ways withdrawal can occur.
The cookie will have the
FSCACHE_COOKIE_RETIRED
flag set on it if the associated data is to be removed from the cache.Change the size of a data storage object [mandatory]:
void (*resize_cookie)(struct netfs_cache_resources *cres, loff_t new_size);This method is called to inform the cache backend of a change in size of the netfs file due to local truncation. The cache backend should make all of the changes it needs to make before returning as this is done under the netfs inode mutex.
The caller holds a cookie-level access pin to prevent a race with withdrawal and the netfs must have the cookie marked in-use to prevent garbage collection or culling from removing any resources.
Invalidate a data storage object [mandatory]:
bool (*invalidate_cookie)(struct fscache_cookie *cookie);This is called when the network filesystem detects a third-party modification or when an O_DIRECT write is made locally. This requests that the cache backend should throw away all the data in the cache for this object and start afresh. It should return true if successful and false otherwise.
On entry, new I O/operations are blocked. Once the cache is in a position to accept I/O again, the backend should release the block by calling:
void fscache_resume_after_invalidation(struct fscache_cookie *cookie);If the method returns false, caching will be withdrawn for this cookie.
Prepare to make local modifications to the cache [mandatory]:
void (*prepare_to_write)(struct fscache_cookie *cookie);This method is called when the network filesystem finds that it is going to need to modify the contents of the cache due to local writes or truncations. This gives the cache a chance to note that a cache object may be incoherent with respect to the server and may need writing back later. This may also cause the cached data to be scrapped on later rebinding if not properly committed.
Begin an operation for the netfs lib [mandatory]:
bool (*begin_operation)(struct netfs_cache_resources *cres, enum fscache_want_state want_state);This method is called when an I/O operation is being set up (read, write or resize). The caller holds an access pin on the cookie and must have marked the cookie as in-use.
If it can, the backend should attach any resources it needs to keep around to the netfs_cache_resources object and return true.
If it can’t complete the setup, it should return false.
The want_state parameter indicates the state the caller needs the cache object to be in and what it wants to do during the operation:
FSCACHE_WANT_PARAMS
- The caller just wants to access cache object parameters; it doesn’t need to do data I/O yet.
FSCACHE_WANT_READ
- The caller wants to read data.
FSCACHE_WANT_WRITE
- The caller wants to write to or resize the cache object.Note that there won’t necessarily be anything attached to the cookie’s cache_priv yet if the cookie is still being created.
Data I/O API¶
A cache backend provides a data I/O API by through the netfs library’s struct
netfs_cache_ops
attached to a struct netfs_cache_resources
by the
begin_operation
method described above.
See the Network Filesystem Helper Library for a description.
Miscellaneous Functions¶
FS-Cache provides some utilities that a cache backend may make use of:
Note occurrence of an I/O error in a cache:
void fscache_io_error(struct fscache_cache *cache);This tells FS-Cache that an I/O error occurred in the cache. This prevents any new I/O from being started on the cache.
This does not actually withdraw the cache. That must be done separately.
Note cessation of caching on a cookie due to failure:
void fscache_caching_failed(struct fscache_cookie *cookie);This notes that a the caching that was being done on a cookie failed in some way, for instance the backing storage failed to be created or invalidation failed and that no further I/O operations should take place on it until the cache is reset.
Count I/O requests:
void fscache_count_read(void); void fscache_count_write(void);These record reads and writes from/to the cache. The numbers are displayed in /proc/fs/fscache/stats.
Count out-of-space errors:
void fscache_count_no_write_space(void); void fscache_count_no_create_space(void);These record ENOSPC errors in the cache, divided into failures of data writes and failures of filesystem object creations (e.g. mkdir).
Count objects culled:
void fscache_count_culled(void);This records the culling of an object.
Get the cookie from a set of cache resources:
struct fscache_cookie *fscache_cres_cookie(struct netfs_cache_resources *cres)Pull a pointer to the cookie from the cache resources. This may return a NULL cookie if no cookie was set.
API Function Reference¶
-
enum fscache_cookie_state fscache_cookie_state(struct fscache_cookie *cookie)¶
Read the state of a cookie
Parameters
struct fscache_cookie *cookie
The cookie to query
Description
Get the state of a cookie, imposing an ordering between the cookie contents and the state value. Paired with fscache_set_cookie_state().
-
void *fscache_get_key(struct fscache_cookie *cookie)¶
Get a pointer to the cookie key
Parameters
struct fscache_cookie *cookie
The cookie to query
Description
Return a pointer to the where a cookie’s key is stored.
-
void fscache_count_object(struct fscache_cache *cache)¶
Tell fscache that an object has been added
Parameters
struct fscache_cache *cache
The cache to account to
Description
Tell fscache that an object has been added to the cache. This prevents the cache from tearing down the cache structure until the object is uncounted.
-
void fscache_uncount_object(struct fscache_cache *cache)¶
Tell fscache that an object has been removed
Parameters
struct fscache_cache *cache
The cache to account to
Description
Tell fscache that an object has been removed from the cache and will no longer be accessed. After this point, the cache cookie may be destroyed.
-
void fscache_wait_for_objects(struct fscache_cache *cache)¶
Wait for all objects to be withdrawn
Parameters
struct fscache_cache *cache
The cache to query
Description
Wait for all extant objects in a cache to finish being withdrawn and go away.