Index: linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm.c =================================================================== --- linux-2.6.24.7-ibmrt2.16-view.orig/drivers/md/dm.c +++ linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm.c @@ -876,20 +876,16 @@ static void dm_unplug_all(struct request static int dm_any_congested(void *congested_data, int bdi_bits) { - int r = bdi_bits; + int r; struct mapped_device *md = (struct mapped_device *) congested_data; - struct dm_table *map; + struct dm_table *map = dm_get_table(md); - atomic_inc(&md->pending); - if (!test_bit(DMF_BLOCK_IO, &md->flags)) { - map = dm_get_table(md); - if (map) { - r = dm_table_any_congested(map, bdi_bits); - dm_table_put(map); - } - } - if (!atomic_dec_return(&md->pending)) - wake_up(&md->wait); + if (!map || test_bit(DMF_BLOCK_IO, &md->flags)) + r = bdi_bits; + else + r = dm_table_any_congested(map, bdi_bits); + + dm_table_put(map); return r; } @@ -1143,10 +1139,11 @@ static int __bind(struct mapped_device * if (md->suspended_bdev) __set_size(md, size); - if (size == 0) + if (size == 0) { + dm_table_destroy(t); return 0; + } - dm_table_get(t); dm_table_event_callback(t, event_callback, md); write_lock(&md->map_lock); @@ -1168,7 +1165,7 @@ static void __unbind(struct mapped_devic write_lock(&md->map_lock); md->map = NULL; write_unlock(&md->map_lock); - dm_table_put(map); + dm_table_destroy(map); } /* @@ -1256,8 +1253,8 @@ void dm_put(struct mapped_device *md) dm_table_presuspend_targets(map); dm_table_postsuspend_targets(map); } - __unbind(md); dm_table_put(map); + __unbind(md); free_dev(md); } } Index: linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm-ioctl.c =================================================================== --- linux-2.6.24.7-ibmrt2.16-view.orig/drivers/md/dm-ioctl.c +++ linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm-ioctl.c @@ -232,7 +232,7 @@ static void __hash_remove(struct hash_ce } if (hc->new_map) - dm_table_put(hc->new_map); + dm_table_destroy(hc->new_map); dm_put(hc->md); free_cell(hc); } @@ -826,8 +826,8 @@ static int do_resume(struct dm_ioctl *pa r = dm_swap_table(md, new_map); if (r) { + dm_table_destroy(new_map); dm_put(md); - dm_table_put(new_map); return r; } @@ -835,8 +835,6 @@ static int do_resume(struct dm_ioctl *pa set_disk_ro(dm_disk(md), 0); else set_disk_ro(dm_disk(md), 1); - - dm_table_put(new_map); } if (dm_suspended(md)) @@ -1079,7 +1077,7 @@ static int table_load(struct dm_ioctl *p } if (hc->new_map) - dm_table_put(hc->new_map); + dm_table_destroy(hc->new_map); hc->new_map = t; up_write(&_hash_lock); @@ -1108,7 +1106,7 @@ static int table_clear(struct dm_ioctl * } if (hc->new_map) { - dm_table_put(hc->new_map); + dm_table_destroy(hc->new_map); hc->new_map = NULL; } Index: linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm-table.c =================================================================== --- linux-2.6.24.7-ibmrt2.16-view.orig/drivers/md/dm-table.c +++ linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm-table.c @@ -59,6 +59,19 @@ struct dm_table { void *event_context; }; + /* + * New table reference rules: + * + * The table has always exactly one reference from either mapped_device->map + * or hash_cell->new_map. This reference is not counted in table->holders. + * A pair of dm_create_table/dm_destroy_table functions is used for table + * creation/destruction. + * + * Temporary references from the other code increase table->holders. A pair + * of dm_table_get/dm_table_put functions is used to manipulate it. + * + * When the table is about to be destroyed, we wait for table->holders. + */ /* * Similar to ceiling(log_size(n)) */ @@ -226,7 +239,7 @@ int dm_table_create(struct dm_table **re return -ENOMEM; INIT_LIST_HEAD(&t->devices); - atomic_set(&t->holders, 1); + atomic_set(&t->holders, 0); if (!num_targets) num_targets = KEYS_PER_NODE; @@ -294,10 +307,14 @@ static void free_devices(struct list_hea } } -static void table_destroy(struct dm_table *t) +void dm_table_destroy(struct dm_table *t) { unsigned int i; + while (atomic_read(&t->holders)) + yield(); + smp_mb(); + /* free the indexes (see dm_table_complete) */ if (t->depth >= 2) vfree(t->index[t->depth - 2]); @@ -335,8 +352,9 @@ void dm_table_put(struct dm_table *t) if (!t) return; - if (atomic_dec_and_test(&t->holders)) - table_destroy(t); + smp_mb__before_atomic_dec(); + atomic_dec(&t->holders); + } /* Index: linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm.h =================================================================== --- linux-2.6.24.7-ibmrt2.16-view.orig/drivers/md/dm.h +++ linux-2.6.24.7-ibmrt2.16-view/drivers/md/dm.h @@ -100,6 +100,7 @@ struct dm_table; /*----------------------------------------------------------------- * Internal table functions. *---------------------------------------------------------------*/ +void dm_table_destroy(struct dm_table *t); void dm_table_event_callback(struct dm_table *t, void (*fn)(void *), void *context); struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);