diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-05 19:20:59 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-05 19:20:59 -0800 |
commit | 238c6d54830c624f34ac9cf123ac04aebfca5013 (patch) | |
tree | 43b7f595013483382a3053237c45d9d2824e0295 /drivers/md/dm-table.c | |
parent | 8e128ce3318a147903c893de1891f6c2306f8a61 (diff) | |
parent | a159c1ac5f33c6cf0f5aa3c9d1ccdc82c907ee46 (diff) | |
download | kernel-crypto-238c6d54830c624f34ac9cf123ac04aebfca5013.tar.gz kernel-crypto-238c6d54830c624f34ac9cf123ac04aebfca5013.tar.xz kernel-crypto-238c6d54830c624f34ac9cf123ac04aebfca5013.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm:
dm snapshot: extend exception store functions
dm snapshot: split out exception store implementations
dm snapshot: rename struct exception_store
dm snapshot: separate out exception store interface
dm mpath: move trigger_event to system workqueue
dm: add name and uuid to sysfs
dm table: rework reference counting
dm: support barriers on simple devices
dm request: extend target interface
dm request: add caches
dm ioctl: allow dm_copy_name_and_uuid to return only one field
dm log: ensure log bitmap fits on log device
dm log: move region_size validation
dm log: avoid reinitialising io_req on every operation
dm: consolidate target deregistration error handling
dm raid1: fix error count
dm log: fix dm_io_client leak on error paths
dm snapshot: change yield to msleep
dm table: drop reference at unbind
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 04e5fd742c2..2fd66c30f7f 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Sistina Software (UK) Limited. - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. * * This file is released under the GPL. */ @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/mutex.h> +#include <linux/delay.h> #include <asm/atomic.h> #define DM_MSG_PREFIX "table" @@ -24,6 +25,19 @@ #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) +/* + * 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 to + * drop to zero. + */ + struct dm_table { struct mapped_device *md; atomic_t holders; @@ -38,6 +52,8 @@ struct dm_table { sector_t *highs; struct dm_target *targets; + unsigned barriers_supported:1; + /* * Indicates the rw permissions for the new logical * device. This should be a combination of FMODE_READ @@ -226,7 +242,8 @@ int dm_table_create(struct dm_table **result, fmode_t mode, return -ENOMEM; INIT_LIST_HEAD(&t->devices); - atomic_set(&t->holders, 1); + atomic_set(&t->holders, 0); + t->barriers_supported = 1; if (!num_targets) num_targets = KEYS_PER_NODE; @@ -256,10 +273,14 @@ static void free_devices(struct list_head *devices) } } -static void table_destroy(struct dm_table *t) +void dm_table_destroy(struct dm_table *t) { unsigned int i; + while (atomic_read(&t->holders)) + msleep(1); + smp_mb(); + /* free the indexes (see dm_table_complete) */ if (t->depth >= 2) vfree(t->index[t->depth - 2]); @@ -297,8 +318,8 @@ 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); } /* @@ -728,6 +749,10 @@ int dm_table_add_target(struct dm_table *t, const char *type, /* FIXME: the plan is to combine high here and then have * the merge fn apply the target level restrictions. */ combine_restrictions_low(&t->limits, &tgt->limits); + + if (!(tgt->type->features & DM_TARGET_SUPPORTS_BARRIERS)) + t->barriers_supported = 0; + return 0; bad: @@ -772,6 +797,12 @@ int dm_table_complete(struct dm_table *t) check_for_valid_limits(&t->limits); + /* + * We only support barriers if there is exactly one underlying device. + */ + if (!list_is_singular(&t->devices)) + t->barriers_supported = 0; + /* how many indexes will the btree have ? */ leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); 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) return t->md; } +int dm_table_barrier_ok(struct dm_table *t) +{ + return t->barriers_supported; +} +EXPORT_SYMBOL(dm_table_barrier_ok); + EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); |