mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 12:44:11 +08:00
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:
parent
135db384a2
commit
ce3d1536ac
@ -19,7 +19,7 @@
|
|||||||
* # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
|
* # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \
|
||||||
* > /sys/bus/vmbus/drivers/uio_hv_generic/bind
|
* > /sys/bus/vmbus/drivers/uio_hv_generic/bind
|
||||||
*/
|
*/
|
||||||
|
#define DEBUG 1
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
@ -122,54 +122,23 @@ static void hv_uio_rescind(struct vmbus_channel *channel)
|
|||||||
uio_event_notify(&pdata->info);
|
uio_event_notify(&pdata->info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Sysfs API to allow mmap of the ring buffers
|
||||||
* Handle fault when looking for sub channel ring buffer
|
* The ring buffer is allocated as contiguous memory by vmbus_open
|
||||||
* Subchannel ring buffer is same as resource 0 which is main ring buffer
|
|
||||||
* This is derived from uio_vma_fault
|
|
||||||
*/
|
*/
|
||||||
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,
|
static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj,
|
||||||
struct bin_attribute *attr,
|
struct bin_attribute *attr,
|
||||||
struct vm_area_struct *vma)
|
struct vm_area_struct *vma)
|
||||||
{
|
{
|
||||||
struct vmbus_channel *channel
|
struct vmbus_channel *channel
|
||||||
= container_of(kobj, struct vmbus_channel, kobj);
|
= 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)
|
dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
|
||||||
return -EINVAL;
|
q_idx, vma_pages(vma), vma->vm_pgoff);
|
||||||
|
|
||||||
/* only allow 0 for now */
|
return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages),
|
||||||
if (vma->vm_pgoff > 0)
|
channel->ringbuffer_pagecount << PAGE_SHIFT);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct bin_attribute ring_buffer_bin_attr = {
|
static const struct bin_attribute ring_buffer_bin_attr = {
|
||||||
|
Loading…
Reference in New Issue
Block a user