[PATCH] Reread partition table when a partition is added

From: Stefanos Harhalakis
Date: Sun Aug 22 2004 - 17:24:18 EST


This small patch rereads the partition table even if the block device is
beeing used. It only rereads it when there are no changes at the current
partitions and there are new partitions added at the end. Any existing
partition change will/should make it fail.

Is it OK and/or useful ?

(I'm quite inexperienced about kernel coding so be gentle :)

Signed-off-by: Stefanos Harhalakis <v13@xxxxxxxxxx>

RCS file: /usr/local/cvsroot/linux-2.6/fs/partitions/check.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 check.c
--- check.c 22 Aug 2004 11:08:27 -0000 1.1.1.1
+++ check.c 22 Aug 2004 22:09:11 -0000
@@ -391,19 +391,44 @@ void register_disk(struct gendisk *disk)
blkdev_put(bdev);
}

+/*
+ * Determine the last partition.
+ * Return the partition number or 0 if there is no partition
+ */
+static int get_last_partition(struct gendisk *disk)
+{
+ int n, ret = 0;
+
+ for (n=0; n < disk->minors ; n++) {
+ if (disk->part[n])
+ ret=n+1;
+ }
+
+ return(ret);
+}
+
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
struct parsed_partitions *state;
+ struct hd_struct *phd;
int p, res;
+ int is_busy = 0, last_partition = 0;
+
+ if (bdev->bd_part_count) {
+ is_busy = 1;
+ last_partition=get_last_partition(disk);
+ }

- if (bdev->bd_part_count)
- return -EBUSY;
res = invalidate_partition(disk, 0);
if (res)
return res;
bdev->bd_invalidated = 0;
- for (p = 1; p < disk->minors; p++)
- delete_partition(disk, p);
+
+ if (!is_busy) {
+ for (p = 1; p < disk->minors; p++)
+ delete_partition(disk, p);
+ }
+
if (disk->fops->revalidate_disk)
disk->fops->revalidate_disk(disk);
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
@@ -411,13 +436,29 @@ int rescan_partitions(struct gendisk *di
for (p = 1; p < state->limit; p++) {
sector_t size = state->parts[p].size;
sector_t from = state->parts[p].from;
+
+ if (is_busy && p<=last_partition) {
+ phd=disk->part[p-1];
+ if (phd != NULL && (phd->start_sect != from ||
+ phd->nr_sects != size)) {
+ printk(KERN_INFO
+ "Existing partition was changed. "
+ "Reboot is required.\n");
+ res=-EBUSY;
+ break;
+ }
+ }
+
if (!size)
continue;
- add_partition(disk, p, from, size);
+
+ if (!is_busy || p>last_partition) {
+ add_partition(disk, p, from, size);
#ifdef CONFIG_BLK_DEV_MD
- if (state->parts[p].flags)
- md_autodetect_dev(bdev->bd_dev+p);
+ if (state->parts[p].flags)
+ md_autodetect_dev(bdev->bd_dev+p);
#endif
+ }
}
kfree(state);
return res;
RCS file: /usr/local/cvsroot/linux-2.6/fs/partitions/check.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 check.c
--- check.c 22 Aug 2004 11:08:27 -0000 1.1.1.1
+++ check.c 22 Aug 2004 22:09:11 -0000
@@ -391,19 +391,44 @@ void register_disk(struct gendisk *disk)
blkdev_put(bdev);
}

+/*
+ * Determine the last partition.
+ * Return the partition number or 0 if there is no partition
+ */
+static int get_last_partition(struct gendisk *disk)
+{
+ int n, ret = 0;
+
+ for (n=0; n < disk->minors ; n++) {
+ if (disk->part[n])
+ ret=n+1;
+ }
+
+ return(ret);
+}
+
int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
struct parsed_partitions *state;
+ struct hd_struct *phd;
int p, res;
+ int is_busy = 0, last_partition = 0;
+
+ if (bdev->bd_part_count) {
+ is_busy = 1;
+ last_partition=get_last_partition(disk);
+ }

- if (bdev->bd_part_count)
- return -EBUSY;
res = invalidate_partition(disk, 0);
if (res)
return res;
bdev->bd_invalidated = 0;
- for (p = 1; p < disk->minors; p++)
- delete_partition(disk, p);
+
+ if (!is_busy) {
+ for (p = 1; p < disk->minors; p++)
+ delete_partition(disk, p);
+ }
+
if (disk->fops->revalidate_disk)
disk->fops->revalidate_disk(disk);
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
@@ -411,13 +436,29 @@ int rescan_partitions(struct gendisk *di
for (p = 1; p < state->limit; p++) {
sector_t size = state->parts[p].size;
sector_t from = state->parts[p].from;
+
+ if (is_busy && p<=last_partition) {
+ phd=disk->part[p-1];
+ if (phd != NULL && (phd->start_sect != from ||
+ phd->nr_sects != size)) {
+ printk(KERN_INFO
+ "Existing partition was changed. "
+ "Reboot is required.\n");
+ res=-EBUSY;
+ break;
+ }
+ }
+
if (!size)
continue;
- add_partition(disk, p, from, size);
+
+ if (!is_busy || p>last_partition) {
+ add_partition(disk, p, from, size);
#ifdef CONFIG_BLK_DEV_MD
- if (state->parts[p].flags)
- md_autodetect_dev(bdev->bd_dev+p);
+ if (state->parts[p].flags)
+ md_autodetect_dev(bdev->bd_dev+p);
#endif
+ }
}
kfree(state);
return res;

Attachment: pgp00000.pgp
Description: PGP signature