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' */

Reply via email to