]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] preparation to use of driverfs refcounts, part 1 - partitions
authorAlexander Viro <viro@math.psu.edu>
Tue, 15 Oct 2002 11:25:18 +0000 (04:25 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 15 Oct 2002 11:25:18 +0000 (04:25 -0700)
* update_partition() split into add_partition() and delete_partition().
* all updating of ->part[] is switched to these two (including initial
filling/final cleaning).
* per-partition devices are allocated on-demand and never reused.
We allocate struct device in add_partition() and put reference to it into
hd_struct.  ->release() for that struct device frees it.  delete_partition()
removes reference from hd_struct and does put_device() on it.  Basically,
we get rid of problems with reused struct device by never reusing them...
At that point devices for partitions are nice and sane.

drivers/block/ioctl.c
fs/partitions/check.c
include/linux/genhd.h

index fb6a8edb8e2115a4d0f3c325287a137e89809b4b..4af05bc32db2b0040de8c5fc9385adacc00b8b0e 100644 (file)
@@ -58,9 +58,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
                                        return -EBUSY;
                        }
                        /* all seems OK */
-                       disk->part[part - 1].start_sect = start;
-                       disk->part[part - 1].nr_sects = length;
-                       update_partition(disk, part);
+                       add_partition(disk, part, start, length);
                        return 0;
                case BLKPG_DEL_PARTITION:
                        if (disk->part[part - 1].nr_sects == 0)
@@ -79,9 +77,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
                        fsync_bdev(bdevp);
                        invalidate_bdev(bdevp, 0);
 
-                       disk->part[part].start_sect = 0;
-                       disk->part[part].nr_sects = 0;
-                       update_partition(disk, part);
+                       delete_partition(disk, part);
                        bd_release(bdevp);
                        bdput(bdevp);
                        return 0;
index 72e71ea060e7d9c494cf792030e1e322f75bb4e6..a61a83ded312fb9f458fc96ac8283ef201646800 100644 (file)
@@ -130,96 +130,49 @@ static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL);
 
 static void driverfs_create_partitions(struct gendisk *hd)
 {
-       int max_p = hd->minors;
-       struct hd_struct *p = hd->part;
-       char name[DEVICE_NAME_SIZE];
-       char bus_id[BUS_ID_SIZE];
-       struct device *dev, *parent;
-       int part;
+       struct device *parent = hd->driverfs_dev;
+       struct device *dev = &hd->disk_dev;
 
        /* if driverfs not supported by subsystem, skip partitions */
        if (!(hd->flags & GENHD_FL_DRIVERFS))
                return;
 
-       parent = hd->driverfs_dev;
-
        if (parent)  {
-               sprintf(name, "%s", parent->name);
-               sprintf(bus_id, "%s:", parent->bus_id);
+               sprintf(dev->name, "%sdisc", parent->name);
+               sprintf(dev->bus_id, "%sdisc", parent->bus_id);
+               dev->parent = parent;
+               dev->bus = parent->bus;
        } else {
-               *name = *bus_id = '\0';
+               sprintf(dev->name, "disc");
+               sprintf(dev->bus_id, "disc");
        }
-
-       dev = &hd->disk_dev;
        dev->driver_data = (void *)(long)__mkdev(hd->major, hd->first_minor);
-       sprintf(dev->name, "%sdisc", name);
-       sprintf(dev->bus_id, "%sdisc", bus_id);
-       for (part=1; part < max_p; part++) {
-               dev = &p[part-1].hd_driverfs_dev;
-               sprintf(dev->name, "%spart%d", name, part);
-               sprintf(dev->bus_id, "%s:p%d", bus_id, part);
-               if (!p[part-1].nr_sects)
-                       continue;
-               dev->driver_data =
-                               (void *)(long)__mkdev(hd->major, hd->first_minor+part);
-       }
-
-       dev = &hd->disk_dev;
-       dev->parent = parent;
-       if (parent)
-               dev->bus = parent->bus;
        device_register(dev);
        device_create_file(dev, &dev_attr_type);
        device_create_file(dev, &dev_attr_kdev);
-
-       for (part=0; part < max_p-1; part++) {
-               dev = &p[part].hd_driverfs_dev;
-               dev->parent = parent;
-               if (parent)
-                       dev->bus = parent->bus;
-               if (!dev->driver_data)
-                       continue;
-               device_register(dev);
-               device_create_file(dev, &dev_attr_type);
-               device_create_file(dev, &dev_attr_kdev);
-       }
 }
 
 static void driverfs_remove_partitions(struct gendisk *hd)
 {
-       int max_p = hd->minors;
-       struct device *dev;
-       struct hd_struct *p;
-       int part;
-
-       for (part=1, p = hd->part; part < max_p; part++, p++) {
-               dev = &p->hd_driverfs_dev;
-               if (dev->driver_data) {
-                       device_remove_file(dev, &dev_attr_type);
-                       device_remove_file(dev, &dev_attr_kdev);
-                       put_device(dev);        
-                       dev->driver_data = NULL;
-               }
-       }
-       dev = &hd->disk_dev;
-       if (dev->driver_data) {
-               device_remove_file(dev, &dev_attr_type);
-               device_remove_file(dev, &dev_attr_kdev);
-               put_device(dev);        
-               dev->driver_data = NULL;
-       }
+       struct device *dev = &hd->disk_dev;
+       if (!(hd->flags & GENHD_FL_DRIVERFS))
+               return;
+       device_remove_file(dev, &dev_attr_type);
+       device_remove_file(dev, &dev_attr_kdev);
+       put_device(dev);        
 }
 
-static void check_partition(struct gendisk *hd, struct block_device *bdev)
+static struct parsed_partitions *
+check_partition(struct gendisk *hd, struct block_device *bdev)
 {
+       struct parsed_partitions *state;
        devfs_handle_t de = NULL;
        char buf[64];
-       struct parsed_partitions *state;
-       int i;
+       int i, res;
 
        state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
        if (!state)
-               return;
+               return NULL;
 
        if (hd->flags & GENHD_FL_DEVFS)
                de = hd->de;
@@ -234,31 +187,19 @@ static void check_partition(struct gendisk *hd, struct block_device *bdev)
                        sprintf(state->name, "p");
        }
        state->limit = hd->minors;
-       for (i = 0; check_part[i]; i++) {
-               int res, j;
-               struct hd_struct *p;
+       i = res = 0;
+       while (!res && check_part[i]) {
                memset(&state->parts, 0, sizeof(state->parts));
-               res = check_part[i](state, bdev);
-               if (!res)
-                       continue;
-               if (res < 0) {
-                       if (warn_no_part)
-                               printk(" unable to read partition table\n");
-                       return;
-               } 
-               p = hd->part;
-               for (j = 1; j < state->limit; j++) {
-                       p[j-1].start_sect = state->parts[j].from;
-                       p[j-1].nr_sects = state->parts[j].size;
-#if CONFIG_BLK_DEV_MD
-                       if (!state->parts[j].flags)
-                               continue;
-                       md_autodetect_dev(bdev->bd_dev+j);
-#endif
-               }
-               return;
+               res = check_part[i++](state, bdev);
        }
-       printk(" unknown partition table\n");
+       if (res > 0)
+               return state;
+       if (!res)
+               printk(" unknown partition table\n");
+       else if (warn_no_part)
+               printk(" unable to read partition table\n");
+       kfree(state);
+       return NULL;
 }
 
 static void devfs_register_partition(struct gendisk *dev, int part)
@@ -329,9 +270,6 @@ static void devfs_create_partitions(struct gendisk *dev)
        devfs_auto_unregister(dev->disk_de, slave);
        if (!(dev->flags & GENHD_FL_DEVFS))
                devfs_auto_unregister (slave, dir);
-       for (part = 1; part < max_p; part++, p++)
-               if (p->nr_sects)
-                       devfs_register_partition(dev, part);
 #endif
 }
 
@@ -379,11 +317,6 @@ static void devfs_create_cdrom(struct gendisk *dev)
 static void devfs_remove_partitions(struct gendisk *dev)
 {
 #ifdef CONFIG_DEVFS_FS
-       int part;
-       for (part = dev->minors-1; part--; ) {
-               devfs_unregister(dev->part[part].de);
-               dev->part[part].de = NULL;
-       }
        devfs_unregister(dev->disk_de);
        dev->disk_de = NULL;
        if (dev->flags & GENHD_FL_CD)
@@ -393,10 +326,69 @@ static void devfs_remove_partitions(struct gendisk *dev)
 #endif
 }
 
