The vhost_net (and vhost_sock) drivers create worker tasks to handle
the virtual queues. Provide a new ioctl VHOST_GET_VRING_WORKER_INFO that
can be used to determine the PID of these tasks so that, for example,
they can be pinned to specific CPU(s).

Signed-off-by: Nick Hudson <[email protected]>
Reviewed-by: Max Tottenham <[email protected]>
---
 drivers/vhost/net.c              |  5 +++++
 drivers/vhost/vhost.c            | 19 +++++++++++++++++++
 include/linux/sched/vhost_task.h |  2 ++
 include/uapi/linux/vhost.h       |  3 +++
 include/uapi/linux/vhost_types.h | 13 +++++++++++++
 kernel/vhost_task.c              | 12 ++++++++++++
 6 files changed, 54 insertions(+)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 35ded4330431..e86bd5d7d202 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -1804,6 +1804,11 @@ static long vhost_net_ioctl(struct file *f, unsigned int 
ioctl,
                return vhost_net_reset_owner(n);
        case VHOST_SET_OWNER:
                return vhost_net_set_owner(n);
+       case VHOST_GET_VRING_WORKER_INFO:
+               mutex_lock(&n->dev.mutex);
+               r = vhost_worker_ioctl(&n->dev, ioctl, argp);
+               mutex_unlock(&n->dev.mutex);
+               return r;
        default:
                mutex_lock(&n->dev.mutex);
                r = vhost_dev_ioctl(&n->dev, ioctl, argp);
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 8570fdf2e14a..20ad9d190dc3 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1012,6 +1012,7 @@ long vhost_worker_ioctl(struct vhost_dev *dev, unsigned 
int ioctl,
                        void __user *argp)
 {
        struct vhost_vring_worker ring_worker;
+       struct vhost_vring_worker_info ring_worker_info;
        struct vhost_worker_state state;
        struct vhost_worker *worker;
        struct vhost_virtqueue *vq;
@@ -1050,6 +1051,7 @@ long vhost_worker_ioctl(struct vhost_dev *dev, unsigned 
int ioctl,
        /* vring worker ioctls */
        case VHOST_ATTACH_VRING_WORKER:
        case VHOST_GET_VRING_WORKER:
+       case VHOST_GET_VRING_WORKER_INFO:
                break;
        default:
                return -ENOIOCTLCMD;
@@ -1082,6 +1084,23 @@ long vhost_worker_ioctl(struct vhost_dev *dev, unsigned 
int ioctl,
                if (copy_to_user(argp, &ring_worker, sizeof(ring_worker)))
                        ret = -EFAULT;
                break;
+       case VHOST_GET_VRING_WORKER_INFO:
+               worker = rcu_dereference_check(vq->worker,
+                                              lockdep_is_held(&dev->mutex));
+               if (!worker) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               memset(&ring_worker_info, 0, sizeof(ring_worker_info));
+               ring_worker_info.index = idx;
+               ring_worker_info.worker_id = worker->id;
+               ring_worker_info.worker_pid = 
task_pid_vnr(vhost_get_task(worker->vtsk));
+
+               if (copy_to_user(argp, &ring_worker_info, 
sizeof(ring_worker_info)))
+                       ret = -EFAULT;
+               break;
+
        default:
                ret = -ENOIOCTLCMD;
                break;
diff --git a/include/linux/sched/vhost_task.h b/include/linux/sched/vhost_task.h
index 25446c5d3508..568f9596f29e 100644
--- a/include/linux/sched/vhost_task.h
+++ b/include/linux/sched/vhost_task.h
@@ -11,4 +11,6 @@ void vhost_task_start(struct vhost_task *vtsk);
 void vhost_task_stop(struct vhost_task *vtsk);
 void vhost_task_wake(struct vhost_task *vtsk);
 
+struct task_struct *vhost_get_task(struct vhost_task *vtsk);
+
 #endif /* _LINUX_SCHED_VHOST_TASK_H */
diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h
index c57674a6aa0d..c32aa8c71952 100644
--- a/include/uapi/linux/vhost.h
+++ b/include/uapi/linux/vhost.h
@@ -101,6 +101,9 @@
 /* Return the vring worker's ID */
 #define VHOST_GET_VRING_WORKER _IOWR(VHOST_VIRTIO, 0x16,               \
                                     struct vhost_vring_worker)
+/* Return the vring worker's ID and PID */
+#define VHOST_GET_VRING_WORKER_INFO _IOWR(VHOST_VIRTIO, 0x17,  \
+                                    struct vhost_vring_worker_info)
 
 /* The following ioctls use eventfd file descriptors to signal and poll
  * for events. */
diff --git a/include/uapi/linux/vhost_types.h b/include/uapi/linux/vhost_types.h
index 1c39cc5f5a31..28e00f8ade85 100644
--- a/include/uapi/linux/vhost_types.h
+++ b/include/uapi/linux/vhost_types.h
@@ -63,6 +63,19 @@ struct vhost_vring_worker {
        unsigned int worker_id;
 };
 
+/* Per-virtqueue worker mapping entry */
+struct vhost_vring_worker_info {
+       /* vring index */
+       unsigned int index;
+       /*
+        * The id of the vhost_worker returned from VHOST_NEW_WORKER or
+        * allocated as part of vhost_dev_set_owner.
+        */
+       unsigned int worker_id;
+
+       __kernel_pid_t worker_pid;  /* PID/TID of worker thread, -1 if none */
+};
+
 /* no alignment requirement */
 struct vhost_iotlb_msg {
        __u64 iova;
diff --git a/kernel/vhost_task.c b/kernel/vhost_task.c
index 27107dcc1cbf..aa87a7f0c98a 100644
--- a/kernel/vhost_task.c
+++ b/kernel/vhost_task.c
@@ -67,6 +67,18 @@ static int vhost_task_fn(void *data)
        do_exit(0);
 }
 
+/**
+ * vhost_get_task - get a pointer to the vhost_task's task_struct
+ * @vtsk: vhost_task to return the task for
+ *
+ * return the vhost_task's task.
+ */
+struct task_struct *vhost_get_task(struct vhost_task *vtsk)
+{
+       return vtsk->task;
+}
+EXPORT_SYMBOL_GPL(vhost_get_task);
+
 /**
  * vhost_task_wake - wakeup the vhost_task
  * @vtsk: vhost_task to wake
-- 
2.34.1


Reply via email to