RE: [EXTERNAL] Re: [PATCH v2 1/5] uio: Add hv_vmbus_client driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Greg KH <gregkh@xxxxxxxxxxxxxxxxxxx>
> Sent: Thursday, June 15, 2023 2:43 AM
> To: Saurabh Sengar <ssengar@xxxxxxxxxxxxxxxxxxx>
> Cc: KY Srinivasan <kys@xxxxxxxxxxxxx>; Haiyang Zhang
> <haiyangz@xxxxxxxxxxxxx>; wei.liu@xxxxxxxxxx; Dexuan Cui
> <decui@xxxxxxxxxxxxx>; Michael Kelley (LINUX) <mikelley@xxxxxxxxxxxxx>;
> corbet@xxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; linux-hyperv@xxxxxxxxxxxxxxx;
> linux-doc@xxxxxxxxxxxxxxx
> Subject: [EXTERNAL] Re: [PATCH v2 1/5] uio: Add hv_vmbus_client driver
> 
> On Wed, Jun 14, 2023 at 11:15:08AM -0700, Saurabh Sengar wrote:
> > --- a/Documentation/ABI/stable/sysfs-bus-vmbus
> > +++ b/Documentation/ABI/stable/sysfs-bus-vmbus
> > @@ -153,6 +153,13 @@ Contact:	Stephen Hemminger
> <sthemmin@xxxxxxxxxxxxx>
> >  Description:	Binary file created by uio_hv_generic for ring buffer
> >  Users:		Userspace drivers
> >
> > +What:		/sys/bus/vmbus/devices/<UUID>/ring_size
> > +Date:		June. 2023
> 
> No need for the "."

OK

> 
> > +KernelVersion:	6.4
> 
> 6.4 will be released without this, sorry.

Ok will change it to 6.5.

> 
> > +Contact:	Saurabh Sengar <ssengar@xxxxxxxxxxxxx>
> > +Description:	File created by uio_hv_vmbus_client for setting device ring
> buffer size
> > +Users:		Userspace drivers
> > +
> >  What:           /sys/bus/vmbus/devices/<UUID>/channels/<N>/intr_in_full
> >  Date:           February 2019
> >  KernelVersion:  5.0
> > diff --git a/Documentation/driver-api/uio-howto.rst
> > b/Documentation/driver-api/uio-howto.rst
> > index 907ffa3b38f5..33b67f876b96 100644
> > --- a/Documentation/driver-api/uio-howto.rst
> > +++ b/Documentation/driver-api/uio-howto.rst
> > @@ -722,6 +722,52 @@ For example::
> >
> >
> > /sys/bus/vmbus/devices/3811fe4d-0fa0-4b62-981a-
> 74fc1084c757/channels/2
> > 1/ring
> >
> > +Generic Hyper-V driver for low speed devices
> > +============================================
> > +
> > +The generic driver is a kernel module named uio_hv_vmbus_client. It
> > +supports slow devices on the Hyper-V VMBus similar to uio_hv_generic
> > +for faster devices. This driver also gives flexibility of customized
> > +ring buffer sizes.
> > +
> > +Making the driver recognize the device
> > +--------------------------------------
> > +
> > +Since the driver does not declare any device GUID's, it will not get
> > +loaded automatically and will not automatically bind to any devices,
> > +you must load it and allocate id to the driver yourself. For example,
> > +to use the fcopy device class GUID::
> > +
> > +        DEV_UUID=eb765408-105f-49b6-b4aa-c123b64d17d4
> > +        driverctl -b vmbus set-override $DEV_UUID uio_hv_vmbus_client
> 
> Why are you adding a dependancy on a 300 line bash script that is not used
> by most distros?
> 
> Why not just show the "real" commands that you can use here that don't
> require an external tool not controlled by the kernel at all.

Ok will mention the regular  "echo" commands as you suggested.

> 
> > --- /dev/null
> > +++ b/drivers/uio/uio_hv_vmbus_client.c
> > @@ -0,0 +1,217 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * uio_hv_vmbus_client - UIO driver for low speed VMBus devices
> > + *
> > + * Copyright (c) 2023, Microsoft Corporation.
> > + *
> > + * Authors:
> > + *   Saurabh Sengar <ssengar@xxxxxxxxxxxxx>
> > + *
> > + * Since the driver does not declare any device ids, you must
> > +allocate
> > + * id and bind the device to the driver yourself.  For example:
> > + * driverctl -b vmbus set-override <dev uuid> uio_hv_vmbus_client
> 
> Again, no need to discuss driverctl.

