aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2017-02-14 12:54:37 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-12 00:41:51 -0500
commitd00d1b71d98468ad6fbee590705c27fc1241f96e (patch)
tree2d7cc75a50ac66d8f7c478c99dfb3b692a9a8bc3
parentec160ad2acaad4a7de6eab7338ef5e3b2b19f907 (diff)
f2fs: fix multiple f2fs_add_link() calls having same name
commit 88c5c13a5027b36d914536fdba23f069d7067204 upstream. It turns out a stakable filesystem like sdcardfs in AOSP can trigger multiple vfs_create() to lower filesystem. In that case, f2fs will add multiple dentries having same name which breaks filesystem consistency. Until upper layer fixes, let's work around by f2fs, which shows actually not much performance regression. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/f2fs/dir.c34
-rw-r--r--fs/f2fs/f2fs.h1
2 files changed, 30 insertions, 5 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 369f4513be37..ebdc90fc71b7 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -207,9 +207,13 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
207 f2fs_put_page(dentry_page, 0); 207 f2fs_put_page(dentry_page, 0);
208 } 208 }
209 209
210 if (!de && room && F2FS_I(dir)->chash != namehash) { 210 /* This is to increase the speed of f2fs_create */
211 F2FS_I(dir)->chash = namehash; 211 if (!de && room) {
212 F2FS_I(dir)->clevel = level; 212 F2FS_I(dir)->task = current;
213 if (F2FS_I(dir)->chash != namehash) {
214 F2FS_I(dir)->chash = namehash;
215 F2FS_I(dir)->clevel = level;
216 }
213 } 217 }
214 218
215 return de; 219 return de;
@@ -643,14 +647,34 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
643 struct inode *inode, nid_t ino, umode_t mode) 647 struct inode *inode, nid_t ino, umode_t mode)
644{ 648{
645 struct fscrypt_name fname; 649 struct fscrypt_name fname;
650 struct page *page = NULL;
651 struct f2fs_dir_entry *de = NULL;
646 int err; 652 int err;
647 653
648 err = fscrypt_setup_filename(dir, name, 0, &fname); 654 err = fscrypt_setup_filename(dir, name, 0, &fname);
649 if (err) 655 if (err)
650 return err; 656 return err;
651 657
652 err = __f2fs_do_add_link(dir, &fname, inode, ino, mode); 658 /*
653 659 * An immature stakable filesystem shows a race condition between lookup
660 * and create. If we have same task when doing lookup and create, it's
661 * definitely fine as expected by VFS normally. Otherwise, let's just
662 * verify on-disk dentry one more time, which guarantees filesystem
663 * consistency more.
664 */
665 if (current != F2FS_I(dir)->task) {
666 de = __f2fs_find_entry(dir, &fname, &page);
667 F2FS_I(dir)->task = NULL;
668 }
669 if (de) {
670 f2fs_dentry_kunmap(dir, page);
671 f2fs_put_page(page, 0);
672 err = -EEXIST;
673 } else if (IS_ERR(page)) {
674 err = PTR_ERR(page);
675 } else {
676 err = __f2fs_do_add_link(dir, &fname, inode, ino, mode);
677 }
654 fscrypt_free_filename(&fname); 678 fscrypt_free_filename(&fname);
655 return err; 679 return err;
656} 680}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 506af456412f..ecc3fd0ca6bb 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -431,6 +431,7 @@ struct f2fs_inode_info {
431 atomic_t dirty_pages; /* # of dirty pages */ 431 atomic_t dirty_pages; /* # of dirty pages */
432 f2fs_hash_t chash; /* hash value of given file name */ 432 f2fs_hash_t chash; /* hash value of given file name */
433 unsigned int clevel; /* maximum level of given file name */ 433 unsigned int clevel; /* maximum level of given file name */
434 struct task_struct *task; /* lookup and create consistency */
434 nid_t i_xattr_nid; /* node id that contains xattrs */ 435 nid_t i_xattr_nid; /* node id that contains xattrs */
435 unsigned long long xattr_ver; /* cp version of xattr modification */ 436 unsigned long long xattr_ver; /* cp version of xattr modification */
436 loff_t last_disk_size; /* lastly written file size */ 437 loff_t last_disk_size; /* lastly written file size */