diff options
Diffstat (limited to 'fs/f2fs/super.c')
-rw-r--r-- | fs/f2fs/super.c | 253 |
1 files changed, 168 insertions, 85 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 8555f7df82c7..75c7dc363e92 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -34,7 +34,7 @@ | |||
34 | static struct kmem_cache *f2fs_inode_cachep; | 34 | static struct kmem_cache *f2fs_inode_cachep; |
35 | 35 | ||
36 | enum { | 36 | enum { |
37 | Opt_gc_background_off, | 37 | Opt_gc_background, |
38 | Opt_disable_roll_forward, | 38 | Opt_disable_roll_forward, |
39 | Opt_discard, | 39 | Opt_discard, |
40 | Opt_noheap, | 40 | Opt_noheap, |
@@ -46,7 +46,7 @@ enum { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | static match_table_t f2fs_tokens = { | 48 | static match_table_t f2fs_tokens = { |
49 | {Opt_gc_background_off, "background_gc_off"}, | 49 | {Opt_gc_background, "background_gc=%s"}, |
50 | {Opt_disable_roll_forward, "disable_roll_forward"}, | 50 | {Opt_disable_roll_forward, "disable_roll_forward"}, |
51 | {Opt_discard, "discard"}, | 51 | {Opt_discard, "discard"}, |
52 | {Opt_noheap, "no_heap"}, | 52 | {Opt_noheap, "no_heap"}, |
@@ -76,6 +76,91 @@ static void init_once(void *foo) | |||
76 | inode_init_once(&fi->vfs_inode); | 76 | inode_init_once(&fi->vfs_inode); |
77 | } | 77 | } |
78 | 78 | ||
79 | static int parse_options(struct super_block *sb, char *options) | ||
80 | { | ||
81 | struct f2fs_sb_info *sbi = F2FS_SB(sb); | ||
82 | substring_t args[MAX_OPT_ARGS]; | ||
83 | char *p, *name; | ||
84 | int arg = 0; | ||
85 | |||
86 | if (!options) | ||
87 | return 0; | ||
88 | |||
89 | while ((p = strsep(&options, ",")) != NULL) { | ||
90 | int token; | ||
91 | if (!*p) | ||
92 | continue; | ||
93 | /* | ||
94 | * Initialize args struct so we know whether arg was | ||
95 | * found; some options take optional arguments. | ||
96 | */ | ||
97 | args[0].to = args[0].from = NULL; | ||
98 | token = match_token(p, f2fs_tokens, args); | ||
99 | |||
100 | switch (token) { | ||
101 | case Opt_gc_background: | ||
102 | name = match_strdup(&args[0]); | ||
103 | |||
104 | if (!name) | ||
105 | return -ENOMEM; | ||
106 | if (!strncmp(name, "on", 2)) | ||
107 | set_opt(sbi, BG_GC); | ||
108 | else if (!strncmp(name, "off", 3)) | ||
109 | clear_opt(sbi, BG_GC); | ||
110 | else { | ||
111 | kfree(name); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | kfree(name); | ||
115 | break; | ||
116 | case Opt_disable_roll_forward: | ||
117 | set_opt(sbi, DISABLE_ROLL_FORWARD); | ||
118 | break; | ||
119 | case Opt_discard: | ||
120 | set_opt(sbi, DISCARD); | ||
121 | break; | ||
122 | case Opt_noheap: | ||
123 | set_opt(sbi, NOHEAP); | ||
124 | break; | ||
125 | #ifdef CONFIG_F2FS_FS_XATTR | ||
126 | case Opt_nouser_xattr: | ||
127 | clear_opt(sbi, XATTR_USER); | ||
128 | break; | ||
129 | #else | ||
130 | case Opt_nouser_xattr: | ||
131 | f2fs_msg(sb, KERN_INFO, | ||
132 | "nouser_xattr options not supported"); | ||
133 | break; | ||
134 | #endif | ||
135 | #ifdef CONFIG_F2FS_FS_POSIX_ACL | ||
136 | case Opt_noacl: | ||
137 | clear_opt(sbi, POSIX_ACL); | ||
138 | break; | ||
139 | #else | ||
140 | case Opt_noacl: | ||
141 | f2fs_msg(sb, KERN_INFO, "noacl options not supported"); | ||
142 | break; | ||
143 | #endif | ||
144 | case Opt_active_logs: | ||
145 | if (args->from && match_int(args, &arg)) | ||
146 | return -EINVAL; | ||
147 | if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) | ||
148 | return -EINVAL; | ||
149 | sbi->active_logs = arg; | ||
150 | break; | ||
151 | case Opt_disable_ext_identify: | ||
152 | set_opt(sbi, DISABLE_EXT_IDENTIFY); | ||
153 | break; | ||
154 | default: | ||
155 | f2fs_msg(sb, KERN_ERR, | ||
156 | "Unrecognized mount option \"%s\" or missing value", | ||
157 | p); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
79 | static struct inode *f2fs_alloc_inode(struct super_block *sb) | 164 | static struct inode *f2fs_alloc_inode(struct super_block *sb) |
80 | { | 165 | { |
81 | struct f2fs_inode_info *fi; | 166 | struct f2fs_inode_info *fi; |
@@ -112,6 +197,17 @@ static int f2fs_drop_inode(struct inode *inode) | |||
112 | return generic_drop_inode(inode); | 197 | return generic_drop_inode(inode); |
113 | } | 198 | } |
114 | 199 | ||
200 | /* | ||
201 | * f2fs_dirty_inode() is called from __mark_inode_dirty() | ||
202 | * | ||
203 | * We should call set_dirty_inode to write the dirty inode through write_inode. | ||
204 | */ | ||
205 | static void f2fs_dirty_inode(struct inode *inode, int flags) | ||
206 | { | ||
207 | set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); | ||
208 | return; | ||
209 | } | ||
210 | |||
115 | static void f2fs_i_callback(struct rcu_head *head) | 211 | static void f2fs_i_callback(struct rcu_head *head) |
116 | { | 212 | { |
117 | struct inode *inode = container_of(head, struct inode, i_rcu); | 213 | struct inode *inode = container_of(head, struct inode, i_rcu); |
@@ -170,7 +266,7 @@ static int f2fs_freeze(struct super_block *sb) | |||
170 | { | 266 | { |
171 | int err; | 267 | int err; |
172 | 268 | ||
173 | if (sb->s_flags & MS_RDONLY) | 269 | if (f2fs_readonly(sb)) |
174 | return 0; | 270 | return 0; |
175 | 271 | ||
176 | err = f2fs_sync_fs(sb, 1); | 272 | err = f2fs_sync_fs(sb, 1); |
@@ -214,10 +310,10 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) | |||
214 | { | 310 | { |
215 | struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); | 311 | struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); |
216 | 312 | ||
217 | if (test_opt(sbi, BG_GC)) | 313 | if (!(root->d_sb->s_flags & MS_RDONLY) && test_opt(sbi, BG_GC)) |
218 | seq_puts(seq, ",background_gc_on"); | 314 | seq_printf(seq, ",background_gc=%s", "on"); |
219 | else | 315 | else |
220 | seq_puts(seq, ",background_gc_off"); | 316 | seq_printf(seq, ",background_gc=%s", "off"); |
221 | if (test_opt(sbi, DISABLE_ROLL_FORWARD)) | 317 | if (test_opt(sbi, DISABLE_ROLL_FORWARD)) |
222 | seq_puts(seq, ",disable_roll_forward"); | 318 | seq_puts(seq, ",disable_roll_forward"); |
223 | if (test_opt(sbi, DISCARD)) | 319 | if (test_opt(sbi, DISCARD)) |
@@ -244,11 +340,64 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) | |||
244 | return 0; | 340 | return 0; |
245 | } | 341 | } |
246 | 342 | ||
343 | static int f2fs_remount(struct super_block *sb, int *flags, char *data) | ||
344 | { | ||
345 | struct f2fs_sb_info *sbi = F2FS_SB(sb); | ||
346 | struct f2fs_mount_info org_mount_opt; | ||
347 | int err, active_logs; | ||
348 | |||
349 | /* | ||
350 | * Save the old mount options in case we | ||
351 | * need to restore them. | ||
352 | */ | ||
353 | org_mount_opt = sbi->mount_opt; | ||
354 | active_logs = sbi->active_logs; | ||
355 | |||
356 | /* parse mount options */ | ||
357 | err = parse_options(sb, data); | ||
358 | if (err) | ||
359 | goto restore_opts; | ||
360 | |||
361 | /* | ||
362 | * Previous and new state of filesystem is RO, | ||
363 | * so no point in checking GC conditions. | ||
364 | */ | ||
365 | if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) | ||
366 | goto skip; | ||
367 | |||
368 | /* | ||
369 | * We stop the GC thread if FS is mounted as RO | ||
370 | * or if background_gc = off is passed in mount | ||
371 | * option. Also sync the filesystem. | ||
372 | */ | ||
373 | if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) { | ||
374 | if (sbi->gc_thread) { | ||
375 | stop_gc_thread(sbi); | ||
376 | f2fs_sync_fs(sb, 1); | ||
377 | } | ||
378 | } else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) { | ||
379 | err = start_gc_thread(sbi); | ||
380 | if (err) | ||
381 | goto restore_opts; | ||
382 | } | ||
383 | skip: | ||
384 | /* Update the POSIXACL Flag */ | ||
385 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | | ||
386 | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); | ||
387 | return 0; | ||
388 | |||
389 | restore_opts: | ||
390 | sbi->mount_opt = org_mount_opt; | ||
391 | sbi->active_logs = active_logs; | ||
392 | return err; | ||
393 | } | ||
394 | |||
247 | static struct super_operations f2fs_sops = { | 395 | static struct super_operations f2fs_sops = { |
248 | .alloc_inode = f2fs_alloc_inode, | 396 | .alloc_inode = f2fs_alloc_inode, |
249 | .drop_inode = f2fs_drop_inode, | 397 | .drop_inode = f2fs_drop_inode, |
250 | .destroy_inode = f2fs_destroy_inode, | 398 | .destroy_inode = f2fs_destroy_inode, |
251 | .write_inode = f2fs_write_inode, | 399 | .write_inode = f2fs_write_inode, |
400 | .dirty_inode = f2fs_dirty_inode, | ||
252 | .show_options = f2fs_show_options, | 401 | .show_options = f2fs_show_options, |
253 | .evict_inode = f2fs_evict_inode, | 402 | .evict_inode = f2fs_evict_inode, |
254 | .put_super = f2fs_put_super, | 403 | .put_super = f2fs_put_super, |
@@ -256,6 +405,7 @@ static struct super_operations f2fs_sops = { | |||
256 | .freeze_fs = f2fs_freeze, | 405 | .freeze_fs = f2fs_freeze, |
257 | .unfreeze_fs = f2fs_unfreeze, | 406 | .unfreeze_fs = f2fs_unfreeze, |
258 | .statfs = f2fs_statfs, | 407 | .statfs = f2fs_statfs, |
408 | .remount_fs = f2fs_remount, | ||
259 | }; | 409 | }; |
260 | 410 | ||
261 | static struct inode *f2fs_nfs_get_inode(struct super_block *sb, | 411 | static struct inode *f2fs_nfs_get_inode(struct super_block *sb, |
@@ -303,79 +453,6 @@ static const struct export_operations f2fs_export_ops = { | |||
303 | .get_parent = f2fs_get_parent, | 453 | .get_parent = f2fs_get_parent, |
304 | }; | 454 | }; |
305 | 455 | ||
306 | static int parse_options(struct super_block *sb, struct f2fs_sb_info *sbi, | ||
307 | char *options) | ||
308 | { | ||
309 | substring_t args[MAX_OPT_ARGS]; | ||
310 | char *p; | ||
311 | int arg = 0; | ||
312 | |||
313 | if (!options) | ||
314 | return 0; | ||
315 | |||
316 | while ((p = strsep(&options, ",")) != NULL) { | ||
317 | int token; | ||
318 | if (!*p) | ||
319 | continue; | ||
320 | /* | ||
321 | * Initialize args struct so we know whether arg was | ||
322 | * found; some options take optional arguments. | ||
323 | */ | ||
324 | args[0].to = args[0].from = NULL; | ||
325 | token = match_token(p, f2fs_tokens, args); | ||
326 | |||
327 | switch (token) { | ||
328 | case Opt_gc_background_off: | ||
329 | clear_opt(sbi, BG_GC); | ||
330 | break; | ||
331 | case Opt_disable_roll_forward: | ||
332 | set_opt(sbi, DISABLE_ROLL_FORWARD); | ||
333 | break; | ||
334 | case Opt_discard: | ||
335 | set_opt(sbi, DISCARD); | ||
336 | break; | ||
337 | case Opt_noheap: | ||
338 | set_opt(sbi, NOHEAP); | ||
339 | break; | ||
340 | #ifdef CONFIG_F2FS_FS_XATTR | ||
341 | case Opt_nouser_xattr: | ||
342 | clear_opt(sbi, XATTR_USER); | ||
343 | break; | ||
344 | #else | ||
345 | case Opt_nouser_xattr: | ||
346 | f2fs_msg(sb, KERN_INFO, | ||
347 | "nouser_xattr options not supported"); | ||
348 | break; | ||
349 | #endif | ||
350 | #ifdef CONFIG_F2FS_FS_POSIX_ACL | ||
351 | case Opt_noacl: | ||
352 | clear_opt(sbi, POSIX_ACL); | ||
353 | break; | ||
354 | #else | ||
355 | case Opt_noacl: | ||
356 | f2fs_msg(sb, KERN_INFO, "noacl options not supported"); | ||
357 | break; | ||
358 | #endif | ||
359 | case Opt_active_logs: | ||
360 | if (args->from && match_int(args, &arg)) | ||
361 | return -EINVAL; | ||
362 | if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) | ||
363 | return -EINVAL; | ||
364 | sbi->active_logs = arg; | ||
365 | break; | ||
366 | case Opt_disable_ext_identify: | ||
367 | set_opt(sbi, DISABLE_EXT_IDENTIFY); | ||
368 | break; | ||
369 | default: | ||
370 | f2fs_msg(sb, KERN_ERR, | ||
371 | "Unrecognized mount option \"%s\" or missing value", | ||
372 | p); | ||
373 | return -EINVAL; | ||
374 | } | ||
375 | } | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static loff_t max_file_size(unsigned bits) | 456 | static loff_t max_file_size(unsigned bits) |
380 | { | 457 | { |
381 | loff_t result = ADDRS_PER_INODE; | 458 | loff_t result = ADDRS_PER_INODE; |
@@ -541,6 +618,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
541 | if (err) | 618 | if (err) |
542 | goto free_sb_buf; | 619 | goto free_sb_buf; |
543 | } | 620 | } |
621 | sb->s_fs_info = sbi; | ||
544 | /* init some FS parameters */ | 622 | /* init some FS parameters */ |
545 | sbi->active_logs = NR_CURSEG_TYPE; | 623 | sbi->active_logs = NR_CURSEG_TYPE; |
546 | 624 | ||
@@ -553,7 +631,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
553 | set_opt(sbi, POSIX_ACL); | 631 | set_opt(sbi, POSIX_ACL); |
554 | #endif | 632 | #endif |
555 | /* parse mount options */ | 633 | /* parse mount options */ |
556 | err = parse_options(sb, sbi, (char *)data); | 634 | err = parse_options(sb, (char *)data); |
557 | if (err) | 635 | if (err) |
558 | goto free_sb_buf; | 636 | goto free_sb_buf; |
559 | 637 | ||
@@ -565,7 +643,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
565 | sb->s_xattr = f2fs_xattr_handlers; | 643 | sb->s_xattr = f2fs_xattr_handlers; |
566 | sb->s_export_op = &f2fs_export_ops; | 644 | sb->s_export_op = &f2fs_export_ops; |
567 | sb->s_magic = F2FS_SUPER_MAGIC; | 645 | sb->s_magic = F2FS_SUPER_MAGIC; |
568 | sb->s_fs_info = sbi; | ||
569 | sb->s_time_gran = 1; | 646 | sb->s_time_gran = 1; |
570 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | | 647 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | |
571 | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); | 648 | (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0); |
@@ -674,10 +751,16 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
674 | "Cannot recover all fsync data errno=%ld", err); | 751 | "Cannot recover all fsync data errno=%ld", err); |
675 | } | 752 | } |
676 | 753 | ||
677 | /* After POR, we can run background GC thread */ | 754 | /* |
678 | err = start_gc_thread(sbi); | 755 | * If filesystem is not mounted as read-only then |
679 | if (err) | 756 | * do start the gc_thread. |
680 | goto fail; | 757 | */ |
758 | if (!(sb->s_flags & MS_RDONLY)) { | ||
759 | /* After POR, we can run background GC thread.*/ | ||
760 | err = start_gc_thread(sbi); | ||
761 | if (err) | ||
762 | goto fail; | ||
763 | } | ||
681 | 764 | ||
682 | err = f2fs_build_stats(sbi); | 765 | err = f2fs_build_stats(sbi); |
683 | if (err) | 766 | if (err) |