aboutsummaryrefslogtreecommitdiff
path: root/sys/geom/label
diff options
context:
space:
mode:
authorJessica Clarke <jrtc27@FreeBSD.org>2021-07-21 01:24:55 +0000
committerJessica Clarke <jrtc27@FreeBSD.org>2021-07-21 01:51:25 +0000
commite77ef47d3649090904e36a6ffa42486a435ba127 (patch)
tree5b28e1c5078faaea1e379f2af03b88dfe466716a /sys/geom/label
parentb684d812fcb04b2997fd755405a92c36b9f6e30e (diff)
Diffstat (limited to 'sys/geom/label')
-rw-r--r--sys/geom/label/g_label_ufs.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c
index 70d59488d7b6..b29a04c9f348 100644
--- a/sys/geom/label/g_label_ufs.c
+++ b/sys/geom/label/g_label_ufs.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/disklabel.h>
#include <sys/malloc.h>
#include <sys/vnode.h>
@@ -49,6 +50,81 @@ __FBSDID("$FreeBSD$");
#define G_LABEL_UFS_ID 1
/*
+ * G_LABEL_UFS_CMP returns true if difference between provider mediasize
+ * and filesystem size is less than G_LABEL_UFS_MAXDIFF sectors
+ */
+#define G_LABEL_UFS_CMP(prov, fsys, size) \
+ ( abs( ((fsys)->size) - ( (prov)->mediasize / (fsys)->fs_fsize )) \
+ < G_LABEL_UFS_MAXDIFF )
+#define G_LABEL_UFS_MAXDIFF 0x100
+
+/*
+ * For providers that look like disklabels we need to check if the file system
+ * size is almost equal to the provider's size, because sysinstall(8) used to
+ * bogusly put the first partition at offset 0 instead of 16, and glabel/ufs
+ * would find a file system on the slice instead of the partition.
+ *
+ * In addition, media size can be a bit bigger than file system size. For
+ * instance, mkuzip can append bytes to align data to large sector size (it
+ * improves compression rates).
+ */
+static bool
+g_label_ufs_ignore_bsdlabel_slice(struct g_consumer *cp,
+ struct fs *fs)
+{
+ struct g_provider *pp;
+ u_char *buf;
+ uint32_t magic1, magic2;
+ int error;
+
+ pp = cp->provider;
+
+ /*
+ * If the expected provider size for the filesystem matches the
+ * real provider size then don't ignore this filesystem.
+ */
+ if (G_LABEL_UFS_CMP(pp, fs, fs_providersize))
+ return (false);
+
+ /*
+ * If the filesystem size matches the real provider size then
+ * don't ignore this filesystem.
+ */
+ if (fs->fs_magic == FS_UFS1_MAGIC ?
+ G_LABEL_UFS_CMP(pp, fs, fs_old_size) :
+ G_LABEL_UFS_CMP(pp, fs, fs_size))
+ return (false);
+
+ /*
+ * Provider is bigger than expected; probe to see if there's a
+ * disklabel. Adapted from g_part_bsd_probe.
+ */
+
+ /* Check if the superblock overlaps where the disklabel lives. */
+ if (fs->fs_sblockloc < pp->sectorsize * 2)
+ return (false);
+
+ /* Sanity-check the provider. */
+ if (pp->sectorsize < sizeof(struct disklabel) ||
+ pp->mediasize < BBSIZE)
+ return (false);
+ if (BBSIZE % pp->sectorsize)
+ return (false);
+
+ /* Check that there's a disklabel. */
+ buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
+ if (buf == NULL)
+ return (false);
+ magic1 = le32dec(buf + 0);
+ magic2 = le32dec(buf + 132);
+ g_free(buf);
+ if (magic1 == DISKMAGIC && magic2 == DISKMAGIC)
+ return (true);
+
+ return (false);
+}
+
+/*
* Try to find a superblock on the provider. If successful, look for a volume
* label and create an appropriate provider based on that.
*/
@@ -78,6 +154,9 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh
} else {
goto out;
}
+ /* Check if this should be ignored for compatibility. */
+ if (g_label_ufs_ignore_bsdlabel_slice(cp, fs))
+ goto out;
G_LABEL_DEBUG(1, "%s file system detected on %s.",
fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name);
switch (what) {