There are two threads:
 f2fs_delete_entry()              get_new_data_page()
                                  f2fs_reserve_block()
                                  dn.blkaddr = XXX
 lock_page(dentry_block)
 truncate_hole()
 dn.blkaddr = NULL
 unlock_page(dentry_block)
                                  lock_page(dentry_block)
                                  fill the block from XXX address
                                  add new dentries
                                  unlock_page(dentry_block)

Later, f2fs_write_data_page() will truncate the dentry_block, since
its block address is NULL.

The reason for this was due to the wrong lock order.
In this case, we should do f2fs_reserve_block() after locking its dentry block.

Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org>
---
 fs/f2fs/data.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 81d1fd5..9ba30b4 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1076,20 +1076,22 @@ struct page *get_new_data_page(struct inode *inode,
        struct page *page;
        struct dnode_of_data dn;
        int err;
+repeat:
+       page = grab_cache_page(mapping, index);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
 
        set_new_dnode(&dn, inode, ipage, NULL, 0);
        err = f2fs_reserve_block(&dn, index);
-       if (err)
+       if (err) {
+               f2fs_put_page(page, 1);
                return ERR_PTR(err);
-repeat:
-       page = grab_cache_page(mapping, index);
-       if (!page) {
-               err = -ENOMEM;
-               goto put_err;
        }
+       if (!ipage)
+               f2fs_put_dnode(&dn);
 
        if (PageUptodate(page))
-               return page;
+               goto got_it;
 
        if (dn.data_blkaddr == NEW_ADDR) {
                zero_user_segment(page, 0, PAGE_CACHE_SIZE);
@@ -1104,20 +1106,19 @@ repeat:
                };
                err = f2fs_submit_page_bio(&fio);
                if (err)
-                       goto put_err;
+                       return ERR_PTR(err);
 
                lock_page(page);
                if (unlikely(!PageUptodate(page))) {
                        f2fs_put_page(page, 1);
-                       err = -EIO;
-                       goto put_err;
+                       return ERR_PTR(-EIO);
                }
                if (unlikely(page->mapping != mapping)) {
                        f2fs_put_page(page, 1);
                        goto repeat;
                }
        }
-
+got_it:
        if (new_i_size &&
                i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) {
                i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT));
@@ -1125,10 +1126,6 @@ repeat:
                set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR);
        }
        return page;
-
-put_err:
-       f2fs_put_dnode(&dn);
-       return ERR_PTR(err);
 }
 
 static int __allocate_data_block(struct dnode_of_data *dn)
-- 
2.1.1


------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud 
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to