diff options
-rw-r--r-- | fs/btrfs/inode.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2d1208f964eb..edafc28883af 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -6153,6 +6153,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io | |||
6153 | unsigned long nr_segs) | 6153 | unsigned long nr_segs) |
6154 | { | 6154 | { |
6155 | int seg; | 6155 | int seg; |
6156 | int i; | ||
6156 | size_t size; | 6157 | size_t size; |
6157 | unsigned long addr; | 6158 | unsigned long addr; |
6158 | unsigned blocksize_mask = root->sectorsize - 1; | 6159 | unsigned blocksize_mask = root->sectorsize - 1; |
@@ -6167,8 +6168,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io | |||
6167 | addr = (unsigned long)iov[seg].iov_base; | 6168 | addr = (unsigned long)iov[seg].iov_base; |
6168 | size = iov[seg].iov_len; | 6169 | size = iov[seg].iov_len; |
6169 | end += size; | 6170 | end += size; |
6170 | if ((addr & blocksize_mask) || (size & blocksize_mask)) | 6171 | if ((addr & blocksize_mask) || (size & blocksize_mask)) |
6171 | goto out; | 6172 | goto out; |
6173 | |||
6174 | /* If this is a write we don't need to check anymore */ | ||
6175 | if (rw & WRITE) | ||
6176 | continue; | ||
6177 | |||
6178 | /* | ||
6179 | * Check to make sure we don't have duplicate iov_base's in this | ||
6180 | * iovec, if so return EINVAL, otherwise we'll get csum errors | ||
6181 | * when reading back. | ||
6182 | */ | ||
6183 | for (i = seg + 1; i < nr_segs; i++) { | ||
6184 | if (iov[seg].iov_base == iov[i].iov_base) | ||
6185 | goto out; | ||
6186 | } | ||
6172 | } | 6187 | } |
6173 | retval = 0; | 6188 | retval = 0; |
6174 | out: | 6189 | out: |