Commit 1f7aa42d166cd104b0700d61efe2064178a3f6da
Committed by
Rusty Russell
1 parent
7f5d810dac
Exists in
master
and in
41 other branches
virtio: console: Add ability to hot-unplug ports
Remove port data; deregister from the hvc core if it's a console port. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Showing 2 changed files with 64 additions and 2 deletions Side-by-side Diff
drivers/char/virtio_console.c
... | ... | @@ -783,6 +783,36 @@ |
783 | 783 | .attrs = port_sysfs_entries, |
784 | 784 | }; |
785 | 785 | |
786 | +/* Remove all port-specific data. */ | |
787 | +static int remove_port(struct port *port) | |
788 | +{ | |
789 | + spin_lock_irq(&port->portdev->ports_lock); | |
790 | + list_del(&port->list); | |
791 | + spin_unlock_irq(&port->portdev->ports_lock); | |
792 | + | |
793 | + if (is_console_port(port)) { | |
794 | + spin_lock_irq(&pdrvdata_lock); | |
795 | + list_del(&port->cons.list); | |
796 | + spin_unlock_irq(&pdrvdata_lock); | |
797 | + hvc_remove(port->cons.hvc); | |
798 | + } | |
799 | + if (port->guest_connected) | |
800 | + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); | |
801 | + | |
802 | + while (port->in_vq->vq_ops->detach_unused_buf(port->in_vq)) | |
803 | + ; | |
804 | + | |
805 | + sysfs_remove_group(&port->dev->kobj, &port_attribute_group); | |
806 | + device_destroy(pdrvdata.class, port->dev->devt); | |
807 | + cdev_del(&port->cdev); | |
808 | + | |
809 | + discard_port_data(port); | |
810 | + kfree(port->name); | |
811 | + | |
812 | + kfree(port); | |
813 | + return 0; | |
814 | +} | |
815 | + | |
786 | 816 | /* Any private messages that the Host and Guest want to share */ |
787 | 817 | static void handle_control_message(struct ports_device *portdev, |
788 | 818 | struct port_buffer *buf) |
... | ... | @@ -854,6 +884,32 @@ |
854 | 884 | err); |
855 | 885 | |
856 | 886 | break; |
887 | + case VIRTIO_CONSOLE_PORT_REMOVE: | |
888 | + /* | |
889 | + * Hot unplug the port. We don't decrement nr_ports | |
890 | + * since we don't want to deal with extra complexities | |
891 | + * of using the lowest-available port id: We can just | |
892 | + * pick up the nr_ports number as the id and not have | |
893 | + * userspace send it to us. This helps us in two | |
894 | + * ways: | |
895 | + * | |
896 | + * - We don't need to have a 'port_id' field in the | |
897 | + * config space when a port is hot-added. This is a | |
898 | + * good thing as we might queue up multiple hotplug | |
899 | + * requests issued in our workqueue. | |
900 | + * | |
901 | + * - Another way to deal with this would have been to | |
902 | + * use a bitmap of the active ports and select the | |
903 | + * lowest non-active port from that map. That | |
904 | + * bloats the already tight config space and we | |
905 | + * would end up artificially limiting the | |
906 | + * max. number of ports to sizeof(bitmap). Right | |
907 | + * now we can support 2^32 ports (as the port id is | |
908 | + * stored in a u32 type). | |
909 | + * | |
910 | + */ | |
911 | + remove_port(port); | |
912 | + break; | |
857 | 913 | } |
858 | 914 | } |
859 | 915 | |
860 | 916 | |
... | ... | @@ -1078,12 +1134,17 @@ |
1078 | 1134 | /* |
1079 | 1135 | * Port 0 got hot-added. Since we already did all the |
1080 | 1136 | * other initialisation for it, just tell the Host |
1081 | - * that the port is ready. | |
1137 | + * that the port is ready if we find the port. In | |
1138 | + * case the port was hot-removed earlier, we call | |
1139 | + * add_port to add the port. | |
1082 | 1140 | */ |
1083 | 1141 | struct port *port; |
1084 | 1142 | |
1085 | 1143 | port = find_port_by_id(portdev, 0); |
1086 | - send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | |
1144 | + if (!port) | |
1145 | + add_port(portdev, 0); | |
1146 | + else | |
1147 | + send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | |
1087 | 1148 | return; |
1088 | 1149 | } |
1089 | 1150 | if (virtconconf.nr_ports > portdev->config.max_nr_ports) { |
include/linux/virtio_console.h