diff options
Diffstat (limited to 'fs/btrfs/file.c')
| -rw-r--r-- | fs/btrfs/file.c | 118 | 
1 files changed, 54 insertions, 64 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 0e155f013839..864c08d08a35 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2014,14 +2014,8 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,  	else  		num_written = btrfs_buffered_write(iocb, from); -	/* -	 * We also have to set last_sub_trans to the current log transid, -	 * otherwise subsequent syncs to a file that's been synced in this -	 * transaction will appear to have already occurred. -	 */ -	spin_lock(&inode->lock); -	inode->last_sub_trans = inode->root->log_transid; -	spin_unlock(&inode->lock); +	btrfs_set_inode_last_sub_trans(inode); +  	if (num_written > 0)  		num_written = generic_write_sync(iocb, num_written); @@ -2122,7 +2116,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  	if (ret)  		goto out; -	inode_lock(inode); +	btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP);  	atomic_inc(&root->log_batch); @@ -2135,11 +2129,11 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  			     &BTRFS_I(inode)->runtime_flags);  	/* -	 * Before we acquired the inode's lock, someone may have dirtied more -	 * pages in the target range. We need to make sure that writeback for -	 * any such pages does not start while we are logging the inode, because -	 * if it does, any of the following might happen when we are not doing a -	 * full inode sync: +	 * Before we acquired the inode's lock and the mmap lock, someone may +	 * have dirtied more pages in the target range. We need to make sure +	 * that writeback for any such pages does not start while we are logging +	 * the inode, because if it does, any of the following might happen when +	 * we are not doing a full inode sync:  	 *  	 * 1) We log an extent after its writeback finishes but before its  	 *    checksums are added to the csum tree, leading to -EIO errors @@ -2154,7 +2148,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  	 */  	ret = start_ordered_ops(inode, start, end);  	if (ret) { -		inode_unlock(inode); +		btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  		goto out;  	} @@ -2255,7 +2249,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)  	 * file again, but that will end up using the synchronization  	 * inside btrfs_sync_log to keep things safe.  	 */ -	inode_unlock(inode); +	btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  	if (ret != BTRFS_NO_LOG_SYNC) {  		if (!ret) { @@ -2285,7 +2279,7 @@ out:  out_release_extents:  	btrfs_release_log_ctx_extents(&ctx); -	inode_unlock(inode); +	btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  	goto out;  } @@ -2605,16 +2599,17 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans,   * extents without inserting a new one, so we must abort the transaction to avoid   * a corruption.   */ -int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path, -			   const u64 start, const u64 end, -			   struct btrfs_replace_extent_info *extent_info, -			   struct btrfs_trans_handle **trans_out) +int btrfs_replace_file_extents(struct btrfs_inode *inode, +			       struct btrfs_path *path, const u64 start, +			       const u64 end, +			       struct btrfs_replace_extent_info *extent_info, +			       struct btrfs_trans_handle **trans_out)  {  	struct btrfs_drop_extents_args drop_args = { 0 }; -	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); +	struct btrfs_root *root = inode->root; +	struct btrfs_fs_info *fs_info = root->fs_info;  	u64 min_size = btrfs_calc_insert_metadata_size(fs_info, 1); -	u64 ino_size = round_up(inode->i_size, fs_info->sectorsize); -	struct btrfs_root *root = BTRFS_I(inode)->root; +	u64 ino_size = round_up(inode->vfs_inode.i_size, fs_info->sectorsize);  	struct btrfs_trans_handle *trans = NULL;  	struct btrfs_block_rsv *rsv;  	unsigned int rsv_count; @@ -2662,10 +2657,10 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  	drop_args.drop_cache = true;  	while (cur_offset < end) {  		drop_args.start = cur_offset; -		ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args); +		ret = btrfs_drop_extents(trans, root, inode, &drop_args);  		/* If we are punching a hole decrement the inode's byte count */  		if (!extent_info) -			btrfs_update_inode_bytes(BTRFS_I(inode), 0, +			btrfs_update_inode_bytes(inode, 0,  						 drop_args.bytes_found);  		if (ret != -ENOSPC) {  			/* @@ -2685,8 +2680,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  		if (!extent_info && cur_offset < drop_args.drop_end &&  		    cur_offset < ino_size) { -			ret = fill_holes(trans, BTRFS_I(inode), path, -					 cur_offset, drop_args.drop_end); +			ret = fill_holes(trans, inode, path, cur_offset, +					 drop_args.drop_end);  			if (ret) {  				/*  				 * If we failed then we didn't insert our hole @@ -2704,7 +2699,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  			 * know to not set disk_i_size in this area until a new  			 * file extent is inserted here.  			 */ -			ret = btrfs_inode_clear_file_extent_range(BTRFS_I(inode), +			ret = btrfs_inode_clear_file_extent_range(inode,  					cur_offset,  					drop_args.drop_end - cur_offset);  			if (ret) { @@ -2723,8 +2718,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  			u64 replace_len = drop_args.drop_end -  					  extent_info->file_offset; -			ret = btrfs_insert_replace_extent(trans, BTRFS_I(inode), -					path, extent_info, replace_len, +			ret = btrfs_insert_replace_extent(trans, inode,	path, +					extent_info, replace_len,  					drop_args.bytes_found);  			if (ret) {  				btrfs_abort_transaction(trans, ret); @@ -2735,9 +2730,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  			extent_info->file_offset += replace_len;  		} -		cur_offset = drop_args.drop_end; - -		ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); +		ret = btrfs_update_inode(trans, root, inode);  		if (ret)  			break; @@ -2756,9 +2749,10 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  		BUG_ON(ret);	/* shouldn't happen */  		trans->block_rsv = rsv; -		if (!extent_info) { -			ret = find_first_non_hole(BTRFS_I(inode), &cur_offset, -						  &len); +		cur_offset = drop_args.drop_end; +		len = end - cur_offset; +		if (!extent_info && len) { +			ret = find_first_non_hole(inode, &cur_offset, &len);  			if (unlikely(ret < 0))  				break;  			if (ret && !len) { @@ -2771,14 +2765,11 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  	/*  	 * If we were cloning, force the next fsync to be a full one since we  	 * we replaced (or just dropped in the case of cloning holes when -	 * NO_HOLES is enabled) extents and extent maps. -	 * This is for the sake of simplicity, and cloning into files larger -	 * than 16Mb would force the full fsync any way (when -	 * try_release_extent_mapping() is invoked during page cache truncation. +	 * NO_HOLES is enabled) file extent items and did not setup new extent +	 * maps for the replacement extents (or holes).  	 */  	if (extent_info && !extent_info->is_new_extent) -		set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, -			&BTRFS_I(inode)->runtime_flags); +		set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags);  	if (ret)  		goto out_trans; @@ -2804,8 +2795,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  	 */  	if (!extent_info && cur_offset < ino_size &&  	    cur_offset < drop_args.drop_end) { -		ret = fill_holes(trans, BTRFS_I(inode), path, -				 cur_offset, drop_args.drop_end); +		ret = fill_holes(trans, inode, path, cur_offset, +				 drop_args.drop_end);  		if (ret) {  			/* Same comment as above. */  			btrfs_abort_transaction(trans, ret); @@ -2813,8 +2804,8 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  		}  	} else if (!extent_info && cur_offset < drop_args.drop_end) {  		/* See the comment in the loop above for the reasoning here. */ -		ret = btrfs_inode_clear_file_extent_range(BTRFS_I(inode), -				cur_offset, drop_args.drop_end - cur_offset); +		ret = btrfs_inode_clear_file_extent_range(inode, cur_offset, +					drop_args.drop_end - cur_offset);  		if (ret) {  			btrfs_abort_transaction(trans, ret);  			goto out_trans; @@ -2822,7 +2813,7 @@ int btrfs_replace_file_extents(struct inode *inode, struct btrfs_path *path,  	}  	if (extent_info) { -		ret = btrfs_insert_replace_extent(trans, BTRFS_I(inode), path, +		ret = btrfs_insert_replace_extent(trans, inode, path,  				extent_info, extent_info->data_len,  				drop_args.bytes_found);  		if (ret) { @@ -2868,7 +2859,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)  	if (ret)  		return ret; -	inode_lock(inode); +	btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP);  	ino_size = round_up(inode->i_size, fs_info->sectorsize);  	ret = find_first_non_hole(BTRFS_I(inode), &offset, &len);  	if (ret < 0) @@ -2908,7 +2899,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)  		truncated_block = true;  		ret = btrfs_truncate_block(BTRFS_I(inode), offset, 0, 0);  		if (ret) { -			inode_unlock(inode); +			btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  			return ret;  		}  	} @@ -2967,8 +2958,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)  		goto out;  	} -	ret = btrfs_replace_file_extents(inode, path, lockstart, lockend, NULL, -				     &trans); +	ret = btrfs_replace_file_extents(BTRFS_I(inode), path, lockstart, +					 lockend, NULL, &trans);  	btrfs_free_path(path);  	if (ret)  		goto out; @@ -3009,7 +3000,7 @@ out_only_mutex:  				ret = ret2;  		}  	} -	inode_unlock(inode); +	btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  	return ret;  } @@ -3335,7 +3326,7 @@ static long btrfs_fallocate(struct file *file, int mode,  			return ret;  	} -	btrfs_inode_lock(inode, 0); +	btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP);  	if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) {  		ret = inode_newsize_ok(inode, offset + len); @@ -3377,7 +3368,7 @@ static long btrfs_fallocate(struct file *file, int mode,  	if (mode & FALLOC_FL_ZERO_RANGE) {  		ret = btrfs_zero_range(inode, offset, len, mode); -		inode_unlock(inode); +		btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  		return ret;  	} @@ -3487,7 +3478,7 @@ out_unlock:  	unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,  			     &cached_state);  out: -	inode_unlock(inode); +	btrfs_inode_unlock(inode, BTRFS_ILOCK_MMAP);  	/* Let go of our reservation. */  	if (ret != 0 && !(mode & FALLOC_FL_ZERO_RANGE))  		btrfs_free_reserved_data_space(BTRFS_I(inode), data_reserved, @@ -3496,13 +3487,13 @@ out:  	return ret;  } -static loff_t find_desired_extent(struct inode *inode, loff_t offset, +static loff_t find_desired_extent(struct btrfs_inode *inode, loff_t offset,  				  int whence)  { -	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); +	struct btrfs_fs_info *fs_info = inode->root->fs_info;  	struct extent_map *em = NULL;  	struct extent_state *cached_state = NULL; -	loff_t i_size = inode->i_size; +	loff_t i_size = inode->vfs_inode.i_size;  	u64 lockstart;  	u64 lockend;  	u64 start; @@ -3525,11 +3516,10 @@ static loff_t find_desired_extent(struct inode *inode, loff_t offset,  	lockend--;  	len = lockend - lockstart + 1; -	lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, -			 &cached_state); +	lock_extent_bits(&inode->io_tree, lockstart, lockend, &cached_state);  	while (start < i_size) { -		em = btrfs_get_extent_fiemap(BTRFS_I(inode), start, len); +		em = btrfs_get_extent_fiemap(inode, start, len);  		if (IS_ERR(em)) {  			ret = PTR_ERR(em);  			em = NULL; @@ -3551,7 +3541,7 @@ static loff_t find_desired_extent(struct inode *inode, loff_t offset,  		cond_resched();  	}  	free_extent_map(em); -	unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, +	unlock_extent_cached(&inode->io_tree, lockstart, lockend,  			     &cached_state);  	if (ret) {  		offset = ret; @@ -3575,7 +3565,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)  	case SEEK_DATA:  	case SEEK_HOLE:  		btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED); -		offset = find_desired_extent(inode, offset, whence); +		offset = find_desired_extent(BTRFS_I(inode), offset, whence);  		btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);  		break;  	}  |