diff options
Diffstat (limited to 'fs/ocfs2/file.c')
| -rw-r--r-- | fs/ocfs2/file.c | 51 | 
1 files changed, 47 insertions, 4 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index efb09de4343d..91a194596552 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2100,14 +2100,20 @@ static long ocfs2_fallocate(struct file *file, int mode, loff_t offset,  	struct ocfs2_space_resv sr;  	int change_size = 1;  	int cmd = OCFS2_IOC_RESVSP64; +	int ret = 0;  	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))  		return -EOPNOTSUPP;  	if (!ocfs2_writes_unwritten_extents(osb))  		return -EOPNOTSUPP; -	if (mode & FALLOC_FL_KEEP_SIZE) +	if (mode & FALLOC_FL_KEEP_SIZE) {  		change_size = 0; +	} else { +		ret = inode_newsize_ok(inode, offset + len); +		if (ret) +			return ret; +	}  	if (mode & FALLOC_FL_PUNCH_HOLE)  		cmd = OCFS2_IOC_UNRESVSP64; @@ -2552,7 +2558,7 @@ static ssize_t ocfs2_file_read_iter(struct kiocb *iocb,  	 *  	 * Take and drop the meta data lock to update inode fields  	 * like i_size. This allows the checks down below -	 * generic_file_read_iter() a chance of actually working. +	 * copy_splice_read() a chance of actually working.  	 */  	ret = ocfs2_inode_lock_atime(inode, filp->f_path.mnt, &lock_level,  				     !nowait); @@ -2581,6 +2587,43 @@ bail:  	return ret;  } +static ssize_t ocfs2_file_splice_read(struct file *in, loff_t *ppos, +				      struct pipe_inode_info *pipe, +				      size_t len, unsigned int flags) +{ +	struct inode *inode = file_inode(in); +	ssize_t ret = 0; +	int lock_level = 0; + +	trace_ocfs2_file_splice_read(inode, in, in->f_path.dentry, +				     (unsigned long long)OCFS2_I(inode)->ip_blkno, +				     in->f_path.dentry->d_name.len, +				     in->f_path.dentry->d_name.name, +				     flags); + +	/* +	 * We're fine letting folks race truncates and extending writes with +	 * read across the cluster, just like they can locally.  Hence no +	 * rw_lock during read. +	 * +	 * Take and drop the meta data lock to update inode fields like i_size. +	 * This allows the checks down below filemap_splice_read() a chance of +	 * actually working. +	 */ +	ret = ocfs2_inode_lock_atime(inode, in->f_path.mnt, &lock_level, 1); +	if (ret < 0) { +		if (ret != -EAGAIN) +			mlog_errno(ret); +		goto bail; +	} +	ocfs2_inode_unlock(inode, lock_level); + +	ret = filemap_splice_read(in, ppos, pipe, len, flags); +	trace_filemap_splice_read_ret(ret); +bail: +	return ret; +} +  /* Refer generic_file_llseek_unlocked() */  static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)  { @@ -2744,7 +2787,7 @@ const struct file_operations ocfs2_fops = {  #endif  	.lock		= ocfs2_lock,  	.flock		= ocfs2_flock, -	.splice_read	= generic_file_splice_read, +	.splice_read	= ocfs2_file_splice_read,  	.splice_write	= iter_file_splice_write,  	.fallocate	= ocfs2_fallocate,  	.remap_file_range = ocfs2_remap_file_range, @@ -2790,7 +2833,7 @@ const struct file_operations ocfs2_fops_no_plocks = {  	.compat_ioctl   = ocfs2_compat_ioctl,  #endif  	.flock		= ocfs2_flock, -	.splice_read	= generic_file_splice_read, +	.splice_read	= filemap_splice_read,  	.splice_write	= iter_file_splice_write,  	.fallocate	= ocfs2_fallocate,  	.remap_file_range = ocfs2_remap_file_range,  |