FS-Cache: Permit fscache_cancel_op() to cancel in-progress operations too
[firefly-linux-kernel-4.4.55.git] / fs / fscache / operation.c
index 18658fffbba17f11cffbdf8d2249eefe9557badc..67594a8d791a50ca74c380a4fe59dee13296dd04 100644 (file)
@@ -312,9 +312,11 @@ 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,
-                     void (*do_cancel)(struct fscache_operation *))
+                     void (*do_cancel)(struct fscache_operation *),
+                     bool cancel_in_progress_op)
 {
        struct fscache_object *object = op->object;
+       bool put = false;
        int ret;
 
        _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id);
@@ -328,8 +330,19 @@ int fscache_cancel_op(struct fscache_operation *op,
        ret = -EBUSY;
        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);
+               put = true;
+               fscache_stat(&fscache_n_op_cancelled);
+               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))
+                       wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
+               ret = 0;
+       } else if (op->state == FSCACHE_OP_ST_IN_PROGRESS && cancel_in_progress_op) {
+               fscache_stat(&fscache_n_op_cancelled);
                if (do_cancel)
                        do_cancel(op);
                op->state = FSCACHE_OP_ST_CANCELLED;
@@ -337,10 +350,11 @@ int fscache_cancel_op(struct fscache_operation *op,
                        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);
                ret = 0;
        }
 
+       if (put)
+               fscache_put_operation(op);
        spin_unlock(&object->lock);
        _leave(" = %d", ret);
        return ret;