diff options
author | Russ Knize <Russ.Knize@motorola.com> | 2013-09-24 16:49:23 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-09-25 04:51:24 -0400 |
commit | 52ab956000214aa111254e52e5eac3d91bd7cf4b (patch) | |
tree | f449477dc83760d163de59e629f68bb74696b36c /fs | |
parent | 885166c03c1d0ea6d79d707229340e3161ed1316 (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.c | 35 |
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 |
157 | static int __f2fs_setxattr(struct inode *inode, int name_index, | ||
158 | const char *name, const void *value, size_t value_len, | ||
159 | struct page *ipage); | ||
157 | static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_array, | 160 | static 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 | ||
472 | int f2fs_setxattr(struct inode *inode, int name_index, const char *name, | 475 | static 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); |
580 | exit: | 578 | exit: |
581 | mutex_unlock_op(sbi, ilock); | ||
582 | kzfree(base_addr); | 579 | kzfree(base_addr); |
583 | return error; | 580 | return error; |
584 | } | 581 | } |
582 | |||
583 | int 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 | } | ||