uio_hv_generic: fix subchannel ring mmap
authorStephen Hemminger <stephen@networkplumber.org>
Mon, 16 Apr 2018 18:19:27 +0000 (11:19 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 23 Apr 2018 10:43:48 +0000 (12:43 +0200)
The fault method of handling subchannel ring, did not work correctly
(it only worked for the first page).

Since ring buffer is physically contiguous, using the vm helper
function is simpler and handles more cases.

Fixes: 37b96a4931db ("uio_hv_generic: support sub-channels")
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/uio/uio_hv_generic.c

index a9d7be4b964f1bdb0838f14bf5aa1590bbbfb899..c690d100adcd075b2999b82443b08e4ce03c2b53 100644 (file)
@@ -19,7 +19,7 @@
  * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
  *    > /sys/bus/vmbus/drivers/uio_hv_generic/bind
  */
-
+#define DEBUG 1
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/device.h>
@@ -122,54 +122,23 @@ static void hv_uio_rescind(struct vmbus_channel *channel)
        uio_event_notify(&pdata->info);
 }
 
-/*
- * Handle fault when looking for sub channel ring buffer
- * Subchannel ring buffer is same as resource 0 which is main ring buffer
- * This is derived from uio_vma_fault
+/* Sysfs API to allow mmap of the ring buffers
+ * The ring buffer is allocated as contiguous memory by vmbus_open
  */
-static int hv_uio_vma_fault(struct vm_fault *vmf)
-{
-       struct vm_area_struct *vma = vmf->vma;
-       void *ring_buffer = vma->vm_private_data;
-       struct page *page;
-       void *addr;
-
-       addr = ring_buffer + (vmf->pgoff << PAGE_SHIFT);
-       page = virt_to_page(addr);
-       get_page(page);
-       vmf->page = page;
-       return 0;
-}
-
-static const struct vm_operations_struct hv_uio_vm_ops = {
-       .fault = hv_uio_vma_fault,
-};
-
-/* Sysfs API to allow mmap of the ring buffers */
 static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj,
                            struct bin_attribute *attr,
                            struct vm_area_struct *vma)
 {
        struct vmbus_channel *channel
                = container_of(kobj, struct vmbus_channel, kobj);
-       unsigned long requested_pages, actual_pages;
-
-       if (vma->vm_end < vma->vm_start)
-               return -EINVAL;
+       struct hv_device *dev = channel->primary_channel->device_obj;
+       u16 q_idx = channel->offermsg.offer.sub_channel_index;
 
-       /* only allow 0 for now */
-       if (vma->vm_pgoff > 0)
-               return -EINVAL;
+       dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
+               q_idx, vma_pages(vma), vma->vm_pgoff);
 
-       requested_pages = vma_pages(vma);
-       actual_pages = 2 * HV_RING_SIZE;
-       if (requested_pages > actual_pages)
-               return -EINVAL;
-
-       vma->vm_private_data = channel->ringbuffer_pages;
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
-       vma->vm_ops = &hv_uio_vm_ops;
-       return 0;
+       return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages),
+                              channel->ringbuffer_pagecount << PAGE_SHIFT);
 }
 
 static const struct bin_attribute ring_buffer_bin_attr = {