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

FS-Cache: Add interface to check consistency of a cached object



Extend the fscache netfs API so that the netfs can ask as to whether a cache
object is up to date with respect to its corresponding netfs object:

	int fscache_check_consistency(struct fscache_cookie *cookie)

This will call back to the netfs to check whether the auxiliary data associated
with a cookie is correct.  It returns 0 if it is and -ESTALE if it isn't; it
may also return -ENOMEM and -ERESTARTSYS.

The backends now have to implement a mandatory operation pointer:

	int (*check_consistency)(struct fscache_object *object)

that corresponds to the above API call.  FS-Cache takes care of pinning the
object and the cookie in memory and managing this call with respect to the
object state.

Original-author: Hongyi Jia <jiayisuse@gmail.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: Hongyi Jia <jiayisuse@gmail.com>
cc: Milosz Tanski <milosz@adfin.com>
parent 6e466452
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -299,6 +299,15 @@ performed on the denizens of the cache. These are held in a structure of type:
     enough space in the cache to permit this.


 (*) Check coherency state of an object [mandatory]:

	int (*check_consistency)(struct fscache_object *object)

     This method is called to have the cache check the saved auxiliary data of
     the object against the netfs's idea of the state.  0 should be returned
     if they're consistent and -ESTALE otherwise.  -ENOMEM and -ERESTARTSYS
     may also be returned.

 (*) Update object [mandatory]:

	int (*update_object)(struct fscache_object *object)
+13 −4
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ This document contains the following sections:
	 (9) Setting the data file size
	(10) Page alloc/read/write
	(11) Page uncaching
	(12) Index and data file update
	(12) Index and data file consistency
	(13) Miscellaneous cookie operations
	(14) Cookie unregistration
	(15) Index invalidation
@@ -690,9 +690,18 @@ written to the cache and for the cache to finish with the page generally. No
error is returned.


==========================
INDEX AND DATA FILE UPDATE
==========================
===============================
INDEX AND DATA FILE CONSISTENCY
===============================

To find out whether auxiliary data for an object is up to data within the
cache, the following function can be called:

	int fscache_check_consistency(struct fscache_cookie *cookie)

This will call back to the netfs to check whether the auxiliary data associated
with a cookie is correct.  It returns 0 if it is and -ESTALE if it isn't; it
may also return -ENOMEM and -ERESTARTSYS.

To request an update of the index data for an index or other object, the
following function should be called:
+71 −0
Original line number Diff line number Diff line
@@ -558,3 +558,74 @@ void __fscache_cookie_put(struct fscache_cookie *cookie)

	_leave("");
}

/*
 * check the consistency between the netfs inode and the backing cache
 *
 * NOTE: it only serves no-index type
 */
int __fscache_check_consistency(struct fscache_cookie *cookie)
{
	struct fscache_operation *op;
	struct fscache_object *object;
	int ret;

	_enter("%p,", cookie);

	ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE);

	if (fscache_wait_for_deferred_lookup(cookie) < 0)
		return -ERESTARTSYS;

	if (hlist_empty(&cookie->backing_objects))
		return 0;

	op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY);
	if (!op)
		return -ENOMEM;

	fscache_operation_init(op, NULL, NULL);
	op->flags = FSCACHE_OP_MYTHREAD |
		(1 << FSCACHE_OP_WAITING);

	spin_lock(&cookie->lock);

	if (hlist_empty(&cookie->backing_objects))
		goto inconsistent;
	object = hlist_entry(cookie->backing_objects.first,
			     struct fscache_object, cookie_link);
	if (test_bit(FSCACHE_IOERROR, &object->cache->flags))
		goto inconsistent;

	op->debug_id = atomic_inc_return(&fscache_op_debug_id);

	atomic_inc(&cookie->n_active);
	if (fscache_submit_op(object, op) < 0)
		goto submit_failed;

	/* the work queue now carries its own ref on the object */
	spin_unlock(&cookie->lock);

	ret = fscache_wait_for_operation_activation(object, op,
						    NULL, NULL, NULL);
	if (ret == 0) {
		/* ask the cache to honour the operation */
		ret = object->cache->ops->check_consistency(op);
		fscache_op_complete(op, false);
	} else if (ret == -ENOBUFS) {
		ret = 0;
	}

	fscache_put_operation(op);
	_leave(" = %d", ret);
	return ret;

submit_failed:
	atomic_dec(&cookie->n_active);
inconsistent:
	spin_unlock(&cookie->lock);
	kfree(op);
	_leave(" = -ESTALE");
	return -ESTALE;
}
EXPORT_SYMBOL(__fscache_check_consistency);
+6 −0
Original line number Diff line number Diff line
@@ -130,6 +130,12 @@ extern void fscache_operation_gc(struct work_struct *);
/*
 * page.c
 */
