mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
metadata: add direct size limit
Previously the size was limited by checking if the old and new copies of the metadata overlapped. This generally limited the size to about half of the total space, but it could be larger given the size differences between old and new. Now add a direct check to limit the size to half the space.
This commit is contained in:
parent
91c7e66f2b
commit
6be1efd13d
@ -682,6 +682,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
struct pv_list *pvl;
|
struct pv_list *pvl;
|
||||||
uint64_t old_start = 0, old_last = 0, old_size = 0, old_wrap = 0;
|
uint64_t old_start = 0, old_last = 0, old_size = 0, old_wrap = 0;
|
||||||
uint64_t new_start = 0, new_last = 0, new_size = 0, new_wrap = 0;
|
uint64_t new_start = 0, new_last = 0, new_size = 0, new_wrap = 0;
|
||||||
|
uint64_t max_size;
|
||||||
char *new_buf = NULL;
|
char *new_buf = NULL;
|
||||||
int overlap;
|
int overlap;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
@ -721,6 +722,27 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The max size of a single copy of text metadata.
|
||||||
|
*
|
||||||
|
* The space available for all text metadata is the size of the
|
||||||
|
* metadata area (mdah->size) minus the sector used for the header.
|
||||||
|
* Two copies of the text metadata must fit in this space, so it is
|
||||||
|
* divided in two. This result is then reduced by 512 because any
|
||||||
|
* single copy of metadata is rounded to begin on a sector boundary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
max_size = ((mdah->size - MDA_HEADER_SIZE) / 2) - 512;
|
||||||
|
|
||||||
|
if (new_size > max_size) {
|
||||||
|
log_error("VG %s metadata on %s (%llu bytes) exceeds maximum metadata size (%llu bytes)",
|
||||||
|
vg->name,
|
||||||
|
dev_name(mdac->area.dev),
|
||||||
|
(unsigned long long)new_size,
|
||||||
|
(unsigned long long)max_size);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rlocn_old is the current, committed, raw_locn data in slot0 on disk.
|
* rlocn_old is the current, committed, raw_locn data in slot0 on disk.
|
||||||
*
|
*
|
||||||
@ -816,6 +838,13 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
/*
|
/*
|
||||||
* If the new copy of the metadata would overlap the old copy of the
|
* If the new copy of the metadata would overlap the old copy of the
|
||||||
* metadata, it means that the circular metadata buffer is full.
|
* metadata, it means that the circular metadata buffer is full.
|
||||||
|
*
|
||||||
|
* Given the max_size restriction above, two copies of metadata should
|
||||||
|
* never overlap, so these overlap checks should not be technically
|
||||||
|
* necessary, and a failure should not occur here. It's left as a
|
||||||
|
* sanity check. For some unknown time, lvm did not enforce a
|
||||||
|
* max_size, but rather detected the too-large failure by checking for
|
||||||
|
* overlap between old and new.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (new_wrap && old_wrap) {
|
if (new_wrap && old_wrap) {
|
||||||
@ -1540,16 +1569,15 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
|||||||
/*
|
/*
|
||||||
* Report remaining space on the assumption that a single copy
|
* Report remaining space on the assumption that a single copy
|
||||||
* of metadata can be as large as half the total metadata
|
* of metadata can be as large as half the total metadata
|
||||||
* space. Technically, it can be larger if the other copy is
|
* space, minus 512 because each copy is rounded to begin
|
||||||
* less. 511 is subtracted from max because the next copy can
|
* on a sector boundary.
|
||||||
* be rounded up by 511 bytes to start on a sector boundary.
|
|
||||||
*/
|
*/
|
||||||
uint64_t max = (mdah->size - MDA_HEADER_SIZE - 511) / 2;
|
uint64_t max_size = ((mdah->size - MDA_HEADER_SIZE) / 2) - 512;
|
||||||
|
|
||||||
if (rlocn->size >= max)
|
if (rlocn->size >= max_size)
|
||||||
*mda_free_sectors = UINT64_C(0);
|
*mda_free_sectors = UINT64_C(0);
|
||||||
else
|
else
|
||||||
*mda_free_sectors = (max - rlocn->size) >> SECTOR_SHIFT;
|
*mda_free_sectors = (max_size - rlocn->size) >> SECTOR_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user