diff options
Diffstat (limited to 'fs/f2fs/file.c')
| -rw-r--r-- | fs/f2fs/file.c | 105 | 
1 files changed, 75 insertions, 30 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7d8b96275092..060aee65aee8 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -41,6 +41,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,  	sb_start_pagefault(inode->i_sb); +	/* force to convert with normal data indices */ +	err = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, page); +	if (err) +		goto out; +  	/* block allocation */  	f2fs_lock_op(sbi);  	set_new_dnode(&dn, inode, NULL, NULL, 0); @@ -110,6 +115,25 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)  	return 1;  } +static inline bool need_do_checkpoint(struct inode *inode) +{ +	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); +	bool need_cp = false; + +	if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) +		need_cp = true; +	else if (file_wrong_pino(inode)) +		need_cp = true; +	else if (!space_for_roll_forward(sbi)) +		need_cp = true; +	else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) +		need_cp = true; +	else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi))) +		need_cp = true; + +	return need_cp; +} +  int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  {  	struct inode *inode = file->f_mapping->host; @@ -127,32 +151,39 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  		return 0;  	trace_f2fs_sync_file_enter(inode); + +	/* if fdatasync is triggered, let's do in-place-update */ +	if (datasync) +		set_inode_flag(fi, FI_NEED_IPU); +  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end); +	if (datasync) +		clear_inode_flag(fi, FI_NEED_IPU);  	if (ret) {  		trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);  		return ret;  	} +	/* +	 * if there is no written data, don't waste time to write recovery info. +	 */ +	if (!is_inode_flag_set(fi, FI_APPEND_WRITE) && +		!exist_written_data(sbi, inode->i_ino, APPEND_INO)) { +		if (is_inode_flag_set(fi, FI_UPDATE_WRITE) || +			exist_written_data(sbi, inode->i_ino, UPDATE_INO)) +			goto flush_out; +		goto out; +	} +  	/* guarantee free sections for fsync */  	f2fs_balance_fs(sbi); -	down_read(&fi->i_sem); -  	/*  	 * Both of fdatasync() and fsync() are able to be recovered from  	 * sudden-power-off.  	 */ -	if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) -		need_cp = true; -	else if (file_wrong_pino(inode)) -		need_cp = true; -	else if (!space_for_roll_forward(sbi)) -		need_cp = true; -	else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino)) -		need_cp = true; -	else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi))) -		need_cp = true; - +	down_read(&fi->i_sem); +	need_cp = need_do_checkpoint(inode);  	up_read(&fi->i_sem);  	if (need_cp) { @@ -188,6 +219,13 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  		ret = wait_on_node_pages_writeback(sbi, inode->i_ino);  		if (ret)  			goto out; + +		/* once recovery info is written, don't need to tack this */ +		remove_dirty_inode(sbi, inode->i_ino, APPEND_INO); +		clear_inode_flag(fi, FI_APPEND_WRITE); +flush_out: +		remove_dirty_inode(sbi, inode->i_ino, UPDATE_INO); +		clear_inode_flag(fi, FI_UPDATE_WRITE);  		ret = f2fs_issue_flush(F2FS_SB(inode->i_sb));  	}  out: @@ -206,8 +244,9 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,  	/* find first dirty page index */  	pagevec_init(&pvec, 0); -	nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1); -	pgofs = nr_pages ? pvec.pages[0]->index: LONG_MAX; +	nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, +					PAGECACHE_TAG_DIRTY, 1); +	pgofs = nr_pages ? pvec.pages[0]->index : LONG_MAX;  	pagevec_release(&pvec);  	return pgofs;  } @@ -262,7 +301,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)  		if (err && err != -ENOENT) {  			goto fail;  		} else if (err == -ENOENT) { -			/* direct node is not exist */ +			/* direct node does not exists */  			if (whence == SEEK_DATA) {  				pgofs = PGOFS_OF_NEXT_DNODE(pgofs,  							F2FS_I(inode)); @@ -272,8 +311,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)  			}  		} -		end_offset = IS_INODE(dn.node_page) ? -			ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK; +		end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));  		/* find data/hole in dnode block */  		for (; dn.ofs_in_node < end_offset; @@ -380,17 +418,19 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)  		return;  	lock_page(page); -	if (unlikely(page->mapping != inode->i_mapping)) { -		f2fs_put_page(page, 1); -		return; -	} +	if (unlikely(!PageUptodate(page) || +			page->mapping != inode->i_mapping)) +		goto out; +  	f2fs_wait_on_page_writeback(page, DATA);  	zero_user(page, offset, PAGE_CACHE_SIZE - offset);  	set_page_dirty(page); + +out:  	f2fs_put_page(page, 1);  } -int truncate_blocks(struct inode *inode, u64 from) +int truncate_blocks(struct inode *inode, u64 from, bool lock)  {  	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);  	unsigned int blocksize = inode->i_sb->s_blocksize; @@ -406,14 +446,16 @@ int truncate_blocks(struct inode *inode, u64 from)  	free_from = (pgoff_t)  			((from + blocksize - 1) >> (sbi->log_blocksize)); -	f2fs_lock_op(sbi); +	if (lock) +		f2fs_lock_op(sbi);  	set_new_dnode(&dn, inode, NULL, NULL, 0);  	err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);  	if (err) {  		if (err == -ENOENT)  			goto free_next; -		f2fs_unlock_op(sbi); +		if (lock) +			f2fs_unlock_op(sbi);  		trace_f2fs_truncate_blocks_exit(inode, err);  		return err;  	} @@ -431,7 +473,8 @@ int truncate_blocks(struct inode *inode, u64 from)  	f2fs_put_dnode(&dn);  free_next:  	err = truncate_inode_blocks(inode, free_from); -	f2fs_unlock_op(sbi); +	if (lock) +		f2fs_unlock_op(sbi);  done:  	/* lastly zero out the first data page */  	truncate_partial_data_page(inode, from); @@ -448,7 +491,7 @@ void f2fs_truncate(struct inode *inode)  	trace_f2fs_truncate(inode); -	if (!truncate_blocks(inode, i_size_read(inode))) { +	if (!truncate_blocks(inode, i_size_read(inode), true)) {  		inode->i_mtime = inode->i_ctime = CURRENT_TIME;  		mark_inode_dirty(inode);  	} @@ -506,7 +549,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)  	if ((attr->ia_valid & ATTR_SIZE) &&  			attr->ia_size != i_size_read(inode)) { -		err = f2fs_convert_inline_data(inode, attr->ia_size); +		err = f2fs_convert_inline_data(inode, attr->ia_size, NULL);  		if (err)  			return err; @@ -595,7 +638,7 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)  	loff_t off_start, off_end;  	int ret = 0; -	ret = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1); +	ret = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, NULL);  	if (ret)  		return ret; @@ -645,11 +688,13 @@ static int expand_inode_data(struct inode *inode, loff_t offset,  	loff_t off_start, off_end;  	int ret = 0; +	f2fs_balance_fs(sbi); +  	ret = inode_newsize_ok(inode, (len + offset));  	if (ret)  		return ret; -	ret = f2fs_convert_inline_data(inode, offset + len); +	ret = f2fs_convert_inline_data(inode, offset + len, NULL);  	if (ret)  		return ret;  |