Skip to content

Commit

Permalink
Btrfs: allow unaligned DIO
Browse files Browse the repository at this point in the history
In order to support DIO that isn't aligned to the filesystem blocksize,
we fall back to buffered for any unaligned DIOs.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed May 27, 2010
1 parent 933b585 commit 5a5f79b
Showing 1 changed file with 35 additions and 3 deletions.
38 changes: 35 additions & 3 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -5722,6 +5722,32 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
bio_endio(bio, ret);
}

static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb,
const struct iovec *iov, 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)iov[seg].iov_base;
size = iov[seg].iov_len;
end += size;
if ((addr & blocksize_mask) || (size & blocksize_mask))
goto out;
}
retval = 0;
out:
return retval;
}
static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset,
unsigned long nr_segs)
Expand All @@ -5736,6 +5762,11 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
int write_bits = 0;
size_t count = iov_length(iov, nr_segs);

if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov,
offset, nr_segs)) {
return 0;
}

lockstart = offset;
lockend = offset + count - 1;

Expand Down Expand Up @@ -5784,9 +5815,10 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
free_extent_state(cached_state);
cached_state = NULL;

ret = __blockdev_direct_IO(rw, iocb, inode, NULL, iov, offset, nr_segs,
btrfs_get_blocks_direct, NULL,
btrfs_submit_direct, 0);
ret = __blockdev_direct_IO(rw, iocb, inode,
BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev,
iov, offset, nr_segs, btrfs_get_blocks_direct, NULL,
btrfs_submit_direct, 0);

if (ret < 0 && ret != -EIOCBQUEUED) {
clear_extent_bit(&BTRFS_I(inode)->io_tree, offset,
Expand Down

0 comments on commit 5a5f79b

Please sign in to comment.