Re: [PATCH v3,1/3] driver: rpmon: new driver Remote Processor Monitor
From: Greg KH
Date: Tue Apr 28 2020 - 08:57:21 EST
On Mon, Apr 13, 2020 at 08:59:47PM -0700, Wang Wenhu wrote:
> RPMON is a driver framework. It supports remote processor monitor
> from user level. The basic components are a character device
> with sysfs interfaces for user space communication and different
> kinds of message drivers introduced modularly, which are used to
> communicate with remote processors.
>
> As for user space, one can get notifications of different events
> of remote processors, like their registrations, through standard
> file read operation of the file descriptors related to the exported
> character devices. Actions can also be taken into account via
> standard write operations to the devices. Besides, the sysfs class
> attributes could be accessed conveniently.
>
> Message drivers act as engines to communicate with remote processors.
> Currently RPMON_QMI is available which uses QMI infrastructures
> on Qualcomm SoC Platforms.
>
> Cc: Andy Gross <agross@xxxxxxxxxx>
> Cc: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>
> Cc: Ohad Ben-Cohen <ohad@xxxxxxxxxx>
> Cc: linux-remoteproc@xxxxxxxxxxxxxxx
> Cc: linux-arm-msm@xxxxxxxxxxxxxxx
> Signed-off-by: Wang Wenhu <wenhu.wang@xxxxxxxx>
> ---
> Changes since v1:
> - Addressed review comments from Randy
> Changes since v2:
> - Log message typo
> - Added Cc list
> ---
> drivers/Kconfig | 2 +
> drivers/Makefile | 1 +
> drivers/rpmon/Kconfig | 26 +++
> drivers/rpmon/Makefile | 1 +
> drivers/rpmon/rpmon.c | 506 +++++++++++++++++++++++++++++++++++++++++
> include/linux/rpmon.h | 68 ++++++
> 6 files changed, 604 insertions(+)
> create mode 100644 drivers/rpmon/Kconfig
> create mode 100644 drivers/rpmon/Makefile
> create mode 100644 drivers/rpmon/rpmon.c
> create mode 100644 include/linux/rpmon.h
You create a bunch of sysfs files, but you do not have any
Documentation/ABI/ updates showing what those files are for? Please fix
that up.
> +config RPMON
> + tristate "Remote Processor Monitor Core Framework"
> + help
> + RPMON is a driver framework. It supports remote processor monitor
> + from user level. The basic components are a character device
> + with sysfs interfaces for user space communication and different
> + kinds of message drivers introduced modularly, which are used to
> + communicate with remote processors.
> +
> + As for user space, one can get notifications of different events
> + of remote processors, like their registrations, through standard
> + file read operation of the file descriptors related to the exported
> + character devices. Actions can also be taken into account via
> + standard write operations to the devices. Besides, the sysfs class
> + attributes could be accessed conveniently.
So you don't need the char dev node? The sysfs files are sufficient?
Or do they both do different things?
How does the user/kernel api work for the char node?
> +#define RPMON_MAX_DEVICES (1U << MINORBITS)
Why do you have a limit?
Why not just make it dynamic?
> +#define RPMON_NAME "rpmon"
> +
> +static int rpmon_major;
Why do you need a whole major for this? Why not use a misc device?
> +static struct cdev *rpmon_cdev;
> +static DEFINE_IDR(rpmon_idr);
> +static const struct file_operations rpmon_fops;
> +
> +/* Protect idr accesses */
> +static DEFINE_MUTEX(minor_lock);
Are you sure you need this?
> +
> +static ssize_t name_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct rpmon_device *rpmondev = dev_get_drvdata(dev);
> + int ret;
> +
> + mutex_lock(&rpmondev->info_lock);
> + if (!rpmondev->info) {
> + ret = -EINVAL;
> + dev_err(dev, "the device has been unregistered\n");
How can that happen in your sysfs file? Shouldn't the name be part of
the structure itself? And what's wrong with the default name in struct
device?
> +static ssize_t rpmon_read(struct file *filep, char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + struct rpmon_device *rpmondev = filep->private_data;
> + DECLARE_WAITQUEUE(wait, current);
> + ssize_t ret = 0;
> + u32 event;
> +
> + if (count != sizeof(u32))
> + return -EINVAL;
> +
> + add_wait_queue(&rpmondev->wait, &wait);
> +
> + do {
> + mutex_lock(&rpmondev->info_lock);
> + if (!rpmondev->info) {
> + ret = -EIO;
> + mutex_unlock(&rpmondev->info_lock);
> + break;
> + }
> + mutex_unlock(&rpmondev->info_lock);
> +
> + set_current_state(TASK_INTERRUPTIBLE);
> +
> + event = atomic_read(&rpmondev->event);
> + if (event) {
> + __set_current_state(TASK_RUNNING);
> + if (copy_to_user(buf, &event, count))
> + ret = -EFAULT;
> + else {
> + atomic_set(&rpmondev->event, 0);
> + ret = count;
> + }
> + break;
> + }
> +
> + if (filep->f_flags & O_NONBLOCK) {
> + ret = -EAGAIN;
> + break;
> + }
> +
> + if (signal_pending(current)) {
> + ret = -ERESTARTSYS;
> + break;
> + }
> + schedule();
> + } while (1);
> +
> + __set_current_state(TASK_RUNNING);
Are you _sure_ that is the right way to do this???
> + remove_wait_queue(&rpmondev->wait, &wait);
> +
> + return ret;
> +}
> +
> +static ssize_t rpmon_write(struct file *filep, const char __user *buf,
> + size_t count, loff_t *ppos)
> +{
> + struct rpmon_device *rpmondev = filep->private_data;
> + ssize_t ret;
> + u32 action;
> +
> + if (count != sizeof(u32))
> + return -EINVAL;
That's rude, how can you enforce userspace doing this? What about short
writes?
> +
> + if (copy_from_user(&action, buf, count))
> + return -EFAULT;
> +
> + mutex_lock(&rpmondev->info_lock);
> + if (!rpmondev->info) {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + if (!rpmondev->info->monitor) {
> + ret = -ENOTSUPP;
> + goto out;
> + }
> +
> + if (rpmondev->info->monitor)
> + ret = rpmondev->info->monitor(rpmondev->info, action);
> +out:
> + mutex_unlock(&rpmondev->info_lock);
> + return ret ? ret : sizeof(u32);
> +}
> +
> +static const struct file_operations rpmon_fops = {
> + .owner = THIS_MODULE,
> + .open = rpmon_open,
> + .read = rpmon_read,
> + .write = rpmon_write,
> + .poll = rpmon_poll,
> + .release = rpmon_release,
> +};
> +
> +static int rpmon_major_init(void)
> +{
> + static const char name[] = RPMON_NAME;
> + struct cdev *cdev = NULL;
> + dev_t rpmon_dev = 0;
> + int ret;
> +
> + ret = alloc_chrdev_region(&rpmon_dev, 0, RPMON_MAX_DEVICES, name);
> + if (ret)
> + goto out;
> +
> + ret = -ENOMEM;
> + cdev = cdev_alloc();
> + if (!cdev)
> + goto out_unregister;
> +
> + cdev->owner = THIS_MODULE;
> + cdev->ops = &rpmon_fops;
> + kobject_set_name(&cdev->kobj, "%s", name);
That doesn't do what you think it does :)
Just use a misc device please.
thanks,
greg k-h