aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <stephen@networkplumber.org>2018-04-16 14:19:27 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-23 06:43:48 -0400
commitce3d1536acabbdcdc3c945c3c078dd4ed1b8edfa (patch)
tree89e619b2d2e172d1d78e9a7af4f3e2db0a953527
parent135db384a2efde3718fd551e3968e97fcb400c84 (diff)
uio_hv_generic: fix subchannel ring mmap
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>
-rw-r--r--drivers/uio/uio_hv_generic.c49
1 files changed, 9 insertions, 40 deletions
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index a9d7be4b964f..c690d100adcd 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -19,7 +19,7 @@
19 * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ 19 * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
20 * > /sys/bus/vmbus/drivers/uio_hv_generic/bind 20 * > /sys/bus/vmbus/drivers/uio_hv_generic/bind
21 */ 21 */
22 22#define DEBUG 1
23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24 24
25#include <linux/device.h> 25#include <linux/device.h>
@@ -122,54 +122,23 @@ static void hv_uio_rescind(struct vmbus_channel *channel)
122 uio_event_notify(&pdata->info); 122 uio_event_notify(&pdata->info);
123} 123}
124 124
125/* 125/* Sysfs API to allow mmap of the ring buffers
126 * Handle fault when looking for sub channel ring buffer 126 * The ring buffer is allocated as contiguous memory by vmbus_open
127 * Subchannel ring buffer is same as resource 0 which is main ring buffer
128 * This is derived from uio_vma_fault
129 */ 127 */
130static int hv_uio_vma_fault(struct vm_fault *vmf)
131{
132 struct vm_area_struct *vma = vmf->vma;
133 void *ring_buffer = vma->vm_private_data;
134 struct page *page;
135 void *addr;
136
137 addr = ring_buffer + (vmf->pgoff << PAGE_SHIFT);
138 page = virt_to_page(addr);
139 get_page(page);
140 vmf->page = page;
141 return 0;
142}
143
144static const struct vm_operations_struct hv_uio_vm_ops = {
145 .fault = hv_uio_vma_fault,
146};
147
148/* Sysfs API to allow mmap of the ring buffers */
149static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, 128static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj,
150 struct bin_attribute *attr, 129 struct bin_attribute *attr,
151 struct vm_area_struct *vma) 130 struct vm_area_struct *vma)
152{ 131{
153 struct vmbus_channel *channel 132 struct vmbus_channel *channel
154 = container_of(kobj, struct vmbus_channel, kobj); 133 = container_of(kobj, struct vmbus_channel, kobj);
155 unsigned long requested_pages, actual_pages; 134 struct hv_device *dev = channel->primary_channel->device_obj;
156 135 u16 q_idx = channel->offermsg.offer.sub_channel_index;
157 if (vma->vm_end < vma->vm_start)
158 return -EINVAL;
159 136
160 /* only allow 0 for now */ 137 dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
161 if (vma->vm_pgoff > 0) 138 q_idx, vma_pages(vma), vma->vm_pgoff);
162 return -EINVAL;
163 139
164 requested_pages = vma_pages(vma); 140 return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages),
165 actual_pages = 2 * HV_RING_SIZE; 141 channel->ringbuffer_pagecount << PAGE_SHIFT);
166 if (requested_pages > actual_pages)
167 return -EINVAL;
168
169 vma->vm_private_data = channel->ringbuffer_pages;
170 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
171 vma->vm_ops = &hv_uio_vm_ops;
172 return 0;
173} 142}
174 143
175static const struct bin_attribute ring_buffer_bin_attr = { 144static const struct bin_attribute ring_buffer_bin_attr = {