diff options
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 74 |
1 files changed, 49 insertions, 25 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 8bd77cbd7e45..dc500a6f6232 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -59,6 +59,9 @@ struct dm_snapshot { | |||
59 | struct rw_semaphore lock; | 59 | struct rw_semaphore lock; |
60 | 60 | ||
61 | struct dm_dev *origin; | 61 | struct dm_dev *origin; |
62 | struct dm_dev *cow; | ||
63 | |||
64 | struct dm_target *ti; | ||
62 | 65 | ||
63 | /* List of snapshots per Origin */ | 66 | /* List of snapshots per Origin */ |
64 | struct list_head list; | 67 | struct list_head list; |
@@ -97,6 +100,12 @@ struct dm_snapshot { | |||
97 | struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE]; | 100 | struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE]; |
98 | }; | 101 | }; |
99 | 102 | ||
103 | struct dm_dev *dm_snap_cow(struct dm_snapshot *s) | ||
104 | { | ||
105 | return s->cow; | ||
106 | } | ||
107 | EXPORT_SYMBOL(dm_snap_cow); | ||
108 | |||
100 | static struct workqueue_struct *ksnapd; | 109 | static struct workqueue_struct *ksnapd; |
101 | static void flush_queued_bios(struct work_struct *work); | 110 | static void flush_queued_bios(struct work_struct *work); |
102 | 111 | ||
@@ -558,7 +567,7 @@ static int init_hash_tables(struct dm_snapshot *s) | |||
558 | * Calculate based on the size of the original volume or | 567 | * Calculate based on the size of the original volume or |
559 | * the COW volume... | 568 | * the COW volume... |
560 | */ | 569 | */ |
561 | cow_dev_size = get_dev_size(s->store->cow->bdev); | 570 | cow_dev_size = get_dev_size(s->cow->bdev); |
562 | origin_dev_size = get_dev_size(s->origin->bdev); | 571 | origin_dev_size = get_dev_size(s->origin->bdev); |
563 | max_buckets = calc_max_buckets(); | 572 | max_buckets = calc_max_buckets(); |
564 | 573 | ||
@@ -596,45 +605,55 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
596 | struct dm_snapshot *s; | 605 | struct dm_snapshot *s; |
597 | int i; | 606 | int i; |
598 | int r = -EINVAL; | 607 | int r = -EINVAL; |
599 | char *origin_path; | 608 | char *origin_path, *cow_path; |
600 | struct dm_exception_store *store; | ||
601 | unsigned args_used; | 609 | unsigned args_used; |
602 | 610 | ||
603 | if (argc != 4) { | 611 | if (argc != 4) { |
604 | ti->error = "requires exactly 4 arguments"; | 612 | ti->error = "requires exactly 4 arguments"; |
605 | r = -EINVAL; | 613 | r = -EINVAL; |
606 | goto bad_args; | 614 | goto bad; |
607 | } | 615 | } |
608 | 616 | ||
609 | origin_path = argv[0]; | 617 | origin_path = argv[0]; |
610 | argv++; | 618 | argv++; |
611 | argc--; | 619 | argc--; |
612 | 620 | ||
613 | r = dm_exception_store_create(ti, argc, argv, &args_used, &store); | 621 | s = kmalloc(sizeof(*s), GFP_KERNEL); |
622 | if (!s) { | ||
623 | ti->error = "Cannot allocate snapshot context private " | ||
624 | "structure"; | ||
625 | r = -ENOMEM; | ||
626 | goto bad; | ||
627 | } | ||
628 | |||
629 | cow_path = argv[0]; | ||
630 | argv++; | ||
631 | argc--; | ||
632 | |||
633 | r = dm_get_device(ti, cow_path, 0, 0, | ||
634 | FMODE_READ | FMODE_WRITE, &s->cow); | ||
635 | if (r) { | ||
636 | ti->error = "Cannot get COW device"; | ||
637 | goto bad_cow; | ||
638 | } | ||
639 | |||
640 | r = dm_exception_store_create(ti, argc, argv, s, &args_used, &s->store); | ||
614 | if (r) { | 641 | if (r) { |
615 | ti->error = "Couldn't create exception store"; | 642 | ti->error = "Couldn't create exception store"; |
616 | r = -EINVAL; | 643 | r = -EINVAL; |
617 | goto bad_args; | 644 | goto bad_store; |
618 | } | 645 | } |
619 | 646 | ||
620 | argv += args_used; | 647 | argv += args_used; |
621 | argc -= args_used; | 648 | argc -= args_used; |
622 | 649 | ||
623 | s = kmalloc(sizeof(*s), GFP_KERNEL); | ||
624 | if (!s) { | ||
625 | ti->error = "Cannot allocate snapshot context private " | ||
626 | "structure"; | ||
627 | r = -ENOMEM; | ||
628 | goto bad_snap; | ||
629 | } | ||
630 | |||
631 | r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin); | 650 | r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin); |
632 | if (r) { | 651 | if (r) { |
633 | ti->error = "Cannot get origin device"; | 652 | ti->error = "Cannot get origin device"; |
634 | goto bad_origin; | 653 | goto bad_origin; |
635 | } | 654 | } |
636 | 655 | ||
637 | s->store = store; | 656 | s->ti = ti; |
638 | s->valid = 1; | 657 | s->valid = 1; |
639 | s->active = 0; | 658 | s->active = 0; |
640 | atomic_set(&s->pending_exceptions_count, 0); | 659 | atomic_set(&s->pending_exceptions_count, 0); |
@@ -723,12 +742,15 @@ bad_hash_tables: | |||
723 | dm_put_device(ti, s->origin); | 742 | dm_put_device(ti, s->origin); |
724 | 743 | ||
725 | bad_origin: | 744 | bad_origin: |
726 | kfree(s); | 745 | dm_exception_store_destroy(s->store); |
727 | 746 | ||
728 | bad_snap: | 747 | bad_store: |
729 | dm_exception_store_destroy(store); | 748 | dm_put_device(ti, s->cow); |
730 | 749 | ||
731 | bad_args: | 750 | bad_cow: |
751 | kfree(s); | ||
752 | |||
753 | bad: | ||
732 | return r; | 754 | return r; |
733 | } | 755 | } |
734 | 756 | ||
@@ -777,6 +799,8 @@ static void snapshot_dtr(struct dm_target *ti) | |||
777 | 799 | ||
778 | dm_exception_store_destroy(s->store); | 800 | dm_exception_store_destroy(s->store); |
779 | 801 | ||
802 | dm_put_device(ti, s->cow); | ||
803 | |||
780 | kfree(s); | 804 | kfree(s); |
781 | } | 805 | } |
782 | 806 | ||
@@ -839,7 +863,7 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) | |||
839 | 863 | ||
840 | s->valid = 0; | 864 | s->valid = 0; |
841 | 865 | ||
842 | dm_table_event(s->store->ti->table); | 866 | dm_table_event(s->ti->table); |
843 | } | 867 | } |
844 | 868 | ||
845 | static void get_pending_exception(struct dm_snap_pending_exception *pe) | 869 | static void get_pending_exception(struct dm_snap_pending_exception *pe) |
@@ -977,7 +1001,7 @@ static void start_copy(struct dm_snap_pending_exception *pe) | |||
977 | src.sector = chunk_to_sector(s->store, pe->e.old_chunk); | 1001 | src.sector = chunk_to_sector(s->store, pe->e.old_chunk); |
978 | src.count = min((sector_t)s->store->chunk_size, dev_size - src.sector); | 1002 | src.count = min((sector_t)s->store->chunk_size, dev_size - src.sector); |
979 | 1003 | ||
980 | dest.bdev = s->store->cow->bdev; | 1004 | dest.bdev = s->cow->bdev; |
981 | dest.sector = chunk_to_sector(s->store, pe->e.new_chunk); | 1005 | dest.sector = chunk_to_sector(s->store, pe->e.new_chunk); |
982 | dest.count = src.count; | 1006 | dest.count = src.count; |
983 | 1007 | ||
@@ -1038,7 +1062,7 @@ __find_pending_exception(struct dm_snapshot *s, | |||
1038 | static void remap_exception(struct dm_snapshot *s, struct dm_exception *e, | 1062 | static void remap_exception(struct dm_snapshot *s, struct dm_exception *e, |
1039 | struct bio *bio, chunk_t chunk) | 1063 | struct bio *bio, chunk_t chunk) |
1040 | { | 1064 | { |
1041 | bio->bi_bdev = s->store->cow->bdev; | 1065 | bio->bi_bdev = s->cow->bdev; |
1042 | bio->bi_sector = chunk_to_sector(s->store, | 1066 | bio->bi_sector = chunk_to_sector(s->store, |
1043 | dm_chunk_number(e->new_chunk) + | 1067 | dm_chunk_number(e->new_chunk) + |
1044 | (chunk - e->old_chunk)) + | 1068 | (chunk - e->old_chunk)) + |
@@ -1056,7 +1080,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
1056 | struct dm_snap_pending_exception *pe = NULL; | 1080 | struct dm_snap_pending_exception *pe = NULL; |
1057 | 1081 | ||
1058 | if (unlikely(bio_empty_barrier(bio))) { | 1082 | if (unlikely(bio_empty_barrier(bio))) { |
1059 | bio->bi_bdev = s->store->cow->bdev; | 1083 | bio->bi_bdev = s->cow->bdev; |
1060 | return DM_MAPIO_REMAPPED; | 1084 | return DM_MAPIO_REMAPPED; |
1061 | } | 1085 | } |
1062 | 1086 | ||
@@ -1200,7 +1224,7 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
1200 | * to make private copies if the output is to | 1224 | * to make private copies if the output is to |
1201 | * make sense. | 1225 | * make sense. |
1202 | */ | 1226 | */ |
1203 | DMEMIT("%s", snap->origin->name); | 1227 | DMEMIT("%s %s", snap->origin->name, snap->cow->name); |
1204 | snap->store->type->status(snap->store, type, result + sz, | 1228 | snap->store->type->status(snap->store, type, result + sz, |
1205 | maxlen - sz); | 1229 | maxlen - sz); |
1206 | break; | 1230 | break; |
@@ -1240,7 +1264,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) | |||
1240 | goto next_snapshot; | 1264 | goto next_snapshot; |
1241 | 1265 | ||
1242 | /* Nothing to do if writing beyond end of snapshot */ | 1266 | /* Nothing to do if writing beyond end of snapshot */ |
1243 | if (bio->bi_sector >= dm_table_get_size(snap->store->ti->table)) | 1267 | if (bio->bi_sector >= dm_table_get_size(snap->ti->table)) |
1244 | goto next_snapshot; | 1268 | goto next_snapshot; |
1245 | 1269 | ||
1246 | /* | 1270 | /* |