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

USB: whci-hcd: check return value of usb_hcd_link_urb_to_ep()

Check the return value of usb_hcd_link_urb_to_ep() and do not add the
urb to the ASL/PZL if it returns an error.

Omitting the check results in urbs that appear to be submitted
successfully but then cannot be unliked (because
usb_hcd_check_unlink_urb() returns an error). This can cause khubd (for
example) to block forever in usb_kill_urb().

Signed-off-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

David Vrabel and committed by
Greg Kroah-Hartman
f720af91 7f0406db

+18 -6
+9 -3
drivers/usb/host/whci/asl.c
··· 255 255 256 256 spin_lock_irqsave(&whc->lock, flags); 257 257 258 + err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); 259 + if (err < 0) { 260 + spin_unlock_irqrestore(&whc->lock, flags); 261 + return err; 262 + } 263 + 258 264 qset = get_qset(whc, urb, GFP_ATOMIC); 259 265 if (qset == NULL) 260 266 err = -ENOMEM; 261 267 else 262 268 err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); 263 269 if (!err) { 264 - usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); 265 270 if (!qset->in_sw_list) 266 271 asl_qset_insert_begin(whc, qset); 267 - } 272 + } else 273 + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); 268 274 269 275 spin_unlock_irqrestore(&whc->lock, flags); 270 276 271 277 if (!err) 272 278 queue_work(whc->workqueue, &whc->async_work); 273 279 274 - return 0; 280 + return err; 275 281 } 276 282 277 283 /**
+9 -3
drivers/usb/host/whci/pzl.c
··· 283 283 284 284 spin_lock_irqsave(&whc->lock, flags); 285 285 286 + err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); 287 + if (err < 0) { 288 + spin_unlock_irqrestore(&whc->lock, flags); 289 + return err; 290 + } 291 + 286 292 qset = get_qset(whc, urb, GFP_ATOMIC); 287 293 if (qset == NULL) 288 294 err = -ENOMEM; 289 295 else 290 296 err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); 291 297 if (!err) { 292 - usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); 293 298 if (!qset->in_sw_list) 294 299 qset_insert_in_sw_list(whc, qset); 295 - } 300 + } else 301 + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); 296 302 297 303 spin_unlock_irqrestore(&whc->lock, flags); 298 304 299 305 if (!err) 300 306 queue_work(whc->workqueue, &whc->periodic_work); 301 307 302 - return 0; 308 + return err; 303 309 } 304 310 305 311 /**