Noted.

> 
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/uio_driver.h>
> > +#include <linux/hyperv.h>
> > +
> > +#define DRIVER_AUTHOR	"Saurabh Sengar <ssengar@xxxxxxxxxxxxx>"
> > +#define DRIVER_DESC	"Generic UIO driver for low speed VMBus
> devices"
> 
> You only use these defines in one place, so why not just spell them out there,
> no need for 2 extra lines, right?

Sure, will fix

> 
> > +
> > +#define DEFAULT_HV_RING_SIZE	VMBUS_RING_SIZE(3 *
> HV_HYP_PAGE_SIZE)
> > +static int ring_size = DEFAULT_HV_RING_SIZE;
> 
> You only use that #define in one place, why have it at all?

Ok, will fix

> 
> And you are defining a "global" variable that can be modified by an individual
> sysfs file for ANY device bound to this driver, messing with the other device's
> ring buffer size, right?  This needs to be per-device, or explain in huge detail
> here why not.

The global variable is expected to be set by userspace per device before opening, the
particular uio device. For a particular Hyper-v device this value be same, and once
device is open the ring buffer is allocated and there won't be any impact afterwards
changing it. I can elaborate more of this in sysfs documentation.

> 
> > +
> > +struct uio_hv_vmbus_dev {
> > +	struct uio_info info;
> > +	struct hv_device *device;
> > +};
> > +
> > +/* Sysfs API to allow mmap of the ring buffers */ static int
> > +uio_hv_vmbus_mmap(struct file *filp, struct kobject *kobj,
> > +			     struct bin_attribute *attr, struct vm_area_struct
> *vma) {
> > +	struct device *dev = container_of(kobj, struct device, kobj);
> > +	struct hv_device *hv_dev = container_of(dev, struct hv_device,
> device);
> > +	struct vmbus_channel *channel = hv_dev->channel;
> > +	void *ring_buffer = page_address(channel->ringbuffer_page);
> > +
> > +	return vm_iomap_memory(vma, virt_to_phys(ring_buffer),
> > +			       channel->ringbuffer_pagecount << PAGE_SHIFT); }
> > +
> > +static const struct bin_attribute ring_buffer_bin_attr = {
> > +	.attr = {
> > +		.name = "ringbuffer",
> > +		.mode = 0600,
> > +	},
> > +	.mmap = uio_hv_vmbus_mmap,
> > +};
> > +
> > +/*
> > + * This is the irqcontrol callback to be registered to uio_info.
> > + * It can be used to disable/enable interrupt from user space processes.
> > + *
> > + * @param info
> > + *  pointer to uio_info.
> > + * @param irq_state
> > + *  state value. 1 to enable interrupt, 0 to disable interrupt.
> > + */
> > +static int uio_hv_vmbus_irqcontrol(struct uio_info *info, s32
> > +irq_state) {
> > +	struct uio_hv_vmbus_dev *pdata = info->priv;
> > +	struct hv_device *hv_dev = pdata->device;
> > +
> > +	/* Issue a full memory barrier before triggering the notification */
> > +	virt_mb();
> > +
> > +	vmbus_setevent(hv_dev->channel);
> > +	return 0;
> > +}
> > +
> > +/*
> > + * Callback from vmbus_event when something is in inbound ring.
> > + */
> > +static void uio_hv_vmbus_channel_cb(void *context) {
> > +	struct uio_hv_vmbus_dev *pdata = context;
> > +
> > +	/* Issue a full memory barrier before sending the event to userspace
> */
> > +	virt_mb();
> > +
> > +	uio_event_notify(&pdata->info);
> > +}
> > +
> > +static int uio_hv_vmbus_open(struct uio_info *info, struct inode
> > +*inode) {
> > +	struct uio_hv_vmbus_dev *pdata = container_of(info, struct
> uio_hv_vmbus_dev, info);
> > +	struct hv_device *hv_dev = pdata->device;
> > +	struct vmbus_channel *channel = hv_dev->channel;
> > +	int ret;
> > +
> > +	ret = vmbus_open(channel, ring_size, ring_size, NULL, 0,
> > +			 uio_hv_vmbus_channel_cb, pdata);
> > +	if (ret) {
> > +		dev_err(&hv_dev->device, "error %d when opening the
> channel\n", ret);
> > +		return ret;
> > +	}
> > +	channel->inbound.ring_buffer->interrupt_mask = 0;
> > +	set_channel_read_mode(channel, HV_CALL_ISR);
> > +
> > +	ret = device_create_bin_file(&hv_dev->device,
> &ring_buffer_bin_attr);
> > +	if (ret)
> > +		dev_err(&hv_dev->device, "sysfs create ring bin file failed;
> %d\n",
> > +ret);
> > +
> > +	return ret;
> > +}
> > +
> > +/* VMbus primary channel is closed on last close */ static int
> > +uio_hv_vmbus_release(struct uio_info *info, struct inode *inode) {
> > +	struct uio_hv_vmbus_dev *pdata = container_of(info, struct
> uio_hv_vmbus_dev, info);
> > +	struct hv_device *hv_dev = pdata->device;
> > +	struct vmbus_channel *channel = hv_dev->channel;
> > +
> > +	device_remove_bin_file(&hv_dev->device, &ring_buffer_bin_attr);
> > +	vmbus_close(channel);
> > +
> > +	return 0;
> > +}
> > +
> > +static ssize_t ring_size_show(struct device *dev, struct device_attribute
> *attr,
> > +			      char *buf)
> > +{
> > +	return sysfs_emit(buf, "%d\n", ring_size); }
> > +
> > +static ssize_t ring_size_store(struct device *dev, struct device_attribute
> *attr,
> > +			       const char *buf, size_t count) {
> > +	unsigned int val;
> > +
> > +	if (kstrtouint(buf, 0, &val) < 0)
> > +		return -EINVAL;
> > +
> > +	if (val < HV_HYP_PAGE_SIZE)
> > +		return -EINVAL;
> > +
> > +	ring_size = val;
> > +
> > +	return count;
> > +}
> > +
> > +static DEVICE_ATTR_RW(ring_size);
> > +
> > +static struct attribute *uio_hv_vmbus_client_attrs[] = {
> > +	&dev_attr_ring_size.attr,
> > +	NULL,
> > +};
> > +ATTRIBUTE_GROUPS(uio_hv_vmbus_client);
> > +
> > +static int uio_hv_vmbus_probe(struct hv_device *dev, const struct
> > +hv_vmbus_device_id *dev_id) {
> > +	struct uio_hv_vmbus_dev *pdata;
> > +	int ret;
> > +	char *name = NULL;
> > +
> > +	pdata = devm_kzalloc(&dev->device, sizeof(*pdata), GFP_KERNEL);
> > +	if (!pdata)
> > +		return -ENOMEM;
> > +
> > +	name = kasprintf(GFP_KERNEL, "%pUl", &dev->dev_instance);
> > +
> > +	/* Fill general uio info */
> > +	pdata->info.name = name; /* /sys/class/uio/uioX/name */
> > +	pdata->info.version = "1";
> > +	pdata->info.irqcontrol = uio_hv_vmbus_irqcontrol;
> > +	pdata->info.open = uio_hv_vmbus_open;
> > +	pdata->info.release = uio_hv_vmbus_release;
> > +	pdata->info.irq = UIO_IRQ_CUSTOM;
> > +	pdata->info.priv = pdata;
> > +	pdata->device = dev;
> > +
> > +	ret = uio_register_device(&dev->device, &pdata->info);
> > +	if (ret) {
> > +		dev_err(&dev->device, "uio_hv_vmbus register failed\n");
> > +		return ret;
> > +	}
> > +
> > +	hv_set_drvdata(dev, pdata);
> > +
> > +	return 0;
> > +}
> > +
> > +static void uio_hv_vmbus_remove(struct hv_device *dev) {
> > +	struct uio_hv_vmbus_dev *pdata = hv_get_drvdata(dev);
> > +
> > +	if (pdata)
> > +		uio_unregister_device(&pdata->info);
> > +}
> > +
> > +static struct hv_driver uio_hv_vmbus_drv = {
> > +	.driver.dev_groups = uio_hv_vmbus_client_groups,
> > +	.name = "uio_hv_vmbus_client",
> > +	.id_table = NULL, /* only dynamic id's */
> 
> No need to set this if it's NULL.

Ok.

Thanks for your review.
- Saurabh

> 
> thanks,
> 
> greg k-h




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux