From eb7e206a73a4fae5b93ffcdf96640675f7a72a73 Mon Sep 17 00:00:00 2001 From: Zdenek Kabelac Date: Wed, 29 May 2013 12:44:54 +0200 Subject: [PATCH] snapshot: add cow_max_extents Add more precise calculation of the maximum usable snapshot size. Using only percentage fails for small size of snapshot and extents. --- WHATS_NEW | 1 + lib/metadata/metadata-exported.h | 1 + lib/metadata/snapshot_manip.c | 40 +++++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 256adece0..c7eb82a99 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.99 - =================================== + Add cow_max_extents() to calc extents for 100% origin coverage. For creation of snapshot require size for at least 3 chunks. Fix lvresize --use-policies of VALID but 100% full snapshot. Do not accept size parameters bigger then 16EiB. diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index f698b33a2..7ef4220ff 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -717,6 +717,7 @@ int lv_is_virtual_origin(const struct logical_volume *lv); int lv_is_cow(const struct logical_volume *lv); int lv_is_merging_origin(const struct logical_volume *origin); int lv_is_merging_cow(const struct logical_volume *snapshot); +uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size); int lv_is_cow_covering_origin(const struct logical_volume *lv); /* Test if given LV is visible from user's perspective */ diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c index a7f57a617..c3d111225 100644 --- a/lib/metadata/snapshot_manip.c +++ b/lib/metadata/snapshot_manip.c @@ -31,11 +31,45 @@ int lv_is_cow(const struct logical_volume *lv) return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0; } +static uint64_t _cow_max_size(uint64_t origin_size, uint32_t chunk_size) +{ + /* Snapshot disk layout: + * COW is divided into chunks + * 1st. chunk is reserved for header + * 2nd. chunk is the 1st. metadata chunk + * 3rd. chunk is the 1st. data chunk + */ + + /* Size of metadata for snapshot in sectors */ + uint64_t mdata_size = ((origin_size + chunk_size - 1) / chunk_size * 16 + 511) >> SECTOR_SHIFT; + + /* Sum all chunks - header + metadata size + origin size (aligned on chunk boundary) */ + uint64_t size = chunk_size + + ((mdata_size + chunk_size - 1) & ~(uint64_t)(chunk_size - 1)) + + ((origin_size + chunk_size - 1) & ~(uint64_t)(chunk_size - 1)); + + /* Does not overflow since size is in sectors (9 bits) */ + return size; +} + +uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size) +{ + uint64_t size = _cow_max_size(origin->size, chunk_size); + uint32_t extent_size = origin->vg->extent_size; + + if (size % extent_size) + size += extent_size - size % extent_size; + + if (size > UINT32_MAX) + size = UINT32_MAX; /* Origin is too big for 100% snapshot anyway */ + + return (uint32_t) (size / extent_size); +} + int lv_is_cow_covering_origin(const struct logical_volume *lv) { - /* TODO: we need less then 1% of origin size, depends on chunk size */ - return lv_is_cow(lv) ? - (origin_from_cow(lv)->size * UINT64_C(101) <= lv->size * UINT64_C(100)) : 0; + return lv_is_cow(lv) && + (lv->size >= _cow_max_size(origin_from_cow(lv)->size, find_cow(lv)->chunk_size)); } int lv_is_visible(const struct logical_volume *lv) -- 2.43.5