aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/inode.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 5ab120d544bc..6866c36c26fb 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5722,6 +5722,32 @@ free_ordered:
5722 bio_endio(bio, ret); 5722 bio_endio(bio, ret);
5723} 5723}
5724 5724
5725static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb,
5726 const struct iovec *iov, loff_t offset,
5727 unsigned long nr_segs)
5728{
5729 int seg;
5730 size_t size;
5731 unsigned long addr;
5732 unsigned blocksize_mask = root->sectorsize - 1;
5733 ssize_t retval = -EINVAL;
5734 loff_t end = offset;
5735
5736 if (offset & blocksize_mask)
5737 goto out;
5738
5739 /* Check the memory alignment. Blocks cannot straddle pages */
5740 for (seg = 0; seg < nr_segs; seg++) {
5741 addr = (unsigned long)iov[seg].iov_base;
5742 size = iov[seg].iov_len;
5743 end += size;
5744 if ((addr & blocksize_mask) || (size & blocksize_mask))
5745 goto out;
5746 }
5747 retval = 0;
5748out:
5749 return retval;
5750}
5725static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, 5751static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
5726 const struct iovec *iov, loff_t offset, 5752 const struct iovec *iov, loff_t offset,
5727 unsigned long nr_segs) 5753 unsigned long nr_segs)
@@ -5736,6 +5762,11 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
5736 int write_bits = 0; 5762 int write_bits = 0;
5737 size_t count = iov_length(iov, nr_segs); 5763 size_t count = iov_length(iov, nr_segs);
5738 5764
5765 if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov,
5766 offset, nr_segs)) {
5767 return 0;
5768 }
5769
5739 lockstart = offset; 5770 lockstart = offset;
5740 lockend = offset + count - 1; 5771 lockend = offset + count - 1;
5741 5772
@@ -5784,9 +5815,10 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
5784 free_extent_state(cached_state); 5815 free_extent_state(cached_state);
5785 cached_state = NULL; 5816 cached_state = NULL;
5786 5817
5787 ret = __blockdev_direct_IO(rw, iocb, inode, NULL, iov, offset, nr_segs, 5818 ret = __blockdev_direct_IO(rw, iocb, inode,
5788 btrfs_get_blocks_direct, NULL, 5819 BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev,
5789 btrfs_submit_direct, 0); 5820 iov, offset, nr_segs, btrfs_get_blocks_direct, NULL,
5821 btrfs_submit_direct, 0);
5790 5822
5791 if (ret < 0 && ret != -EIOCBQUEUED) { 5823 if (ret < 0 && ret != -EIOCBQUEUED) {
5792 clear_extent_bit(&BTRFS_I(inode)->io_tree, offset, 5824 clear_extent_bit(&BTRFS_I(inode)->io_tree, offset,