diff options
Diffstat (limited to 'fs/iomap.c')
| -rw-r--r-- | fs/iomap.c | 54 | 
1 files changed, 32 insertions, 22 deletions
| diff --git a/fs/iomap.c b/fs/iomap.c index 269b24a01f32..d4801f8dd4fd 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -713,6 +713,8 @@ struct iomap_dio {  static ssize_t iomap_dio_complete(struct iomap_dio *dio)  {  	struct kiocb *iocb = dio->iocb; +	struct inode *inode = file_inode(iocb->ki_filp); +	loff_t offset = iocb->ki_pos;  	ssize_t ret;  	if (dio->end_io) { @@ -726,12 +728,33 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio)  	if (likely(!ret)) {  		ret = dio->size;  		/* check for short read */ -		if (iocb->ki_pos + ret > dio->i_size && +		if (offset + ret > dio->i_size &&  		    !(dio->flags & IOMAP_DIO_WRITE)) -			ret = dio->i_size - iocb->ki_pos; +			ret = dio->i_size - offset;  		iocb->ki_pos += ret;  	} +	/* +	 * Try again to invalidate clean pages which might have been cached by +	 * non-direct readahead, or faulted in by get_user_pages() if the source +	 * of the write was an mmap'ed region of the file we're writing.  Either +	 * one is a pretty crazy thing to do, so we don't support it 100%.  If +	 * this invalidation fails, tough, the write still worked... +	 * +	 * And this page cache invalidation has to be after dio->end_io(), as +	 * some filesystems convert unwritten extents to real allocations in +	 * end_io() when necessary, otherwise a racing buffer read would cache +	 * zeros from unwritten extents. +	 */ +	if (!dio->error && +	    (dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) { +		int err; +		err = invalidate_inode_pages2_range(inode->i_mapping, +				offset >> PAGE_SHIFT, +				(offset + dio->size - 1) >> PAGE_SHIFT); +		WARN_ON_ONCE(err); +	} +  	inode_dio_end(file_inode(iocb->ki_filp));  	kfree(dio); @@ -993,6 +1016,13 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,  	WARN_ON_ONCE(ret);  	ret = 0; +	if (iov_iter_rw(iter) == WRITE && !is_sync_kiocb(iocb) && +	    !inode->i_sb->s_dio_done_wq) { +		ret = sb_init_dio_done_wq(inode->i_sb); +		if (ret < 0) +			goto out_free_dio; +	} +  	inode_dio_begin(inode);  	blk_start_plug(&plug); @@ -1015,13 +1045,6 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,  	if (ret < 0)  		iomap_dio_set_error(dio, ret); -	if (ret >= 0 && iov_iter_rw(iter) == WRITE && !is_sync_kiocb(iocb) && -			!inode->i_sb->s_dio_done_wq) { -		ret = sb_init_dio_done_wq(inode->i_sb); -		if (ret < 0) -			iomap_dio_set_error(dio, ret); -	} -  	if (!atomic_dec_and_test(&dio->ref)) {  		if (!is_sync_kiocb(iocb))  			return -EIOCBQUEUED; @@ -1042,19 +1065,6 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,  	ret = iomap_dio_complete(dio); -	/* -	 * Try again to invalidate clean pages which might have been cached by -	 * non-direct readahead, or faulted in by get_user_pages() if the source -	 * of the write was an mmap'ed region of the file we're writing.  Either -	 * one is a pretty crazy thing to do, so we don't support it 100%.  If -	 * this invalidation fails, tough, the write still worked... -	 */ -	if (iov_iter_rw(iter) == WRITE) { -		int err = invalidate_inode_pages2_range(mapping, -				start >> PAGE_SHIFT, end >> PAGE_SHIFT); -		WARN_ON_ONCE(err); -	} -  	return ret;  out_free_dio: |