summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSagi Grimberg <sagig@mellanox.com>2015-06-11 18:58:34 +0200
committerNicholas Bellinger <nab@linux-iscsi.org>2015-06-23 09:43:40 +0200
commite2e21bd8f979a24462070cc89fae11e819cae90a (patch)
tree06ab5dcf58dcf1d58f72f53659af9f8090e1e07d
parenttarget: Send UA when changing LUN inventory (diff)
downloadlinux-e2e21bd8f979a24462070cc89fae11e819cae90a.tar.xz
linux-e2e21bd8f979a24462070cc89fae11e819cae90a.zip
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>
-rw-r--r--drivers/target/target_core_user.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 949e6165ef8a..078ef6e3eb70 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);
}
}