Hi,
here is the new one which includes suggestions made,
at least so I hope.
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], 2002-07-02 23:14:07+02:00, [EMAIL PROTECTED]
- BKL against module unload only where needed
diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c Tue Jul 2 23:15:46 2002
+++ b/drivers/usb/core/devices.c Tue Jul 2 23:15:46 2002
@@ -239,6 +239,7 @@
if (start > end)
return start;
+ lock_kernel(); /* driver might be unloaded */
start += sprintf(start, format_iface,
desc->bInterfaceNumber,
desc->bAlternateSetting,
@@ -248,6 +249,7 @@
desc->bInterfaceSubClass,
desc->bInterfaceProtocol,
iface->driver ? iface->driver->name : "(none)");
+ unlock_kernel();
return start;
}
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c Tue Jul 2 23:15:46 2002
+++ b/drivers/usb/core/devio.c Tue Jul 2 23:15:46 2002
@@ -722,14 +722,11 @@
if (test_bit(i, &ps->ifclaimed))
continue;
- if (intf->driver) {
- const struct usb_device_id *id;
- down(&intf->driver->serialize);
- intf->driver->disconnect(ps->dev, intf->private_data);
- id = usb_match_id(ps->dev,intf,intf->driver->id_table);
- intf->driver->probe(ps->dev, i, id);
- up(&intf->driver->serialize);
+ lock_kernel();
+ if (intf->driver && ps->dev) {
+ usb_bind_driver(intf->driver,ps->dev, i);
}
+ unlock_kernel();
}
return 0;
@@ -1092,16 +1089,17 @@
/* disconnect kernel driver from interface, leaving it unbound. */
case USBDEVFS_DISCONNECT:
+ /* this function is voodoo. without locking it is a maybe thing */
+ lock_kernel();
driver = ifp->driver;
if (driver) {
- down (&driver->serialize);
dbg ("disconnect '%s' from dev %d interface %d",
driver->name, ps->dev->devnum, ctrl.ifno);
- driver->disconnect (ps->dev, ifp->private_data);
+ usb_unbind_driver(ps->dev, ifp);
usb_driver_release_interface (driver, ifp);
- up (&driver->serialize);
} else
retval = -EINVAL;
+ unlock_kernel();
break;
/* let kernel drivers try to (re)bind to the interface */
@@ -1111,18 +1109,28 @@
/* talk directly to the interface's driver */
default:
+ lock_kernel(); /* against module unload */
driver = ifp->driver;
- if (driver == 0 || driver->ioctl == 0)
- retval = -ENOSYS;
- else {
- if (ifp->driver->owner)
+ if (driver == 0 || driver->ioctl == 0) {
+ unlock_kernel();
+ retval = -ENOSYS;
+ } else {
+ if (ifp->driver->owner) {
__MOD_INC_USE_COUNT(ifp->driver->owner);
+ unlock_kernel();
+ }
/* ifno might usefully be passed ... */
retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
/* size = min_t(int, size, retval)? */
- if (ifp->driver->owner)
+ if (ifp->driver->owner) {
__MOD_DEC_USE_COUNT(ifp->driver->owner);
+ } else {
+ unlock_kernel();
+ }
}
+
+ if (retval == -ENOIOCTLCMD)
+ retval = -ENOTTY;
}
/* cleanup and return */
@@ -1139,7 +1147,7 @@
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c Tue Jul 2 23:15:46 2002
+++ b/drivers/usb/core/hub.c Tue Jul 2 23:15:46 2002
@@ -1050,8 +1050,6 @@
static int usb_hub_thread(void *__hub)
{
- lock_kernel();
-
/*
* This thread doesn't need any user-level access,
* so get rid of all our resources
@@ -1071,8 +1069,6 @@
} while (!signal_pending(current));
dbg("usb_hub_thread exiting");
-
- unlock_kernel();
complete_and_exit(&khubd_exited, 0);
}
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c Tue Jul 2 23:15:46 2002
+++ b/drivers/usb/core/usb.c Tue Jul 2 23:15:46 2002
@@ -33,6 +33,7 @@
#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
+#include <linux/smp_lock.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
@@ -254,6 +255,96 @@
up (&usb_bus_list_lock);
}
+/**
+ * usb_unbind_driver - disconnects a driver from a device
+ * @driver: Driver to be disconnected
+ * @device: usb device to be disconnected
+ * @priv: private pointer passed to device driver
+ * Context: BKL held
+ *
+ * Handles module usage count correctly
+ */
+
+void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf)
+{
+ struct usb_driver *driver;
+ void *priv;
+
+
+ driver = intf->driver;
+ priv = intf->private_data;
+
+ if (!driver)
+ return;
+
+ /* as soon as we increase the module use count we drop the BKL
+ before that we must not sleep */
+ if (driver->owner) {
+ __MOD_INC_USE_COUNT(driver->owner);
+ unlock_kernel();
+ }
+ down(&driver->serialize); /* if we sleep here on an umanaged driver
+ the holder of the lock guards against
+ module unload */
+
+ driver->disconnect(device, priv);
+
+ up(&driver->serialize);
+ if (driver->owner) {
+ lock_kernel();
+ __MOD_DEC_USE_COUNT(driver->owner);
+ }
+}
+
+/**
+ * usb_bind_driver - connect a driver to a device's interface
+ */
+
+void *usb_bind_driver(struct usb_driver *driver, struct usb_device *dev, unsigned int
+ifnum)
+{
+ int i;
+ void *private;
+ const struct usb_device_id *id;
+ struct usb_interface *interface;
+
+ if (driver->owner) {
+ __MOD_INC_USE_COUNT(driver->owner);
+ unlock_kernel();
+ }
+
+ interface = &dev->actconfig->interface[ifnum];
+
+ id = driver->id_table;
+ /* new style driver? */
+ if (id) {
+ for (i = 0; i < interface->num_altsetting; i++) {
+ interface->act_altsetting = i;
+ id = usb_match_id(dev, interface, id);
+ if (id) {
+ down(&driver->serialize);
+ private = driver->probe(dev,ifnum,id);
+ up(&driver->serialize);
+ if (private != NULL)
+ break;
+ }
+ }
+
+ /* if driver not bound, leave defaults unchanged */
+ if (private == NULL)
+ interface->act_altsetting = 0;
+ } else { /* "old style" driver */
+ down(&driver->serialize);
+ private = driver->probe(dev, ifnum, NULL);
+ up(&driver->serialize);
+ }
+ if (driver->owner) {
+ lock_kernel();
+ __MOD_DEC_USE_COUNT(driver->owner);
+ }
+
+ return private;
+}
+
/*
* This function is part of a depth-first search down the device tree,
* removing any instances of a device driver.
@@ -278,13 +369,7 @@
struct usb_interface *interface = &dev->actconfig->interface[i];
if (interface->driver == driver) {
- if (driver->owner)
- __MOD_INC_USE_COUNT(driver->owner);
- down(&driver->serialize);
- driver->disconnect(dev, interface->private_data);
- up(&driver->serialize);
- if (driver->owner)
- __MOD_DEC_USE_COUNT(driver->owner);
+ usb_unbind_driver(dev, interface);
/* if driver->disconnect didn't release the interface */
if (interface->driver)
usb_driver_release_interface(driver, interface);
@@ -300,7 +385,7 @@
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
- * Context: !in_interrupt ()
+ * Context: !in_interrupt (), must be called with BKL held
*
* Unlinks the specified driver from the internal USB driver list.
*/
@@ -666,9 +751,7 @@
struct list_head *tmp;
struct usb_interface *interface;
void *private;
- const struct usb_device_id *id;
struct usb_driver *driver;
- int i;
if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
err("bad find_interface_driver params");
@@ -683,37 +766,12 @@
goto out_err;
private = NULL;
+ lock_kernel();
for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) {
driver = list_entry(tmp, struct usb_driver, driver_list);
tmp = tmp->next;
- if (driver->owner)
- __MOD_INC_USE_COUNT(driver->owner);
- id = driver->id_table;
- /* new style driver? */
- if (id) {
- for (i = 0; i < interface->num_altsetting; i++) {
- interface->act_altsetting = i;
- id = usb_match_id(dev, interface, id);
- if (id) {
- down(&driver->serialize);
- private = driver->probe(dev,ifnum,id);
- up(&driver->serialize);
- if (private != NULL)
- break;
- }
- }
-
- /* if driver not bound, leave defaults unchanged */
- if (private == NULL)
- interface->act_altsetting = 0;
- } else { /* "old style" driver */
- down(&driver->serialize);
- private = driver->probe(dev, ifnum, NULL);
- up(&driver->serialize);
- }
- if (driver->owner)
- __MOD_DEC_USE_COUNT(driver->owner);
+ private = usb_bind_driver(driver, dev, ifnum);
/* probe() may have changed the config on us */
interface = dev->actconfig->interface + ifnum;
@@ -721,9 +779,11 @@
if (private) {
usb_driver_claim_interface(driver, interface, private);
up(&dev->serialize);
+ unlock_kernel();
return 0;
}
}
+ unlock_kernel();
out_err:
up(&dev->serialize);
@@ -1135,27 +1195,22 @@
info("USB disconnect on device %d", dev->devnum);
+ lock_kernel();
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface =
&dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
if (driver) {
- if (driver->owner)
- __MOD_INC_USE_COUNT(driver->owner);
- down(&driver->serialize);
- driver->disconnect(dev, interface->private_data);
- up(&driver->serialize);
+ usb_unbind_driver(dev, interface);
/* if driver->disconnect didn't release the interface
*/
if (interface->driver)
usb_driver_release_interface(driver,
interface);
- /* we don't need the driver any longer */
- if (driver->owner)
- __MOD_DEC_USE_COUNT(driver->owner);
}
/* remove our device node for this interface */
put_device(&interface->dev);
}
}
+ unlock_kernel();
/* Free up all the children.. */
for (i = 0; i < USB_MAXCHILDREN; i++) {
@@ -1484,6 +1539,8 @@
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
+EXPORT_SYMBOL(usb_bind_driver);
+EXPORT_SYMBOL(usb_unbind_driver);
EXPORT_SYMBOL(__usb_get_extra_descriptor);
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h Tue Jul 2 23:15:46 2002
+++ b/include/linux/usb.h Tue Jul 2 23:15:46 2002
@@ -251,7 +251,7 @@
int act_altsetting; /* active alternate setting */
int num_altsetting; /* number of alternate settings */
int max_altsetting; /* total memory allocated */
-
+
struct usb_driver *driver; /* driver */
struct device dev; /* interface specific device info */
void *private_data;
@@ -429,6 +429,10 @@
/* for when layers above USB add new non-USB drivers */
extern void usb_scan_devices(void);
+
+/* for probe/disconnect with correct module usage counting */
+void *usb_bind_driver(struct usb_driver *driver, struct usb_device *dev, unsigned int
+ifnum);
+void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf);
/* mostly for devices emulating SCSI over USB */
extern int usb_reset_device(struct usb_device *dev);
===================================================================
This BitKeeper patch contains the following changesets:
1.646
## Wrapped with gzip_uu ##
begin 664 bkpatch5604
M'XL(``(8(CT``[59>V_;.!+_V_H4[!;H)6D<DY0HV<XFUVL2W`:;-D73`E?<
M'@P]:%N(+/KT2)H[Y[O?#"G9\BNOS05-9(N<X;SG-^Q;\CV76;^EDOA&9M9;
M\IO*"_@J4Y7*@[&:R"1.RY\'*AO!XE>E8+&#KSN&HA-<MXM,RAP^)-R"/5_\
M(AP36,K[+79@S]\4=U/9;WT]^_OWB[]]M:RC(W(R]M.1O)(%.3JR@NL/42F3
M@^M,^6,\;C9?GG%*&6-<4%NX3,QXU[:=&7-I$,''B'N]8>#VK%$F1Q\,>:@F
MR^2<NMQECNUR,1-<V,(Z)>S`=5Q">8=Z'<H)M_O,Z5/O/>5]2HE1[\,F0Y#W
M@K2I]9'\>9E/K)"TR<??+X@_\N,T+\A$164B29DFRH^(2I,[<CN6F22IE)&,
MK-^)Z-D];GU9F,]J/_/'LJA/K>,-\D<9:IUWRCSHC,O@(%SHX=`><V<V<[@]
M"YGO#H5G.TX4".&)AZRUQ#-4F5PPYM2CG`-W3F>,VPY_5";X79<)*(4S"UTN
MI>ARYH6!;]-GRC1GW)2)]KH]]U&9(GD3JU6IO!GK.EX7@FW(Y-#F+."2!LQ^
MGE0-UDVY((Q[]I/D"F6^P5[<XVSF=\%8GA!=X=.@.^P]7[(Y\Z9LCDO%9IO%
M:9B4D>QHKMK@XZ9DP@&#NX[CS2+.[:@;"3%T(6/9@X)M8;HDD:#4U05GNQ:;
M*]"?L.9J-7K,@"[SJ&`V[<W`$EU/ER>(EJ7JQ/N</J4Z\=>M3L/XYTI5ROQ0
M0B$RKKXD[>Q6_X/"\N4!&[^@3)USAQ%FM1(57@^N99;*9&?WD'3VJF/()!Z-
M"Q+4DLF(['6`2E"DPG=-NNTQH)X:`4_.\R?Y7ZU[W_8P6-'[MGBA]QW29NXK
M^G_B7X-]\V"8PU])1C*561R2::8"4"/.0Y6F,BS(6"934/&!F,G);5R,2:S"
M(B$@2P1BC^;[S6N992HCF2S*+%WP0FI#/!W?Y7'H)Z1Q<MT[03PD_7<I\P)"
M8;$#@M74S*<$JWI1J)YZ7!#/.O=L1FRKM1*R\"(>DITX+8;MXRIVW[TCTQR^
MR9M=\E_8T`(I!D&<[email protected]?K5UG\3`#4[A&.'K(7[.:,\AW"+FIP6I4HSC
MG`S+-"QBE1+X?*-4I-2!MJ<J"X(LP!$D+G#5!X??048!&;R#=%K3Y13.\.#X
M4\8H)MIY]6RUJE-1D3)MJK*0?CC5'!CE%:6S31$&]8^MG8[)OQDK@:C`EPGB
M:.(N$;45ZA]T065\J`24S&95!+2/3?#AV]H9JP+!.XC*&XB\(](^^WQY]>,*
M7]X3F4!6:!KMXN&T]EG[6-U"KB!#%*@';FEMX7R/HG/;F(0;O1]F!VEN:\K&
M^5M8XVZA=U=A6.MA%#F_//EV<?+I='=-Q6_??FA?.96O]+,%88GYV=RSL;!J
MF/=X67T&S'RTJ#:0I>`]UN,]*F9,<-XS)=5[64FEI.V\9D%5-U)C_@@<>NMG
M40[UR>#?Q^J35O`EU8E184/\P=/#\K#181H#/^ZP9V#P1QW6@-TNM1D,9)0#
MA(3L-0@(//,BCV%Y:3OB%9WF1X@NZN:'_6@(8R^92*BA$=17:%JK'1&\J@>(
MQYRJC?`2=`00@5EO*PA,?C48.)],!U@%#L;'B(1<TJ-69V_/(GNMM;H,>BW$
MQ=)?O1YF:H+?-'1#R@]FH4].S89"(>A:T,)@JG=I@CXV@(IXV\XI\.D3_.L7
MDDP5%!5@._7S'*P,-!6U.18I3A3L^%GT=>(`U$`V^/XWA!&`+.I>D/LC24)5
M0I$"XV9P8G)G86_XP[I1<;2A-^5%5H:%7JA.W3//?=)8T@(.$8;L85_>M:#B
M-BF-7?;,$PJO/FP/%80O<'BK;CRDV=9A#;?,WU8&&41^X2.=+M=OS%ZLSP87
M'2(_[(,YR17T='C>2N`09M+/L7/+A3EJ8]RB,=54+X()+>S5@82PQ?V^7I^4
MT%-359`\D7*J6_^B8S:Z3ZLU&'RZ/!V<?SX9?+\Z&YQ<?O_\;67;X::>#KVH
MA35OYUV]&0!;["?Q?R0T=M0(S@-!S/[email protected]\5/P:U3'`_8Z5`"5&:LD
M`KNJH?Z&)Y)1B46UA@GSW6MP8>X5<,<\0'=JYZ,O=K6IR^E&B;>:9ZT)&WN=
MGCUHKWOK'@YKI.IRHL[!;IVDD"5UBOXE)_/XU,%.3+#OK4+*K1&[%.N---@'
M<^7Q*`7;8]^/AVDYT;&OORW%.<0M?`<Q(8K6F`UP5QP=+B7-<DZ9C]K@KQ]V
M6N#JL"/R#H1J'_MA`=(.XQ'`OWKQGUK#?QDI(G*T`(C1H/"#!%6$.$WE+>AX
ME]05ZJ_S;(DC(RLVA)T8&-!#$I-?%_YI'\,!`S\I<ED4`+%A^?U[0P-XO;$-
MQ&MLPQ*A\9R6"JTWP6M5L.N.`=8U(7R,#/)KBM/:GGAZM:[$"X5U-].\M4GV
M:Z[;LZ$ZLF;UYHA\_GYQL6OR+X#:=%T!4OP%^U8)7P4B%IX`2E6T3Q+I`T**
MY-`O07^(P%"W[,A,(\TSCAIG/&0ZBE%0(66<('Z!HF$<^$M]ON;]D)$>,I%)
MC'TCC`[";4:Z?_6J`;%MV@*99R&:]Y1W&0ZDO.N9<6*]\RT'#LYE-M4SB'DT
MN^Z;.#7IFI73@NSL[IMN`:T=9O$$7*.'\WEO/G7='DZ(KH?W-^=N5ZQ?X\!J
MCQ*.,S-SM8@+"Z_6K;I(+6RMI^!Z4EJ?'CWN;KP"@BG&]C;)`M.-#1,C3CF5
MO9YD,)@W<=X',M'=<J#3=0%QG_WCR^77;X.K'Y\^7E[LK.@'^];7EXZN;J\V
M7'=N!NPOO6Q=1>Q;[U<7<!VF*V$N+-WNR]"Z(&WVBE`]DF'B9SY>=QA@/D?K
M&Q"ZN1U>@>@;M'[)T,4%7FZ<F\<?UKEC,^+H'K]Q7C`Y5*'6#8"VNH_Y?W;V
@P]<%R8>+_Q`,QS*\SLO)48\%;K<K`NM_O$5**'L<````
`
end
-------------------------------------------------------
Sponsored by:
ThinkGeek at http://www.ThinkGeek.com/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel