Linux-NVME Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: John Garry <john.garry@linux.dev>
To: axboe@kernel.dk, kbusch@kernel.org, sagi@grimberg.me, hch@lst.de
Cc: linux-block@vger.kernel.org, linux-nvme@lists.infradead.org,
	John Garry <john.garry@linux.dev>
Subject: [PATCH v4 1/4] block: support cloning partitions
Date: Mon, 21 Sep 2026 09:37:49 +0100	[thread overview]
Message-ID: <20260921083752.1154316-2-john.garry@linux.dev> (raw)
In-Reply-To: <20260921083752.1154316-1-john.garry@linux.dev>

For NVMe multipath support, per-path gendisks have flag GENHD_FL_HIDDEN
set. This means that no partition scan will be run for those disks.
However the head disk will still have its partitions scanned.

Even though for hidden disks there is no partition scan, it can be useful
to have the partition table available. Such is a case for NVMe multipath
when we want to send bios to specific partitions.

Support allowing a disk to clone the partitions from a multipath head disk.

Add struct block_device_operations.disk_changed_notify callback to allow
block drivers be notified of when partition layout may have changed. In
the NVMe multipath case, the head disk would use this callback to re-clone
the partitions onto the per-path disks.

Signed-off-by: John Garry <john.garry@linux.dev>
---
 block/partitions/core.c | 43 +++++++++++++++++++++++++++++++++++++++++
 include/linux/blkdev.h  |  2 ++
 2 files changed, 45 insertions(+)

diff --git a/block/partitions/core.c b/block/partitions/core.c
index b5c59b79ca7c..b03b206bc050 100644
--- a/block/partitions/core.c
+++ b/block/partitions/core.c
@@ -703,6 +703,9 @@ int bdev_disk_changed(struct gendisk *disk, bool invalidate)
 		kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);
 	}
 
+	if (disk->fops->disk_changed_notify)
+		disk->fops->disk_changed_notify(disk);
+
 	return ret;
 }
 /*
@@ -711,6 +714,46 @@ int bdev_disk_changed(struct gendisk *disk, bool invalidate)
  */
 EXPORT_SYMBOL_GPL(bdev_disk_changed);
 
+int bdev_clone_partitions(struct gendisk *disk, struct gendisk *mirror)
+{
+	struct block_device *part;
+	unsigned long idx;
+
+	if (disk_has_partscan(mirror))
+		return -EINVAL;
+
+	lockdep_assert_held(&disk->open_mutex);
+	mutex_lock_nested(&mirror->open_mutex, SINGLE_DEPTH_NESTING);
+
+	xa_for_each_start(&mirror->part_tbl, idx, part, 1) {
+		/* Same as bdev_disk_changed() */
+		bdev_unhash(part);
+		WARN_ON_ONCE(atomic_read(&part->bd_openers));
+		invalidate_bdev(part);
+		drop_partition(part);
+	}
+
+	xa_for_each_start(&disk->part_tbl, idx, part, 1) {
+		struct block_device *part_added;
+
+		part_added = add_partition(mirror, idx, part->bd_start_sect,
+					part->bd_nr_sectors, ADDPART_FLAG_NONE,
+					part->bd_meta_info);
+		if (IS_ERR(part_added)) {
+			if (PTR_ERR(part_added) != -ENXIO) {
+				dev_err(disk_to_dev(mirror), "p%ld could not be added: %pe\n",
+				       idx, part_added);
+			}
+			mutex_unlock(&mirror->open_mutex);
+			return PTR_ERR(part_added);
+		}
+	}
+	mutex_unlock(&mirror->open_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(bdev_clone_partitions);
+
 void *read_part_sector(struct parsed_partitions *state, sector_t n, Sector *p)
 {
 	struct address_space *mapping = state->disk->part0->bd_mapping;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index d003a9d2d1f6..249a4250a56d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -978,6 +978,7 @@ static inline unsigned int bdev_nr_zones(struct block_device *bdev)
 }
 
 int bdev_disk_changed(struct gendisk *disk, bool invalidate);
+int bdev_clone_partitions(struct gendisk *disk, struct gendisk *mirror);
 
 void put_disk(struct gendisk *disk);
 struct gendisk *__blk_alloc_disk(struct queue_limits *lim, int node,
@@ -1599,6 +1600,7 @@ struct block_device_operations {
 	/* returns the length of the identifier or a negative errno: */
 	int (*get_unique_id)(struct gendisk *disk, u8 id[16],
 			enum blk_unique_id id_type);
+	void (*disk_changed_notify)(struct gendisk *disk);
 	struct module *owner;
 	const struct pr_ops *pr_ops;
 
-- 
2.43.0



  reply	other threads:[~2026-09-21  8:38 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21  8:37 [PATCH v4 0/4] fix NVMe multipath partition diskstats John Garry
2026-09-21  8:37 ` John Garry [this message]
2026-09-21  8:37 ` [PATCH v4 2/4] block: don't show partition diskstats for GENHD_FL_HIDDEN John Garry
2026-09-21  8:37 ` [PATCH v4 3/4] nvme-multipath: clone head disk partitions to per-path disks John Garry
2026-09-21  8:37 ` [PATCH v4 4/4] nvme-multipath: fix diskstats for partitions John Garry
2026-09-28  7:30 ` [PATCH v4 0/4] fix NVMe multipath partition diskstats John Garry
2026-09-28  9:14   ` Christoph Hellwig
2026-09-28 10:16     ` John Garry

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260921083752.1154316-2-john.garry@linux.dev \
    --to=john.garry@linux.dev \
    --cc=axboe@kernel.dk \
    --cc=hch@lst.de \
    --cc=kbusch@kernel.org \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=sagi@grimberg.me \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox