Merge branch 'rmobile-fixes-for-linus' of git://github.com/pmundt/linux-sh
[pandora-kernel.git] / fs / fs-writeback.c
index 6401cd7..ac86f8b 100644 (file)
@@ -41,11 +41,23 @@ struct wb_writeback_work {
        unsigned int for_kupdate:1;
        unsigned int range_cyclic:1;
        unsigned int for_background:1;
+       enum wb_reason reason;          /* why was writeback initiated? */
 
        struct list_head list;          /* pending work list */
        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
@@ -115,7 +127,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi,
 
 static void
 __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
-                     bool range_cyclic)
+                     bool range_cyclic, enum wb_reason reason)
 {
        struct wb_writeback_work *work;
 
@@ -135,6 +147,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
        work->sync_mode = WB_SYNC_NONE;
        work->nr_pages  = nr_pages;
        work->range_cyclic = range_cyclic;
+       work->reason    = reason;
 
        bdi_queue_work(bdi, work);
 }
@@ -143,6 +156,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
  * bdi_start_writeback - start writeback
  * @bdi: the backing device to write from
  * @nr_pages: the number of pages to write
+ * @reason: reason why some writeback work was initiated
  *
  * Description:
  *   This does WB_SYNC_NONE opportunistic writeback. The IO is only
@@ -150,9 +164,10 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
  *   completion. Caller need not hold sb s_umount semaphore.
  *
  */
-void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages)
+void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
+                       enum wb_reason reason)
 {
-       __bdi_start_writeback(bdi, nr_pages, true);
+       __bdi_start_writeback(bdi, nr_pages, true, reason);
 }
 
 /**
@@ -251,7 +266,7 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t)
  */
 static int move_expired_inodes(struct list_head *delaying_queue,
                               struct list_head *dispatch_queue,
-                              unsigned long *older_than_this)
+                              struct wb_writeback_work *work)
 {
        LIST_HEAD(tmp);
        struct list_head *pos, *node;
@@ -262,8 +277,8 @@ static int move_expired_inodes(struct list_head *delaying_queue,
 
        while (!list_empty(delaying_queue)) {
                inode = wb_inode(delaying_queue->prev);
-               if (older_than_this &&
-                   inode_dirtied_after(inode, *older_than_this))
+               if (work->older_than_this &&
+                   inode_dirtied_after(inode, *work->older_than_this))
                        break;
                if (sb && sb != inode->i_sb)
                        do_sb_sort = 1;
@@ -302,13 +317,13 @@ out:
  *                                           |
  *                                           +--> dequeue for IO
  */
-static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this)
+static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work)
 {
        int moved;
        assert_spin_locked(&wb->list_lock);
        list_splice_init(&wb->b_more_io, &wb->b_io);
-       moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
-       trace_writeback_queue_io(wb, older_than_this, moved);
+       moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, work);
+       trace_writeback_queue_io(wb, work, moved);
 }
 
 static int write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -641,17 +656,19 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb,
        return wrote;
 }
 
-long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages)
+long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
+                               enum wb_reason reason)
 {
        struct wb_writeback_work work = {
                .nr_pages       = nr_pages,
                .sync_mode      = WB_SYNC_NONE,
                .range_cyclic   = 1,
+               .reason         = reason,
        };
 
        spin_lock(&wb->list_lock);
        if (list_empty(&wb->b_io))
-               queue_io(wb, NULL);
+               queue_io(wb, &work);
        __writeback_inodes_wb(wb, &work);
        spin_unlock(&wb->list_lock);
 
@@ -745,7 +762,7 @@ static long wb_writeback(struct bdi_writeback *wb,
 
                trace_writeback_start(wb->bdi, work);
                if (list_empty(&wb->b_io))
-                       queue_io(wb, work->older_than_this);
+                       queue_io(wb, work);
                if (work->sb)
                        progress = writeback_sb_inodes(work->sb, wb, work);
                else
@@ -825,6 +842,7 @@ static long wb_check_background_flush(struct bdi_writeback *wb)
                        .sync_mode      = WB_SYNC_NONE,
                        .for_background = 1,
                        .range_cyclic   = 1,
+                       .reason         = WB_REASON_BACKGROUND,
                };
 
                return wb_writeback(wb, &work);
@@ -858,6 +876,7 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb)
                        .sync_mode      = WB_SYNC_NONE,
                        .for_kupdate    = 1,
                        .range_cyclic   = 1,
