]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/page-writeback.c
ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t
[mirror_ubuntu-artful-kernel.git] / mm / page-writeback.c
index 143c1c25d680c272eefd1e2ee7f58a0043d4f8b1..bf050ab025b76a268cd09a37173eac4f86febcb8 100644 (file)
@@ -601,7 +601,7 @@ static inline void __wb_writeout_inc(struct bdi_writeback *wb)
 {
        struct wb_domain *cgdom;
 
-       __inc_wb_stat(wb, WB_WRITTEN);
+       inc_wb_stat(wb, WB_WRITTEN);
        wb_domain_writeout_inc(&global_wb_domain, &wb->completions,
                               wb->bdi->max_prop_frac);
 
@@ -2366,15 +2366,15 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 }
 
 /**
- * write_one_page - write out a single page and optionally wait on I/O
+ * write_one_page - write out a single page and wait on I/O
  * @page: the page to write
- * @wait: if true, wait on writeout
  *
  * The page must be locked by the caller and will be unlocked upon return.
  *
- * write_one_page() returns a negative error code if I/O failed.
+ * Note that the mapping's AS_EIO/AS_ENOSPC flags will be cleared when this
+ * function returns.
  */
-int write_one_page(struct page *page, int wait)
+int write_one_page(struct page *page)
 {
        struct address_space *mapping = page->mapping;
        int ret = 0;
@@ -2385,21 +2385,20 @@ int write_one_page(struct page *page, int wait)
 
        BUG_ON(!PageLocked(page));
 
-       if (wait)
-               wait_on_page_writeback(page);
+       wait_on_page_writeback(page);
 
        if (clear_page_dirty_for_io(page)) {
                get_page(page);
                ret = mapping->a_ops->writepage(page, &wbc);
-               if (ret == 0 && wait) {
+               if (ret == 0)
                        wait_on_page_writeback(page);
-                       if (PageError(page))
-                               ret = -EIO;
-               }
                put_page(page);
        } else {
                unlock_page(page);
        }
+
+       if (!ret)
+               ret = filemap_check_errors(mapping);
        return ret;
 }
 EXPORT_SYMBOL(write_one_page);
@@ -2433,12 +2432,11 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
                inode_attach_wb(inode, page);
                wb = inode_to_wb(inode);
 
-               inc_memcg_page_state(page, NR_FILE_DIRTY);
-               __inc_node_page_state(page, NR_FILE_DIRTY);
+               __inc_lruvec_page_state(page, NR_FILE_DIRTY);
                __inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                __inc_node_page_state(page, NR_DIRTIED);
-               __inc_wb_stat(wb, WB_RECLAIMABLE);
-               __inc_wb_stat(wb, WB_DIRTIED);
+               inc_wb_stat(wb, WB_RECLAIMABLE);
+               inc_wb_stat(wb, WB_DIRTIED);
                task_io_account_write(PAGE_SIZE);
                current->nr_dirtied++;
                this_cpu_inc(bdp_ratelimits);
@@ -2455,8 +2453,7 @@ void account_page_cleaned(struct page *page, struct address_space *mapping,
                          struct bdi_writeback *wb)
 {
        if (mapping_cap_account_dirty(mapping)) {
-               dec_memcg_page_state(page, NR_FILE_DIRTY);
-               dec_node_page_state(page, NR_FILE_DIRTY);
+               dec_lruvec_page_state(page, NR_FILE_DIRTY);
                dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                dec_wb_stat(wb, WB_RECLAIMABLE);
                task_io_account_cancelled_write(PAGE_SIZE);
@@ -2712,8 +2709,7 @@ int clear_page_dirty_for_io(struct page *page)
                 */
                wb = unlocked_inode_to_wb_begin(inode, &locked);
                if (TestClearPageDirty(page)) {
-                       dec_memcg_page_state(page, NR_FILE_DIRTY);
-                       dec_node_page_state(page, NR_FILE_DIRTY);
+                       dec_lruvec_page_state(page, NR_FILE_DIRTY);
                        dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                        dec_wb_stat(wb, WB_RECLAIMABLE);
                        ret = 1;
@@ -2728,9 +2724,12 @@ 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;
+       struct lruvec *lruvec;
        int ret;
 
-       lock_page_memcg(page);
+       memcg = lock_page_memcg(page);
+       lruvec = mem_cgroup_page_lruvec(page, page_pgdat(page));
        if (mapping && mapping_use_writeback_tags(mapping)) {
                struct inode *inode = mapping->host;
                struct backing_dev_info *bdi = inode_to_bdi(inode);
@@ -2745,7 +2744,7 @@ int test_clear_page_writeback(struct page *page)
                        if (bdi_cap_account_writeback(bdi)) {
                                struct bdi_writeback *wb = inode_to_wb(inode);
 
-                               __dec_wb_stat(wb, WB_WRITEBACK);
+                               dec_wb_stat(wb, WB_WRITEBACK);
                                __wb_writeout_inc(wb);
                        }
                }
@@ -2758,13 +2757,18 @@ int test_clear_page_writeback(struct page *page)
        } else {
                ret = TestClearPageWriteback(page);
        }
+       /*
+        * NOTE: Page might be free now! Writeback doesn't hold a page
+        * reference on its own, it relies on truncation to wait for
+        * the clearing of PG_writeback. The below can only access
+        * page state that is static across allocation cycles.
+        */
        if (ret) {
-               dec_memcg_page_state(page, NR_WRITEBACK);
-               dec_node_page_state(page, NR_WRITEBACK);
+               dec_lruvec_state(lruvec, NR_WRITEBACK);
                dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
                inc_node_page_state(page, NR_WRITTEN);
        }
-       unlock_page_memcg(page);
+       __unlock_page_memcg(memcg);
        return ret;
 }
 
@@ -2791,7 +2795,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
                                                page_index(page),
                                                PAGECACHE_TAG_WRITEBACK);
                        if (bdi_cap_account_writeback(bdi))
-                               __inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK);
+                               inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK);
 
                        /*
                         * We can come through here when swapping anonymous
@@ -2814,8 +2818,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
                ret = TestSetPageWriteback(page);
        }
        if (!ret) {
-               inc_memcg_page_state(page, NR_WRITEBACK);
-               inc_node_page_state(page, NR_WRITEBACK);
+               inc_lruvec_page_state(page, NR_WRITEBACK);
                inc_zone_page_state(page, NR_ZONE_WRITE_PENDING);
        }
        unlock_page_memcg(page);