if (!rlocn)
/* Find an empty slot */
/* 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 */
old_end = rlocn->offset + rlocn->size;
/* 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);
- /* If new location is beyond the end of the buffer, wrap around back to start of circular buffer */
- if (new_start_offset >= mdah->size)
- new_start_offset -= (mdah->size - MDA_HEADER_SIZE);
+ /* 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 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;
}
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 */
+ /*
+ * 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? */
if (MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)
return_0;
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 (new_wrap && old_wrap)
if ((new_wrap || old_wrap) && (new_end > old_start))
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;
}
struct pv_list *pvl;
int r = 0;
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 noprecommit = 0;
const char *old_vg_name = NULL;
/* Find where the new metadata would be written with our preferred 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)
- new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
- else
- new_wrap = 0;
+ mdac->rlocn.offset = ALIGN_ABSOLUTE(MDA_HEADER_SIZE, mdac->area.start, alignment);
- 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;
+ /*
+ * If the metadata doesn't fit into the buffer correctly with these
+ * settings, fall back to the 512-byte alignment used by the original
+ * 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,
(char *)&vgsummary->vgid);
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;