extern int fscache_wait_for_deferred_lookup(struct fscache_cookie *);
extern int fscache_wait_for_operation_activation(struct fscache_object *,
						 struct fscache_operation *,
						 atomic_t *,
						 atomic_t *,
						 void (*)(struct fscache_operation *));
extern void fscache_invalidate_writes(struct fscache_cookie *);

/*
+31 −24
Original line number Diff line number Diff line
@@ -278,7 +278,7 @@ static struct fscache_retrieval *fscache_alloc_retrieval(
/*
 * wait for a deferred lookup to complete
 */
static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
{
	unsigned long jif;

@@ -322,41 +322,45 @@ static void fscache_do_cancel_retrieval(struct fscache_operation *_op)
/*
 * wait for an object to become active (or dead)
 */
static int fscache_wait_for_retrieval_activation(struct fscache_object *object,
						 struct fscache_retrieval *op,
int fscache_wait_for_operation_activation(struct fscache_object *object,
					  struct fscache_operation *op,
					  atomic_t *stat_op_waits,
						 atomic_t *stat_object_dead)
					  atomic_t *stat_object_dead,
					  void (*do_cancel)(struct fscache_operation *))
{
	int ret;

	if (!test_bit(FSCACHE_OP_WAITING, &op->op.flags))
	if (!test_bit(FSCACHE_OP_WAITING, &op->flags))
		goto check_if_dead;

	_debug(">>> WT");
	if (stat_op_waits)
		fscache_stat(stat_op_waits);
	if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
	if (wait_on_bit(&op->flags, FSCACHE_OP_WAITING,
			fscache_wait_bit_interruptible,
			TASK_INTERRUPTIBLE) != 0) {
		ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval);
		ret = fscache_cancel_op(op, do_cancel);
		if (ret == 0)
			return -ERESTARTSYS;

		/* it's been removed from the pending queue by another party,
		 * so we should get to run shortly */
		wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
		wait_on_bit(&op->flags, FSCACHE_OP_WAITING,
			    fscache_wait_bit, TASK_UNINTERRUPTIBLE);
	}
	_debug("<<< GO");

check_if_dead:
	if (op->op.state == FSCACHE_OP_ST_CANCELLED) {
	if (op->state == FSCACHE_OP_ST_CANCELLED) {
		if (stat_object_dead)
			fscache_stat(stat_object_dead);
		_leave(" = -ENOBUFS [cancelled]");
		return -ENOBUFS;
	}
	if (unlikely(fscache_object_is_dead(object))) {
		pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state);
		fscache_cancel_op(&op->op, fscache_do_cancel_retrieval);
		pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->state);
		fscache_cancel_op(op, do_cancel);
		if (stat_object_dead)
			fscache_stat(stat_object_dead);
		return -ENOBUFS;
	}
@@ -432,10 +436,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,

	/* we wait for the operation to become active, and then process it
	 * *here*, in this thread, and not in the thread pool */
	ret = fscache_wait_for_retrieval_activation(
		object, op,
	ret = fscache_wait_for_operation_activation(
		object, &op->op,
		__fscache_stat(&fscache_n_retrieval_op_waits),
		__fscache_stat(&fscache_n_retrievals_object_dead));
		__fscache_stat(&fscache_n_retrievals_object_dead),
		fscache_do_cancel_retrieval);
	if (ret < 0)
		goto error;

@@ -557,10 +562,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,

	/* we wait for the operation to become active, and then process it
	 * *here*, in this thread, and not in the thread pool */
	ret = fscache_wait_for_retrieval_activation(
		object, op,
	ret = fscache_wait_for_operation_activation(
		object, &op->op,
		__fscache_stat(&fscache_n_retrieval_op_waits),
		__fscache_stat(&fscache_n_retrievals_object_dead));
		__fscache_stat(&fscache_n_retrievals_object_dead),
		fscache_do_cancel_retrieval);
	if (ret < 0)
		goto error;

@@ -658,10 +664,11 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,

	fscache_stat(&fscache_n_alloc_ops);

	ret = fscache_wait_for_retrieval_activation(
		object, op,
	ret = fscache_wait_for_operation_activation(
		object, &op->op,
		__fscache_stat(&fscache_n_alloc_op_waits),
		__fscache_stat(&fscache_n_allocs_object_dead));
		__fscache_stat(&fscache_n_allocs_object_dead),
		fscache_do_cancel_retrieval);
	if (ret < 0)
		goto error;

Loading