aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r--drivers/md/dm-table.c47
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
27struct dm_table { 41struct 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
259static void table_destroy(struct dm_table *t) 276void 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
1020int dm_table_barrier_ok(struct dm_table *t)
1021{
1022 return t->barriers_supported;
1023}
1024EXPORT_SYMBOL(dm_table_barrier_ok);
1025
989EXPORT_SYMBOL(dm_vcalloc); 1026EXPORT_SYMBOL(dm_vcalloc);
990EXPORT_SYMBOL(dm_get_device); 1027EXPORT_SYMBOL(dm_get_device);
991EXPORT_SYMBOL(dm_put_device); 1028EXPORT_SYMBOL(dm_put_device);