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.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index ebaaf72cd822..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;
@@ -228,7 +242,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
228 return -ENOMEM; 242 return -ENOMEM;
229 243
230 INIT_LIST_HEAD(&t->devices); 244 INIT_LIST_HEAD(&t->devices);
231 atomic_set(&t->holders, 1); 245 atomic_set(&t->holders, 0);
232 t->barriers_supported = 1; 246 t->barriers_supported = 1;
233 247
234 if (!num_targets) 248 if (!num_targets)
@@ -259,10 +273,14 @@ static void free_devices(struct list_head *devices)
259 } 273 }
260} 274}
261 275
262static void table_destroy(struct dm_table *t) 276void dm_table_destroy(struct dm_table *t)
263{ 277{
264 unsigned int i; 278 unsigned int i;
265 279
280 while (atomic_read(&t->holders))
281 msleep(1);
282 smp_mb();
283
266 /* free the indexes (see dm_table_complete) */ 284 /* free the indexes (see dm_table_complete) */
267 if (t->depth >= 2) 285 if (t->depth >= 2)
268 vfree(t->index[t->depth - 2]); 286 vfree(t->index[t->depth - 2]);
@@ -300,8 +318,8 @@ void dm_table_put(struct dm_table *t)
300 if (!t) 318 if (!t)
301 return; 319 return;
302 320
303 if (atomic_dec_and_test(&t->holders)) 321 smp_mb__before_atomic_dec();
304 table_destroy(t); 322 atomic_dec(&t->holders);
305} 323}
306 324
307/* 325/*