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);