aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRuss Knize <Russ.Knize@motorola.com>2013-09-24 16:49:23 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-09-25 04:51:24 -0400
commit52ab956000214aa111254e52e5eac3d91bd7cf4b (patch)
treef449477dc83760d163de59e629f68bb74696b36c /fs
parent885166c03c1d0ea6d79d707229340e3161ed1316 (diff)
f2fs: don't GC or take an fs_lock from f2fs_initxattrs()
f2fs_initxattrs() is called internally from within F2FS and should not call functions that are used by VFS handlers. This avoids certain deadlocks: - vfs_create() - f2fs_create() <-- takes an fs_lock - f2fs_add_link() - __f2fs_add_link() - init_inode_metadata() - f2fs_init_security() - security_inode_init_security() - f2fs_initxattrs() - f2fs_setxattr() <-- also takes an fs_lock If the caller happens to grab the same fs_lock from the pool in both places, they will deadlock. There are also deadlocks involving multiple threads and mutexes: - f2fs_write_begin() - f2fs_balance_fs() <-- takes gc_mutex - f2fs_gc() - write_checkpoint() - block_operations() - mutex_lock_all() <-- blocks trying to grab all fs_locks - f2fs_mkdir() <-- takes an fs_lock - __f2fs_add_link() - f2fs_init_security() - security_inode_init_security() - f2fs_initxattrs() - f2fs_setxattr() - f2fs_balance_fs() <-- blocks trying to take gc_mutex Signed-off-by: Russ Knize <Russ.Knize@motorola.com> Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/f2fs/xattr.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 1ac8a5f6e380..3d900ea34e47 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -154,6 +154,9 @@ static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
154} 154}
155 155
156#ifdef CONFIG_F2FS_FS_SECURITY 156#ifdef CONFIG_F2FS_FS_SECURITY
157static int __f2fs_setxattr(struct inode *inode, int name_index,
158 const char *name, const void *value, size_t value_len,
159 struct page *ipage);
157static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, 160static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
158 void *page) 161 void *page)
159{ 162{
@@ -161,7 +164,7 @@ static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
161 int err = 0; 164 int err = 0;
162 165
163 for (xattr = xattr_array; xattr->name != NULL; xattr++) { 166 for (xattr = xattr_array; xattr->name != NULL; xattr++) {
164 err = f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY, 167 err = __f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY,
165 xattr->name, xattr->value, 168 xattr->name, xattr->value,
166 xattr->value_len, (struct page *)page); 169 xattr->value_len, (struct page *)page);
167 if (err < 0) 170 if (err < 0)
@@ -469,16 +472,15 @@ cleanup:
469 return error; 472 return error;
470} 473}
471 474
472int f2fs_setxattr(struct inode *inode, int name_index, const char *name, 475static int __f2fs_setxattr(struct inode *inode, int name_index,
473 const void *value, size_t value_len, struct page *ipage) 476 const char *name, const void *value, size_t value_len,
477 struct page *ipage)
474{ 478{
475 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
476 struct f2fs_inode_info *fi = F2FS_I(inode); 479 struct f2fs_inode_info *fi = F2FS_I(inode);
477 struct f2fs_xattr_entry *here, *last; 480 struct f2fs_xattr_entry *here, *last;
478 void *base_addr; 481 void *base_addr;
479 int found, newsize; 482 int found, newsize;
480 size_t name_len; 483 size_t name_len;
481 int ilock;
482 __u32 new_hsize; 484 __u32 new_hsize;
483 int error = -ENOMEM; 485 int error = -ENOMEM;
484 486
@@ -493,10 +495,6 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
493 if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode)) 495 if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode))
494 return -ERANGE; 496 return -ERANGE;
495 497
496 f2fs_balance_fs(sbi);
497
498 ilock = mutex_lock_op(sbi);
499
500 base_addr = read_all_xattrs(inode, ipage); 498 base_addr = read_all_xattrs(inode, ipage);
501 if (!base_addr) 499 if (!base_addr)
502 goto exit; 500 goto exit;
@@ -578,7 +576,24 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
578 else 576 else
579 update_inode_page(inode); 577 update_inode_page(inode);
580exit: 578exit:
581 mutex_unlock_op(sbi, ilock);
582 kzfree(base_addr); 579 kzfree(base_addr);
583 return error; 580 return error;
584} 581}
582
583int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
584 const void *value, size_t value_len, struct page *ipage)
585{
586 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
587 int ilock;
588 int err;
589
590 f2fs_balance_fs(sbi);
591
592 ilock = mutex_lock_op(sbi);
593
594 err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage);
595
596 mutex_unlock_op(sbi, ilock);
597
598 return err;
599}