From: Dave Kleikamp Date: Thu, 22 Mar 2012 22:19:44 +0000 (-0500) Subject: btrfs: btrfs_direct_IO_bvec() needs to check for sector alignment X-Git-Tag: v2.6.39-400.9.0~577^2 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=7d1157b24d53d17b3ce242b96b6bde7ff20d840d;p=users%2Fjedix%2Flinux-maple.git btrfs: btrfs_direct_IO_bvec() needs to check for sector alignment I left out a vital piece of btrfs_direct_IO_bvec(). I didn't think check_direct_IO() was needed, but it is. This patch creates its equivalent, check_direct_IO_bvec(). Signed-off-by: Dave Kleikamp --- diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 66f1f56c107d..39d9353d56e7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6126,6 +6126,33 @@ out: return retval; } +static ssize_t check_direct_IO_bvec(struct btrfs_root *root, int rw, + struct kiocb *iocb, struct bio_vec *bvec, + loff_t offset, unsigned long nr_segs) +{ + int seg; + size_t size; + unsigned long addr; + unsigned blocksize_mask = root->sectorsize - 1; + ssize_t retval = -EINVAL; + loff_t end = offset; + + if (offset & blocksize_mask) + goto out; + + /* Check the memory alignment. Blocks cannot straddle pages */ + for (seg = 0; seg < nr_segs; seg++) { + addr = (unsigned long)bvec[seg].bv_offset; + size = bvec[seg].bv_len; + end += size; + if ((addr & blocksize_mask) || (size & blocksize_mask)) + goto out; + } + retval = 0; +out: + return retval; +} + static ssize_t btrfs_pre_direct_IO(int writing, loff_t offset, size_t count, struct inode *inode, int *write_bits) { @@ -6246,6 +6273,10 @@ static ssize_t btrfs_direct_IO_bvec(int rw, struct kiocb *iocb, int write_bits = 0; size_t count = bvec_length(bvec, bvec_len); + if (check_direct_IO_bvec(BTRFS_I(inode)->root, rw, iocb, bvec, + offset, bvec_len)) + return 0; + ret = btrfs_pre_direct_IO(writing, offset, count, inode, &write_bits); if (ret) return ret;