Commit 3e5cce62 authored by Linus Torvalds's avatar Linus Torvalds

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: tidy local_init
  dm: remove unused flush_all
  dm raid1: separate region_hash interface part1
  dm: mark split bio as cloned
  dm crypt: remove waitqueue
  dm crypt: fix async split
  dm crypt: tidy sector
  dm: remove dm header from targets
  dm: publish array_too_big
  dm exception store: fix misordered writes
  dm exception store: refactor zero_area
  dm snapshot: drop unused last_percent
  dm snapshot: fix primary_pe race
  dm kcopyd: avoid queue shuffle
parents f2e4bd2b 51157b4a
...@@ -34,7 +34,7 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o ...@@ -34,7 +34,7 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_DELAY) += dm-delay.o obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o obj-$(CONFIG_DM_ZERO) += dm-zero.o
quiet_cmd_unroll = UNROLL $@ quiet_cmd_unroll = UNROLL $@
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "dm.h" #include <linux/device-mapper.h>
#define DM_MSG_PREFIX "crypt" #define DM_MSG_PREFIX "crypt"
#define MESG_STR(x) x, sizeof(x) #define MESG_STR(x) x, sizeof(x)
...@@ -56,6 +56,7 @@ struct dm_crypt_io { ...@@ -56,6 +56,7 @@ struct dm_crypt_io {
atomic_t pending; atomic_t pending;
int error; int error;
sector_t sector; sector_t sector;
struct dm_crypt_io *base_io;
}; };
struct dm_crypt_request { struct dm_crypt_request {
...@@ -93,7 +94,6 @@ struct crypt_config { ...@@ -93,7 +94,6 @@ struct crypt_config {
struct workqueue_struct *io_queue; struct workqueue_struct *io_queue;
struct workqueue_struct *crypt_queue; struct workqueue_struct *crypt_queue;
wait_queue_head_t writeq;
/* /*
* crypto related data * crypto related data
...@@ -534,6 +534,7 @@ static struct dm_crypt_io *crypt_io_alloc(struct dm_target *ti, ...@@ -534,6 +534,7 @@ static struct dm_crypt_io *crypt_io_alloc(struct dm_target *ti,
io->base_bio = bio; io->base_bio = bio;
io->sector = sector; io->sector = sector;
io->error = 0; io->error = 0;
io->base_io = NULL;
atomic_set(&io->pending, 0); atomic_set(&io->pending, 0);
return io; return io;
...@@ -547,6 +548,7 @@ static void crypt_inc_pending(struct dm_crypt_io *io) ...@@ -547,6 +548,7 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
/* /*
* One of the bios was finished. Check for completion of * One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer. * the whole request and correctly clean up the buffer.
* If base_io is set, wait for the last fragment to complete.
*/ */
static void crypt_dec_pending(struct dm_crypt_io *io) static void crypt_dec_pending(struct dm_crypt_io *io)
{ {
...@@ -555,7 +557,14 @@ static void crypt_dec_pending(struct dm_crypt_io *io) ...@@ -555,7 +557,14 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
if (!atomic_dec_and_test(&io->pending)) if (!atomic_dec_and_test(&io->pending))
return; return;
bio_endio(io->base_bio, io->error); if (likely(!io->base_io))
bio_endio(io->base_bio, io->error);
else {
if (io->error && !io->base_io->error)
io->base_io->error = io->error;
crypt_dec_pending(io->base_io);
}
mempool_free(io, cc->io_pool); mempool_free(io, cc->io_pool);
} }
...@@ -646,10 +655,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io) ...@@ -646,10 +655,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io)
static void kcryptd_io_write(struct dm_crypt_io *io) static void kcryptd_io_write(struct dm_crypt_io *io)
{ {
struct bio *clone = io->ctx.bio_out; struct bio *clone = io->ctx.bio_out;
struct crypt_config *cc = io->target->private;
generic_make_request(clone); generic_make_request(clone);
wake_up(&cc->writeq);
} }
static void kcryptd_io(struct work_struct *work) static void kcryptd_io(struct work_struct *work)
...@@ -688,7 +694,6 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, ...@@ -688,7 +694,6 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
BUG_ON(io->ctx.idx_out < clone->bi_vcnt); BUG_ON(io->ctx.idx_out < clone->bi_vcnt);
clone->bi_sector = cc->start + io->sector; clone->bi_sector = cc->start + io->sector;
io->sector += bio_sectors(clone);
if (async) if (async)
kcryptd_queue_io(io); kcryptd_queue_io(io);
...@@ -700,16 +705,18 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) ...@@ -700,16 +705,18 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
{ {
struct crypt_config *cc = io->target->private; struct crypt_config *cc = io->target->private;
struct bio *clone; struct bio *clone;
struct dm_crypt_io *new_io;
int crypt_finished; int crypt_finished;
unsigned out_of_pages = 0; unsigned out_of_pages = 0;
unsigned remaining = io->base_bio->bi_size; unsigned remaining = io->base_bio->bi_size;
sector_t sector = io->sector;
int r; int r;
/* /*
* Prevent io from disappearing until this function completes. * Prevent io from disappearing until this function completes.
*/ */
crypt_inc_pending(io); crypt_inc_pending(io);
crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, io->sector); crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, sector);
/* /*
* The allocated buffers can be smaller than the whole bio, * The allocated buffers can be smaller than the whole bio,
...@@ -726,6 +733,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) ...@@ -726,6 +733,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
io->ctx.idx_out = 0; io->ctx.idx_out = 0;
remaining -= clone->bi_size; remaining -= clone->bi_size;
sector += bio_sectors(clone);
crypt_inc_pending(io); crypt_inc_pending(io);
r = crypt_convert(cc, &io->ctx); r = crypt_convert(cc, &io->ctx);
...@@ -741,6 +749,8 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) ...@@ -741,6 +749,8 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
*/ */
if (unlikely(r < 0)) if (unlikely(r < 0))
break; break;
io->sector = sector;
} }
/* /*
...@@ -750,8 +760,33 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) ...@@ -750,8 +760,33 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
if (unlikely(out_of_pages)) if (unlikely(out_of_pages))
congestion_wait(WRITE, HZ/100); congestion_wait(WRITE, HZ/100);
if (unlikely(remaining)) /*
wait_event(cc->writeq, !atomic_read(&io->ctx.pending)); * With async crypto it is unsafe to share the crypto context
* between fragments, so switch to a new dm_crypt_io structure.
*/
if (unlikely(!crypt_finished && remaining)) {
new_io = crypt_io_alloc(io->target, io->base_bio,
sector);
crypt_inc_pending(new_io);
crypt_convert_init(cc, &new_io->ctx, NULL,
io->base_bio, sector);
new_io->ctx.idx_in = io->ctx.idx_in;
new_io->ctx.offset_in = io->ctx.offset_in;
/*
* Fragments after the first use the base_io
* pending count.
*/
if (!io->base_io)
new_io->base_io = io;
else {
new_io->base_io = io->base_io;
crypt_inc_pending(io->base_io);
crypt_dec_pending(io);
}
io = new_io;
}
} }
crypt_dec_pending(io); crypt_dec_pending(io);
...@@ -1078,7 +1113,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1078,7 +1113,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad_crypt_queue; goto bad_crypt_queue;
} }
init_waitqueue_head(&cc->writeq);
ti->private = cc; ti->private = cc;
return 0; return 0;
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "dm.h" #include <linux/device-mapper.h>
#include "dm-bio-list.h" #include "dm-bio-list.h"
#define DM_MSG_PREFIX "delay" #define DM_MSG_PREFIX "delay"
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* This file is released under the GPL. * This file is released under the GPL.
*/ */
#include "dm.h"
#include "dm-snap.h" #include "dm-snap.h"
#include <linux/mm.h> #include <linux/mm.h>
...@@ -104,6 +103,11 @@ struct pstore { ...@@ -104,6 +103,11 @@ struct pstore {
*/ */
void *area; void *area;
/*
* An area of zeros used to clear the next area.
*/
void *zero_area;
/* /*
* Used to keep track of which metadata area the data in * Used to keep track of which metadata area the data in
* 'chunk' refers to. * 'chunk' refers to.
...@@ -149,6 +153,13 @@ static int alloc_area(struct pstore *ps) ...@@ -149,6 +153,13 @@ static int alloc_area(struct pstore *ps)
if (!ps->area) if (!ps->area)
return r; return r;
ps->zero_area = vmalloc(len);
if (!ps->zero_area) {
vfree(ps->area);
return r;
}
memset(ps->zero_area, 0, len);
return 0; return 0;
} }
...@@ -156,6 +167,8 @@ static void free_area(struct pstore *ps) ...@@ -156,6 +167,8 @@ static void free_area(struct pstore *ps)
{ {
vfree(ps->area); vfree(ps->area);
ps->area = NULL; ps->area = NULL;
vfree(ps->zero_area);
ps->zero_area = NULL;
} }
struct mdata_req { struct mdata_req {
...@@ -220,25 +233,41 @@ static chunk_t area_location(struct pstore *ps, chunk_t area) ...@@ -220,25 +233,41 @@ static chunk_t area_location(struct pstore *ps, chunk_t area)
* Read or write a metadata area. Remembering to skip the first * Read or write a metadata area. Remembering to skip the first
* chunk which holds the header. * chunk which holds the header.
*/ */
static int area_io(struct pstore *ps, chunk_t area, int rw) static int area_io(struct pstore *ps, int rw)
{ {
int r; int r;
chunk_t chunk; chunk_t chunk;
chunk = area_location(ps, area); chunk = area_location(ps, ps->current_area);
r = chunk_io(ps, chunk, rw, 0); r = chunk_io(ps, chunk, rw, 0);
if (r) if (r)
return r; return r;
ps->current_area = area;
return 0; return 0;
} }
static int zero_area(struct pstore *ps, chunk_t area) static void zero_memory_area(struct pstore *ps)
{ {
memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
return area_io(ps, area, WRITE); }
static int zero_disk_area(struct pstore *ps, chunk_t area)
{
struct dm_io_region where = {
.bdev = ps->snap->cow->bdev,
.sector = ps->snap->chunk_size * area_location(ps, area),
.count = ps->snap->chunk_size,
};
struct dm_io_request io_req = {
.bi_rw = WRITE,
.mem.type = DM_IO_VMA,
.mem.ptr.vma = ps->zero_area,
.client = ps->io_client,
.notify.fn = NULL,
};
return dm_io(&io_req, 1, &where, NULL);
} }
static int read_header(struct pstore *ps, int *new_snapshot) static int read_header(struct pstore *ps, int *new_snapshot)
...@@ -411,15 +440,14 @@ static int insert_exceptions(struct pstore *ps, int *full) ...@@ -411,15 +440,14 @@ static int insert_exceptions(struct pstore *ps, int *full)
static int read_exceptions(struct pstore *ps) static int read_exceptions(struct pstore *ps)
{ {
chunk_t area;
int r, full = 1; int r, full = 1;
/* /*
* Keeping reading chunks and inserting exceptions until * Keeping reading chunks and inserting exceptions until
* we find a partially full area. * we find a partially full area.
*/ */
for (area = 0; full; area++) { for (ps->current_area = 0; full; ps->current_area++) {
r = area_io(ps, area, READ); r = area_io(ps, READ);
if (r) if (r)
return r; return r;
...@@ -428,6 +456,8 @@ static int read_exceptions(struct pstore *ps) ...@@ -428,6 +456,8 @@ static int read_exceptions(struct pstore *ps)
return r; return r;
} }
ps->current_area--;
return 0; return 0;
} }
...@@ -486,12 +516,13 @@ static int persistent_read_metadata(struct exception_store *store) ...@@ -486,12 +516,13 @@ static int persistent_read_metadata(struct exception_store *store)
return r; return r;
} }
r = zero_area(ps, 0); ps->current_area = 0;
zero_memory_area(ps);
r = zero_disk_area(ps, 0);
if (r) { if (r) {
DMWARN("zero_area(0) failed"); DMWARN("zero_disk_area(0) failed");
return r; return r;
} }
} else { } else {
/* /*
* Sanity checks. * Sanity checks.
...@@ -551,7 +582,6 @@ static void persistent_commit(struct exception_store *store, ...@@ -551,7 +582,6 @@ static void persistent_commit(struct exception_store *store,
void (*callback) (void *, int success), void (*callback) (void *, int success),
void *callback_context) void *callback_context)
{ {
int r;
unsigned int i; unsigned int i;
struct pstore *ps = get_info(store); struct pstore *ps = get_info(store);
struct disk_exception de; struct disk_exception de;
...@@ -572,33 +602,41 @@ static void persistent_commit(struct exception_store *store, ...@@ -572,33 +602,41 @@ static void persistent_commit(struct exception_store *store,
cb->context = callback_context; cb->context = callback_context;
/* /*
* If there are no more exceptions in flight, or we have * If there are exceptions in flight and we have not yet
* filled this metadata area we commit the exceptions to * filled this metadata area there's nothing more to do.
* disk.
*/ */
if (atomic_dec_and_test(&ps->pending_count) || if (!atomic_dec_and_test(&ps->pending_count) &&
(ps->current_committed == ps->exceptions_per_area)) { (ps->current_committed != ps->exceptions_per_area))
r = area_io(ps, ps->current_area, WRITE); return;
if (r)
ps->valid = 0;
/* /*
* Have we completely filled the current area ? * If we completely filled the current area, then wipe the next one.
*/ */
if (ps->current_committed == ps->exceptions_per_area) { if ((ps->current_committed == ps->exceptions_per_area) &&
ps->current_committed = 0; zero_disk_area(ps, ps->current_area + 1))
r = zero_area(ps, ps->current_area + 1); ps->valid = 0;
if (r)
ps->valid = 0;
}
for (i = 0; i < ps->callback_count; i++) { /*
cb = ps->callbacks + i; * Commit exceptions to disk.
cb->callback(cb->context, r == 0 ? 1 : 0); */
} if (ps->valid && area_io(ps, WRITE))
ps->valid = 0;
ps->callback_count = 0; /*
* Advance to the next area if this one is full.
*/
if (ps->current_committed == ps->exceptions_per_area) {
ps->current_committed = 0;
ps->current_area++;
zero_memory_area(ps);
} }
for (i = 0; i < ps->callback_count; i++) {
cb = ps->callbacks + i;
cb->callback(cb->context, ps->valid);
}
ps->callback_count = 0;
} }
static void persistent_drop(struct exception_store *store) static void persistent_drop(struct exception_store *store)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* This file is released under the GPL. * This file is released under the GPL.
*/ */
#include "dm.h" #include <linux/device-mapper.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/mempool.h> #include <linux/mempool.h>
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/device-mapper.h>
#include <linux/dm-kcopyd.h> #include <linux/dm-kcopyd.h>
#include "dm.h" #include "dm.h"
...@@ -268,6 +269,17 @@ static void push(struct list_head *jobs, struct kcopyd_job *job) ...@@ -268,6 +269,17 @@ static void push(struct list_head *jobs, struct kcopyd_job *job)
spin_unlock_irqrestore(&kc->job_lock, flags); spin_unlock_irqrestore(&kc->job_lock, flags);
} }
static void push_head(struct list_head *jobs, struct kcopyd_job *job)
{
unsigned long flags;
struct dm_kcopyd_client *kc = job->kc;
spin_lock_irqsave(&kc->job_lock, flags);
list_add(&job->list, jobs);
spin_unlock_irqrestore(&kc->job_lock, flags);
}
/* /*
* These three functions process 1 item from the corresponding * These three functions process 1 item from the corresponding
* job list. * job list.
...@@ -398,7 +410,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc, ...@@ -398,7 +410,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
* We couldn't service this job ATM, so * We couldn't service this job ATM, so
* push this job back onto the list. * push this job back onto the list.
*/ */
push(jobs, job); push_head(jobs, job);
break; break;
} }
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
*/ */
#include "dm.h" #include "dm.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device-mapper.h>
#define DM_MSG_PREFIX "linear" #define DM_MSG_PREFIX "linear"
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/dm-io.h> #include <linux/dm-io.h>
#include <linux/dm-dirty-log.h> #include <linux/dm-dirty-log.h>
#include "dm.h" #include <linux/device-mapper.h>
#define DM_MSG_PREFIX "dirty region log" #define DM_MSG_PREFIX "dirty region log"
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
* This file is released under the GPL. * This file is released under the GPL.
*/ */
#include "dm.h" #include <linux/device-mapper.h>
#include "dm-path-selector.h" #include "dm-path-selector.h"
#include "dm-bio-list.h" #include "dm-bio-list.h"
#include "dm-bio-record.h" #include "dm-bio-record.h"
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
* Path selector registration. * Path selector registration.
*/ */
#include "dm.h" #include <linux/device-mapper.h>
#include "dm-path-selector.h" #include "dm-path-selector.h"
#include <linux/slab.h> #include <linux/slab.h>
......
This diff is collapsed.
This diff is collapsed.
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
* Round-robin path selector. * Round-robin path selector.
*/ */
#include "dm.h" #include <linux/device-mapper.h>
#include "dm-path-selector.h" #include "dm-path-selector.h"
#include <linux/slab.h> #include <linux/slab.h>
......
...@@ -600,7 +600,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -600,7 +600,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
s->valid = 1; s->valid = 1;
s->active = 0; s->active = 0;
s->last_percent = 0;
init_rwsem(&s->lock); init_rwsem(&s->lock);
spin_lock_init(&s->pe_lock); spin_lock_init(&s->pe_lock);
s->ti = ti; s->ti = ti;
...@@ -824,8 +823,10 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe) ...@@ -824,8 +823,10 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
* the bios for the original write to the origin. * the bios for the original write to the origin.
*/ */
if (primary_pe && if (primary_pe &&
atomic_dec_and_test(&primary_pe->ref_count)) atomic_dec_and_test(&primary_pe->ref_count)) {
origin_bios = bio_list_get(&primary_pe->origin_bios); origin_bios = bio_list_get(&primary_pe->origin_bios);
free_pending_exception(primary_pe);
}
/* /*
* Free the pe if it's not linked to an origin write or if * Free the pe if it's not linked to an origin write or if
...@@ -834,12 +835,6 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe) ...@@ -834,12 +835,6 @@ static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
if (!primary_pe || primary_pe != pe) if (!primary_pe || primary_pe != pe)
free_pending_exception(pe); free_pending_exception(pe);
/*
* Free the primary pe if nothing references it.
*/
if (primary_pe && !atomic_read(&primary_pe->ref_count))
free_pending_exception(primary_pe);
return origin_bios; return origin_bios;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#ifndef DM_SNAPSHOT_H #ifndef DM_SNAPSHOT_H
#define DM_SNAPSHOT_H #define DM_SNAPSHOT_H
#include "dm.h" #include <linux/device-mapper.h>
#include "dm-bio-list.h" #include "dm-bio-list.h"
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -158,9 +158,6 @@ struct dm_snapshot { ...@@ -158,9 +158,6 @@ struct dm_snapshot {
/* Used for display of table */ /* Used for display of table */
char type; char type;
/* The last percentage we notified */
int last_percent;
mempool_t *pending_pool; mempool_t *pending_pool;
struct exception_table pending; struct exception_table pending;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This file is released under the GPL. * This file is released under the GPL.
*/ */
#include "dm.h" #include <linux/device-mapper.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -60,8 +60,8 @@ static inline struct stripe_c *alloc_context(unsigned int stripes) ...@@ -60,8 +60,8 @@ static inline struct stripe_c *alloc_context(unsigned int stripes)
{ {
size_t len; size_t len;
if (array_too_big(sizeof(struct stripe_c), sizeof(struct stripe), if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
stripes)) stripes))
return NULL; return NULL;
len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes); len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This file is released under the GPL. * This file is released under the GPL.
*/ */
#include "dm.h" #include <linux/device-mapper.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
......
...@@ -76,7 +76,6 @@ union map_info *dm_get_mapinfo(struct bio *bio) ...@@ -76,7 +76,6 @@ union map_info *dm_get_mapinfo(struct bio *bio)
*/ */
struct dm_wq_req { struct dm_wq_req {
enum { enum {
DM_WQ_FLUSH_ALL,
DM_WQ_FLUSH_DEFERRED, DM_WQ_FLUSH_DEFERRED,
} type; } type;
struct work_struct work; struct work_struct work;
...@@ -151,40 +150,40 @@ static struct kmem_cache *_tio_cache; ...@@ -151,40 +150,40 @@ static struct kmem_cache *_tio_cache;
static int __init local_init(void) static int __init local_init(void)
{ {
int r; int r = -ENOMEM;
/* allocate a slab for the dm_ios */ /* allocate a slab for the dm_ios */
_io_cache = KMEM_CACHE(dm_io, 0); _io_cache = KMEM_CACHE(dm_io, 0);
if (!_io_cache) if (!_io_cache)
return -ENOMEM; return r;
/* allocate a slab for the target ios */ /* allocate a slab for the target ios */
_tio_cache = KMEM_CACHE(dm_target_io, 0); _tio_cache = KMEM_CACHE(dm_target_io, 0);
if (!_tio_cache) { if (!_tio_cache)
kmem_cache_destroy(_io_cache); goto out_free_io_cache;
return -ENOMEM;
}
r = dm_uevent_init(); r = dm_uevent_init();
if (r) { if (r)
kmem_cache_destroy(_tio_cache); goto out_free_tio_cache;
kmem_cache_destroy(_io_cache);
return r;
}
_major = major; _major = major;
r = register_blkdev(_major, _name); r = register_blkdev(_major, _name);
if (r < 0) { if (r < 0)
kmem_cache_destroy(_tio_cache); goto out_uevent_exit;
kmem_cache_destroy(_io_cache);
dm_uevent_exit();
return r;
}
if (!_major) if (!_major)
_major = r; _major = r;
return 0; return 0;
out_uevent_exit:
dm_uevent_exit();
out_free_tio_cache:
kmem_cache_destroy(_tio_cache);
out_free_io_cache:
kmem_cache_destroy(_io_cache);
return r;
} }
static void local_exit(void) static void local_exit(void)
...@@ -669,6 +668,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector, ...@@ -669,6 +668,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
clone->bi_size = to_bytes(len); clone->bi_size = to_bytes(len);
clone->bi_io_vec->bv_offset = offset; clone->bi_io_vec->bv_offset = offset;
clone->bi_io_vec->bv_len = clone->bi_size; clone->bi_io_vec->bv_len = clone->bi_size;
clone->bi_flags |= 1 << BIO_CLONED;
return clone; return clone;
} }
...@@ -1394,9 +1394,6 @@ static void dm_wq_work(struct work_struct *work) ...@@ -1394,9 +1394,6 @@ static void dm_wq_work(struct work_struct *work)
down_write(&md->io_lock); down_write(&md->io_lock);
switch (req->type) { switch (req->type) {
case DM_WQ_FLUSH_ALL:
__merge_pushback_list(md);
/* pass through */
case DM_WQ_FLUSH_DEFERRED: case DM_WQ_FLUSH_DEFERRED:
__flush_deferred_io(md); __flush_deferred_io(md);
break; break;
...@@ -1526,7 +1523,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) ...@@ -1526,7 +1523,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
if (!md->suspended_bdev) { if (!md->suspended_bdev) {
DMWARN("bdget failed in dm_suspend"); DMWARN("bdget failed in dm_suspend");
r = -ENOMEM; r = -ENOMEM;
goto flush_and_out; goto out;
} }
/* /*
...@@ -1577,14 +1574,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) ...@@ -1577,14 +1574,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
set_bit(DMF_SUSPENDED, &md->flags); set_bit(DMF_SUSPENDED, &md->flags);
flush_and_out:
if (r && noflush)
/*
* Because there may be already I/Os in the pushback list,
* flush them before return.
*/
dm_queue_flush(md, DM_WQ_FLUSH_ALL, NULL);
out: out:
if (r && md->suspended_bdev) { if (r && md->suspended_bdev) {
bdput(md->suspended_bdev); bdput(md->suspended_bdev);
......
...@@ -62,15 +62,6 @@ void dm_put_target_type(struct target_type *t); ...@@ -62,15 +62,6 @@ void dm_put_target_type(struct target_type *t);
int dm_target_iterate(void (*iter_func)(struct target_type *tt, int dm_target_iterate(void (*iter_func)(struct target_type *tt,
void *param), void *param); void *param), void *param);
/*-----------------------------------------------------------------
* Useful inlines.
*---------------------------------------------------------------*/
static inline int array_too_big(unsigned long fixed, unsigned long obj,
unsigned long num)
{
return (num > (ULONG_MAX - fixed) / obj);
}
int dm_split_args(int *argc, char ***argvp, char *input); int dm_split_args(int *argc, char ***argvp, char *input);
/* /*
......
...@@ -354,6 +354,9 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size); ...@@ -354,6 +354,9 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
*/ */
#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz)) #define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
#define dm_array_too_big(fixed, obj, num) \
((num) > (UINT_MAX - (fixed)) / (obj))
static inline sector_t to_sector(unsigned long n) static inline sector_t to_sector(unsigned long n)
{ {
return (n >> SECTOR_SHIFT); return (n >> SECTOR_SHIFT);
......
/*
* Copyright (C) 2003 Sistina Software Limited.
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
*
* Device-Mapper dirty region hash interface.
*
* This file is released under the GPL.
*/
#ifndef DM_REGION_HASH_H
#define DM_REGION_HASH_H
#include <linux/dm-dirty-log.h>
/*-----------------------------------------------------------------
* Region hash
*----------------------------------------------------------------*/
struct dm_region_hash;
struct dm_region;
/*
* States a region can have.
*/
enum dm_rh_region_states {
DM_RH_CLEAN = 0x01, /* No writes in flight. */
DM_RH_DIRTY = 0x02, /* Writes in flight. */
DM_RH_NOSYNC = 0x04, /* Out of sync. */
DM_RH_RECOVERING = 0x08, /* Under resynchronization. */
};
/*
* Region hash create/destroy.
*/
struct bio_list;
struct dm_region_hash *dm_region_hash_create(
void *context, void (*dispatch_bios)(void *context,
struct bio_list *bios),
void (*wakeup_workers)(void *context),
void (*wakeup_all_recovery_waiters)(void *context),
sector_t target_begin, unsigned max_recovery,
struct dm_dirty_log *log, uint32_t region_size,
region_t nr_regions);
void dm_region_hash_destroy(struct dm_region_hash *rh);
struct dm_dirty_log *dm_rh_dirty_log(struct dm_region_hash *rh);
/*
* Conversion functions.
*/
region_t dm_rh_bio_to_region(struct dm_region_hash *rh, struct bio *bio);
sector_t dm_rh_region_to_sector(struct dm_region_hash *rh, region_t region);
void *dm_rh_region_context(struct dm_region *reg);
/*
* Get region size and key (ie. number of the region).
*/
sector_t dm_rh_get_region_size(struct dm_region_hash *rh);
region_t dm_rh_get_region_key(struct dm_region *reg);
/*
* Get/set/update region state (and dirty log).
*
*/
int dm_rh_get_state(struct dm_region_hash *rh, region_t region, int may_block);
void dm_rh_set_state(struct dm_region_hash *rh, region_t region,
enum dm_rh_region_states state, int may_block);
/* Non-zero errors_handled leaves the state of the region NOSYNC */
void dm_rh_update_states(struct dm_region_hash *rh, int errors_handled);
/* Flush the region hash and dirty log. */
int dm_rh_flush(struct dm_region_hash *rh);
/* Inc/dec pending count on regions. */
void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios);
void dm_rh_dec(struct dm_region_hash *rh, region_t region);
/* Delay bios on regions. */
void dm_rh_delay(struct dm_region_hash *rh, struct bio *bio);
void dm_rh_mark_nosync(struct dm_region_hash *rh,
struct bio *bio, unsigned done, int error);
/*
* Region recovery control.
*/
/* Prepare some regions for recovery by starting to quiesce them. */
void dm_rh_recovery_prepare(struct dm_region_hash *rh);
/* Try fetching a quiesced region for recovery. */
struct dm_region *dm_rh_recovery_start(struct dm_region_hash *rh);
/* Report recovery end on a region. */
void dm_rh_recovery_end(struct dm_region *reg, int error);
/* Returns number of regions with recovery work outstanding. */
int dm_rh_recovery_in_flight(struct dm_region_hash *rh);
/* Start/stop recovery. */
void dm_rh_start_recovery(struct dm_region_hash *rh);
void dm_rh_stop_recovery(struct dm_region_hash *rh);
#endif /* DM_REGION_HASH_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment