1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-02 01:18:26 +03:00

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.
This commit is contained in:
Zdenek Kabelac 2013-05-29 12:44:54 +02:00
parent 59962d8d3e
commit eb7e206a73
3 changed files with 39 additions and 3 deletions

View File

@ -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.

View File

@ -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 */

View File

@ -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)