[PATCH] zoned vm counters: conversion of nr_writeback to per zone counter
[safe/jmp/linux-2.6] / mm / page-writeback.c
index c1052ee..3cfdff4 100644 (file)
@@ -72,13 +72,12 @@ int dirty_background_ratio = 10;
 int vm_dirty_ratio = 40;
 
 /*
- * The interval between `kupdate'-style writebacks, in centiseconds
- * (hundredths of a second)
+ * The interval between `kupdate'-style writebacks, in jiffies
  */
 int dirty_writeback_interval = 5 * HZ;
 
 /*
- * The longest number of centiseconds for which data is allowed to remain dirty
+ * The longest number of jiffies for which data is allowed to remain dirty
  */
 int dirty_expire_interval = 30 * HZ;
 
@@ -110,10 +109,11 @@ struct writeback_state
 
 static void get_writeback_state(struct writeback_state *wbs)
 {
-       wbs->nr_dirty = read_page_state(nr_dirty);
+       wbs->nr_dirty = global_page_state(NR_FILE_DIRTY);
        wbs->nr_unstable = read_page_state(nr_unstable);
-       wbs->nr_mapped = read_page_state(nr_mapped);
-       wbs->nr_writeback = read_page_state(nr_writeback);
+       wbs->nr_mapped = global_page_state(NR_FILE_MAPPED) +
+                               global_page_state(NR_ANON_PAGES);
+       wbs->nr_writeback = global_page_state(NR_WRITEBACK);
 }
 
 /*
@@ -205,6 +205,7 @@ static void balance_dirty_pages(struct address_space *mapping)
                        .sync_mode      = WB_SYNC_NONE,
                        .older_than_this = NULL,
                        .nr_to_write    = write_chunk,
+                       .range_cyclic   = 1,
                };
 
                get_dirty_limits(&wbs, &background_thresh,
@@ -256,8 +257,9 @@ static void balance_dirty_pages(struct address_space *mapping)
 }
 
 /**
- * balance_dirty_pages_ratelimited - balance dirty memory state
+ * balance_dirty_pages_ratelimited_nr - balance dirty memory state
  * @mapping: address_space which was dirtied
+ * @nr_pages_dirtied: number of pages which the caller has just dirtied
  *
  * Processes which are dirtying memory should call in here once for each page
  * which was newly dirtied.  The function will periodically check the system's
@@ -268,10 +270,12 @@ static void balance_dirty_pages(struct address_space *mapping)
  * limit we decrease the ratelimiting by a lot, to prevent individual processes
  * from overshooting the limit by (ratelimit_pages) each.
  */
-void balance_dirty_pages_ratelimited(struct address_space *mapping)
+void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
+                                       unsigned long nr_pages_dirtied)
 {
-       static DEFINE_PER_CPU(int, ratelimits) = 0;
-       long ratelimit;
+       static DEFINE_PER_CPU(unsigned long, ratelimits) = 0;
+       unsigned long ratelimit;
+       unsigned long *p;
 
        ratelimit = ratelimit_pages;
        if (dirty_exceeded)
@@ -281,15 +285,18 @@ void balance_dirty_pages_ratelimited(struct address_space *mapping)
         * Check the rate limiting. Also, we do not want to throttle real-time
         * tasks in balance_dirty_pages(). Period.
         */
-       if (get_cpu_var(ratelimits)++ >= ratelimit) {
-               __get_cpu_var(ratelimits) = 0;
-               put_cpu_var(ratelimits);
+       preempt_disable();
+       p =  &__get_cpu_var(ratelimits);
+       *p += nr_pages_dirtied;
+       if (unlikely(*p >= ratelimit)) {
+               *p = 0;
+               preempt_enable();
                balance_dirty_pages(mapping);
                return;
        }
-       put_cpu_var(ratelimits);
+       preempt_enable();
 }
-EXPORT_SYMBOL(balance_dirty_pages_ratelimited);
+EXPORT_SYMBOL(balance_dirty_pages_ratelimited_nr);
 
 void throttle_vm_writeout(void)
 {
@@ -326,6 +333,7 @@ static void background_writeout(unsigned long _min_pages)
                .older_than_this = NULL,
                .nr_to_write    = 0,
                .nonblocking    = 1,
+               .range_cyclic   = 1,
        };
 
        for ( ; ; ) {
@@ -402,6 +410,7 @@ static void wb_kupdate(unsigned long arg)
                .nr_to_write    = 0,
                .nonblocking    = 1,
                .for_kupdate    = 1,
+               .range_cyclic   = 1,
        };
 
        sync_supers();
@@ -508,14 +517,14 @@ static void set_ratelimit(void)
                ratelimit_pages = (4096 * 1024) / PAGE_CACHE_SIZE;
 }
 
-static int
+static int __cpuinit
 ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
 {
        set_ratelimit();
        return 0;
 }
 
-static struct notifier_block ratelimit_nb = {
+static struct notifier_block __cpuinitdata ratelimit_nb = {
        .notifier_call  = ratelimit_handler,
        .next           = NULL,
 };
@@ -622,8 +631,6 @@ EXPORT_SYMBOL(write_one_page);
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
-       int ret = 0;
-
        if (!TestSetPageDirty(page)) {
                struct address_space *mapping = page_mapping(page);
                struct address_space *mapping2;
@@ -634,7 +641,8 @@ int __set_page_dirty_nobuffers(struct page *page)
                        if (mapping2) { /* Race with truncate? */
                                BUG_ON(mapping2 != mapping);
                                if (mapping_cap_account_dirty(mapping))
-                                       inc_page_state(nr_dirty);
+                                       __inc_zone_page_state(page,
+                                                               NR_FILE_DIRTY);
                                radix_tree_tag_set(&mapping->page_tree,
                                        page_index(page), PAGECACHE_TAG_DIRTY);
                        }
@@ -645,8 +653,9 @@ int __set_page_dirty_nobuffers(struct page *page)
                                                        I_DIRTY_PAGES);
                        }
                }
+               return 1;
        }
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 
@@ -676,8 +685,10 @@ int fastcall set_page_dirty(struct page *page)
                        return (*spd)(page);
                return __set_page_dirty_buffers(page);
        }
-       if (!PageDirty(page))
-               SetPageDirty(page);
+       if (!PageDirty(page)) {
+               if (!TestSetPageDirty(page))
+                       return 1;
+       }
        return 0;
 }
 EXPORT_SYMBOL(set_page_dirty);
@@ -718,9 +729,9 @@ int test_clear_page_dirty(struct page *page)
                        radix_tree_tag_clear(&mapping->page_tree,
                                                page_index(page),
                                                PAGECACHE_TAG_DIRTY);
-                       write_unlock_irqrestore(&mapping->tree_lock, flags);
                        if (mapping_cap_account_dirty(mapping))
-                               dec_page_state(nr_dirty);
+                               __dec_zone_page_state(page, NR_FILE_DIRTY);
+                       write_unlock_irqrestore(&mapping->tree_lock, flags);
                        return 1;
                }
                write_unlock_irqrestore(&mapping->tree_lock, flags);
@@ -751,7 +762,7 @@ int clear_page_dirty_for_io(struct page *page)
        if (mapping) {
                if (TestClearPageDirty(page)) {
                        if (mapping_cap_account_dirty(mapping))
-                               dec_page_state(nr_dirty);
+                               dec_zone_page_state(page, NR_FILE_DIRTY);
                        return 1;
                }
                return 0;