Commit afae25b7 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] preparation to use of driverfs refcounts, part 1 - partitions

	* 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.
parent c6973580
...@@ -58,9 +58,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) ...@@ -58,9 +58,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
return -EBUSY; return -EBUSY;
} }
/* all seems OK */ /* all seems OK */
disk->part[part - 1].start_sect = start; add_partition(disk, part, start, length);
disk->part[part - 1].nr_sects = length;
update_partition(disk, part);
return 0; return 0;
case BLKPG_DEL_PARTITION: case BLKPG_DEL_PARTITION:
if (disk->part[part - 1].nr_sects == 0) 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) ...@@ -79,9 +77,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
fsync_bdev(bdevp); fsync_bdev(bdevp);
invalidate_bdev(bdevp, 0); invalidate_bdev(bdevp, 0);
disk->part[part].start_sect = 0; delete_partition(disk, part);
disk->part[part].nr_sects = 0;
update_partition(disk, part);
bd_release(bdevp); bd_release(bdevp);
bdput(bdevp); bdput(bdevp);
return 0; return 0;
......
...@@ -130,96 +130,49 @@ static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL); ...@@ -130,96 +130,49 @@ static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL);
static void driverfs_create_partitions(struct gendisk *hd) static void driverfs_create_partitions(struct gendisk *hd)
{ {
int max_p = hd->minors; struct device *parent = hd->driverfs_dev;
struct hd_struct *p = hd->part; struct device *dev = &hd->disk_dev;
char name[DEVICE_NAME_SIZE];
char bus_id[BUS_ID_SIZE];
struct device *dev, *parent;
int part;
/* if driverfs not supported by subsystem, skip partitions */ /* if driverfs not supported by subsystem, skip partitions */
if (!(hd->flags & GENHD_FL_DRIVERFS)) if (!(hd->flags & GENHD_FL_DRIVERFS))
return; return;
parent = hd->driverfs_dev;
if (parent) { if (parent) {
sprintf(name, "%s", parent->name); sprintf(dev->name, "%sdisc", parent->name);
sprintf(bus_id, "%s:", parent->bus_id); sprintf(dev->bus_id, "%sdisc", parent->bus_id);
dev->parent = parent;
dev->bus = parent->bus;
} else { } 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); 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_register(dev);
device_create_file(dev, &dev_attr_type); device_create_file(dev, &dev_attr_type);
device_create_file(dev, &dev_attr_kdev); device_create_file(dev, &dev_attr_kdev);
}
} }
static void driverfs_remove_partitions(struct gendisk *hd) static void driverfs_remove_partitions(struct gendisk *hd)
{ {
int max_p = hd->minors; struct device *dev = &hd->disk_dev;
struct device *dev; if (!(hd->flags & GENHD_FL_DRIVERFS))
struct hd_struct *p; return;
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_type);
device_remove_file(dev, &dev_attr_kdev); device_remove_file(dev, &dev_attr_kdev);
put_device(dev); put_device(dev);
dev->driver_data = NULL;
}
} }
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; devfs_handle_t de = NULL;
char buf[64]; char buf[64];
struct parsed_partitions *state; int i, res;
int i;
state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
if (!state) if (!state)
return; return NULL;
if (hd->flags & GENHD_FL_DEVFS) if (hd->flags & GENHD_FL_DEVFS)
de = hd->de; de = hd->de;
...@@ -234,31 +187,19 @@ static void check_partition(struct gendisk *hd, struct block_device *bdev) ...@@ -234,31 +187,19 @@ static void check_partition(struct gendisk *hd, struct block_device *bdev)
sprintf(state->name, "p"); sprintf(state->name, "p");
} }
state->limit = hd->minors; state->limit = hd->minors;
for (i = 0; check_part[i]; i++) { i = res = 0;
int res, j; while (!res && check_part[i]) {
struct hd_struct *p;
memset(&state->parts, 0, sizeof(state->parts)); memset(&state->parts, 0, sizeof(state->parts));
res = check_part[i](state, bdev); 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;
} }
if (res > 0)
return state;
if (!res)
printk(" unknown partition table\n"); 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) static void devfs_register_partition(struct gendisk *dev, int part)
...@@ -329,9 +270,6 @@ static void devfs_create_partitions(struct gendisk *dev) ...@@ -329,9 +270,6 @@ static void devfs_create_partitions(struct gendisk *dev)
devfs_auto_unregister(dev->disk_de, slave); devfs_auto_unregister(dev->disk_de, slave);
if (!(dev->flags & GENHD_FL_DEVFS)) if (!(dev->flags & GENHD_FL_DEVFS))
devfs_auto_unregister (slave, dir); devfs_auto_unregister (slave, dir);
for (part = 1; part < max_p; part++, p++)
if (p->nr_sects)
devfs_register_partition(dev, part);
#endif #endif
} }
...@@ -379,11 +317,6 @@ static void devfs_create_cdrom(struct gendisk *dev) ...@@ -379,11 +317,6 @@ static void devfs_create_cdrom(struct gendisk *dev)
static void devfs_remove_partitions(struct gendisk *dev) static void devfs_remove_partitions(struct gendisk *dev)
{ {
#ifdef CONFIG_DEVFS_FS #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); devfs_unregister(dev->disk_de);
dev->disk_de = NULL; dev->disk_de = NULL;
if (dev->flags & GENHD_FL_CD) if (dev->flags & GENHD_FL_CD)
...@@ -393,10 +326,69 @@ static void devfs_remove_partitions(struct gendisk *dev) ...@@ -393,10 +326,69 @@ static void devfs_remove_partitions(struct gendisk *dev)
#endif #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(). */ /* Not exported, helper to add_disk(). */
void register_disk(struct gendisk *disk) void register_disk(struct gendisk *disk)
{ {
struct parsed_partitions *state;
struct block_device *bdev; struct block_device *bdev;
int j;
if (disk->flags & GENHD_FL_CD) if (disk->flags & GENHD_FL_CD)
devfs_create_cdrom(disk); devfs_create_cdrom(disk);
...@@ -411,45 +403,33 @@ void register_disk(struct gendisk *disk) ...@@ -411,45 +403,33 @@ void register_disk(struct gendisk *disk)
bdev = bdget(MKDEV(disk->major, disk->first_minor)); bdev = bdget(MKDEV(disk->major, disk->first_minor));
if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0) if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
return; return;
check_partition(disk, bdev); state = check_partition(disk, bdev);
driverfs_create_partitions(disk); driverfs_create_partitions(disk);
devfs_create_partitions(disk); devfs_create_partitions(disk);
blkdev_put(bdev, BDEV_RAW); if (state) {
} for (j = 1; j < state->limit; j++) {
sector_t size = state->parts[j].size;
void update_partition(struct gendisk *disk, int part) sector_t from = state->parts[j].from;
{ if (!size)
struct hd_struct *p = disk->part + part - 1; continue;
struct device *dev = &p->hd_driverfs_dev; add_partition(disk, j, from, size);
#if CONFIG_BLK_DEV_MD
if (!p->nr_sects) { if (!state->parts[j].flags)
if (p->de) { continue;
devfs_unregister(p->de); md_autodetect_dev(bdev->bd_dev+j);
p->de = NULL; #endif
}
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;
} }
return; kfree(state);
} }
if (!p->de) blkdev_put(bdev, BDEV_RAW);
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);
} }
int rescan_partitions(struct gendisk *disk, struct block_device *bdev) int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{ {
kdev_t dev = to_kdev_t(bdev->bd_dev); kdev_t dev = to_kdev_t(bdev->bd_dev);
struct parsed_partitions *state;
int p, res; int p, res;
if (!bdev->bd_invalidated) if (!bdev->bd_invalidated)
return 0; return 0;
if (bdev->bd_part_count) if (bdev->bd_part_count)
...@@ -458,16 +438,25 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) ...@@ -458,16 +438,25 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
if (res) if (res)
return res; return res;
bdev->bd_invalidated = 0; bdev->bd_invalidated = 0;
for (p = 0; p < disk->minors - 1; p++) { for (p = 1; p < disk->minors; p++)
disk->part[p].start_sect = 0; delete_partition(disk, p);
disk->part[p].nr_sects = 0;
}
if (bdev->bd_op->revalidate) if (bdev->bd_op->revalidate)
bdev->bd_op->revalidate(dev); bdev->bd_op->revalidate(dev);
if (get_capacity(disk)) if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
check_partition(disk, bdev); return res;
for (p = 1; p < disk->minors; p++) for (p = 1; p < state->limit; p++) {
update_partition(disk, 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; return res;
} }
...@@ -493,45 +482,25 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) ...@@ -493,45 +482,25 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
return NULL; return NULL;
} }
static int wipe_partitions(struct gendisk *disk) void del_gendisk(struct gendisk *disk)
{ {
int max_p = disk->minors; int max_p = disk->minors;
kdev_t devp; kdev_t devp;
int res;
int p; int p;
/* invalidate stuff */ /* invalidate stuff */
for (p = max_p - 1; p > 0; p--) { for (p = max_p - 1; p > 0; p--) {
devp = mk_kdev(disk->major,disk->first_minor + p); devp = mk_kdev(disk->major,disk->first_minor + p);
#if 0 /* %%% superfluous? */ invalidate_device(devp, 1);
if (disk->part[p-1].nr_sects == 0) delete_partition(disk, p);
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;
} }
devp = mk_kdev(disk->major,disk->first_minor); devp = mk_kdev(disk->major,disk->first_minor);
#if 0 /* %%% superfluous? */ invalidate_device(devp, 1);
if (disk->part[p].nr_sects == 0)
continue;
#endif
res = invalidate_device(devp, 1);
if (res)
return res;
disk->capacity = 0; disk->capacity = 0;
return 0; disk->flags &= ~GENHD_FL_UP;
}
void del_gendisk(struct gendisk *disk)
{
driverfs_remove_partitions(disk);
wipe_partitions(disk);
unlink_gendisk(disk); unlink_gendisk(disk);
driverfs_remove_partitions(disk);
devfs_remove_partitions(disk); devfs_remove_partitions(disk);
disk->flags &= ~GENHD_FL_UP;
} }
struct dev_name { struct dev_name {
......
...@@ -62,7 +62,7 @@ struct hd_struct { ...@@ -62,7 +62,7 @@ struct hd_struct {
sector_t start_sect; sector_t start_sect;
sector_t nr_sects; sector_t nr_sects;
devfs_handle_t de; /* primary (master) devfs entry */ 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 #define GENHD_FL_REMOVABLE 1
...@@ -262,7 +262,8 @@ struct unixware_disklabel { ...@@ -262,7 +262,8 @@ struct unixware_disklabel {
char *disk_name (struct gendisk *hd, int part, char *buf); char *disk_name (struct gendisk *hd, int part, char *buf);
extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); 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 struct gendisk *alloc_disk(int minors);
extern void put_disk(struct gendisk *disk); extern void put_disk(struct gendisk *disk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment