Hi, I think there's a small window during which a low level driver can be unloaded while sg_open() is executing. The attached patch should fix it by incrementing the usage counter before sg_open() might sleep. Regards Oliver
--- drivers/scsi/sg.c.alt Tue Mar 6 23:33:15 2001 +++ drivers/scsi/sg.c Tue Mar 6 23:44:33 2001 @@ -257,6 +257,7 @@ Sg_device * sdp; Sg_fd * sfp; int res; + int retval = -EBUSY; sdp = sg_get_dev(dev); if ((! sdp) || (! sdp->device) || (! sdp->device->host)) @@ -269,31 +270,46 @@ * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ - if (! ((flags & O_NONBLOCK) || - scsi_block_when_processing_errors(sdp->device))) - return -ENXIO; + + /* Prevent the device driver from vanishing while we sleep */ + + if (sdp->device->host->hostt->module) + __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); + + + if (! ((flags & O_NONBLOCK) || + scsi_block_when_processing_errors(sdp->device))) { + retval = -ENXIO; + goto error_out; + } SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); if (flags & O_EXCL) { - if (O_RDONLY == (flags & O_ACCMODE)) - return -EACCES; /* Can't lock it with read only access */ - if (sdp->headfp && (flags & O_NONBLOCK)) - return -EBUSY; + if (O_RDONLY == (flags & O_ACCMODE)) { + retval = -EACCES; /* Can't lock it with read only access */ + goto error_out; + } + if (sdp->headfp && (flags & O_NONBLOCK)) + goto error_out; res = 0; /* following is a macro that beats race condition */ __wait_event_interruptible(sdp->o_excl_wait, ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); - if (res) - return res; /* -ERESTARTSYS because signal hit process */ + if (res) { + retval = res; /* -ERESTARTSYS because signal hit process */ + goto error_out; + } } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */ if (flags & O_NONBLOCK) - return -EBUSY; + goto error_out; res = 0; /* following is a macro that beats race condition */ __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res); - if (res) - return res; /* -ERESTARTSYS because signal hit process */ + if (res) { + retval = res; /* -ERESTARTSYS because signal hit process */ + goto error_out; + } } if (! sdp->headfp) { /* no existing opens on this device */ sdp->sgdebug = 0; @@ -303,12 +319,17 @@ filp->private_data = sfp; else { if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */ - return -ENOMEM; + retval = -ENOMEM; + goto error_out; } - if (sdp->device->host->hostt->module) - __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); return 0; + +error_out: + + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); + return retval; } /* Following function was formerly called 'sg_close' */