dm: add support for get_unique_id

This adds support to obtain a device's unique id through dm, similar to the
existing ioctl and persistent resevation handling. We limit this to
single-target devices.

This enables knfsd to export pNFS SCSI luns that have been exported from
multipath devices.

Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>

authored by Benjamin Coddington and committed by Mikulas Patocka d5f01ace 19ac19e0

Changed files
+55
drivers
md
+55
drivers/md/dm.c
··· 3343 3343 kfree(pools); 3344 3344 } 3345 3345 3346 + struct dm_blkdev_id { 3347 + u8 *id; 3348 + enum blk_unique_id type; 3349 + }; 3350 + 3351 + static int __dm_get_unique_id(struct dm_target *ti, struct dm_dev *dev, 3352 + sector_t start, sector_t len, void *data) 3353 + { 3354 + struct dm_blkdev_id *dm_id = data; 3355 + const struct block_device_operations *fops = dev->bdev->bd_disk->fops; 3356 + 3357 + if (!fops->get_unique_id) 3358 + return 0; 3359 + 3360 + return fops->get_unique_id(dev->bdev->bd_disk, dm_id->id, dm_id->type); 3361 + } 3362 + 3363 + /* 3364 + * Allow access to get_unique_id() for the first device returning a 3365 + * non-zero result. Reasonable use expects all devices to have the 3366 + * same unique id. 3367 + */ 3368 + static int dm_blk_get_unique_id(struct gendisk *disk, u8 *id, 3369 + enum blk_unique_id type) 3370 + { 3371 + struct mapped_device *md = disk->private_data; 3372 + struct dm_table *table; 3373 + struct dm_target *ti; 3374 + int ret = 0, srcu_idx; 3375 + 3376 + struct dm_blkdev_id dm_id = { 3377 + .id = id, 3378 + .type = type, 3379 + }; 3380 + 3381 + table = dm_get_live_table(md, &srcu_idx); 3382 + if (!table || !dm_table_get_size(table)) 3383 + goto out; 3384 + 3385 + /* We only support devices that have a single target */ 3386 + if (table->num_targets != 1) 3387 + goto out; 3388 + ti = dm_table_get_target(table, 0); 3389 + 3390 + if (!ti->type->iterate_devices) 3391 + goto out; 3392 + 3393 + ret = ti->type->iterate_devices(ti, __dm_get_unique_id, &dm_id); 3394 + out: 3395 + dm_put_live_table(md, srcu_idx); 3396 + return ret; 3397 + } 3398 + 3346 3399 struct dm_pr { 3347 3400 u64 old_key; 3348 3401 u64 new_key; ··· 3721 3668 .ioctl = dm_blk_ioctl, 3722 3669 .getgeo = dm_blk_getgeo, 3723 3670 .report_zones = dm_blk_report_zones, 3671 + .get_unique_id = dm_blk_get_unique_id, 3724 3672 .pr_ops = &dm_pr_ops, 3725 3673 .owner = THIS_MODULE 3726 3674 }; ··· 3731 3677 .release = dm_blk_close, 3732 3678 .ioctl = dm_blk_ioctl, 3733 3679 .getgeo = dm_blk_getgeo, 3680 + .get_unique_id = dm_blk_get_unique_id, 3734 3681 .pr_ops = &dm_pr_ops, 3735 3682 .owner = THIS_MODULE 3736 3683 };