Commit eafdc7d1 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Al Viro
Browse files

sort out blockdev_direct_IO variants



Move the call to vmtruncate to get rid of accessive blocks to the callers
in prepearation of the new truncate calling sequence.  This was only done
for DIO_LOCKING filesystems, so the __blockdev_direct_IO_newtrunc variant
was not needed anyway.  Get rid of blockdev_direct_IO_no_locking and
its _newtrunc variant while at it as just opencoding the two additional
paramters is shorted than the name suffix.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 25624958
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -172,9 +172,8 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
	struct file *file = iocb->ki_filp;
	struct inode *inode = file->f_mapping->host;

	return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
				I_BDEV(inode), iov, offset, nr_segs,
				blkdev_get_blocks, NULL);
	return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
				    nr_segs, blkdev_get_blocks, NULL, NULL, 0);
}

int __sync_blockdev(struct block_device *bdev, int wait)
+20 −54
Original line number Diff line number Diff line
@@ -1136,8 +1136,27 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
	return ret;
}

/*
 * This is a library function for use by filesystem drivers.
 *
 * The locking rules are governed by the flags parameter:
 *  - if the flags value contains DIO_LOCKING we use a fancy locking
 *    scheme for dumb filesystems.
 *    For writes this function is called under i_mutex and returns with
 *    i_mutex held, for reads, i_mutex is not held on entry, but it is
 *    taken and dropped again before returning.
 *    For reads and writes i_alloc_sem is taken in shared mode and released
 *    on I/O completion (which may happen asynchronously after returning to
 *    the caller).
 *
 *  - if the flags value does NOT contain DIO_LOCKING we don't use any
 *    internal locking but rather rely on the filesystem to synchronize
 *    direct I/O reads/writes versus each other and truncate.
 *    For reads and writes both i_mutex and i_alloc_sem are not held on
 *    entry and are never taken.
 */
ssize_t
__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
	struct block_device *bdev, const struct iovec *iov, loff_t offset, 
	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
	dio_submit_t submit_io,	int flags)
@@ -1233,57 +1252,4 @@ __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
out:
	return retval;
}
EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc);

/*
 * This is a library function for use by filesystem drivers.
 *
 * The locking rules are governed by the flags parameter:
 *  - if the flags value contains DIO_LOCKING we use a fancy locking
 *    scheme for dumb filesystems.
 *    For writes this function is called under i_mutex and returns with
 *    i_mutex held, for reads, i_mutex is not held on entry, but it is
 *    taken and dropped again before returning.
 *    For reads and writes i_alloc_sem is taken in shared mode and released
 *    on I/O completion (which may happen asynchronously after returning to
 *    the caller).
 *
 *  - if the flags value does NOT contain DIO_LOCKING we don't use any
 *    internal locking but rather rely on the filesystem to synchronize
 *    direct I/O reads/writes versus each other and truncate.
 *    For reads and writes both i_mutex and i_alloc_sem are not held on
 *    entry and are never taken.
 */
ssize_t
__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
	struct block_device *bdev, const struct iovec *iov, loff_t offset,
	unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
	dio_submit_t submit_io,	int flags)
{
	ssize_t retval;

	retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov,
			offset, nr_segs, get_block, end_io, submit_io, flags);
	/*
	 * In case of error extending write may have instantiated a few
	 * blocks outside i_size. Trim these off again for DIO_LOCKING.
	 * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in
	 * their own manner. This is a further example of where the old
	 * truncate sequence is inadequate.
	 *
	 * NOTE: filesystems with their own locking have to handle this
	 * on their own.
	 */
	if (flags & DIO_LOCKING) {
		if (unlikely((rw & WRITE) && retval < 0)) {
			loff_t isize = i_size_read(inode);
			loff_t end = offset + iov_length(iov, nr_segs);

			if (end > isize)
				vmtruncate(inode, isize);
		}
	}

	return retval;
}
EXPORT_SYMBOL(__blockdev_direct_IO);
+1 −1
Original line number Diff line number Diff line
@@ -838,7 +838,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
	struct inode *inode = mapping->host;
	ssize_t ret;

	ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
				iov, offset, nr_segs, ext2_get_block, NULL);
	if (ret < 0 && (rw & WRITE))
		ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
+11 −0
Original line number Diff line number Diff line
@@ -1785,6 +1785,17 @@ retry:
	ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
				 offset, nr_segs,
				 ext3_get_block, NULL);
	/*
	 * In case of error extending write may have instantiated a few
	 * blocks outside i_size. Trim these off again.
	 */
	if (unlikely((rw & WRITE) && ret < 0)) {
		loff_t isize = i_size_read(inode);
		loff_t end = offset + iov_length(iov, nr_segs);

		if (end > isize)
			vmtruncate(inode, isize);
	}
	if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
		goto retry;

+12 −3
Original line number Diff line number Diff line
@@ -3545,15 +3545,24 @@ static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,

retry:
	if (rw == READ && ext4_should_dioread_nolock(inode))
		ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
		ret = __blockdev_direct_IO(rw, iocb, inode,
				 inode->i_sb->s_bdev, iov,
				 offset, nr_segs,
				 ext4_get_block, NULL);
	else
				 ext4_get_block, NULL, NULL, 0);
	else {
		ret = blockdev_direct_IO(rw, iocb, inode,
				 inode->i_sb->s_bdev, iov,
				 offset, nr_segs,
				 ext4_get_block, NULL);

		if (unlikely((rw & WRITE) && ret < 0)) {
			loff_t isize = i_size_read(inode);
			loff_t end = offset + iov_length(iov, nr_segs);

			if (end > isize)
				vmtruncate(inode, isize);
		}
	}
	if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
		goto retry;

Loading