diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 47 |
1 files changed, 18 insertions, 29 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 7fa5f7fd7bc7..8925f66a1411 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -7445,39 +7445,30 @@ free_ordered: | |||
7445 | } | 7445 | } |
7446 | 7446 | ||
7447 | static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb, | 7447 | static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *iocb, |
7448 | const struct iovec *iov, loff_t offset, | 7448 | const struct iov_iter *iter, loff_t offset) |
7449 | unsigned long nr_segs) | ||
7450 | { | 7449 | { |
7451 | int seg; | 7450 | int seg; |
7452 | int i; | 7451 | int i; |
7453 | size_t size; | ||
7454 | unsigned long addr; | ||
7455 | unsigned blocksize_mask = root->sectorsize - 1; | 7452 | unsigned blocksize_mask = root->sectorsize - 1; |
7456 | ssize_t retval = -EINVAL; | 7453 | ssize_t retval = -EINVAL; |
7457 | loff_t end = offset; | ||
7458 | 7454 | ||
7459 | if (offset & blocksize_mask) | 7455 | if (offset & blocksize_mask) |
7460 | goto out; | 7456 | goto out; |
7461 | 7457 | ||
7462 | /* Check the memory alignment. Blocks cannot straddle pages */ | 7458 | if (iov_iter_alignment(iter) & blocksize_mask) |
7463 | for (seg = 0; seg < nr_segs; seg++) { | 7459 | goto out; |
7464 | addr = (unsigned long)iov[seg].iov_base; | ||
7465 | size = iov[seg].iov_len; | ||
7466 | end += size; | ||
7467 | if ((addr & blocksize_mask) || (size & blocksize_mask)) | ||
7468 | goto out; | ||
7469 | |||
7470 | /* If this is a write we don't need to check anymore */ | ||
7471 | if (rw & WRITE) | ||
7472 | continue; | ||
7473 | 7460 | ||
7474 | /* | 7461 | /* If this is a write we don't need to check anymore */ |
7475 | * Check to make sure we don't have duplicate iov_base's in this | 7462 | if (rw & WRITE) |
7476 | * iovec, if so return EINVAL, otherwise we'll get csum errors | 7463 | return 0; |
7477 | * when reading back. | 7464 | /* |
7478 | */ | 7465 | * Check to make sure we don't have duplicate iov_base's in this |
7479 | for (i = seg + 1; i < nr_segs; i++) { | 7466 | * iovec, if so return EINVAL, otherwise we'll get csum errors |
7480 | if (iov[seg].iov_base == iov[i].iov_base) | 7467 | * when reading back. |
7468 | */ | ||
7469 | for (seg = 0; seg < iter->nr_segs; seg++) { | ||
7470 | for (i = seg + 1; i < iter->nr_segs; i++) { | ||
7471 | if (iter->iov[seg].iov_base == iter->iov[i].iov_base) | ||
7481 | goto out; | 7472 | goto out; |
7482 | } | 7473 | } |
7483 | } | 7474 | } |
@@ -7487,8 +7478,7 @@ out: | |||
7487 | } | 7478 | } |
7488 | 7479 | ||
7489 | static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | 7480 | static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, |
7490 | const struct iovec *iov, loff_t offset, | 7481 | struct iov_iter *iter, loff_t offset) |
7491 | unsigned long nr_segs) | ||
7492 | { | 7482 | { |
7493 | struct file *file = iocb->ki_filp; | 7483 | struct file *file = iocb->ki_filp; |
7494 | struct inode *inode = file->f_mapping->host; | 7484 | struct inode *inode = file->f_mapping->host; |
@@ -7498,8 +7488,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
7498 | bool relock = false; | 7488 | bool relock = false; |
7499 | ssize_t ret; | 7489 | ssize_t ret; |
7500 | 7490 | ||
7501 | if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov, | 7491 | if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iter, offset)) |
7502 | offset, nr_segs)) | ||
7503 | return 0; | 7492 | return 0; |
7504 | 7493 | ||
7505 | atomic_inc(&inode->i_dio_count); | 7494 | atomic_inc(&inode->i_dio_count); |
@@ -7511,7 +7500,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
7511 | * we need to flush the dirty pages again to make absolutely sure | 7500 | * we need to flush the dirty pages again to make absolutely sure |
7512 | * that any outstanding dirty pages are on disk. | 7501 | * that any outstanding dirty pages are on disk. |
7513 | */ | 7502 | */ |
7514 | count = iov_length(iov, nr_segs); | 7503 | count = iov_iter_count(iter); |
7515 | if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, | 7504 | if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, |
7516 | &BTRFS_I(inode)->runtime_flags)) | 7505 | &BTRFS_I(inode)->runtime_flags)) |
7517 | filemap_fdatawrite_range(inode->i_mapping, offset, count); | 7506 | filemap_fdatawrite_range(inode->i_mapping, offset, count); |
@@ -7538,7 +7527,7 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, | |||
7538 | 7527 | ||
7539 | ret = __blockdev_direct_IO(rw, iocb, inode, | 7528 | ret = __blockdev_direct_IO(rw, iocb, inode, |
7540 | BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, | 7529 | BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, |
7541 | iov, offset, nr_segs, btrfs_get_blocks_direct, NULL, | 7530 | iter, offset, btrfs_get_blocks_direct, NULL, |
7542 | btrfs_submit_direct, flags); | 7531 | btrfs_submit_direct, flags); |
7543 | if (rw & WRITE) { | 7532 | if (rw & WRITE) { |
7544 | if (ret < 0 && ret != -EIOCBQUEUED) | 7533 | if (ret < 0 && ret != -EIOCBQUEUED) |