diff options
| author | Jessica Clarke <jrtc27@FreeBSD.org> | 2021-07-21 01:24:55 +0000 |
|---|---|---|
| committer | Jessica Clarke <jrtc27@FreeBSD.org> | 2021-07-21 01:51:25 +0000 |
| commit | e77ef47d3649090904e36a6ffa42486a435ba127 (patch) | |
| tree | 5b28e1c5078faaea1e379f2af03b88dfe466716a /sys/geom/label | |
| parent | b684d812fcb04b2997fd755405a92c36b9f6e30e (diff) | |
Diffstat (limited to 'sys/geom/label')
| -rw-r--r-- | sys/geom/label/g_label_ufs.c | 79 |
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) { |