+                       .reason         = WB_REASON_PERIODIC,
                };
 
                return wb_writeback(wb, &work);
@@ -976,7 +995,7 @@ int bdi_writeback_thread(void *data)
  * Start writeback of `nr_pages' pages.  If `nr_pages' is zero, write back
  * the whole world.
  */
-void wakeup_flusher_threads(long nr_pages)
+void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
 {
        struct backing_dev_info *bdi;
 
@@ -989,7 +1008,7 @@ void wakeup_flusher_threads(long nr_pages)
        list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
                if (!bdi_has_dirty_io(bdi))
                        continue;
-               __bdi_start_writeback(bdi, nr_pages, false);
+               __bdi_start_writeback(bdi, nr_pages, false, reason);
        }
        rcu_read_unlock();
 }
@@ -1205,12 +1224,15 @@ static void wait_sb_inodes(struct super_block *sb)
  * writeback_inodes_sb_nr -    writeback dirty inodes from given super_block
  * @sb: the superblock
  * @nr: the number of pages to write
+ * @reason: reason why some writeback work initiated
  *
  * Start writeback on some inodes on this super_block. No guarantees are made
  * on how many (if any) will be written, and this function does not wait
  * for IO completion of submitted IO.
  */
-void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr)
+void writeback_inodes_sb_nr(struct super_block *sb,
+                           unsigned long nr,
+                           enum wb_reason reason)
 {
        DECLARE_COMPLETION_ONSTACK(done);
        struct wb_writeback_work work = {
@@ -1219,6 +1241,7 @@ void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr)
                .tagged_writepages      = 1,
                .done                   = &done,
                .nr_pages               = nr,
+               .reason                 = reason,
        };
 
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
@@ -1230,29 +1253,31 @@ EXPORT_SYMBOL(writeback_inodes_sb_nr);
 /**
  * writeback_inodes_sb -       writeback dirty inodes from given super_block
  * @sb: the superblock
+ * @reason: reason why some writeback work was initiated
  *
  * Start writeback on some inodes on this super_block. No guarantees are made
  * on how many (if any) will be written, and this function does not wait
  * for IO completion of submitted IO.
  */
-void writeback_inodes_sb(struct super_block *sb)
+void writeback_inodes_sb(struct super_block *sb, enum wb_reason reason)
 {
-       return writeback_inodes_sb_nr(sb, get_nr_dirty_pages());
+       return writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason);
 }
 EXPORT_SYMBOL(writeback_inodes_sb);
 
 /**
  * writeback_inodes_sb_if_idle -       start writeback if none underway
  * @sb: the superblock
+ * @reason: reason why some writeback work was initiated
  *
  * Invoke writeback_inodes_sb if no writeback is currently underway.
  * Returns 1 if writeback was started, 0 if not.
  */
-int writeback_inodes_sb_if_idle(struct super_block *sb)
+int writeback_inodes_sb_if_idle(struct super_block *sb, enum wb_reason reason)
 {
        if (!writeback_in_progress(sb->s_bdi)) {
                down_read(&sb->s_umount);
-               writeback_inodes_sb(sb);
+               writeback_inodes_sb(sb, reason);
                up_read(&sb->s_umount);
                return 1;
        } else
@@ -1264,16 +1289,18 @@ EXPORT_SYMBOL(writeback_inodes_sb_if_idle);
  * writeback_inodes_sb_if_idle -       start writeback if none underway
  * @sb: the superblock
  * @nr: the number of pages to write
+ * @reason: reason why some writeback work was initiated
  *
  * Invoke writeback_inodes_sb if no writeback is currently underway.
  * Returns 1 if writeback was started, 0 if not.
  */
 int writeback_inodes_sb_nr_if_idle(struct super_block *sb,
-                                  unsigned long nr)
+                                  unsigned long nr,
+                                  enum wb_reason reason)
 {
        if (!writeback_in_progress(sb->s_bdi)) {
                down_read(&sb->s_umount);
-               writeback_inodes_sb_nr(sb, nr);
+               writeback_inodes_sb_nr(sb, nr, reason);
                up_read(&sb->s_umount);
                return 1;
        } else
@@ -1297,6 +1324,7 @@ void sync_inodes_sb(struct super_block *sb)
                .nr_pages       = LONG_MAX,
                .range_cyclic   = 0,
                .done           = &done,
+               .reason         = WB_REASON_SYNC,
        };
 
        WARN_ON(!rwsem_is_locked(&sb->s_umount));