mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
[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>
This commit is contained in:
parent
9d493fa8c9
commit
ca3a931fd3
@ -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);
|
||||
|
@ -10,7 +10,9 @@
|
||||
#define DM_SNAPSHOT_H
|
||||
|
||||
#include "dm.h"
|
||||
#include "dm-bio-list.h"
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct exception_table {
|
||||
uint32_t hash_mask;
|
||||
@ -112,10 +114,20 @@ struct dm_snapshot {
|
||||
struct exception_table pending;
|
||||
struct exception_table complete;
|
||||
|
||||
/*
|
||||
* pe_lock protects all pending_exception operations and access
|
||||
* as well as the snapshot_bios list.
|
||||
*/
|
||||
spinlock_t pe_lock;
|
||||
|
||||
/* The on disk metadata handler */
|
||||
struct exception_store store;
|
||||
|
||||
struct kcopyd_client *kcopyd_client;
|
||||
|
||||
/* Queue of snapshot writes for ksnapd to flush */
|
||||
struct bio_list queued_bios;
|
||||
struct work_struct queued_bios_work;
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user