diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-08 18:11:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-08 18:11:48 -0400 |
commit | 942d33da999b86821c9aee9615fcb81207ee04c7 (patch) | |
tree | db14ab92982f936c0a2ea2202f5e301310f33bdd /fs/f2fs/super.c | |
parent | 246e6a0d781091c4657890ffa497c2576bd99095 (diff) | |
parent | 59bbd474abb9dd6a0c1a74df758ec29c7a8b150f (diff) |
Merge tag 'f2fs-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"This patch-set includes the following major enhancement patches.
- introduce a new gloabl lock scheme
- add tracepoints on several major functions
- fix the overall cleaning process focused on victim selection
- apply the block plugging to merge IOs as much as possible
- enhance management of free nids and its list
- enhance the readahead mode for node pages
- address several cretical deadlock conditions
- reduce lock_page calls
The other minor bug fixes and enhancements are as follows.
- calculation mistakes: overflow
- bio types: READ, READA, and READ_SYNC
- fix the recovery flow, data races, and null pointer errors"
* tag 'f2fs-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (68 commits)
f2fs: cover free_nid management with spin_lock
f2fs: optimize scan_nat_page()
f2fs: code cleanup for scan_nat_page() and build_free_nids()
f2fs: bugfix for alloc_nid_failed()
f2fs: recover when journal contains deleted files
f2fs: continue to mount after failing recovery
f2fs: avoid deadlock during evict after f2fs_gc
f2fs: modify the number of issued pages to merge IOs
f2fs: remove useless #include <linux/proc_fs.h> as we're now using sysfs as debug entry.
f2fs: fix inconsistent using of NM_WOUT_THRESHOLD
f2fs: check truncation of mapping after lock_page
f2fs: enhance alloc_nid and build_free_nids flows
f2fs: add a tracepoint on f2fs_new_inode
f2fs: check nid == 0 in add_free_nid
f2fs: add REQ_META about metadata requests for submit
f2fs: give a chance to merge IOs by IO scheduler
f2fs: avoid frequent background GC
f2fs: add tracepoints to debug checkpoint request
f2fs: add tracepoints for write page operations
f2fs: add tracepoints to debug the block allocation
...
Diffstat (limited to 'fs/f2fs/super.c')
-rw-r--r-- | fs/f2fs/super.c | 67 |
1 files changed, 54 insertions, 13 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 62e017743af6..8555f7df82c7 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/statfs.h> | 14 | #include <linux/statfs.h> |
15 | #include <linux/proc_fs.h> | ||
16 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
17 | #include <linux/backing-dev.h> | 16 | #include <linux/backing-dev.h> |
18 | #include <linux/kthread.h> | 17 | #include <linux/kthread.h> |
@@ -21,12 +20,17 @@ | |||
21 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
22 | #include <linux/random.h> | 21 | #include <linux/random.h> |
23 | #include <linux/exportfs.h> | 22 | #include <linux/exportfs.h> |
23 | #include <linux/blkdev.h> | ||
24 | #include <linux/f2fs_fs.h> | 24 | #include <linux/f2fs_fs.h> |
25 | 25 | ||
26 | #include "f2fs.h" | 26 | #include "f2fs.h" |
27 | #include "node.h" | 27 | #include "node.h" |
28 | #include "segment.h" | ||
28 | #include "xattr.h" | 29 | #include "xattr.h" |
29 | 30 | ||
31 | #define CREATE_TRACE_POINTS | ||
32 | #include <trace/events/f2fs.h> | ||
33 | |||
30 | static struct kmem_cache *f2fs_inode_cachep; | 34 | static struct kmem_cache *f2fs_inode_cachep; |
31 | 35 | ||
32 | enum { | 36 | enum { |
@@ -94,6 +98,20 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) | |||
94 | return &fi->vfs_inode; | 98 | return &fi->vfs_inode; |
95 | } | 99 | } |
96 | 100 | ||
101 | static int f2fs_drop_inode(struct inode *inode) | ||
102 | { | ||
103 | /* | ||
104 | * This is to avoid a deadlock condition like below. | ||
105 | * writeback_single_inode(inode) | ||
106 | * - f2fs_write_data_page | ||
107 | * - f2fs_gc -> iput -> evict | ||
108 | * - inode_wait_for_writeback(inode) | ||
109 | */ | ||
110 | if (!inode_unhashed(inode) && inode->i_state & I_SYNC) | ||
111 | return 0; | ||
112 | return generic_drop_inode(inode); | ||
113 | } | ||
114 | |||
97 | static void f2fs_i_callback(struct rcu_head *head) | 115 | static void f2fs_i_callback(struct rcu_head *head) |
98 | { | 116 | { |
99 | struct inode *inode = container_of(head, struct inode, i_rcu); | 117 | struct inode *inode = container_of(head, struct inode, i_rcu); |
@@ -132,13 +150,18 @@ int f2fs_sync_fs(struct super_block *sb, int sync) | |||
132 | { | 150 | { |
133 | struct f2fs_sb_info *sbi = F2FS_SB(sb); | 151 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
134 | 152 | ||
153 | trace_f2fs_sync_fs(sb, sync); | ||
154 | |||
135 | if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) | 155 | if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) |
136 | return 0; | 156 | return 0; |
137 | 157 | ||
138 | if (sync) | 158 | if (sync) { |
159 | mutex_lock(&sbi->gc_mutex); | ||
139 | write_checkpoint(sbi, false); | 160 | write_checkpoint(sbi, false); |
140 | else | 161 | mutex_unlock(&sbi->gc_mutex); |
162 | } else { | ||
141 | f2fs_balance_fs(sbi); | 163 | f2fs_balance_fs(sbi); |
164 | } | ||
142 | 165 | ||
143 | return 0; | 166 | return 0; |
144 | } | 167 | } |
@@ -180,7 +203,7 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
180 | buf->f_files = sbi->total_node_count; | 203 | buf->f_files = sbi->total_node_count; |
181 | buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi); | 204 | buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi); |
182 | 205 | ||
183 | buf->f_namelen = F2FS_MAX_NAME_LEN; | 206 | buf->f_namelen = F2FS_NAME_LEN; |
184 | buf->f_fsid.val[0] = (u32)id; | 207 | buf->f_fsid.val[0] = (u32)id; |
185 | buf->f_fsid.val[1] = (u32)(id >> 32); | 208 | buf->f_fsid.val[1] = (u32)(id >> 32); |
186 | 209 | ||
@@ -223,6 +246,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) | |||
223 | 246 | ||
224 | static struct super_operations f2fs_sops = { | 247 | static struct super_operations f2fs_sops = { |
225 | .alloc_inode = f2fs_alloc_inode, | 248 | .alloc_inode = f2fs_alloc_inode, |
249 | .drop_inode = f2fs_drop_inode, | ||
226 | .destroy_inode = f2fs_destroy_inode, | 250 | .destroy_inode = f2fs_destroy_inode, |
227 | .write_inode = f2fs_write_inode, | 251 | .write_inode = f2fs_write_inode, |
228 | .show_options = f2fs_show_options, | 252 | .show_options = f2fs_show_options, |
@@ -457,6 +481,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) | |||
457 | sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); | 481 | sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); |
458 | sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); | 482 | sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); |
459 | sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); | 483 | sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); |
484 | sbi->cur_victim_sec = NULL_SECNO; | ||
460 | 485 | ||
461 | for (i = 0; i < NR_COUNT_TYPE; i++) | 486 | for (i = 0; i < NR_COUNT_TYPE; i++) |
462 | atomic_set(&sbi->nr_pages[i], 0); | 487 | atomic_set(&sbi->nr_pages[i], 0); |
@@ -473,7 +498,7 @@ static int validate_superblock(struct super_block *sb, | |||
473 | if (!*raw_super_buf) { | 498 | if (!*raw_super_buf) { |
474 | f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", | 499 | f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", |
475 | super); | 500 | super); |
476 | return 1; | 501 | return -EIO; |
477 | } | 502 | } |
478 | 503 | ||
479 | *raw_super = (struct f2fs_super_block *) | 504 | *raw_super = (struct f2fs_super_block *) |
@@ -485,7 +510,7 @@ static int validate_superblock(struct super_block *sb, | |||
485 | 510 | ||
486 | f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " | 511 | f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " |
487 | "in %s superblock", super); | 512 | "in %s superblock", super); |
488 | return 1; | 513 | return -EINVAL; |
489 | } | 514 | } |
490 | 515 | ||
491 | static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | 516 | static int f2fs_fill_super(struct super_block *sb, void *data, int silent) |
@@ -508,9 +533,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
508 | goto free_sbi; | 533 | goto free_sbi; |
509 | } | 534 | } |
510 | 535 | ||
511 | if (validate_superblock(sb, &raw_super, &raw_super_buf, 0)) { | 536 | err = validate_superblock(sb, &raw_super, &raw_super_buf, 0); |
537 | if (err) { | ||
512 | brelse(raw_super_buf); | 538 | brelse(raw_super_buf); |
513 | if (validate_superblock(sb, &raw_super, &raw_super_buf, 1)) | 539 | /* check secondary superblock when primary failed */ |
540 | err = validate_superblock(sb, &raw_super, &raw_super_buf, 1); | ||
541 | if (err) | ||
514 | goto free_sb_buf; | 542 | goto free_sb_buf; |
515 | } | 543 | } |
516 | /* init some FS parameters */ | 544 | /* init some FS parameters */ |
@@ -525,7 +553,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
525 | set_opt(sbi, POSIX_ACL); | 553 | set_opt(sbi, POSIX_ACL); |
526 | #endif | 554 | #endif |
527 | /* parse mount options */ | 555 | /* parse mount options */ |
528 | if (parse_options(sb, sbi, (char *)data)) | 556 | err = parse_options(sb, sbi, (char *)data); |
557 | if (err) | ||
529 | goto free_sb_buf; | 558 | goto free_sb_buf; |
530 | 559 | ||
531 | sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); | 560 | sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); |
@@ -547,11 +576,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
547 | sbi->raw_super = raw_super; | 576 | sbi->raw_super = raw_super; |
548 | sbi->raw_super_buf = raw_super_buf; | 577 | sbi->raw_super_buf = raw_super_buf; |
549 | mutex_init(&sbi->gc_mutex); | 578 | mutex_init(&sbi->gc_mutex); |
550 | mutex_init(&sbi->write_inode); | ||
551 | mutex_init(&sbi->writepages); | 579 | mutex_init(&sbi->writepages); |
552 | mutex_init(&sbi->cp_mutex); | 580 | mutex_init(&sbi->cp_mutex); |
553 | for (i = 0; i < NR_LOCK_TYPE; i++) | 581 | for (i = 0; i < NR_GLOBAL_LOCKS; i++) |
554 | mutex_init(&sbi->fs_lock[i]); | 582 | mutex_init(&sbi->fs_lock[i]); |
583 | mutex_init(&sbi->node_write); | ||
555 | sbi->por_doing = 0; | 584 | sbi->por_doing = 0; |
556 | spin_lock_init(&sbi->stat_lock); | 585 | spin_lock_init(&sbi->stat_lock); |
557 | init_rwsem(&sbi->bio_sem); | 586 | init_rwsem(&sbi->bio_sem); |
@@ -638,8 +667,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
638 | } | 667 | } |
639 | 668 | ||
640 | /* recover fsynced data */ | 669 | /* recover fsynced data */ |
641 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) | 670 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { |
642 | recover_fsync_data(sbi); | 671 | err = recover_fsync_data(sbi); |
672 | if (err) | ||
673 | f2fs_msg(sb, KERN_ERR, | ||
674 | "Cannot recover all fsync data errno=%ld", err); | ||
675 | } | ||
643 | 676 | ||
644 | /* After POR, we can run background GC thread */ | 677 | /* After POR, we can run background GC thread */ |
645 | err = start_gc_thread(sbi); | 678 | err = start_gc_thread(sbi); |
@@ -650,6 +683,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
650 | if (err) | 683 | if (err) |
651 | goto fail; | 684 | goto fail; |
652 | 685 | ||
686 | if (test_opt(sbi, DISCARD)) { | ||
687 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | ||
688 | if (!blk_queue_discard(q)) | ||
689 | f2fs_msg(sb, KERN_WARNING, | ||
690 | "mounting with \"discard\" option, but " | ||
691 | "the device does not support discard"); | ||
692 | } | ||
693 | |||
653 | return 0; | 694 | return 0; |
654 | fail: | 695 | fail: |
655 | stop_gc_thread(sbi); | 696 | stop_gc_thread(sbi); |