Am Montag, 13. Januar 2003 16:16 schrieb Alan Stern: > On Mon, 13 Jan 2003, Oliver Neukum wrote: > > Let me explain. > > The first problem we avoid is with unloading. We want to be sure that > > the completion handler is not running after return from usb_unlink_urb(). > > If we wish to make the guarantee, usb_unlink_urb() must not simply > > fail if the completion handler is running. A synchronous unlink must > > wait. > > > > The second problem we fix is with resubmission from the completion > > handler. If we have a state for unlinked during completion, we can fail > > resubmission. Thus we kill races with disconnect in rx paths. > > This is highly analogous to the problem of cancelling a kernel timer. If
Absolutely. > the timer's handler reschedules another timer interrupt, it can be hard to > cancel reliably. For kernel timers, the problem was only partially solved > by having del_timer() return a code indicating whether or not the timer > was still active and by adding del_timer_sync(). There still has to be a > requirement that the handler must avoid restarting the timer. > > Much the same is true for USB. No matter what the core does, if the > user's completion handler resubmits, it will be hard to kill the URB > entirely. > > Furthermore, there is a conceptual problem that has not been fully > addressed. When a usb_unlink_urb() is called for an URB whose completion > handler is running, which incarnation are we being asked to cancel? The > one that just completed or the one that the completion handler is about to > submit? If you can't answer this question first, then naturally you don't > know what you're supposed to do. My answer is not kill the URB about to be submitted, but to simply fail the call to usb_submit_urb(). I believe that to be the simplest solution. > As far as guaranteeing that when usb_unlink_urb() returns from a > synchronous unlink, the completion handler will have already finished -- > so far as I can tell there is currently no such guarantee. At least, the There's if the unlink doesn't return an error. > kerneldoc preceding usb_unlink_urb() is sufficiently vague that it doesn't > make this promise. Of course, we need to have something like this. But > in principle there should be no problem -- or rather, the only problem is Not trivial. The only way to do it is to use complete_and_exit() in the completion handler. > dealing with the case that the handler resubmits. What happens if the > handler resubmits the URB, and another thread tries to unlink the > newly-submitted incarnation before the handler has returned? We must make sure that an interrupt handler is not reentered. > If it weren't for the fact that a completion handler is allowed to > resubmit an URB, I suspect the best solution would simply be to lock the > URB while the handler is running. Yes, if. By the way. I am including the code I have so far. I am afraid it's still buggy. But you might have a look at it. Regards Oliver You can import this changeset into BK by piping this whole message to: '| bk receive [path to repository]' or apply the patch as usual. =================================================================== [EMAIL PROTECTED], 2003-01-13 16:01:26+01:00, [EMAIL PROTECTED] - state machine drivers/usb/core/hcd.c | 40 ++++++++++++++++++++++++++++++++++++---- drivers/usb/core/urb.c | 21 ++++++++++++++++++++- include/linux/usb.h | 15 ++++++++++++--- 3 files changed, 68 insertions(+), 8 deletions(-) diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Mon Jan 13 16:14:48 2003 +++ b/drivers/usb/core/hcd.c Mon Jan 13 16:14:48 2003 @@ -1101,6 +1101,7 @@ struct device *sys = 0; unsigned long flags; struct completion_splice splice; + struct completion cp; int retval; if (!urb) @@ -1138,14 +1139,26 @@ goto done; } - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. + /* + * Decide what is to be done based on state * - * FIXME use better explicit urb state */ - if (urb->status != -EINPROGRESS) { + switch (urb->state) { + case URB_SUBMITTED: + break; /* common case hopefully */ + case URB_COMPLETING: + urb->state = URB_CANCELED; + retval = -EBUSY; + if (urb->transfer_flags & URB_ASYNC_UNLINK) + goto done; + else + goto wait_for_handler; + case URB_IDLE: + case URB_CANCELED: retval = -EBUSY; goto done; + default: + BUG(); } /* maybe set up to block until the urb's completion fires. the @@ -1205,6 +1218,14 @@ if (retval && sys) dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; + +wait_for_handler: + init_completion(&cp); + urb->unlink_wait = &cp; + spin_unlock (&hcd_data_lock); + spin_unlock_irqrestore (&urb->lock, flags); + wait_for_completion(&cp); + return retval; } /*-------------------------------------------------------------------------*/ @@ -1307,7 +1328,18 @@ } /* pass ownership to the completion handler */ + spin_lock(&urb->lock); + if (urb->state == URB_SUBMITTED) /* in case the unlinking fails */ + urb->state = URB_COMPLETING; + spin_unlock(&urb->lock); /* handler may resubmit */ urb->complete (urb, regs); + spin_lock(&urb->lock); + if (urb->state != URB_SUBMITTED) + urb->state = URB_IDLE; + /* somebody might be waiting on us */ + if (urb->unlink_wait) + complete(urb->unlink_wait); + spin_unlock(&urb->lock); usb_put_urb (urb); } EXPORT_SYMBOL (usb_hcd_giveback_urb); diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c Mon Jan 13 16:14:48 2003 +++ b/drivers/usb/core/urb.c Mon Jan 13 16:14:48 2003 @@ -192,6 +192,8 @@ struct usb_device *dev; struct usb_operations *op; int is_out; + unsigned long flags; + int retval; if (!urb || urb->hcpriv || !urb->complete) return -EINVAL; @@ -346,7 +348,24 @@ urb->interval = temp; } - return op->submit_urb (urb, mem_flags); + retval = 0; + spin_lock_irqsave(&urb->lock, flags); + switch (urb->state) { + case URB_IDLE: + case URB_COMPLETING: + urb->state = URB_SUBMITTED; + break; + case URB_CANCELED: + retval = -EBUSY; + break; + case URB_SUBMITTED: + default: + BUG(); + break; + } + spin_unlock_irqrestore(&urb->lock, flags); + + return retval ? retval : op->submit_urb (urb, mem_flags); } /*-------------------------------------------------------------------*/ diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Mon Jan 13 16:14:48 2003 +++ b/include/linux/usb.h Mon Jan 13 16:14:48 2003 @@ -583,6 +583,7 @@ * status of the particular request. ISO requests only use it * to tell whether the URB was unlinked; detailed status for * each frame is in the fields of the iso_frame-desc. + * @state: internal state used for unlinking * @transfer_flags: A variety of flags may be used to affect how URB * submission, unlinking, or operation are handled. Different * kinds of URB can use different flags. @@ -605,7 +606,7 @@ * transferred. It will normally be the same as requested, unless * either an error was reported or a short read was performed. * The URB_SHORT_NOT_OK transfer flag may be used to make such - * short reads be reported as errors. + * short reads be reported as errors. * @setup_packet: Only used for control transfers, this points to eight bytes * of setup data. Control transfers always start by sending this data * to the device. Then transfer_buffer is read or written, if needed. @@ -626,7 +627,7 @@ * @complete: Completion handler. This URB is passed as the parameter to the * completion function. The completion function may then do what * it likes with the URB, including resubmitting or freeing it. - * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to + * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to * collect the transfer status for each buffer. * * This structure identifies USB transfer requests. URBs must be allocated by @@ -660,7 +661,7 @@ * The URB_ASYNC_UNLINK transfer flag affects later invocations of * the usb_unlink_urb() routine. * - * All URBs must also initialize + * All URBs must also initialize * transfer_buffer and transfer_buffer_length. They may provide the * URB_SHORT_NOT_OK transfer flag, indicating that short reads are * to be treated as errors; that flag is invalid for write requests. @@ -726,6 +727,8 @@ { spinlock_t lock; /* lock for the URB */ atomic_t count; /* reference count of the URB */ + int state; /* current state, lock must be held for access +*/ + struct completion *unlink_wait; /* to wait for a completion handler to finish +*/ void *hcpriv; /* private data for host controller */ struct list_head urb_list; /* list pointer to all active urbs */ struct usb_device *dev; /* (in) pointer to associated device */ @@ -748,6 +751,12 @@ usb_complete_t complete; /* (in) completion routine */ struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */ }; + +/* internal states an URB may have */ +#define URB_IDLE 0 +#define URB_SUBMITTED 1 +#define URB_COMPLETING 2 +#define URB_CANCELED 3 /* -------------------------------------------------------------------------- */ =================================================================== This BitKeeper patch contains the following changesets: 1.1267 ## Wrapped with gzip_uu ## begin 664 bkpatch18195 M'XL(`.G7(CX``[57;6_;-A#^+/V*&PH$25K;I-YE(UU>D1E-TR"I/Q0H8-`2 M;0F6)8^4DF7S_ON.E-_CIFG6!D%(D7?'>X[WW#%OH">Y:!M%EMYS8;Z!/PI9 MXB?/BYPWDV+"LS2O_FH68H2;MT6!FRVUW*HU6H-QHQ2<RU:5H^38<DV4NV%E ME`!NR[9!F_9RI7R<\K9Q>W'9NSJY-<VC(SA+6#[B=[R$HR-S,#Z.*YXUQZ)@ MB3IRMMR>68102BV7V*Y'W9D5V+8SHQX9Q#B-+3\<#KS0'`D^.J[5HV*RJ6ZC M`9OX-+3"F>TXA)KG0)O4\GP@=HO0%K6!>FU"VY;W%O\2`C7&XUW1@+<V-(AY M"O_?Z3,S@@;(DI4<)BQ*TIR;'\`./.J9-ZL(F8T?_#%-PHCY'K:"$@L%"B], M#EI1(7BK$H-FI'RUB$=LZCH.]6:4A':(OCHQB3S+=X>AZP7\N8@\8UB'GCIN M2(.9ZP2!A5X]C5N:1UD5\Y:VJ*PTDU4$'>(Z9$8\Q_%GL679<1"[[M!S;(\^ MZ]0WC*Y[9`74#]"CJ<K1;:?60251O`@4)6IP'4RET*<^)E3(!@YS&*..S0/G MQP*U-+QRRY\1U_4\39(=&';3Y;41W.;-MX.&&>):U$4[U/?].8.L-0*Y;3=L MT^`E!*(6-.Q?R*#Z7C]!0SSH7V3$S:Y8OH)873=P@9IP",?ZU#;:+;G(63;W MHI(\AF$AH"Z+:3XRSST2H$ZW'N#0D$DA2A"<Q1(&'"=3_$8U)H$+40C91!TK MU#IZ4,>ELN@/!9OP?LQEU%;E.X:R@*DH[M.8`Q."/4HHAM"]^P2E8+D<<@&# M:HB#!)8K:;3KV=JN'M#N299![_94PJ22);!,%H@H+5.6I7]SL^M;`5BF@2!K M?!W#,%J'$%5"\,7:.\B*:%P;0#@)S^H(L"CB4L)ARS1D*:JH!$RQ:<;+M,CA ML(Y/_X&E94>91"AJ7FNN2V)*Q!DB08$ANB839;'KNP0\\ZN)FILWH*`J1)@/ MCZA[SY7XFYBC+E?K_>[YU85!-I;N>J<?NY\_7YP;=&/][-/'FZN+S]WK2\/: MW#BY/KNX0GE;\W1W`514_8DE^`=L432%Q'$)UC@?^:/I:I'7L17U&O07LK7N M"UMLW0WN-82EH:,RN,IE.LJ1,EF1CPQCF+&1[.C$QHP6O+QG6<<\QVJNV*&' MP)ROPQ$0%)73-.^K3.^GXD^)B;6_ATXUWJNE=Z`-'BBQAU2]>/;UGL9Z`/^8 M1L3D*OW::]^K',-58Z6%IVZD)IHV!E@SQIUUY7D>*M6ELXV+T][=EYWR2VNH M@.G,JJQ4JJ>]R_V#=85_YW"1I'/`@LL2[V$GYJ\Z4I7(8>[#[XM)&XHIXJD& MD[3LHZ8.RSN8\$E_H;R3/[HO*O[\S-;\70)M=&-BX<2E,XIM,M`$"OPG!/)? M]%[TH.'\2@*IY\+W^*.QO8H_6$F0$T]+N&%$4Z0,I0Y%@J&<8RFBM0Y-`_O* M.8]45WI(6`FI5,4;6T.,T8$!4YT+"[O&H0TX>(`:/46^>K2^SZ3U9)YG+JC> M5$PF:%V+)<64#ZLL>]1=Z*6<6["JLYM5Z7#NTZ+)UKD,>UKYY.[+]5F_=WW5 MO?YP@-+&J$#P"KG2Y9GDRT75[_K8[_KS%M=YKDPLF:X"I)OR4P)WJ45\")"0 MVZ;;JM3ATNKZ]O>BJ>*\1K+6C!'JGKK8]0(`^WN8/_V8E4Q7P(/.M^H#["Z* M2W>>GK]1.10$FX3@K)7;-8M*?AG]^8UME<D#T"^"^OK+A*_>83!D:58_1W9< M^3(C-J%M'*Y,+UXCZG6!F'5ETP\2?+X3\%_L]V_;?N_R2B6!RAH\5V)-&13Q M(TS24:+?62JF"A;F>E7#6AZQ=IW*[CSH_.GF,V!7_\Y'"8_&LIH<N3P(!B$6 +F_\`&<RK;CT0```` ` end ------------------------------------------------------- This SF.NET email is sponsored by: FREE SSL Guide from Thawte are you planning your Web Server Security? Click here to get a FREE Thawte SSL guide and find the answers to all your SSL security issues. http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0026en _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel