diff options
Diffstat (limited to 'fs/f2fs/super.c')
| -rw-r--r-- | fs/f2fs/super.c | 53 | 
1 files changed, 37 insertions, 16 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 8f96d9372ade..41bdf511003d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -52,6 +52,7 @@ enum {  	Opt_inline_xattr,  	Opt_inline_data,  	Opt_flush_merge, +	Opt_nobarrier,  	Opt_err,  }; @@ -69,6 +70,7 @@ static match_table_t f2fs_tokens = {  	{Opt_inline_xattr, "inline_xattr"},  	{Opt_inline_data, "inline_data"},  	{Opt_flush_merge, "flush_merge"}, +	{Opt_nobarrier, "nobarrier"},  	{Opt_err, NULL},  }; @@ -339,6 +341,9 @@ static int parse_options(struct super_block *sb, char *options)  		case Opt_flush_merge:  			set_opt(sbi, FLUSH_MERGE);  			break; +		case Opt_nobarrier: +			set_opt(sbi, NOBARRIER); +			break;  		default:  			f2fs_msg(sb, KERN_ERR,  				"Unrecognized mount option \"%s\" or missing value", @@ -427,9 +432,15 @@ static void f2fs_put_super(struct super_block *sb)  	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)) +	if (sbi->s_dirty)  		write_checkpoint(sbi, true); +	/* +	 * normally superblock is clean, so we need to release this. +	 * In addition, EIO will skip do checkpoint, we need this as well. +	 */ +	release_dirty_inode(sbi); +  	iput(sbi->node_inode);  	iput(sbi->meta_inode); @@ -452,9 +463,6 @@ int f2fs_sync_fs(struct super_block *sb, int sync)  	trace_f2fs_sync_fs(sb, sync); -	if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES)) -		return 0; -  	if (sync) {  		mutex_lock(&sbi->gc_mutex);  		write_checkpoint(sbi, false); @@ -500,8 +508,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)  	buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count;  	buf->f_bavail = user_block_count - valid_user_blocks(sbi); -	buf->f_files = sbi->total_node_count; -	buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi); +	buf->f_files = sbi->total_node_count - F2FS_RESERVED_NODE_NUM; +	buf->f_ffree = buf->f_files - valid_inode_count(sbi);  	buf->f_namelen = F2FS_NAME_LEN;  	buf->f_fsid.val[0] = (u32)id; @@ -544,6 +552,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)  		seq_puts(seq, ",inline_data");  	if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE))  		seq_puts(seq, ",flush_merge"); +	if (test_opt(sbi, NOBARRIER)) +		seq_puts(seq, ",nobarrier");  	seq_printf(seq, ",active_logs=%u", sbi->active_logs);  	return 0; @@ -615,7 +625,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)  	 * Previous and new state of filesystem is RO,  	 * so skip checking GC and FLUSH_MERGE conditions.  	 */ -	if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) +	if (f2fs_readonly(sb) && (*flags & MS_RDONLY))  		goto skip;  	/* @@ -642,8 +652,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)  	 */  	if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {  		destroy_flush_cmd_control(sbi); -	} else if (test_opt(sbi, FLUSH_MERGE) && -					!sbi->sm_info->cmd_control_info) { +	} else if (test_opt(sbi, FLUSH_MERGE) && !SM_I(sbi)->cmd_control_info) {  		err = create_flush_cmd_control(sbi);  		if (err)  			goto restore_gc; @@ -657,7 +666,7 @@ restore_gc:  	if (need_restart_gc) {  		if (start_gc_thread(sbi))  			f2fs_msg(sbi->sb, KERN_WARNING, -				"background gc thread is stop"); +				"background gc thread has stopped");  	} else if (need_stop_gc) {  		stop_gc_thread(sbi);  	} @@ -806,7 +815,7 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi)  	if (unlikely(fsmeta >= total))  		return 1; -	if (unlikely(is_set_ckpt_flags(ckpt, CP_ERROR_FLAG))) { +	if (unlikely(f2fs_cp_error(sbi))) {  		f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");  		return 1;  	} @@ -893,8 +902,10 @@ 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; +	bool retry = true;  	int i; +try_onemore:  	/* allocate memory for f2fs-specific super block info */  	sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);  	if (!sbi) @@ -947,7 +958,7 @@ 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); -	mutex_init(&sbi->node_write); +	init_rwsem(&sbi->node_write);  	sbi->por_doing = false;  	spin_lock_init(&sbi->stat_lock); @@ -997,7 +1008,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)  	INIT_LIST_HEAD(&sbi->dir_inode_list);  	spin_lock_init(&sbi->dir_inode_lock); -	init_orphan_info(sbi); +	init_ino_entry_info(sbi);  	/* setup f2fs internal modules */  	err = build_segment_manager(sbi); @@ -1034,8 +1045,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)  		goto free_node_inode;  	}  	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { +		iput(root);  		err = -EINVAL; -		goto free_root_inode; +		goto free_node_inode;  	}  	sb->s_root = d_make_root(root); /* allocate root dentry */ @@ -1073,16 +1085,18 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)  	/* recover fsynced data */  	if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {  		err = recover_fsync_data(sbi); -		if (err) +		if (err) {  			f2fs_msg(sb, KERN_ERR,  				"Cannot recover all fsync data errno=%ld", err); +			goto free_kobj; +		}  	}  	/*  	 * If filesystem is not mounted as read-only then  	 * do start the gc_thread.  	 */ -	if (!(sb->s_flags & MS_RDONLY)) { +	if (!f2fs_readonly(sb)) {  		/* After POR, we can run background GC thread.*/  		err = start_gc_thread(sbi);  		if (err) @@ -1116,6 +1130,13 @@ free_sb_buf:  	brelse(raw_super_buf);  free_sbi:  	kfree(sbi); + +	/* give only one another chance */ +	if (retry) { +		retry = 0; +		shrink_dcache_sb(sb); +		goto try_onemore; +	}  	return err;  }  | 
