]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/fscache/object.c
MIPS: Avoid overoptimization by GCC.
[karo-tx-linux.git] / fs / fscache / object.c
index b6b897c550acfea609acc9f99f0cdd2eaa90b2a3..50d41c1802110b472f93eae0cae5f775d332fd13 100644 (file)
@@ -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 *);
@@ -78,6 +82,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object)
        spin_unlock(&parent->lock);
 }
 
+/*
+ * 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
@@ -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]");
+}