Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: pxrc - fix freeing URB on device teardown

URB is the only resource that is not managed, and thus is destroyed too early,
before we unregister input device and stop URB in pxrc_close(). To fix it let's
install custom devm handler to free the URB at the right time in devm unwind
sequence.

Reviewed-by: Marcus Folkesson <marcus.folkesson@gmail.com>
Tested-by: Marcus Folkesson <marcus.folkesson@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+30 -36
+30 -36
drivers/input/joystick/pxrc.c
··· 119 119 mutex_unlock(&pxrc->pm_mutex); 120 120 } 121 121 122 + static void pxrc_free_urb(void *_pxrc) 123 + { 124 + struct pxrc *pxrc = _pxrc; 125 + 126 + usb_free_urb(pxrc->urb); 127 + } 128 + 122 129 static int pxrc_usb_init(struct pxrc *pxrc) 123 130 { 124 131 struct usb_device *udev = interface_to_usbdev(pxrc->intf); 125 132 struct usb_endpoint_descriptor *epirq; 126 133 unsigned int pipe; 127 - int retval; 134 + int error; 128 135 129 136 /* Set up the endpoint information */ 130 137 /* This device only has an interrupt endpoint */ 131 - retval = usb_find_common_endpoints(pxrc->intf->cur_altsetting, 132 - NULL, NULL, &epirq, NULL); 133 - if (retval) { 134 - dev_err(&pxrc->intf->dev, 135 - "Could not find endpoint\n"); 136 - goto error; 138 + error = usb_find_common_endpoints(pxrc->intf->cur_altsetting, 139 + NULL, NULL, &epirq, NULL); 140 + if (error) { 141 + dev_err(&pxrc->intf->dev, "Could not find endpoint\n"); 142 + return error; 137 143 } 138 144 139 145 pxrc->bsize = usb_endpoint_maxp(epirq); 140 146 pxrc->epaddr = epirq->bEndpointAddress; 141 147 pxrc->data = devm_kmalloc(&pxrc->intf->dev, pxrc->bsize, GFP_KERNEL); 142 - if (!pxrc->data) { 143 - retval = -ENOMEM; 144 - goto error; 145 - } 148 + if (!pxrc->data) 149 + return -ENOMEM; 146 150 147 151 usb_set_intfdata(pxrc->intf, pxrc); 148 152 usb_make_path(udev, pxrc->phys, sizeof(pxrc->phys)); 149 153 strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys)); 150 154 151 155 pxrc->urb = usb_alloc_urb(0, GFP_KERNEL); 152 - if (!pxrc->urb) { 153 - retval = -ENOMEM; 154 - goto error; 155 - } 156 + if (!pxrc->urb) 157 + return -ENOMEM; 158 + 159 + error = devm_add_action_or_reset(&pxrc->intf->dev, pxrc_free_urb, pxrc); 160 + if (error) 161 + return error; 156 162 157 163 pipe = usb_rcvintpipe(udev, pxrc->epaddr), 158 164 usb_fill_int_urb(pxrc->urb, udev, pipe, pxrc->data, pxrc->bsize, 159 165 pxrc_usb_irq, pxrc, 1); 160 166 161 - error: 162 - return retval; 163 - 164 - 167 + return 0; 165 168 } 166 169 167 170 static int pxrc_input_init(struct pxrc *pxrc) ··· 200 197 const struct usb_device_id *id) 201 198 { 202 199 struct pxrc *pxrc; 203 - int retval; 200 + int error; 204 201 205 202 pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL); 206 203 if (!pxrc) ··· 209 206 mutex_init(&pxrc->pm_mutex); 210 207 pxrc->intf = intf; 211 208 212 - retval = pxrc_usb_init(pxrc); 213 - if (retval) 214 - goto error; 209 + error = pxrc_usb_init(pxrc); 210 + if (error) 211 + return error; 215 212 216 - retval = pxrc_input_init(pxrc); 217 - if (retval) 218 - goto err_free_urb; 213 + error = pxrc_input_init(pxrc); 214 + if (error) 215 + return error; 219 216 220 217 return 0; 221 - 222 - err_free_urb: 223 - usb_free_urb(pxrc->urb); 224 - 225 - error: 226 - return retval; 227 218 } 228 219 229 220 static void pxrc_disconnect(struct usb_interface *intf) 230 221 { 231 - struct pxrc *pxrc = usb_get_intfdata(intf); 232 - 233 - usb_free_urb(pxrc->urb); 234 - usb_set_intfdata(intf, NULL); 222 + /* All driver resources are devm-managed. */ 235 223 } 236 224 237 225 static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)