Introduce find_shared_cow() and lv_is_shared_cow() wrappers. Also relocates some functions within snapshot_manip.c so that the code is organized more logically. Signed-off-by: Mike Snitzer --- lib/activate/dev_manager.c | 11 +-- lib/metadata/metadata-exported.h | 3 lib/metadata/snapshot_manip.c | 130 ++++++++++++++++++++++++--------------- lib/report/report.c | 8 +- tools/lvresize.c | 3 5 files changed, 96 insertions(+), 59 deletions(-) Index: LVM2.2.02.73/lib/activate/dev_manager.c =================================================================== --- LVM2.2.02.73.orig/lib/activate/dev_manager.c 2010-09-10 19:15:10.000000000 +0200 +++ LVM2.2.02.73/lib/activate/dev_manager.c 2010-09-10 19:15:15.000000000 +0200 @@ -1386,8 +1386,8 @@ static int _add_origin_target_to_dtree(s } 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, + find_shared_cow(lv)->exception_store, + find_shared_cow(lv)->chunk_size, n, snapids)) return_0; } else { @@ -1436,7 +1436,7 @@ static int _add_snapshot_target_to_dtree return 0; } - if (snap_seg->status & SNAPSHOT_SHARED) + if (lv_is_shared_cow(lv)) return 1; if (!(origin_dlid = build_dm_uuid(dm->mem, snap_seg->origin->lvid.s, "real"))) @@ -1582,7 +1582,8 @@ static int _add_segment_to_dtree(struct return 0; } if (lv_is_multisnap_origin(seg->lv)) { - if (!_add_new_lv_to_dtree(dm, dtree, seg->lv->shared_snapshot->cow, seg->lv, "cow")) + if (!_add_new_lv_to_dtree(dm, dtree, + find_shared_cow(seg->lv)->cow, seg->lv, "cow")) return_0; } else if (lv_is_merging_origin(seg->lv)) { if (!_add_new_lv_to_dtree(dm, dtree, @@ -1667,7 +1668,7 @@ static int _add_new_lv_to_dtree(struct d } } - if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_SHARED && !layer) + if (lv_is_shared_cow(lv) && !layer) return 1; if (!identity_lv) Index: LVM2.2.02.73/lib/metadata/metadata-exported.h =================================================================== --- LVM2.2.02.73.orig/lib/metadata/metadata-exported.h 2010-09-10 19:15:09.000000000 +0200 +++ LVM2.2.02.73/lib/metadata/metadata-exported.h 2010-09-10 19:15:15.000000000 +0200 @@ -729,6 +729,7 @@ int lv_is_merging_origin(const struct lo int lv_is_merging_cow(const struct logical_volume *snapshot); int lv_is_multisnap_origin(const struct logical_volume *lv); int lv_is_multisnap_cow(const struct logical_volume *lv); +int lv_is_shared_cow(const struct logical_volume *lv); /* Test if given LV is visible from user's perspective */ int lv_is_visible(const struct logical_volume *lv); @@ -737,6 +738,8 @@ int pv_is_in_vg(struct volume_group *vg, struct lv_segment *find_merging_cow(const struct logical_volume *origin); +struct lv_segment *find_shared_cow(const struct logical_volume *origin); + /* Given a cow LV, return return the snapshot lv_segment that uses it */ struct lv_segment *find_cow(const struct logical_volume *lv); Index: LVM2.2.02.73/lib/metadata/snapshot_manip.c =================================================================== --- LVM2.2.02.73.orig/lib/metadata/snapshot_manip.c 2010-09-10 19:15:09.000000000 +0200 +++ LVM2.2.02.73/lib/metadata/snapshot_manip.c 2010-09-10 19:15:15.000000000 +0200 @@ -31,17 +31,6 @@ int lv_is_cow(const struct logical_volum return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0; } -int lv_is_multisnap_origin(const struct logical_volume *lv) -{ - return lv_is_origin(lv) && lv->shared_snapshot; -} - -int lv_is_multisnap_cow(const struct logical_volume *lv) -{ - struct lv_segment *seg = first_seg(lv); - return seg && seg_is_virtual(seg) && seg->origin; -} - int lv_is_visible(const struct logical_volume *lv) { if (lv->status & SNAPSHOT) @@ -84,6 +73,31 @@ int lv_is_merging_cow(const struct logic return (find_cow(snapshot)->status & MERGING) ? 1 : 0; } +int lv_is_multisnap_origin(const struct logical_volume *origin) +{ + return (origin->shared_snapshot) ? 1 : 0; +} + +struct lv_segment *find_shared_cow(const struct logical_volume *origin) +{ + if (!lv_is_multisnap_origin(origin)) + return NULL; + + return origin->shared_snapshot; +} + +int lv_is_shared_cow(const struct logical_volume *lv) +{ + return lv_is_cow(lv) && (find_cow(lv)->status & SNAPSHOT_SHARED); +} + +/* Is LV a snapshot that is using a shared cow? */ +int lv_is_multisnap_cow(const struct logical_volume *lv) +{ + struct lv_segment *seg = first_seg(lv); + return seg && seg_is_virtual(seg) && seg->origin; +} + /* Given a cow LV, return the snapshot lv_segment that uses it */ struct lv_segment *find_cow(const struct logical_volume *lv) { @@ -96,6 +110,44 @@ struct logical_volume *origin_from_cow(c return lv->snapshot->origin; } +void init_snapshot_merge(struct lv_segment *cow_seg, + struct logical_volume *origin) +{ + /* + * Even though lv_is_visible(cow_seg->lv) returns 0, + * the cow_seg->lv (name: snapshotX) is _not_ hidden; + * this is part of the lvm2 snapshot fiction. Must + * clear VISIBLE_LV directly (lv_set_visible can't) + * - cow_seg->lv->status is used to control whether 'lv' + * (with user provided snapshot LV name) is visible + * - this also enables vg_validate() to succeed with + * merge metadata (cow_seg->lv is now "internal") + */ + cow_seg->lv->status &= ~VISIBLE_LV; + cow_seg->status |= MERGING; + origin->snapshot = cow_seg; + origin->status |= MERGING; +} + +void clear_snapshot_merge(struct logical_volume *origin) +{ + /* clear merge attributes */ + origin->snapshot->status &= ~MERGING; + origin->snapshot = NULL; + origin->status &= ~MERGING; +} + +static void init_shared_snapshot(struct lv_segment *cow_seg, + struct logical_volume *origin) +{ + origin->shared_snapshot = cow_seg; +} + +static void clear_shared_snapshot(struct logical_volume *origin) +{ + origin->shared_snapshot = NULL; +} + int init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin, struct logical_volume *cow, const char *exception_store, uint32_t chunk_size, int merge) @@ -129,12 +181,11 @@ int init_snapshot_seg(struct lv_segment init_snapshot_merge(seg, origin); if (seg->status & SNAPSHOT_SHARED) { - if (!origin->shared_snapshot) { - origin->shared_snapshot = seg; - } else { - log_err("Origin '%s' has already a shared snapshot.", origin->name); + if (lv_is_multisnap_origin(origin)) { + log_err("Origin '%s' already has a shared snapshot.", origin->name); return_0; } + init_shared_snapshot(seg, origin); } dm_list_add(&origin->snapshot_segs, &seg->origin_list); @@ -142,33 +193,6 @@ int init_snapshot_seg(struct lv_segment return 1; } -void init_snapshot_merge(struct lv_segment *cow_seg, - struct logical_volume *origin) -{ - /* - * Even though lv_is_visible(cow_seg->lv) returns 0, - * the cow_seg->lv (name: snapshotX) is _not_ hidden; - * this is part of the lvm2 snapshot fiction. Must - * clear VISIBLE_LV directly (lv_set_visible can't) - * - cow_seg->lv->status is used to control whether 'lv' - * (with user provided snapshot LV name) is visible - * - this also enables vg_validate() to succeed with - * merge metadata (cow_seg->lv is now "internal") - */ - cow_seg->lv->status &= ~VISIBLE_LV; - cow_seg->status |= MERGING; - origin->snapshot = cow_seg; - origin->status |= MERGING; -} - -void clear_snapshot_merge(struct logical_volume *origin) -{ - /* clear merge attributes */ - origin->snapshot->status &= ~MERGING; - origin->snapshot = NULL; - origin->status &= ~MERGING; -} - int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow, union lvid *lvid, uint32_t extent_count, const char *exception_store, @@ -190,8 +214,8 @@ int vg_add_snapshot(struct logical_volum return 0; } - if (snapshot_flags & SNAPSHOT_SHARED && origin->shared_snapshot) { - log_error("Origin has already a shared snapshot."); + if (snapshot_flags & SNAPSHOT_SHARED && lv_is_multisnap_origin(origin)) { + log_error("Origin already has a shared snapshot."); return 0; } @@ -215,8 +239,11 @@ int vg_remove_snapshot(struct logical_vo int preload_origin = 0; struct logical_volume *origin = origin_from_cow(cow); - dm_list_del(&cow->snapshot->origin_list); - origin->origin_count--; + /* safety net, purely to catch potential future bugs */ + if (origin == cow) { + log_error("Attempt to remove a snapshot which is the origin!?"); + return 0; + } if (find_merging_cow(origin) == find_cow(cow)) { clear_snapshot_merge(origin); @@ -237,8 +264,15 @@ int vg_remove_snapshot(struct logical_vo } } - if (cow->snapshot->origin->shared_snapshot == cow->snapshot) - cow->snapshot->origin->shared_snapshot = NULL; + if (find_shared_cow(origin) == find_cow(cow)) + clear_shared_snapshot(origin); + + /* + * adjust associations and attributes after using + * wrappers which may require them (e.g. find_*_cow) + */ + dm_list_del(&cow->snapshot->origin_list); + origin->origin_count--; if (!lv_remove(cow->snapshot->lv)) { log_error("Failed to remove internal snapshot LV %s", Index: LVM2.2.02.73/lib/report/report.c =================================================================== --- LVM2.2.02.73.orig/lib/report/report.c 2010-09-10 19:15:09.000000000 +0200 +++ LVM2.2.02.73/lib/report/report.c 2010-09-10 19:15:15.000000000 +0200 @@ -383,8 +383,8 @@ static int _lvstatus_disp(struct dm_repo repstr[5] = '-'; } - if (lv_is_cow(lv) && lv->snapshot->status & SNAPSHOT_SHARED) - lv = lv->snapshot->origin; + if (lv_is_shared_cow(lv)) + lv = origin_from_cow(lv); else if (lv_is_multisnap_cow(lv)) lv = first_seg(lv)->origin; else @@ -1110,8 +1110,8 @@ report_empty: return 1; } - if (lv->snapshot->status & SNAPSHOT_SHARED) - lv = lv->snapshot->origin; + if (lv_is_shared_cow(lv)) + lv = origin_from_cow(lv); if (!lv_info(lv->vg->cmd, lv, 0, &info, 0, 0) || !info.exists) goto report_empty; Index: LVM2.2.02.73/tools/lvresize.c =================================================================== --- LVM2.2.02.73.orig/tools/lvresize.c 2010-09-10 19:15:09.000000000 +0200 +++ LVM2.2.02.73/tools/lvresize.c 2010-09-10 19:15:15.000000000 +0200 @@ -578,8 +578,7 @@ static int _lvresize(struct cmd_context return ECMD_FAILED; } } - if (lp->resize == LV_REDUCE && - lv_is_cow(lv) && lv->snapshot->status & SNAPSHOT_SHARED) { + if (lp->resize == LV_REDUCE && lv_is_shared_cow(lv)) { log_error("Shared snapshot cannot be reduced."); return ECMD_FAILED; }