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 Reviewed-by: Max Tottenham --- 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