diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-03-20 06:10:08 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-03-20 09:10:11 -0400 |
commit | d928bfbfe77aa457b765c19e9db8cd4cc72b3c89 (patch) | |
tree | f56763175e0fbee1e2079c9a330f3d73f971bc5c /fs | |
parent | 58c410351eba3d24f741c85a0eb9eaf15c94047d (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.c | 6 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 1 | ||||
-rw-r--r-- | fs/f2fs/file.c | 14 | ||||
-rw-r--r-- | fs/f2fs/namei.c | 7 | ||||
-rw-r--r-- | fs/f2fs/super.c | 1 | ||||
-rw-r--r-- | fs/f2fs/xattr.c | 3 |
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: | |||
493 | add_dentry: | 493 | add_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); |
517 | fail: | 518 | fail: |
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) | |||
111 | int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | 111 | int 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 | } |
182 | out: | 189 | out: |
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; |