diff options
author | Sagi Grimberg <sagig@mellanox.com> | 2015-06-11 16:58:34 (GMT) |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-06-23 07:43:40 (GMT) |
commit | e2e21bd8f979a24462070cc89fae11e819cae90a (patch) | |
tree | 06ab5dcf58dcf1d58f72f53659af9f8090e1e07d /drivers | |
parent | 7c0d0d51d26497866d2951a35f1736fc765e4fcf (diff) | |
download | linux-e2e21bd8f979a24462070cc89fae11e819cae90a.tar.xz |
target/user: Fix inconsistent kmap_atomic/kunmap_atomic
Pointers that are mapped by kmap_atomic() + offset must
be unmapped without the offset. That would cause problems
if the SG element length exceeds the PAGE_SIZE limit.
Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/target/target_core_user.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 949e616..078ef6e 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -260,7 +260,8 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ if (sg->length != copy_bytes) { - from += copy_bytes; + void *from_skip = from + copy_bytes; + copy_bytes = sg->length - copy_bytes; (*iov)->iov_len = copy_bytes; @@ -270,7 +271,7 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, if (copy_data) { to = (void *) udev->mb_addr + udev->data_off + udev->data_head; - memcpy(to, from, copy_bytes); + memcpy(to, from_skip, copy_bytes); tcmu_flush_dcache_range(to, copy_bytes); } @@ -281,7 +282,7 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, copy_bytes, udev->data_size); } - kunmap_atomic(from); + kunmap_atomic(from - sg->offset); } } @@ -309,18 +310,19 @@ static void gather_and_free_data_area(struct tcmu_dev *udev, /* Uh oh, wrapped the data buffer for this sg's data */ if (sg->length != copy_bytes) { + void *to_skip = to + copy_bytes; + from = (void *) udev->mb_addr + udev->data_off + udev->data_tail; WARN_ON(udev->data_tail); - to += copy_bytes; copy_bytes = sg->length - copy_bytes; tcmu_flush_dcache_range(from, copy_bytes); - memcpy(to, from, copy_bytes); + memcpy(to_skip, from, copy_bytes); UPDATE_HEAD(udev->data_tail, copy_bytes, udev->data_size); } - kunmap_atomic(to); + kunmap_atomic(to - sg->offset); } } |