2019-05-27 14:55:01 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2009-04-03 23:42:36 +08:00
|
|
|
/* General filesystem caching backing cache interface
|
|
|
|
*
|
2021-10-26 04:53:44 +08:00
|
|
|
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
2009-04-03 23:42:36 +08:00
|
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
|
|
*
|
|
|
|
* NOTE!!! See:
|
|
|
|
*
|
2020-04-28 05:16:58 +08:00
|
|
|
* Documentation/filesystems/caching/backend-api.rst
|
2009-04-03 23:42:36 +08:00
|
|
|
*
|
|
|
|
* for a description of the cache backend interface declared here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _LINUX_FSCACHE_CACHE_H
|
|
|
|
#define _LINUX_FSCACHE_CACHE_H
|
|
|
|
|
|
|
|
#include <linux/fscache.h>
|
2015-02-20 07:47:31 +08:00
|
|
|
|
2021-10-20 22:00:26 +08:00
|
|
|
enum fscache_cache_trace;
|
fscache: Implement cookie registration
Add functions to the fscache API to allow data file cookies to be acquired
and relinquished by the network filesystem. It is intended that the
filesystem will create such cookies per-inode under a volume.
To request a cookie, the filesystem should call:
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)
The filesystem must first have created a volume cookie, which is passed in
here. If it passes in NULL then the function will just return a NULL
cookie.
A binary key should be passed in index_key and is of size index_key_len.
This is saved in the cookie and is used to locate the associated data in
the cache.
A coherency data buffer of size aux_data_len will be allocated and
initialised from the buffer pointed to by aux_data. This is used to
validate cache objects when they're opened and is stored on disk with them
when they're committed. The data is stored in the cookie and will be
updateable by various functions in later patches.
The object_size must also be given. This is also used to perform a
coherency check and to size the backing storage appropriately.
This function disallows a cookie from being acquired twice in parallel,
though it will cause the second user to wait if the first is busy
relinquishing its cookie.
When a network filesystem has finished with a cookie, it should call:
void
fscache_relinquish_cookie(struct fscache_volume *volume,
bool retire)
If retire is true, any backing data will be discarded immediately.
Changes
=======
ver #3:
- fscache_hash()'s size parameter is now in bytes. Use __le32 as the unit
to round up to.
- When comparing cookies, simply see if the attributes are the same rather
than subtracting them to produce a strcmp-style return[1].
- Add a check to see if the cookie is still hashed at the point of
freeing.
ver #2:
- Don't hold n_accesses elevated whilst cache is bound to a cookie, but
rather add a flag that prevents the state machine from being queued when
n_accesses reaches 0.
- Remove the unused cookie pointer field from the fscache_acquire
tracepoint.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/CAHk-=whtkzB446+hX0zdLsdcUJsJ=8_-0S1mE_R+YurThfUbLA@mail.gmail.com/ [1]
Link: https://lore.kernel.org/r/163819590658.215744.14934902514281054323.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906891983.143852.6219772337558577395.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967088507.1823006.12659006350221417165.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021498432.640689.12743483856927722772.stgit@warthog.procyon.org.uk/ # v4
2021-10-20 22:53:34 +08:00
|
|
|
enum fscache_cookie_trace;
|
2021-10-20 22:00:26 +08:00
|
|
|
enum fscache_access_trace;
|
|
|
|
|
|
|
|
enum fscache_cache_state {
|
|
|
|
FSCACHE_CACHE_IS_NOT_PRESENT, /* No cache is present for this name */
|
|
|
|
FSCACHE_CACHE_IS_PREPARING, /* A cache is preparing to come live */
|
|
|
|
FSCACHE_CACHE_IS_ACTIVE, /* Attached cache is active and can be used */
|
|
|
|
FSCACHE_CACHE_GOT_IOERROR, /* Attached cache stopped on I/O error */
|
|
|
|
FSCACHE_CACHE_IS_WITHDRAWN, /* Attached cache is being withdrawn */
|
|
|
|
#define NR__FSCACHE_CACHE_STATE (FSCACHE_CACHE_IS_WITHDRAWN + 1)
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cache cookie.
|
|
|
|
*/
|
|
|
|
struct fscache_cache {
|
2021-10-20 22:00:26 +08:00
|
|
|
const struct fscache_cache_ops *ops;
|
2021-10-20 22:00:26 +08:00
|
|
|
struct list_head cache_link; /* Link in cache list */
|
|
|
|
void *cache_priv; /* Private cache data (or NULL) */
|
|
|
|
refcount_t ref;
|
|
|
|
atomic_t n_volumes; /* Number of active volumes; */
|
|
|
|
atomic_t n_accesses; /* Number of in-progress accesses on the cache */
|
|
|
|
atomic_t object_count; /* no. of live objects in this cache */
|
|
|
|
unsigned int debug_id;
|
|
|
|
enum fscache_cache_state state;
|
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
2021-10-20 22:00:26 +08:00
|
|
|
/*
|
|
|
|
* cache operations
|
|
|
|
*/
|
|
|
|
struct fscache_cache_ops {
|
|
|
|
/* name of cache provider */
|
|
|
|
const char *name;
|
2021-10-20 22:26:17 +08:00
|
|
|
|
|
|
|
/* Acquire a volume */
|
|
|
|
void (*acquire_volume)(struct fscache_volume *volume);
|
|
|
|
|
|
|
|
/* Free the cache's data attached to a volume */
|
|
|
|
void (*free_volume)(struct fscache_volume *volume);
|
2021-10-20 22:53:34 +08:00
|
|
|
|
|
|
|
/* Look up a cookie in the cache */
|
|
|
|
bool (*lookup_cookie)(struct fscache_cookie *cookie);
|
|
|
|
|
|
|
|
/* Withdraw an object without any cookie access counts held */
|
|
|
|
void (*withdraw_cookie)(struct fscache_cookie *cookie);
|
|
|
|
|
2021-10-20 21:06:34 +08:00
|
|
|
/* Change the size of a data object */
|
|
|
|
void (*resize_cookie)(struct netfs_cache_resources *cres,
|
|
|
|
loff_t new_size);
|
|
|
|
|
2021-10-20 22:53:34 +08:00
|
|
|
/* Invalidate an object */
|
|
|
|
bool (*invalidate_cookie)(struct fscache_cookie *cookie);
|
|
|
|
|
2021-10-20 21:06:34 +08:00
|
|
|
/* Begin an operation for the netfs lib */
|
|
|
|
bool (*begin_operation)(struct netfs_cache_resources *cres,
|
|
|
|
enum fscache_want_state want_state);
|
|
|
|
|
2021-10-20 22:53:34 +08:00
|
|
|
/* Prepare to write to a live cache object */
|
|
|
|
void (*prepare_to_write)(struct fscache_cookie *cookie);
|
2021-10-20 22:00:26 +08:00
|
|
|
};
|
|
|
|
|
2021-10-20 21:34:41 +08:00
|
|
|
extern struct workqueue_struct *fscache_wq;
|
2021-11-12 07:14:29 +08:00
|
|
|
extern wait_queue_head_t fscache_clearance_waiters;
|
2021-10-20 21:34:41 +08:00
|
|
|
|
2021-10-20 22:00:26 +08:00
|
|
|
/*
|
|
|
|
* out-of-line cache backend functions
|
|
|
|
*/
|
|
|
|
extern struct rw_semaphore fscache_addremove_sem;
|
|
|
|
extern struct fscache_cache *fscache_acquire_cache(const char *name);
|
|
|
|
extern void fscache_relinquish_cache(struct fscache_cache *cache);
|
2021-10-20 22:00:26 +08:00
|
|
|
extern int fscache_add_cache(struct fscache_cache *cache,
|
|
|
|
const struct fscache_cache_ops *ops,
|
|
|
|
void *cache_priv);
|
|
|
|
extern void fscache_withdraw_cache(struct fscache_cache *cache);
|
2021-10-20 22:26:17 +08:00
|
|
|
extern void fscache_withdraw_volume(struct fscache_volume *volume);
|
2021-10-20 22:53:34 +08:00
|
|
|
extern void fscache_withdraw_cookie(struct fscache_cookie *cookie);
|
2021-10-20 22:00:26 +08:00
|
|
|
|
2021-10-20 22:00:26 +08:00
|
|
|
extern void fscache_io_error(struct fscache_cache *cache);
|
|
|
|
|
fscache: Implement volume-level access helpers
Add a pair of helper functions to manage access to a volume, pinning the
volume in place for the duration to prevent cache withdrawal from removing
it:
bool fscache_begin_volume_access(struct fscache_volume *volume,
enum fscache_access_trace why);
void fscache_end_volume_access(struct fscache_volume *volume,
enum fscache_access_trace why);
The way the access gate on the volume works/will work is:
(1) If the cache tests as not live (state is not FSCACHE_CACHE_IS_ACTIVE),
then we return false to indicate access was not permitted.
(2) If the cache tests as live, then we increment the volume's n_accesses
count and then recheck the cache liveness, ending the access if it
ceased to be live.
(3) When we end the access, we decrement the volume's n_accesses and wake
up the any waiters if it reaches 0.
(4) Whilst the cache is caching, the volume's n_accesses is kept
artificially incremented to prevent wakeups from happening.
(5) When the cache is taken offline, the state is changed to prevent new
accesses, the volume's n_accesses is decremented and we wait for it to
become 0.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/163819594158.215744.8285859817391683254.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906894315.143852.5454793807544710479.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967095028.1823006.9173132503876627466.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021501546.640689.9631510472149608443.stgit@warthog.procyon.org.uk/ # v4
2021-10-20 22:26:17 +08:00
|
|
|
extern void fscache_end_volume_access(struct fscache_volume *volume,
|
|
|
|
struct fscache_cookie *cookie,
|
|
|
|
enum fscache_access_trace why);
|
|
|
|
|
fscache: Implement cookie registration
Add functions to the fscache API to allow data file cookies to be acquired
and relinquished by the network filesystem. It is intended that the
filesystem will create such cookies per-inode under a volume.
To request a cookie, the filesystem should call:
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)
The filesystem must first have created a volume cookie, which is passed in
here. If it passes in NULL then the function will just return a NULL
cookie.
A binary key should be passed in index_key and is of size index_key_len.
This is saved in the cookie and is used to locate the associated data in
the cache.
A coherency data buffer of size aux_data_len will be allocated and
initialised from the buffer pointed to by aux_data. This is used to
validate cache objects when they're opened and is stored on disk with them
when they're committed. The data is stored in the cookie and will be
updateable by various functions in later patches.
The object_size must also be given. This is also used to perform a
coherency check and to size the backing storage appropriately.
This function disallows a cookie from being acquired twice in parallel,
though it will cause the second user to wait if the first is busy
relinquishing its cookie.
When a network filesystem has finished with a cookie, it should call:
void
fscache_relinquish_cookie(struct fscache_volume *volume,
bool retire)
If retire is true, any backing data will be discarded immediately.
Changes
=======
ver #3:
- fscache_hash()'s size parameter is now in bytes. Use __le32 as the unit
to round up to.
- When comparing cookies, simply see if the attributes are the same rather
than subtracting them to produce a strcmp-style return[1].
- Add a check to see if the cookie is still hashed at the point of
freeing.
ver #2:
- Don't hold n_accesses elevated whilst cache is bound to a cookie, but
rather add a flag that prevents the state machine from being queued when
n_accesses reaches 0.
- Remove the unused cookie pointer field from the fscache_acquire
tracepoint.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/CAHk-=whtkzB446+hX0zdLsdcUJsJ=8_-0S1mE_R+YurThfUbLA@mail.gmail.com/ [1]
Link: https://lore.kernel.org/r/163819590658.215744.14934902514281054323.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906891983.143852.6219772337558577395.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967088507.1823006.12659006350221417165.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021498432.640689.12743483856927722772.stgit@warthog.procyon.org.uk/ # v4
2021-10-20 22:53:34 +08:00
|
|
|
extern struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie,
|
|
|
|
enum fscache_cookie_trace where);
|
|
|
|
extern void fscache_put_cookie(struct fscache_cookie *cookie,
|
|
|
|
enum fscache_cookie_trace where);
|
2021-10-20 22:53:34 +08:00
|
|
|
extern void fscache_end_cookie_access(struct fscache_cookie *cookie,
|
|
|
|
enum fscache_access_trace why);
|
2021-10-20 22:53:34 +08:00
|
|
|
extern void fscache_cookie_lookup_negative(struct fscache_cookie *cookie);
|
2021-10-20 22:53:34 +08:00
|
|
|
extern void fscache_resume_after_invalidation(struct fscache_cookie *cookie);
|
2021-10-20 22:53:34 +08:00
|
|
|
extern void fscache_caching_failed(struct fscache_cookie *cookie);
|
2021-10-20 21:06:34 +08:00
|
|
|
extern bool fscache_wait_for_operation(struct netfs_cache_resources *cred,
|
|
|
|
enum fscache_want_state state);
|
2021-10-20 22:53:34 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* fscache_cookie_state - Read the state of a cookie
|
|
|
|
* @cookie: The cookie to query
|
|
|
|
*
|
|
|
|
* Get the state of a cookie, imposing an ordering between the cookie contents
|
|
|
|
* and the state value. Paired with fscache_set_cookie_state().
|
|
|
|
*/
|
|
|
|
static inline
|
|
|
|
enum fscache_cookie_state fscache_cookie_state(struct fscache_cookie *cookie)
|
|
|
|
{
|
|
|
|
return smp_load_acquire(&cookie->state);
|
|
|
|
}
|
fscache: Implement cookie registration
Add functions to the fscache API to allow data file cookies to be acquired
and relinquished by the network filesystem. It is intended that the
filesystem will create such cookies per-inode under a volume.
To request a cookie, the filesystem should call:
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)
The filesystem must first have created a volume cookie, which is passed in
here. If it passes in NULL then the function will just return a NULL
cookie.
A binary key should be passed in index_key and is of size index_key_len.
This is saved in the cookie and is used to locate the associated data in
the cache.
A coherency data buffer of size aux_data_len will be allocated and
initialised from the buffer pointed to by aux_data. This is used to
validate cache objects when they're opened and is stored on disk with them
when they're committed. The data is stored in the cookie and will be
updateable by various functions in later patches.
The object_size must also be given. This is also used to perform a
coherency check and to size the backing storage appropriately.
This function disallows a cookie from being acquired twice in parallel,
though it will cause the second user to wait if the first is busy
relinquishing its cookie.
When a network filesystem has finished with a cookie, it should call:
void
fscache_relinquish_cookie(struct fscache_volume *volume,
bool retire)
If retire is true, any backing data will be discarded immediately.
Changes
=======
ver #3:
- fscache_hash()'s size parameter is now in bytes. Use __le32 as the unit
to round up to.
- When comparing cookies, simply see if the attributes are the same rather
than subtracting them to produce a strcmp-style return[1].
- Add a check to see if the cookie is still hashed at the point of
freeing.
ver #2:
- Don't hold n_accesses elevated whilst cache is bound to a cookie, but
rather add a flag that prevents the state machine from being queued when
n_accesses reaches 0.
- Remove the unused cookie pointer field from the fscache_acquire
tracepoint.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/CAHk-=whtkzB446+hX0zdLsdcUJsJ=8_-0S1mE_R+YurThfUbLA@mail.gmail.com/ [1]
Link: https://lore.kernel.org/r/163819590658.215744.14934902514281054323.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906891983.143852.6219772337558577395.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967088507.1823006.12659006350221417165.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021498432.640689.12743483856927722772.stgit@warthog.procyon.org.uk/ # v4
2021-10-20 22:53:34 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* fscache_get_key - Get a pointer to the cookie key
|
|
|
|
* @cookie: The cookie to query
|
|
|
|
*
|
|
|
|
* Return a pointer to the where a cookie's key is stored.
|
|
|
|
*/
|
|
|
|
static inline void *fscache_get_key(struct fscache_cookie *cookie)
|
|
|
|
{
|
|
|
|
if (cookie->key_len <= sizeof(cookie->inline_key))
|
|
|
|
return cookie->inline_key;
|
|
|
|
else
|
|
|
|
return cookie->key;
|
|
|
|
}
|
|
|
|
|
2021-10-20 21:06:34 +08:00
|
|
|
static inline struct fscache_cookie *fscache_cres_cookie(struct netfs_cache_resources *cres)
|
|
|
|
{
|
|
|
|
return cres->cache_priv;
|
|
|
|
}
|
|
|
|
|
2021-11-12 07:14:29 +08:00
|
|
|
/**
|
|
|
|
* fscache_count_object - Tell fscache that an object has been added
|
|
|
|
* @cache: The cache to account to
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
static inline void fscache_count_object(struct fscache_cache *cache)
|
|
|
|
{
|
|
|
|
atomic_inc(&cache->object_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fscache_uncount_object - Tell fscache that an object has been removed
|
|
|
|
* @cache: The cache to account to
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
static inline void fscache_uncount_object(struct fscache_cache *cache)
|
|
|
|
{
|
|
|
|
if (atomic_dec_and_test(&cache->object_count))
|
|
|
|
wake_up_all(&fscache_clearance_waiters);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fscache_wait_for_objects - Wait for all objects to be withdrawn
|
|
|
|
* @cache: The cache to query
|
|
|
|
*
|
|
|
|
* Wait for all extant objects in a cache to finish being withdrawn
|
|
|
|
* and go away.
|
|
|
|
*/
|
|
|
|
static inline void fscache_wait_for_objects(struct fscache_cache *cache)
|
|
|
|
{
|
|
|
|
wait_event(fscache_clearance_waiters,
|
|
|
|
atomic_read(&cache->object_count) == 0);
|
|
|
|
}
|
|
|
|
|
2021-10-21 06:06:16 +08:00
|
|
|
#ifdef CONFIG_FSCACHE_STATS
|
|
|
|
extern atomic_t fscache_n_read;
|
|
|
|
extern atomic_t fscache_n_write;
|
2021-10-22 04:58:29 +08:00
|
|
|
extern atomic_t fscache_n_no_write_space;
|
|
|
|
extern atomic_t fscache_n_no_create_space;
|
2021-10-22 16:17:58 +08:00
|
|
|
extern atomic_t fscache_n_culled;
|
2021-10-21 06:06:16 +08:00
|
|
|
#define fscache_count_read() atomic_inc(&fscache_n_read)
|
|
|
|
#define fscache_count_write() atomic_inc(&fscache_n_write)
|
2021-10-22 04:58:29 +08:00
|
|
|
#define fscache_count_no_write_space() atomic_inc(&fscache_n_no_write_space)
|
|
|
|
#define fscache_count_no_create_space() atomic_inc(&fscache_n_no_create_space)
|
2021-10-22 16:17:58 +08:00
|
|
|
#define fscache_count_culled() atomic_inc(&fscache_n_culled)
|
2021-10-21 06:06:16 +08:00
|
|
|
#else
|
|
|
|
#define fscache_count_read() do {} while(0)
|
|
|
|
#define fscache_count_write() do {} while(0)
|
2021-10-22 04:58:29 +08:00
|
|
|
#define fscache_count_no_write_space() do {} while(0)
|
|
|
|
#define fscache_count_no_create_space() do {} while(0)
|
2021-10-22 16:17:58 +08:00
|
|
|
#define fscache_count_culled() do {} while(0)
|
2021-10-21 06:06:16 +08:00
|
|
|
#endif
|
|
|
|
|
2009-04-03 23:42:36 +08:00
|
|
|
#endif /* _LINUX_FSCACHE_CACHE_H */
|