]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/fscache/operation.c
hwmon: (pmbus/lm25066) Refactor device specific coefficients
[karo-tx-linux.git] / fs / fscache / operation.c
index 30afdfa7aec78b6a7e47ab791fbf9ec1198870d6..762a9ec4ffa4739686e41cd3f8521765ca6e9719 100644 (file)
@@ -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))
@@ -310,6 +333,70 @@ int fscache_cancel_op(struct fscache_operation *op)
        return ret;
 }
 
+/*
+ * 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);