mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	btrfs: introduce btrfs_write_check()
btrfs_write_check() checks write parameters in one place before beginning a write. This does away with inode_unlock() after every check. In the later patches, it will help push inode_lock/unlock() in buffered and direct write functions respectively. generic_write_checks needs to be called before as it could truncate iov_iter and its return used as count. Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									c86537a42f
								
							
						
					
					
						commit
						b8d8e1fd57
					
				
					 1 changed files with 77 additions and 74 deletions
				
			
		
							
								
								
									
										151
									
								
								fs/btrfs/file.c
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								fs/btrfs/file.c
									
									
									
									
									
								
							|  | @ -1564,6 +1564,79 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode) | ||||||
| 	btrfs_drew_write_unlock(&inode->root->snapshot_lock); | 	btrfs_drew_write_unlock(&inode->root->snapshot_lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void update_time_for_write(struct inode *inode) | ||||||
|  | { | ||||||
|  | 	struct timespec64 now; | ||||||
|  | 
 | ||||||
|  | 	if (IS_NOCMTIME(inode)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	now = current_time(inode); | ||||||
|  | 	if (!timespec64_equal(&inode->i_mtime, &now)) | ||||||
|  | 		inode->i_mtime = now; | ||||||
|  | 
 | ||||||
|  | 	if (!timespec64_equal(&inode->i_ctime, &now)) | ||||||
|  | 		inode->i_ctime = now; | ||||||
|  | 
 | ||||||
|  | 	if (IS_I_VERSION(inode)) | ||||||
|  | 		inode_inc_iversion(inode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from, | ||||||
|  | 			     size_t count) | ||||||
|  | { | ||||||
|  | 	struct file *file = iocb->ki_filp; | ||||||
|  | 	struct inode *inode = file_inode(file); | ||||||
|  | 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); | ||||||
|  | 	loff_t pos = iocb->ki_pos; | ||||||
|  | 	int ret; | ||||||
|  | 	loff_t oldsize; | ||||||
|  | 	loff_t start_pos; | ||||||
|  | 
 | ||||||
|  | 	if (iocb->ki_flags & IOCB_NOWAIT) { | ||||||
|  | 		size_t nocow_bytes = count; | ||||||
|  | 
 | ||||||
|  | 		/* We will allocate space in case nodatacow is not set, so bail */ | ||||||
|  | 		if (check_nocow_nolock(BTRFS_I(inode), pos, &nocow_bytes) <= 0) | ||||||
|  | 			return -EAGAIN; | ||||||
|  | 		/*
 | ||||||
|  | 		 * There are holes in the range or parts of the range that must | ||||||
|  | 		 * be COWed (shared extents, RO block groups, etc), so just bail | ||||||
|  | 		 * out. | ||||||
|  | 		 */ | ||||||
|  | 		if (nocow_bytes < count) | ||||||
|  | 			return -EAGAIN; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	current->backing_dev_info = inode_to_bdi(inode); | ||||||
|  | 	ret = file_remove_privs(file); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * We reserve space for updating the inode when we reserve space for the | ||||||
|  | 	 * extent we are going to write, so we will enospc out there.  We don't | ||||||
|  | 	 * need to start yet another transaction to update the inode as we will | ||||||
|  | 	 * update the inode when we finish writing whatever data we write. | ||||||
|  | 	 */ | ||||||
|  | 	update_time_for_write(inode); | ||||||
|  | 
 | ||||||
|  | 	start_pos = round_down(pos, fs_info->sectorsize); | ||||||
|  | 	oldsize = i_size_read(inode); | ||||||
|  | 	if (start_pos > oldsize) { | ||||||
|  | 		/* Expand hole size to cover write data, preventing empty gap */ | ||||||
|  | 		loff_t end_pos = round_up(pos + count, fs_info->sectorsize); | ||||||
|  | 
 | ||||||
|  | 		ret = btrfs_cont_expand(inode, oldsize, end_pos); | ||||||
|  | 		if (ret) { | ||||||
|  | 			current->backing_dev_info = NULL; | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, | static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, | ||||||
| 					       struct iov_iter *i) | 					       struct iov_iter *i) | ||||||
| { | { | ||||||
|  | @ -1873,24 +1946,6 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) | ||||||
| 	return written ? written : err; | 	return written ? written : err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void update_time_for_write(struct inode *inode) |  | ||||||
| { |  | ||||||
| 	struct timespec64 now; |  | ||||||
| 
 |  | ||||||
| 	if (IS_NOCMTIME(inode)) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	now = current_time(inode); |  | ||||||
| 	if (!timespec64_equal(&inode->i_mtime, &now)) |  | ||||||
| 		inode->i_mtime = now; |  | ||||||
| 
 |  | ||||||
| 	if (!timespec64_equal(&inode->i_ctime, &now)) |  | ||||||
| 		inode->i_ctime = now; |  | ||||||
| 
 |  | ||||||
| 	if (IS_I_VERSION(inode)) |  | ||||||
| 		inode_inc_iversion(inode); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static ssize_t btrfs_file_write_iter(struct kiocb *iocb, | static ssize_t btrfs_file_write_iter(struct kiocb *iocb, | ||||||
| 				    struct iov_iter *from) | 				    struct iov_iter *from) | ||||||
| { | { | ||||||
|  | @ -1898,14 +1953,9 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, | ||||||
| 	struct inode *inode = file_inode(file); | 	struct inode *inode = file_inode(file); | ||||||
| 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); | 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); | ||||||
| 	struct btrfs_root *root = BTRFS_I(inode)->root; | 	struct btrfs_root *root = BTRFS_I(inode)->root; | ||||||
| 	u64 start_pos; |  | ||||||
| 	u64 end_pos; |  | ||||||
| 	ssize_t num_written = 0; | 	ssize_t num_written = 0; | ||||||
| 	const bool sync = iocb->ki_flags & IOCB_DSYNC; | 	const bool sync = iocb->ki_flags & IOCB_DSYNC; | ||||||
| 	ssize_t err; | 	ssize_t err; | ||||||
| 	loff_t pos; |  | ||||||
| 	size_t count; |  | ||||||
| 	loff_t oldsize; |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * If the fs flips readonly due to some impossible error, although we | 	 * If the fs flips readonly due to some impossible error, although we | ||||||
|  | @ -1932,57 +1982,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, | ||||||
| 		return err; | 		return err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pos = iocb->ki_pos; | 	err = btrfs_write_check(iocb, from, err); | ||||||
| 	count = iov_iter_count(from); | 	if (err < 0) { | ||||||
| 	if (iocb->ki_flags & IOCB_NOWAIT) { |  | ||||||
| 		size_t nocow_bytes = count; |  | ||||||
| 
 |  | ||||||
| 		/*
 |  | ||||||
| 		 * We will allocate space in case nodatacow is not set, |  | ||||||
| 		 * so bail |  | ||||||
| 		 */ |  | ||||||
| 		if (check_nocow_nolock(BTRFS_I(inode), pos, &nocow_bytes) |  | ||||||
| 		    <= 0) { |  | ||||||
| 			inode_unlock(inode); |  | ||||||
| 			return -EAGAIN; |  | ||||||
| 		} |  | ||||||
| 		/*
 |  | ||||||
| 		 * There are holes in the range or parts of the range that must |  | ||||||
| 		 * be COWed (shared extents, RO block groups, etc), so just bail |  | ||||||
| 		 * out. |  | ||||||
| 		 */ |  | ||||||
| 		if (nocow_bytes < count) { |  | ||||||
| 			inode_unlock(inode); |  | ||||||
| 			return -EAGAIN; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	current->backing_dev_info = inode_to_bdi(inode); |  | ||||||
| 	err = file_remove_privs(file); |  | ||||||
| 	if (err) { |  | ||||||
| 		inode_unlock(inode); | 		inode_unlock(inode); | ||||||
| 		goto out; | 		return err; | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * We reserve space for updating the inode when we reserve space for the |  | ||||||
| 	 * extent we are going to write, so we will enospc out there.  We don't |  | ||||||
| 	 * need to start yet another transaction to update the inode as we will |  | ||||||
| 	 * update the inode when we finish writing whatever data we write. |  | ||||||
| 	 */ |  | ||||||
| 	update_time_for_write(inode); |  | ||||||
| 
 |  | ||||||
| 	start_pos = round_down(pos, fs_info->sectorsize); |  | ||||||
| 	oldsize = i_size_read(inode); |  | ||||||
| 	if (start_pos > oldsize) { |  | ||||||
| 		/* Expand hole size to cover write data, preventing empty gap */ |  | ||||||
| 		end_pos = round_up(pos + count, |  | ||||||
| 				   fs_info->sectorsize); |  | ||||||
| 		err = btrfs_cont_expand(inode, oldsize, end_pos); |  | ||||||
| 		if (err) { |  | ||||||
| 			inode_unlock(inode); |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (sync) | 	if (sync) | ||||||
|  | @ -2042,7 +2045,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, | ||||||
| 
 | 
 | ||||||
| 	if (sync) | 	if (sync) | ||||||
| 		atomic_dec(&BTRFS_I(inode)->sync_writers); | 		atomic_dec(&BTRFS_I(inode)->sync_writers); | ||||||
| out: | 
 | ||||||
| 	current->backing_dev_info = NULL; | 	current->backing_dev_info = NULL; | ||||||
| 	return num_written ? num_written : err; | 	return num_written ? num_written : err; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Goldwyn Rodrigues
						Goldwyn Rodrigues