writeback: limit max dirty pause time
[pandora-kernel.git] / mm / page-writeback.c
index f32f250..cc351e6 100644 (file)
@@ -939,6 +939,43 @@ static unsigned long dirty_poll_interval(unsigned long dirty,
        return 1;
 }
 
+static unsigned long bdi_max_pause(struct backing_dev_info *bdi,
+                                  unsigned long bdi_dirty)
+{
+       unsigned long bw = bdi->avg_write_bandwidth;
+       unsigned long hi = ilog2(bw);
+       unsigned long lo = ilog2(bdi->dirty_ratelimit);
+       unsigned long t;
+
+       /* target for 20ms max pause on 1-dd case */
+       t = HZ / 50;
+
+       /*
+        * Scale up pause time for concurrent dirtiers in order to reduce CPU
+        * overheads.
+        *
+        * (N * 20ms) on 2^N concurrent tasks.
+        */
+       if (hi > lo)
+               t += (hi - lo) * (20 * HZ) / 1024;
+
+       /*
+        * Limit pause time for small memory systems. If sleeping for too long
+        * time, a small pool of dirty/writeback pages may go empty and disk go
+        * idle.
+        *
+        * 8 serves as the safety ratio.
+        */
+       if (bdi_dirty)
+               t = min(t, bdi_dirty * HZ / (8 * bw + 1));
+
+       /*
+        * The pause time will be settled within range (max_pause/4, max_pause).
+        * Apply a minimal value of 4 to get a non-zero max_pause/4.
+        */
+       return clamp_val(t, 4, MAX_PAUSE);
+}
+
 /*
  * balance_dirty_pages() must be called by processes which are generating dirty
  * data.  It looks at the number of dirty pages in the machine and will force
@@ -958,6 +995,7 @@ static void balance_dirty_pages(struct address_space *mapping,
        unsigned long dirty_thresh;
        unsigned long bdi_thresh;
        long pause = 0;
+       long max_pause;
        bool dirty_exceeded = false;
        unsigned long task_ratelimit;
        unsigned long dirty_ratelimit;
@@ -1035,18 +1073,20 @@ static void balance_dirty_pages(struct address_space *mapping,
                                     nr_dirty, bdi_thresh, bdi_dirty,
                                     start_time);
 
+               max_pause = bdi_max_pause(bdi, bdi_dirty);
+
                dirty_ratelimit = bdi->dirty_ratelimit;
                pos_ratio = bdi_position_ratio(bdi, dirty_thresh,
                                               background_thresh, nr_dirty,
                                               bdi_thresh, bdi_dirty);
                if (unlikely(pos_ratio == 0)) {
-                       pause = MAX_PAUSE;
+                       pause = max_pause;
                        goto pause;
                }
                task_ratelimit = (u64)dirty_ratelimit *
                                        pos_ratio >> RATELIMIT_CALC_SHIFT;
                pause = (HZ * pages_dirtied) / (task_ratelimit | 1);
-               pause = min_t(long, pause, MAX_PAUSE);
+               pause = min(pause, max_pause);
 
 pause:
                __set_current_state(TASK_UNINTERRUPTIBLE);