diff options
Diffstat (limited to 'fs/fscache/object.c')
| -rw-r--r-- | fs/fscache/object.c | 101 | 
1 files changed, 93 insertions, 8 deletions
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index b6b897c550a..50d41c18021 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 @@ -90,6 +103,7 @@ static void fscache_object_state_machine(struct fscache_object *object)  {  	enum fscache_object_state new_state;  	struct fscache_cookie *cookie; +	int event;  	ASSERT(object != NULL); @@ -101,7 +115,8 @@ static void fscache_object_state_machine(struct fscache_object *object)  		/* wait for the parent object to become ready */  	case FSCACHE_OBJECT_INIT:  		object->event_mask = -			ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED); +			FSCACHE_OBJECT_EVENTS_MASK & +			~(1 << FSCACHE_OBJECT_EV_CLEARED);  		fscache_initialise_object(object);  		goto done; @@ -125,6 +140,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); @@ -251,13 +276,17 @@ static void fscache_object_state_machine(struct fscache_object *object)  	/* determine the transition from a lookup state */  lookup_transit: -	switch (fls(object->events & object->event_mask) - 1) { +	event = fls(object->events & object->event_mask) - 1; +	switch (event) {  	case FSCACHE_OBJECT_EV_WITHDRAW:  	case FSCACHE_OBJECT_EV_RETIRE:  	case FSCACHE_OBJECT_EV_RELEASE:  	case FSCACHE_OBJECT_EV_ERROR:  		new_state = FSCACHE_OBJECT_LC_DYING;  		goto change_state; +	case FSCACHE_OBJECT_EV_INVALIDATE: +		new_state = FSCACHE_OBJECT_INVALIDATING; +		goto change_state;  	case FSCACHE_OBJECT_EV_REQUEUE:  		goto done;  	case -1: @@ -268,13 +297,17 @@ lookup_transit:  	/* determine the transition from an active state */  active_transit: -	switch (fls(object->events & object->event_mask) - 1) { +	event = fls(object->events & object->event_mask) - 1; +	switch (event) {  	case FSCACHE_OBJECT_EV_WITHDRAW:  	case FSCACHE_OBJECT_EV_RETIRE:  	case FSCACHE_OBJECT_EV_RELEASE:  	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; @@ -287,7 +320,8 @@ active_transit:  	/* determine the transition from a terminal state */  terminal_transit: -	switch (fls(object->events & object->event_mask) - 1) { +	event = fls(object->events & object->event_mask) - 1; +	switch (event) {  	case FSCACHE_OBJECT_EV_WITHDRAW:  		new_state = FSCACHE_OBJECT_WITHDRAWING;  		goto change_state; @@ -320,8 +354,8 @@ done:  unsupported_event:  	printk(KERN_ERR "FS-Cache:" -	       " Unsupported event %lx [mask %lx] in state %s\n", -	       object->events, object->event_mask, +	       " Unsupported event %d [%lx/%lx] in state %s\n", +	       event, object->events, object->event_mask,  	       fscache_object_states[object->state]);  	BUG();  } @@ -587,8 +621,6 @@ static void fscache_object_available(struct fscache_object *object)  	if (object->n_in_progress == 0) {  		if (object->n_ops > 0) {  			ASSERTCMP(object->n_ops, >=, object->n_obj_ops); -			ASSERTIF(object->n_ops > object->n_obj_ops, -				 !list_empty(&object->pending_ops));  			fscache_start_operations(object);  		} else {  			ASSERT(list_empty(&object->pending_ops)); @@ -681,6 +713,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); @@ -890,3 +923,55 @@ 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) +		goto submit_op_failed; +	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(""); +	return; + +submit_op_failed: +	spin_unlock(&cookie->lock); +	kfree(op); +	fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); +	_leave(" [EIO]"); +}  |