* [PATCH] get rid of global arrays in sd
@ 2002-10-28 16:38 Christoph Hellwig
0 siblings, 0 replies; only message in thread
From: Christoph Hellwig @ 2002-10-28 16:38 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
Okay, this is the final version of the sd patch to remove sd_dsk_arr.
Instead of keeping a big global array we allocate one structure for
each disk dynamically in sd_attach. We can use the higher level
private data to access it almost everywhere, for the few other
places we keep a linked list of all disks (these are walked only
in slow-patheß).
This patch also allows to get rid of the sd_init midlayer method and
the CONFIG_SD_EXTRA_DEVS option - sd has no more static limit to
the number of disk except of the number of assigned majors.
--- 1.3/drivers/scsi/Config.help Tue Oct 1 19:04:56 2002
+++ edited/drivers/scsi/Config.help Mon Oct 28 16:27:38 2002
@@ -34,19 +34,6 @@
is located on a SCSI disk. In this case, do not compile the driver
for your SCSI host adapter (below) as a module either.
-CONFIG_SD_EXTRA_DEVS
- This controls the amount of additional space allocated in tables for
- drivers that are loaded as modules after the kernel is booted. In
- the event that the SCSI core itself was loaded as a module, this
- value is the number of additional disks that can be loaded after the
- first host driver is loaded.
-
- Admittedly this isn't pretty, but there are tons of race conditions
- involved with resizing the internal arrays on the fly. Someday this
- flag will go away, and everything will work automatically.
-
- If you don't understand what's going on, go with the default.
-
CONFIG_CHR_DEV_ST
If you want to use a SCSI tape drive under Linux, say Y and read the
SCSI-HOWTO, available from
--- 1.16/drivers/scsi/Config.in Fri Oct 11 10:24:07 2002
+++ edited/drivers/scsi/Config.in Mon Oct 28 16:27:38 2002
@@ -2,10 +2,6 @@
dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
-if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
- int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
-fi
-
dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
dep_tristate ' SCSI OnStream SC-x0 tape support' CONFIG_CHR_DEV_OSST $CONFIG_SCSI
--- 1.23/drivers/scsi/hosts.h Mon Oct 28 01:41:15 2002
+++ edited/drivers/scsi/hosts.h Mon Oct 28 16:27:38 2002
@@ -620,13 +620,9 @@
* The generics driver has been updated to resize as required. So as the tape
* driver. Two down, two more to go.
*/
-#ifndef CONFIG_SD_EXTRA_DEVS
-#define CONFIG_SD_EXTRA_DEVS 2
-#endif
#ifndef CONFIG_SR_EXTRA_DEVS
#define CONFIG_SR_EXTRA_DEVS 2
#endif
-#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
--- 1.78/drivers/scsi/sd.c Sun Oct 27 16:54:59 2002
+++ edited/drivers/scsi/sd.c Mon Oct 28 17:17:57 2002
@@ -54,29 +54,17 @@
#include <scsi/scsi_ioctl.h>
#include <scsi/scsicam.h>
-
-#define N_SD_MAJORS 8
-#define SD_MAJOR_MASK (N_SD_MAJORS - 1)
-
-#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
-
-#define SCSI_DISKS_PER_MAJOR 16
-#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8)
-#define SD_MINOR_NUMBER(i) ((i) & 255)
-#define MKDEV_SD_PARTITION(i) mk_kdev(SD_MAJOR_NUMBER(i), (i) & 255)
-#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4)
-#define N_USED_SD_MAJORS (1 + ((sd_template.dev_max - 1) >> 4))
-
/*
- * Time out in seconds for disks and Magneto-opticals (which are slower).
+ * Remaining dev_t-handling stuff
*/
-#define SD_TIMEOUT (30 * HZ)
-#define SD_MOD_TIMEOUT (75 * HZ)
+#define SD_MAJORS 8
+#define SD_MAJOR(i) ((i) ? SCSI_DISK1_MAJOR+(i) : SCSI_DISK0_MAJOR)
/*
- * Amount to over allocate sd_dsk_arr by
+ * Time out in seconds for disks and Magneto-opticals (which are slower).
*/
-#define SD_DSK_ARR_LUMP 6
+#define SD_TIMEOUT (30 * HZ)
+#define SD_MOD_TIMEOUT (75 * HZ)
/*
* Number of allowed retries
@@ -84,6 +72,7 @@
#define SD_MAX_RETRIES 5
struct scsi_disk {
+ struct list_head list; /* list of all scsi_disks */
struct scsi_device *device;
struct gendisk *disk;
sector_t capacity; /* size in 512-byte sectors */
@@ -93,20 +82,20 @@
unsigned RCD : 1; /* state of disk RCD bit */
};
-static struct scsi_disk ** sd_dsk_arr;
-static rwlock_t sd_dsk_arr_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(sd_devlist);
+static spinlock_t sd_devlist_lock = SPIN_LOCK_UNLOCKED;
static int check_scsidisk_media_change(struct gendisk *);
static int sd_revalidate(struct gendisk *);
static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk);
+static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-static int sd_init(void);
static int sd_attach(struct scsi_device *);
static int sd_detect(struct scsi_device *);
static void sd_detach(struct scsi_device *);
static int sd_init_command(struct scsi_cmnd *);
-static int sd_synchronize_cache(int, int);
+static int sd_synchronize_cache(struct scsi_disk *, int);
static int sd_notifier(struct notifier_block *, unsigned long, void *);
static struct notifier_block sd_notifier_block = {sd_notifier, NULL, 0};
@@ -121,58 +110,40 @@
.max_major = SCSI_DISK7_MAJOR,
.blk = 1,
.detect = sd_detect,
- .init = sd_init,
.attach = sd_attach,
.detach = sd_detach,
.init_command = sd_init_command,
};
-static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-
-static struct scsi_disk * sd_get_sdisk(int index);
-
-#if defined(CONFIG_PPC32)
-/**
- * sd_find_target - find kdev_t of first scsi disk that matches
- * given host and scsi_id.
- * @host: Scsi_Host object pointer that owns scsi device of interest
- * @scsi_id: scsi (target) id number of device of interest
- *
- * Returns kdev_t of first scsi device that matches arguments or
- * NODEV of no match.
- *
- * Notes: Looks like a hack, should scan for <host,channel,id,lin>
- * tuple.
- * [Architectural dependency: ppc only.] Moved here from
- * arch/ppc/pmac_setup.c.
- **/
-kdev_t __init
-sd_find_target(void *hp, int scsi_id)
+static struct scsi_disk *sd_find_by_sdev(Scsi_Device *sd)
{
struct scsi_disk *sdkp;
- struct scsi_device *sdp;
- struct Scsi_Host *shp = hp;
- int dsk_nr;
- kdev_t retval = NODEV;
- unsigned long iflags;
- SCSI_LOG_HLQUEUE(3, printk("sd_find_target: host_nr=%d, "
- "scsi_id=%d\n", shp->host_no, scsi_id));
- read_lock_irqsave(&sd_dsk_arr_lock, iflags);
- for (dsk_nr = 0; dsk_nr < sd_template.dev_max; ++dsk_nr) {
- sdkp = sd_dsk_arr[dsk_nr];
- if (sdkp == NULL)
- continue;
- sdp = sdkp->device;
- if (sdp && (sdp->host == shp) && (sdp->id == scsi_id)) {
- retval = MKDEV_SD(dsk_nr);
- break;
+ spin_lock(&sd_devlist_lock);
+ list_for_each_entry(sdkp, &sd_devlist, list) {
+ if (sdkp->device == sd) {
+ spin_unlock(&sd_devlist_lock);
+ return sdkp;
}
}
- read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
- return retval;
+
+ spin_unlock(&sd_devlist_lock);
+ return NULL;
+}
+
+static inline void sd_devlist_insert(struct scsi_disk *sdkp)
+{
+ spin_lock(&sd_devlist_lock);
+ list_add(&sdkp->list, &sd_devlist);
+ spin_unlock(&sd_devlist_lock);
+}
+
+static inline void sd_devlist_remove(struct scsi_disk *sdkp)
+{
+ spin_lock(&sd_devlist_lock);
+ list_del(&sdkp->list);
+ spin_unlock(&sd_devlist_lock);
}
-#endif
/**
* sd_ioctl - process an ioctl
@@ -1188,94 +1159,6 @@
kfree(buffer);
}
-/*
- * The sd_init() function looks at all SCSI drives present, determines
- * their size, and reads partition table entries for them.
- */
-
-static int sd_registered;
-
-/**
- * sd_init- called during driver initialization (after
- * sd_detect() is called for each scsi device present).
- *
- * Returns 0 is successful (or already called); 1 if error
- *
- * Note: this function is invoked from the scsi mid-level.
- **/
-static int sd_init()
-{
- int k, maxparts;
- struct scsi_disk * sdkp;
-
- SCSI_LOG_HLQUEUE(3, printk("sd_init: dev_noticed=%d\n",
- sd_template.dev_noticed));
- if (sd_template.dev_noticed == 0)
- return 0;
-
- if (NULL == sd_dsk_arr)
- sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
-
- if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR)
- sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR;
-
- /* At most 16 partitions on each scsi disk. */
- maxparts = (sd_template.dev_max << 4);
- if (maxparts == 0)
- return 0;
-
- if (!sd_registered) {
- for (k = 0; k < N_USED_SD_MAJORS; k++) {
- if (register_blkdev(SD_MAJOR(k), "sd", &sd_fops)) {
- printk(KERN_NOTICE "Unable to get major %d "
- "for SCSI disk\n", SD_MAJOR(k));
- return 1;
- }
- }
- sd_registered++;
- }
- /* We do not support attaching loadable devices yet. */
- if (sd_dsk_arr)
- return 0;
-
- /* allocate memory */
-#define init_mem_lth(x,n) x = vmalloc((n) * sizeof(*x))
-#define zero_mem_lth(x,n) memset(x, 0, (n) * sizeof(*x))
-
- init_mem_lth(sd_dsk_arr, sd_template.dev_max);
- if (sd_dsk_arr) {
- zero_mem_lth(sd_dsk_arr, sd_template.dev_max);
- for (k = 0; k < sd_template.dev_max; ++k) {
- sdkp = vmalloc(sizeof(struct scsi_disk));
- if (NULL == sdkp)
- goto cleanup_mem;
- memset(sdkp, 0, sizeof(struct scsi_disk));
- sd_dsk_arr[k] = sdkp;
- }
- }
-
- if (!sd_dsk_arr)
- goto cleanup_mem;
-
- return 0;
-
-#undef init_mem_lth
-#undef zero_mem_lth
-
-cleanup_mem:
- if (sd_dsk_arr) {
- for (k = 0; k < sd_template.dev_max; ++k)
- vfree(sd_dsk_arr[k]);
- vfree(sd_dsk_arr);
- sd_dsk_arr = NULL;
- }
- for (k = 0; k < N_USED_SD_MAJORS; k++) {
- unregister_blkdev(SD_MAJOR(k), "sd");
- }
- sd_registered--;
- return 1;
-}
-
/**
* sd_detect - called at the start of driver initialization, once
* for each scsi device (not just disks) present.
@@ -1284,7 +1167,6 @@
* 1 if this device is of interest (e.g. a disk).
*
* Note: this function is invoked from the scsi mid-level.
- * This function is called before sd_init() so very little is available.
**/
static int sd_detect(struct scsi_device * sdp)
{
@@ -1309,51 +1191,43 @@
* <host,channel,id,lun> (found in sdp) and new device name
* (e.g. /dev/sda). More precisely it is the block device major
* and minor number that is chosen here.
+ *
+ * Assume sd_attach is not re-entrant (for time being)
+ * Also think about sd_attach() and sd_detach() running coincidentally.
**/
static int sd_attach(struct scsi_device * sdp)
{
struct scsi_disk *sdkp = NULL; /* shut up lame gcc warning */
int dsk_nr;
- unsigned long iflags;
struct gendisk *gd;
if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD))
return 0;
- gd = alloc_disk(16);
- if (!gd)
- return 1;
-
SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
- if (sd_template.nr_dev >= sd_template.dev_max) {
- printk(KERN_ERR "sd_init: no more room for device\n");
+ sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
+ if (!sdkp)
goto out;
- }
+
+ gd = alloc_disk(16);
+ if (!gd)
+ goto out_free;
/*
- * Assume sd_attach is not re-entrant (for time being)
- * Also think about sd_attach() and sd_detach() running coincidentally.
+ * XXX This doesn't make us better than the previous code in the
+ * XXX end (not worse either, though..).
+ * XXX To properly support hotplugging we should have a bitmap and
+ * XXX use find_first_zero_bit on it. This will happen at the
+ * XXX same time template->nr_* goes away. --hch
*/
- write_lock_irqsave(&sd_dsk_arr_lock, iflags);
- for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
- sdkp = sd_dsk_arr[dsk_nr];
- if (!sdkp->device) {
- memset(sdkp, 0, sizeof(struct scsi_disk));
- sdkp->device = sdp;
- break;
- }
- }
- write_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
+ dsk_nr = sd_template.nr_dev++;
- if (!sdkp || dsk_nr >= sd_template.dev_max) {
- printk(KERN_ERR "sd_init: sd_dsk_arr corrupted\n");
- goto out;
- }
+ sdkp->device = sdp;
+ sdkp->disk = gd;
sd_init_onedisk(sdkp, gd);
- sd_template.nr_dev++;
gd->de = sdp->de;
gd->major = SD_MAJOR(dsk_nr>>4);
@@ -1363,24 +1237,28 @@
sprintf(gd->disk_name, "sd%c%c",'a'+dsk_nr/26-1,'a'+dsk_nr%26);
else
sprintf(gd->disk_name, "sd%c",'a'+dsk_nr%26);
- gd->flags = sdp->removable ? GENHD_FL_REMOVABLE : 0;
gd->driverfs_dev = &sdp->sdev_driverfs_dev;
- gd->flags |= GENHD_FL_DRIVERFS | GENHD_FL_DEVFS;
+ gd->flags = GENHD_FL_DRIVERFS | GENHD_FL_DEVFS;
+ if (sdp->removable)
+ gd->flags |= GENHD_FL_REMOVABLE;
gd->private_data = sdkp;
gd->queue = &sdkp->device->request_queue;
+ sd_devlist_insert(sdkp);
set_capacity(gd, sdkp->capacity);
add_disk(gd);
- sdkp->disk = gd;
printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
"id %d, lun %d\n", sdp->removable ? "removable " : "",
- gd->disk_name, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+ gd->disk_name, sdp->host->host_no, sdp->channel,
+ sdp->id, sdp->lun);
+
return 0;
+out_free:
+ kfree(sdkp);
out:
sdp->attached--;
- put_disk(gd);
return 1;
}
@@ -1409,39 +1287,30 @@
**/
static void sd_detach(struct scsi_device * sdp)
{
- struct scsi_disk *sdkp = NULL;
- int dsk_nr;
- unsigned long iflags;
+ struct scsi_disk *sdkp;
SCSI_LOG_HLQUEUE(3, printk("sd_detach: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id,
sdp->lun));
- write_lock_irqsave(&sd_dsk_arr_lock, iflags);
- for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
- sdkp = sd_dsk_arr[dsk_nr];
- if (sdkp->device == sdp) {
- break;
- }
- }
- write_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
- if (dsk_nr >= sd_template.dev_max)
+
+ sdkp = sd_find_by_sdev(sdp);
+ if (!sdkp)
return;
/* check that we actually have a write back cache to synchronize */
- if(sdkp->WCE) {
+ if (sdkp->WCE) {
printk(KERN_NOTICE "Synchronizing SCSI cache: ");
- sd_synchronize_cache(dsk_nr, 1);
+ sd_synchronize_cache(sdkp, 1);
printk("\n");
}
- sdkp->device = NULL;
- sdkp->capacity = 0;
- /* sdkp->detaching = 1; */
+ sd_devlist_remove(sdkp);
del_gendisk(sdkp->disk);
sdp->attached--;
sd_template.dev_noticed--;
sd_template.nr_dev--;
put_disk(sdkp->disk);
+ kfree(sdkp);
}
/**
@@ -1452,16 +1321,29 @@
**/
static int __init init_sd(void)
{
- int rc;
+ int majors = 0, rc = -ENODEV, i;
+
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
- sd_template.module = THIS_MODULE;
- rc = scsi_register_device(&sd_template);
- if (!rc) {
- sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag;
- sd_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
- driver_register(&sd_template.scsi_driverfs_driver);
- register_reboot_notifier(&sd_notifier_block);
+
+ for (i = 0; i < SD_MAJORS; i++) {
+ if (register_blkdev(SD_MAJOR(i), "sd", &sd_fops))
+ printk(KERN_NOTICE
+ "Unable to get major %d for SCSI disk\n",
+ SD_MAJOR(i));
+ else
+ majors++;
}
+
+ if (!majors)
+ return -ENODEV;
+
+ rc = scsi_register_device(&sd_template);
+ if (rc)
+ return rc;
+ sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag;
+ sd_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+ driver_register(&sd_template.scsi_driverfs_driver);
+ register_reboot_notifier(&sd_notifier_block);
return rc;
}
@@ -1472,48 +1354,38 @@
**/
static void __exit exit_sd(void)
{
- int k;
+ int i;
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
- scsi_unregister_device(&sd_template);
- for (k = 0; k < N_USED_SD_MAJORS; k++)
- unregister_blkdev(SD_MAJOR(k), "sd");
-
- sd_registered--;
- if (sd_dsk_arr != NULL) {
- for (k = 0; k < sd_template.dev_max; ++k)
- vfree(sd_dsk_arr[k]);
- vfree(sd_dsk_arr);
- }
- sd_template.dev_max = 0;
- driver_unregister(&sd_template.scsi_driverfs_driver);
unregister_reboot_notifier(&sd_notifier_block);
+ scsi_unregister_device(&sd_template);
+ for (i = 0; i < SD_MAJORS; i++)
+ unregister_blkdev(SD_MAJOR(i), "sd");
+ driver_unregister(&sd_template.scsi_driverfs_driver);
}
-static int sd_notifier(struct notifier_block *nbt, unsigned long event, void *buf)
+/*
+ * XXX: this function does not take sd_devlist_lock to synchronize
+ * access to sd_devlist. This should be safe as no other reboot
+ * notifier can access it.
+ */
+static int sd_notifier(struct notifier_block *n, unsigned long event, void *p)
{
- int i;
- char *msg = "Synchronizing SCSI caches: ";
-
- if (!(event == SYS_RESTART || event == SYS_HALT
- || event == SYS_POWER_OFF))
+ if (event != SYS_RESTART &&
+ event != SYS_HALT &&
+ event != SYS_POWER_OFF)
return NOTIFY_DONE;
- for (i = 0; i < sd_template.dev_max; i++) {
- struct scsi_disk *sdkp = sd_get_sdisk(i);
- if (!sdkp || !sdkp->device)
- continue;
- if (sdkp->WCE) {
- if(msg) {
- printk(KERN_NOTICE "%s", msg);
- msg = NULL;
- }
- sd_synchronize_cache(i, 1);
- }
- }
- if(!msg)
+ if (!list_empty(&sd_devlist)) {
+ struct scsi_disk *sdkp;
+
+ printk(KERN_NOTICE "Synchronizing SCSI caches: ");
+ list_for_each_entry(sdkp, &sd_devlist, list)
+ if (sdkp->WCE)
+ sd_synchronize_cache(sdkp, 1);
printk("\n");
+ }
return NOTIFY_OK;
}
@@ -1521,10 +1393,9 @@
/* send a SYNCHRONIZE CACHE instruction down to the device through the
* normal SCSI command structure. Wait for the command to complete (must
* have user context) */
-static int sd_synchronize_cache(int index, int verbose)
+static int sd_synchronize_cache(struct scsi_disk *sdkp, int verbose)
{
struct scsi_request *SRpnt;
- struct scsi_disk *sdkp = sd_get_sdisk(index);
struct scsi_device *SDpnt = sdkp->device;
int retries, the_result;
@@ -1570,18 +1441,6 @@
}
scsi_release_request(SRpnt);
return (the_result == 0);
-}
-
-static struct scsi_disk * sd_get_sdisk(int index)
-{
- struct scsi_disk * sdkp = NULL;
- unsigned long iflags;
-
- read_lock_irqsave(&sd_dsk_arr_lock, iflags);
- if (sd_dsk_arr && (index >= 0) && (index < sd_template.dev_max))
- sdkp = sd_dsk_arr[index];
- read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
- return sdkp;
}
MODULE_LICENSE("GPL");
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2002-10-28 16:38 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-10-28 16:38 [PATCH] get rid of global arrays in sd Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).