summaryrefslogtreecommitdiffstats
path: root/drivers/md/dm.c
diff options
context:
space:
mode:
authorBenjamin Marzinski <bmarzins@redhat.com>2014-08-13 14:53:43 -0400
committerMike Snitzer <snitzer@redhat.com>2014-10-05 20:03:35 -0400
commit86f1152b117a404229fd6f08ec3faca779f37b92 (patch)
treedceee3703ab97065c3e425b55d42cb4edb9a079b /drivers/md/dm.c
parent1f271972478d84dd9e4d6dd82f414d70ed9e78ce (diff)
dm: allow active and inactive tables to share dm_devs
Until this change, when loading a new DM table, DM core would re-open all of the devices in the DM table. Now, DM core will avoid redundant device opens (and closes when destroying the old table) if the old table already has a device open using the same mode. This is achieved by managing reference counts on the table_devices that DM core now stores in the mapped_device structure (rather than in the dm_table structure). So a mapped_device's active and inactive dm_tables' dm_dev lists now just point to the dm_devs stored in the mapped_device's table_devices list. This improvement in DM core's device reference counting has the side-effect of fixing a long-standing limitation of the multipath target: a DM multipath table couldn't include any paths that were unusable (failed). For example: if all paths have failed and you add a new, working, path to the table; you can't use it since the table load would fail due to it still containing failed paths. Now a re-load of a multipath table can include failed devices and when those devices become active again they can be used instantly. The device list code in dm.c isn't a straight copy/paste from the code in dm-table.c, but it's very close (aside from some variable renames). One subtle difference is that find_table_device for the tables_devices list will only match devices with the same name and mode. This is because we don't want to upgrade a device's mode in the active table when an inactive table is loaded. Access to the mapped_device structure's tables_devices list requires a mutex (tables_devices_lock), so that tables cannot be created and destroyed concurrently. Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r--drivers/md/dm.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 56a2c74c9a3f..58f3927fd7cc 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -142,6 +142,9 @@ struct mapped_device {
142 */ 142 */
143 struct dm_table *map; 143 struct dm_table *map;
144 144
145 struct list_head table_devices;
146 struct mutex table_devices_lock;
147
145 unsigned long flags; 148 unsigned long flags;
146 149
147 struct request_queue *queue; 150 struct request_queue *queue;
@@ -212,6 +215,12 @@ struct dm_md_mempools {
212 struct bio_set *bs; 215 struct bio_set *bs;
213}; 216};
214 217
218struct table_device {
219 struct list_head list;
220 atomic_t count;
221 struct dm_dev dm_dev;
222};
223
215#define RESERVED_BIO_BASED_IOS 16 224#define RESERVED_BIO_BASED_IOS 16
216#define RESERVED_REQUEST_BASED_IOS 256 225#define RESERVED_REQUEST_BASED_IOS 256
217#define RESERVED_MAX_IOS 1024 226#define RESERVED_MAX_IOS 1024
@@ -670,6 +679,120 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
670} 679}
671 680
672/* 681/*
682 * Open a table device so we can use it as a map destination.
683 */
684static int open_table_device(struct table_device *td, dev_t dev,
685 struct mapped_device *md)
686{
687 static char *_claim_ptr = "I belong to device-mapper";
688 struct block_device *bdev;
689
690 int r;
691
692 BUG_ON(td->dm_dev.bdev);
693
694 bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr);
695 if (IS_ERR(bdev))
696 return PTR_ERR(bdev);
697
698 r = bd_link_disk_holder(bdev, dm_disk(md));
699 if (r) {
700 blkdev_put(bdev, td->dm_dev.mode | FMODE_EXCL);
701 return r;
702 }
703
704 td->dm_dev.bdev = bdev;
705 return 0;
706}
707
708/*
709 * Close a table device that we've been using.
710 */
711static void close_table_device(struct table_device *td, struct mapped_device *md)
712{
713 if (!td->dm_dev.bdev)
714 return;
715
716 bd_unlink_disk_holder(td->dm_dev.bdev, dm_disk(md));
717 blkdev_put(td->dm_dev.bdev, td->dm_dev.mode | FMODE_EXCL);
718 td->dm_dev.bdev = NULL;
719}
720
721static struct table_device *find_table_device(struct list_head *l, dev_t dev,
722 fmode_t mode) {
723 struct table_device *td;
724
725 list_for_each_entry(td, l, list)
726 if (td->dm_dev.bdev->bd_dev == dev && td->dm_dev.mode == mode)
727 return td;
728
729 return NULL;
730}
731
732int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode,
733 struct dm_dev **result) {
734 int r;
735 struct table_device *td;
736
737 mutex_lock(&md->table_devices_lock);
738 td = find_table_device(&md->table_devices, dev, mode);
739 if (!td) {
740 td = kmalloc(sizeof(*td), GFP_KERNEL);
741 if (!td) {
742 mutex_unlock(&md->table_devices_lock);
743 return -ENOMEM;
744 }
745
746 td->dm_dev.mode = mode;
747 td->dm_dev.bdev = NULL;
748
749 if ((r = open_table_device(td, dev, md))) {
750 mutex_unlock(&md->table_devices_lock);
751 kfree(td);
752 return r;
753 }
754
755 format_dev_t(td->dm_dev.name, dev);
756
757 atomic_set(&td->count, 0);
758 list_add(&td->list, &md->table_devices);
759 }
760 atomic_inc(&td->count);
761 mutex_unlock(&md->table_devices_lock);
762
763 *result = &td->dm_dev;
764 return 0;
765}
766EXPORT_SYMBOL_GPL(dm_get_table_device);
767
768void dm_put_table_device(struct mapped_device *md, struct dm_dev *d)
769{
770 struct table_device *td = container_of(d, struct table_device, dm_dev);
771
772 mutex_lock(&md->table_devices_lock);
773 if (atomic_dec_and_test(&td->count)) {
774 close_table_device(td, md);
775 list_del(&td->list);
776 kfree(td);
777 }
778 mutex_unlock(&md->table_devices_lock);
779}
780EXPORT_SYMBOL(dm_put_table_device);
781
782static void free_table_devices(struct list_head *devices)
783{
784 struct list_head *tmp, *next;
785
786 list_for_each_safe(tmp, next, devices) {
787 struct table_device *td = list_entry(tmp, struct table_device, list);
788
789 DMWARN("dm_destroy: %s still exists with %d references",
790 td->dm_dev.name, atomic_read(&td->count));
791 kfree(td);
792 }
793}
794
795/*
673 * Get the geometry associated with a dm device 796 * Get the geometry associated with a dm device
674 */ 797 */
675int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo) 798int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo)
@@ -1944,12 +2067,14 @@ static struct mapped_device *alloc_dev(int minor)
1944 md->type = DM_TYPE_NONE; 2067 md->type = DM_TYPE_NONE;
1945 mutex_init(&md->suspend_lock); 2068 mutex_init(&md->suspend_lock);
1946 mutex_init(&md->type_lock); 2069 mutex_init(&md->type_lock);
2070 mutex_init(&md->table_devices_lock);
1947 spin_lock_init(&md->deferred_lock); 2071 spin_lock_init(&md->deferred_lock);
1948 atomic_set(&md->holders, 1); 2072 atomic_set(&md->holders, 1);
1949 atomic_set(&md->open_count, 0); 2073 atomic_set(&md->open_count, 0);
1950 atomic_set(&md->event_nr, 0); 2074 atomic_set(&md->event_nr, 0);
1951 atomic_set(&md->uevent_seq, 0); 2075 atomic_set(&md->uevent_seq, 0);
1952 INIT_LIST_HEAD(&md->uevent_list); 2076 INIT_LIST_HEAD(&md->uevent_list);
2077 INIT_LIST_HEAD(&md->table_devices);
1953 spin_lock_init(&md->uevent_lock); 2078 spin_lock_init(&md->uevent_lock);
1954 2079
1955 md->queue = blk_alloc_queue(GFP_KERNEL); 2080 md->queue = blk_alloc_queue(GFP_KERNEL);
@@ -2035,6 +2160,7 @@ static void free_dev(struct mapped_device *md)
2035 blk_integrity_unregister(md->disk); 2160 blk_integrity_unregister(md->disk);
2036 del_gendisk(md->disk); 2161 del_gendisk(md->disk);
2037 cleanup_srcu_struct(&md->io_barrier); 2162 cleanup_srcu_struct(&md->io_barrier);
2163 free_table_devices(&md->table_devices);
2038 free_minor(minor); 2164 free_minor(minor);
2039 2165
2040 spin_lock(&_minor_lock); 2166 spin_lock(&_minor_lock);