Module Name:    src
Committed By:   martin
Date:           Sat Jul 17 18:07:23 UTC 2021

Modified Files:
        src/usr.sbin/sysinst: gpt.c

Log Message:
PR 56310: if we fail to create a wedge this either means there is
a bug here (and we requested something nonsensial), or there are pre-
existing "foreign" wedges which disturb our work.
So remove all wedges on this disk that we do not know about and retry
to add our new wedge.


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/usr.sbin/sysinst/gpt.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/sysinst/gpt.c
diff -u src/usr.sbin/sysinst/gpt.c:1.24 src/usr.sbin/sysinst/gpt.c:1.25
--- src/usr.sbin/sysinst/gpt.c:1.24	Sat Jul 17 11:32:50 2021
+++ src/usr.sbin/sysinst/gpt.c	Sat Jul 17 18:07:22 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: gpt.c,v 1.24 2021/07/17 11:32:50 martin Exp $	*/
+/*	$NetBSD: gpt.c,v 1.25 2021/07/17 18:07:22 martin Exp $	*/
 
 /*
  * Copyright 2018 The NetBSD Foundation, Inc.
@@ -32,6 +32,7 @@
 #include "md.h"
 #include "gpt_uuid.h"
 #include <assert.h>
+#include <errno.h>
 #include <err.h>
 #include <paths.h>
 #include <sys/param.h>
@@ -1325,8 +1326,71 @@ bsdlabel_fstype_to_str(uint8_t fstype)
 	return (str);
 }
 
+/*
+ * diskfd is an open file descriptor for a disk we had trouble with
+ * creating some new wedges.
+ * Go through all wedges actually on that disk, check if we have a
+ * record for them and remove all others.
+ * This should sync our internal model of partitions with the real state.
+ */
+static void
+gpt_sanitize(int diskfd, const struct gpt_disk_partitions *parts,
+    struct gpt_part_entry *ignore)
+{
+	struct dkwedge_info *dkw, delw;
+	struct dkwedge_list dkwl;
+	size_t bufsize;
+	u_int i;
+
+	dkw = NULL;
+	dkwl.dkwl_buf = dkw;
+	dkwl.dkwl_bufsize = 0;
+
+	/* get a list of all wedges */
+	for (;;) {
+		if (ioctl(diskfd, DIOCLWEDGES, &dkwl) == -1)
+			return;
+		if (dkwl.dkwl_nwedges == dkwl.dkwl_ncopied)
+			break;
+		bufsize = dkwl.dkwl_nwedges * sizeof(*dkw);
+		if (dkwl.dkwl_bufsize < bufsize) {
+			dkw = realloc(dkwl.dkwl_buf, bufsize);
+			if (dkw == NULL)
+				return;
+			dkwl.dkwl_buf = dkw;
+			dkwl.dkwl_bufsize = bufsize;
+		}
+	}
+
+	/* try to remove all the ones we do not know about */
+	for (i = 0; i < dkwl.dkwl_nwedges; i++) {
+		bool found = false;
+		const char *devname = dkw[i].dkw_devname;
+
+		for (struct gpt_part_entry *pe = parts->partitions;
+		    pe != NULL; pe = pe->gp_next) {
+			if (pe == ignore)
+				continue;
+			if ((pe->gp_flags & GPEF_WEDGE) &&
+			    strcmp(pe->gp_dev_name, devname) == 0) {
+				found = true;
+				break;
+			}
+		}
+		if (found)
+			continue;
+		memset(&delw, 0, sizeof(delw));
+		strncpy(delw.dkw_devname, devname, sizeof(delw.dkw_devname));
+		(void)ioctl(diskfd, DIOCDWEDGE, &delw);
+	}
+
+	/* cleanup */
+	free(dkw);
+}
+
 static bool
-gpt_add_wedge(const char *disk, struct gpt_part_entry *p)
+gpt_add_wedge(const char *disk, struct gpt_part_entry *p,
+    const struct gpt_disk_partitions *parts)
 {
 	struct dkwedge_info dkw;
 	const char *tname;
@@ -1355,9 +1419,16 @@ gpt_add_wedge(const char *disk, struct g
 	if (fd < 0)
 		return false;
 	if (ioctl(fd, DIOCAWEDGE, &dkw) == -1) {
+		if (errno == EINVAL) {
+			/* sanitize existing wedges and try again */
+			gpt_sanitize(fd, parts, p);
+			if (ioctl(fd, DIOCAWEDGE, &dkw) == 0)
+				goto ok;
+		}
 		close(fd);
 		return false;
 	}
+ok:
 	close(fd);
 
 	strlcpy(p->gp_dev_name, dkw.dkw_devname, sizeof(p->gp_dev_name));
@@ -1405,10 +1476,8 @@ gpt_get_part_device(const struct disk_pa
 	if (usage == plain_name || usage == raw_dev_name)
 		life = true;
 	if (!(p->gp_flags & GPEF_WEDGE) && life &&
-	    !gpt_add_wedge(arg->disk, p)) {
-		devname[0] = 0;
+	    !gpt_add_wedge(arg->disk, p, parts))
 		return false;
-	}
 
 	switch (usage) {
 	case logical_name:

Reply via email to