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

format_text: Change metadata alignment from 512 to 4096.

If there is sufficient space in the metadata area, align the next
metadata to a disk offset that is a multiple of 4096 bytes and
don't write it circularly.  If it doesn't all fit at the end
of the metadata area, go back to the start and write it all there
contiguously.

If there is insufficient space to use the new stricter rules, revert to
the original behaviour, aligning on 512-byte boundaries wrapping around
the circular buffer as required.
This commit is contained in:
Alasdair G Kergon 2017-12-12 20:57:36 +00:00
parent 643df602c7
commit 78ffa44fc5
3 changed files with 57 additions and 15 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.177 - Version 2.02.177 -
==================================== ====================================
Change text format metadata alignment from 512 to 4096 bytes.
When writing metadata, consistently skip mdas marked as failed. When writing metadata, consistently skip mdas marked as failed.
Refactor and adjust text format metadata alignment calculation. Refactor and adjust text format metadata alignment calculation.
Fix python3 path in lvmdbusd to use value detected by configure. Fix python3 path in lvmdbusd to use value detected by configure.

View File

@ -488,7 +488,7 @@ static uint64_t _next_rlocn_offset(struct raw_locn *rlocn, struct mda_header *md
if (!rlocn) if (!rlocn)
/* Find an empty slot */ /* Find an empty slot */
/* FIXME Assumes only one VG per mdah for now */ /* FIXME Assumes only one VG per mdah for now */
return alignment; return ALIGN_ABSOLUTE(MDA_HEADER_SIZE, mdac_area_start, alignment);
/* First find the end of the old metadata */ /* First find the end of the old metadata */
old_end = rlocn->offset + rlocn->size; old_end = rlocn->offset + rlocn->size;
@ -501,10 +501,21 @@ static uint64_t _next_rlocn_offset(struct raw_locn *rlocn, struct mda_header *md
/* Calculate new start position relative to start of buffer rounded up to absolute alignment */ /* Calculate new start position relative to start of buffer rounded up to absolute alignment */
new_start_offset = ALIGN_ABSOLUTE(old_end, mdac_area_start, alignment); new_start_offset = ALIGN_ABSOLUTE(old_end, mdac_area_start, alignment);
/* If new location is beyond the end of the buffer, wrap around back to start of circular buffer */ /* If new location is beyond the end of the buffer, return to start of circular buffer and realign */
if (new_start_offset >= mdah->size) if (new_start_offset >= mdah->size) {
new_start_offset -= (mdah->size - MDA_HEADER_SIZE); /* If the start of the buffer is occupied, move past it */
if (old_wrapped || rlocn->offset == MDA_HEADER_SIZE)
new_start_offset = old_end;
else
new_start_offset = MDA_HEADER_SIZE;
new_start_offset = ALIGN_ABSOLUTE(new_start_offset, mdac_area_start, alignment);
}
/*
* Note that we don't check here that this location isn't inside the existing metadata.
* If it is, then it means this value of alignment cannot be used.
*/
return new_start_offset; return new_start_offset;
} }
@ -640,6 +651,15 @@ static int _metadata_fits_into_buffer(struct mda_context *mdac, struct mda_heade
uint64_t old_start = 0; /* The start of the existing metadata */ uint64_t old_start = 0; /* The start of the existing metadata */
uint64_t new_start = mdac->rlocn.offset; /* The proposed start of the new metadata */ uint64_t new_start = mdac->rlocn.offset; /* The proposed start of the new metadata */
/*
* If the (aligned) start of the new metadata is already beyond the end
* of the buffer this means it didn't fit with the given alignment.
* (The caller has already tried to wrap it back to the start
* of the buffer but the alignment pushed it back outside.)
*/
if (new_start >= mdah->size)
return_0;
/* Does the total amount of metadata, old and new, fit inside the buffer? */ /* Does the total amount of metadata, old and new, fit inside the buffer? */
if (MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size) if (MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)
return_0; return_0;
@ -654,7 +674,7 @@ static int _metadata_fits_into_buffer(struct mda_context *mdac, struct mda_heade
old_wrap = old_end - mdah->size; old_wrap = old_end - mdah->size;
} }
new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE : (mdac->rlocn.offset + mdac->rlocn.size); new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE : new_start + mdac->rlocn.size;
/* If both wrap around, there's necessarily overlap */ /* If both wrap around, there's necessarily overlap */
if (new_wrap && old_wrap) if (new_wrap && old_wrap)
@ -668,6 +688,10 @@ static int _metadata_fits_into_buffer(struct mda_context *mdac, struct mda_heade
if ((new_wrap || old_wrap) && (new_end > old_start)) if ((new_wrap || old_wrap) && (new_end > old_start))
return_0; return_0;
/* If there's no wrap, check there's no overlap */
if (!new_wrap && !old_wrap && (old_end > new_start) && (old_start < new_end))
return_0;
return 1; return 1;
} }
@ -681,7 +705,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
struct pv_list *pvl; struct pv_list *pvl;
int r = 0; int r = 0;
uint64_t new_wrap; /* Number of bytes of new metadata that wrap around to start of buffer */ uint64_t new_wrap; /* Number of bytes of new metadata that wrap around to start of buffer */
uint64_t alignment = MDA_ORIGINAL_ALIGNMENT; uint64_t alignment = MDA_ALIGNMENT;
int found = 0; int found = 0;
int noprecommit = 0; int noprecommit = 0;
const char *old_vg_name = NULL; const char *old_vg_name = NULL;
@ -725,16 +749,32 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
/* Find where the new metadata would be written with our preferred alignment */ /* Find where the new metadata would be written with our preferred alignment */
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, alignment); mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, alignment);
/* Does the new metadata wrap around? */ /* If metadata extends beyond the buffer, return to the start instead of wrapping it */
if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size) if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size; mdac->rlocn.offset = ALIGN_ABSOLUTE(MDA_HEADER_SIZE, mdac->area.start, alignment);
else
new_wrap = 0;
if (!_metadata_fits_into_buffer(mdac, mdah, rlocn, new_wrap)) { /*
log_error("VG %s metadata on %s (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes with " FMTu64 " used)", * If the metadata doesn't fit into the buffer correctly with these
vg->name, dev_name(mdac->area.dev), mdac->rlocn.size, mdah->size - MDA_HEADER_SIZE, rlocn ? rlocn->size : 0); * settings, fall back to the 512-byte alignment used by the original
goto out; * LVM2 code and allow the metadata to be split into two parts,
* wrapping around from the end of the circular buffer back to the
* beginning.
*/
if (!_metadata_fits_into_buffer(mdac, mdah, rlocn, 0)) {
alignment = MDA_ORIGINAL_ALIGNMENT;
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, alignment);
/* Does the new metadata wrap around? */
if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
else
new_wrap = 0;
if (!_metadata_fits_into_buffer(mdac, mdah, rlocn, new_wrap)) {
log_error("VG %s metadata on %s (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes with " FMTu64 " used)",
vg->name, dev_name(mdac->area.dev), mdac->rlocn.size, mdah->size - MDA_HEADER_SIZE, rlocn ? rlocn->size : 0);
goto out;
}
} }
log_debug_metadata("Writing %s metadata to %s at " FMTu64 " len " FMTu64 " of " FMTu64 " aligned to " FMTu64, log_debug_metadata("Writing %s metadata to %s at " FMTu64 " len " FMTu64 " of " FMTu64 " aligned to " FMTu64,
@ -1323,7 +1363,7 @@ int vgname_from_mda(const struct format_type *fmt,
(char *)&vgsummary->vgid); (char *)&vgsummary->vgid);
if (mda_free_sectors) { if (mda_free_sectors) {
current_usage = ALIGN_ABSOLUTE(rlocn->size, dev_area->start + rlocn->offset, MDA_ORIGINAL_ALIGNMENT); current_usage = ALIGN_ABSOLUTE(rlocn->size, dev_area->start + rlocn->offset, MDA_ALIGNMENT);
buffer_size = mdah->size - MDA_HEADER_SIZE; buffer_size = mdah->size - MDA_HEADER_SIZE;

View File

@ -103,6 +103,7 @@ struct mda_context {
#define LVM2_LABEL "LVM2 001" #define LVM2_LABEL "LVM2 001"
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize()) #define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */ #define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
#define MDA_ALIGNMENT 4096 /* Default alignment in bytes since 2.02.177 for start of VG metadata content. */
int vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah, int primary_mda, int vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary, struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,