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: 37b96a4931 ("uio_hv_generic: support sub-channels")
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Stephen Hemminger 2018-04-16 11:19:27 -07:00 коммит произвёл Greg Kroah-Hartman
Родитель 135db384a2
Коммит ce3d1536ac
1 изменённых файлов: 9 добавлений и 40 удалений

Просмотреть файл

@ -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;
struct hv_device *dev = channel->primary_channel->device_obj;
u16 q_idx = channel->offermsg.offer.sub_channel_index;
if (vma->vm_end < vma->vm_start)
return -EINVAL;
dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
q_idx, vma_pages(vma), vma->vm_pgoff);
/* only allow 0 for now */
if (vma->vm_pgoff > 0)
return -EINVAL;
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 = {