--- linux-vanilla/drivers/scsi/scsi.c Mon Jan 1 14:28:32 2001 +++ linux/drivers/scsi/scsi.c Sat Jan 6 00:41:38 2001 @@ -53,6 +53,7 @@ #include #include #include +#include #define __KERNEL_SYSCALLS__ @@ -1376,7 +1377,7 @@ } static int scsi_register_host(Scsi_Host_Template *); -static void scsi_unregister_host(Scsi_Host_Template *); +static int scsi_unregister_host(Scsi_Host_Template *); /* * Function: scsi_release_commandblocks() @@ -1963,14 +1964,8 @@ /* * Similarly, this entry point should be called by a loadable module if it * is trying to remove a low level scsi driver from the system. - * - * Note - there is a fatal flaw in the deregister module function. - * There is no way to return a code that says 'I cannot be unloaded now'. - * The system relies entirely upon usage counts that are maintained, - * and the assumption is that if the usage count is 0, then the module - * can be unloaded. */ -static void scsi_unregister_host(Scsi_Host_Template * tpnt) +static int scsi_unregister_host(Scsi_Host_Template * tpnt) { int online_status; int pcount0, pcount; @@ -1982,6 +1977,9 @@ struct Scsi_Host *shpnt; char name[10]; /* host_no>=10^9? I don't think so. */ + /* get the big kernel lock, so we don't race with open() */ + lock_kernel(); + /* * First verify that this host adapter is completely free with no pending * commands @@ -1992,7 +1990,7 @@ if (SDpnt->host->hostt == tpnt && SDpnt->host->hostt->module && GET_USE_COUNT(SDpnt->host->hostt->module)) - return; + goto err_out; /* * FIXME(eric) - We need to find a way to notify the * low level driver that we are shutting down - via the @@ -2044,7 +2042,7 @@ } SDpnt->online = online_status; printk(KERN_ERR "Device busy???\n"); - return; + goto err_out; } /* * No, this device is really free. Mark it as such, and @@ -2070,7 +2068,7 @@ /* If something still attached, punt */ if (SDpnt->attached) { printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached); - return; + goto err_out; } devfs_unregister (SDpnt->de); } @@ -2178,6 +2176,13 @@ } } MOD_DEC_USE_COUNT; + + unlock_kernel(); + return 0; + +err_out: + unlock_kernel(); + return -1; } static int scsi_unregister_device(struct Scsi_Device_Template *tpnt); @@ -2259,12 +2264,13 @@ struct Scsi_Host *shpnt; struct Scsi_Device_Template *spnt; struct Scsi_Device_Template *prev_spnt; - + + lock_kernel(); /* * If we are busy, this is not going to fly. */ if (GET_USE_COUNT(tpnt->module) != 0) - return 0; + goto error_out; /* * Next, detach the devices from the driver. @@ -2301,11 +2307,15 @@ prev_spnt->next = spnt->next; MOD_DEC_USE_COUNT; + unlock_kernel(); /* * Final cleanup for the driver is done in the driver sources in the * cleanup function. */ return 0; +error_out: + unlock_kernel(); + return -1; } @@ -2342,22 +2352,24 @@ /* Reverse the actions taken above */ -void scsi_unregister_module(int module_type, void *ptr) +int scsi_unregister_module(int module_type, void *ptr) { + int retval = 0; + switch (module_type) { case MODULE_SCSI_HA: - scsi_unregister_host((Scsi_Host_Template *) ptr); + retval = scsi_unregister_host((Scsi_Host_Template *) ptr); break; case MODULE_SCSI_DEV: - scsi_unregister_device((struct Scsi_Device_Template *) ptr); - break; + retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr); + break; /* The rest of these are not yet implemented. */ case MODULE_SCSI_CONST: case MODULE_SCSI_IOCTL: break; default: } - return; + return retval; } #ifdef CONFIG_PROC_FS