The complex patch with which MohammadAG had his success
[h-e-n] / fs / fs-writeback.c
index 16519fe..4ce9b26 100644 (file)
@@ -8,7 +8,7 @@
  * pages against inodes.  ie: data writeback.  Writeout of the
  * inode itself is not handled here.
  *
- * 10Apr2002   akpm@zip.com.au
+ * 10Apr2002   Andrew Morton
  *             Split out of fs/inode.c
  *             Additions for address_space-based writeback
  */
@@ -65,6 +65,24 @@ static void writeback_release(struct backing_dev_info *bdi)
 }
 
 /**
+ * enable_pwb - enable periodic write-back after an inode was marked as dirty.
+ * @inode: the inode which was marked as dirty
+ *
+ * This is a helper function for '__mark_inode_dirty()' which enables the
+ * periodic write-back, unless:
+ *   * the backing device @inode belongs to does not support write-back;
+ *   * periodic write-back is already enabled.
+ */
+static void enable_pwb(struct inode *inode)
+{
+       struct backing_dev_info *bdi = inode->i_mapping->backing_dev_info;
+
+       if (bdi_cap_writeback_dirty(bdi) &&
+           atomic_add_unless(&periodic_wb_enabled, 1, 1))
+               enable_periodic_wb();
+}
+
+/**
  *     __mark_inode_dirty -    internal function
  *     @inode: inode to mark
  *     @flags: what kind of dirty (i.e. I_DIRTY_SYNC)
@@ -164,6 +182,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                if (!was_dirty) {
                        inode->dirtied_when = jiffies;
                        list_move(&inode->i_list, &sb->s_dirty);
+                       enable_pwb(inode);
                }
        }
 out:
@@ -172,6 +191,28 @@ out:
 
 EXPORT_SYMBOL(__mark_inode_dirty);
 
+/**
+ * mark_sb_dirty - mark super block as dirty.
+ * @sb: the super block to mark as dirty
+ *
+ * This function marks super block @sb as dirty and enables the periodic
+ * write-back, unless it is already enabled. Note, VFS does not serialize the
+ * super block clean/dirty (@sb->s_dirt) state changes, and each FS is
+ * responsible for doing its own serialization.
+ */
+void mark_sb_dirty(struct super_block *sb)
+{
+       sb->s_dirt = 1;
+       /*
+        * If 'periodic_wb_enabled' is 0, set it to 1 and enable the periodic
+        * write-back.
+        */
+       if (atomic_add_unless(&periodic_wb_enabled, 1, 1))
+               enable_periodic_wb();
+}
+
+EXPORT_SYMBOL(mark_sb_dirty);
+
 static int write_inode(struct inode *inode, int sync)
 {
        if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode))
@@ -439,8 +480,8 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
  * on the writer throttling path, and we get decent balancing between many
  * throttled threads: we don't want them all piling up on inode_sync_wait.
  */
-static void
-sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
+void generic_sync_sb_inodes(struct super_block *sb,
+                               struct writeback_control *wbc)
 {
        const unsigned long start = jiffies;    /* livelock avoidance */
 
@@ -526,6 +567,13 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
        spin_unlock(&inode_lock);
        return;         /* Leave any unwritten inodes on s_io */
 }
+EXPORT_SYMBOL_GPL(generic_sync_sb_inodes);
+
+static void sync_sb_inodes(struct super_block *sb,
+                               struct writeback_control *wbc)
+{
+       generic_sync_sb_inodes(sb, wbc);
+}
 
 /*
  * Start writeback of dirty pagecache data against all unlocked inodes.