Merge branch 'for-4.6-ns' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[linux-2.6-block.git] / mm / page-writeback.c
index 6fe7d15bd1f7804e87f192c6b06b681ac6c51896..11ff8f75863105b773ee279fee5d6853e4680abb 100644 (file)
@@ -1169,6 +1169,7 @@ static void wb_update_dirty_ratelimit(struct dirty_throttle_control *dtc,
        unsigned long balanced_dirty_ratelimit;
        unsigned long step;
        unsigned long x;
+       unsigned long shift;
 
        /*
         * The dirty rate will match the writeout rate in long term, except
@@ -1293,11 +1294,11 @@ static void wb_update_dirty_ratelimit(struct dirty_throttle_control *dtc,
         * rate itself is constantly fluctuating. So decrease the track speed
         * when it gets close to the target. Helps eliminate pointless tremors.
         */
-       step >>= dirty_ratelimit / (2 * step + 1);
-       /*
-        * Limit the tracking speed to avoid overshooting.
-        */
-       step = (step + 7) / 8;
+       shift = dirty_ratelimit / (2 * step + 1);
+       if (shift < BITS_PER_LONG)
+               step = DIV_ROUND_UP(step >> shift, 8);
+       else
+               step = 0;
 
        if (dirty_ratelimit < balanced_dirty_ratelimit)
                dirty_ratelimit += step;
@@ -2409,12 +2410,11 @@ int __set_page_dirty_no_writeback(struct page *page)
 /*
  * Helper function for set_page_dirty family.
  *
- * Caller must hold mem_cgroup_begin_page_stat().
+ * Caller must hold lock_page_memcg().
  *
  * NOTE: This relies on being atomic wrt interrupts.
  */
-void account_page_dirtied(struct page *page, struct address_space *mapping,
-                         struct mem_cgroup *memcg)
+void account_page_dirtied(struct page *page, struct address_space *mapping)
 {
        struct inode *inode = mapping->host;
 
@@ -2426,7 +2426,7 @@ void account_page_dirtied(struct page *page, struct address_space *mapping,
                inode_attach_wb(inode, page);
                wb = inode_to_wb(inode);
 
-               mem_cgroup_inc_page_stat(memcg, MEM_CGROUP_STAT_DIRTY);
+               mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_DIRTY);
                __inc_zone_page_state(page, NR_FILE_DIRTY);
                __inc_zone_page_state(page, NR_DIRTIED);
                __inc_wb_stat(wb, WB_RECLAIMABLE);
@@ -2441,13 +2441,13 @@ EXPORT_SYMBOL(account_page_dirtied);
 /*
  * Helper function for deaccounting dirty page without writeback.
  *
- * Caller must hold mem_cgroup_begin_page_stat().
+ * Caller must hold lock_page_memcg().
  */
 void account_page_cleaned(struct page *page, struct address_space *mapping,
-                         struct mem_cgroup *memcg, struct bdi_writeback *wb)
+                         struct bdi_writeback *wb)
 {
        if (mapping_cap_account_dirty(mapping)) {
-               mem_cgroup_dec_page_stat(memcg, MEM_CGROUP_STAT_DIRTY);
+               mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
                dec_zone_page_state(page, NR_FILE_DIRTY);
                dec_wb_stat(wb, WB_RECLAIMABLE);
                task_io_account_cancelled_write(PAGE_CACHE_SIZE);
@@ -2468,26 +2468,24 @@ void account_page_cleaned(struct page *page, struct address_space *mapping,
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
-       struct mem_cgroup *memcg;
-
-       memcg = mem_cgroup_begin_page_stat(page);
+       lock_page_memcg(page);
        if (!TestSetPageDirty(page)) {
                struct address_space *mapping = page_mapping(page);
                unsigned long flags;
 
                if (!mapping) {
-                       mem_cgroup_end_page_stat(memcg);
+                       unlock_page_memcg(page);
                        return 1;
                }
 
                spin_lock_irqsave(&mapping->tree_lock, flags);
                BUG_ON(page_mapping(page) != mapping);
                WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-               account_page_dirtied(page, mapping, memcg);
+               account_page_dirtied(page, mapping);
                radix_tree_tag_set(&mapping->page_tree, page_index(page),
                                   PAGECACHE_TAG_DIRTY);
                spin_unlock_irqrestore(&mapping->tree_lock, flags);
-               mem_cgroup_end_page_stat(memcg);
+               unlock_page_memcg(page);
 
                if (mapping->host) {
                        /* !PageAnon && !swapper_space */
@@ -2495,7 +2493,7 @@ int __set_page_dirty_nobuffers(struct page *page)
                }
                return 1;
        }
-       mem_cgroup_end_page_stat(memcg);
+       unlock_page_memcg(page);
        return 0;
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
@@ -2625,17 +2623,16 @@ void cancel_dirty_page(struct page *page)
        if (mapping_cap_account_dirty(mapping)) {
                struct inode *inode = mapping->host;
                struct bdi_writeback *wb;
-               struct mem_cgroup *memcg;
                bool locked;
 
-               memcg = mem_cgroup_begin_page_stat(page);
+               lock_page_memcg(page);
                wb = unlocked_inode_to_wb_begin(inode, &locked);
 
                if (TestClearPageDirty(page))
-                       account_page_cleaned(page, mapping, memcg, wb);
+                       account_page_cleaned(page, mapping, wb);
 
                unlocked_inode_to_wb_end(inode, locked);
-               mem_cgroup_end_page_stat(memcg);
+               unlock_page_memcg(page);
        } else {
                ClearPageDirty(page);
        }
@@ -2666,7 +2663,6 @@ int clear_page_dirty_for_io(struct page *page)
        if (mapping && mapping_cap_account_dirty(mapping)) {
                struct inode *inode = mapping->host;
                struct bdi_writeback *wb;
-               struct mem_cgroup *memcg;
                bool locked;
 
                /*
@@ -2704,16 +2700,14 @@ int clear_page_dirty_for_io(struct page *page)
                 * always locked coming in here, so we get the desired
                 * exclusion.
                 */
-               memcg = mem_cgroup_begin_page_stat(page);
                wb = unlocked_inode_to_wb_begin(inode, &locked);
                if (TestClearPageDirty(page)) {
-                       mem_cgroup_dec_page_stat(memcg, MEM_CGROUP_STAT_DIRTY);
+                       mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
                        dec_zone_page_state(page, NR_FILE_DIRTY);
                        dec_wb_stat(wb, WB_RECLAIMABLE);
                        ret = 1;
                }
                unlocked_inode_to_wb_end(inode, locked);
-               mem_cgroup_end_page_stat(memcg);
                return ret;
        }
        return TestClearPageDirty(page);
@@ -2723,10 +2717,9 @@ EXPORT_SYMBOL(clear_page_dirty_for_io);
 int test_clear_page_writeback(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
-       struct mem_cgroup *memcg;
        int ret;
 
-       memcg = mem_cgroup_begin_page_stat(page);
+       lock_page_memcg(page);
        if (mapping) {
                struct inode *inode = mapping->host;
                struct backing_dev_info *bdi = inode_to_bdi(inode);
@@ -2750,21 +2743,20 @@ int test_clear_page_writeback(struct page *page)
                ret = TestClearPageWriteback(page);
        }
        if (ret) {
-               mem_cgroup_dec_page_stat(memcg, MEM_CGROUP_STAT_WRITEBACK);
+               mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
                dec_zone_page_state(page, NR_WRITEBACK);
                inc_zone_page_state(page, NR_WRITTEN);
        }
-       mem_cgroup_end_page_stat(memcg);
+       unlock_page_memcg(page);
        return ret;
 }
 
 int __test_set_page_writeback(struct page *page, bool keep_write)
 {
        struct address_space *mapping = page_mapping(page);
-       struct mem_cgroup *memcg;
        int ret;
 
-       memcg = mem_cgroup_begin_page_stat(page);
+       lock_page_memcg(page);
        if (mapping) {
                struct inode *inode = mapping->host;
                struct backing_dev_info *bdi = inode_to_bdi(inode);
@@ -2792,10 +2784,10 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
                ret = TestSetPageWriteback(page);
        }
        if (!ret) {
-               mem_cgroup_inc_page_stat(memcg, MEM_CGROUP_STAT_WRITEBACK);
+               mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
                inc_zone_page_state(page, NR_WRITEBACK);
        }
-       mem_cgroup_end_page_stat(memcg);
+       unlock_page_memcg(page);
        return ret;
 
 }