]> git.karo-electronics.de Git - linux-beck.git/commitdiff
target/user: Fix inconsistent kmap_atomic/kunmap_atomic
authorSagi Grimberg <sagig@mellanox.com>
Thu, 11 Jun 2015 16:58:34 +0000 (19:58 +0300)
committerNicholas Bellinger <nab@linux-iscsi.org>
Tue, 23 Jun 2015 07:43:40 +0000 (00:43 -0700)
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>
drivers/target/target_core_user.c

index 949e6165ef8a758b1d0aab4c80150d6c92bc501c..078ef6e3eb70efa6784f0d13a17e00ac06d11563 100644 (file)
@@ -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);
        }
 }