fscache: Implement cookie invalidation
[linux-2.6-microblaze.git] / fs / fscache / cookie.c
index 2f5ee71..a7ea7d1 100644 (file)
@@ -19,6 +19,7 @@ static void fscache_cookie_lru_timed_out(struct timer_list *timer);
 static void fscache_cookie_lru_worker(struct work_struct *work);
 static void fscache_cookie_worker(struct work_struct *work);
 static void fscache_unhash_cookie(struct fscache_cookie *cookie);
+static void fscache_perform_invalidation(struct fscache_cookie *cookie);
 
 #define fscache_cookie_hash_shift 15
 static struct hlist_bl_head fscache_cookie_hash[1 << fscache_cookie_hash_shift];
@@ -28,7 +29,7 @@ static LIST_HEAD(fscache_cookie_lru);
 static DEFINE_SPINLOCK(fscache_cookie_lru_lock);
 DEFINE_TIMER(fscache_cookie_lru_timer, fscache_cookie_lru_timed_out);
 static DECLARE_WORK(fscache_cookie_lru_work, fscache_cookie_lru_worker);
-static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAFUWRD";
+static const char fscache_cookie_states[FSCACHE_COOKIE_STATE__NR] = "-LCAIFUWRD";
 unsigned int fscache_lru_cookie_timeout = 10 * HZ;
 
 void fscache_print_cookie(struct fscache_cookie *cookie, char prefix)
@@ -236,6 +237,19 @@ void fscache_cookie_lookup_negative(struct fscache_cookie *cookie)
 }
 EXPORT_SYMBOL(fscache_cookie_lookup_negative);
 
+/**
+ * fscache_resume_after_invalidation - Allow I/O to resume after invalidation
+ * @cookie: The cookie that was invalidated
+ *
+ * Tell fscache that invalidation is sufficiently complete that I/O can be
+ * allowed again.
+ */
+void fscache_resume_after_invalidation(struct fscache_cookie *cookie)
+{
+       fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+}
+EXPORT_SYMBOL(fscache_resume_after_invalidation);
+
 /**
  * fscache_caching_failed - Report that a failure stopped caching on a cookie
  * @cookie: The cookie that was affected
@@ -566,6 +580,7 @@ again:
                        set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
                break;
        case FSCACHE_COOKIE_STATE_ACTIVE:
+       case FSCACHE_COOKIE_STATE_INVALIDATING:
                if (will_modify &&
                    !test_and_set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags)) {
                        set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
@@ -671,6 +686,11 @@ again_locked:
                fscache_perform_lookup(cookie);
                goto again;
 
+       case FSCACHE_COOKIE_STATE_INVALIDATING:
+               spin_unlock(&cookie->lock);
+               fscache_perform_invalidation(cookie);
+               goto again;
+
        case FSCACHE_COOKIE_STATE_ACTIVE:
                if (test_and_clear_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags)) {
                        spin_unlock(&cookie->lock);
@@ -962,6 +982,72 @@ struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie,
 }
 EXPORT_SYMBOL(fscache_get_cookie);
 
+/*
+ * Ask the cache to effect invalidation of a cookie.
+ */
+static void fscache_perform_invalidation(struct fscache_cookie *cookie)
+{
+       if (!cookie->volume->cache->ops->invalidate_cookie(cookie))
+               fscache_caching_failed(cookie);
+       fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
+}
+
+/*
+ * Invalidate an object.
+ */
+void __fscache_invalidate(struct fscache_cookie *cookie,
+                         const void *aux_data, loff_t new_size,
+                         unsigned int flags)
+{
+       bool is_caching;
+
+       _enter("c=%x", cookie->debug_id);
+
+       fscache_stat(&fscache_n_invalidates);
+
+       if (WARN(test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags),
+                "Trying to invalidate relinquished cookie\n"))
+               return;
+
+       if ((flags & FSCACHE_INVAL_DIO_WRITE) &&
+           test_and_set_bit(FSCACHE_COOKIE_DISABLED, &cookie->flags))
+               return;
+
+       spin_lock(&cookie->lock);
+       set_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
+       fscache_update_aux(cookie, aux_data, &new_size);
+       cookie->inval_counter++;
+       trace_fscache_invalidate(cookie, new_size);
+
+       switch (cookie->state) {
+       case FSCACHE_COOKIE_STATE_INVALIDATING: /* is_still_valid will catch it */
+       default:
+               spin_unlock(&cookie->lock);
+               _leave(" [no %u]", cookie->state);
+               return;
+
+       case FSCACHE_COOKIE_STATE_LOOKING_UP:
+       case FSCACHE_COOKIE_STATE_CREATING:
+               spin_unlock(&cookie->lock);
+               _leave(" [look %x]", cookie->inval_counter);
+               return;
+
+       case FSCACHE_COOKIE_STATE_ACTIVE:
+               is_caching = fscache_begin_cookie_access(
+                       cookie, fscache_access_invalidate_cookie);
+               if (is_caching)
+                       __fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_INVALIDATING);
+               spin_unlock(&cookie->lock);
+               wake_up_cookie_state(cookie);
+
+               if (is_caching)
+                       fscache_queue_cookie(cookie, fscache_cookie_get_inval_work);
+               _leave(" [inv]");
+               return;
+       }
+}
+EXPORT_SYMBOL(__fscache_invalidate);
+
 /*
  * Generate a list of extant cookies in /proc/fs/fscache/cookies
  */