* [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id
@ 2012-03-02 23:59 Mike Snitzer
2012-03-02 23:59 ` [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use Mike Snitzer
2012-03-05 10:29 ` [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Joe Thornber
0 siblings, 2 replies; 6+ messages in thread
From: Mike Snitzer @ 2012-03-02 23:59 UTC (permalink / raw)
To: dm-devel; +Cc: ejt, snitzer
dm_thin_id is too specific to thin devices. Rename to allow for reuse
by other targets.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
drivers/md/dm-thin-metadata.c | 24 ++++++++++++------------
drivers/md/dm-thin-metadata.h | 14 +++++++-------
drivers/md/dm-thin.c | 16 ++++++++--------
3 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 1783741..62e7024 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -184,7 +184,7 @@ struct dm_pool_metadata {
struct dm_thin_device {
struct list_head list;
struct dm_pool_metadata *pmd;
- dm_thin_id id;
+ dm_dev_id id;
int open_count;
int changed;
@@ -799,7 +799,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
* on failure, @td is not initialized.
*/
static int __open_device(struct dm_pool_metadata *pmd,
- dm_thin_id dev, int create,
+ dm_dev_id dev, int create,
struct dm_thin_device **td)
{
int r, changed = 0;
@@ -867,7 +867,7 @@ static void __close_device(struct dm_thin_device *td)
}
static int __create_thin(struct dm_pool_metadata *pmd,
- dm_thin_id dev)
+ dm_dev_id dev)
{
int r;
dm_block_t dev_root;
@@ -910,7 +910,7 @@ static int __create_thin(struct dm_pool_metadata *pmd,
return r;
}
-int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev)
+int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_dev_id dev)
{
int r;
@@ -923,7 +923,7 @@ int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev)
static int __set_snapshot_details(struct dm_pool_metadata *pmd,
struct dm_thin_device *snap,
- dm_thin_id origin, uint32_t time)
+ dm_dev_id origin, uint32_t time)
{
int r;
struct dm_thin_device *td;
@@ -943,7 +943,7 @@ static int __set_snapshot_details(struct dm_pool_metadata *pmd,
}
static int __create_snap(struct dm_pool_metadata *pmd,
- dm_thin_id dev, dm_thin_id origin)
+ dm_dev_id dev, dm_dev_id origin)
{
int r;
dm_block_t origin_root;
@@ -1000,8 +1000,8 @@ bad:
}
int dm_pool_create_snap(struct dm_pool_metadata *pmd,
- dm_thin_id dev,
- dm_thin_id origin)
+ dm_dev_id dev,
+ dm_dev_id origin)
{
int r;
@@ -1012,7 +1012,7 @@ int dm_pool_create_snap(struct dm_pool_metadata *pmd,
return r;
}
-static int __delete_device(struct dm_pool_metadata *pmd, dm_thin_id dev)
+static int __delete_device(struct dm_pool_metadata *pmd, dm_dev_id dev)
{
int r;
uint64_t key = dev;
@@ -1045,7 +1045,7 @@ static int __delete_device(struct dm_pool_metadata *pmd, dm_thin_id dev)
}
int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
- dm_thin_id dev)
+ dm_dev_id dev)
{
int r;
@@ -1188,7 +1188,7 @@ int dm_pool_get_held_metadata_root(struct dm_pool_metadata *pmd,
return r;
}
-int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev,
+int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_dev_id dev,
struct dm_thin_device **td)
{
int r;
@@ -1209,7 +1209,7 @@ int dm_pool_close_thin_device(struct dm_thin_device *td)
return 0;
}
-dm_thin_id dm_thin_dev_id(struct dm_thin_device *td)
+dm_dev_id dm_thin_dev_id(struct dm_thin_device *td)
{
return td->id;
}
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 4460857..511a223 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -34,7 +34,7 @@ struct dm_thin_device;
/*
* Device identifier
*/
-typedef uint64_t dm_thin_id;
+typedef uint64_t dm_dev_id;
/*
* Reopens or creates a new, empty metadata volume.
@@ -55,7 +55,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd);
/*
* Device creation/deletion.
*/
-int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev);
+int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_dev_id dev);
/*
* An internal snapshot.
@@ -63,8 +63,8 @@ int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev);
* You can only snapshot a quiesced origin i.e. one that is either
* suspended or not instanced at all.
*/
-int dm_pool_create_snap(struct dm_pool_metadata *pmd, dm_thin_id dev,
- dm_thin_id origin);
+int dm_pool_create_snap(struct dm_pool_metadata *pmd, dm_dev_id dev,
+ dm_dev_id origin);
/*
* Deletes a virtual device from the metadata. It _is_ safe to call this
@@ -72,7 +72,7 @@ int dm_pool_create_snap(struct dm_pool_metadata *pmd, dm_thin_id dev,
* failing. You still need to call close() on the device.
*/
int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd,
- dm_thin_id dev);
+ dm_dev_id dev);
/*
* Commits _all_ metadata changes: device creation, deletion, mapping
@@ -106,12 +106,12 @@ int dm_pool_get_held_metadata_root(struct dm_pool_metadata *pmd,
/*
* Opening the same device more than once will fail with -EBUSY.
*/
-int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev,
+int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_dev_id dev,
struct dm_thin_device **td);
int dm_pool_close_thin_device(struct dm_thin_device *td);
-dm_thin_id dm_thin_dev_id(struct dm_thin_device *td);
+dm_dev_id dm_thin_dev_id(struct dm_thin_device *td);
struct dm_thin_lookup_result {
dm_block_t block;
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index d9ea643..536835f 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -107,7 +107,7 @@ struct bio_prison;
struct cell_key {
int virtual;
- dm_thin_id dev;
+ dm_dev_id dev;
dm_block_t block;
};
@@ -560,7 +560,7 @@ struct pool_c {
struct thin_c {
struct dm_dev *pool_dev;
struct dm_dev *origin_dev;
- dm_thin_id dev_id;
+ dm_dev_id dev_id;
struct pool *pool;
struct dm_thin_device *td;
@@ -2116,7 +2116,7 @@ static int check_arg_count(unsigned argc, unsigned args_required)
return 0;
}
-static int read_dev_id(char *arg, dm_thin_id *dev_id, int warning)
+static int read_dev_id(char *arg, dm_dev_id *dev_id, int warning)
{
if (!kstrtoull(arg, 10, (unsigned long long *)dev_id) &&
*dev_id <= MAX_DEV_ID)
@@ -2130,7 +2130,7 @@ static int read_dev_id(char *arg, dm_thin_id *dev_id, int warning)
static int process_create_thin_mesg(unsigned argc, char **argv, struct pool *pool)
{
- dm_thin_id dev_id;
+ dm_dev_id dev_id;
int r;
r = check_arg_count(argc, 2);
@@ -2153,8 +2153,8 @@ static int process_create_thin_mesg(unsigned argc, char **argv, struct pool *poo
static int process_create_snap_mesg(unsigned argc, char **argv, struct pool *pool)
{
- dm_thin_id dev_id;
- dm_thin_id origin_dev_id;
+ dm_dev_id dev_id;
+ dm_dev_id origin_dev_id;
int r;
r = check_arg_count(argc, 3);
@@ -2181,7 +2181,7 @@ static int process_create_snap_mesg(unsigned argc, char **argv, struct pool *poo
static int process_delete_mesg(unsigned argc, char **argv, struct pool *pool)
{
- dm_thin_id dev_id;
+ dm_dev_id dev_id;
int r;
r = check_arg_count(argc, 2);
@@ -2201,7 +2201,7 @@ static int process_delete_mesg(unsigned argc, char **argv, struct pool *pool)
static int process_set_transaction_id_mesg(unsigned argc, char **argv, struct pool *pool)
{
- dm_thin_id old_id, new_id;
+ dm_dev_id old_id, new_id;
int r;
r = check_arg_count(argc, 3);
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use
2012-03-02 23:59 [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Mike Snitzer
@ 2012-03-02 23:59 ` Mike Snitzer
2012-03-03 0:26 ` Alasdair G Kergon
2012-03-03 3:13 ` [PATCH 2/2 v2] " Mike Snitzer
2012-03-05 10:29 ` [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Joe Thornber
1 sibling, 2 replies; 6+ messages in thread
From: Mike Snitzer @ 2012-03-02 23:59 UTC (permalink / raw)
To: dm-devel; +Cc: ejt, snitzer
Allow other DM targets to make use of the bio_prison and deferred_set
infrastructure. Code elevated to drivers/md/dm-bio-prison.[hc]
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
drivers/md/Makefile | 2 +-
drivers/md/dm-bio-prison.c | 336 +++++++++++++++++++++++++++++++++++++
drivers/md/dm-bio-prison.h | 110 ++++++++++++
drivers/md/dm-thin-metadata.h | 6 +-
drivers/md/dm-thin.c | 368 +----------------------------------------
5 files changed, 449 insertions(+), 373 deletions(-)
create mode 100644 drivers/md/dm-bio-prison.c
create mode 100644 drivers/md/dm-bio-prison.h
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 046860c..c1706ed 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -3,7 +3,7 @@
#
dm-mod-y += dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
- dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o
+ dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o dm-bio-prison.o
dm-multipath-y += dm-path-selector.o dm-mpath.o
dm-snapshot-y += dm-snap.o dm-exception-store.o dm-snap-transient.o \
dm-snap-persistent.o
diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c
new file mode 100644
index 0000000..ddc4afc
--- /dev/null
+++ b/drivers/md/dm-bio-prison.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2012 Red Hat.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-bio-prison.h"
+
+#include <linux/module.h>
+
+/*----------------------------------------------------------------*/
+
+static uint32_t calc_nr_buckets(unsigned nr_cells)
+{
+ uint32_t n = 128;
+
+ nr_cells /= 4;
+ nr_cells = min(nr_cells, 8192u);
+
+ while (n < nr_cells)
+ n <<= 1;
+
+ return n;
+}
+
+/*
+ * @nr_cells should be the number of cells you want in use _concurrently_.
+ * Don't confuse it with the number of distinct keys.
+ */
+struct bio_prison *prison_create(unsigned nr_cells)
+{
+ unsigned i;
+ uint32_t nr_buckets = calc_nr_buckets(nr_cells);
+ size_t len = sizeof(struct bio_prison) +
+ (sizeof(struct hlist_head) * nr_buckets);
+ struct bio_prison *prison = kmalloc(len, GFP_KERNEL);
+
+ if (!prison)
+ return NULL;
+
+ spin_lock_init(&prison->lock);
+ prison->cell_pool = mempool_create_kmalloc_pool(nr_cells,
+ sizeof(struct cell));
+ if (!prison->cell_pool) {
+ kfree(prison);
+ return NULL;
+ }
+
+ prison->nr_buckets = nr_buckets;
+ prison->hash_mask = nr_buckets - 1;
+ prison->cells = (struct hlist_head *) (prison + 1);
+ for (i = 0; i < nr_buckets; i++)
+ INIT_HLIST_HEAD(prison->cells + i);
+
+ return prison;
+}
+EXPORT_SYMBOL(prison_create);
+
+void prison_destroy(struct bio_prison *prison)
+{
+ mempool_destroy(prison->cell_pool);
+ kfree(prison);
+}
+EXPORT_SYMBOL(prison_destroy);
+
+static uint32_t hash_key(struct bio_prison *prison, struct cell_key *key)
+{
+ const unsigned long BIG_PRIME = 4294967291UL;
+ uint64_t hash = key->block * BIG_PRIME;
+
+ return (uint32_t) (hash & prison->hash_mask);
+}
+
+static int keys_equal(struct cell_key *lhs, struct cell_key *rhs)
+{
+ return (lhs->virtual == rhs->virtual) &&
+ (lhs->dev == rhs->dev) &&
+ (lhs->block == rhs->block);
+}
+
+static struct cell *__search_bucket(struct hlist_head *bucket,
+ struct cell_key *key)
+{
+ struct cell *cell;
+ struct hlist_node *tmp;
+
+ hlist_for_each_entry(cell, tmp, bucket, list)
+ if (keys_equal(&cell->key, key))
+ return cell;
+
+ return NULL;
+}
+
+/*
+ * This may block if a new cell needs allocating. You must ensure that
+ * cells will be unlocked even if the calling thread is blocked.
+ *
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
+ */
+int bio_detain(struct bio_prison *prison, struct cell_key *key,
+ struct bio *inmate, struct cell **ref)
+{
+ int r;
+ unsigned long flags;
+ uint32_t hash = hash_key(prison, key);
+ struct cell *uninitialized_var(cell), *cell2 = NULL;
+
+ BUG_ON(hash > prison->nr_buckets);
+
+ spin_lock_irqsave(&prison->lock, flags);
+ cell = __search_bucket(prison->cells + hash, key);
+
+ if (!cell) {
+ /*
+ * Allocate a new cell
+ */
+ spin_unlock_irqrestore(&prison->lock, flags);
+ cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
+ spin_lock_irqsave(&prison->lock, flags);
+
+ /*
+ * We've been unlocked, so we have to double check that
+ * nobody else has inserted this cell in the meantime.
+ */
+ cell = __search_bucket(prison->cells + hash, key);
+
+ if (!cell) {
+ cell = cell2;
+ cell2 = NULL;
+
+ cell->prison = prison;
+ memcpy(&cell->key, key, sizeof(cell->key));
+ cell->holder = inmate;
+ bio_list_init(&cell->bios);
+ hlist_add_head(&cell->list, prison->cells + hash);
+ r = 0;
+
+ } else {
+ mempool_free(cell2, prison->cell_pool);
+ cell2 = NULL;
+ r = 1;
+ bio_list_add(&cell->bios, inmate);
+ }
+
+ } else {
+ r = 1;
+ bio_list_add(&cell->bios, inmate);
+ }
+ spin_unlock_irqrestore(&prison->lock, flags);
+
+ *ref = cell;
+ return r;
+}
+EXPORT_SYMBOL(bio_detain);
+
+/*
+ * @inmates must have been initialised prior to this call
+ */
+static void __cell_release(struct cell *cell, struct bio_list *inmates)
+{
+ struct bio_prison *prison = cell->prison;
+
+ hlist_del(&cell->list);
+
+ if (inmates) {
+ bio_list_add(inmates, cell->holder);
+ bio_list_merge(inmates, &cell->bios);
+ }
+
+ mempool_free(cell, prison->cell_pool);
+}
+
+void cell_release(struct cell *cell, struct bio_list *bios)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release(cell, bios);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL(cell_release);
+
+/*
+ * There are a couple of places where we put a bio into a cell briefly
+ * before taking it out again. In these situations we know that no other
+ * bio may be in the cell. This function releases the cell, and also does
+ * a sanity check.
+ */
+static void __cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+ hlist_del(&cell->list);
+ BUG_ON(cell->holder != bio);
+ BUG_ON(!bio_list_empty(&cell->bios));
+}
+
+void cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release_singleton(cell, bio);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL(cell_release_singleton);
+
+/*
+ * Sometimes we don't want the holder, just the additional bios.
+ */
+static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+ struct bio_prison *prison = cell->prison;
+
+ hlist_del(&cell->list);
+ if (inmates)
+ bio_list_merge(inmates, &cell->bios);
+
+ mempool_free(cell, prison->cell_pool);
+}
+
+void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release_no_holder(cell, inmates);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL(cell_release_no_holder);
+
+void cell_error(struct cell *cell)
+{
+ struct bio_prison *prison = cell->prison;
+ struct bio_list bios;
+ struct bio *bio;
+ unsigned long flags;
+
+ bio_list_init(&bios);
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release(cell, &bios);
+ spin_unlock_irqrestore(&prison->lock, flags);
+
+ while ((bio = bio_list_pop(&bios)))
+ bio_io_error(bio);
+}
+EXPORT_SYMBOL(cell_error);
+
+/*----------------------------------------------------------------*/
+
+void ds_init(struct deferred_set *ds)
+{
+ int i;
+
+ spin_lock_init(&ds->lock);
+ ds->current_entry = 0;
+ ds->sweeper = 0;
+ for (i = 0; i < DEFERRED_SET_SIZE; i++) {
+ ds->entries[i].ds = ds;
+ ds->entries[i].count = 0;
+ INIT_LIST_HEAD(&ds->entries[i].work_items);
+ }
+}
+EXPORT_SYMBOL(ds_init);
+
+struct deferred_entry *ds_inc(struct deferred_set *ds)
+{
+ unsigned long flags;
+ struct deferred_entry *entry;
+
+ spin_lock_irqsave(&ds->lock, flags);
+ entry = ds->entries + ds->current_entry;
+ entry->count++;
+ spin_unlock_irqrestore(&ds->lock, flags);
+
+ return entry;
+}
+EXPORT_SYMBOL(ds_inc);
+
+unsigned ds_next(unsigned index)
+{
+ return (index + 1) % DEFERRED_SET_SIZE;
+}
+
+static void __sweep(struct deferred_set *ds, struct list_head *head)
+{
+ while ((ds->sweeper != ds->current_entry) &&
+ !ds->entries[ds->sweeper].count) {
+ list_splice_init(&ds->entries[ds->sweeper].work_items, head);
+ ds->sweeper = ds_next(ds->sweeper);
+ }
+
+ if ((ds->sweeper == ds->current_entry) && !ds->entries[ds->sweeper].count)
+ list_splice_init(&ds->entries[ds->sweeper].work_items, head);
+}
+
+void ds_dec(struct deferred_entry *entry, struct list_head *head)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&entry->ds->lock, flags);
+ BUG_ON(!entry->count);
+ --entry->count;
+ __sweep(entry->ds, head);
+ spin_unlock_irqrestore(&entry->ds->lock, flags);
+}
+EXPORT_SYMBOL(ds_dec);
+
+/*
+ * Returns 1 if deferred or 0 if no pending items to delay job.
+ */
+int ds_add_work(struct deferred_set *ds, struct list_head *work)
+{
+ int r = 1;
+ unsigned long flags;
+ unsigned next_entry;
+
+ spin_lock_irqsave(&ds->lock, flags);
+ if ((ds->sweeper == ds->current_entry) &&
+ !ds->entries[ds->current_entry].count)
+ r = 0;
+ else {
+ list_add(work, &ds->entries[ds->current_entry].work_items);
+ next_entry = ds_next(ds->current_entry);
+ if (!ds->entries[next_entry].count)
+ ds->current_entry = next_entry;
+ }
+ spin_unlock_irqrestore(&ds->lock, flags);
+
+ return r;
+}
+EXPORT_SYMBOL(ds_add_work);
+
+/*----------------------------------------------------------------*/
diff --git a/drivers/md/dm-bio-prison.h b/drivers/md/dm-bio-prison.h
new file mode 100644
index 0000000..ba428d0
--- /dev/null
+++ b/drivers/md/dm-bio-prison.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 Red Hat.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_BIO_PRISON_H
+#define DM_BIO_PRISON_H
+
+#include "persistent-data/dm-block-manager.h"
+
+#include <linux/list.h>
+
+/*----------------------------------------------------------------*/
+
+/*
+ * Device identifier
+ */
+typedef uint64_t dm_dev_id;
+
+/*----------------------------------------------------------------*/
+
+/*
+ * Sometimes we can't deal with a bio straight away. We put them in prison
+ * where they can't cause any mischief. Bios are put in a cell identified
+ * by a key, multiple bios can be in the same cell. When the cell is
+ * subsequently unlocked the bios become available.
+ */
+struct bio_prison;
+
+struct cell_key {
+ int virtual;
+ dm_dev_id dev;
+ dm_block_t block;
+};
+
+struct cell {
+ struct hlist_node list;
+ struct bio_prison *prison;
+ struct cell_key key;
+ struct bio *holder;
+ struct bio_list bios;
+};
+
+struct bio_prison {
+ spinlock_t lock;
+ mempool_t *cell_pool;
+
+ unsigned nr_buckets;
+ unsigned hash_mask;
+ struct hlist_head *cells;
+};
+
+/*
+ * @nr_cells should be the number of cells you want in use _concurrently_.
+ * Don't confuse it with the number of distinct keys.
+ */
+struct bio_prison *prison_create(unsigned nr_cells);
+void prison_destroy(struct bio_prison *prison);
+
+/*
+ * This may block if a new cell needs allocating. You must ensure that
+ * cells will be unlocked even if the calling thread is blocked.
+ *
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
+ */
+int bio_detain(struct bio_prison *prison, struct cell_key *key,
+ struct bio *inmate, struct cell **ref);
+void cell_release(struct cell *cell, struct bio_list *bios);
+void cell_release_singleton(struct cell *cell, struct bio *bio);
+void cell_release_no_holder(struct cell *cell, struct bio_list *inmates);
+void cell_error(struct cell *cell);
+
+/*----------------------------------------------------------------*/
+
+/*
+ * We use the deferred set to keep track of pending reads to shared blocks.
+ * We do this to ensure the new mapping caused by a write isn't performed
+ * until these prior reads have completed. Otherwise the insertion of the
+ * new mapping could free the old block that the read bios are mapped to.
+ */
+#define DEFERRED_SET_SIZE 64
+
+struct deferred_set;
+struct deferred_entry {
+ struct deferred_set *ds;
+ unsigned count;
+ struct list_head work_items;
+};
+
+struct deferred_set {
+ spinlock_t lock;
+ unsigned current_entry;
+ unsigned sweeper;
+ struct deferred_entry entries[DEFERRED_SET_SIZE];
+};
+
+void ds_init(struct deferred_set *ds);
+struct deferred_entry *ds_inc(struct deferred_set *ds);
+unsigned ds_next(unsigned index);
+void ds_dec(struct deferred_entry *entry, struct list_head *head);
+
+/*
+ * Returns 1 if deferred or 0 if no pending items to delay job.
+ */
+int ds_add_work(struct deferred_set *ds, struct list_head *work);
+
+/*----------------------------------------------------------------*/
+
+#endif
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 511a223..d718189 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -7,6 +7,7 @@
#ifndef DM_THIN_METADATA_H
#define DM_THIN_METADATA_H
+#include "dm-bio-prison.h"
#include "persistent-data/dm-block-manager.h"
#define THIN_METADATA_BLOCK_SIZE 4096
@@ -32,11 +33,6 @@ struct dm_pool_metadata;
struct dm_thin_device;
/*
- * Device identifier
- */
-typedef uint64_t dm_dev_id;
-
-/*
* Reopens or creates a new, empty metadata volume.
*/
struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 536835f..d0be4b0 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -4,6 +4,7 @@
* This file is released under the GPL.
*/
+#include "dm-bio-prison.h"
#include "dm-thin-metadata.h"
#include <linux/device-mapper.h>
@@ -20,7 +21,6 @@
* Tunable constants
*/
#define ENDIO_HOOK_POOL_SIZE 10240
-#define DEFERRED_SET_SIZE 64
#define MAPPING_POOL_SIZE 1024
#define PRISON_CELLS 1024
#define COMMIT_PERIOD HZ
@@ -98,372 +98,6 @@
/*----------------------------------------------------------------*/
/*
- * Sometimes we can't deal with a bio straight away. We put them in prison
- * where they can't cause any mischief. Bios are put in a cell identified
- * by a key, multiple bios can be in the same cell. When the cell is
- * subsequently unlocked the bios become available.
- */
-struct bio_prison;
-
-struct cell_key {
- int virtual;
- dm_dev_id dev;
- dm_block_t block;
-};
-
-struct cell {
- struct hlist_node list;
- struct bio_prison *prison;
- struct cell_key key;
- struct bio *holder;
- struct bio_list bios;
-};
-
-struct bio_prison {
- spinlock_t lock;
- mempool_t *cell_pool;
-
- unsigned nr_buckets;
- unsigned hash_mask;
- struct hlist_head *cells;
-};
-
-static uint32_t calc_nr_buckets(unsigned nr_cells)
-{
- uint32_t n = 128;
-
- nr_cells /= 4;
- nr_cells = min(nr_cells, 8192u);
-
- while (n < nr_cells)
- n <<= 1;
-
- return n;
-}
-
-/*
- * @nr_cells should be the number of cells you want in use _concurrently_.
- * Don't confuse it with the number of distinct keys.
- */
-static struct bio_prison *prison_create(unsigned nr_cells)
-{
- unsigned i;
- uint32_t nr_buckets = calc_nr_buckets(nr_cells);
- size_t len = sizeof(struct bio_prison) +
- (sizeof(struct hlist_head) * nr_buckets);
- struct bio_prison *prison = kmalloc(len, GFP_KERNEL);
-
- if (!prison)
- return NULL;
-
- spin_lock_init(&prison->lock);
- prison->cell_pool = mempool_create_kmalloc_pool(nr_cells,
- sizeof(struct cell));
- if (!prison->cell_pool) {
- kfree(prison);
- return NULL;
- }
-
- prison->nr_buckets = nr_buckets;
- prison->hash_mask = nr_buckets - 1;
- prison->cells = (struct hlist_head *) (prison + 1);
- for (i = 0; i < nr_buckets; i++)
- INIT_HLIST_HEAD(prison->cells + i);
-
- return prison;
-}
-
-static void prison_destroy(struct bio_prison *prison)
-{
- mempool_destroy(prison->cell_pool);
- kfree(prison);
-}
-
-static uint32_t hash_key(struct bio_prison *prison, struct cell_key *key)
-{
- const unsigned long BIG_PRIME = 4294967291UL;
- uint64_t hash = key->block * BIG_PRIME;
-
- return (uint32_t) (hash & prison->hash_mask);
-}
-
-static int keys_equal(struct cell_key *lhs, struct cell_key *rhs)
-{
- return (lhs->virtual == rhs->virtual) &&
- (lhs->dev == rhs->dev) &&
- (lhs->block == rhs->block);
-}
-
-static struct cell *__search_bucket(struct hlist_head *bucket,
- struct cell_key *key)
-{
- struct cell *cell;
- struct hlist_node *tmp;
-
- hlist_for_each_entry(cell, tmp, bucket, list)
- if (keys_equal(&cell->key, key))
- return cell;
-
- return NULL;
-}
-
-/*
- * This may block if a new cell needs allocating. You must ensure that
- * cells will be unlocked even if the calling thread is blocked.
- *
- * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
- */
-static int bio_detain(struct bio_prison *prison, struct cell_key *key,
- struct bio *inmate, struct cell **ref)
-{
- int r;
- unsigned long flags;
- uint32_t hash = hash_key(prison, key);
- struct cell *uninitialized_var(cell), *cell2 = NULL;
-
- BUG_ON(hash > prison->nr_buckets);
-
- spin_lock_irqsave(&prison->lock, flags);
- cell = __search_bucket(prison->cells + hash, key);
-
- if (!cell) {
- /*
- * Allocate a new cell
- */
- spin_unlock_irqrestore(&prison->lock, flags);
- cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
- spin_lock_irqsave(&prison->lock, flags);
-
- /*
- * We've been unlocked, so we have to double check that
- * nobody else has inserted this cell in the meantime.
- */
- cell = __search_bucket(prison->cells + hash, key);
-
- if (!cell) {
- cell = cell2;
- cell2 = NULL;
-
- cell->prison = prison;
- memcpy(&cell->key, key, sizeof(cell->key));
- cell->holder = inmate;
- bio_list_init(&cell->bios);
- hlist_add_head(&cell->list, prison->cells + hash);
- r = 0;
-
- } else {
- mempool_free(cell2, prison->cell_pool);
- cell2 = NULL;
- r = 1;
- bio_list_add(&cell->bios, inmate);
- }
-
- } else {
- r = 1;
- bio_list_add(&cell->bios, inmate);
- }
- spin_unlock_irqrestore(&prison->lock, flags);
-
- *ref = cell;
- return r;
-}
-
-/*
- * @inmates must have been initialised prior to this call
- */
-static void __cell_release(struct cell *cell, struct bio_list *inmates)
-{
- struct bio_prison *prison = cell->prison;
-
- hlist_del(&cell->list);
-
- if (inmates) {
- bio_list_add(inmates, cell->holder);
- bio_list_merge(inmates, &cell->bios);
- }
-
- mempool_free(cell, prison->cell_pool);
-}
-
-static void cell_release(struct cell *cell, struct bio_list *bios)
-{
- unsigned long flags;
- struct bio_prison *prison = cell->prison;
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release(cell, bios);
- spin_unlock_irqrestore(&prison->lock, flags);
-}
-
-/*
- * There are a couple of places where we put a bio into a cell briefly
- * before taking it out again. In these situations we know that no other
- * bio may be in the cell. This function releases the cell, and also does
- * a sanity check.
- */
-static void __cell_release_singleton(struct cell *cell, struct bio *bio)
-{
- hlist_del(&cell->list);
- BUG_ON(cell->holder != bio);
- BUG_ON(!bio_list_empty(&cell->bios));
-}
-
-static void cell_release_singleton(struct cell *cell, struct bio *bio)
-{
- unsigned long flags;
- struct bio_prison *prison = cell->prison;
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release_singleton(cell, bio);
- spin_unlock_irqrestore(&prison->lock, flags);
-}
-
-/*
- * Sometimes we don't want the holder, just the additional bios.
- */
-static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
-{
- struct bio_prison *prison = cell->prison;
-
- hlist_del(&cell->list);
- if (inmates)
- bio_list_merge(inmates, &cell->bios);
-
- mempool_free(cell, prison->cell_pool);
-}
-
-static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
-{
- unsigned long flags;
- struct bio_prison *prison = cell->prison;
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release_no_holder(cell, inmates);
- spin_unlock_irqrestore(&prison->lock, flags);
-}
-
-static void cell_error(struct cell *cell)
-{
- struct bio_prison *prison = cell->prison;
- struct bio_list bios;
- struct bio *bio;
- unsigned long flags;
-
- bio_list_init(&bios);
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release(cell, &bios);
- spin_unlock_irqrestore(&prison->lock, flags);
-
- while ((bio = bio_list_pop(&bios)))
- bio_io_error(bio);
-}
-
-/*----------------------------------------------------------------*/
-
-/*
- * We use the deferred set to keep track of pending reads to shared blocks.
- * We do this to ensure the new mapping caused by a write isn't performed
- * until these prior reads have completed. Otherwise the insertion of the
- * new mapping could free the old block that the read bios are mapped to.
- */
-
-struct deferred_set;
-struct deferred_entry {
- struct deferred_set *ds;
- unsigned count;
- struct list_head work_items;
-};
-
-struct deferred_set {
- spinlock_t lock;
- unsigned current_entry;
- unsigned sweeper;
- struct deferred_entry entries[DEFERRED_SET_SIZE];
-};
-
-static void ds_init(struct deferred_set *ds)
-{
- int i;
-
- spin_lock_init(&ds->lock);
- ds->current_entry = 0;
- ds->sweeper = 0;
- for (i = 0; i < DEFERRED_SET_SIZE; i++) {
- ds->entries[i].ds = ds;
- ds->entries[i].count = 0;
- INIT_LIST_HEAD(&ds->entries[i].work_items);
- }
-}
-
-static struct deferred_entry *ds_inc(struct deferred_set *ds)
-{
- unsigned long flags;
- struct deferred_entry *entry;
-
- spin_lock_irqsave(&ds->lock, flags);
- entry = ds->entries + ds->current_entry;
- entry->count++;
- spin_unlock_irqrestore(&ds->lock, flags);
-
- return entry;
-}
-
-static unsigned ds_next(unsigned index)
-{
- return (index + 1) % DEFERRED_SET_SIZE;
-}
-
-static void __sweep(struct deferred_set *ds, struct list_head *head)
-{
- while ((ds->sweeper != ds->current_entry) &&
- !ds->entries[ds->sweeper].count) {
- list_splice_init(&ds->entries[ds->sweeper].work_items, head);
- ds->sweeper = ds_next(ds->sweeper);
- }
-
- if ((ds->sweeper == ds->current_entry) && !ds->entries[ds->sweeper].count)
- list_splice_init(&ds->entries[ds->sweeper].work_items, head);
-}
-
-static void ds_dec(struct deferred_entry *entry, struct list_head *head)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&entry->ds->lock, flags);
- BUG_ON(!entry->count);
- --entry->count;
- __sweep(entry->ds, head);
- spin_unlock_irqrestore(&entry->ds->lock, flags);
-}
-
-/*
- * Returns 1 if deferred or 0 if no pending items to delay job.
- */
-static int ds_add_work(struct deferred_set *ds, struct list_head *work)
-{
- int r = 1;
- unsigned long flags;
- unsigned next_entry;
-
- spin_lock_irqsave(&ds->lock, flags);
- if ((ds->sweeper == ds->current_entry) &&
- !ds->entries[ds->current_entry].count)
- r = 0;
- else {
- list_add(work, &ds->entries[ds->current_entry].work_items);
- next_entry = ds_next(ds->current_entry);
- if (!ds->entries[next_entry].count)
- ds->current_entry = next_entry;
- }
- spin_unlock_irqrestore(&ds->lock, flags);
-
- return r;
-}
-
-/*----------------------------------------------------------------*/
-
-/*
* Key building.
*/
static void build_data_key(struct dm_thin_device *td,
--
1.7.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use
2012-03-02 23:59 ` [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use Mike Snitzer
@ 2012-03-03 0:26 ` Alasdair G Kergon
2012-03-03 3:13 ` [PATCH 2/2 v2] " Mike Snitzer
1 sibling, 0 replies; 6+ messages in thread
From: Alasdair G Kergon @ 2012-03-03 0:26 UTC (permalink / raw)
To: Mike Snitzer; +Cc: dm-devel, ejt
On Fri, Mar 02, 2012 at 06:59:30PM -0500, Mike Snitzer wrote:
> +EXPORT_SYMBOL(prison_create);
_GPL please and place a dm_something prefix on everything exported.
Thanks,
Alasdair
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2 v2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use
2012-03-02 23:59 ` [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use Mike Snitzer
2012-03-03 0:26 ` Alasdair G Kergon
@ 2012-03-03 3:13 ` Mike Snitzer
1 sibling, 0 replies; 6+ messages in thread
From: Mike Snitzer @ 2012-03-03 3:13 UTC (permalink / raw)
To: dm-devel; +Cc: ejt
Allow other DM targets to make use of the bio_prison and deferred_set
infrastructure. Code elevated to drivers/md/dm-bio-prison.[hc]
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
drivers/md/Makefile | 2
drivers/md/dm-bio-prison.c | 336 ++++++++++++++++++++++++++++++++
drivers/md/dm-bio-prison.h | 109 ++++++++++
drivers/md/dm-thin-metadata.h | 6
drivers/md/dm-thin.c | 438 +++---------------------------------------
5 files changed, 483 insertions(+), 408 deletions(-)
create mode 100644 drivers/md/dm-bio-prison.c
create mode 100644 drivers/md/dm-bio-prison.h
Index: linux-2.6/drivers/md/Makefile
===================================================================
--- linux-2.6.orig/drivers/md/Makefile
+++ linux-2.6/drivers/md/Makefile
@@ -3,7 +3,7 @@
#
dm-mod-y += dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
- dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o
+ dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o dm-bio-prison.o
dm-multipath-y += dm-path-selector.o dm-mpath.o
dm-snapshot-y += dm-snap.o dm-exception-store.o dm-snap-transient.o \
dm-snap-persistent.o
Index: linux-2.6/drivers/md/dm-bio-prison.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/md/dm-bio-prison.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2012 Red Hat.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-bio-prison.h"
+
+#include <linux/module.h>
+
+/*----------------------------------------------------------------*/
+
+static uint32_t calc_nr_buckets(unsigned nr_cells)
+{
+ uint32_t n = 128;
+
+ nr_cells /= 4;
+ nr_cells = min(nr_cells, 8192u);
+
+ while (n < nr_cells)
+ n <<= 1;
+
+ return n;
+}
+
+/*
+ * @nr_cells should be the number of cells you want in use _concurrently_.
+ * Don't confuse it with the number of distinct keys.
+ */
+struct bio_prison *dm_prison_create(unsigned nr_cells)
+{
+ unsigned i;
+ uint32_t nr_buckets = calc_nr_buckets(nr_cells);
+ size_t len = sizeof(struct bio_prison) +
+ (sizeof(struct hlist_head) * nr_buckets);
+ struct bio_prison *prison = kmalloc(len, GFP_KERNEL);
+
+ if (!prison)
+ return NULL;
+
+ spin_lock_init(&prison->lock);
+ prison->cell_pool = mempool_create_kmalloc_pool(nr_cells,
+ sizeof(struct cell));
+ if (!prison->cell_pool) {
+ kfree(prison);
+ return NULL;
+ }
+
+ prison->nr_buckets = nr_buckets;
+ prison->hash_mask = nr_buckets - 1;
+ prison->cells = (struct hlist_head *) (prison + 1);
+ for (i = 0; i < nr_buckets; i++)
+ INIT_HLIST_HEAD(prison->cells + i);
+
+ return prison;
+}
+EXPORT_SYMBOL_GPL(dm_prison_create);
+
+void dm_prison_destroy(struct bio_prison *prison)
+{
+ mempool_destroy(prison->cell_pool);
+ kfree(prison);
+}
+EXPORT_SYMBOL_GPL(dm_prison_destroy);
+
+static uint32_t hash_key(struct bio_prison *prison, struct cell_key *key)
+{
+ const unsigned long BIG_PRIME = 4294967291UL;
+ uint64_t hash = key->block * BIG_PRIME;
+
+ return (uint32_t) (hash & prison->hash_mask);
+}
+
+static int keys_equal(struct cell_key *lhs, struct cell_key *rhs)
+{
+ return (lhs->virtual == rhs->virtual) &&
+ (lhs->dev == rhs->dev) &&
+ (lhs->block == rhs->block);
+}
+
+static struct cell *__search_bucket(struct hlist_head *bucket,
+ struct cell_key *key)
+{
+ struct cell *cell;
+ struct hlist_node *tmp;
+
+ hlist_for_each_entry(cell, tmp, bucket, list)
+ if (keys_equal(&cell->key, key))
+ return cell;
+
+ return NULL;
+}
+
+/*
+ * This may block if a new cell needs allocating. You must ensure that
+ * cells will be unlocked even if the calling thread is blocked.
+ *
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
+ */
+int dm_bio_detain(struct bio_prison *prison, struct cell_key *key,
+ struct bio *inmate, struct cell **ref)
+{
+ int r;
+ unsigned long flags;
+ uint32_t hash = hash_key(prison, key);
+ struct cell *uninitialized_var(cell), *cell2 = NULL;
+
+ BUG_ON(hash > prison->nr_buckets);
+
+ spin_lock_irqsave(&prison->lock, flags);
+ cell = __search_bucket(prison->cells + hash, key);
+
+ if (!cell) {
+ /*
+ * Allocate a new cell
+ */
+ spin_unlock_irqrestore(&prison->lock, flags);
+ cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
+ spin_lock_irqsave(&prison->lock, flags);
+
+ /*
+ * We've been unlocked, so we have to double check that
+ * nobody else has inserted this cell in the meantime.
+ */
+ cell = __search_bucket(prison->cells + hash, key);
+
+ if (!cell) {
+ cell = cell2;
+ cell2 = NULL;
+
+ cell->prison = prison;
+ memcpy(&cell->key, key, sizeof(cell->key));
+ cell->holder = inmate;
+ bio_list_init(&cell->bios);
+ hlist_add_head(&cell->list, prison->cells + hash);
+ r = 0;
+
+ } else {
+ mempool_free(cell2, prison->cell_pool);
+ cell2 = NULL;
+ r = 1;
+ bio_list_add(&cell->bios, inmate);
+ }
+
+ } else {
+ r = 1;
+ bio_list_add(&cell->bios, inmate);
+ }
+ spin_unlock_irqrestore(&prison->lock, flags);
+
+ *ref = cell;
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_bio_detain);
+
+/*
+ * @inmates must have been initialised prior to this call
+ */
+static void __cell_release(struct cell *cell, struct bio_list *inmates)
+{
+ struct bio_prison *prison = cell->prison;
+
+ hlist_del(&cell->list);
+
+ if (inmates) {
+ bio_list_add(inmates, cell->holder);
+ bio_list_merge(inmates, &cell->bios);
+ }
+
+ mempool_free(cell, prison->cell_pool);
+}
+
+void dm_cell_release(struct cell *cell, struct bio_list *bios)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release(cell, bios);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL_GPL(dm_cell_release);
+
+/*
+ * There are a couple of places where we put a bio into a cell briefly
+ * before taking it out again. In these situations we know that no other
+ * bio may be in the cell. This function releases the cell, and also does
+ * a sanity check.
+ */
+static void __cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+ hlist_del(&cell->list);
+ BUG_ON(cell->holder != bio);
+ BUG_ON(!bio_list_empty(&cell->bios));
+}
+
+void dm_cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release_singleton(cell, bio);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL_GPL(dm_cell_release_singleton);
+
+/*
+ * Sometimes we don't want the holder, just the additional bios.
+ */
+static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+ struct bio_prison *prison = cell->prison;
+
+ hlist_del(&cell->list);
+ if (inmates)
+ bio_list_merge(inmates, &cell->bios);
+
+ mempool_free(cell, prison->cell_pool);
+}
+
+void dm_cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+ unsigned long flags;
+ struct bio_prison *prison = cell->prison;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release_no_holder(cell, inmates);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL_GPL(dm_cell_release_no_holder);
+
+void dm_cell_error(struct cell *cell)
+{
+ struct bio_prison *prison = cell->prison;
+ struct bio_list bios;
+ struct bio *bio;
+ unsigned long flags;
+
+ bio_list_init(&bios);
+
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release(cell, &bios);
+ spin_unlock_irqrestore(&prison->lock, flags);
+
+ while ((bio = bio_list_pop(&bios)))
+ bio_io_error(bio);
+}
+EXPORT_SYMBOL_GPL(dm_cell_error);
+
+/*----------------------------------------------------------------*/
+
+void dm_ds_init(struct deferred_set *ds)
+{
+ int i;
+
+ spin_lock_init(&ds->lock);
+ ds->current_entry = 0;
+ ds->sweeper = 0;
+ for (i = 0; i < DEFERRED_SET_SIZE; i++) {
+ ds->entries[i].ds = ds;
+ ds->entries[i].count = 0;
+ INIT_LIST_HEAD(&ds->entries[i].work_items);
+ }
+}
+EXPORT_SYMBOL_GPL(dm_ds_init);
+
+struct deferred_entry *dm_ds_inc(struct deferred_set *ds)
+{
+ unsigned long flags;
+ struct deferred_entry *entry;
+
+ spin_lock_irqsave(&ds->lock, flags);
+ entry = ds->entries + ds->current_entry;
+ entry->count++;
+ spin_unlock_irqrestore(&ds->lock, flags);
+
+ return entry;
+}
+EXPORT_SYMBOL_GPL(dm_ds_inc);
+
+static unsigned ds_next(unsigned index)
+{
+ return (index + 1) % DEFERRED_SET_SIZE;
+}
+
+static void __sweep(struct deferred_set *ds, struct list_head *head)
+{
+ while ((ds->sweeper != ds->current_entry) &&
+ !ds->entries[ds->sweeper].count) {
+ list_splice_init(&ds->entries[ds->sweeper].work_items, head);
+ ds->sweeper = ds_next(ds->sweeper);
+ }
+
+ if ((ds->sweeper == ds->current_entry) && !ds->entries[ds->sweeper].count)
+ list_splice_init(&ds->entries[ds->sweeper].work_items, head);
+}
+
+void dm_ds_dec(struct deferred_entry *entry, struct list_head *head)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&entry->ds->lock, flags);
+ BUG_ON(!entry->count);
+ --entry->count;
+ __sweep(entry->ds, head);
+ spin_unlock_irqrestore(&entry->ds->lock, flags);
+}
+EXPORT_SYMBOL_GPL(dm_ds_dec);
+
+/*
+ * Returns 1 if deferred or 0 if no pending items to delay job.
+ */
+int dm_ds_add_work(struct deferred_set *ds, struct list_head *work)
+{
+ int r = 1;
+ unsigned long flags;
+ unsigned next_entry;
+
+ spin_lock_irqsave(&ds->lock, flags);
+ if ((ds->sweeper == ds->current_entry) &&
+ !ds->entries[ds->current_entry].count)
+ r = 0;
+ else {
+ list_add(work, &ds->entries[ds->current_entry].work_items);
+ next_entry = ds_next(ds->current_entry);
+ if (!ds->entries[next_entry].count)
+ ds->current_entry = next_entry;
+ }
+ spin_unlock_irqrestore(&ds->lock, flags);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_ds_add_work);
+
+/*----------------------------------------------------------------*/
Index: linux-2.6/drivers/md/dm-bio-prison.h
===================================================================
--- /dev/null
+++ linux-2.6/drivers/md/dm-bio-prison.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 Red Hat.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_BIO_PRISON_H
+#define DM_BIO_PRISON_H
+
+#include "persistent-data/dm-block-manager.h"
+
+#include <linux/list.h>
+
+/*----------------------------------------------------------------*/
+
+/*
+ * Device identifier
+ */
+typedef uint64_t dm_dev_id;
+
+/*----------------------------------------------------------------*/
+
+/*
+ * Sometimes we can't deal with a bio straight away. We put them in prison
+ * where they can't cause any mischief. Bios are put in a cell identified
+ * by a key, multiple bios can be in the same cell. When the cell is
+ * subsequently unlocked the bios become available.
+ */
+struct bio_prison;
+
+struct cell_key {
+ int virtual;
+ dm_dev_id dev;
+ dm_block_t block;
+};
+
+struct cell {
+ struct hlist_node list;
+ struct bio_prison *prison;
+ struct cell_key key;
+ struct bio *holder;
+ struct bio_list bios;
+};
+
+struct bio_prison {
+ spinlock_t lock;
+ mempool_t *cell_pool;
+
+ unsigned nr_buckets;
+ unsigned hash_mask;
+ struct hlist_head *cells;
+};
+
+/*
+ * @nr_cells should be the number of cells you want in use _concurrently_.
+ * Don't confuse it with the number of distinct keys.
+ */
+struct bio_prison *dm_prison_create(unsigned nr_cells);
+void dm_prison_destroy(struct bio_prison *prison);
+
+/*
+ * This may block if a new cell needs allocating. You must ensure that
+ * cells will be unlocked even if the calling thread is blocked.
+ *
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
+ */
+int dm_bio_detain(struct bio_prison *prison, struct cell_key *key,
+ struct bio *inmate, struct cell **ref);
+void dm_cell_release(struct cell *cell, struct bio_list *bios);
+void dm_cell_release_singleton(struct cell *cell, struct bio *bio);
+void dm_cell_release_no_holder(struct cell *cell, struct bio_list *inmates);
+void dm_cell_error(struct cell *cell);
+
+/*----------------------------------------------------------------*/
+
+/*
+ * We use the deferred set to keep track of pending reads to shared blocks.
+ * We do this to ensure the new mapping caused by a write isn't performed
+ * until these prior reads have completed. Otherwise the insertion of the
+ * new mapping could free the old block that the read bios are mapped to.
+ */
+#define DEFERRED_SET_SIZE 64
+
+struct deferred_set;
+struct deferred_entry {
+ struct deferred_set *ds;
+ unsigned count;
+ struct list_head work_items;
+};
+
+struct deferred_set {
+ spinlock_t lock;
+ unsigned current_entry;
+ unsigned sweeper;
+ struct deferred_entry entries[DEFERRED_SET_SIZE];
+};
+
+void dm_ds_init(struct deferred_set *ds);
+struct deferred_entry *dm_ds_inc(struct deferred_set *ds);
+void dm_ds_dec(struct deferred_entry *entry, struct list_head *head);
+
+/*
+ * Returns 1 if deferred or 0 if no pending items to delay job.
+ */
+int dm_ds_add_work(struct deferred_set *ds, struct list_head *work);
+
+/*----------------------------------------------------------------*/
+
+#endif
Index: linux-2.6/drivers/md/dm-thin-metadata.h
===================================================================
--- linux-2.6.orig/drivers/md/dm-thin-metadata.h
+++ linux-2.6/drivers/md/dm-thin-metadata.h
@@ -7,6 +7,7 @@
#ifndef DM_THIN_METADATA_H
#define DM_THIN_METADATA_H
+#include "dm-bio-prison.h"
#include "persistent-data/dm-block-manager.h"
#define THIN_METADATA_BLOCK_SIZE 4096
@@ -32,11 +33,6 @@ struct dm_pool_metadata;
struct dm_thin_device;
/*
- * Device identifier
- */
-typedef uint64_t dm_dev_id;
-
-/*
* Reopens or creates a new, empty metadata volume.
*/
struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
Index: linux-2.6/drivers/md/dm-thin.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-thin.c
+++ linux-2.6/drivers/md/dm-thin.c
@@ -4,6 +4,7 @@
* This file is released under the GPL.
*/
+#include "dm-bio-prison.h"
#include "dm-thin-metadata.h"
#include <linux/device-mapper.h>
@@ -20,7 +21,6 @@
* Tunable constants
*/
#define ENDIO_HOOK_POOL_SIZE 10240
-#define DEFERRED_SET_SIZE 64
#define MAPPING_POOL_SIZE 1024
#define PRISON_CELLS 1024
#define COMMIT_PERIOD HZ
@@ -98,372 +98,6 @@
/*----------------------------------------------------------------*/
/*
- * Sometimes we can't deal with a bio straight away. We put them in prison
- * where they can't cause any mischief. Bios are put in a cell identified
- * by a key, multiple bios can be in the same cell. When the cell is
- * subsequently unlocked the bios become available.
- */
-struct bio_prison;
-
-struct cell_key {
- int virtual;
- dm_dev_id dev;
- dm_block_t block;
-};
-
-struct cell {
- struct hlist_node list;
- struct bio_prison *prison;
- struct cell_key key;
- struct bio *holder;
- struct bio_list bios;
-};
-
-struct bio_prison {
- spinlock_t lock;
- mempool_t *cell_pool;
-
- unsigned nr_buckets;
- unsigned hash_mask;
- struct hlist_head *cells;
-};
-
-static uint32_t calc_nr_buckets(unsigned nr_cells)
-{
- uint32_t n = 128;
-
- nr_cells /= 4;
- nr_cells = min(nr_cells, 8192u);
-
- while (n < nr_cells)
- n <<= 1;
-
- return n;
-}
-
-/*
- * @nr_cells should be the number of cells you want in use _concurrently_.
- * Don't confuse it with the number of distinct keys.
- */
-static struct bio_prison *prison_create(unsigned nr_cells)
-{
- unsigned i;
- uint32_t nr_buckets = calc_nr_buckets(nr_cells);
- size_t len = sizeof(struct bio_prison) +
- (sizeof(struct hlist_head) * nr_buckets);
- struct bio_prison *prison = kmalloc(len, GFP_KERNEL);
-
- if (!prison)
- return NULL;
-
- spin_lock_init(&prison->lock);
- prison->cell_pool = mempool_create_kmalloc_pool(nr_cells,
- sizeof(struct cell));
- if (!prison->cell_pool) {
- kfree(prison);
- return NULL;
- }
-
- prison->nr_buckets = nr_buckets;
- prison->hash_mask = nr_buckets - 1;
- prison->cells = (struct hlist_head *) (prison + 1);
- for (i = 0; i < nr_buckets; i++)
- INIT_HLIST_HEAD(prison->cells + i);
-
- return prison;
-}
-
-static void prison_destroy(struct bio_prison *prison)
-{
- mempool_destroy(prison->cell_pool);
- kfree(prison);
-}
-
-static uint32_t hash_key(struct bio_prison *prison, struct cell_key *key)
-{
- const unsigned long BIG_PRIME = 4294967291UL;
- uint64_t hash = key->block * BIG_PRIME;
-
- return (uint32_t) (hash & prison->hash_mask);
-}
-
-static int keys_equal(struct cell_key *lhs, struct cell_key *rhs)
-{
- return (lhs->virtual == rhs->virtual) &&
- (lhs->dev == rhs->dev) &&
- (lhs->block == rhs->block);
-}
-
-static struct cell *__search_bucket(struct hlist_head *bucket,
- struct cell_key *key)
-{
- struct cell *cell;
- struct hlist_node *tmp;
-
- hlist_for_each_entry(cell, tmp, bucket, list)
- if (keys_equal(&cell->key, key))
- return cell;
-
- return NULL;
-}
-
-/*
- * This may block if a new cell needs allocating. You must ensure that
- * cells will be unlocked even if the calling thread is blocked.
- *
- * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
- */
-static int bio_detain(struct bio_prison *prison, struct cell_key *key,
- struct bio *inmate, struct cell **ref)
-{
- int r;
- unsigned long flags;
- uint32_t hash = hash_key(prison, key);
- struct cell *uninitialized_var(cell), *cell2 = NULL;
-
- BUG_ON(hash > prison->nr_buckets);
-
- spin_lock_irqsave(&prison->lock, flags);
- cell = __search_bucket(prison->cells + hash, key);
-
- if (!cell) {
- /*
- * Allocate a new cell
- */
- spin_unlock_irqrestore(&prison->lock, flags);
- cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
- spin_lock_irqsave(&prison->lock, flags);
-
- /*
- * We've been unlocked, so we have to double check that
- * nobody else has inserted this cell in the meantime.
- */
- cell = __search_bucket(prison->cells + hash, key);
-
- if (!cell) {
- cell = cell2;
- cell2 = NULL;
-
- cell->prison = prison;
- memcpy(&cell->key, key, sizeof(cell->key));
- cell->holder = inmate;
- bio_list_init(&cell->bios);
- hlist_add_head(&cell->list, prison->cells + hash);
- r = 0;
-
- } else {
- mempool_free(cell2, prison->cell_pool);
- cell2 = NULL;
- r = 1;
- bio_list_add(&cell->bios, inmate);
- }
-
- } else {
- r = 1;
- bio_list_add(&cell->bios, inmate);
- }
- spin_unlock_irqrestore(&prison->lock, flags);
-
- *ref = cell;
- return r;
-}
-
-/*
- * @inmates must have been initialised prior to this call
- */
-static void __cell_release(struct cell *cell, struct bio_list *inmates)
-{
- struct bio_prison *prison = cell->prison;
-
- hlist_del(&cell->list);
-
- if (inmates) {
- bio_list_add(inmates, cell->holder);
- bio_list_merge(inmates, &cell->bios);
- }
-
- mempool_free(cell, prison->cell_pool);
-}
-
-static void cell_release(struct cell *cell, struct bio_list *bios)
-{
- unsigned long flags;
- struct bio_prison *prison = cell->prison;
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release(cell, bios);
- spin_unlock_irqrestore(&prison->lock, flags);
-}
-
-/*
- * There are a couple of places where we put a bio into a cell briefly
- * before taking it out again. In these situations we know that no other
- * bio may be in the cell. This function releases the cell, and also does
- * a sanity check.
- */
-static void __cell_release_singleton(struct cell *cell, struct bio *bio)
-{
- hlist_del(&cell->list);
- BUG_ON(cell->holder != bio);
- BUG_ON(!bio_list_empty(&cell->bios));
-}
-
-static void cell_release_singleton(struct cell *cell, struct bio *bio)
-{
- unsigned long flags;
- struct bio_prison *prison = cell->prison;
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release_singleton(cell, bio);
- spin_unlock_irqrestore(&prison->lock, flags);
-}
-
-/*
- * Sometimes we don't want the holder, just the additional bios.
- */
-static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
-{
- struct bio_prison *prison = cell->prison;
-
- hlist_del(&cell->list);
- if (inmates)
- bio_list_merge(inmates, &cell->bios);
-
- mempool_free(cell, prison->cell_pool);
-}
-
-static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
-{
- unsigned long flags;
- struct bio_prison *prison = cell->prison;
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release_no_holder(cell, inmates);
- spin_unlock_irqrestore(&prison->lock, flags);
-}
-
-static void cell_error(struct cell *cell)
-{
- struct bio_prison *prison = cell->prison;
- struct bio_list bios;
- struct bio *bio;
- unsigned long flags;
-
- bio_list_init(&bios);
-
- spin_lock_irqsave(&prison->lock, flags);
- __cell_release(cell, &bios);
- spin_unlock_irqrestore(&prison->lock, flags);
-
- while ((bio = bio_list_pop(&bios)))
- bio_io_error(bio);
-}
-
-/*----------------------------------------------------------------*/
-
-/*
- * We use the deferred set to keep track of pending reads to shared blocks.
- * We do this to ensure the new mapping caused by a write isn't performed
- * until these prior reads have completed. Otherwise the insertion of the
- * new mapping could free the old block that the read bios are mapped to.
- */
-
-struct deferred_set;
-struct deferred_entry {
- struct deferred_set *ds;
- unsigned count;
- struct list_head work_items;
-};
-
-struct deferred_set {
- spinlock_t lock;
- unsigned current_entry;
- unsigned sweeper;
- struct deferred_entry entries[DEFERRED_SET_SIZE];
-};
-
-static void ds_init(struct deferred_set *ds)
-{
- int i;
-
- spin_lock_init(&ds->lock);
- ds->current_entry = 0;
- ds->sweeper = 0;
- for (i = 0; i < DEFERRED_SET_SIZE; i++) {
- ds->entries[i].ds = ds;
- ds->entries[i].count = 0;
- INIT_LIST_HEAD(&ds->entries[i].work_items);
- }
-}
-
-static struct deferred_entry *ds_inc(struct deferred_set *ds)
-{
- unsigned long flags;
- struct deferred_entry *entry;
-
- spin_lock_irqsave(&ds->lock, flags);
- entry = ds->entries + ds->current_entry;
- entry->count++;
- spin_unlock_irqrestore(&ds->lock, flags);
-
- return entry;
-}
-
-static unsigned ds_next(unsigned index)
-{
- return (index + 1) % DEFERRED_SET_SIZE;
-}
-
-static void __sweep(struct deferred_set *ds, struct list_head *head)
-{
- while ((ds->sweeper != ds->current_entry) &&
- !ds->entries[ds->sweeper].count) {
- list_splice_init(&ds->entries[ds->sweeper].work_items, head);
- ds->sweeper = ds_next(ds->sweeper);
- }
-
- if ((ds->sweeper == ds->current_entry) && !ds->entries[ds->sweeper].count)
- list_splice_init(&ds->entries[ds->sweeper].work_items, head);
-}
-
-static void ds_dec(struct deferred_entry *entry, struct list_head *head)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&entry->ds->lock, flags);
- BUG_ON(!entry->count);
- --entry->count;
- __sweep(entry->ds, head);
- spin_unlock_irqrestore(&entry->ds->lock, flags);
-}
-
-/*
- * Returns 1 if deferred or 0 if no pending items to delay job.
- */
-static int ds_add_work(struct deferred_set *ds, struct list_head *work)
-{
- int r = 1;
- unsigned long flags;
- unsigned next_entry;
-
- spin_lock_irqsave(&ds->lock, flags);
- if ((ds->sweeper == ds->current_entry) &&
- !ds->entries[ds->current_entry].count)
- r = 0;
- else {
- list_add(work, &ds->entries[ds->current_entry].work_items);
- next_entry = ds_next(ds->current_entry);
- if (!ds->entries[next_entry].count)
- ds->current_entry = next_entry;
- }
- spin_unlock_irqrestore(&ds->lock, flags);
-
- return r;
-}
-
-/*----------------------------------------------------------------*/
-
-/*
* Key building.
*/
static void build_data_key(struct dm_thin_device *td,
@@ -816,7 +450,7 @@ static void cell_defer(struct thin_c *tc
unsigned long flags;
spin_lock_irqsave(&pool->lock, flags);
- cell_release(cell, &pool->deferred_bios);
+ dm_cell_release(cell, &pool->deferred_bios);
spin_unlock_irqrestore(&tc->pool->lock, flags);
wake_worker(pool);
@@ -835,7 +469,7 @@ static void cell_defer_except(struct thi
bio_list_init(&bios);
spin_lock_irqsave(&pool->lock, flags);
- cell_release_no_holder(cell, &pool->deferred_bios);
+ dm_cell_release_no_holder(cell, &pool->deferred_bios);
spin_unlock_irqrestore(&pool->lock, flags);
wake_worker(pool);
@@ -852,7 +486,7 @@ static void process_prepared_mapping(str
bio->bi_end_io = m->saved_bi_end_io;
if (m->err) {
- cell_error(m->cell);
+ dm_cell_error(m->cell);
return;
}
@@ -864,7 +498,7 @@ static void process_prepared_mapping(str
r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block);
if (r) {
DMERR("dm_thin_insert_block() failed");
- cell_error(m->cell);
+ dm_cell_error(m->cell);
return;
}
@@ -983,7 +617,7 @@ static void schedule_copy(struct thin_c
m->err = 0;
m->bio = NULL;
- if (!ds_add_work(&pool->shared_read_ds, &m->list))
+ if (!dm_ds_add_work(&pool->shared_read_ds, &m->list))
m->quiesced = 1;
/*
@@ -1014,7 +648,7 @@ static void schedule_copy(struct thin_c
if (r < 0) {
mempool_free(m, pool->mapping_pool);
DMERR("dm_kcopyd_copy() failed");
- cell_error(cell);
+ dm_cell_error(cell);
}
}
}
@@ -1079,7 +713,7 @@ static void schedule_zero(struct thin_c
if (r < 0) {
mempool_free(m, pool->mapping_pool);
DMERR("dm_kcopyd_zero() failed");
- cell_error(cell);
+ dm_cell_error(cell);
}
}
}
@@ -1167,7 +801,7 @@ static void no_space(struct cell *cell)
struct bio_list bios;
bio_list_init(&bios);
- cell_release(cell, &bios);
+ dm_cell_release(cell, &bios);
while ((bio = bio_list_pop(&bios)))
retry_on_resume(bio);
@@ -1184,7 +818,7 @@ static void process_discard(struct thin_
struct new_mapping *m;
build_virtual_key(tc->td, block, &key);
- if (bio_detain(tc->pool->prison, &key, bio, &cell))
+ if (dm_bio_detain(tc->pool->prison, &key, bio, &cell))
return;
r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
@@ -1196,8 +830,8 @@ static void process_discard(struct thin_
* on this block.
*/
build_data_key(tc->td, lookup_result.block, &key2);
- if (bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
- cell_release_singleton(cell, bio);
+ if (dm_bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
+ dm_cell_release_singleton(cell, bio);
break;
}
@@ -1216,7 +850,7 @@ static void process_discard(struct thin_
m->err = 0;
m->bio = bio;
- if (!ds_add_work(&pool->all_io_ds, &m->list)) {
+ if (!dm_ds_add_work(&pool->all_io_ds, &m->list)) {
list_add(&m->list, &pool->prepared_discards);
wake_worker(pool);
}
@@ -1231,8 +865,8 @@ static void process_discard(struct thin_
unsigned remaining = (pool->sectors_per_block - offset) << 9;
bio->bi_size = min(bio->bi_size, remaining);
- cell_release_singleton(cell, bio);
- cell_release_singleton(cell2, bio);
+ dm_cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell2, bio);
remap_and_issue(tc, bio, lookup_result.block);
}
break;
@@ -1241,13 +875,13 @@ static void process_discard(struct thin_
/*
* It isn't provisioned, just forget it.
*/
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
bio_endio(bio, 0);
break;
default:
DMERR("discard: find block unexpectedly returned %d\n", r);
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
bio_io_error(bio);
break;
}
@@ -1274,7 +908,7 @@ static void break_sharing(struct thin_c
default:
DMERR("%s: alloc_data_block() failed, error = %d", __func__, r);
- cell_error(cell);
+ dm_cell_error(cell);
break;
}
}
@@ -1292,7 +926,7 @@ static void process_shared_bio(struct th
* of being broken so we have nothing further to do here.
*/
build_data_key(tc->td, lookup_result->block, &key);
- if (bio_detain(pool->prison, &key, bio, &cell))
+ if (dm_bio_detain(pool->prison, &key, bio, &cell))
return;
if (bio_data_dir(bio) == WRITE)
@@ -1300,9 +934,9 @@ static void process_shared_bio(struct th
else {
struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
- h->shared_read_entry = ds_inc(&pool->shared_read_ds);
+ h->shared_read_entry = dm_ds_inc(&pool->shared_read_ds);
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
remap_and_issue(tc, bio, lookup_result->block);
}
}
@@ -1317,7 +951,7 @@ static void provision_block(struct thin_
* Remap empty bios (flushes) immediately, without provisioning.
*/
if (!bio->bi_size) {
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
remap_and_issue(tc, bio, 0);
return;
}
@@ -1327,7 +961,7 @@ static void provision_block(struct thin_
*/
if (bio_data_dir(bio) == READ) {
zero_fill_bio(bio);
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
bio_endio(bio, 0);
return;
}
@@ -1347,7 +981,7 @@ static void provision_block(struct thin_
default:
DMERR("%s: alloc_data_block() failed, error = %d", __func__, r);
- cell_error(cell);
+ dm_cell_error(cell);
break;
}
}
@@ -1365,7 +999,7 @@ static void process_bio(struct thin_c *t
* being provisioned so we have nothing further to do here.
*/
build_virtual_key(tc->td, block, &key);
- if (bio_detain(tc->pool->prison, &key, bio, &cell))
+ if (dm_bio_detain(tc->pool->prison, &key, bio, &cell))
return;
r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
@@ -1380,7 +1014,7 @@ static void process_bio(struct thin_c *t
* TODO: this will probably have to change when discard goes
* back in.
*/
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
if (lookup_result.shared)
process_shared_bio(tc, bio, block, &lookup_result);
@@ -1390,7 +1024,7 @@ static void process_bio(struct thin_c *t
case -ENODATA:
if (bio_data_dir(bio) == READ && tc->origin_dev) {
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
remap_to_origin_and_issue(tc, bio);
} else
provision_block(tc, bio, block, cell);
@@ -1398,7 +1032,7 @@ static void process_bio(struct thin_c *t
default:
DMERR("dm_thin_find_block() failed, error = %d", r);
- cell_release_singleton(cell, bio);
+ dm_cell_release_singleton(cell, bio);
bio_io_error(bio);
break;
}
@@ -1522,7 +1156,7 @@ static struct endio_hook *thin_hook_bio(
h->tc = tc;
h->shared_read_entry = NULL;
- h->all_io_entry = bio->bi_rw & REQ_DISCARD ? NULL : ds_inc(&pool->all_io_ds);
+ h->all_io_entry = bio->bi_rw & REQ_DISCARD ? NULL : dm_ds_inc(&pool->all_io_ds);
h->overwrite_mapping = NULL;
return h;
@@ -1652,7 +1286,7 @@ static void __pool_destroy(struct pool *
if (dm_pool_metadata_close(pool->pmd) < 0)
DMWARN("%s: dm_pool_metadata_close() failed.", __func__);
- prison_destroy(pool->prison);
+ dm_prison_destroy(pool->prison);
dm_kcopyd_client_destroy(pool->copier);
if (pool->wq)
@@ -1693,7 +1327,7 @@ static struct pool *pool_create(struct m
pool->offset_mask = block_size - 1;
pool->low_water_blocks = 0;
pool_features_init(&pool->pf);
- pool->prison = prison_create(PRISON_CELLS);
+ pool->prison = dm_prison_create(PRISON_CELLS);
if (!pool->prison) {
*error = "Error creating pool's bio prison";
err_p = ERR_PTR(-ENOMEM);
@@ -1729,8 +1363,8 @@ static struct pool *pool_create(struct m
pool->low_water_triggered = 0;
pool->no_free_space = 0;
bio_list_init(&pool->retry_on_resume_list);
- ds_init(&pool->shared_read_ds);
- ds_init(&pool->all_io_ds);
+ dm_ds_init(&pool->shared_read_ds);
+ dm_ds_init(&pool->all_io_ds);
pool->next_mapping = NULL;
pool->mapping_pool =
@@ -1763,7 +1397,7 @@ bad_mapping_pool:
bad_wq:
dm_kcopyd_client_destroy(pool->copier);
bad_kcopyd_client:
- prison_destroy(pool->prison);
+ dm_prison_destroy(pool->prison);
bad_prison:
kfree(pool);
bad_pool:
@@ -2614,7 +2248,7 @@ static int thin_endio(struct dm_target *
if (h->shared_read_entry) {
INIT_LIST_HEAD(&work);
- ds_dec(h->shared_read_entry, &work);
+ dm_ds_dec(h->shared_read_entry, &work);
spin_lock_irqsave(&pool->lock, flags);
list_for_each_entry_safe(m, tmp, &work, list) {
@@ -2627,7 +2261,7 @@ static int thin_endio(struct dm_target *
if (h->all_io_entry) {
INIT_LIST_HEAD(&work);
- ds_dec(h->all_io_entry, &work);
+ dm_ds_dec(h->all_io_entry, &work);
list_for_each_entry_safe(m, tmp, &work, list)
list_add(&m->list, &pool->prepared_discards);
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id
2012-03-02 23:59 [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Mike Snitzer
2012-03-02 23:59 ` [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use Mike Snitzer
@ 2012-03-05 10:29 ` Joe Thornber
2012-03-05 14:08 ` Mike Snitzer
1 sibling, 1 reply; 6+ messages in thread
From: Joe Thornber @ 2012-03-05 10:29 UTC (permalink / raw)
To: Mike Snitzer; +Cc: dm-devel, ejt
This is part of the hsm target development work. Let's keep this in
git for now; there's no point spamming dm-devel with work in progress.
I'm happy to give you write access to my github repo if you like.
Otherwise I can merge from any git repo you wish.
On Fri, Mar 02, 2012 at 06:59:29PM -0500, Mike Snitzer wrote:
> dm_thin_id is too specific to thin devices. Rename to allow for reuse
> by other targets.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id
2012-03-05 10:29 ` [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Joe Thornber
@ 2012-03-05 14:08 ` Mike Snitzer
0 siblings, 0 replies; 6+ messages in thread
From: Mike Snitzer @ 2012-03-05 14:08 UTC (permalink / raw)
To: dm-devel, ejt
On Mon, Mar 05 2012 at 5:29am -0500,
Joe Thornber <thornber@redhat.com> wrote:
> This is part of the hsm target development work. Let's keep this in
> git for now; there's no point spamming dm-devel with work in progress.
> I'm happy to give you write access to my github repo if you like.
> Otherwise I can merge from any git repo you wish.
Sure, dm-devel is just a public list (doubt people who care about DM see
these patches as spam). I didn't see the need for a back channel
exchange, but noted.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-03-05 14:08 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-02 23:59 [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Mike Snitzer
2012-03-02 23:59 ` [PATCH 2/2] dm thin: elevate the bio_prison and deferred_set code to allow for re-use Mike Snitzer
2012-03-03 0:26 ` Alasdair G Kergon
2012-03-03 3:13 ` [PATCH 2/2 v2] " Mike Snitzer
2012-03-05 10:29 ` [PATCH 1/2] dm thin: rename dm_thin_id to more generic dm_dev_id Joe Thornber
2012-03-05 14:08 ` Mike Snitzer
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.