RE: [PATCH v2] storvsc: get rid of bounce buffer

2015-09-23 Thread KY Srinivasan


> -Original Message-
> From: Vitaly Kuznetsov [mailto:vkuzn...@redhat.com]
> Sent: Wednesday, September 23, 2015 5:59 AM
> To: linux-scsi@vger.kernel.org
> Cc: linux-ker...@vger.kernel.org; de...@linuxdriverproject.org; KY
> Srinivasan ; Haiyang Zhang
> ; James E.J. Bottomley ;
> Radim Krčmář ; Christoph Hellwig
> 
> Subject: [PATCH v2] storvsc: get rid of bounce buffer
> 
> Storvsc driver needs to ensure there are no 'holes' in the presented
> sg list (all segments in the middle of the list need to be of PAGE_SIZE).
> When a hole is detected storvsc driver creates a 'bounce sgl' without
> holes and copies data over with copy_{to,from}_bounce_buffer() functions.
> Setting virt_boundary_mask to PAGE_SIZE - 1 guarantees we'll never see
> such holes so we can significantly simplify the driver. This is also
> supposed to bring us some performance improvement for certain workloads
> as we eliminate copying.
> 
> Reported-by: Radim Krčmář 
> Signed-off-by: Vitaly Kuznetsov 
> ---
> Changes since v1:
> - This patch is a successor of 'storvsc: get rid of homegrown
>  copy_{to,from}_bounce_buffer()'. Use virt_boundary instead to
>  eliminate the need for bounce buffer completely [Christoph Hellwig].
> ---
>  drivers/scsi/storvsc_drv.c | 286 
> +
>  1 file changed, 5 insertions(+), 281 deletions(-)
> 
> diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
> index 40c43ae..eeade40 100644
> --- a/drivers/scsi/storvsc_drv.c
> +++ b/drivers/scsi/storvsc_drv.c
> @@ -393,9 +393,6 @@ static void storvsc_on_channel_callback(void
> *context);
>  struct storvsc_cmd_request {
>   struct scsi_cmnd *cmd;
> 
> - unsigned int bounce_sgl_count;
> - struct scatterlist *bounce_sgl;
> -
>   struct hv_device *device;
> 
>   /* Synchronize the request/response if needed */
> @@ -586,241 +583,6 @@ get_in_err:
> 
>  }
> 
> -static void destroy_bounce_buffer(struct scatterlist *sgl,
> -   unsigned int sg_count)
> -{
> - int i;
> - struct page *page_buf;
> -
> - for (i = 0; i < sg_count; i++) {
> - page_buf = sg_page((&sgl[i]));
> - if (page_buf != NULL)
> - __free_page(page_buf);
> - }
> -
> - kfree(sgl);
> -}
> -
> -static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
> -{
> - int i;
> -
> - /* No need to check */
> - if (sg_count < 2)
> - return -1;
> -
> - /* We have at least 2 sg entries */
> - for (i = 0; i < sg_count; i++) {
> - if (i == 0) {
> - /* make sure 1st one does not have hole */
> - if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
> - return i;
> - } else if (i == sg_count - 1) {
> - /* make sure last one does not have hole */
> - if (sgl[i].offset != 0)
> - return i;
> - } else {
> - /* make sure no hole in the middle */
> - if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
> - return i;
> - }
> - }
> - return -1;
> -}
> -
> -static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
> - unsigned int sg_count,
> - unsigned int len,
> - int write)
> -{
> - int i;
> - int num_pages;
> - struct scatterlist *bounce_sgl;
> - struct page *page_buf;
> - unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
> -
> - num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
> -
> - bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist),
> GFP_ATOMIC);
> - if (!bounce_sgl)
> - return NULL;
> -
> - sg_init_table(bounce_sgl, num_pages);
> - for (i = 0; i < num_pages; i++) {
> - page_buf = alloc_page(GFP_ATOMIC);
> - if (!page_buf)
> - goto cleanup;
> - sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
> - }
> -
> - return bounce_sgl;
> -
> -cleanup:
> - destroy_bounce_buffer(bounce_sgl, num_pages);
> - return NULL;
> -}
> -
> -/* Assume the original sgl has enough room */
> -static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
> - struct scatterlist *bounce_sgl,
>

