]>
Commit | Line | Data |
---|---|---|
14e9555d GKH |
1 | From 3ea3091f1bd8586125848c62be295910e9802af0 Mon Sep 17 00:00:00 2001 |
2 | From: Shuah Khan <skhan@linuxfoundation.org> | |
3 | Date: Wed, 29 May 2019 13:46:15 -0600 | |
4 | Subject: usbip: usbip_host: fix stub_dev lock context imbalance regression | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Shuah Khan <skhan@linuxfoundation.org> | |
10 | ||
11 | commit 3ea3091f1bd8586125848c62be295910e9802af0 upstream. | |
12 | ||
13 | Fix the following sparse context imbalance regression introduced in | |
14 | a patch that fixed sleeping function called from invalid context bug. | |
15 | ||
16 | kbuild test robot reported on: | |
17 | ||
18 | tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-linus | |
19 | ||
20 | Regressions in current branch: | |
21 | ||
22 | drivers/usb/usbip/stub_dev.c:399:9: sparse: sparse: context imbalance in 'stub_probe' - different lock contexts for basic block | |
23 | drivers/usb/usbip/stub_dev.c:418:13: sparse: sparse: context imbalance in 'stub_disconnect' - different lock contexts for basic block | |
24 | drivers/usb/usbip/stub_dev.c:464:1-10: second lock on line 476 | |
25 | ||
26 | Error ids grouped by kconfigs: | |
27 | ||
28 | recent_errors | |
29 | ├── i386-allmodconfig | |
30 | │ └── drivers-usb-usbip-stub_dev.c:second-lock-on-line | |
31 | ├── x86_64-allmodconfig | |
32 | │ ├── drivers-usb-usbip-stub_dev.c:sparse:sparse:context-imbalance-in-stub_disconnect-different-lock-contexts-for-basic-block | |
33 | │ └── drivers-usb-usbip-stub_dev.c:sparse:sparse:context-imbalance-in-stub_probe-different-lock-contexts-for-basic-block | |
34 | └── x86_64-allyesconfig | |
35 | └── drivers-usb-usbip-stub_dev.c:second-lock-on-line | |
36 | ||
37 | This is a real problem in an error leg where spin_lock() is called on an | |
38 | already held lock. | |
39 | ||
40 | Fix the imbalance in stub_probe() and stub_disconnect(). | |
41 | ||
42 | Signed-off-by: Shuah Khan <skhan@linuxfoundation.org> | |
43 | Fixes: 0c9e8b3cad65 ("usbip: usbip_host: fix BUG: sleeping function called from invalid context") | |
44 | Cc: stable <stable@vger.kernel.org> | |
45 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
46 | ||
47 | --- | |
48 | drivers/usb/usbip/stub_dev.c | 36 +++++++++++++++++++++++------------- | |
49 | 1 file changed, 23 insertions(+), 13 deletions(-) | |
50 | ||
51 | --- a/drivers/usb/usbip/stub_dev.c | |
52 | +++ b/drivers/usb/usbip/stub_dev.c | |
53 | @@ -326,14 +326,17 @@ static int stub_probe(struct usb_device | |
54 | * See driver_probe_device() in driver/base/dd.c | |
55 | */ | |
56 | rc = -ENODEV; | |
57 | - goto sdev_free; | |
58 | + if (!busid_priv) | |
59 | + goto sdev_free; | |
60 | + | |
61 | + goto call_put_busid_priv; | |
62 | } | |
63 | ||
64 | if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) { | |
65 | dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n", | |
66 | udev_busid); | |
67 | rc = -ENODEV; | |
68 | - goto sdev_free; | |
69 | + goto call_put_busid_priv; | |
70 | } | |
71 | ||
72 | if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { | |
73 | @@ -342,7 +345,7 @@ static int stub_probe(struct usb_device | |
74 | udev_busid); | |
75 | ||
76 | rc = -ENODEV; | |
77 | - goto sdev_free; | |
78 | + goto call_put_busid_priv; | |
79 | } | |
80 | ||
81 | ||
82 | @@ -361,6 +364,9 @@ static int stub_probe(struct usb_device | |
83 | save_status = busid_priv->status; | |
84 | busid_priv->status = STUB_BUSID_ALLOC; | |
85 | ||
86 | + /* release the busid_lock */ | |
87 | + put_busid_priv(busid_priv); | |
88 | + | |
89 | /* | |
90 | * Claim this hub port. | |
91 | * It doesn't matter what value we pass as owner | |
92 | @@ -373,9 +379,6 @@ static int stub_probe(struct usb_device | |
93 | goto err_port; | |
94 | } | |
95 | ||
96 | - /* release the busid_lock */ | |
97 | - put_busid_priv(busid_priv); | |
98 | - | |
99 | rc = stub_add_files(&udev->dev); | |
100 | if (rc) { | |
101 | dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid); | |
102 | @@ -395,11 +398,17 @@ err_port: | |
103 | spin_lock(&busid_priv->busid_lock); | |
104 | busid_priv->sdev = NULL; | |
105 | busid_priv->status = save_status; | |
106 | -sdev_free: | |
107 | - stub_device_free(sdev); | |
108 | + spin_unlock(&busid_priv->busid_lock); | |
109 | + /* lock is released - go to free */ | |
110 | + goto sdev_free; | |
111 | + | |
112 | +call_put_busid_priv: | |
113 | /* release the busid_lock */ | |
114 | put_busid_priv(busid_priv); | |
115 | ||
116 | +sdev_free: | |
117 | + stub_device_free(sdev); | |
118 | + | |
119 | return rc; | |
120 | } | |
121 | ||
122 | @@ -435,7 +444,9 @@ static void stub_disconnect(struct usb_d | |
123 | /* get stub_device */ | |
124 | if (!sdev) { | |
125 | dev_err(&udev->dev, "could not get device"); | |
126 | - goto call_put_busid_priv; | |
127 | + /* release busid_lock */ | |
128 | + put_busid_priv(busid_priv); | |
129 | + return; | |
130 | } | |
131 | ||
132 | dev_set_drvdata(&udev->dev, NULL); | |
133 | @@ -465,7 +476,7 @@ static void stub_disconnect(struct usb_d | |
134 | if (!busid_priv->shutdown_busid) | |
135 | busid_priv->shutdown_busid = 1; | |
136 | /* release busid_lock */ | |
137 | - put_busid_priv(busid_priv); | |
138 | + spin_unlock(&busid_priv->busid_lock); | |
139 | ||
140 | /* shutdown the current connection */ | |
141 | shutdown_busid(busid_priv); | |
142 | @@ -480,10 +491,9 @@ static void stub_disconnect(struct usb_d | |
143 | ||
144 | if (busid_priv->status == STUB_BUSID_ALLOC) | |
145 | busid_priv->status = STUB_BUSID_ADDED; | |
146 | - | |
147 | -call_put_busid_priv: | |
148 | /* release busid_lock */ | |
149 | - put_busid_priv(busid_priv); | |
150 | + spin_unlock(&busid_priv->busid_lock); | |
151 | + return; | |
152 | } | |
153 | ||
154 | #ifdef CONFIG_PM |