diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
| -rw-r--r-- | fs/xfs/xfs_file.c | 139 | 
1 files changed, 41 insertions, 98 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 79e96ce98733..1f66779d7a46 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -155,7 +155,7 @@ xfs_dir_fsync(  	if (!lsn)  		return 0; -	return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL); +	return -_xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL);  }  STATIC int @@ -229,34 +229,27 @@ xfs_file_fsync(  }  STATIC ssize_t -xfs_file_aio_read( +xfs_file_read_iter(  	struct kiocb		*iocb, -	const struct iovec	*iovp, -	unsigned long		nr_segs, -	loff_t			pos) +	struct iov_iter		*to)  {  	struct file		*file = iocb->ki_filp;  	struct inode		*inode = file->f_mapping->host;  	struct xfs_inode	*ip = XFS_I(inode);  	struct xfs_mount	*mp = ip->i_mount; -	size_t			size = 0; +	size_t			size = iov_iter_count(to);  	ssize_t			ret = 0;  	int			ioflags = 0;  	xfs_fsize_t		n; +	loff_t			pos = iocb->ki_pos;  	XFS_STATS_INC(xs_read_calls); -	BUG_ON(iocb->ki_pos != pos); -  	if (unlikely(file->f_flags & O_DIRECT))  		ioflags |= IO_ISDIRECT;  	if (file->f_mode & FMODE_NOCMTIME)  		ioflags |= IO_INVIS; -	ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE); -	if (ret < 0) -		return ret; -  	if (unlikely(ioflags & IO_ISDIRECT)) {  		xfs_buftarg_t	*target =  			XFS_IS_REALTIME_INODE(ip) ? @@ -295,7 +288,7 @@ xfs_file_aio_read(  		xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);  		if (inode->i_mapping->nrpages) { -			ret = -filemap_write_and_wait_range( +			ret = filemap_write_and_wait_range(  							VFS_I(ip)->i_mapping,  							pos, -1);  			if (ret) { @@ -309,7 +302,7 @@ xfs_file_aio_read(  	trace_xfs_file_read(ip, size, pos, ioflags); -	ret = generic_file_aio_read(iocb, iovp, nr_segs, pos); +	ret = generic_file_read_iter(iocb, to);  	if (ret > 0)  		XFS_STATS_ADD(xs_read_bytes, ret); @@ -350,47 +343,6 @@ xfs_file_splice_read(  }  /* - * xfs_file_splice_write() does not use xfs_rw_ilock() because - * generic_file_splice_write() takes the i_mutex itself. This, in theory, - * couuld cause lock inversions between the aio_write path and the splice path - * if someone is doing concurrent splice(2) based writes and write(2) based - * writes to the same inode. The only real way to fix this is to re-implement - * the generic code here with correct locking orders. - */ -STATIC ssize_t -xfs_file_splice_write( -	struct pipe_inode_info	*pipe, -	struct file		*outfilp, -	loff_t			*ppos, -	size_t			count, -	unsigned int		flags) -{ -	struct inode		*inode = outfilp->f_mapping->host; -	struct xfs_inode	*ip = XFS_I(inode); -	int			ioflags = 0; -	ssize_t			ret; - -	XFS_STATS_INC(xs_write_calls); - -	if (outfilp->f_mode & FMODE_NOCMTIME) -		ioflags |= IO_INVIS; - -	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) -		return -EIO; - -	xfs_ilock(ip, XFS_IOLOCK_EXCL); - -	trace_xfs_file_splice_write(ip, count, *ppos, ioflags); - -	ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); -	if (ret > 0) -		XFS_STATS_ADD(xs_write_bytes, ret); - -	xfs_iunlock(ip, XFS_IOLOCK_EXCL); -	return ret; -} - -/*   * This routine is called to handle zeroing any space in the last block of the   * file that is beyond the EOF.  We do this since the size is being increased   * without writing anything to that block and we don't want to read the @@ -625,10 +577,7 @@ restart:  STATIC ssize_t  xfs_file_dio_aio_write(  	struct kiocb		*iocb, -	const struct iovec	*iovp, -	unsigned long		nr_segs, -	loff_t			pos, -	size_t			ocount) +	struct iov_iter		*from)  {  	struct file		*file = iocb->ki_filp;  	struct address_space	*mapping = file->f_mapping; @@ -636,9 +585,10 @@ xfs_file_dio_aio_write(  	struct xfs_inode	*ip = XFS_I(inode);  	struct xfs_mount	*mp = ip->i_mount;  	ssize_t			ret = 0; -	size_t			count = ocount;  	int			unaligned_io = 0;  	int			iolock; +	size_t			count = iov_iter_count(from); +	loff_t			pos = iocb->ki_pos;  	struct xfs_buftarg	*target = XFS_IS_REALTIME_INODE(ip) ?  					mp->m_rtdev_targp : mp->m_ddev_targp; @@ -677,9 +627,10 @@ xfs_file_dio_aio_write(  	ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock);  	if (ret)  		goto out; +	iov_iter_truncate(from, count);  	if (mapping->nrpages) { -		ret = -filemap_write_and_wait_range(VFS_I(ip)->i_mapping, +		ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,  						    pos, -1);  		if (ret)  			goto out; @@ -698,8 +649,7 @@ xfs_file_dio_aio_write(  	}  	trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0); -	ret = generic_file_direct_write(iocb, iovp, -			&nr_segs, pos, count, ocount); +	ret = generic_file_direct_write(iocb, from, pos);  out:  	xfs_rw_iunlock(ip, iolock); @@ -712,10 +662,7 @@ out:  STATIC ssize_t  xfs_file_buffered_aio_write(  	struct kiocb		*iocb, -	const struct iovec	*iovp, -	unsigned long		nr_segs, -	loff_t			pos, -	size_t			count) +	struct iov_iter		*from)  {  	struct file		*file = iocb->ki_filp;  	struct address_space	*mapping = file->f_mapping; @@ -724,7 +671,8 @@ xfs_file_buffered_aio_write(  	ssize_t			ret;  	int			enospc = 0;  	int			iolock = XFS_IOLOCK_EXCL; -	struct iov_iter		from; +	loff_t			pos = iocb->ki_pos; +	size_t			count = iov_iter_count(from);  	xfs_rw_ilock(ip, iolock); @@ -732,13 +680,13 @@ xfs_file_buffered_aio_write(  	if (ret)  		goto out; -	iov_iter_init(&from, iovp, nr_segs, count, 0); +	iov_iter_truncate(from, count);  	/* We can write back this queue in page reclaim */  	current->backing_dev_info = mapping->backing_dev_info;  write_retry:  	trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, 0); -	ret = generic_perform_write(file, &from, pos); +	ret = generic_perform_write(file, from, pos);  	if (likely(ret >= 0))  		iocb->ki_pos = pos + ret;  	/* @@ -759,40 +707,29 @@ out:  }  STATIC ssize_t -xfs_file_aio_write( +xfs_file_write_iter(  	struct kiocb		*iocb, -	const struct iovec	*iovp, -	unsigned long		nr_segs, -	loff_t			pos) +	struct iov_iter		*from)  {  	struct file		*file = iocb->ki_filp;  	struct address_space	*mapping = file->f_mapping;  	struct inode		*inode = mapping->host;  	struct xfs_inode	*ip = XFS_I(inode);  	ssize_t			ret; -	size_t			ocount = 0; +	size_t			ocount = iov_iter_count(from);  	XFS_STATS_INC(xs_write_calls); -	BUG_ON(iocb->ki_pos != pos); - -	ret = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ); -	if (ret) -		return ret; -  	if (ocount == 0)  		return 0; -	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { -		ret = -EIO; -		goto out; -	} +	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) +		return -EIO;  	if (unlikely(file->f_flags & O_DIRECT)) -		ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount); +		ret = xfs_file_dio_aio_write(iocb, from);  	else -		ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos, -						  ocount); +		ret = xfs_file_buffered_aio_write(iocb, from);  	if (ret > 0) {  		ssize_t err; @@ -804,8 +741,6 @@ xfs_file_aio_write(  		if (err < 0)  			ret = err;  	} - -out:  	return ret;  } @@ -837,11 +772,19 @@ xfs_file_fallocate(  		unsigned blksize_mask = (1 << inode->i_blkbits) - 1;  		if (offset & blksize_mask || len & blksize_mask) { -			error = -EINVAL; +			error = EINVAL; +			goto out_unlock; +		} + +		/* +		 * There is no need to overlap collapse range with EOF, +		 * in which case it is effectively a truncate operation +		 */ +		if (offset + len >= i_size_read(inode)) { +			error = EINVAL;  			goto out_unlock;  		} -		ASSERT(offset + len < i_size_read(inode));  		new_size = i_size_read(inode) - len;  		error = xfs_collapse_file_space(ip, offset, len); @@ -936,7 +879,7 @@ xfs_dir_open(  	 */  	mode = xfs_ilock_data_map_shared(ip);  	if (ip->i_d.di_nextents > 0) -		xfs_dir3_data_readahead(NULL, ip, 0, -1); +		xfs_dir3_data_readahead(ip, 0, -1);  	xfs_iunlock(ip, mode);  	return 0;  } @@ -1453,12 +1396,12 @@ xfs_file_llseek(  const struct file_operations xfs_file_operations = {  	.llseek		= xfs_file_llseek, -	.read		= do_sync_read, -	.write		= do_sync_write, -	.aio_read	= xfs_file_aio_read, -	.aio_write	= xfs_file_aio_write, +	.read		= new_sync_read, +	.write		= new_sync_write, +	.read_iter	= xfs_file_read_iter, +	.write_iter	= xfs_file_write_iter,  	.splice_read	= xfs_file_splice_read, -	.splice_write	= xfs_file_splice_write, +	.splice_write	= iter_file_splice_write,  	.unlocked_ioctl	= xfs_file_ioctl,  #ifdef CONFIG_COMPAT  	.compat_ioctl	= xfs_file_compat_ioctl,  |