Commit bfa22da3 authored by David Howells's avatar David Howells
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeff 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
parent 2e0c76ae
Loading
Loading
Loading
Loading
+86 −3
Original line number Diff line number Diff line
@@ -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 LIST_HEAD(fscache_volumes);

static void fscache_create_volume_work(struct work_struct *work);

struct fscache_volume *fscache_get_volume(struct fscache_volume *volume,
					  enum fscache_volume_trace where)
{
@@ -213,7 +215,7 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,

	volume->cache = cache;
	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);
	spin_lock_init(&volume->lock);

@@ -249,6 +251,58 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,
	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.
 */
@@ -269,7 +323,7 @@ struct fscache_volume *__fscache_acquire_volume(const char *volume_key,
		return ERR_PTR(-EBUSY);
	}

	// PLACEHOLDER: Create the volume if we have a cache available
	fscache_create_volume(volume, false);
	return 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;

	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);
@@ -369,6 +428,30 @@ void __fscache_relinquish_volume(struct fscache_volume *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
/*
 * Generate a list of volumes in /proc/fs/fscache/volumes
+7 −0
Original line number Diff line number Diff line
@@ -51,6 +51,12 @@ struct fscache_cache {
struct fscache_cache_ops {
	/* name of cache provider */
	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;
@@ -65,6 +71,7 @@ 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);
extern void fscache_withdraw_volume(struct fscache_volume *volume);

extern void fscache_end_volume_access(struct fscache_volume *volume,
				      struct fscache_cookie *cookie,
+10 −1
Original line number Diff line number Diff line
@@ -64,8 +64,12 @@ enum fscache_cookie_trace {
};

enum fscache_access_trace {
	fscache_access_acquire_volume,
	fscache_access_acquire_volume_end,
	fscache_access_cache_pin,
	fscache_access_cache_unpin,
	fscache_access_relinquish_volume,
	fscache_access_relinquish_volume_end,
	fscache_access_unlive,
};

@@ -96,7 +100,8 @@ enum fscache_access_trace {
	EM(fscache_volume_put_hash_collision,	"PUT hcoll")		\
	EM(fscache_volume_put_relinquish,	"PUT relnq")		\
	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						\
	EM(fscache_cookie_collision,		"*COLLIDE*")		\
@@ -115,8 +120,12 @@ enum fscache_access_trace {
	E_(fscache_cookie_see_work,		"-   work ")

#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_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 ")

/*