OSDN Git Service

f2fs: handle error case when adding xattr entry
authorJaegeuk Kim <jaegeuk@kernel.org>
Mon, 16 Oct 2017 22:05:16 +0000 (15:05 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Thu, 16 Nov 2017 05:58:14 +0000 (21:58 -0800)
This patch fixes recovering incomplete xattr entries remaining in inline xattr
and xattr block, caused by any kind of errors.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/xattr.c

index bcf455a..7acf56e 100644 (file)
@@ -436,10 +436,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        size_t inline_size = inline_xattr_size(inode);
+       struct page *in_page = NULL;
        void *xattr_addr;
+       void *inline_addr = NULL;
        struct page *xpage;
        nid_t new_nid = 0;
-       int err;
+       int err = 0;
 
        if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
                if (!alloc_nid(sbi, &new_nid))
@@ -447,30 +449,30 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
 
        /* write to inline xattr */
        if (inline_size) {
-               struct page *page = NULL;
-               void *inline_addr;
-
                if (ipage) {
                        inline_addr = inline_xattr_addr(inode, ipage);
-                       f2fs_wait_on_page_writeback(ipage, NODE, true);
-                       set_page_dirty(ipage);
                } else {
-                       page = get_node_page(sbi, inode->i_ino);
-                       if (IS_ERR(page)) {
+                       in_page = get_node_page(sbi, inode->i_ino);
+                       if (IS_ERR(in_page)) {
                                alloc_nid_failed(sbi, new_nid);
-                               return PTR_ERR(page);
+                               return PTR_ERR(in_page);
                        }
-                       inline_addr = inline_xattr_addr(inode, page);
-                       f2fs_wait_on_page_writeback(page, NODE, true);
+                       inline_addr = inline_xattr_addr(inode, in_page);
                }
-               memcpy(inline_addr, txattr_addr, inline_size);
-               f2fs_put_page(page, 1);
 
+               f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
+                                                       NODE, true);
                /* no need to use xattr node block */
                if (hsize <= inline_size) {
                        err = truncate_xattr_node(inode);
                        alloc_nid_failed(sbi, new_nid);
-                       return err;
+                       if (err) {
+                               f2fs_put_page(in_page, 1);
+                               return err;
+                       }
+                       memcpy(inline_addr, txattr_addr, inline_size);
+                       set_page_dirty(ipage ? ipage : in_page);
+                       goto in_page_out;
                }
        }
 
@@ -479,7 +481,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
                if (IS_ERR(xpage)) {
                        alloc_nid_failed(sbi, new_nid);
-                       return PTR_ERR(xpage);
+                       goto in_page_out;
                }
                f2fs_bug_on(sbi, new_nid);
                f2fs_wait_on_page_writeback(xpage, NODE, true);
@@ -489,17 +491,24 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
                if (IS_ERR(xpage)) {
                        alloc_nid_failed(sbi, new_nid);
-                       return PTR_ERR(xpage);
+                       goto in_page_out;
                }
                alloc_nid_done(sbi, new_nid);
        }
-
        xattr_addr = page_address(xpage);
+
+       if (inline_size)
+               memcpy(inline_addr, txattr_addr, inline_size);
        memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
+
+       if (inline_size)
+               set_page_dirty(ipage ? ipage : in_page);
        set_page_dirty(xpage);
-       f2fs_put_page(xpage, 1);
 
-       return 0;
+       f2fs_put_page(xpage, 1);
+in_page_out:
+       f2fs_put_page(in_page, 1);
+       return err;
 }
 
 int f2fs_getxattr(struct inode *inode, int index, const char *name,