diff options
Diffstat (limited to 'drivers/usb/usbip/stub_dev.c')
| -rw-r--r-- | drivers/usb/usbip/stub_dev.c | 49 | 
1 files changed, 42 insertions, 7 deletions
| diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 2305d425e6c9..d8d3892e5a69 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -46,6 +46,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a  	int sockfd = 0;  	struct socket *socket;  	int rv; +	struct task_struct *tcp_rx = NULL; +	struct task_struct *tcp_tx = NULL;  	if (!sdev) {  		dev_err(dev, "sdev is null\n"); @@ -61,6 +63,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a  		dev_info(dev, "stub up\n"); +		mutex_lock(&sdev->ud.sysfs_lock);  		spin_lock_irq(&sdev->ud.lock);  		if (sdev->ud.status != SDEV_ST_AVAILABLE) { @@ -69,23 +72,49 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a  		}  		socket = sockfd_lookup(sockfd, &err); -		if (!socket) +		if (!socket) { +			dev_err(dev, "failed to lookup sock");  			goto err; +		} -		sdev->ud.tcp_socket = socket; -		sdev->ud.sockfd = sockfd; +		if (socket->type != SOCK_STREAM) { +			dev_err(dev, "Expecting SOCK_STREAM - found %d", +				socket->type); +			goto sock_err; +		} +		/* unlock and create threads and get tasks */  		spin_unlock_irq(&sdev->ud.lock); +		tcp_rx = kthread_create(stub_rx_loop, &sdev->ud, "stub_rx"); +		if (IS_ERR(tcp_rx)) { +			sockfd_put(socket); +			goto unlock_mutex; +		} +		tcp_tx = kthread_create(stub_tx_loop, &sdev->ud, "stub_tx"); +		if (IS_ERR(tcp_tx)) { +			kthread_stop(tcp_rx); +			sockfd_put(socket); +			goto unlock_mutex; +		} -		sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, -						  "stub_rx"); -		sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, -						  "stub_tx"); +		/* get task structs now */ +		get_task_struct(tcp_rx); +		get_task_struct(tcp_tx); +		/* lock and update sdev->ud state */  		spin_lock_irq(&sdev->ud.lock); +		sdev->ud.tcp_socket = socket; +		sdev->ud.sockfd = sockfd; +		sdev->ud.tcp_rx = tcp_rx; +		sdev->ud.tcp_tx = tcp_tx;  		sdev->ud.status = SDEV_ST_USED;  		spin_unlock_irq(&sdev->ud.lock); +		wake_up_process(sdev->ud.tcp_rx); +		wake_up_process(sdev->ud.tcp_tx); + +		mutex_unlock(&sdev->ud.sysfs_lock); +  	} else {  		dev_info(dev, "stub down\n"); @@ -96,12 +125,17 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a  		spin_unlock_irq(&sdev->ud.lock);  		usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN); +		mutex_unlock(&sdev->ud.sysfs_lock);  	}  	return count; +sock_err: +	sockfd_put(socket);  err:  	spin_unlock_irq(&sdev->ud.lock); +unlock_mutex: +	mutex_unlock(&sdev->ud.sysfs_lock);  	return -EINVAL;  }  static DEVICE_ATTR_WO(usbip_sockfd); @@ -242,6 +276,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)  	sdev->ud.side		= USBIP_STUB;  	sdev->ud.status		= SDEV_ST_AVAILABLE;  	spin_lock_init(&sdev->ud.lock); +	mutex_init(&sdev->ud.sysfs_lock);  	sdev->ud.tcp_socket	= NULL;  	sdev->ud.sockfd		= -1; |