+void delete_partition(struct gendisk *disk, int part)
+{
+       struct hd_struct *p = disk->part + part - 1;
+       struct device *dev;
+       if (!p->nr_sects)
+               return;
+       p->start_sect = 0;
+       p->nr_sects = 0;
+       devfs_unregister(p->de);
+       dev = p->hd_driverfs_dev;
+       p->hd_driverfs_dev = NULL;
+       if (dev) {
+               device_remove_file(dev, &dev_attr_type);
+               device_remove_file(dev, &dev_attr_kdev);
+               device_unregister(dev); 
+       }
+}
+
+static void part_release(struct device *dev)
+{
+       kfree(dev);
+}
+
+void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
+{
+       struct hd_struct *p = disk->part + part - 1;
+       struct device *parent = disk->disk_dev.parent;
+       struct device *dev;
+
+       p->start_sect = start;
+       p->nr_sects = len;
+       devfs_register_partition(disk, part);
+       if (!(disk->flags & GENHD_FL_DRIVERFS))
+               return;
+       dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+       if (!dev)
+               return;
+       memset(dev, 0, sizeof(struct device));
+       if (parent)  {
+               sprintf(dev->name, "%spart%d", parent->name, part);
+               sprintf(dev->bus_id, "%s:p%d", parent->bus_id, part);
+               dev->parent = parent;
+               dev->bus = parent->bus;
+       } else {
+               sprintf(dev->name, "part%d", part);
+               sprintf(dev->bus_id, "p%d", part);
+       }
+       dev->release = part_release;
+       dev->driver_data =
+               (void *)(long)__mkdev(disk->major, disk->first_minor+part);
+       device_register(dev);
+       device_create_file(dev, &dev_attr_type);
+       device_create_file(dev, &dev_attr_kdev);
+       p->hd_driverfs_dev = dev;
+}
+
 /* Not exported, helper to add_disk(). */
 void register_disk(struct gendisk *disk)
 {
+       struct parsed_partitions *state;
        struct block_device *bdev;
+       int j;
+
        if (disk->flags & GENHD_FL_CD)
                devfs_create_cdrom(disk);
 
@@ -411,45 +403,33 @@ void register_disk(struct gendisk *disk)
        bdev = bdget(MKDEV(disk->major, disk->first_minor));
        if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
                return;
-       check_partition(disk, bdev);
+       state = check_partition(disk, bdev);
        driverfs_create_partitions(disk);
        devfs_create_partitions(disk);
-       blkdev_put(bdev, BDEV_RAW);
-}
-
-void update_partition(struct gendisk *disk, int part)
-{
-       struct hd_struct *p = disk->part + part - 1;
-       struct device *dev = &p->hd_driverfs_dev;
-
-       if (!p->nr_sects) {
-               if (p->de) {
-                       devfs_unregister(p->de);
-                       p->de = NULL;
-               }
-               if (dev->driver_data) {
-                       device_remove_file(dev, &dev_attr_type);
-                       device_remove_file(dev, &dev_attr_kdev);
-                       put_device(dev);        
-                       dev->driver_data = NULL;
+       if (state) {
+               for (j = 1; j < state->limit; j++) {
+                       sector_t size = state->parts[j].size;
+                       sector_t from = state->parts[j].from;
+                       if (!size)
+                               continue;
+                       add_partition(disk, j, from, size);
+#if CONFIG_BLK_DEV_MD
+                       if (!state->parts[j].flags)
+                               continue;
+                       md_autodetect_dev(bdev->bd_dev+j);
+#endif
                }
-               return;
+               kfree(state);
        }
-       if (!p->de)
-               devfs_register_partition(disk, part);
-       if (dev->driver_data || !(disk->flags & GENHD_FL_DRIVERFS))
-               return;
-       dev->driver_data =
-               (void *)(long)__mkdev(disk->major, disk->first_minor+part);
-       device_register(dev);
-       device_create_file(dev, &dev_attr_type);
-       device_create_file(dev, &dev_attr_kdev);
+       blkdev_put(bdev, BDEV_RAW);
 }
 
 int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
 {
        kdev_t dev = to_kdev_t(bdev->bd_dev);
+       struct parsed_partitions *state;
        int p, res;
+
        if (!bdev->bd_invalidated)
                return 0;
        if (bdev->bd_part_count)
@@ -458,16 +438,25 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
        if (res)
                return res;
        bdev->bd_invalidated = 0;
-       for (p = 0; p < disk->minors - 1; p++) {
-               disk->part[p].start_sect = 0;
-               disk->part[p].nr_sects = 0;
-       }
+       for (p = 1; p < disk->minors; p++)
+               delete_partition(disk, p);
        if (bdev->bd_op->revalidate)
                bdev->bd_op->revalidate(dev);
-       if (get_capacity(disk))
-               check_partition(disk, bdev);
-       for (p = 1; p < disk->minors; p++)
-               update_partition(disk, p);
+       if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
+               return res;
+       for (p = 1; p < state->limit; p++) {
+               sector_t size = state->parts[p].size;
+               sector_t from = state->parts[p].from;
+               if (!size)
+                       continue;
+               add_partition(disk, p, from, size);
+#if CONFIG_BLK_DEV_MD
+               if (!state->parts[j].flags)
+                       continue;
+               md_autodetect_dev(bdev->bd_dev+p);
+#endif
+       }
+       kfree(state);
        return res;
 }
 
@@ -493,45 +482,25 @@ fail:
        return NULL;
 }
 
-static int wipe_partitions(struct gendisk *disk)
+void del_gendisk(struct gendisk *disk)
 {
        int max_p = disk->minors;
        kdev_t devp;
-       int res;
        int p;
 
        /* invalidate stuff */
        for (p = max_p - 1; p > 0; p--) {
                devp = mk_kdev(disk->major,disk->first_minor + p);
-#if 0                                  /* %%% superfluous? */
-               if (disk->part[p-1].nr_sects == 0)
-                       continue;
-#endif
-               res = invalidate_device(devp, 1);
-               if (res)
-                       return res;
-               disk->part[p-1].start_sect = 0;
-               disk->part[p-1].nr_sects = 0;
+               invalidate_device(devp, 1);
+               delete_partition(disk, p);
        }
        devp = mk_kdev(disk->major,disk->first_minor);
-#if 0                                  /* %%% superfluous? */
-       if (disk->part[p].nr_sects == 0)
-               continue;
-#endif
-       res = invalidate_device(devp, 1);
-       if (res)
-               return res;
+       invalidate_device(devp, 1);
        disk->capacity = 0;
-       return 0;
-}
-
-void del_gendisk(struct gendisk *disk)
-{
-       driverfs_remove_partitions(disk);
-       wipe_partitions(disk);
+       disk->flags &= ~GENHD_FL_UP;
        unlink_gendisk(disk);
+       driverfs_remove_partitions(disk);
        devfs_remove_partitions(disk);
-       disk->flags &= ~GENHD_FL_UP;
 }
 
 struct dev_name {
index 6e1f68900bba24bd2facd0a88af1caac600ec6d2..6b859fad6a8a5cdd02b2cc84d8f60973fc0ac046 100644 (file)
@@ -62,7 +62,7 @@ struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
        devfs_handle_t de;              /* primary (master) devfs entry  */
-       struct device hd_driverfs_dev;  /* support driverfs hiearchy     */
+       struct device *hd_driverfs_dev;  /* support driverfs hiearchy     */
 };
 
 #define GENHD_FL_REMOVABLE  1
@@ -262,7 +262,8 @@ struct unixware_disklabel {
 char *disk_name (struct gendisk *hd, int part, char *buf);
 
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
-extern void update_partition(struct gendisk *disk, int part);
+extern void add_partition(struct gendisk *, int, sector_t, sector_t);
+extern void delete_partition(struct gendisk *, int);
 
 extern struct gendisk *alloc_disk(int minors);
 extern void put_disk(struct gendisk *disk);