Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 305

kernel-2.6.18-238.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Sun, 29 Aug 2010 15:49:21 -0400
Subject: [block] cciss: dynamic allocate struct device for logical
Message-id: <1283097002-3341-23-git-send-email-thenzl@redhat.com>
Patchwork-id: 27868
O-Subject: [RHEL6 PATCH 22/63] cciss: Dynamically allocate struct device for
	logical drive
Bugzilla: 568830
RH-Acked-by: Neil Horman <nhorman@redhat.com>

Dynamically allocated struct device for each logical drive as needed
instead of allocating them all at once up front.

diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 862d1ca..b2cd894 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -252,6 +252,16 @@ static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[],
 
 #ifdef CONFIG_PROC_FS
 
+/* cciss_hba_release is called when the reference count
+ * of h->dev goes to zero.
+ */
+static void cciss_hba_release(struct device *dev)
+{
+	/* nothing to do, but need this to avoid a warning
+	 * about not having a release handler from lib/kref.c.
+	 */
+}
+
 /*
  * Report information about this controller.
  */
@@ -589,6 +599,7 @@ static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
 {
 	device_initialize(&h->dev);
 	h->dev.bus = &cciss_bus_type;
+	h->dev.release = cciss_hba_release;
 	strncpy(h->dev.bus_id, h->devname, BUS_ID_SIZE);
 	h->dev.parent = &h->pdev->dev;
 
@@ -601,6 +612,15 @@ static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
 static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
 {
 	device_del(&h->dev);
+	put_device(&h->dev); /* final put. */
+}
+
+/* cciss_device_release is called when the reference count
+ * of h->drv[x].dev goes to zero.
+ */
+static void cciss_device_release(struct device *dev)
+{
+	kfree(dev);
 }
 
 /*
@@ -609,28 +629,30 @@ static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
  * /sys/bus/pci/devices/<dev/ccis#/. We also create a link from
  * /sys/block/cciss!c#d# to this entry.
  */
-static int cciss_create_ld_sysfs_entry(struct ctlr_info *h,
-				       drive_info_struct *drv,
+static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,
 				       int drv_index)
 {
 	int err;
 	int i;
+	drive_info_struct *drv = &h->drv[drv_index];
+	struct device *dev;
 
-	drv->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
-	if (!drv->dev)
+	dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!dev)
 		return -ENOMEM;
 
 	/*
 	 * Stuff backpointer to drv into dev->driver_data, so we can
 	 * get back to the device in sysfs routines.
 	 */
-	dev_set_drvdata(drv->dev, drv);
-
-	device_initialize(drv->dev);
-	(*drv->dev).bus = &cciss_bus_type;
-	snprintf((*drv->dev).bus_id, BUS_ID_SIZE, "c%dd%d", h->ctlr, drv_index);
-	(*drv->dev).parent = &h->dev;
-
+	device_initialize(dev);
+	// dev->type = &cciss_dev_type;
+	dev->bus = &cciss_bus_type;
+	dev->release = cciss_device_release;
+	snprintf(dev->bus_id, BUS_ID_SIZE, "c%dd%d", h->ctlr, drv_index);
+	dev->parent = &h->dev;
+	h->drv[drv_index].dev = dev;
+	dev_set_drvdata(dev, &h->drv[drv_index]);
 	err = device_add(drv->dev);
 	if (err)
 		goto mem;
@@ -655,11 +677,12 @@ mem:
 /*
  * Remove sysfs entries for a logical drive.
  */
-static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv)
+static void cciss_destroy_ld_sysfs_entry(struct ctlr_info *h, int drv_index)
 {
-	device_del(drv->dev);
-	kfree(drv->dev);
-	drv->dev = NULL;
+	struct device *dev = h->drv[drv_index].dev;
+	device_del(dev);
+	put_device(dev); /* the "final" put. */
+	h->drv[drv_index].dev = NULL;
 }
 
 /*
@@ -1725,15 +1748,24 @@ static void cciss_get_uid(int ctlr, int logvol,
 	kfree(buf);
 	return;
 }
-
-static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
+/*
+ * cciss_add_disk sets up the block device queue for a logical drive
+ */
+static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
 				int drv_index)
 {
 	disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+	if (!disk->queue)
+		goto init_queue_failure;
+
 	sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index);
 	disk->major = h->major;
 	disk->first_minor = drv_index << NWD_SHIFT;
 	disk->fops = &cciss_fops;
+	if (h->drv[drv_index].dev == NULL) {
+		if (cciss_create_ld_sysfs_entry(h, drv_index))
+			goto cleanup_queue;
+	}
 	disk->private_data = &h->drv[drv_index];
 	disk->driverfs_dev = &h->pdev->dev;
 
@@ -1761,6 +1793,14 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
 	wmb();
 	h->drv[drv_index].queue = disk->queue;
 	add_disk(disk);
+	return 0;
+
+cleanup_queue:
+	blk_cleanup_queue(disk->queue);
+	disk->queue = NULL;
+
+init_queue_failure:
+	return -1;
 }
 
 /* This function will check the usage_count of the drive to be updated/added.
@@ -1945,7 +1985,7 @@ static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[], int controll
 	memcpy(h->drv[drv_index].LunID, lunid,
 		sizeof(h->drv[drv_index].LunID));
 
-	if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index))
+	if (cciss_create_ld_sysfs_entry(h, drv_index))
 		goto err_free_disk;
 
 	/* Don't need to mark this busy because nobody
@@ -2085,7 +2125,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
  			h->drv[i].busy_configuring = 1;
  			spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
  			return_code = deregister_disk(h, i, 1);
-			cciss_destroy_ld_sysfs_entry(&h->drv[i]);
+			cciss_destroy_ld_sysfs_entry(h, i);
  			h->drv[i].busy_configuring = 0;
 		}
  	}
@@ -2227,7 +2267,7 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
 				 * indicate that this element of the drive
 				 * array is free.
 				 */
-	cciss_destroy_ld_sysfs_entry(drv);
+	cciss_destroy_ld_sysfs_entry(h, drv_index);
 
 	if (clear_all) {
 		/* check to see if it was the last disk */
@@ -4156,6 +4196,9 @@ clean4:
 		drive_info_struct *drv = &(hba[i]->drv[j]);
 		if (drv->queue)
 			blk_cleanup_queue(drv->queue);
+		if (hba[i]->drv[j].dev != NULL &&
+			(j == 0 || hba[i]->drv[j].raid_level != -1))
+				cciss_destroy_ld_sysfs_entry(hba[i], j);
 	}
 	pci_release_regions(pdev);
 	/* This call to pci_disable_device causes the driver to be unable
@@ -4233,7 +4276,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
 				blk_cleanup_queue(q);
 		}
 		if (hba[i]->drv[j].raid_level != -1)
-			cciss_destroy_ld_sysfs_entry(&hba[i]->drv[j]);
+			cciss_destroy_ld_sysfs_entry(hba[i], j);
 
 	}
 
@@ -4293,7 +4336,7 @@ static int __init cciss_init(void)
 	if (err)
 		goto err_bus_register;
 
-	return 0;
+	return err;
 
 err_bus_register:
 	bus_unregister(&cciss_bus_type);