mirror of https://gitee.com/openkylin/linux.git
More virtio console fixes than I'm happy with, but all real issues,
and all CC:stable.. Thanks, Rusty. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJSAtjmAAoJENkgDmzRrbjxV/kP+wQaShGQ6Q8U7yYew7yZvo2H CE3VHpSkp3NnJfAqNMz/sCES7pAvYXvUM1hcVQ+GI1ZqVnN5yJViqeygIOU/xQEN WjslgtCvpdw0/R3dL4oxhcIMdgBioP9hknB56WPqHFZ9Ytb5GxPVf4wCNpd7FrsC iGHklImzN1r4AjxSTdbCCCk8iYKJOJRTAfZrtVtkc9uOU68GGBcAl8ArSPIScwEb 41JuuB/Qgja0ssCYpD5jrC74QePvU1eTgSQWs8Tgc6v43UNFjZyKWSY8G13MAd+l c3SCLCRqzPxpwhIhvAMQFnkmIlIqVpp66nnh6AqJt8Mw2ymSvP3AY5PMegV92Al+ afBofUz2KRPinGINe7SrrpRt/NU3SM+k1CWHeVu76U7V59f8ohxW9dLqI6otOrq+ 6GZx2Z9vyVkj4TP8vz4rNZINKXjRBaGhTNcQ0rM3obMFM4Dg+4dhF+PpGA8UyFwI 3Tw2c0zbVIqQ6fEO63ZYGhAdVNdlZoPA2tuA34hfY/D07842tgkPhuAF6yDeb4jg JmiERc506JpLws0Tu6E6H+x6LQAGr9cYPgBpvucab/SVa3bcrEJj2oqDt0pZaTiO q6HkkDwfoDVdv9TY3sCgOmKSUp/smkrloa3vMHLUZsnjx66iIPdHn+PcN/7Im8ut kfnKgLgo/BloWT0XeFv+ =ZV9B -----END PGP SIGNATURE----- Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux Pull virtio fixes from Rusty Russell: "More virtio console fixes than I'm happy with, but all real issues, and all CC:stable.." * tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: virtio-scsi: Fix virtqueue affinity setup virtio: console: return -ENODEV on all read operations after unplug virtio: console: fix raising SIGIO after port unplug virtio: console: clean up port data immediately at time of unplug virtio: console: fix race in port_fops_open() and port unplug virtio: console: fix race with port unplug and open/close virtio/console: Add pipe_lock/unlock for splice_write virtio/console: Quit from splice_write if pipe->nrbufs is 0
This commit is contained in:
commit
bb014db07c
|
@ -272,9 +272,12 @@ static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&portdev->ports_lock, flags);
|
spin_lock_irqsave(&portdev->ports_lock, flags);
|
||||||
list_for_each_entry(port, &portdev->ports, list)
|
list_for_each_entry(port, &portdev->ports, list) {
|
||||||
if (port->cdev->dev == dev)
|
if (port->cdev->dev == dev) {
|
||||||
|
kref_get(&port->kref);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
port = NULL;
|
port = NULL;
|
||||||
out:
|
out:
|
||||||
spin_unlock_irqrestore(&portdev->ports_lock, flags);
|
spin_unlock_irqrestore(&portdev->ports_lock, flags);
|
||||||
|
@ -746,6 +749,10 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
|
||||||
|
|
||||||
port = filp->private_data;
|
port = filp->private_data;
|
||||||
|
|
||||||
|
/* Port is hot-unplugged. */
|
||||||
|
if (!port->guest_connected)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (!port_has_data(port)) {
|
if (!port_has_data(port)) {
|
||||||
/*
|
/*
|
||||||
* If nothing's connected on the host just return 0 in
|
* If nothing's connected on the host just return 0 in
|
||||||
|
@ -762,7 +769,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/* Port got hot-unplugged. */
|
/* Port got hot-unplugged while we were waiting above. */
|
||||||
if (!port->guest_connected)
|
if (!port->guest_connected)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
/*
|
/*
|
||||||
|
@ -932,13 +939,25 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
|
||||||
if (is_rproc_serial(port->out_vq->vdev))
|
if (is_rproc_serial(port->out_vq->vdev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pipe->nrbufs == 0 means there are no data to transfer,
|
||||||
|
* so this returns just 0 for no data.
|
||||||
|
*/
|
||||||
|
pipe_lock(pipe);
|
||||||
|
if (!pipe->nrbufs) {
|
||||||
|
ret = 0;
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
|
ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto error_out;
|
||||||
|
|
||||||
buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
|
buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
|
||||||
if (!buf)
|
if (!buf) {
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
sgl.n = 0;
|
sgl.n = 0;
|
||||||
sgl.len = 0;
|
sgl.len = 0;
|
||||||
|
@ -946,12 +965,17 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
|
||||||
sgl.sg = buf->sg;
|
sgl.sg = buf->sg;
|
||||||
sg_init_table(sgl.sg, sgl.size);
|
sg_init_table(sgl.sg, sgl.size);
|
||||||
ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
|
ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
|
||||||
|
pipe_unlock(pipe);
|
||||||
if (likely(ret > 0))
|
if (likely(ret > 0))
|
||||||
ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
|
ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
|
||||||
|
|
||||||
if (unlikely(ret <= 0))
|
if (unlikely(ret <= 0))
|
||||||
free_buf(buf, true);
|
free_buf(buf, true);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
error_out:
|
||||||
|
pipe_unlock(pipe);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
|
static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
|
||||||
|
@ -1019,14 +1043,14 @@ static int port_fops_open(struct inode *inode, struct file *filp)
|
||||||
struct port *port;
|
struct port *port;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* We get the port with a kref here */
|
||||||
port = find_port_by_devt(cdev->dev);
|
port = find_port_by_devt(cdev->dev);
|
||||||
|
if (!port) {
|
||||||
|
/* Port was unplugged before we could proceed */
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
filp->private_data = port;
|
filp->private_data = port;
|
||||||
|
|
||||||
/* Prevent against a port getting hot-unplugged at the same time */
|
|
||||||
spin_lock_irq(&port->portdev->ports_lock);
|
|
||||||
kref_get(&port->kref);
|
|
||||||
spin_unlock_irq(&port->portdev->ports_lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't allow opening of console port devices -- that's done
|
* Don't allow opening of console port devices -- that's done
|
||||||
* via /dev/hvc
|
* via /dev/hvc
|
||||||
|
@ -1498,14 +1522,6 @@ static void remove_port(struct kref *kref)
|
||||||
|
|
||||||
port = container_of(kref, struct port, kref);
|
port = container_of(kref, struct port, kref);
|
||||||
|
|
||||||
sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
|
|
||||||
device_destroy(pdrvdata.class, port->dev->devt);
|
|
||||||
cdev_del(port->cdev);
|
|
||||||
|
|
||||||
kfree(port->name);
|
|
||||||
|
|
||||||
debugfs_remove(port->debugfs_file);
|
|
||||||
|
|
||||||
kfree(port);
|
kfree(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1539,12 +1555,14 @@ static void unplug_port(struct port *port)
|
||||||
spin_unlock_irq(&port->portdev->ports_lock);
|
spin_unlock_irq(&port->portdev->ports_lock);
|
||||||
|
|
||||||
if (port->guest_connected) {
|
if (port->guest_connected) {
|
||||||
port->guest_connected = false;
|
|
||||||
port->host_connected = false;
|
|
||||||
wake_up_interruptible(&port->waitqueue);
|
|
||||||
|
|
||||||
/* Let the app know the port is going down. */
|
/* Let the app know the port is going down. */
|
||||||
send_sigio_to_port(port);
|
send_sigio_to_port(port);
|
||||||
|
|
||||||
|
/* Do this after sigio is actually sent */
|
||||||
|
port->guest_connected = false;
|
||||||
|
port->host_connected = false;
|
||||||
|
|
||||||
|
wake_up_interruptible(&port->waitqueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_console_port(port)) {
|
if (is_console_port(port)) {
|
||||||
|
@ -1563,6 +1581,14 @@ static void unplug_port(struct port *port)
|
||||||
*/
|
*/
|
||||||
port->portdev = NULL;
|
port->portdev = NULL;
|
||||||
|
|
||||||
|
sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
|
||||||
|
device_destroy(pdrvdata.class, port->dev->devt);
|
||||||
|
cdev_del(port->cdev);
|
||||||
|
|
||||||
|
kfree(port->name);
|
||||||
|
|
||||||
|
debugfs_remove(port->debugfs_file);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locks around here are not necessary - a port can't be
|
* Locks around here are not necessary - a port can't be
|
||||||
* opened after we removed the port struct from ports_list
|
* opened after we removed the port struct from ports_list
|
||||||
|
|
|
@ -751,7 +751,7 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
|
||||||
|
|
||||||
vscsi->affinity_hint_set = true;
|
vscsi->affinity_hint_set = true;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++)
|
for (i = 0; i < vscsi->num_queues; i++)
|
||||||
virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
|
virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
|
||||||
|
|
||||||
vscsi->affinity_hint_set = false;
|
vscsi->affinity_hint_set = false;
|
||||||
|
|
Loading…
Reference in New Issue