From d631abdac9d541d282a1461b5aeae70aa3866e9f Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sun, 1 Jun 2014 23:24:30 +0900 Subject: [PATCH] f2fs: fix recursive lock by f2fs_setxattr This patch should resolve the following recursive lock. [] call_rwsem_down_write_failed+0x13/0x20 [] f2fs_setxattr+0x5c/0xa0 [f2fs] [] __f2fs_set_acl+0x1b9/0x340 [f2fs] [] f2fs_init_acl+0x4a/0xcb [f2fs] [] __f2fs_add_link+0x26e/0x780 [f2fs] [] f2fs_mkdir+0xb8/0x150 [f2fs] [] vfs_mkdir+0xb7/0x160 [] SyS_mkdir+0xab/0xe0 [] tracesys+0xe1/0xe6 [] 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 --- fs/f2fs/xattr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 1f546b4b6b61..8bea941ee309 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -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);