Merge branch 'stable/for-jens-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / fs / fscache / operation.c
index c58dbe6..762a9ec 100644 (file)
@@ -84,6 +84,8 @@ static void fscache_run_op(struct fscache_object *object,
 int fscache_submit_exclusive_op(struct fscache_object *object,
                                struct fscache_operation *op)
 {
+       int ret;
+
        _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
 
        ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);
@@ -116,6 +118,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
 
                /* need to issue a new write op after this */
                clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+               ret = 0;
        } else if (object->state == FSCACHE_OBJECT_CREATING) {
                op->object = object;
                object->n_ops++;
@@ -123,13 +126,17 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
                atomic_inc(&op->usage);
                list_add_tail(&op->pend_link, &object->pending_ops);
                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);
-       return 0;
+       return ret;
 }
 
 /*
@@ -291,7 +298,8 @@ 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;
@@ -309,6 +317,8 @@ int fscache_cancel_op(struct fscache_operation *op)
                ASSERT(!list_empty(&op->pend_link));
                fscache_stat(&fscache_n_op_cancelled);
                list_del_init(&op->pend_link);
+               if (do_cancel)
+                       do_cancel(op);
                op->state = FSCACHE_OP_ST_CANCELLED;
                if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
                        object->n_exclusive--;
@@ -356,9 +366,9 @@ void fscache_cancel_all_ops(struct fscache_object *object)
 }
 
 /*
- * Record the completion of an in-progress operation.
+ * Record the completion or cancellation of an in-progress operation.
  */
-void fscache_op_complete(struct fscache_operation *op)
+void fscache_op_complete(struct fscache_operation *op, bool cancelled)
 {
        struct fscache_object *object = op->object;
 
@@ -373,7 +383,8 @@ void fscache_op_complete(struct fscache_operation *op)
 
        spin_lock(&object->lock);
 
-       op->state = FSCACHE_OP_ST_COMPLETE;
+       op->state = cancelled ?
+               FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE;
 
        if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
                object->n_exclusive--;