diff options
author | Alasdair G Kergon <agk@redhat.com> | 2006-10-03 01:15:30 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-03 08:04:14 -0700 |
commit | ca3a931fd33b841cbcc5932f8eac7c43e0909242 (patch) | |
tree | bc8aa7ace1a5e528cbfabc01b17a2016c55bc448 /drivers/md/dm-snap.c | |
parent | 9d493fa8c943ed4ec6e42b7ebfd8f0b7657d54f8 (diff) | |
download | lwn-ca3a931fd33b841cbcc5932f8eac7c43e0909242.tar.gz lwn-ca3a931fd33b841cbcc5932f8eac7c43e0909242.zip |
[PATCH] dm snapshot: add workqueue
Add a workqueue so that I/O can be queued up to be flushed from a separate
thread (e.g. if local interrupts are disabled).
A new per-snapshot spinlock pe_lock is introduced to protect queued_bios.
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index d92980177b5c..1c6485404db4 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -39,6 +39,9 @@ */ #define SNAPSHOT_PAGES 256 +struct workqueue_struct *ksnapd; +static void flush_queued_bios(void *data); + struct pending_exception { struct exception e; @@ -488,6 +491,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) s->active = 0; s->last_percent = 0; init_rwsem(&s->lock); + spin_lock_init(&s->pe_lock); s->table = ti->table; /* Allocate hash table for COW data */ @@ -523,6 +527,9 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad6; } + bio_list_init(&s->queued_bios); + INIT_WORK(&s->queued_bios_work, flush_queued_bios, s); + /* Add snapshot to the list of snapshots for this origin */ /* Exceptions aren't triggered till snapshot_resume() is called */ if (register_snapshot(s)) { @@ -561,6 +568,8 @@ static void snapshot_dtr(struct dm_target *ti) { struct dm_snapshot *s = (struct dm_snapshot *) ti->private; + flush_workqueue(ksnapd); + /* Prevent further origin writes from using this snapshot. */ /* After this returns there can be no new kcopyd jobs. */ unregister_snapshot(s); @@ -594,6 +603,19 @@ static void flush_bios(struct bio *bio) } } +static void flush_queued_bios(void *data) +{ + struct dm_snapshot *s = (struct dm_snapshot *) data; + struct bio *queued_bios; + unsigned long flags; + + spin_lock_irqsave(&s->pe_lock, flags); + queued_bios = bio_list_get(&s->queued_bios); + spin_unlock_irqrestore(&s->pe_lock, flags); + + flush_bios(queued_bios); +} + /* * Error a list of buffers. */ @@ -1240,8 +1262,17 @@ static int __init dm_snapshot_init(void) goto bad5; } + ksnapd = create_singlethread_workqueue("ksnapd"); + if (!ksnapd) { + DMERR("Failed to create ksnapd workqueue."); + r = -ENOMEM; + goto bad6; + } + return 0; + bad6: + mempool_destroy(pending_pool); bad5: kmem_cache_destroy(pending_cache); bad4: @@ -1259,6 +1290,8 @@ static void __exit dm_snapshot_exit(void) { int r; + destroy_workqueue(ksnapd); + r = dm_unregister_target(&snapshot_target); if (r) DMERR("snapshot unregister failed %d", r); |