diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-snap.c | 33 | ||||
-rw-r--r-- | drivers/md/dm-snap.h | 12 |
2 files changed, 45 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 @@ | |||
39 | */ | 39 | */ |
40 | #define SNAPSHOT_PAGES 256 | 40 | #define SNAPSHOT_PAGES 256 |
41 | 41 | ||
42 | struct workqueue_struct *ksnapd; | ||
43 | static void flush_queued_bios(void *data); | ||
44 | |||
42 | struct pending_exception { | 45 | struct pending_exception { |
43 | struct exception e; | 46 | struct exception e; |
44 | 47 | ||
@@ -488,6 +491,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
488 | s->active = 0; | 491 | s->active = 0; |
489 | s->last_percent = 0; | 492 | s->last_percent = 0; |
490 | init_rwsem(&s->lock); | 493 | init_rwsem(&s->lock); |
494 | spin_lock_init(&s->pe_lock); | ||
491 | s->table = ti->table; | 495 | s->table = ti->table; |
492 | 496 | ||
493 | /* Allocate hash table for COW data */ | 497 | /* Allocate hash table for COW data */ |
@@ -523,6 +527,9 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
523 | goto bad6; | 527 | goto bad6; |
524 | } | 528 | } |
525 | 529 | ||
530 | bio_list_init(&s->queued_bios); | ||
531 | INIT_WORK(&s->queued_bios_work, flush_queued_bios, s); | ||
532 | |||
526 | /* Add snapshot to the list of snapshots for this origin */ | 533 | /* Add snapshot to the list of snapshots for this origin */ |
527 | /* Exceptions aren't triggered till snapshot_resume() is called */ | 534 | /* Exceptions aren't triggered till snapshot_resume() is called */ |
528 | if (register_snapshot(s)) { | 535 | if (register_snapshot(s)) { |
@@ -561,6 +568,8 @@ static void snapshot_dtr(struct dm_target *ti) | |||
561 | { | 568 | { |
562 | struct dm_snapshot *s = (struct dm_snapshot *) ti->private; | 569 | struct dm_snapshot *s = (struct dm_snapshot *) ti->private; |
563 | 570 | ||
571 | flush_workqueue(ksnapd); | ||
572 | |||
564 | /* Prevent further origin writes from using this snapshot. */ | 573 | /* Prevent further origin writes from using this snapshot. */ |
565 | /* After this returns there can be no new kcopyd jobs. */ | 574 | /* After this returns there can be no new kcopyd jobs. */ |
566 | unregister_snapshot(s); | 575 | unregister_snapshot(s); |
@@ -594,6 +603,19 @@ static void flush_bios(struct bio *bio) | |||
594 | } | 603 | } |
595 | } | 604 | } |
596 | 605 | ||
606 | static void flush_queued_bios(void *data) | ||
607 | { | ||
608 | struct dm_snapshot *s = (struct dm_snapshot *) data; | ||
609 | struct bio *queued_bios; | ||
610 | unsigned long flags; | ||
611 | |||
612 | spin_lock_irqsave(&s->pe_lock, flags); | ||
613 | queued_bios = bio_list_get(&s->queued_bios); | ||
614 | spin_unlock_irqrestore(&s->pe_lock, flags); | ||
615 | |||
616 | flush_bios(queued_bios); | ||
617 | } | ||
618 | |||
597 | /* | 619 | /* |
598 | * Error a list of buffers. | 620 | * Error a list of buffers. |
599 | */ | 621 | */ |
@@ -1240,8 +1262,17 @@ static int __init dm_snapshot_init(void) | |||
1240 | goto bad5; | 1262 | goto bad5; |
1241 | } | 1263 | } |
1242 | 1264 | ||
1265 | ksnapd = create_singlethread_workqueue("ksnapd"); | ||
1266 | if (!ksnapd) { | ||
1267 | DMERR("Failed to create ksnapd workqueue."); | ||
1268 | r = -ENOMEM; | ||
1269 | goto bad6; | ||
1270 | } | ||
1271 | |||
1243 | return 0; | 1272 | return 0; |
1244 | 1273 | ||
1274 | bad6: | ||
1275 | mempool_destroy(pending_pool); | ||
1245 | bad5: | 1276 | bad5: |
1246 | kmem_cache_destroy(pending_cache); | 1277 | kmem_cache_destroy(pending_cache); |
1247 | bad4: | 1278 | bad4: |
@@ -1259,6 +1290,8 @@ static void __exit dm_snapshot_exit(void) | |||
1259 | { | 1290 | { |
1260 | int r; | 1291 | int r; |
1261 | 1292 | ||
1293 | destroy_workqueue(ksnapd); | ||
1294 | |||
1262 | r = dm_unregister_target(&snapshot_target); | 1295 | r = dm_unregister_target(&snapshot_target); |
1263 | if (r) | 1296 | if (r) |
1264 | DMERR("snapshot unregister failed %d", r); | 1297 | DMERR("snapshot unregister failed %d", r); |
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h index 221eb8880c80..15fa2ae6cdc2 100644 --- a/drivers/md/dm-snap.h +++ b/drivers/md/dm-snap.h | |||
@@ -10,7 +10,9 @@ | |||
10 | #define DM_SNAPSHOT_H | 10 | #define DM_SNAPSHOT_H |
11 | 11 | ||
12 | #include "dm.h" | 12 | #include "dm.h" |
13 | #include "dm-bio-list.h" | ||
13 | #include <linux/blkdev.h> | 14 | #include <linux/blkdev.h> |
15 | #include <linux/workqueue.h> | ||
14 | 16 | ||
15 | struct exception_table { | 17 | struct exception_table { |
16 | uint32_t hash_mask; | 18 | uint32_t hash_mask; |
@@ -112,10 +114,20 @@ struct dm_snapshot { | |||
112 | struct exception_table pending; | 114 | struct exception_table pending; |
113 | struct exception_table complete; | 115 | struct exception_table complete; |
114 | 116 | ||
117 | /* | ||
118 | * pe_lock protects all pending_exception operations and access | ||
119 | * as well as the snapshot_bios list. | ||
120 | */ | ||
121 | spinlock_t pe_lock; | ||
122 | |||
115 | /* The on disk metadata handler */ | 123 | /* The on disk metadata handler */ |
116 | struct exception_store store; | 124 | struct exception_store store; |
117 | 125 | ||
118 | struct kcopyd_client *kcopyd_client; | 126 | struct kcopyd_client *kcopyd_client; |
127 | |||
128 | /* Queue of snapshot writes for ksnapd to flush */ | ||
129 | struct bio_list queued_bios; | ||
130 | struct work_struct queued_bios_work; | ||
119 | }; | 131 | }; |
120 | 132 | ||
121 | /* | 133 | /* |