diff options
Diffstat (limited to 'fs/f2fs/super.c')
-rw-r--r-- | fs/f2fs/super.c | 143 |
1 files changed, 101 insertions, 42 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 13d0a0fe49dd..bafff72de8e8 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -43,7 +43,9 @@ enum { | |||
43 | Opt_disable_roll_forward, | 43 | Opt_disable_roll_forward, |
44 | Opt_discard, | 44 | Opt_discard, |
45 | Opt_noheap, | 45 | Opt_noheap, |
46 | Opt_user_xattr, | ||
46 | Opt_nouser_xattr, | 47 | Opt_nouser_xattr, |
48 | Opt_acl, | ||
47 | Opt_noacl, | 49 | Opt_noacl, |
48 | Opt_active_logs, | 50 | Opt_active_logs, |
49 | Opt_disable_ext_identify, | 51 | Opt_disable_ext_identify, |
@@ -56,7 +58,9 @@ static match_table_t f2fs_tokens = { | |||
56 | {Opt_disable_roll_forward, "disable_roll_forward"}, | 58 | {Opt_disable_roll_forward, "disable_roll_forward"}, |
57 | {Opt_discard, "discard"}, | 59 | {Opt_discard, "discard"}, |
58 | {Opt_noheap, "no_heap"}, | 60 | {Opt_noheap, "no_heap"}, |
61 | {Opt_user_xattr, "user_xattr"}, | ||
59 | {Opt_nouser_xattr, "nouser_xattr"}, | 62 | {Opt_nouser_xattr, "nouser_xattr"}, |
63 | {Opt_acl, "acl"}, | ||
60 | {Opt_noacl, "noacl"}, | 64 | {Opt_noacl, "noacl"}, |
61 | {Opt_active_logs, "active_logs=%u"}, | 65 | {Opt_active_logs, "active_logs=%u"}, |
62 | {Opt_disable_ext_identify, "disable_ext_identify"}, | 66 | {Opt_disable_ext_identify, "disable_ext_identify"}, |
@@ -65,24 +69,40 @@ static match_table_t f2fs_tokens = { | |||
65 | }; | 69 | }; |
66 | 70 | ||
67 | /* Sysfs support for f2fs */ | 71 | /* Sysfs support for f2fs */ |
72 | enum { | ||
73 | GC_THREAD, /* struct f2fs_gc_thread */ | ||
74 | SM_INFO, /* struct f2fs_sm_info */ | ||
75 | }; | ||
76 | |||
68 | struct f2fs_attr { | 77 | struct f2fs_attr { |
69 | struct attribute attr; | 78 | struct attribute attr; |
70 | ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); | 79 | ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); |
71 | ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *, | 80 | ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *, |
72 | const char *, size_t); | 81 | const char *, size_t); |
82 | int struct_type; | ||
73 | int offset; | 83 | int offset; |
74 | }; | 84 | }; |
75 | 85 | ||
86 | static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | ||
87 | { | ||
88 | if (struct_type == GC_THREAD) | ||
89 | return (unsigned char *)sbi->gc_thread; | ||
90 | else if (struct_type == SM_INFO) | ||
91 | return (unsigned char *)SM_I(sbi); | ||
92 | return NULL; | ||
93 | } | ||
94 | |||
76 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, | 95 | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, |
77 | struct f2fs_sb_info *sbi, char *buf) | 96 | struct f2fs_sb_info *sbi, char *buf) |
78 | { | 97 | { |
79 | struct f2fs_gc_kthread *gc_kth = sbi->gc_thread; | 98 | unsigned char *ptr = NULL; |
80 | unsigned int *ui; | 99 | unsigned int *ui; |
81 | 100 | ||
82 | if (!gc_kth) | 101 | ptr = __struct_ptr(sbi, a->struct_type); |
102 | if (!ptr) | ||
83 | return -EINVAL; | 103 | return -EINVAL; |
84 | 104 | ||
85 | ui = (unsigned int *)(((char *)gc_kth) + a->offset); | 105 | ui = (unsigned int *)(ptr + a->offset); |
86 | 106 | ||
87 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | 107 | return snprintf(buf, PAGE_SIZE, "%u\n", *ui); |
88 | } | 108 | } |
@@ -91,15 +111,16 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, | |||
91 | struct f2fs_sb_info *sbi, | 111 | struct f2fs_sb_info *sbi, |
92 | const char *buf, size_t count) | 112 | const char *buf, size_t count) |
93 | { | 113 | { |
94 | struct f2fs_gc_kthread *gc_kth = sbi->gc_thread; | 114 | unsigned char *ptr; |
95 | unsigned long t; | 115 | unsigned long t; |
96 | unsigned int *ui; | 116 | unsigned int *ui; |
97 | ssize_t ret; | 117 | ssize_t ret; |
98 | 118 | ||
99 | if (!gc_kth) | 119 | ptr = __struct_ptr(sbi, a->struct_type); |
120 | if (!ptr) | ||
100 | return -EINVAL; | 121 | return -EINVAL; |
101 | 122 | ||
102 | ui = (unsigned int *)(((char *)gc_kth) + a->offset); | 123 | ui = (unsigned int *)(ptr + a->offset); |
103 | 124 | ||
104 | ret = kstrtoul(skip_spaces(buf), 0, &t); | 125 | ret = kstrtoul(skip_spaces(buf), 0, &t); |
105 | if (ret < 0) | 126 | if (ret < 0) |
@@ -135,21 +156,25 @@ static void f2fs_sb_release(struct kobject *kobj) | |||
135 | complete(&sbi->s_kobj_unregister); | 156 | complete(&sbi->s_kobj_unregister); |
136 | } | 157 | } |
137 | 158 | ||
138 | #define F2FS_ATTR_OFFSET(_name, _mode, _show, _store, _elname) \ | 159 | #define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ |
139 | static struct f2fs_attr f2fs_attr_##_name = { \ | 160 | static struct f2fs_attr f2fs_attr_##_name = { \ |
140 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | 161 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
141 | .show = _show, \ | 162 | .show = _show, \ |
142 | .store = _store, \ | 163 | .store = _store, \ |
143 | .offset = offsetof(struct f2fs_gc_kthread, _elname), \ | 164 | .struct_type = _struct_type, \ |
165 | .offset = _offset \ | ||
144 | } | 166 | } |
145 | 167 | ||
146 | #define F2FS_RW_ATTR(name, elname) \ | 168 | #define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \ |
147 | F2FS_ATTR_OFFSET(name, 0644, f2fs_sbi_show, f2fs_sbi_store, elname) | 169 | F2FS_ATTR_OFFSET(struct_type, name, 0644, \ |
170 | f2fs_sbi_show, f2fs_sbi_store, \ | ||
171 | offsetof(struct struct_name, elname)) | ||
148 | 172 | ||
149 | F2FS_RW_ATTR(gc_min_sleep_time, min_sleep_time); | 173 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); |
150 | F2FS_RW_ATTR(gc_max_sleep_time, max_sleep_time); | 174 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); |
151 | F2FS_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time); | 175 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); |
152 | F2FS_RW_ATTR(gc_idle, gc_idle); | 176 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); |
177 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); | ||
153 | 178 | ||
154 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) | 179 | #define ATTR_LIST(name) (&f2fs_attr_##name.attr) |
155 | static struct attribute *f2fs_attrs[] = { | 180 | static struct attribute *f2fs_attrs[] = { |
@@ -157,6 +182,7 @@ static struct attribute *f2fs_attrs[] = { | |||
157 | ATTR_LIST(gc_max_sleep_time), | 182 | ATTR_LIST(gc_max_sleep_time), |
158 | ATTR_LIST(gc_no_gc_sleep_time), | 183 | ATTR_LIST(gc_no_gc_sleep_time), |
159 | ATTR_LIST(gc_idle), | 184 | ATTR_LIST(gc_idle), |
185 | ATTR_LIST(reclaim_segments), | ||
160 | NULL, | 186 | NULL, |
161 | }; | 187 | }; |
162 | 188 | ||
@@ -237,6 +263,9 @@ static int parse_options(struct super_block *sb, char *options) | |||
237 | set_opt(sbi, NOHEAP); | 263 | set_opt(sbi, NOHEAP); |
238 | break; | 264 | break; |
239 | #ifdef CONFIG_F2FS_FS_XATTR | 265 | #ifdef CONFIG_F2FS_FS_XATTR |
266 | case Opt_user_xattr: | ||
267 | set_opt(sbi, XATTR_USER); | ||
268 | break; | ||
240 | case Opt_nouser_xattr: | 269 | case Opt_nouser_xattr: |
241 | clear_opt(sbi, XATTR_USER); | 270 | clear_opt(sbi, XATTR_USER); |
242 | break; | 271 | break; |
@@ -244,6 +273,10 @@ static int parse_options(struct super_block *sb, char *options) | |||
244 | set_opt(sbi, INLINE_XATTR); | 273 | set_opt(sbi, INLINE_XATTR); |
245 | break; | 274 | break; |
246 | #else | 275 | #else |
276 | case Opt_user_xattr: | ||
277 | f2fs_msg(sb, KERN_INFO, | ||
278 | "user_xattr options not supported"); | ||
279 | break; | ||
247 | case Opt_nouser_xattr: | 280 | case Opt_nouser_xattr: |
248 | f2fs_msg(sb, KERN_INFO, | 281 | f2fs_msg(sb, KERN_INFO, |
249 | "nouser_xattr options not supported"); | 282 | "nouser_xattr options not supported"); |
@@ -254,10 +287,16 @@ static int parse_options(struct super_block *sb, char *options) | |||
254 | break; | 287 | break; |
255 | #endif | 288 | #endif |
256 | #ifdef CONFIG_F2FS_FS_POSIX_ACL | 289 | #ifdef CONFIG_F2FS_FS_POSIX_ACL |
290 | case Opt_acl: | ||
291 | set_opt(sbi, POSIX_ACL); | ||
292 | break; | ||
257 | case Opt_noacl: | 293 | case Opt_noacl: |
258 | clear_opt(sbi, POSIX_ACL); | 294 | clear_opt(sbi, POSIX_ACL); |
259 | break; | 295 | break; |
260 | #else | 296 | #else |
297 | case Opt_acl: | ||
298 | f2fs_msg(sb, KERN_INFO, "acl options not supported"); | ||
299 | break; | ||
261 | case Opt_noacl: | 300 | case Opt_noacl: |
262 | f2fs_msg(sb, KERN_INFO, "noacl options not supported"); | 301 | f2fs_msg(sb, KERN_INFO, "noacl options not supported"); |
263 | break; | 302 | break; |
@@ -355,7 +394,9 @@ static void f2fs_put_super(struct super_block *sb) | |||
355 | f2fs_destroy_stats(sbi); | 394 | f2fs_destroy_stats(sbi); |
356 | stop_gc_thread(sbi); | 395 | stop_gc_thread(sbi); |
357 | 396 | ||
358 | write_checkpoint(sbi, true); | 397 | /* We don't need to do checkpoint when it's clean */ |
398 | if (sbi->s_dirty && get_pages(sbi, F2FS_DIRTY_NODES)) | ||
399 | write_checkpoint(sbi, true); | ||
359 | 400 | ||
360 | iput(sbi->node_inode); | 401 | iput(sbi->node_inode); |
361 | iput(sbi->meta_inode); | 402 | iput(sbi->meta_inode); |
@@ -727,30 +768,47 @@ static void init_sb_info(struct f2fs_sb_info *sbi) | |||
727 | atomic_set(&sbi->nr_pages[i], 0); | 768 | atomic_set(&sbi->nr_pages[i], 0); |
728 | } | 769 | } |
729 | 770 | ||
730 | static int validate_superblock(struct super_block *sb, | 771 | /* |
731 | struct f2fs_super_block **raw_super, | 772 | * Read f2fs raw super block. |
732 | struct buffer_head **raw_super_buf, sector_t block) | 773 | * Because we have two copies of super block, so read the first one at first, |
774 | * if the first one is invalid, move to read the second one. | ||
775 | */ | ||
776 | static int read_raw_super_block(struct super_block *sb, | ||
777 | struct f2fs_super_block **raw_super, | ||
778 | struct buffer_head **raw_super_buf) | ||
733 | { | 779 | { |
734 | const char *super = (block == 0 ? "first" : "second"); | 780 | int block = 0; |
735 | 781 | ||
736 | /* read f2fs raw super block */ | 782 | retry: |
737 | *raw_super_buf = sb_bread(sb, block); | 783 | *raw_super_buf = sb_bread(sb, block); |
738 | if (!*raw_super_buf) { | 784 | if (!*raw_super_buf) { |
739 | f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", | 785 | f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", |
740 | super); | 786 | block + 1); |
741 | return -EIO; | 787 | if (block == 0) { |
788 | block++; | ||
789 | goto retry; | ||
790 | } else { | ||
791 | return -EIO; | ||
792 | } | ||
742 | } | 793 | } |
743 | 794 | ||
744 | *raw_super = (struct f2fs_super_block *) | 795 | *raw_super = (struct f2fs_super_block *) |
745 | ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); | 796 | ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); |
746 | 797 | ||
747 | /* sanity checking of raw super */ | 798 | /* sanity checking of raw super */ |
748 | if (!sanity_check_raw_super(sb, *raw_super)) | 799 | if (sanity_check_raw_super(sb, *raw_super)) { |
749 | return 0; | 800 | brelse(*raw_super_buf); |
801 | f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " | ||
802 | "in %dth superblock", block + 1); | ||
803 | if(block == 0) { | ||
804 | block++; | ||
805 | goto retry; | ||
806 | } else { | ||
807 | return -EINVAL; | ||
808 | } | ||
809 | } | ||
750 | 810 | ||
751 | f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " | 811 | return 0; |
752 | "in %s superblock", super); | ||
753 | return -EINVAL; | ||
754 | } | 812 | } |
755 | 813 | ||
756 | static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | 814 | static int f2fs_fill_super(struct super_block *sb, void *data, int silent) |
@@ -760,7 +818,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
760 | struct buffer_head *raw_super_buf; | 818 | struct buffer_head *raw_super_buf; |
761 | struct inode *root; | 819 | struct inode *root; |
762 | long err = -EINVAL; | 820 | long err = -EINVAL; |
763 | int i; | ||
764 | 821 | ||
765 | /* allocate memory for f2fs-specific super block info */ | 822 | /* allocate memory for f2fs-specific super block info */ |
766 | sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); | 823 | sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); |
@@ -773,14 +830,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
773 | goto free_sbi; | 830 | goto free_sbi; |
774 | } | 831 | } |
775 | 832 | ||
776 | err = validate_superblock(sb, &raw_super, &raw_super_buf, 0); | 833 | err = read_raw_super_block(sb, &raw_super, &raw_super_buf); |
777 | if (err) { | 834 | if (err) |
778 | brelse(raw_super_buf); | 835 | goto free_sbi; |
779 | /* check secondary superblock when primary failed */ | 836 | |
780 | err = validate_superblock(sb, &raw_super, &raw_super_buf, 1); | ||
781 | if (err) | ||
782 | goto free_sb_buf; | ||
783 | } | ||
784 | sb->s_fs_info = sbi; | 837 | sb->s_fs_info = sbi; |
785 | /* init some FS parameters */ | 838 | /* init some FS parameters */ |
786 | sbi->active_logs = NR_CURSEG_TYPE; | 839 | sbi->active_logs = NR_CURSEG_TYPE; |
@@ -818,12 +871,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
818 | mutex_init(&sbi->gc_mutex); | 871 | mutex_init(&sbi->gc_mutex); |
819 | mutex_init(&sbi->writepages); | 872 | mutex_init(&sbi->writepages); |
820 | mutex_init(&sbi->cp_mutex); | 873 | mutex_init(&sbi->cp_mutex); |
821 | for (i = 0; i < NR_GLOBAL_LOCKS; i++) | ||
822 | mutex_init(&sbi->fs_lock[i]); | ||
823 | mutex_init(&sbi->node_write); | 874 | mutex_init(&sbi->node_write); |
824 | sbi->por_doing = 0; | 875 | sbi->por_doing = false; |
825 | spin_lock_init(&sbi->stat_lock); | 876 | spin_lock_init(&sbi->stat_lock); |
826 | init_rwsem(&sbi->bio_sem); | 877 | init_rwsem(&sbi->bio_sem); |
878 | init_rwsem(&sbi->cp_rwsem); | ||
879 | init_waitqueue_head(&sbi->cp_wait); | ||
827 | init_sb_info(sbi); | 880 | init_sb_info(sbi); |
828 | 881 | ||
829 | /* get an inode for meta space */ | 882 | /* get an inode for meta space */ |
@@ -922,12 +975,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
922 | /* After POR, we can run background GC thread.*/ | 975 | /* After POR, we can run background GC thread.*/ |
923 | err = start_gc_thread(sbi); | 976 | err = start_gc_thread(sbi); |
924 | if (err) | 977 | if (err) |
925 | goto fail; | 978 | goto free_gc; |
926 | } | 979 | } |
927 | 980 | ||
928 | err = f2fs_build_stats(sbi); | 981 | err = f2fs_build_stats(sbi); |
929 | if (err) | 982 | if (err) |
930 | goto fail; | 983 | goto free_gc; |
931 | 984 | ||
932 | if (f2fs_proc_root) | 985 | if (f2fs_proc_root) |
933 | sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); | 986 | sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); |
@@ -953,6 +1006,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
953 | 1006 | ||
954 | return 0; | 1007 | return 0; |
955 | fail: | 1008 | fail: |
1009 | if (sbi->s_proc) { | ||
1010 | remove_proc_entry("segment_info", sbi->s_proc); | ||
1011 | remove_proc_entry(sb->s_id, f2fs_proc_root); | ||
1012 | } | ||
1013 | f2fs_destroy_stats(sbi); | ||
1014 | free_gc: | ||
956 | stop_gc_thread(sbi); | 1015 | stop_gc_thread(sbi); |
957 | free_root_inode: | 1016 | free_root_inode: |
958 | dput(sb->s_root); | 1017 | dput(sb->s_root); |