diff options
author | Sagi Grimberg <sagig@mellanox.com> | 2015-06-11 12:58:34 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-06-23 03:43:40 -0400 |
commit | e2e21bd8f979a24462070cc89fae11e819cae90a (patch) | |
tree | 06ab5dcf58dcf1d58f72f53659af9f8090e1e07d | |
parent | 7c0d0d51d26497866d2951a35f1736fc765e4fcf (diff) |
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.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 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, | |||
260 | 260 | ||
261 | /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ | 261 | /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ |
262 | if (sg->length != copy_bytes) { | 262 | if (sg->length != copy_bytes) { |
263 | from += copy_bytes; | 263 | void *from_skip = from + copy_bytes; |
264 | |||
264 | copy_bytes = sg->length - copy_bytes; | 265 | copy_bytes = sg->length - copy_bytes; |
265 | 266 | ||
266 | (*iov)->iov_len = copy_bytes; | 267 | (*iov)->iov_len = copy_bytes; |
@@ -270,7 +271,7 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, | |||
270 | if (copy_data) { | 271 | if (copy_data) { |
271 | to = (void *) udev->mb_addr + | 272 | to = (void *) udev->mb_addr + |
272 | udev->data_off + udev->data_head; | 273 | udev->data_off + udev->data_head; |
273 | memcpy(to, from, copy_bytes); | 274 | memcpy(to, from_skip, copy_bytes); |
274 | tcmu_flush_dcache_range(to, copy_bytes); | 275 | tcmu_flush_dcache_range(to, copy_bytes); |
275 | } | 276 | } |
276 | 277 | ||
@@ -281,7 +282,7 @@ static void alloc_and_scatter_data_area(struct tcmu_dev *udev, | |||
281 | copy_bytes, udev->data_size); | 282 | copy_bytes, udev->data_size); |
282 | } | 283 | } |
283 | 284 | ||
284 | kunmap_atomic(from); | 285 | kunmap_atomic(from - sg->offset); |
285 | } | 286 | } |
286 | } | 287 | } |
287 | 288 | ||
@@ -309,18 +310,19 @@ static void gather_and_free_data_area(struct tcmu_dev *udev, | |||
309 | 310 | ||
310 | /* Uh oh, wrapped the data buffer for this sg's data */ | 311 | /* Uh oh, wrapped the data buffer for this sg's data */ |
311 | if (sg->length != copy_bytes) { | 312 | if (sg->length != copy_bytes) { |
313 | void *to_skip = to + copy_bytes; | ||
314 | |||
312 | from = (void *) udev->mb_addr + | 315 | from = (void *) udev->mb_addr + |
313 | udev->data_off + udev->data_tail; | 316 | udev->data_off + udev->data_tail; |
314 | WARN_ON(udev->data_tail); | 317 | WARN_ON(udev->data_tail); |
315 | to += copy_bytes; | ||
316 | copy_bytes = sg->length - copy_bytes; | 318 | copy_bytes = sg->length - copy_bytes; |
317 | tcmu_flush_dcache_range(from, copy_bytes); | 319 | tcmu_flush_dcache_range(from, copy_bytes); |
318 | memcpy(to, from, copy_bytes); | 320 | memcpy(to_skip, from, copy_bytes); |
319 | 321 | ||
320 | UPDATE_HEAD(udev->data_tail, | 322 | UPDATE_HEAD(udev->data_tail, |
321 | copy_bytes, udev->data_size); | 323 | copy_bytes, udev->data_size); |
322 | } | 324 | } |
323 | kunmap_atomic(to); | 325 | kunmap_atomic(to - sg->offset); |
324 | } | 326 | } |
325 | } | 327 | } |
326 | 328 | ||