[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:
committed by
Linus Torvalds
parent
9d493fa8c9
commit
ca3a931fd3
@@ -39,6 +39,9 @@
|
|||||||
*/
|
*/
|
||||||
#define SNAPSHOT_PAGES 256
|
#define SNAPSHOT_PAGES 256
|
||||||
|
|
||||||
|
struct workqueue_struct *ksnapd;
|
||||||
|
static void flush_queued_bios(void *data);
|
||||||
|
|
||||||
struct pending_exception {
|
struct pending_exception {
|
||||||
struct exception e;
|
struct exception e;
|
||||||
|
|
||||||
@@ -488,6 +491,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|||||||
s->active = 0;
|
s->active = 0;
|
||||||
s->last_percent = 0;
|
s->last_percent = 0;
|
||||||
init_rwsem(&s->lock);
|
init_rwsem(&s->lock);
|
||||||
|
spin_lock_init(&s->pe_lock);
|
||||||
s->table = ti->table;
|
s->table = ti->table;
|
||||||
|
|
||||||
/* Allocate hash table for COW data */
|
/* 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;
|
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 */
|
/* Add snapshot to the list of snapshots for this origin */
|
||||||
/* Exceptions aren't triggered till snapshot_resume() is called */
|
/* Exceptions aren't triggered till snapshot_resume() is called */
|
||||||
if (register_snapshot(s)) {
|
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;
|
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
|
||||||
|
|
||||||
|
flush_workqueue(ksnapd);
|
||||||
|
|
||||||
/* Prevent further origin writes from using this snapshot. */
|
/* Prevent further origin writes from using this snapshot. */
|
||||||
/* After this returns there can be no new kcopyd jobs. */
|
/* After this returns there can be no new kcopyd jobs. */
|
||||||
unregister_snapshot(s);
|
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.
|
* Error a list of buffers.
|
||||||
*/
|
*/
|
||||||
@@ -1240,8 +1262,17 @@ static int __init dm_snapshot_init(void)
|
|||||||
goto bad5;
|
goto bad5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ksnapd = create_singlethread_workqueue("ksnapd");
|
||||||
|
if (!ksnapd) {
|
||||||
|
DMERR("Failed to create ksnapd workqueue.");
|
||||||
|
r = -ENOMEM;
|
||||||
|
goto bad6;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
bad6:
|
||||||
|
mempool_destroy(pending_pool);
|
||||||
bad5:
|
bad5:
|
||||||
kmem_cache_destroy(pending_cache);
|
kmem_cache_destroy(pending_cache);
|
||||||
bad4:
|
bad4:
|
||||||
@@ -1259,6 +1290,8 @@ static void __exit dm_snapshot_exit(void)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
destroy_workqueue(ksnapd);
|
||||||
|
|
||||||
r = dm_unregister_target(&snapshot_target);
|
r = dm_unregister_target(&snapshot_target);
|
||||||
if (r)
|
if (r)
|
||||||
DMERR("snapshot unregister failed %d", r);
|
DMERR("snapshot unregister failed %d", r);
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
#define DM_SNAPSHOT_H
|
#define DM_SNAPSHOT_H
|
||||||
|
|
||||||
#include "dm.h"
|
#include "dm.h"
|
||||||
|
#include "dm-bio-list.h"
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
struct exception_table {
|
struct exception_table {
|
||||||
uint32_t hash_mask;
|
uint32_t hash_mask;
|
||||||
@@ -112,10 +114,20 @@ struct dm_snapshot {
|
|||||||
struct exception_table pending;
|
struct exception_table pending;
|
||||||
struct exception_table complete;
|
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 */
|
/* The on disk metadata handler */
|
||||||
struct exception_store store;
|
struct exception_store store;
|
||||||
|
|
||||||
struct kcopyd_client *kcopyd_client;
|
struct kcopyd_client *kcopyd_client;
|
||||||
|
|
||||||
|
/* Queue of snapshot writes for ksnapd to flush */
|
||||||
|
struct bio_list queued_bios;
|
||||||
|
struct work_struct queued_bios_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user