diff options
Diffstat (limited to 'fs/fscache/object.c')
| -rw-r--r-- | fs/fscache/object.c | 72 | 
1 files changed, 72 insertions, 0 deletions
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 773bc798a41..80b549141ea 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -14,6 +14,7 @@  #define FSCACHE_DEBUG_LEVEL COOKIE  #include <linux/module.h> +#include <linux/slab.h>  #include "internal.h"  const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { @@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {  	[FSCACHE_OBJECT_CREATING]	= "OBJECT_CREATING",  	[FSCACHE_OBJECT_AVAILABLE]	= "OBJECT_AVAILABLE",  	[FSCACHE_OBJECT_ACTIVE]		= "OBJECT_ACTIVE", +	[FSCACHE_OBJECT_INVALIDATING]	= "OBJECT_INVALIDATING",  	[FSCACHE_OBJECT_UPDATING]	= "OBJECT_UPDATING",  	[FSCACHE_OBJECT_DYING]		= "OBJECT_DYING",  	[FSCACHE_OBJECT_LC_DYING]	= "OBJECT_LC_DYING", @@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {  	[FSCACHE_OBJECT_CREATING]	= "CRTN",  	[FSCACHE_OBJECT_AVAILABLE]	= "AVBL",  	[FSCACHE_OBJECT_ACTIVE]		= "ACTV", +	[FSCACHE_OBJECT_INVALIDATING]	= "INVL",  	[FSCACHE_OBJECT_UPDATING]	= "UPDT",  	[FSCACHE_OBJECT_DYING]		= "DYNG",  	[FSCACHE_OBJECT_LC_DYING]	= "LCDY", @@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *);  static void fscache_initialise_object(struct fscache_object *);  static void fscache_lookup_object(struct fscache_object *);  static void fscache_object_available(struct fscache_object *); +static void fscache_invalidate_object(struct fscache_object *);  static void fscache_release_object(struct fscache_object *);  static void fscache_withdraw_object(struct fscache_object *);  static void fscache_enqueue_dependents(struct fscache_object *); @@ -79,6 +83,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object)  }  /* + * Notify netfs of invalidation completion. + */ +static inline void fscache_invalidation_complete(struct fscache_cookie *cookie) +{ +	if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) +		wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); +} + +/*   * process events that have been sent to an object's state machine   * - initiates parent lookup   * - does object lookup @@ -125,6 +138,16 @@ static void fscache_object_state_machine(struct fscache_object *object)  	case FSCACHE_OBJECT_ACTIVE:  		goto active_transit; +		/* Invalidate an object on disk */ +	case FSCACHE_OBJECT_INVALIDATING: +		clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events); +		fscache_stat(&fscache_n_invalidates_run); +		fscache_stat(&fscache_n_cop_invalidate_object); +		fscache_invalidate_object(object); +		fscache_stat_d(&fscache_n_cop_invalidate_object); +		fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); +		goto active_transit; +  		/* update the object metadata on disk */  	case FSCACHE_OBJECT_UPDATING:  		clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); @@ -275,6 +298,9 @@ active_transit:  	case FSCACHE_OBJECT_EV_ERROR:  		new_state = FSCACHE_OBJECT_DYING;  		goto change_state; +	case FSCACHE_OBJECT_EV_INVALIDATE: +		new_state = FSCACHE_OBJECT_INVALIDATING; +		goto change_state;  	case FSCACHE_OBJECT_EV_UPDATE:  		new_state = FSCACHE_OBJECT_UPDATING;  		goto change_state; @@ -679,6 +705,7 @@ static void fscache_withdraw_object(struct fscache_object *object)  		if (object->cookie == cookie) {  			hlist_del_init(&object->cookie_link);  			object->cookie = NULL; +			fscache_invalidation_complete(cookie);  			detached = true;  		}  		spin_unlock(&cookie->lock); @@ -888,3 +915,48 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object,  	return result;  }  EXPORT_SYMBOL(fscache_check_aux); + +/* + * Asynchronously invalidate an object. + */ +static void fscache_invalidate_object(struct fscache_object *object) +{ +	struct fscache_operation *op; +	struct fscache_cookie *cookie = object->cookie; + +	_enter("{OBJ%x}", object->debug_id); + +	/* Reject any new read/write ops and abort any that are pending. */ +	fscache_invalidate_writes(cookie); +	clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); +	fscache_cancel_all_ops(object); + +	/* Now we have to wait for in-progress reads and writes */ +	op = kzalloc(sizeof(*op), GFP_KERNEL); +	if (!op) { +		fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); +		_leave(" [ENOMEM]"); +		return; +	} + +	fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); +	op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); + +	spin_lock(&cookie->lock); +	if (fscache_submit_exclusive_op(object, op) < 0) +		BUG(); +	spin_unlock(&cookie->lock); +	fscache_put_operation(op); + +	/* Once we've completed the invalidation, we know there will be no data +	 * stored in the cache and thus we can reinstate the data-check-skip +	 * optimisation. +	 */ +	set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); + +	/* We can allow read and write requests to come in once again.  They'll +	 * queue up behind our exclusive invalidation operation. +	 */ +	fscache_invalidation_complete(cookie); +	_leave(""); +}  |