On activate, add the list of snapshot ids to the target line. This patch causes that in-store list of snapshot ids is synchronized with the list in the metadata. If the crash happens immediatelly after creating a snapshot (and before committing it to the metadata) or immediatelly after committing deteled snapshot but before sending the delete message, the metadata and shared store becomes desynchronized. This patch adds the list of snapshot its to the table line so that it becomes resynchronized again on activation. Note the hack in libdm/ioctl/libdm-iface.c. If we leave it as it is, dm would attempt to reload the origin device (because of changed table) and deadlock. So, the hack causes that for multisnapshot devices, the tables are always considered equal regardless of parameters. Signed-off-by: Mikulas Patocka --- lib/activate/dev_manager.c | 29 ++++++++++++++++++++++++++++- libdm/ioctl/libdm-iface.c | 2 +- libdm/libdevmapper.h | 4 +++- libdm/libdm-deptree.c | 33 ++++++++++++++++++++++++--------- 4 files changed, 56 insertions(+), 12 deletions(-) Index: LVM2.2.02.73/lib/activate/dev_manager.c =================================================================== --- LVM2.2.02.73.orig/lib/activate/dev_manager.c 2010-09-10 18:54:31.000000000 +0200 +++ LVM2.2.02.73/lib/activate/dev_manager.c 2010-09-10 18:54:49.000000000 +0200 @@ -1344,6 +1344,9 @@ static int _add_origin_target_to_dtree(s return_0; if (lv_is_multisnap_origin(lv)) { + unsigned n; + const char **snapids; + struct lv_list *lvl; /* * Using origin uuid so info-by-uuid -cow cleanup works. * An origin with a shared snapshot store will only ever @@ -1351,10 +1354,34 @@ static int _add_origin_target_to_dtree(s */ if (!(cow_dlid = build_dm_uuid(dm->mem, lv->lvid.s, "cow"))) return_0; + n = 0; + dm_list_iterate_items(lvl, &lv->vg->lvs) { + struct logical_volume *snap_l = lvl->lv; + struct lv_segment *snap_s; + if (lv_is_multisnap_cow(snap_l) && + (snap_s = first_seg(snap_l)) && + snap_s->origin == lv) + n++; + } + snapids = dm_pool_alloc(dm->mem, n * sizeof(const char *)); + if (!snapids) { + log_error("Out of memory."); + return_0; + } + n = 0; + dm_list_iterate_items(lvl, &lv->vg->lvs) { + struct logical_volume *snap_l = lvl->lv; + struct lv_segment *snap_s; + if (lv_is_multisnap_cow(snap_l) && + (snap_s = first_seg(snap_l)) && + snap_s->origin == lv) + snapids[n++] = snap_s->snapid; + } if (!dm_tree_node_add_snapshot_shared_target(dnode, lv->size, real_dlid, cow_dlid, lv->shared_snapshot->exception_store, - lv->shared_snapshot->chunk_size)) + lv->shared_snapshot->chunk_size, + n, snapids)) return_0; } else { if (!dm_tree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid)) Index: LVM2.2.02.73/libdm/libdevmapper.h =================================================================== --- LVM2.2.02.73.orig/libdm/libdevmapper.h 2010-09-10 18:32:55.000000000 +0200 +++ LVM2.2.02.73/libdm/libdevmapper.h 2010-09-10 18:54:49.000000000 +0200 @@ -414,7 +414,9 @@ int dm_tree_node_add_snapshot_shared_tar const char *origin_uuid, const char *cow_uuid, const char *exception_store, - uint32_t chunk_size); + uint32_t chunk_size, + unsigned n_snapids, + const char **snapids); int dm_tree_node_add_snapshot_shared_snap_target(struct dm_tree_node *node, uint64_t size, const char *origin_uuid, Index: LVM2.2.02.73/libdm/libdm-deptree.c =================================================================== --- LVM2.2.02.73.orig/libdm/libdm-deptree.c 2010-09-10 18:54:31.000000000 +0200 +++ LVM2.2.02.73/libdm/libdm-deptree.c 2010-09-10 18:54:49.000000000 +0200 @@ -113,6 +113,9 @@ struct load_segment { struct dm_tree_node *merge; /* Snapshot */ const char *snapid; /* Shared snapshot */ + unsigned n_snapids; /* Shared origin */ + const char **snapids; /* Shared origin */ + struct dm_tree_node *log; /* Mirror + Replicator */ uint32_t region_size; /* Mirror */ unsigned clustered; /* Mirror */ @@ -1667,6 +1670,7 @@ static int _emit_segment_line(struct dm_ int pos = 0; int r; char originbuf[DM_FORMAT_DEV_BUFSIZE], cowbuf[DM_FORMAT_DEV_BUFSIZE]; + unsigned i; switch(seg->type) { case SEG_ERROR: @@ -1714,8 +1718,11 @@ static int _emit_segment_line(struct dm_ return_0; if (!_build_dev_string(cowbuf, sizeof(cowbuf), seg->cow)) return_0; - EMIT_PARAMS(pos, "%s %s %d 0 %s 0", originbuf, cowbuf, - seg->chunk_size, seg->exception_store); + EMIT_PARAMS(pos, "%s %s %d 1 sync-snapshots %s 0 %u", + originbuf, cowbuf, seg->chunk_size, + seg->exception_store, seg->n_snapids); + for (i = 0; i < seg->n_snapids; i++) + EMIT_PARAMS(pos, " %s", seg->snapids[i]); break; case SEG_SNAPSHOT_SHARED_SNAP: if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin)) @@ -2035,7 +2042,9 @@ static int _add_snapshot_target(struct d const char *merge_uuid, unsigned seg_type, const char *exception_store, - uint32_t chunk_size) + uint32_t chunk_size, + unsigned n_snapids, + const char **snapids) { struct load_segment *seg; struct dm_tree_node *origin_node, *cow_node, *merge_node; @@ -2085,6 +2094,9 @@ static int _add_snapshot_target(struct d } } + seg->n_snapids = n_snapids; + seg->snapids = snapids; + return 1; } @@ -2096,9 +2108,9 @@ int dm_tree_node_add_snapshot_target(str const char *exception_store, uint32_t chunk_size) { - return _add_snapshot_target(node, size, origin_uuid, cow_uuid, - NULL, SEG_SNAPSHOT, exception_store, - chunk_size); + return _add_snapshot_target(node, size, origin_uuid, cow_uuid, NULL, + SEG_SNAPSHOT, exception_store, chunk_size, + 0, NULL); } int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node, @@ -2110,7 +2122,7 @@ int dm_tree_node_add_snapshot_merge_targ { return _add_snapshot_target(node, size, origin_uuid, cow_uuid, merge_uuid, SEG_SNAPSHOT_MERGE, "P", - chunk_size); + chunk_size, 0, NULL); } int dm_tree_node_add_snapshot_shared_target(struct dm_tree_node *node, @@ -2118,10 +2130,13 @@ int dm_tree_node_add_snapshot_shared_tar const char *origin_uuid, const char *cow_uuid, const char *exception_store, - uint32_t chunk_size) + uint32_t chunk_size, + unsigned n_snapids, + const char **snapids) { return _add_snapshot_target(node, size, origin_uuid, cow_uuid, NULL, - SEG_SNAPSHOT_SHARED, exception_store, chunk_size); + SEG_SNAPSHOT_SHARED, exception_store, chunk_size, + n_snapids, snapids); } int dm_tree_node_add_snapshot_shared_snap_target(struct dm_tree_node *node, Index: LVM2.2.02.73/libdm/ioctl/libdm-iface.c =================================================================== --- LVM2.2.02.73.orig/libdm/ioctl/libdm-iface.c 2010-08-18 15:11:57.000000000 +0200 +++ LVM2.2.02.73/libdm/ioctl/libdm-iface.c 2010-09-10 18:54:49.000000000 +0200 @@ -1809,7 +1809,7 @@ static int _reload_with_suppression_v4(s if ((t1->start != t2->start) || (t1->length != t2->length) || (strcmp(t1->type, t2->type)) || - (strcmp(t1->params, t2->params))) + (strcmp(t1->params, t2->params) && strcmp(t1->type, "multisnapshot"))) goto no_match; t1 = t1->next; t2 = t2->next;