diff options
| -rw-r--r-- | drivers/usb/usbip/stub.h | 2 | ||||
| -rw-r--r-- | drivers/usb/usbip/stub_dev.c | 33 | ||||
| -rw-r--r-- | drivers/usb/usbip/stub_main.c | 40 |
3 files changed, 60 insertions, 15 deletions
diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h index 14a72357800a..35618ceb2791 100644 --- a/drivers/usb/usbip/stub.h +++ b/drivers/usb/usbip/stub.h | |||
| @@ -73,6 +73,7 @@ struct bus_id_priv { | |||
| 73 | struct stub_device *sdev; | 73 | struct stub_device *sdev; |
| 74 | struct usb_device *udev; | 74 | struct usb_device *udev; |
| 75 | char shutdown_busid; | 75 | char shutdown_busid; |
| 76 | spinlock_t busid_lock; | ||
| 76 | }; | 77 | }; |
| 77 | 78 | ||
| 78 | /* stub_priv is allocated from stub_priv_cache */ | 79 | /* stub_priv is allocated from stub_priv_cache */ |
| @@ -83,6 +84,7 @@ extern struct usb_device_driver stub_driver; | |||
| 83 | 84 | ||
| 84 | /* stub_main.c */ | 85 | /* stub_main.c */ |
| 85 | struct bus_id_priv *get_busid_priv(const char *busid); | 86 | struct bus_id_priv *get_busid_priv(const char *busid); |
| 87 | void put_busid_priv(struct bus_id_priv *bid); | ||
| 86 | int del_match_busid(char *busid); | 88 | int del_match_busid(char *busid); |
| 87 | void stub_device_cleanup_urbs(struct stub_device *sdev); | 89 | void stub_device_cleanup_urbs(struct stub_device *sdev); |
| 88 | 90 | ||
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index 9d0425113c4b..c0d6ff1baa72 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c | |||
| @@ -300,7 +300,7 @@ static int stub_probe(struct usb_device *udev) | |||
| 300 | struct stub_device *sdev = NULL; | 300 | struct stub_device *sdev = NULL; |
| 301 | const char *udev_busid = dev_name(&udev->dev); | 301 | const char *udev_busid = dev_name(&udev->dev); |
| 302 | struct bus_id_priv *busid_priv; | 302 | struct bus_id_priv *busid_priv; |
| 303 | int rc; | 303 | int rc = 0; |
| 304 | 304 | ||
| 305 | dev_dbg(&udev->dev, "Enter probe\n"); | 305 | dev_dbg(&udev->dev, "Enter probe\n"); |
| 306 | 306 | ||
| @@ -317,13 +317,15 @@ static int stub_probe(struct usb_device *udev) | |||
| 317 | * other matched drivers by the driver core. | 317 | * other matched drivers by the driver core. |
| 318 | * See driver_probe_device() in driver/base/dd.c | 318 | * See driver_probe_device() in driver/base/dd.c |
| 319 | */ | 319 | */ |
| 320 | return -ENODEV; | 320 | rc = -ENODEV; |
| 321 | goto call_put_busid_priv; | ||
| 321 | } | 322 | } |
| 322 | 323 | ||
| 323 | if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) { | 324 | if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) { |
| 324 | dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n", | 325 | dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n", |
| 325 | udev_busid); | 326 | udev_busid); |
| 326 | return -ENODEV; | 327 | rc = -ENODEV; |
| 328 | goto call_put_busid_priv; | ||
| 327 | } | 329 | } |
| 328 | 330 | ||
| 329 | if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { | 331 | if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { |
| @@ -331,13 +333,16 @@ static int stub_probe(struct usb_device *udev) | |||
| 331 | "%s is attached on vhci_hcd... skip!\n", | 333 | "%s is attached on vhci_hcd... skip!\n", |
| 332 | udev_busid); | 334 | udev_busid); |
| 333 | 335 | ||
| 334 | return -ENODEV; | 336 | rc = -ENODEV; |
| 337 | goto call_put_busid_priv; | ||
| 335 | } | 338 | } |
| 336 | 339 | ||
| 337 | /* ok, this is my device */ | 340 | /* ok, this is my device */ |
| 338 | sdev = stub_device_alloc(udev); | 341 | sdev = stub_device_alloc(udev); |
| 339 | if (!sdev) | 342 | if (!sdev) { |
| 340 | return -ENOMEM; | 343 | rc = -ENOMEM; |
| 344 | goto call_put_busid_priv; | ||
| 345 | } | ||
| 341 | 346 | ||
| 342 | dev_info(&udev->dev, | 347 | dev_info(&udev->dev, |
| 343 | "usbip-host: register new device (bus %u dev %u)\n", | 348 | "usbip-host: register new device (bus %u dev %u)\n", |
| @@ -369,7 +374,9 @@ static int stub_probe(struct usb_device *udev) | |||
| 369 | } | 374 | } |
| 370 | busid_priv->status = STUB_BUSID_ALLOC; | 375 | busid_priv->status = STUB_BUSID_ALLOC; |
| 371 | 376 | ||
| 372 | return 0; | 377 | rc = 0; |
| 378 | goto call_put_busid_priv; | ||
| 379 | |||
| 373 | err_files: | 380 | err_files: |
| 374 | usb_hub_release_port(udev->parent, udev->portnum, | 381 | usb_hub_release_port(udev->parent, udev->portnum, |
| 375 | (struct usb_dev_state *) udev); | 382 | (struct usb_dev_state *) udev); |
| @@ -379,6 +386,9 @@ err_port: | |||
| 379 | 386 | ||
| 380 | busid_priv->sdev = NULL; | 387 | busid_priv->sdev = NULL; |
| 381 | stub_device_free(sdev); | 388 | stub_device_free(sdev); |
| 389 | |||
| 390 | call_put_busid_priv: | ||
| 391 | put_busid_priv(busid_priv); | ||
| 382 | return rc; | 392 | return rc; |
| 383 | } | 393 | } |
| 384 | 394 | ||
| @@ -417,7 +427,7 @@ static void stub_disconnect(struct usb_device *udev) | |||
| 417 | /* get stub_device */ | 427 | /* get stub_device */ |
| 418 | if (!sdev) { | 428 | if (!sdev) { |
| 419 | dev_err(&udev->dev, "could not get device"); | 429 | dev_err(&udev->dev, "could not get device"); |
| 420 | return; | 430 | goto call_put_busid_priv; |
| 421 | } | 431 | } |
| 422 | 432 | ||
| 423 | dev_set_drvdata(&udev->dev, NULL); | 433 | dev_set_drvdata(&udev->dev, NULL); |
| @@ -432,12 +442,12 @@ static void stub_disconnect(struct usb_device *udev) | |||
| 432 | (struct usb_dev_state *) udev); | 442 | (struct usb_dev_state *) udev); |
| 433 | if (rc) { | 443 | if (rc) { |
| 434 | dev_dbg(&udev->dev, "unable to release port\n"); | 444 | dev_dbg(&udev->dev, "unable to release port\n"); |
| 435 | return; | 445 | goto call_put_busid_priv; |
| 436 | } | 446 | } |
| 437 | 447 | ||
| 438 | /* If usb reset is called from event handler */ | 448 | /* If usb reset is called from event handler */ |
| 439 | if (usbip_in_eh(current)) | 449 | if (usbip_in_eh(current)) |
| 440 | return; | 450 | goto call_put_busid_priv; |
| 441 | 451 | ||
| 442 | /* shutdown the current connection */ | 452 | /* shutdown the current connection */ |
| 443 | shutdown_busid(busid_priv); | 453 | shutdown_busid(busid_priv); |
| @@ -450,6 +460,9 @@ static void stub_disconnect(struct usb_device *udev) | |||
| 450 | 460 | ||
| 451 | if (busid_priv->status == STUB_BUSID_ALLOC) | 461 | if (busid_priv->status == STUB_BUSID_ALLOC) |
| 452 | busid_priv->status = STUB_BUSID_ADDED; | 462 | busid_priv->status = STUB_BUSID_ADDED; |
| 463 | |||
| 464 | call_put_busid_priv: | ||
| 465 | put_busid_priv(busid_priv); | ||
| 453 | } | 466 | } |
| 454 | 467 | ||
| 455 | #ifdef CONFIG_PM | 468 | #ifdef CONFIG_PM |
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 587b9bc10042..41c7b9de2a92 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c | |||
| @@ -26,6 +26,8 @@ static spinlock_t busid_table_lock; | |||
| 26 | 26 | ||
| 27 | static void init_busid_table(void) | 27 | static void init_busid_table(void) |
| 28 | { | 28 | { |
| 29 | int i; | ||
| 30 | |||
| 29 | /* | 31 | /* |
| 30 | * This also sets the bus_table[i].status to | 32 | * This also sets the bus_table[i].status to |
| 31 | * STUB_BUSID_OTHER, which is 0. | 33 | * STUB_BUSID_OTHER, which is 0. |
| @@ -33,6 +35,9 @@ static void init_busid_table(void) | |||
| 33 | memset(busid_table, 0, sizeof(busid_table)); | 35 | memset(busid_table, 0, sizeof(busid_table)); |
| 34 | 36 | ||
| 35 | spin_lock_init(&busid_table_lock); | 37 | spin_lock_init(&busid_table_lock); |
| 38 | |||
| 39 | for (i = 0; i < MAX_BUSID; i++) | ||
| 40 | spin_lock_init(&busid_table[i].busid_lock); | ||
| 36 | } | 41 | } |
| 37 | 42 | ||
| 38 | /* | 43 | /* |
| @@ -44,15 +49,20 @@ static int get_busid_idx(const char *busid) | |||
| 44 | int i; | 49 | int i; |
| 45 | int idx = -1; | 50 | int idx = -1; |
| 46 | 51 | ||
| 47 | for (i = 0; i < MAX_BUSID; i++) | 52 | for (i = 0; i < MAX_BUSID; i++) { |
| 53 | spin_lock(&busid_table[i].busid_lock); | ||
| 48 | if (busid_table[i].name[0]) | 54 | if (busid_table[i].name[0]) |
| 49 | if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { | 55 | if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { |
| 50 | idx = i; | 56 | idx = i; |
| 57 | spin_unlock(&busid_table[i].busid_lock); | ||
| 51 | break; | 58 | break; |
| 52 | } | 59 | } |
| 60 | spin_unlock(&busid_table[i].busid_lock); | ||
| 61 | } | ||
| 53 | return idx; | 62 | return idx; |
| 54 | } | 63 | } |
| 55 | 64 | ||
| 65 | /* Returns holding busid_lock. Should call put_busid_priv() to unlock */ | ||
| 56 | struct bus_id_priv *get_busid_priv(const char *busid) | 66 | struct bus_id_priv *get_busid_priv(const char *busid) |
| 57 | { | 67 | { |
| 58 | int idx; | 68 | int idx; |
| @@ -60,13 +70,21 @@ struct bus_id_priv *get_busid_priv(const char *busid) | |||
| 60 | 70 | ||
| 61 | spin_lock(&busid_table_lock); | 71 | spin_lock(&busid_table_lock); |
| 62 | idx = get_busid_idx(busid); | 72 | idx = get_busid_idx(busid); |
| 63 | if (idx >= 0) | 73 | if (idx >= 0) { |
| 64 | bid = &(busid_table[idx]); | 74 | bid = &(busid_table[idx]); |
| 75 | /* get busid_lock before returning */ | ||
| 76 | spin_lock(&bid->busid_lock); | ||
| 77 | } | ||
| 65 | spin_unlock(&busid_table_lock); | 78 | spin_unlock(&busid_table_lock); |
| 66 | 79 | ||
| 67 | return bid; | 80 | return bid; |
| 68 | } | 81 | } |
| 69 | 82 | ||
| 83 | void put_busid_priv(struct bus_id_priv *bid) | ||
| 84 | { | ||
| 85 | spin_unlock(&bid->busid_lock); | ||
| 86 | } | ||
| 87 | |||
| 70 | static int add_match_busid(char *busid) | 88 | static int add_match_busid(char *busid) |
| 71 | { | 89 | { |
| 72 | int i; | 90 | int i; |
| @@ -79,15 +97,19 @@ static int add_match_busid(char *busid) | |||
| 79 | goto out; | 97 | goto out; |
| 80 | } | 98 | } |
| 81 | 99 | ||
| 82 | for (i = 0; i < MAX_BUSID; i++) | 100 | for (i = 0; i < MAX_BUSID; i++) { |
| 101 | spin_lock(&busid_table[i].busid_lock); | ||
| 83 | if (!busid_table[i].name[0]) { | 102 | if (!busid_table[i].name[0]) { |
| 84 | strlcpy(busid_table[i].name, busid, BUSID_SIZE); | 103 | strlcpy(busid_table[i].name, busid, BUSID_SIZE); |
| 85 | if ((busid_table[i].status != STUB_BUSID_ALLOC) && | 104 | if ((busid_table[i].status != STUB_BUSID_ALLOC) && |
| 86 | (busid_table[i].status != STUB_BUSID_REMOV)) | 105 | (busid_table[i].status != STUB_BUSID_REMOV)) |
| 87 | busid_table[i].status = STUB_BUSID_ADDED; | 106 | busid_table[i].status = STUB_BUSID_ADDED; |
| 88 | ret = 0; | 107 | ret = 0; |
| 108 | spin_unlock(&busid_table[i].busid_lock); | ||
| 89 | break; | 109 | break; |
| 90 | } | 110 | } |
| 111 | spin_unlock(&busid_table[i].busid_lock); | ||
| 112 | } | ||
| 91 | 113 | ||
| 92 | out: | 114 | out: |
| 93 | spin_unlock(&busid_table_lock); | 115 | spin_unlock(&busid_table_lock); |
| @@ -108,6 +130,8 @@ int del_match_busid(char *busid) | |||
| 108 | /* found */ | 130 | /* found */ |
| 109 | ret = 0; | 131 | ret = 0; |
| 110 | 132 | ||
| 133 | spin_lock(&busid_table[idx].busid_lock); | ||
| 134 | |||
| 111 | if (busid_table[idx].status == STUB_BUSID_OTHER) | 135 | if (busid_table[idx].status == STUB_BUSID_OTHER) |
| 112 | memset(busid_table[idx].name, 0, BUSID_SIZE); | 136 | memset(busid_table[idx].name, 0, BUSID_SIZE); |
| 113 | 137 | ||
| @@ -115,6 +139,7 @@ int del_match_busid(char *busid) | |||
| 115 | (busid_table[idx].status != STUB_BUSID_ADDED)) | 139 | (busid_table[idx].status != STUB_BUSID_ADDED)) |
| 116 | busid_table[idx].status = STUB_BUSID_REMOV; | 140 | busid_table[idx].status = STUB_BUSID_REMOV; |
| 117 | 141 | ||
| 142 | spin_unlock(&busid_table[idx].busid_lock); | ||
| 118 | out: | 143 | out: |
| 119 | spin_unlock(&busid_table_lock); | 144 | spin_unlock(&busid_table_lock); |
| 120 | 145 | ||
| @@ -127,9 +152,12 @@ static ssize_t match_busid_show(struct device_driver *drv, char *buf) | |||
| 127 | char *out = buf; | 152 | char *out = buf; |
| 128 | 153 | ||
| 129 | spin_lock(&busid_table_lock); | 154 | spin_lock(&busid_table_lock); |
| 130 | for (i = 0; i < MAX_BUSID; i++) | 155 | for (i = 0; i < MAX_BUSID; i++) { |
| 156 | spin_lock(&busid_table[i].busid_lock); | ||
| 131 | if (busid_table[i].name[0]) | 157 | if (busid_table[i].name[0]) |
| 132 | out += sprintf(out, "%s ", busid_table[i].name); | 158 | out += sprintf(out, "%s ", busid_table[i].name); |
| 159 | spin_unlock(&busid_table[i].busid_lock); | ||
| 160 | } | ||
| 133 | spin_unlock(&busid_table_lock); | 161 | spin_unlock(&busid_table_lock); |
| 134 | out += sprintf(out, "\n"); | 162 | out += sprintf(out, "\n"); |
| 135 | 163 | ||
| @@ -204,7 +232,7 @@ static void stub_device_rebind(void) | |||
| 204 | } | 232 | } |
| 205 | spin_unlock(&busid_table_lock); | 233 | spin_unlock(&busid_table_lock); |
| 206 | 234 | ||
| 207 | /* now run rebind */ | 235 | /* now run rebind - no need to hold locks. driver files are removed */ |
| 208 | for (i = 0; i < MAX_BUSID; i++) { | 236 | for (i = 0; i < MAX_BUSID; i++) { |
| 209 | if (busid_table[i].name[0] && | 237 | if (busid_table[i].name[0] && |
| 210 | busid_table[i].shutdown_busid) { | 238 | busid_table[i].shutdown_busid) { |
| @@ -234,6 +262,8 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, | |||
| 234 | 262 | ||
| 235 | /* mark the device for deletion so probe ignores it during rescan */ | 263 | /* mark the device for deletion so probe ignores it during rescan */ |
| 236 | bid->status = STUB_BUSID_OTHER; | 264 | bid->status = STUB_BUSID_OTHER; |
| 265 | /* release the busid lock */ | ||
| 266 | put_busid_priv(bid); | ||
| 237 | 267 | ||
| 238 | ret = do_rebind((char *) buf, bid); | 268 | ret = do_rebind((char *) buf, bid); |
| 239 | if (ret < 0) | 269 | if (ret < 0) |
