xref: /freebsd/sys/geom/label/g_label_ufs.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1e1237b28SPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni  *
4e1237b28SPawel Jakub Dawidek  * Copyright (c) 2002, 2003 Gordon Tetlow
5c058f512SPawel Jakub Dawidek  * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
6e1237b28SPawel Jakub Dawidek  * All rights reserved.
7e1237b28SPawel Jakub Dawidek  *
8e1237b28SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
9e1237b28SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
10e1237b28SPawel Jakub Dawidek  * are met:
11e1237b28SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
12e1237b28SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
13e1237b28SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
14e1237b28SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
15e1237b28SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
16e1237b28SPawel Jakub Dawidek  *
17c058f512SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18e1237b28SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19e1237b28SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20c058f512SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21e1237b28SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22e1237b28SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23e1237b28SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24e1237b28SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25e1237b28SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26e1237b28SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27e1237b28SPawel Jakub Dawidek  * SUCH DAMAGE.
28e1237b28SPawel Jakub Dawidek  */
29e1237b28SPawel Jakub Dawidek 
30e1237b28SPawel Jakub Dawidek #include <sys/param.h>
31e1237b28SPawel Jakub Dawidek #include <sys/systm.h>
32e77ef47dSJessica Clarke #include <sys/disklabel.h>
33e1237b28SPawel Jakub Dawidek #include <sys/malloc.h>
34dffce215SKirk McKusick #include <sys/vnode.h>
35e1237b28SPawel Jakub Dawidek 
36e1237b28SPawel Jakub Dawidek #include <ufs/ufs/dinode.h>
37e1237b28SPawel Jakub Dawidek #include <ufs/ffs/fs.h>
38dffce215SKirk McKusick #include <ufs/ufs/quota.h>
39dffce215SKirk McKusick #include <ufs/ufs/extattr.h>
40dffce215SKirk McKusick #include <ufs/ffs/ffs_extern.h>
41e1237b28SPawel Jakub Dawidek 
42e1237b28SPawel Jakub Dawidek #include <geom/geom.h>
43ac03832eSConrad Meyer #include <geom/geom_dbg.h>
44e1237b28SPawel Jakub Dawidek #include <geom/label/g_label.h>
45e1237b28SPawel Jakub Dawidek 
46f7b16839SIvan Voras #define	G_LABEL_UFS_VOLUME	0
47f7b16839SIvan Voras #define	G_LABEL_UFS_ID		1
48e1237b28SPawel Jakub Dawidek 
4955f9588aSMaxim Sobolev /*
50e77ef47dSJessica Clarke  * G_LABEL_UFS_CMP returns true if difference between provider mediasize
51e77ef47dSJessica Clarke  * and filesystem size is less than G_LABEL_UFS_MAXDIFF sectors
52e77ef47dSJessica Clarke  */
53e77ef47dSJessica Clarke #define	G_LABEL_UFS_CMP(prov, fsys, size) 				   \
54e77ef47dSJessica Clarke 	( abs( ((fsys)->size) - ( (prov)->mediasize / (fsys)->fs_fsize ))  \
55e77ef47dSJessica Clarke 				< G_LABEL_UFS_MAXDIFF )
56e77ef47dSJessica Clarke #define	G_LABEL_UFS_MAXDIFF	0x100
57e77ef47dSJessica Clarke 
58e77ef47dSJessica Clarke /*
59e77ef47dSJessica Clarke  * For providers that look like disklabels we need to check if the file system
60e77ef47dSJessica Clarke  * size is almost equal to the provider's size, because sysinstall(8) used to
61e77ef47dSJessica Clarke  * bogusly put the first partition at offset 0 instead of 16, and glabel/ufs
62e77ef47dSJessica Clarke  * would find a file system on the slice instead of the partition.
63e77ef47dSJessica Clarke  *
64e77ef47dSJessica Clarke  * In addition, media size can be a bit bigger than file system size. For
65e77ef47dSJessica Clarke  * instance, mkuzip can append bytes to align data to large sector size (it
66e77ef47dSJessica Clarke  * improves compression rates).
67e77ef47dSJessica Clarke  */
68e77ef47dSJessica Clarke static bool
g_label_ufs_ignore_bsdlabel_slice(struct g_consumer * cp,struct fs * fs)69e77ef47dSJessica Clarke g_label_ufs_ignore_bsdlabel_slice(struct g_consumer *cp,
70e77ef47dSJessica Clarke     struct fs *fs)
71e77ef47dSJessica Clarke {
72e77ef47dSJessica Clarke 	struct g_provider *pp;
73e77ef47dSJessica Clarke 	u_char *buf;
74e77ef47dSJessica Clarke 	uint32_t magic1, magic2;
75e77ef47dSJessica Clarke 	int error;
76e77ef47dSJessica Clarke 
77e77ef47dSJessica Clarke 	pp = cp->provider;
78e77ef47dSJessica Clarke 
79e77ef47dSJessica Clarke 	/*
80e77ef47dSJessica Clarke 	 * If the expected provider size for the filesystem matches the
81e77ef47dSJessica Clarke 	 * real provider size then don't ignore this filesystem.
82e77ef47dSJessica Clarke 	 */
83e77ef47dSJessica Clarke 	if (G_LABEL_UFS_CMP(pp, fs, fs_providersize))
84e77ef47dSJessica Clarke 		return (false);
85e77ef47dSJessica Clarke 
86e77ef47dSJessica Clarke 	/*
87e77ef47dSJessica Clarke 	 * If the filesystem size matches the real provider size then
88e77ef47dSJessica Clarke 	 * don't ignore this filesystem.
89e77ef47dSJessica Clarke 	 */
90e77ef47dSJessica Clarke 	if (fs->fs_magic == FS_UFS1_MAGIC ?
91e77ef47dSJessica Clarke 	    G_LABEL_UFS_CMP(pp, fs, fs_old_size) :
92e77ef47dSJessica Clarke 	    G_LABEL_UFS_CMP(pp, fs, fs_size))
93e77ef47dSJessica Clarke 		return (false);
94e77ef47dSJessica Clarke 
95e77ef47dSJessica Clarke 	/*
96e77ef47dSJessica Clarke 	 * Provider is bigger than expected; probe to see if there's a
97e77ef47dSJessica Clarke 	 * disklabel. Adapted from g_part_bsd_probe.
98e77ef47dSJessica Clarke 	 */
99e77ef47dSJessica Clarke 
100e77ef47dSJessica Clarke 	/* Check if the superblock overlaps where the disklabel lives. */
101e77ef47dSJessica Clarke 	if (fs->fs_sblockloc < pp->sectorsize * 2)
102e77ef47dSJessica Clarke 		return (false);
103e77ef47dSJessica Clarke 
104e77ef47dSJessica Clarke 	/* Sanity-check the provider. */
105e77ef47dSJessica Clarke 	if (pp->sectorsize < sizeof(struct disklabel) ||
106e77ef47dSJessica Clarke 	    pp->mediasize < BBSIZE)
107e77ef47dSJessica Clarke 		return (false);
108e77ef47dSJessica Clarke 	if (BBSIZE % pp->sectorsize)
109e77ef47dSJessica Clarke 		return (false);
110e77ef47dSJessica Clarke 
111e77ef47dSJessica Clarke 	/* Check that there's a disklabel. */
112e77ef47dSJessica Clarke 	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
113e77ef47dSJessica Clarke 	if (buf == NULL)
114e77ef47dSJessica Clarke 		return (false);
115e77ef47dSJessica Clarke 	magic1 = le32dec(buf + 0);
116e77ef47dSJessica Clarke 	magic2 = le32dec(buf + 132);
117e77ef47dSJessica Clarke 	g_free(buf);
118e77ef47dSJessica Clarke 	if (magic1 == DISKMAGIC && magic2 == DISKMAGIC)
119e77ef47dSJessica Clarke 		return (true);
120e77ef47dSJessica Clarke 
121e77ef47dSJessica Clarke 	return (false);
122e77ef47dSJessica Clarke }
123e77ef47dSJessica Clarke 
124e77ef47dSJessica Clarke /*
125af433832SJessica Clarke  * Try to find a superblock on the provider. If successful, look for a volume
126af433832SJessica Clarke  * label and create an appropriate provider based on that.
127dffce215SKirk McKusick  */
128e1237b28SPawel Jakub Dawidek static void
g_label_ufs_taste_common(struct g_consumer * cp,char * label,size_t size,int what)129f7b16839SIvan Voras g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int what)
130e1237b28SPawel Jakub Dawidek {
131e1237b28SPawel Jakub Dawidek 	struct g_provider *pp;
132e1237b28SPawel Jakub Dawidek 	struct fs *fs;
133e1237b28SPawel Jakub Dawidek 
134e1237b28SPawel Jakub Dawidek 	g_topology_assert_not();
135e1237b28SPawel Jakub Dawidek 	pp = cp->provider;
136e1237b28SPawel Jakub Dawidek 	label[0] = '\0';
13733361bb5SPawel Jakub Dawidek 
13816759360SMark Johnston 	fs = NULL;
13905d0f430SAlan Somers 	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize"));
140b21582eeSKirk McKusick 	if (SBLOCKSIZE % pp->sectorsize != 0 || ffs_sbget(cp, &fs, UFS_STDSB,
141b21582eeSKirk McKusick 	    UFS_NOHASHFAIL | UFS_NOCSUM | UFS_NOMSG, M_GEOM, g_use_g_read_data)
142b21582eeSKirk McKusick 	    != 0) {
143efbf3964SKirk McKusick 		KASSERT(fs == NULL,
14490575a0eSConrad Meyer 		    ("g_label_ufs_taste_common: non-NULL fs %p\n", fs));
14517fb8ae7SPawel Jakub Dawidek 		return;
14616759360SMark Johnston 	}
14716759360SMark Johnston 
148af433832SJessica Clarke 	/* Check for magic. */
149af433832SJessica Clarke 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0) {
15099c889fcSPawel Jakub Dawidek 		/* Valid UFS1. */
151af433832SJessica Clarke 	} else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0) {
15299c889fcSPawel Jakub Dawidek 		/* Valid UFS2. */
15399c889fcSPawel Jakub Dawidek 	} else {
154fb15890aSKirk McKusick 		goto out;
155e1237b28SPawel Jakub Dawidek 	}
156e77ef47dSJessica Clarke 	/* Check if this should be ignored for compatibility. */
157e77ef47dSJessica Clarke 	if (g_label_ufs_ignore_bsdlabel_slice(cp, fs))
158e77ef47dSJessica Clarke 		goto out;
159c058f512SPawel Jakub Dawidek 	G_LABEL_DEBUG(1, "%s file system detected on %s.",
160c058f512SPawel Jakub Dawidek 	    fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name);
161f7b16839SIvan Voras 	switch (what) {
162f7b16839SIvan Voras 	case G_LABEL_UFS_VOLUME:
163e1237b28SPawel Jakub Dawidek 		/* Check for volume label */
164dffce215SKirk McKusick 		if (fs->fs_volname[0] != '\0')
165e1237b28SPawel Jakub Dawidek 			strlcpy(label, fs->fs_volname, size);
166f7b16839SIvan Voras 		break;
167f7b16839SIvan Voras 	case G_LABEL_UFS_ID:
168dffce215SKirk McKusick 		if (fs->fs_id[0] != 0 || fs->fs_id[1] != 0)
169f7b16839SIvan Voras 			snprintf(label, size, "%08x%08x", fs->fs_id[0],
170f7b16839SIvan Voras 			    fs->fs_id[1]);
171f7b16839SIvan Voras 		break;
172f7b16839SIvan Voras 	}
173fb15890aSKirk McKusick out:
174e1237b28SPawel Jakub Dawidek 	g_free(fs);
175e1237b28SPawel Jakub Dawidek }
176e1237b28SPawel Jakub Dawidek 
177f7b16839SIvan Voras static void
g_label_ufs_volume_taste(struct g_consumer * cp,char * label,size_t size)178f7b16839SIvan Voras g_label_ufs_volume_taste(struct g_consumer *cp, char *label, size_t size)
179f7b16839SIvan Voras {
180f7b16839SIvan Voras 
181f7b16839SIvan Voras 	g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_VOLUME);
182f7b16839SIvan Voras }
183f7b16839SIvan Voras 
184f7b16839SIvan Voras static void
g_label_ufs_id_taste(struct g_consumer * cp,char * label,size_t size)185f7b16839SIvan Voras g_label_ufs_id_taste(struct g_consumer *cp, char *label, size_t size)
186f7b16839SIvan Voras {
187f7b16839SIvan Voras 
188f7b16839SIvan Voras 	g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_ID);
189f7b16839SIvan Voras }
190f7b16839SIvan Voras 
1913ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ufs_volume = {
192f7b16839SIvan Voras 	.ld_taste = g_label_ufs_volume_taste,
193795c5f36SXin LI 	.ld_dirprefix = "ufs/",
1943ce9ca89SEdward Tomasz Napierala 	.ld_enabled = 1
195f7b16839SIvan Voras };
196f7b16839SIvan Voras 
1973ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ufs_id = {
198f7b16839SIvan Voras 	.ld_taste = g_label_ufs_id_taste,
199795c5f36SXin LI 	.ld_dirprefix = "ufsid/",
2003ce9ca89SEdward Tomasz Napierala 	.ld_enabled = 1
201e1237b28SPawel Jakub Dawidek };
2023ce9ca89SEdward Tomasz Napierala 
2033ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ufsid, g_label_ufs_id, "Create device nodes for UFS file system IDs");
2043ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ufs, g_label_ufs_volume, "Create device nodes for UFS volume names");
20590a48fbaSXin LI 
20690a48fbaSXin LI MODULE_DEPEND(g_label, ufs, 1, 1, 1);
207