mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
fscache: Provide and use cache methods to lookup/create/free a volume
Add cache methods to lookup, create and remove a volume. Looking up or creating the volume requires the cache pinning for access; freeing the volume requires the volume pinning for access. The ->acquire_volume() method is used to ask the cache backend to lookup and, if necessary, create a volume; the ->free_volume() method is used to free the resources for a volume. 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/163819597821.215744.5225318658134989949.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/163906898645.143852.8537799955945956818.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967099771.1823006.1455197910571061835.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021507345.640689.4073511598838843040.stgit@warthog.procyon.org.uk/ # v4
This commit is contained in:
parent
2e0c76aee2
commit
bfa22da3ed
@ -15,6 +15,8 @@ static struct hlist_bl_head fscache_volume_hash[1 << fscache_volume_hash_shift];
|
|||||||
static atomic_t fscache_volume_debug_id;
|
static atomic_t fscache_volume_debug_id;
|
||||||
static LIST_HEAD(fscache_volumes);
|
static LIST_HEAD(fscache_volumes);
|
||||||
|
|
||||||
|
static void fscache_create_volume_work(struct work_struct *work);
|
||||||
|
|
||||||
struct fscache_volume *fscache_get_volume(struct fscache_volume *volume,
|
struct fscache_volume *fscache_get_volume(struct fscache_volume *volume,
|
||||||
enum fscache_volume_trace where)
|
enum fscache_volume_trace where)
|
||||||
{
|
{
|
||||||
@ -213,7 +215,7 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,
|
|||||||
|
|
||||||
volume->cache = cache;
|
volume->cache = cache;
|
||||||
INIT_LIST_HEAD(&volume->proc_link);
|
INIT_LIST_HEAD(&volume->proc_link);
|
||||||
INIT_WORK(&volume->work, NULL /* PLACEHOLDER */);
|
INIT_WORK(&volume->work, fscache_create_volume_work);
|
||||||
refcount_set(&volume->ref, 1);
|
refcount_set(&volume->ref, 1);
|
||||||
spin_lock_init(&volume->lock);
|
spin_lock_init(&volume->lock);
|
||||||
|
|
||||||
@ -249,6 +251,58 @@ err_cache:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a volume's representation on disk. Have a volume ref and a cache
|
||||||
|
* access we have to release.
|
||||||
|
*/
|
||||||
|
static void fscache_create_volume_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
const struct fscache_cache_ops *ops;
|
||||||
|
struct fscache_volume *volume =
|
||||||
|
container_of(work, struct fscache_volume, work);
|
||||||
|
|
||||||
|
fscache_see_volume(volume, fscache_volume_see_create_work);
|
||||||
|
|
||||||
|
ops = volume->cache->ops;
|
||||||
|
if (ops->acquire_volume)
|
||||||
|
ops->acquire_volume(volume);
|
||||||
|
fscache_end_cache_access(volume->cache,
|
||||||
|
fscache_access_acquire_volume_end);
|
||||||
|
|
||||||
|
clear_bit_unlock(FSCACHE_VOLUME_CREATING, &volume->flags);
|
||||||
|
wake_up_bit(&volume->flags, FSCACHE_VOLUME_CREATING);
|
||||||
|
fscache_put_volume(volume, fscache_volume_put_create_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dispatch a worker thread to create a volume's representation on disk.
|
||||||
|
*/
|
||||||
|
void fscache_create_volume(struct fscache_volume *volume, bool wait)
|
||||||
|
{
|
||||||
|
if (test_and_set_bit(FSCACHE_VOLUME_CREATING, &volume->flags))
|
||||||
|
goto maybe_wait;
|
||||||
|
if (volume->cache_priv)
|
||||||
|
goto no_wait; /* We raced */
|
||||||
|
if (!fscache_begin_cache_access(volume->cache,
|
||||||
|
fscache_access_acquire_volume))
|
||||||
|
goto no_wait;
|
||||||
|
|
||||||
|
fscache_get_volume(volume, fscache_volume_get_create_work);
|
||||||
|
if (!schedule_work(&volume->work))
|
||||||
|
fscache_put_volume(volume, fscache_volume_put_create_work);
|
||||||
|
|
||||||
|
maybe_wait:
|
||||||
|
if (wait) {
|
||||||
|
fscache_see_volume(volume, fscache_volume_wait_create_work);
|
||||||
|
wait_on_bit(&volume->flags, FSCACHE_VOLUME_CREATING,
|
||||||
|
TASK_UNINTERRUPTIBLE);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
no_wait:
|
||||||
|
clear_bit_unlock(FSCACHE_VOLUME_CREATING, &volume->flags);
|
||||||
|
wake_up_bit(&volume->flags, FSCACHE_VOLUME_CREATING);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire a volume representation cookie and link it to a (proposed) cache.
|
* Acquire a volume representation cookie and link it to a (proposed) cache.
|
||||||
*/
|
*/
|
||||||
@ -269,7 +323,7 @@ struct fscache_volume *__fscache_acquire_volume(const char *volume_key,
|
|||||||
return ERR_PTR(-EBUSY);
|
return ERR_PTR(-EBUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PLACEHOLDER: Create the volume if we have a cache available
|
fscache_create_volume(volume, false);
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__fscache_acquire_volume);
|
EXPORT_SYMBOL(__fscache_acquire_volume);
|
||||||
@ -316,7 +370,12 @@ static void fscache_free_volume(struct fscache_volume *volume)
|
|||||||
struct fscache_cache *cache = volume->cache;
|
struct fscache_cache *cache = volume->cache;
|
||||||
|
|
||||||
if (volume->cache_priv) {
|
if (volume->cache_priv) {
|
||||||
// PLACEHOLDER: Detach any attached cache
|
__fscache_begin_volume_access(volume, NULL,
|
||||||
|
fscache_access_relinquish_volume);
|
||||||
|
if (volume->cache_priv)
|
||||||
|
cache->ops->free_volume(volume);
|
||||||
|
fscache_end_volume_access(volume, NULL,
|
||||||
|
fscache_access_relinquish_volume_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
down_write(&fscache_addremove_sem);
|
down_write(&fscache_addremove_sem);
|
||||||
@ -369,6 +428,30 @@ void __fscache_relinquish_volume(struct fscache_volume *volume,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__fscache_relinquish_volume);
|
EXPORT_SYMBOL(__fscache_relinquish_volume);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fscache_withdraw_volume - Withdraw a volume from being cached
|
||||||
|
* @volume: Volume cookie
|
||||||
|
*
|
||||||
|
* Withdraw a cache volume from service, waiting for all accesses to complete
|
||||||
|
* before returning.
|
||||||
|
*/
|
||||||
|
void fscache_withdraw_volume(struct fscache_volume *volume)
|
||||||
|
{
|
||||||
|
int n_accesses;
|
||||||
|
|
||||||
|
_debug("withdraw V=%x", volume->debug_id);
|
||||||
|
|
||||||
|
/* Allow wakeups on dec-to-0 */
|
||||||
|
n_accesses = atomic_dec_return(&volume->n_accesses);
|
||||||
|
trace_fscache_access_volume(volume->debug_id, 0,
|
||||||
|
refcount_read(&volume->ref),
|
||||||
|
n_accesses, fscache_access_cache_unpin);
|
||||||
|
|
||||||
|
wait_var_event(&volume->n_accesses,
|
||||||
|
atomic_read(&volume->n_accesses) == 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(fscache_withdraw_volume);
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
/*
|
/*
|
||||||
* Generate a list of volumes in /proc/fs/fscache/volumes
|
* Generate a list of volumes in /proc/fs/fscache/volumes
|
||||||
|
@ -51,6 +51,12 @@ struct fscache_cache {
|
|||||||
struct fscache_cache_ops {
|
struct fscache_cache_ops {
|
||||||
/* name of cache provider */
|
/* name of cache provider */
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct workqueue_struct *fscache_wq;
|
extern struct workqueue_struct *fscache_wq;
|
||||||
@ -65,6 +71,7 @@ extern int fscache_add_cache(struct fscache_cache *cache,
|
|||||||
const struct fscache_cache_ops *ops,
|
const struct fscache_cache_ops *ops,
|
||||||
void *cache_priv);
|
void *cache_priv);
|
||||||
extern void fscache_withdraw_cache(struct fscache_cache *cache);
|
extern void fscache_withdraw_cache(struct fscache_cache *cache);
|
||||||
|
extern void fscache_withdraw_volume(struct fscache_volume *volume);
|
||||||
|
|
||||||
extern void fscache_end_volume_access(struct fscache_volume *volume,
|
extern void fscache_end_volume_access(struct fscache_volume *volume,
|
||||||
struct fscache_cookie *cookie,
|
struct fscache_cookie *cookie,
|
||||||
|
@ -64,8 +64,12 @@ enum fscache_cookie_trace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum fscache_access_trace {
|
enum fscache_access_trace {
|
||||||
|
fscache_access_acquire_volume,
|
||||||
|
fscache_access_acquire_volume_end,
|
||||||
fscache_access_cache_pin,
|
fscache_access_cache_pin,
|
||||||
fscache_access_cache_unpin,
|
fscache_access_cache_unpin,
|
||||||
|
fscache_access_relinquish_volume,
|
||||||
|
fscache_access_relinquish_volume_end,
|
||||||
fscache_access_unlive,
|
fscache_access_unlive,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -96,7 +100,8 @@ enum fscache_access_trace {
|
|||||||
EM(fscache_volume_put_hash_collision, "PUT hcoll") \
|
EM(fscache_volume_put_hash_collision, "PUT hcoll") \
|
||||||
EM(fscache_volume_put_relinquish, "PUT relnq") \
|
EM(fscache_volume_put_relinquish, "PUT relnq") \
|
||||||
EM(fscache_volume_see_create_work, "SEE creat") \
|
EM(fscache_volume_see_create_work, "SEE creat") \
|
||||||
E_(fscache_volume_see_hash_wake, "SEE hwake")
|
EM(fscache_volume_see_hash_wake, "SEE hwake") \
|
||||||
|
E_(fscache_volume_wait_create_work, "WAIT crea")
|
||||||
|
|
||||||
#define fscache_cookie_traces \
|
#define fscache_cookie_traces \
|
||||||
EM(fscache_cookie_collision, "*COLLIDE*") \
|
EM(fscache_cookie_collision, "*COLLIDE*") \
|
||||||
@ -115,8 +120,12 @@ enum fscache_access_trace {
|
|||||||
E_(fscache_cookie_see_work, "- work ")
|
E_(fscache_cookie_see_work, "- work ")
|
||||||
|
|
||||||
#define fscache_access_traces \
|
#define fscache_access_traces \
|
||||||
|
EM(fscache_access_acquire_volume, "BEGIN acq_vol") \
|
||||||
|
EM(fscache_access_acquire_volume_end, "END acq_vol") \
|
||||||
EM(fscache_access_cache_pin, "PIN cache ") \
|
EM(fscache_access_cache_pin, "PIN cache ") \
|
||||||
EM(fscache_access_cache_unpin, "UNPIN cache ") \
|
EM(fscache_access_cache_unpin, "UNPIN cache ") \
|
||||||
|
EM(fscache_access_relinquish_volume, "BEGIN rlq_vol") \
|
||||||
|
EM(fscache_access_relinquish_volume_end,"END rlq_vol") \
|
||||||
E_(fscache_access_unlive, "END unlive ")
|
E_(fscache_access_unlive, "END unlive ")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user