[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-kernel
Subject:    [PATCH] Reread partition table when a partition is added
From:       Stefanos Harhalakis <v13 () priest ! com>
Date:       2004-08-22 22:19:06
Message-ID: 200408230119.12878.v13 () priest ! com
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


  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@priest.com>

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;

["rescan_partitions.patch" (text/x-diff)]

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 #6 (application/pgp-signature)]
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic