Am Freitag, 30. April 2004 16:12 schrieb Alan Stern: > On Fri, 30 Apr 2004, Oliver Neukum wrote: > > Very, very tempting. Elegant and simple. But I have a problem with it. > > It's entirely legal for a driver to call usb_get_urb() twice. And then we > > have a problem. So I don't think that we should use the refcount. > > Yes, it is legal for a driver to do that. I suspect that very few of them > do, because there's not often a reason for it. In fact, a recursive grep > of the kernel source shows that usb_get_urb() is mentioned only within > include/linux/usb.h, core/hcd.c, core/urb.c, host/ehci-sched.c, and > host/hc_simple.c. No drivers call it. Anyway, we can always document at > the start of the routine that it shouldn't be used if the URB's reference > count has been monkeyed with.
But that's the direction we are moving in, isn't it? > On the other hand, there are some very good reasons for using the refcount > in that test. Whatever we test, it needs to be something that is changed > in giveback_urb after the completion handler returns. The only field for > which that is currently true is the refcount. Remember, at the end of > giveback_urb usbcore no longer owns the URB; the driver does. Hence there > isn't much that giveback_urb can afford to change. But giveback_urb doesn't need to change anything. Calling the handler itself it knows when it has run. > Also, whatever we use, it has to take into account the possibility of > resubmission (and even the theoretical possibility of nested invocations > of giveback_urb!). The only thing that will handle this properly is a > refcount of some sort. Yes, we could introduce another one that would > track just the active submissions -- but why go to all that trouble (and > introduce yet another field into the already-bloated struct urb) when > we have a ready-made reference count sitting right there? I don't think we need a refcount. Could you have a look at this code: 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], 2004-04-30 17:27:46+02:00, [EMAIL PROTECTED] - add an API that allows to terminate all activity associated with an URB drivers/usb/core/hcd.c | 7 +++++- drivers/usb/core/hub.c | 24 +++++++++++----------- drivers/usb/core/urb.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/usb.h | 9 ++++++++ 4 files changed, 79 insertions(+), 14 deletions(-) diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Fri Apr 30 17:49:43 2004 +++ b/drivers/usb/core/hcd.c Fri Apr 30 17:49:43 2004 @@ -1478,6 +1478,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) { urb_unlink (urb); + urb->phase = URB_PHASE_DONE; /* to detect resubmission in handler */ // NOTE: a generic device/urb monitoring hook would go here. // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) @@ -1492,7 +1493,7 @@ DMA_TO_DEVICE); if (urb->transfer_buffer_length != 0 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) - dma_unmap_single (hcd->self.controller, + dma_unmap_single (hcd->self.controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) @@ -1502,6 +1503,10 @@ /* pass ownership to the completion handler */ urb->complete (urb, regs); + if (urb->phase != URB_PHASE_DOING) { /* no resubmission */ + urb->phase = URB_PHASE_IDLE; + } + wake_up(&urb->handler_queue); /* for usb_kill_urb() */ usb_put_urb (urb); } EXPORT_SYMBOL (usb_hcd_giveback_urb); diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Fri Apr 30 17:49:43 2004 +++ b/drivers/usb/core/hub.c Fri Apr 30 17:49:43 2004 @@ -233,11 +233,11 @@ int status; spin_lock(&hub_event_lock); - hub->urb_active = 0; - if (hub->urb_complete) { /* disconnect or rmmod */ - complete(hub->urb_complete); - goto done; - } + //hub->urb_active = 0; + //if (hub->urb_complete) { /* disconnect or rmmod */ + // complete(hub->urb_complete); + // goto done; + //} switch (urb->status) { case -ENOENT: /* synchronous unlink */ @@ -252,7 +252,7 @@ goto resubmit; hub->error = urb->status; /* FALL THROUGH */ - + /* let khubd handle things */ case 0: /* we got data: port status changed */ break; @@ -271,8 +271,8 @@ /* ENODEV means we raced disconnect() */ && status != -ENODEV) dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status); - if (status == 0) - hub->urb_active = 1; + //if (status == 0) + // hub->urb_active = 1; done: spin_unlock(&hub_event_lock); } @@ -588,7 +588,7 @@ message = "couldn't submit status urb"; goto fail; } - hub->urb_active = 1; + //hub->urb_active = 1; /* Wake up khubd */ wake_up(&khubd_wait); @@ -640,9 +640,9 @@ flush_scheduled_work (); if (hub->urb) { - usb_unlink_urb(hub->urb); - if (hub->urb_active) - wait_for_completion(&urb_complete); + usb_kill_urb(hub->urb); + //if (hub->urb_active) + // wait_for_completion(&urb_complete); usb_free_urb(hub->urb); hub->urb = NULL; } diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c Fri Apr 30 17:49:43 2004 +++ b/drivers/usb/core/urb.c Fri Apr 30 17:49:43 2004 @@ -33,6 +33,7 @@ memset(urb, 0, sizeof(*urb)); urb->count = (atomic_t)ATOMIC_INIT(1); spin_lock_init(&urb->lock); + init_waitqueue_head(&urb->handler_queue); } } @@ -384,6 +385,7 @@ urb->interval = temp; } + urb->phase = URB_PHASE_DOING; return op->submit_urb (urb, mem_flags); } @@ -454,10 +456,59 @@ return -ENODEV; } +/** + * usb_kill_urb cancel all data transfers designated by an URB + * @urb: pointer to urb describing a previously submitted request + * + * it will cancel/abort all data transfers and make sure that all + * completion handlers have run + * + */ + +int usb_kill_urb(struct urb *urb) +{ + int retval; + + spin_lock_irq(&urb->lock); + if (urb->phase == URB_PHASE_IDLE) { + retval = -EINVAL; + spin_unlock_irq(&urb->lock); + goto done; + } else { + spin_unlock_irq(&urb->lock); + } + +rekill: + retval = usb_unlink_urb(urb); + if (retval < 0) { /* failed - find out whether URB has been given back */ + spin_lock_irq(&urb->lock); + switch (urb->phase) { + case URB_PHASE_IDLE: /* done */ + spin_unlock_irq(&urb->lock); + retval = 0; + break; + case URB_PHASE_DOING: /* handler has resubmitted */ + spin_unlock_irq(&urb->lock); + goto rekill; + case URB_PHASE_DONE: /* will still be given back */ + spin_unlock_irq(&urb->lock); + wait_event(urb->handler_queue, urb->phase != URB_PHASE_IDLE); + retval = 0; + break; + default: + BUG(); + } + } + +done: + return retval; +} + + EXPORT_SYMBOL(usb_init_urb); EXPORT_SYMBOL(usb_alloc_urb); EXPORT_SYMBOL(usb_free_urb); EXPORT_SYMBOL(usb_get_urb); EXPORT_SYMBOL(usb_submit_urb); EXPORT_SYMBOL(usb_unlink_urb); - +EXPORT_SYMBOL(usb_kill_urb); diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Fri Apr 30 17:49:43 2004 +++ b/include/linux/usb.h Fri Apr 30 17:49:43 2004 @@ -551,6 +551,13 @@ #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ +/* + * urb->phase + */ +#define URB_PHASE_IDLE 0 +#define URB_PHASE_DOING 1 +#define URB_PHASE_DONE 2 + struct usb_iso_packet_descriptor { unsigned int offset; unsigned int length; /* expected length */ @@ -736,6 +743,8 @@ void *hcpriv; /* private data for host controller */ struct list_head urb_list; /* list pointer to all active urbs */ int bandwidth; /* bandwidth for INT/ISO request */ + wait_queue_head_t handler_queue;/* waiting for completion handlers */ + int phase; /* tell apart phases of the URB */ /* public, documented fields in the urb that can be used by drivers */ struct usb_device *dev; /* (in) pointer to associated device */ =================================================================== This BitKeeper patch contains the following changesets: 1.1626 ## Wrapped with gzip_uu ## begin 664 bkpatch6746 M'XL(`)=UDD```[58?V_;-A#]6_P4+`H,25I;)/7+<I8@;1.TQKHT2-MA0SL8 MM$3;A&7)%:ED1=WOOB-E.W:C.*G1)($5B^33W>.]NZ.>XH]*E%VGR.25*-%3 M_*90&KZ*O,A%>UQ,12;[EMAIL PROTECTED](H8-`UM]TBRR1S/Y1"*'<BLXR%"&9< M<)V,,4"IKD/;WNJ._CH37>?R[/7'MR\N$3HZPJ_&/!^)]T+CHR.DB_**9ZDZ MX7J<%7E;ESQ74Z%Y.RFF\]74.2.$P6]`(X\$X9R&Q(_F"4TIY3X5*6%^)_31 MN!J-3\`&J;DR`)^6\/]N0OG$9S&CU&.=.8MCGZ%33-LT9"[EMAIL PROTECTED]'L$TZK*H MZX?/"[EMAIL PROTECTED]>3IKXP<]\W"+H)?ZUSKQ""6YAGJ:8Y_C%10_K,=>89UEQK>!1 M6(MR*G.NA;F'>:+EE=1?,5>J2"3<3O&UU&,`P0;@X^5+]`?V:(>$Z.)F#U#K M)W\0([EMAIL PROTECTED]'([EMAIL PROTECTED]:#>5H:?I1;J8&;[EMAIL PROTECTED],*<> MZ9`Y#[CP:!Q[29*2)$ZWD;L%&'[EMAIL PROTECTED]/81S;W212%8-;V+9!YDE6I<"VZ06R/ MUS<#`F%."?/8W$O!NBCQDH@&G0X9;K7P#M1U\T(2!=Z]YJV[.JY6]%GC?$*C MN1_Y83`7PT',F$\&7/!D^)/LK7#7S6->[EMAIL PROTECTED]<1\`O;W3>;N [EMAIL PROTECTED]&KMO,.M\MK^@<@O[B![AW31\P),D>/(7.K^-9?Z2R4JT1\+GN[]!J"M M8_`CS439MP/[A["B$YHE=G`VYDK@(Y._^A=O7KP_ZY^^ZYV_AEE^$&(_1N[! M`<+X8,,IG/`\$9E-C"G7'%OFAN`/3H62H]RFQ\'796([EMAIL PROTECTED]/"IE#8C7Y MU>#`[*24`YF/,,>S4ES)HE+95ZRJP51J`U(*,%MI`V%AI(:T"X^M+7#YH"AU MDQW@,Y[RB0"H4JQ2NX6`S9UE0LLBQPMJ%/QS)7!9Y<OGN/"!P-0-M_>4+JM$ M6\L/X&,??4..F50*#8%TB#XC1\UDWL^*9-*7Y9?%!IBOP+LCAWAOG?1UUGNG M;\_V,>`Y-1AL2>NL=_[7B[>PL$:M\CMPG5$!?*80Z?#E.Q89@'^[=]5W,+<4 MQK<NNGFH\1>6R'QB/39>+BQ?3/D=$[`3NP=XR&4&.]3"0PED%Q7LS%CH,>PN MN`6,*CP0(L<C"/0<[EMAIL PROTECTED],;0Z6QER%-14Z&K6:*I)<1+#V"9=76.$\;K&O9>E M-6I)_7U0"CXY;("W&K#XBPBQ[I3B)BX?^DB[-37-S0\ZK_VP0:VT^1R(6YP] MX$%&^GT!R_3>;=4_QVMQ]^16W-W'3BJ&O,ITU]Y^^?'UGEWQO8XALP-U!%5E MOI*"&?F,[EMAIL PROTECTED]/GR_?O=U;5Q;@[EMAIL PROTECTED],!?KEE?-G MRM!:[EMAIL PROTECTED]@1<'[EMAIL PROTECTED]/[EMAIL PROTECTED](Q23856B1Z&;E*F:0G\X84 M:)I7VPG<5Z<L&;O4*>IWR-:R<WYV:)1PM]5++8(D3JD?F[K76UQ-D$XY"&3* M9WT%]203>`],;1TKD0V!R5R7<+`2Y7-8$A`?^[?2\9-;17"1Y_)BTQ*KR#N\ M,'*RN17T.!']:M9<@VWZ+,K-ZK)OD)ME4"T:L<?H;Q&?S*:KWF[M2+>UMZ4Q MM&$!I=#;,B^T.HAWU`$U[1A[)"54L$&YN/ZQ)ZL[\GMCO=JM)SL%2G"`>D`R M7!S7`+6.X<E]>XP4BQSKNB8$5V,+49J*YYC*)A6$;6Z$`)%23J=%775<UUG. M;%AK83<:[EMAIL PROTECTED](RBWS,X'L4P&5AB-)<5\JT)63?HMRVFAZBTR"F M!JJ^-/IF9H6^ASW4"_T`+B"7]4!?KK!5Y`<2:I!].U#7--!)_R9?63VMNVL$ MTW!"O%\M.Q]6D2D3)Y.RX&/[$J2N&G>>4CV/,D8C&LY]SX>@LZ]"2+";5N+' M>Q.RM6:8=MKLALU:RZX9=%0?O'_040,5NQ0,[EMAIL PROTECTED],',J>/5;[EMAIL PROTECTED]/H2.1 M^8\-H4,:!FPF=VCCR/F9PT`-O<CK&!G8<+LY/O4UWDC;[EMAIL PROTECTED]&)H:#I' M&(&:$X$U]1"JDBEHPKP_FO%R<5OA8@@G$FN*3?G+=WEPR$XFJIH>#7@<$<Z' *Z'^:WR0C1A0````` ` end ------------------------------------------------------- This SF.Net email is sponsored by: Oracle 10g Get certified on the hottest thing ever to hit the market... Oracle 10g. Take an Oracle 10g class now, and we'll give you the exam FREE. http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel