diff options
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r-- | drivers/md/dm-table.c | 47 |
1 files changed, 42 insertions, 5 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 04e5fd742c2c..2fd66c30f7f8 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001 Sistina Software (UK) Limited. | 2 | * Copyright (C) 2001 Sistina Software (UK) Limited. |
3 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
18 | #include <linux/delay.h> | ||
18 | #include <asm/atomic.h> | 19 | #include <asm/atomic.h> |
19 | 20 | ||
20 | #define DM_MSG_PREFIX "table" | 21 | #define DM_MSG_PREFIX "table" |
@@ -24,6 +25,19 @@ | |||
24 | #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) | 25 | #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) |
25 | #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) | 26 | #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) |
26 | 27 | ||
28 | /* | ||
29 | * The table has always exactly one reference from either mapped_device->map | ||
30 | * or hash_cell->new_map. This reference is not counted in table->holders. | ||
31 | * A pair of dm_create_table/dm_destroy_table functions is used for table | ||
32 | * creation/destruction. | ||
33 | * | ||
34 | * Temporary references from the other code increase table->holders. A pair | ||
35 | * of dm_table_get/dm_table_put functions is used to manipulate it. | ||
36 | * | ||
37 | * When the table is about to be destroyed, we wait for table->holders to | ||
38 | * drop to zero. | ||
39 | */ | ||
40 | |||
27 | struct dm_table { | 41 | struct dm_table { |
28 | struct mapped_device *md; | 42 | struct mapped_device *md; |
29 | atomic_t holders; | 43 | atomic_t holders; |
@@ -38,6 +52,8 @@ struct dm_table { | |||
38 | sector_t *highs; | 52 | sector_t *highs; |
39 | struct dm_target *targets; | 53 | struct dm_target *targets; |
40 | 54 | ||
55 | unsigned barriers_supported:1; | ||
56 | |||
41 | /* | 57 | /* |
42 | * Indicates the rw permissions for the new logical | 58 | * Indicates the rw permissions for the new logical |
43 | * device. This should be a combination of FMODE_READ | 59 | * device. This should be a combination of FMODE_READ |
@@ -226,7 +242,8 @@ int dm_table_create(struct dm_table **result, fmode_t mode, | |||
226 | return -ENOMEM; | 242 | return -ENOMEM; |
227 | 243 | ||
228 | INIT_LIST_HEAD(&t->devices); | 244 | INIT_LIST_HEAD(&t->devices); |
229 | atomic_set(&t->holders, 1); | 245 | atomic_set(&t->holders, 0); |
246 | t->barriers_supported = 1; | ||
230 | 247 | ||
231 | if (!num_targets) | 248 | if (!num_targets) |
232 | num_targets = KEYS_PER_NODE; | 249 | num_targets = KEYS_PER_NODE; |
@@ -256,10 +273,14 @@ static void free_devices(struct list_head *devices) | |||
256 | } | 273 | } |
257 | } | 274 | } |
258 | 275 | ||
259 | static void table_destroy(struct dm_table *t) | 276 | void dm_table_destroy(struct dm_table *t) |
260 | { | 277 | { |
261 | unsigned int i; | 278 | unsigned int i; |
262 | 279 | ||
280 | while (atomic_read(&t->holders)) | ||
281 | msleep(1); | ||
282 | smp_mb(); | ||
283 | |||
263 | /* free the indexes (see dm_table_complete) */ | 284 | /* free the indexes (see dm_table_complete) */ |
264 | if (t->depth >= 2) | 285 | if (t->depth >= 2) |
265 | vfree(t->index[t->depth - 2]); | 286 | vfree(t->index[t->depth - 2]); |
@@ -297,8 +318,8 @@ void dm_table_put(struct dm_table *t) | |||
297 | if (!t) | 318 | if (!t) |
298 | return; | 319 | return; |
299 | 320 | ||
300 | if (atomic_dec_and_test(&t->holders)) | 321 | smp_mb__before_atomic_dec(); |
301 | table_destroy(t); | 322 | atomic_dec(&t->holders); |
302 | } | 323 | } |
303 | 324 | ||
304 | /* | 325 | /* |
@@ -728,6 +749,10 @@ int dm_table_add_target(struct dm_table *t, const char *type, | |||
728 | /* FIXME: the plan is to combine high here and then have | 749 | /* FIXME: the plan is to combine high here and then have |
729 | * the merge fn apply the target level restrictions. */ | 750 | * the merge fn apply the target level restrictions. */ |
730 | combine_restrictions_low(&t->limits, &tgt->limits); | 751 | combine_restrictions_low(&t->limits, &tgt->limits); |
752 | |||
753 | if (!(tgt->type->features & DM_TARGET_SUPPORTS_BARRIERS)) | ||
754 | t->barriers_supported = 0; | ||
755 | |||
731 | return 0; | 756 | return 0; |
732 | 757 | ||
733 | bad: | 758 | bad: |
@@ -772,6 +797,12 @@ int dm_table_complete(struct dm_table *t) | |||
772 | 797 | ||
773 | check_for_valid_limits(&t->limits); | 798 | check_for_valid_limits(&t->limits); |
774 | 799 | ||
800 | /* | ||
801 | * We only support barriers if there is exactly one underlying device. | ||
802 | */ | ||
803 | if (!list_is_singular(&t->devices)) | ||
804 | t->barriers_supported = 0; | ||
805 | |||
775 | /* how many indexes will the btree have ? */ | 806 | /* how many indexes will the btree have ? */ |
776 | leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); | 807 | leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); |
777 | t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); | 808 | t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); |
@@ -986,6 +1017,12 @@ struct mapped_device *dm_table_get_md(struct dm_table *t) | |||
986 | return t->md; | 1017 | return t->md; |
987 | } | 1018 | } |
988 | 1019 | ||
1020 | int dm_table_barrier_ok(struct dm_table *t) | ||
1021 | { | ||
1022 | return t->barriers_supported; | ||
1023 | } | ||
1024 | EXPORT_SYMBOL(dm_table_barrier_ok); | ||
1025 | |||
989 | EXPORT_SYMBOL(dm_vcalloc); | 1026 | EXPORT_SYMBOL(dm_vcalloc); |
990 | EXPORT_SYMBOL(dm_get_device); | 1027 | EXPORT_SYMBOL(dm_get_device); |
991 | EXPORT_SYMBOL(dm_put_device); | 1028 | EXPORT_SYMBOL(dm_put_device); |