[PATCH v2] storvsc: get rid of bounce buffer

2015-09-23 Thread Vitaly Kuznetsov
Storvsc driver needs to ensure there are no 'holes' in the presented
sg list (all segments in the middle of the list need to be of PAGE_SIZE).
When a hole is detected storvsc driver creates a 'bounce sgl' without
holes and copies data over with copy_{to,from}_bounce_buffer() functions.
Setting virt_boundary_mask to PAGE_SIZE - 1 guarantees we'll never see
such holes so we can significantly simplify the driver. This is also
supposed to bring us some performance improvement for certain workloads
as we eliminate copying.

Reported-by: Radim Krčmář 
Signed-off-by: Vitaly Kuznetsov 
---
Changes since v1:
- This patch is a successor of 'storvsc: get rid of homegrown
 copy_{to,from}_bounce_buffer()'. Use virt_boundary instead to
 eliminate the need for bounce buffer completely [Christoph Hellwig].
---
 drivers/scsi/storvsc_drv.c | 286 +
 1 file changed, 5 insertions(+), 281 deletions(-)

diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 40c43ae..eeade40 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -393,9 +393,6 @@ static void storvsc_on_channel_callback(void *context);
 struct storvsc_cmd_request {
struct scsi_cmnd *cmd;
 
-   unsigned int bounce_sgl_count;
-   struct scatterlist *bounce_sgl;
-
struct hv_device *device;
 
/* Synchronize the request/response if needed */
@@ -586,241 +583,6 @@ get_in_err:
 
 }
 
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count)
-{
-   int i;
-   struct page *page_buf;
-
-   for (i = 0; i < sg_count; i++) {
-   page_buf = sg_page((&sgl[i]));
-   if (page_buf != NULL)
-   __free_page(page_buf);
-   }
-
-   kfree(sgl);
-}
-
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
-{
-   int i;
-
-   /* No need to check */
-   if (sg_count < 2)
-   return -1;
-
-   /* We have at least 2 sg entries */
-   for (i = 0; i < sg_count; i++) {
-   if (i == 0) {
-   /* make sure 1st one does not have hole */
-   if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
-   return i;
-   } else if (i == sg_count - 1) {
-   /* make sure last one does not have hole */
-   if (sgl[i].offset != 0)
-   return i;
-   } else {
-   /* make sure no hole in the middle */
-   if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
-   return i;
-   }
-   }
-   return -1;
-}
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
-   unsigned int sg_count,
-   unsigned int len,
-   int write)
-{
-   int i;
-   int num_pages;
-   struct scatterlist *bounce_sgl;
-   struct page *page_buf;
-   unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
-
-   num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
-
-   bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
-   if (!bounce_sgl)
-   return NULL;
-
-   sg_init_table(bounce_sgl, num_pages);
-   for (i = 0; i < num_pages; i++) {
-   page_buf = alloc_page(GFP_ATOMIC);
-   if (!page_buf)
-   goto cleanup;
-   sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
-   }
-
-   return bounce_sgl;
-
-cleanup:
-   destroy_bounce_buffer(bounce_sgl, num_pages);
-   return NULL;
-}
-
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
-   struct scatterlist *bounce_sgl,
-   unsigned int orig_sgl_count,
-   unsigned int bounce_sgl_count)
-{
-   int i;
-   int j = 0;
-   unsigned long src, dest;
-   unsigned int srclen, destlen, copylen;
-   unsigned int total_copied = 0;
-   unsigned long bounce_addr = 0;
-   unsigned long dest_addr = 0;
-   unsigned long flags;
-   struct scatterlist *cur_dest_sgl;
-   struct scatterlist *cur_src_sgl;
-
-   local_irq_save(flags);
-   cur_dest_sgl = orig_sgl;
-   cur_src_sgl = bounce_sgl;
-   for (i = 0; i < orig_sgl_count; i++) {
-   dest_addr = (unsigned long)
-   kmap_atomic(sg_page(cur_dest_sgl)) +
-   cur_dest_sgl->offset;
-   dest = dest_addr;
-   destlen = cur_dest_sgl->length;
-
-   if (bounce_addr == 0)
-   bounce_addr