[lvm-devel] master - format_text: Move metadata size checking into separate fn.

Alasdair Kergon agk at sourceware.org
Mon Dec 11 17:11:12 UTC 2017


Gitweb:        https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=2db67a8ea09a6f1073583e135bfb7b66228d3526
Commit:        2db67a8ea09a6f1073583e135bfb7b66228d3526
Parent:        46393bfca0692ebddbecdfb1f3b8699c3caa4f16
Author:        Alasdair G Kergon <agk at redhat.com>
AuthorDate:    Mon Dec 11 17:08:29 2017 +0000
Committer:     Alasdair G Kergon <agk at redhat.com>
CommitterDate: Mon Dec 11 17:08:29 2017 +0000

format_text: Move metadata size checking into separate fn.

Move checks into _metadata_fits_into_buffer() and add macro for alignment.
---
 lib/format_text/format-text.c |   55 +++++++++++++++++++++++++++++++---------
 1 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 0dbab11..881fd4d 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -37,6 +37,12 @@
 #include <dirent.h>
 #include <ctype.h>
 
+/*
+ * Round up offset within buffer to next location that is an exact multiple of alignment.
+ * (We shouldn't assume the start of the metadata area was aligned the same way when it was created.)
+ */
+#define ALIGN_ABSOLUTE(offset, buffer_start, alignment) ((offset) + (alignment) - UINT64_C(1) - ((buffer_start) + (offset) + (alignment) - UINT64_C(1)) % (alignment))
+
 static struct format_instance *_text_create_text_instance(const struct format_type *fmt,
 							  const struct format_instance_ctx *fic);
 
@@ -615,6 +621,34 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
 	return vg;
 }
 
+static int _metadata_fits_into_buffer(struct mda_context *mdac, struct mda_header *mdah,
+				      struct raw_locn *rlocn, uint64_t new_wrap)
+{
+	uint64_t old_wrap = 0;	/* Amount of wrap around in existing metadata */
+	uint64_t new_end;	/* The end location of the new metadata */
+
+	/* Do we have existing metadata that ends beyond the end of the buffer? */
+	if (rlocn && (rlocn->offset + rlocn->size > mdah->size))
+		old_wrap = (rlocn->offset + rlocn->size) - mdah->size;
+
+	new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE :
+			    mdac->rlocn.offset + mdac->rlocn.size;
+
+	/* If both wrap around, there's necessarily overlap */
+	if (new_wrap && old_wrap)
+		return_0;
+
+	/* If either wraps around, does the new end fall beyond the old start? */
+	if (rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset))
+		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;
+
+	return 1;
+}
+
 static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
 			 struct metadata_area *mda)
 {
@@ -624,7 +658,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
 	struct mda_header *mdah;
 	struct pv_list *pvl;
 	int r = 0;
-	uint64_t new_wrap = 0, old_wrap = 0, new_end;
+	uint64_t new_wrap;	/* Number of bytes of new metadata that wrap around to start of buffer */
 	int found = 0;
 	int noprecommit = 0;
 	const char *old_vg_name = NULL;
@@ -657,21 +691,16 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
 
 	rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
 
-	mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, MDA_ORIGINAL_ALIGNMENT);
 	mdac->rlocn.size = fidtc->raw_metadata_buf_size;
 
+	mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, MDA_ORIGINAL_ALIGNMENT);
+
 	if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
 		new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
+	else
+		new_wrap = 0;
 
-	if (rlocn && (rlocn->offset + rlocn->size > mdah->size))
-		old_wrap = (rlocn->offset + rlocn->size) - mdah->size;
-
-	new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE :
-			    mdac->rlocn.offset + mdac->rlocn.size;
-
-	if ((new_wrap && old_wrap) ||
-	    (rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) ||
-	    (MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)) {
+	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;
@@ -1263,8 +1292,8 @@ int vgname_from_mda(const struct format_type *fmt,
 			   (char *)&vgsummary->vgid);
 
 	if (mda_free_sectors) {
-		current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
-				 (rlocn->size + SECTOR_SIZE - UINT64_C(1)) % SECTOR_SIZE;
+		current_usage = ALIGN_ABSOLUTE(rlocn->size, 0, MDA_ORIGINAL_ALIGNMENT);
+
 		buffer_size = mdah->size - MDA_HEADER_SIZE;
 
 		if (current_usage * 2 >= buffer_size)




More information about the lvm-devel mailing list