diff options
Diffstat (limited to 'fs/fscache/operation.c')
| -rw-r--r-- | fs/fscache/operation.c | 140 | 
1 files changed, 108 insertions, 32 deletions
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 30afdfa7aec..762a9ec4ffa 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -37,6 +37,7 @@ void fscache_enqueue_operation(struct fscache_operation *op)  	ASSERT(op->processor != NULL);  	ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE);  	ASSERTCMP(atomic_read(&op->usage), >, 0); +	ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS);  	fscache_stat(&fscache_n_op_enqueue);  	switch (op->flags & FSCACHE_OP_TYPE) { @@ -64,6 +65,9 @@ EXPORT_SYMBOL(fscache_enqueue_operation);  static void fscache_run_op(struct fscache_object *object,  			   struct fscache_operation *op)  { +	ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); + +	op->state = FSCACHE_OP_ST_IN_PROGRESS;  	object->n_in_progress++;  	if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))  		wake_up_bit(&op->flags, FSCACHE_OP_WAITING); @@ -84,18 +88,21 @@ int fscache_submit_exclusive_op(struct fscache_object *object,  	_enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); +	ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); +	ASSERTCMP(atomic_read(&op->usage), >, 0); +  	spin_lock(&object->lock);  	ASSERTCMP(object->n_ops, >=, object->n_in_progress);  	ASSERTCMP(object->n_ops, >=, object->n_exclusive);  	ASSERT(list_empty(&op->pend_link)); -	ret = -ENOBUFS; +	op->state = FSCACHE_OP_ST_PENDING;  	if (fscache_object_is_active(object)) {  		op->object = object;  		object->n_ops++;  		object->n_exclusive++;	/* reads and writes must wait */ -		if (object->n_ops > 1) { +		if (object->n_in_progress > 0) {  			atomic_inc(&op->usage);  			list_add_tail(&op->pend_link, &object->pending_ops);  			fscache_stat(&fscache_n_op_pend); @@ -121,8 +128,11 @@ int fscache_submit_exclusive_op(struct fscache_object *object,  		fscache_stat(&fscache_n_op_pend);  		ret = 0;  	} else { -		/* not allowed to submit ops in any other state */ -		BUG(); +		/* If we're in any other state, there must have been an I/O +		 * error of some nature. +		 */ +		ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags)); +		ret = -EIO;  	}  	spin_unlock(&object->lock); @@ -186,6 +196,7 @@ int fscache_submit_op(struct fscache_object *object,  	_enter("{OBJ%x OP%x},{%u}",  	       object->debug_id, op->debug_id, atomic_read(&op->usage)); +	ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);  	ASSERTCMP(atomic_read(&op->usage), >, 0);  	spin_lock(&object->lock); @@ -196,6 +207,7 @@ int fscache_submit_op(struct fscache_object *object,  	ostate = object->state;  	smp_rmb(); +	op->state = FSCACHE_OP_ST_PENDING;  	if (fscache_object_is_active(object)) {  		op->object = object;  		object->n_ops++; @@ -225,12 +237,15 @@ int fscache_submit_op(struct fscache_object *object,  		   object->state == FSCACHE_OBJECT_LC_DYING ||  		   object->state == FSCACHE_OBJECT_WITHDRAWING) {  		fscache_stat(&fscache_n_op_rejected); +		op->state = FSCACHE_OP_ST_CANCELLED;  		ret = -ENOBUFS;  	} else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) {  		fscache_report_unexpected_submission(object, op, ostate);  		ASSERT(!fscache_object_is_active(object)); +		op->state = FSCACHE_OP_ST_CANCELLED;  		ret = -ENOBUFS;  	} else { +		op->state = FSCACHE_OP_ST_CANCELLED;  		ret = -ENOBUFS;  	} @@ -283,20 +298,28 @@ void fscache_start_operations(struct fscache_object *object)  /*   * cancel an operation that's pending on an object   */ -int fscache_cancel_op(struct fscache_operation *op) +int fscache_cancel_op(struct fscache_operation *op, +		      void (*do_cancel)(struct fscache_operation *))  {  	struct fscache_object *object = op->object;  	int ret;  	_enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); +	ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING); +	ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED); +	ASSERTCMP(atomic_read(&op->usage), >, 0); +  	spin_lock(&object->lock);  	ret = -EBUSY; -	if (!list_empty(&op->pend_link)) { +	if (op->state == FSCACHE_OP_ST_PENDING) { +		ASSERT(!list_empty(&op->pend_link));  		fscache_stat(&fscache_n_op_cancelled);  		list_del_init(&op->pend_link); -		object->n_ops--; +		if (do_cancel) +			do_cancel(op); +		op->state = FSCACHE_OP_ST_CANCELLED;  		if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))  			object->n_exclusive--;  		if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) @@ -311,6 +334,70 @@ int fscache_cancel_op(struct fscache_operation *op)  }  /* + * Cancel all pending operations on an object + */ +void fscache_cancel_all_ops(struct fscache_object *object) +{ +	struct fscache_operation *op; + +	_enter("OBJ%x", object->debug_id); + +	spin_lock(&object->lock); + +	while (!list_empty(&object->pending_ops)) { +		op = list_entry(object->pending_ops.next, +				struct fscache_operation, pend_link); +		fscache_stat(&fscache_n_op_cancelled); +		list_del_init(&op->pend_link); + +		ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); +		op->state = FSCACHE_OP_ST_CANCELLED; + +		if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) +			object->n_exclusive--; +		if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) +			wake_up_bit(&op->flags, FSCACHE_OP_WAITING); +		fscache_put_operation(op); +		cond_resched_lock(&object->lock); +	} + +	spin_unlock(&object->lock); +	_leave(""); +} + +/* + * Record the completion or cancellation of an in-progress operation. + */ +void fscache_op_complete(struct fscache_operation *op, bool cancelled) +{ +	struct fscache_object *object = op->object; + +	_enter("OBJ%x", object->debug_id); + +	ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); +	ASSERTCMP(object->n_in_progress, >, 0); +	ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), +		    object->n_exclusive, >, 0); +	ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), +		    object->n_in_progress, ==, 1); + +	spin_lock(&object->lock); + +	op->state = cancelled ? +		FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE; + +	if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) +		object->n_exclusive--; +	object->n_in_progress--; +	if (object->n_in_progress == 0) +		fscache_start_operations(object); + +	spin_unlock(&object->lock); +	_leave(""); +} +EXPORT_SYMBOL(fscache_op_complete); + +/*   * release an operation   * - queues pending ops if this is the last in-progress op   */ @@ -328,8 +415,9 @@ void fscache_put_operation(struct fscache_operation *op)  		return;  	_debug("PUT OP"); -	if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) -		BUG(); +	ASSERTIFCMP(op->state != FSCACHE_OP_ST_COMPLETE, +		    op->state, ==, FSCACHE_OP_ST_CANCELLED); +	op->state = FSCACHE_OP_ST_DEAD;  	fscache_stat(&fscache_n_op_release); @@ -340,8 +428,14 @@ void fscache_put_operation(struct fscache_operation *op)  	object = op->object; -	if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) -		atomic_dec(&object->n_reads); +	if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) { +		if (atomic_dec_and_test(&object->n_reads)) { +			clear_bit(FSCACHE_COOKIE_WAITING_ON_READS, +				  &object->cookie->flags); +			wake_up_bit(&object->cookie->flags, +				    FSCACHE_COOKIE_WAITING_ON_READS); +		} +	}  	/* now... we may get called with the object spinlock held, so we  	 * complete the cleanup here only if we can immediately acquire the @@ -359,16 +453,6 @@ void fscache_put_operation(struct fscache_operation *op)  		return;  	} -	if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { -		ASSERTCMP(object->n_exclusive, >, 0); -		object->n_exclusive--; -	} - -	ASSERTCMP(object->n_in_progress, >, 0); -	object->n_in_progress--; -	if (object->n_in_progress == 0) -		fscache_start_operations(object); -  	ASSERTCMP(object->n_ops, >, 0);  	object->n_ops--;  	if (object->n_ops == 0) @@ -407,23 +491,14 @@ void fscache_operation_gc(struct work_struct *work)  		spin_unlock(&cache->op_gc_list_lock);  		object = op->object; +		spin_lock(&object->lock);  		_debug("GC DEFERRED REL OBJ%x OP%x",  		       object->debug_id, op->debug_id);  		fscache_stat(&fscache_n_op_gc);  		ASSERTCMP(atomic_read(&op->usage), ==, 0); - -		spin_lock(&object->lock); -		if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { -			ASSERTCMP(object->n_exclusive, >, 0); -			object->n_exclusive--; -		} - -		ASSERTCMP(object->n_in_progress, >, 0); -		object->n_in_progress--; -		if (object->n_in_progress == 0) -			fscache_start_operations(object); +		ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD);  		ASSERTCMP(object->n_ops, >, 0);  		object->n_ops--; @@ -431,6 +506,7 @@ void fscache_operation_gc(struct work_struct *work)  			fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED);  		spin_unlock(&object->lock); +		kfree(op);  	} while (count++ < 20);  |