Commit 897c924e authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] (9/25) update_partition()

	new helper - update_partition(disk, partition_number); does the
right thing wrt devfs and driverfs (un)registration of partition entries.
BLKPG ioctls fixed - now they call that beast rather than calling only
devfs side.  New helper - rescan_partitions(disk, bdev); does all work
with wiping/rereading/etc. and fs/block_dev.c now uses it instead of
check_partition().  The latter became static.
parent 06f55b09
......@@ -107,7 +107,7 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p)
/* all seems OK */
g->part[p->pno].start_sect = pstart;
g->part[p->pno].nr_sects = plength;
devfs_register_partitions (g, 0);
update_partition(g, p->pno);
return 0;
}
......@@ -156,7 +156,7 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p)
g->part[p->pno].start_sect = 0;
g->part[p->pno].nr_sects = 0;
devfs_register_partitions (g, 0);
update_partition(g, p->pno);
bd_release(bdevp);
bdput(bdevp);
......
......@@ -67,22 +67,11 @@ add_gendisk(struct gendisk *gp)
}
EXPORT_SYMBOL(add_gendisk);
EXPORT_SYMBOL(del_gendisk);
/**
* del_gendisk - remove partitioning information from kernel list
* @gp: per-device partitioning information
*
* This function unregisters the partitioning information in @gp
* with the kernel.
*/
void
del_gendisk(struct gendisk *disk)
void unlink_gendisk(struct gendisk *disk)
{
struct gendisk **p;
driverfs_remove_partitions(disk);
wipe_partitions(disk);
write_lock(&gendisk_lock);
for (p = &gendisk_head; *p; p = &((*p)->next))
if (*p == disk)
......@@ -90,12 +79,8 @@ del_gendisk(struct gendisk *disk)
if (*p)
*p = (*p)->next;
write_unlock(&gendisk_lock);
devfs_register_partitions(disk, 1);
}
EXPORT_SYMBOL(del_gendisk);
/**
* get_gendisk - get partitioning information for a given device
* @dev: device to get partitioning information for
......
......@@ -527,22 +527,13 @@ int check_disk_change(struct block_device *bdev)
int full_check_disk_change(struct block_device *bdev)
{
int res;
int res = 0;
if (bdev->bd_contains != bdev)
BUG();
down(&bdev->bd_sem);
res = check_disk_change(bdev);
if (bdev->bd_invalidated && !bdev->bd_part_count) {
struct gendisk *disk = get_gendisk(to_kdev_t(bdev->bd_dev));
int p;
bdev->bd_invalidated = 0;
for (p = 1; p < 1<<disk->minor_shift; p++) {
disk->part[p].start_sect = 0;
disk->part[p].nr_sects = 0;
}
res = invalidate_device(to_kdev_t(bdev->bd_dev), 1);
if (disk->part[0].nr_sects)
check_partition(disk, bdev);
if (check_disk_change(bdev)) {
rescan_partitions(get_gendisk(to_kdev_t(bdev->bd_dev)), bdev);
res = 1;
}
up(&bdev->bd_sem);
return res;
......@@ -654,17 +645,8 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
inode->i_data.backing_dev_info = bdi;
bdev->bd_inode->i_data.backing_dev_info = bdi;
}
if (bdev->bd_invalidated && !bdev->bd_part_count) {
int p;
bdev->bd_invalidated = 0;
for (p = 1; p < 1<<g->minor_shift; p++) {
g->part[p].start_sect = 0;
g->part[p].nr_sects = 0;
}
invalidate_device(dev, 1);
if (g->part[0].nr_sects)
check_partition(g, bdev);
}
if (bdev->bd_invalidated)
rescan_partitions(g, bdev);
} else {
down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count++;
......@@ -799,7 +781,7 @@ static int blkdev_reread_part(struct block_device *bdev)
{
kdev_t dev = to_kdev_t(bdev->bd_dev);
struct gendisk *disk = get_gendisk(dev);
int p, res;
int res = 0;
if (!disk || !disk->minor_shift || bdev != bdev->bd_contains)
return -EINVAL;
......@@ -807,21 +789,7 @@ static int blkdev_reread_part(struct block_device *bdev)
return -EACCES;
if (down_trylock(&bdev->bd_sem))
return -EBUSY;
if (bdev->bd_part_count) {
up(&bdev->bd_sem);
return -EBUSY;
}
for (p = 1; p < 1 << disk->minor_shift; p++) {
disk->part[p].start_sect = 0;
disk->part[p].nr_sects = 0;
}
res = invalidate_device(dev, 1);
if (!res) {
if (bdev->bd_op->revalidate)
bdev->bd_op->revalidate(dev);
if (disk->part[0].nr_sects)
check_partition(disk, bdev);
}
res = rescan_partitions(disk, bdev);
up(&bdev->bd_sem);
return res;
}
......
......@@ -149,29 +149,29 @@ static void driverfs_create_partitions(struct gendisk *hd)
sprintf(dev->name, "%sdisc", name);
sprintf(dev->bus_id, "%sdisc", bus_id);
for (part=1; part < max_p; part++) {
dev = &p[part].hd_driverfs_dev;
sprintf(dev->name, "%spart%d", name, part);
sprintf(dev->bus_id, "%s:p%d", bus_id, part);
if (!p[part].nr_sects)
continue;
dev = &p[part].hd_driverfs_dev;
dev->driver_data =
(void *)(long)__mkdev(hd->major, hd->first_minor+part);
sprintf(dev->name, "%spart%d", name, part);
sprintf(dev->bus_id, "%s:p%d", bus_id, part);
}
for (part=0; part < max_p; part++) {
dev = &p[part].hd_driverfs_dev;
if (!dev->driver_data)
continue;
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);
}
}
void driverfs_remove_partitions(struct gendisk *hd)
static void driverfs_remove_partitions(struct gendisk *hd)
{
int max_p = 1<<hd->minor_shift;
struct hd_struct *p;
......@@ -188,10 +188,7 @@ void driverfs_remove_partitions(struct gendisk *hd)
}
}
/*
* DON'T EXPORT
*/
void check_partition(struct gendisk *hd, struct block_device *bdev)
static void check_partition(struct gendisk *hd, struct block_device *bdev)
{
devfs_handle_t de = NULL;
dev_t dev = bdev->bd_dev;
......@@ -226,7 +223,7 @@ void check_partition(struct gendisk *hd, struct block_device *bdev)
if (res < 0) {
if (warn_no_part)
printk(" unable to read partition table\n");
goto out;
return;
}
p = hd->part;
for (j = 1; j < state->limit; j++) {
......@@ -238,18 +235,14 @@ void check_partition(struct gendisk *hd, struct block_device *bdev)
md_autodetect_dev(dev+j);
#endif
}
goto out;
return;
}
printk(" unknown partition table\n");
out:
driverfs_create_partitions(hd);
devfs_register_partitions(hd, 0);
}
#ifdef CONFIG_DEVFS_FS
static void devfs_register_partition(struct gendisk *dev, int part)
{
#ifdef CONFIG_DEVFS_FS
devfs_handle_t dir;
unsigned int devfs_flags = DEVFS_FL_DEFAULT;
struct hd_struct *p = dev->part;
......@@ -262,26 +255,29 @@ static void devfs_register_partition(struct gendisk *dev, int part)
return;
if (dev->flags & GENHD_FL_REMOVABLE)
devfs_flags |= DEVFS_FL_REMOVABLE;
sprintf (devname, "part%d", part);
sprintf(devname, "part%d", part);
p[part].de = devfs_register (dir, devname, devfs_flags,
dev->major, dev->first_minor + part,
S_IFBLK | S_IRUSR | S_IWUSR,
dev->fops, NULL);
#endif
}
#ifdef CONFIG_DEVFS_FS
static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
#endif
static void devfs_register_disc(struct gendisk *dev)
static void devfs_create_partitions(struct gendisk *dev)
{
#ifdef CONFIG_DEVFS_FS
int pos = 0;
devfs_handle_t dir, slave;
unsigned int devfs_flags = DEVFS_FL_DEFAULT;
char dirname[64], symlink[16];
static devfs_handle_t devfs_handle;
int part, max_p = 1<<dev->minor_shift;
struct hd_struct *p = dev->part;
if (p[0].de)
return;
if (dev->flags & GENHD_FL_REMOVABLE)
devfs_flags |= DEVFS_FL_REMOVABLE;
if (dev->flags & GENHD_FL_DEVFS) {
......@@ -304,38 +300,28 @@ static void devfs_register_disc(struct gendisk *dev)
sprintf(symlink, "disc%d", dev->number);
devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT,
dirname + pos, &slave, NULL);
p[0].de = devfs_register (dir, "disc", devfs_flags,
p->de = devfs_register(dir, "disc", devfs_flags,
dev->major, dev->first_minor,
S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
devfs_auto_unregister(p[0].de, slave);
devfs_auto_unregister(p->de, slave);
if (!(dev->flags & GENHD_FL_DEVFS))
devfs_auto_unregister (slave, dir);
for (part = 1, p++; part < max_p; part++, p++)
if (p->nr_sects)
devfs_register_partition(dev, part);
#endif
}
#endif /* CONFIG_DEVFS_FS */
void devfs_register_partitions (struct gendisk *dev, int unregister)
static void devfs_remove_partitions(struct gendisk *dev)
{
#ifdef CONFIG_DEVFS_FS
int part, max_p;
struct hd_struct *p = dev->part;
if (!unregister)
devfs_register_disc(dev);
max_p = (1 << dev->minor_shift);
for (part = 1; part < max_p; part++) {
if ( unregister || (p[part].nr_sects < 1) ) {
devfs_unregister(p[part].de);
p[part].de = NULL;
continue;
}
devfs_register_partition(dev, part);
int part;
for (part = 1<<dev->minor_shift; part--; ) {
devfs_unregister(dev->part[part].de);
dev->part[part].de = NULL;
}
if (unregister) {
devfs_unregister(p[0].de);
p[0].de = NULL;
devfs_dealloc_unique_number(&disc_numspace, dev->number);
}
#endif /* CONFIG_DEVFS_FS */
#endif
}
/*
......@@ -348,20 +334,20 @@ void devfs_register_partitions (struct gendisk *dev, int unregister)
* done
*/
void register_disk(struct gendisk *g, kdev_t dev, unsigned minors,
void register_disk(struct gendisk *disk, kdev_t dev, unsigned minors,
struct block_device_operations *ops, long size)
{
struct block_device *bdev;
struct hd_struct *p;
if (!g)
if (!disk)
return;
p = g->part;
p = disk->part;
p[0].nr_sects = size;
/* No minors to use for partitions */
if (!g->minor_shift)
if (!disk->minor_shift)
return;
/* No such device (e.g., media were just removed) */
......@@ -371,10 +357,66 @@ void register_disk(struct gendisk *g, kdev_t dev, unsigned minors,
bdev = bdget(kdev_t_to_nr(dev));
if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
return;
check_partition(g, bdev);
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;
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;
}
return;
}
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);
}
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
kdev_t dev = to_kdev_t(bdev->bd_dev);
int p, res;
if (!bdev->bd_invalidated)
return 0;
if (bdev->bd_part_count)
return -EBUSY;
res = invalidate_device(dev, 1);
if (res)
return res;
bdev->bd_invalidated = 0;
for (p = 1; p < (1<<disk->minor_shift); p++) {
disk->part[p].start_sect = 0;
disk->part[p].nr_sects = 0;
}
if (bdev->bd_op->revalidate)
bdev->bd_op->revalidate(dev);
if (disk->part[0].nr_sects)
check_partition(disk, bdev);
for (p = 1; p < (1<<disk->minor_shift); p++)
update_partition(disk, p);
return res;
}
unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p)
{
struct address_space *mapping = bdev->bd_inode->i_mapping;
......@@ -398,7 +440,7 @@ unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Secto
return NULL;
}
int wipe_partitions(struct gendisk *disk)
static int wipe_partitions(struct gendisk *disk)
{
int max_p = 1 << disk->minor_shift;
int p;
......@@ -419,3 +461,11 @@ int wipe_partitions(struct gendisk *disk)
}
return 0;
}
void del_gendisk(struct gendisk *disk)
{
driverfs_remove_partitions(disk);
wipe_partitions(disk);
unlink_gendisk(disk);
devfs_remove_partitions(disk);
}
......@@ -281,9 +281,7 @@ struct sec_size {
extern struct sec_size * blk_sec[MAX_BLKDEV];
extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
extern int wipe_partitions(struct gendisk *disk);
extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size);
extern void check_partition(struct gendisk *disk, struct block_device *bdev);
extern void generic_make_request(struct bio *bio);
extern inline request_queue_t *bdev_get_queue(struct block_device *bdev);
extern void blk_put_request(struct request *);
......
......@@ -89,6 +89,7 @@ struct gendisk {
/* drivers/block/genhd.c */
extern void add_gendisk(struct gendisk *gp);
extern void del_gendisk(struct gendisk *gp);
extern void unlink_gendisk(struct gendisk *gp);
extern struct gendisk *get_gendisk(kdev_t dev);
static inline unsigned long get_start_sect(struct block_device *bdev)
{
......@@ -244,8 +245,8 @@ struct unixware_disklabel {
char *disk_name (struct gendisk *hd, int part, char *buf);
extern void devfs_register_partitions (struct gendisk *dev, int unregister);
extern void driverfs_remove_partitions (struct gendisk *hd);
extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
extern void update_partition(struct gendisk *disk, int part);
static inline unsigned int disk_index (kdev_t dev)
{
......
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