diff options
Diffstat (limited to 'fs/f2fs/super.c')
-rw-r--r-- | fs/f2fs/super.c | 143 |
1 files changed, 42 insertions, 101 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index bafff72..13d0a0f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -43,9 +43,7 @@ enum { Opt_disable_roll_forward, Opt_discard, Opt_noheap, - Opt_user_xattr, Opt_nouser_xattr, - Opt_acl, Opt_noacl, Opt_active_logs, Opt_disable_ext_identify, @@ -58,9 +56,7 @@ static match_table_t f2fs_tokens = { {Opt_disable_roll_forward, "disable_roll_forward"}, {Opt_discard, "discard"}, {Opt_noheap, "no_heap"}, - {Opt_user_xattr, "user_xattr"}, {Opt_nouser_xattr, "nouser_xattr"}, - {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, {Opt_active_logs, "active_logs=%u"}, {Opt_disable_ext_identify, "disable_ext_identify"}, @@ -69,40 +65,24 @@ static match_table_t f2fs_tokens = { }; /* Sysfs support for f2fs */ -enum { - GC_THREAD, /* struct f2fs_gc_thread */ - SM_INFO, /* struct f2fs_sm_info */ -}; - struct f2fs_attr { struct attribute attr; ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *); ssize_t (*store)(struct f2fs_attr *, struct f2fs_sb_info *, const char *, size_t); - int struct_type; int offset; }; -static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) -{ - if (struct_type == GC_THREAD) - return (unsigned char *)sbi->gc_thread; - else if (struct_type == SM_INFO) - return (unsigned char *)SM_I(sbi); - return NULL; -} - static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { - unsigned char *ptr = NULL; + struct f2fs_gc_kthread *gc_kth = sbi->gc_thread; unsigned int *ui; - ptr = __struct_ptr(sbi, a->struct_type); - if (!ptr) + if (!gc_kth) return -EINVAL; - ui = (unsigned int *)(ptr + a->offset); + ui = (unsigned int *)(((char *)gc_kth) + a->offset); return snprintf(buf, PAGE_SIZE, "%u\n", *ui); } @@ -111,16 +91,15 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, struct f2fs_sb_info *sbi, const char *buf, size_t count) { - unsigned char *ptr; + struct f2fs_gc_kthread *gc_kth = sbi->gc_thread; unsigned long t; unsigned int *ui; ssize_t ret; - ptr = __struct_ptr(sbi, a->struct_type); - if (!ptr) + if (!gc_kth) return -EINVAL; - ui = (unsigned int *)(ptr + a->offset); + ui = (unsigned int *)(((char *)gc_kth) + a->offset); ret = kstrtoul(skip_spaces(buf), 0, &t); if (ret < 0) @@ -156,25 +135,21 @@ static void f2fs_sb_release(struct kobject *kobj) complete(&sbi->s_kobj_unregister); } -#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ +#define F2FS_ATTR_OFFSET(_name, _mode, _show, _store, _elname) \ static struct f2fs_attr f2fs_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ - .struct_type = _struct_type, \ - .offset = _offset \ + .offset = offsetof(struct f2fs_gc_kthread, _elname), \ } -#define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \ - F2FS_ATTR_OFFSET(struct_type, name, 0644, \ - f2fs_sbi_show, f2fs_sbi_store, \ - offsetof(struct struct_name, elname)) +#define F2FS_RW_ATTR(name, elname) \ + F2FS_ATTR_OFFSET(name, 0644, f2fs_sbi_show, f2fs_sbi_store, elname) -F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); -F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); -F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); -F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); -F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); +F2FS_RW_ATTR(gc_min_sleep_time, min_sleep_time); +F2FS_RW_ATTR(gc_max_sleep_time, max_sleep_time); +F2FS_RW_ATTR(gc_no_gc_sleep_time, no_gc_sleep_time); +F2FS_RW_ATTR(gc_idle, gc_idle); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -182,7 +157,6 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(gc_max_sleep_time), ATTR_LIST(gc_no_gc_sleep_time), ATTR_LIST(gc_idle), - ATTR_LIST(reclaim_segments), NULL, }; @@ -263,9 +237,6 @@ static int parse_options(struct super_block *sb, char *options) set_opt(sbi, NOHEAP); break; #ifdef CONFIG_F2FS_FS_XATTR - case Opt_user_xattr: - set_opt(sbi, XATTR_USER); - break; case Opt_nouser_xattr: clear_opt(sbi, XATTR_USER); break; @@ -273,10 +244,6 @@ static int parse_options(struct super_block *sb, char *options) set_opt(sbi, INLINE_XATTR); break; #else - case Opt_user_xattr: - f2fs_msg(sb, KERN_INFO, - "user_xattr options not supported"); - break; case Opt_nouser_xattr: f2fs_msg(sb, KERN_INFO, "nouser_xattr options not supported"); @@ -287,16 +254,10 @@ static int parse_options(struct super_block *sb, char *options) break; #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL - case Opt_acl: - set_opt(sbi, POSIX_ACL); - break; case Opt_noacl: clear_opt(sbi, POSIX_ACL); break; #else - case Opt_acl: - f2fs_msg(sb, KERN_INFO, "acl options not supported"); - break; case Opt_noacl: f2fs_msg(sb, KERN_INFO, "noacl options not supported"); break; @@ -394,9 +355,7 @@ static void f2fs_put_super(struct super_block *sb) f2fs_destroy_stats(sbi); stop_gc_thread(sbi); - /* We don't need to do checkpoint when it's clean */ - if (sbi->s_dirty && get_pages(sbi, F2FS_DIRTY_NODES)) - write_checkpoint(sbi, true); + write_checkpoint(sbi, true); iput(sbi->node_inode); iput(sbi->meta_inode); @@ -768,47 +727,30 @@ static void init_sb_info(struct f2fs_sb_info *sbi) atomic_set(&sbi->nr_pages[i], 0); } -/* - * Read f2fs raw super block. - * Because we have two copies of super block, so read the first one at first, - * if the first one is invalid, move to read the second one. - */ -static int read_raw_super_block(struct super_block *sb, - struct f2fs_super_block **raw_super, - struct buffer_head **raw_super_buf) +static int validate_superblock(struct super_block *sb, + struct f2fs_super_block **raw_super, + struct buffer_head **raw_super_buf, sector_t block) { - int block = 0; + const char *super = (block == 0 ? "first" : "second"); -retry: + /* read f2fs raw super block */ *raw_super_buf = sb_bread(sb, block); if (!*raw_super_buf) { - f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", - block + 1); - if (block == 0) { - block++; - goto retry; - } else { - return -EIO; - } + f2fs_msg(sb, KERN_ERR, "unable to read %s superblock", + super); + return -EIO; } *raw_super = (struct f2fs_super_block *) ((char *)(*raw_super_buf)->b_data + F2FS_SUPER_OFFSET); /* sanity checking of raw super */ - if (sanity_check_raw_super(sb, *raw_super)) { - brelse(*raw_super_buf); - f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " - "in %dth superblock", block + 1); - if(block == 0) { - block++; - goto retry; - } else { - return -EINVAL; - } - } + if (!sanity_check_raw_super(sb, *raw_super)) + return 0; - return 0; + f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem " + "in %s superblock", super); + return -EINVAL; } static int f2fs_fill_super(struct super_block *sb, void *data, int silent) @@ -818,6 +760,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) struct buffer_head *raw_super_buf; struct inode *root; long err = -EINVAL; + int i; /* allocate memory for f2fs-specific super block info */ sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); @@ -830,10 +773,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_sbi; } - err = read_raw_super_block(sb, &raw_super, &raw_super_buf); - if (err) - goto free_sbi; - + err = validate_superblock(sb, &raw_super, &raw_super_buf, 0); + if (err) { + brelse(raw_super_buf); + /* check secondary superblock when primary failed */ + err = validate_superblock(sb, &raw_super, &raw_super_buf, 1); + if (err) + goto free_sb_buf; + } sb->s_fs_info = sbi; /* init some FS parameters */ sbi->active_logs = NR_CURSEG_TYPE; @@ -871,12 +818,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) mutex_init(&sbi->gc_mutex); mutex_init(&sbi->writepages); mutex_init(&sbi->cp_mutex); + for (i = 0; i < NR_GLOBAL_LOCKS; i++) + mutex_init(&sbi->fs_lock[i]); mutex_init(&sbi->node_write); - sbi->por_doing = false; + sbi->por_doing = 0; spin_lock_init(&sbi->stat_lock); init_rwsem(&sbi->bio_sem); - init_rwsem(&sbi->cp_rwsem); - init_waitqueue_head(&sbi->cp_wait); init_sb_info(sbi); /* get an inode for meta space */ @@ -975,12 +922,12 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) /* After POR, we can run background GC thread.*/ err = start_gc_thread(sbi); if (err) - goto free_gc; + goto fail; } err = f2fs_build_stats(sbi); if (err) - goto free_gc; + goto fail; if (f2fs_proc_root) sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); @@ -1006,12 +953,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) return 0; fail: - if (sbi->s_proc) { - remove_proc_entry("segment_info", sbi->s_proc); - remove_proc_entry(sb->s_id, f2fs_proc_root); - } - f2fs_destroy_stats(sbi); -free_gc: stop_gc_thread(sbi); free_root_inode: dput(sb->s_root); |