git: 3cfda2537654 - releng/13.2 - efivar: Really look for labels for the provider with right efimedia

From: Warner Losh <imp_at_FreeBSD.org>
Date: Sun, 19 Feb 2023 06:48:29 UTC
The branch releng/13.2 has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=3cfda25376542b65b459bc5af48b2fb0f200b552

commit 3cfda25376542b65b459bc5af48b2fb0f200b552
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-02-16 16:36:03 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-02-19 06:47:25 +0000

    efivar: Really look for labels for the provider with right efimedia
    
    The prior code mistakently thought that the g_consumer that hung off the
    provider we found were the right thing to use to find all the glabel
    aliases for this node. However, the only way to find that is to iterate
    through all the geoms that belong to the glabel geom class, looking for
    those geoms with the same name as the provider with the right efimedia.
    Do this in a way that caches glabel class, and allows for it to be
    absent. Tighten the filter for mounted filesystems to only look
    for the ones that are mounted on /dev/.. since the rest of the code
    assumes that.
    
    MFC After:              3 days
    Sponsored by:           Netflix
    Reviewed by:            corvink, asomers
    Differential Revision:  https://reviews.freebsd.org/D38619
    Approved by:            re@ (cperciva)
    
    (cherry picked from commit 2b460910326c4f39068fe2158a0726dc3d362f68)
    (cherry picked from commit f4d711e7209073404c821c9c26c7c17b87b61997)
---
 lib/libefivar/efivar-dp-xlate.c | 64 ++++++++++++++++++++++++++++++-----------
 1 file changed, 47 insertions(+), 17 deletions(-)

diff --git a/lib/libefivar/efivar-dp-xlate.c b/lib/libefivar/efivar-dp-xlate.c
index 586ba7d08180..3d63868dacef 100644
--- a/lib/libefivar/efivar-dp-xlate.c
+++ b/lib/libefivar/efivar-dp-xlate.c
@@ -134,12 +134,15 @@ efi_hd_to_unix(struct gmesh *mesh, const_efidp dp, char **dev, char **relpath, c
 	const_efidp media, file, walker;
 	size_t len, mntlen;
 	char buf[MAX_DP_TEXT_LEN];
-	char *pwalk;
+	char *pwalk, *newdev = NULL;
 	struct gprovider *pp, *provider;
-	struct gconsumer *cp;
 	struct statfs *mnt;
+	struct gclass *glabel;
+	struct ggeom *gp;
 
 	walker = media = dp;
+	*dev = NULL;
+	*relpath = NULL;
 
 	/*
 	 * Now, we can either have a filepath node next, or the end.
@@ -174,12 +177,6 @@ efi_hd_to_unix(struct gmesh *mesh, const_efidp dp, char **dev, char **relpath, c
 		goto errout;
 	}
 
-	*dev = strdup(pp->lg_name);
-	if (*dev == NULL) {
-		rv = ENOMEM;
-		goto errout;
-	}
-
 	/*
 	 * No file specified, just return the device. Don't even look
 	 * for a mountpoint. XXX Sane?
@@ -217,6 +214,16 @@ efi_hd_to_unix(struct gmesh *mesh, const_efidp dp, char **dev, char **relpath, c
 		rv = errno;
 		goto errout;
 	}
+
+	/*
+	 * Find glabel, if it exists. It's OK if not: we'll skip searching for
+	 * labels.
+	 */
+	LIST_FOREACH(glabel, &mesh->lg_class, lg_class) {
+		if (strcmp(glabel->lg_name, G_LABEL) == 0)
+			break;
+	}
+
 	provider = pp;
 	for (i = 0; i < n; i++) {
 		/*
@@ -225,30 +232,53 @@ efi_hd_to_unix(struct gmesh *mesh, const_efidp dp, char **dev, char **relpath, c
 		 * we'll need to invent one, but its decoding will be handled in
 		 * a separate function.
 		 */
-		if (mnt[i].f_mntfromname[0] != '/')
+		if (strncmp(mnt[i].f_mntfromname, "/dev/", 5) != 0)
 			continue;
 
 		/*
 		 * First see if it is directly attached
 		 */
-		if (strcmp(provider->lg_name, mnt[i].f_mntfromname + 5) == 0)
+		if (strcmp(provider->lg_name, mnt[i].f_mntfromname + 5) == 0) {
+			newdev = provider->lg_name;
 			break;
+		}
 
 		/*
-		 * Next see if it is attached via one of the physical disk's
-		 * labels.
+		 * Next see if it is attached via one of the physical disk's labels.
+		 * We can't search directly from the pointers we have for the
+		 * provider, so we have to cast a wider net for all labels and
+		 * filter those down to geoms whose name matches the PART provider
+		 * we found the efimedia attribute on.
 		 */
-		LIST_FOREACH(cp, &provider->lg_consumers, lg_consumer) {
-			pp = cp->lg_provider;
-			if (strcmp(pp->lg_geom->lg_class->lg_name, G_LABEL) != 0)
+		if (glabel == NULL)
+			continue;
+		LIST_FOREACH(gp, &glabel->lg_geom, lg_geom) {
+			if (strcmp(gp->lg_name, provider->lg_name) != 0) {
 				continue;
-			if (strcmp(g_device_path(pp->lg_name), mnt[i].f_mntfromname) == 0)
-				goto break2;
+			}
+			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+				if (strcmp(pp->lg_name, mnt[i].f_mntfromname + 5) == 0) {
+					newdev = pp->lg_name;
+					goto break2;
+				}
+			}
 		}
 		/* Not the one, try the next mount point */
 	}
 break2:
 
+	/*
+	 * If nothing better was mounted, then use the provider we found as
+	 * is. It's the most correct thing we can return in that acse.
+	 */
+	if (newdev == NULL)
+		newdev = provider->lg_name;
+	*dev = strdup(newdev);
+	if (*dev == NULL) {
+		rv = ENOMEM;
+		goto errout;
+	}
+
 	/*
 	 * No mountpoint found, no absolute path possible
 	 */