pnfsblock: move find lock page logic out of bl_write_pagelist
authorPeng Tao <bergwolf@gmail.com>
Thu, 12 Jan 2012 15:18:42 +0000 (23:18 +0800)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 12 Jan 2012 21:52:10 +0000 (16:52 -0500)
Also avoid unnecessary lock_page if page is handled by others.

Signed-off-by: Peng Tao <peng_tao@emc.com>
Signed-off-by: Benny Halevy <bhalevy@tonian.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/blocklayout/blocklayout.c

index a263810..2342736 100644 (file)
@@ -490,6 +490,55 @@ cleanup:
        return ret;
 }
 
+/* Find or create a zeroing page marked being writeback.
+ * Return ERR_PTR on error, NULL to indicate skip this page and page itself
+ * to indicate write out.
+ */
+static struct page *
+bl_find_get_zeroing_page(struct inode *inode, pgoff_t index,
+                       struct pnfs_block_extent *cow_read)
+{
+       struct page *page;
+       int locked = 0;
+       page = find_get_page(inode->i_mapping, index);
+       if (page)
+               goto check_page;
+
+       page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
+       if (unlikely(!page)) {
+               dprintk("%s oom\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+       locked = 1;
+
+check_page:
+       /* PageDirty: Other will write this out
+        * PageWriteback: Other is writing this out
+        * PageUptodate: It was read before
+        */
+       if (PageDirty(page) || PageWriteback(page)) {
+               print_page(page);
+               if (locked)
+                       unlock_page(page);
+               page_cache_release(page);
+               return NULL;
+       }
+
+       if (!locked) {
+               lock_page(page);
+               locked = 1;
+               goto check_page;
+       }
+       if (!PageUptodate(page)) {
+               /* New page, readin or zero it */
+               init_page_for_write(page, cow_read);
+       }
+       set_page_writeback(page);
+       unlock_page(page);
+
+       return page;
+}
+
 static enum pnfs_try_status
 bl_write_pagelist(struct nfs_write_data *wdata, int sync)
 {
@@ -549,32 +598,13 @@ fill_invalid_ext:
                        dprintk("%s zero %dth page: index %lu isect %llu\n",
                                __func__, npg_zero, index,
                                (unsigned long long)isect);
-                       page =
-                           find_or_create_page(wdata->inode->i_mapping, index,
-                                               GFP_NOFS);
-                       if (!page) {
-                               dprintk("%s oom\n", __func__);
-                               wdata->pnfs_error = -ENOMEM;
+                       page = bl_find_get_zeroing_page(wdata->inode, index,
+                                                       cow_read);
+                       if (unlikely(IS_ERR(page))) {
+                               wdata->pnfs_error = PTR_ERR(page);
                                goto out;
-                       }
-
-                       /* PageDirty: Other will write this out
-                        * PageWriteback: Other is writing this out
-                        * PageUptodate: It was read before
-                        * sector_initialized: already written out
-                        */
-                       if (PageDirty(page) || PageWriteback(page)) {
-                               print_page(page);
-                               unlock_page(page);
-                               page_cache_release(page);
+                       } else if (page == NULL)
                                goto next_page;
-                       }
-                       if (!PageUptodate(page)) {
-                               /* New page, readin or zero it */
-                               init_page_for_write(page, cow_read);
-                       }
-                       set_page_writeback(page);
-                       unlock_page(page);
 
                        ret = bl_mark_sectors_init(be->be_inval, isect,
                                                       PAGE_CACHE_SECTORS);