This allows specifying a disk sequence number in XenStore. If it does not match the disk sequence number of the underlying device, the device will not be exported and a warning will be logged. Userspace can use this to eliminate race conditions due to major/minor number reuse. Older kernels will ignore this, so it is safe for userspace to set it unconditionally. Signed-off-by: Demi Marie Obenour <demi@xxxxxxxxxxxxxxxxxxxxxx> --- I'm marking this patch as RFC because I have not tested it beyond compiliation, and because I want to get feedback on the API before I put more effort into it. drivers/block/xen-blkback/xenbus.c | 35 ++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 97de13b14175eb8ced14d1649a3be461a464ee8a..cb531236b19709c791a82c868bfb4ed9aa284485 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -480,7 +480,7 @@ MODULE_PARM_DESC(feature_persistent, static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, unsigned major, unsigned minor, int readonly, - int cdrom) + bool cdrom, u64 diskseq) { struct xen_vbd *vbd; struct block_device *bdev; @@ -508,6 +508,25 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, xen_vbd_free(vbd); return -ENOENT; } + + if (diskseq != (u64)-1) { + struct gendisk *disk = bdev->bd_disk; + if (unlikely(disk == NULL)) { + pr_err("xen_vbd_create: device %08x has no gendisk\n", + vbd->pdevice); + xen_vbd_free(vbd); + return -EFAULT; + } + + if (unlikely(disk->diskseq != diskseq)) { + pr_warn("xen_vbd_create: device %08x has incorrect sequence " + "number 0x%llx (expected 0x%llx)\n", + vbd->pdevice, disk->diskseq, diskseq); + xen_vbd_free(vbd); + return -ENODEV; + } + } + vbd->size = vbd_sz(vbd); if (cdrom || disk_to_cdi(vbd->bdev->bd_disk)) @@ -712,6 +731,7 @@ static void backend_changed(struct xenbus_watch *watch, int cdrom = 0; unsigned long handle; char *device_type; + unsigned long long diskseq; pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id); @@ -730,6 +750,17 @@ static void backend_changed(struct xenbus_watch *watch, return; } + err = xenbus_scanf(XBT_NIL, dev->nodename, "diskseq", "%llx", &diskseq); + if (err == -ENOENT) { + diskseq = (uint64_t)-1; + } else if (err != 1) { + xenbus_dev_fatal(dev, err, "reading diskseq"); + return; + } else if (diskseq == (uint64_t)-1) { + xenbus_dev_fatal(dev, err, "UINT64_MAX is not a valid diskseq"); + return; + } + if (be->major | be->minor) { if (be->major != major || be->minor != minor) pr_warn("changing physical device (from %x:%x to %x:%x) not supported.\n", @@ -763,7 +794,7 @@ static void backend_changed(struct xenbus_watch *watch, be->minor = minor; err = xen_vbd_create(be->blkif, handle, major, minor, - !strchr(be->mode, 'w'), cdrom); + !strchr(be->mode, 'w'), cdrom, diskseq); if (err) xenbus_dev_fatal(dev, err, "creating vbd structure"); -- Sincerely, Demi Marie Obenour (she/her/hers) Invisible Things Lab