aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2014-03-20 06:10:08 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2014-03-20 09:10:11 -0400
commitd928bfbfe77aa457b765c19e9db8cd4cc72b3c89 (patch)
treef56763175e0fbee1e2079c9a330f3d73f971bc5c /fs
parent58c410351eba3d24f741c85a0eb9eaf15c94047d (diff)
f2fs: introduce fi->i_sem to protect fi's info
This patch introduces fi->i_sem to protect fi's info that includes xattr_ver, pino, i_nlink. This enables to remove i_mutex during f2fs_sync_file, resulting in performance improvement when a number of fsync calls are triggered from many concurrent threads. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/f2fs/dir.c6
-rw-r--r--fs/f2fs/f2fs.h1
-rw-r--r--fs/f2fs/file.c14
-rw-r--r--fs/f2fs/namei.c7
-rw-r--r--fs/f2fs/super.c1
-rw-r--r--fs/f2fs/xattr.c3
6 files changed, 28 insertions, 4 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 7c9b17c03675..972fd0ef230f 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -493,6 +493,7 @@ start:
493add_dentry: 493add_dentry:
494 f2fs_wait_on_page_writeback(dentry_page, DATA); 494 f2fs_wait_on_page_writeback(dentry_page, DATA);
495 495
496 down_write(&F2FS_I(inode)->i_sem);
496 page = init_inode_metadata(inode, dir, name); 497 page = init_inode_metadata(inode, dir, name);
497 if (IS_ERR(page)) { 498 if (IS_ERR(page)) {
498 err = PTR_ERR(page); 499 err = PTR_ERR(page);
@@ -515,6 +516,8 @@ add_dentry:
515 516
516 update_parent_metadata(dir, inode, current_depth); 517 update_parent_metadata(dir, inode, current_depth);
517fail: 518fail:
519 up_write(&F2FS_I(inode)->i_sem);
520
518 if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { 521 if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
519 update_inode_page(dir); 522 update_inode_page(dir);
520 clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); 523 clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
@@ -559,6 +562,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
559 if (inode) { 562 if (inode) {
560 struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); 563 struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
561 564
565 down_write(&F2FS_I(inode)->i_sem);
566
562 if (S_ISDIR(inode->i_mode)) { 567 if (S_ISDIR(inode->i_mode)) {
563 drop_nlink(dir); 568 drop_nlink(dir);
564 update_inode_page(dir); 569 update_inode_page(dir);
@@ -569,6 +574,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
569 drop_nlink(inode); 574 drop_nlink(inode);
570 i_size_write(inode, 0); 575 i_size_write(inode, 0);
571 } 576 }
577 up_write(&F2FS_I(inode)->i_sem);
572 update_inode_page(inode); 578 update_inode_page(inode);
573 579
574 if (inode->i_nlink == 0) 580 if (inode->i_nlink == 0)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 05c652493f04..469779ab1d77 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -210,6 +210,7 @@ struct f2fs_inode_info {
210 210
211 /* Use below internally in f2fs*/ 211 /* Use below internally in f2fs*/
212 unsigned long flags; /* use to pass per-file flags */ 212 unsigned long flags; /* use to pass per-file flags */
213 struct rw_semaphore i_sem; /* protect fi info */
213 atomic_t dirty_dents; /* # of dirty dentry pages */ 214 atomic_t dirty_dents; /* # of dirty dentry pages */
214 f2fs_hash_t chash; /* hash value of given file name */ 215 f2fs_hash_t chash; /* hash value of given file name */
215 unsigned int clevel; /* maximum level of given file name */ 216 unsigned int clevel; /* maximum level of given file name */
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index e755ee57e042..a9474cd4e0db 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -111,6 +111,7 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
111int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) 111int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
112{ 112{
113 struct inode *inode = file->f_mapping->host; 113 struct inode *inode = file->f_mapping->host;
114 struct f2fs_inode_info *fi = F2FS_I(inode);
114 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 115 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
115 int ret = 0; 116 int ret = 0;
116 bool need_cp = false; 117 bool need_cp = false;
@@ -133,7 +134,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
133 /* guarantee free sections for fsync */ 134 /* guarantee free sections for fsync */
134 f2fs_balance_fs(sbi); 135 f2fs_balance_fs(sbi);
135 136
136 mutex_lock(&inode->i_mutex); 137 down_read(&fi->i_sem);
137 138
138 /* 139 /*
139 * Both of fdatasync() and fsync() are able to be recovered from 140 * Both of fdatasync() and fsync() are able to be recovered from
@@ -150,21 +151,27 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
150 else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi))) 151 else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
151 need_cp = true; 152 need_cp = true;
152 153
154 up_read(&fi->i_sem);
155
153 if (need_cp) { 156 if (need_cp) {
154 nid_t pino; 157 nid_t pino;
155 158
156 F2FS_I(inode)->xattr_ver = 0;
157
158 /* all the dirty node pages should be flushed for POR */ 159 /* all the dirty node pages should be flushed for POR */
159 ret = f2fs_sync_fs(inode->i_sb, 1); 160 ret = f2fs_sync_fs(inode->i_sb, 1);
161
162 down_write(&fi->i_sem);
163 F2FS_I(inode)->xattr_ver = 0;
160 if (file_wrong_pino(inode) && inode->i_nlink == 1 && 164 if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
161 get_parent_ino(inode, &pino)) { 165 get_parent_ino(inode, &pino)) {
162 F2FS_I(inode)->i_pino = pino; 166 F2FS_I(inode)->i_pino = pino;
163 file_got_pino(inode); 167 file_got_pino(inode);
168 up_write(&fi->i_sem);
164 mark_inode_dirty_sync(inode); 169 mark_inode_dirty_sync(inode);
165 ret = f2fs_write_inode(inode, NULL); 170 ret = f2fs_write_inode(inode, NULL);
166 if (ret) 171 if (ret)
167 goto out; 172 goto out;
173 } else {
174 up_write(&fi->i_sem);
168 } 175 }
169 } else { 176 } else {
170 /* if there is no written node page, write its inode page */ 177 /* if there is no written node page, write its inode page */
@@ -180,7 +187,6 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
180 ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); 187 ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
181 } 188 }
182out: 189out:
183 mutex_unlock(&inode->i_mutex);
184 trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret); 190 trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
185 return ret; 191 return ret;
186} 192}
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 397d459e97bf..0cea87437a60 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -424,12 +424,17 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
424 } 424 }
425 425
426 f2fs_set_link(new_dir, new_entry, new_page, old_inode); 426 f2fs_set_link(new_dir, new_entry, new_page, old_inode);
427 down_write(&F2FS_I(old_inode)->i_sem);
427 F2FS_I(old_inode)->i_pino = new_dir->i_ino; 428 F2FS_I(old_inode)->i_pino = new_dir->i_ino;
429 up_write(&F2FS_I(old_inode)->i_sem);
428 430
429 new_inode->i_ctime = CURRENT_TIME; 431 new_inode->i_ctime = CURRENT_TIME;
432 down_write(&F2FS_I(new_inode)->i_sem);
430 if (old_dir_entry) 433 if (old_dir_entry)
431 drop_nlink(new_inode); 434 drop_nlink(new_inode);
432 drop_nlink(new_inode); 435 drop_nlink(new_inode);
436 up_write(&F2FS_I(new_inode)->i_sem);
437
433 mark_inode_dirty(new_inode); 438 mark_inode_dirty(new_inode);
434 439
435 if (!new_inode->i_nlink) 440 if (!new_inode->i_nlink)
@@ -459,7 +464,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
459 if (old_dir != new_dir) { 464 if (old_dir != new_dir) {
460 f2fs_set_link(old_inode, old_dir_entry, 465 f2fs_set_link(old_inode, old_dir_entry,
461 old_dir_page, new_dir); 466 old_dir_page, new_dir);
467 down_write(&F2FS_I(old_inode)->i_sem);
462 F2FS_I(old_inode)->i_pino = new_dir->i_ino; 468 F2FS_I(old_inode)->i_pino = new_dir->i_ino;
469 up_write(&F2FS_I(old_inode)->i_sem);
463 update_inode_page(old_inode); 470 update_inode_page(old_inode);
464 } else { 471 } else {
465 kunmap(old_dir_page); 472 kunmap(old_dir_page);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 34c47b2010bc..89ea046c846d 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -360,6 +360,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
360 fi->i_current_depth = 1; 360 fi->i_current_depth = 1;
361 fi->i_advise = 0; 361 fi->i_advise = 0;
362 rwlock_init(&fi->ext.ext_lock); 362 rwlock_init(&fi->ext.ext_lock);
363 init_rwsem(&fi->i_sem);
363 364
364 set_inode_flag(fi, FI_NEW_INODE); 365 set_inode_flag(fi, FI_NEW_INODE);
365 366
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 89d0422a91a8..84191307a670 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -590,7 +590,10 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
590 f2fs_balance_fs(sbi); 590 f2fs_balance_fs(sbi);
591 591
592 f2fs_lock_op(sbi); 592 f2fs_lock_op(sbi);
593 /* protect xattr_ver */
594 down_write(&F2FS_I(inode)->i_sem);
593 err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage); 595 err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage);
596 up_write(&F2FS_I(inode)->i_sem);
594 f2fs_unlock_op(sbi); 597 f2fs_unlock_op(sbi);
595 598
596 return err; 599 return err;