From: Hannes Reinecke <hare@suse.de>
Subject: Implement 'no_partition_scan' commandline option
Refences: FATE#303697
Patch-mainline:  Not yet

Under certain setups the partition table on the disk is not
useable directly (eg for dmraid or multipathing). So we should
be able to switch it off completely so as not to be flooded with
pointless messages.

Signed-off-by: Hannes Reinecke <hare@suse.de>

---
 block/genhd.c         |   39 +++++++++++++++++++++++++++++++++++++--
 fs/partitions/check.c |    2 ++
 include/linux/genhd.h |    1 +
 3 files changed, 40 insertions(+), 2 deletions(-)

--- a/block/genhd.c
+++ b/block/genhd.c
@@ -513,6 +513,18 @@ static int exact_lock(dev_t devt, void *
 	return 0;
 }
 
+static int __read_mostly no_partition_scan;
+
+static int __init no_partition_scan_setup(char *str)
+{
+	no_partition_scan = 1;
+	printk(KERN_INFO "genhd: omit partition scan.\n");
+
+	return 1;
+}
+
+__setup("no_partition_scan", no_partition_scan_setup);
+
 /**
  * add_disk - add partitioning information to kernel list
  * @disk: per-device partitioning information
@@ -537,6 +549,9 @@ void add_disk(struct gendisk *disk)
 
 	disk->flags |= GENHD_FL_UP;
 
+	if (no_partition_scan)
+		disk->flags |= GENHD_FL_NO_PARTITION_SCAN;
+
 	retval = blk_alloc_devt(&disk->part0, &devt);
 	if (retval) {
 		WARN_ON(1);
@@ -825,7 +840,27 @@ static ssize_t disk_range_show(struct de
 {
 	struct gendisk *disk = dev_to_disk(dev);
 
-	return sprintf(buf, "%d\n", disk->minors);
+	return sprintf(buf, "%d\n",
+		       (disk->flags & GENHD_FL_NO_PARTITION_SCAN ? 0 : disk->minors));
+}
+
+static ssize_t disk_range_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+	int i;
+
+	if (count > 0 && sscanf(buf, "%d", &i) > 0) {
+		if (i == 0)
+			disk->flags |= GENHD_FL_NO_PARTITION_SCAN;
+		else if (i <= disk->minors)
+			disk->flags &= ~GENHD_FL_NO_PARTITION_SCAN;
+		else
+			count = -EINVAL;
+	}
+
+	return count;
 }
 
 static ssize_t disk_ext_range_show(struct device *dev,
@@ -879,7 +914,7 @@ static ssize_t disk_discard_alignment_sh
 	return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue));
 }
 
-static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
+static DEVICE_ATTR(range, S_IRUGO|S_IWUSR, disk_range_show, disk_range_store);
 static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
 static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
 static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -559,6 +559,8 @@ int rescan_partitions(struct gendisk *di
 		disk->fops->revalidate_disk(disk);
 	check_disk_size_change(disk, bdev);
 	bdev->bd_invalidated = 0;
+	if (disk->flags & GENHD_FL_NO_PARTITION_SCAN)
+		return 0;
 	if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
 		return 0;
 	if (IS_ERR(state))	/* I/O error reading the partition table */
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -122,6 +122,7 @@ struct hd_struct {
 #define GENHD_FL_SUPPRESS_PARTITION_INFO	32
 #define GENHD_FL_EXT_DEVT			64 /* allow extended devt */
 #define GENHD_FL_NATIVE_CAPACITY		128
+#define GENHD_FL_NO_PARTITION_SCAN		256
 
 #define BLK_SCSI_MAX_CMDS	(256)
 #define BLK_SCSI_CMD_PER_LONG	(BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
