ocfs2: fix start offset to ocfs2_zero_range_for_truncate()
[pandora-kernel.git] / fs / fs-writeback.c
index ac86f8b..7286eb4 100644 (file)
@@ -47,25 +47,6 @@ struct wb_writeback_work {
        struct completion *done;        /* set if the caller waits */
 };
 
-const char *wb_reason_name[] = {
-       [WB_REASON_BACKGROUND]          = "background",
-       [WB_REASON_TRY_TO_FREE_PAGES]   = "try_to_free_pages",
-       [WB_REASON_SYNC]                = "sync",
-       [WB_REASON_PERIODIC]            = "periodic",
-       [WB_REASON_LAPTOP_TIMER]        = "laptop_timer",
-       [WB_REASON_FREE_MORE_MEM]       = "free_more_memory",
-       [WB_REASON_FS_FREE_SPACE]       = "fs_free_space",
-       [WB_REASON_FORKER_THREAD]       = "forker_thread"
-};
-
-/*
- * Include the creation of the trace points after defining the
- * wb_writeback_work structure so that the definition remains local to this
- * file.
- */
-#define CREATE_TRACE_POINTS
-#include <trace/events/writeback.h>
-
 /*
  * We don't actually have pdflush, but this one is exported though /proc...
  */
@@ -82,6 +63,7 @@ int writeback_in_progress(struct backing_dev_info *bdi)
 {
        return test_bit(BDI_writeback_running, &bdi->state);
 }
+EXPORT_SYMBOL(writeback_in_progress);
 
 static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
 {
@@ -98,6 +80,14 @@ static inline struct inode *wb_inode(struct list_head *head)
        return list_entry(head, struct inode, i_wb_list);
 }
 
+/*
+ * Include the creation of the trace points after defining the
+ * wb_writeback_work structure and inline functions so that the definition
+ * remains local to this file.
+ */
+#define CREATE_TRACE_POINTS
+#include <trace/events/writeback.h>
+
 /* Wakeup flusher thread or forker thread to fork it. Requires bdi->wb_lock. */
 static void bdi_wakeup_flusher(struct backing_dev_info *bdi)
 {
@@ -406,7 +396,6 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
 
        /* Set I_SYNC, reset I_DIRTY_PAGES */
        inode->i_state |= I_SYNC;
-       inode->i_state &= ~I_DIRTY_PAGES;
        spin_unlock(&inode->i_lock);
        spin_unlock(&wb->list_lock);
 
@@ -429,9 +418,28 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
         * write_inode()
         */
        spin_lock(&inode->i_lock);
+
        dirty = inode->i_state & I_DIRTY;
-       inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC);
+       inode->i_state &= ~I_DIRTY;
+
+       /*
+        * Paired with smp_mb() in __mark_inode_dirty().  This allows
+        * __mark_inode_dirty() to test i_state without grabbing i_lock -
+        * either they see the I_DIRTY bits cleared or we see the dirtied
+        * inode.
+        *
+        * I_DIRTY_PAGES is always cleared together above even if @mapping
+        * still has dirty pages.  The flag is reinstated after smp_mb() if
+        * necessary.  This guarantees that either __mark_inode_dirty()
+        * sees clear I_DIRTY_PAGES or we see PAGECACHE_TAG_DIRTY.
+        */
+       smp_mb();
+
+       if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
+               inode->i_state |= I_DIRTY_PAGES;
+
        spin_unlock(&inode->i_lock);
+
        /* Don't write the inode if only I_DIRTY_PAGES was set */
        if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
                int err = write_inode(inode, wbc);
@@ -457,7 +465,6 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
                         * We didn't write back all the pages.  nfs_writepages()
                         * sometimes bales out without doing anything.
                         */
-                       inode->i_state |= I_DIRTY_PAGES;
                        if (wbc->nr_to_write <= 0) {
                                /*
                                 * slice used up: queue for next turn
@@ -1074,12 +1081,11 @@ void __mark_inode_dirty(struct inode *inode, int flags)
        }
 
        /*
-        * make sure that changes are seen by all cpus before we test i_state
-        * -- mikulas
+        * Paired with smp_mb() in __writeback_single_inode() for the
+        * following lockless i_state test.  See there for details.
         */
        smp_mb();
 
-       /* avoid the locking if we can */
        if ((inode->i_state & flags) == flags)
                return;