f2fs: fix recursive lock by f2fs_setxattr
authorJaegeuk Kim <jaegeuk@kernel.org>
Sun, 1 Jun 2014 14:24:30 +0000 (23:24 +0900)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 2 Jun 2014 13:13:16 +0000 (22:13 +0900)
This patch should resolve the following recursive lock.

[<ffffffff8135a9c3>] call_rwsem_down_write_failed+0x13/0x20
[<ffffffffa01749dc>] f2fs_setxattr+0x5c/0xa0 [f2fs]
[<ffffffffa0174c99>] __f2fs_set_acl+0x1b9/0x340 [f2fs]
[<ffffffffa017515a>] f2fs_init_acl+0x4a/0xcb [f2fs]
[<ffffffffa0159abe>] __f2fs_add_link+0x26e/0x780 [f2fs]
[<ffffffffa015d4d8>] f2fs_mkdir+0xb8/0x150 [f2fs]
[<ffffffff811cebd7>] vfs_mkdir+0xb7/0x160
[<ffffffff811cf89b>] SyS_mkdir+0xab/0xe0
[<ffffffff817244bf>] tracesys+0xe1/0xe6
[<ffffffffffffffff>] 0xffffffffffffffff

The call path indicates:
- f2fs_add_link
   : down_write(&fi->i_sem);

 - init_inode_metadata
   - f2fs_init_acl
     - __f2fs_set_acl
       - f2fs_setxattr
         : down_write(&fi->i_sem);

Here we should not call f2fs_setxattr, but __f2fs_setxattr.
But __f2fs_setxattr is a static function in xattr.c, so that I found the other
generic approach to use f2fs_setxattr.

In f2fs_setxattr, the page pointer is only given from init_inode_metadata.
So, this patch adds this condition to avoid this in f2fs_setxattr.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/xattr.c

index 1f546b4b6b61913691d34ca11eaa8f61205fb5d5..8bea941ee309607647cbc7a8c1282e0419dcef12 100644 (file)
@@ -156,10 +156,6 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
 }
 
 #ifdef CONFIG_F2FS_FS_SECURITY
-static int __f2fs_setxattr(struct inode *inode, int index,
-                       const char *name, const void *value, size_t size,
-                       struct page *ipage, int);
-
 static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
                void *page)
 {
@@ -167,7 +163,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
        int err = 0;
 
        for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-               err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
+               err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
                                xattr->name, xattr->value,
                                xattr->value_len, (struct page *)page, 0);
                if (err < 0)
@@ -603,6 +599,10 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        int err;
 
+       /* this case is only from init_inode_metadata */
+       if (ipage)
+               return __f2fs_setxattr(inode, index, name, value,
+                                               size, ipage, flags);
        f2fs_balance_fs(sbi);
 
        f2fs_lock_op(sbi);