xref: /freebsd/sys/geom/label/g_label_ufs.c (revision 3ce9ca894748bcf328a9b3b09a6ac742b581b74d)
1e1237b28SPawel Jakub Dawidek /*-
2e1237b28SPawel Jakub Dawidek  * Copyright (c) 2002, 2003 Gordon Tetlow
3c058f512SPawel Jakub Dawidek  * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4e1237b28SPawel Jakub Dawidek  * All rights reserved.
5e1237b28SPawel Jakub Dawidek  *
6e1237b28SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
7e1237b28SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
8e1237b28SPawel Jakub Dawidek  * are met:
9e1237b28SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
10e1237b28SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
11e1237b28SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
12e1237b28SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
13e1237b28SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
14e1237b28SPawel Jakub Dawidek  *
15c058f512SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16e1237b28SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e1237b28SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c058f512SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19e1237b28SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e1237b28SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e1237b28SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e1237b28SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e1237b28SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e1237b28SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e1237b28SPawel Jakub Dawidek  * SUCH DAMAGE.
26e1237b28SPawel Jakub Dawidek  */
27e1237b28SPawel Jakub Dawidek 
28e1237b28SPawel Jakub Dawidek #include <sys/cdefs.h>
29e1237b28SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
30e1237b28SPawel Jakub Dawidek 
31e1237b28SPawel Jakub Dawidek #include <sys/param.h>
32e1237b28SPawel Jakub Dawidek #include <sys/systm.h>
33e1237b28SPawel Jakub Dawidek #include <sys/kernel.h>
34e1237b28SPawel Jakub Dawidek #include <sys/malloc.h>
35e1237b28SPawel Jakub Dawidek 
36e1237b28SPawel Jakub Dawidek #include <ufs/ufs/dinode.h>
37e1237b28SPawel Jakub Dawidek #include <ufs/ffs/fs.h>
38e1237b28SPawel Jakub Dawidek 
39e1237b28SPawel Jakub Dawidek #include <geom/geom.h>
40e1237b28SPawel Jakub Dawidek #include <geom/label/g_label.h>
41e1237b28SPawel Jakub Dawidek 
42f7b16839SIvan Voras #define G_LABEL_UFS_VOLUME_DIR	"ufs"
43f7b16839SIvan Voras #define G_LABEL_UFS_ID_DIR	"ufsid"
44f7b16839SIvan Voras 
45f7b16839SIvan Voras #define	G_LABEL_UFS_VOLUME	0
46f7b16839SIvan Voras #define	G_LABEL_UFS_ID		1
47e1237b28SPawel Jakub Dawidek 
48e1237b28SPawel Jakub Dawidek static const int superblocks[] = SBLOCKSEARCH;
49e1237b28SPawel Jakub Dawidek 
50e1237b28SPawel Jakub Dawidek static void
51f7b16839SIvan Voras g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int what)
52e1237b28SPawel Jakub Dawidek {
53e1237b28SPawel Jakub Dawidek 	struct g_provider *pp;
54b53a1cf3SMaxim Sobolev 	int sb, superblock;
55e1237b28SPawel Jakub Dawidek 	struct fs *fs;
56e1237b28SPawel Jakub Dawidek 
57e1237b28SPawel Jakub Dawidek 	g_topology_assert_not();
58e1237b28SPawel Jakub Dawidek 	pp = cp->provider;
59e1237b28SPawel Jakub Dawidek 	label[0] = '\0';
6033361bb5SPawel Jakub Dawidek 
6133361bb5SPawel Jakub Dawidek 	if (SBLOCKSIZE % cp->provider->sectorsize != 0)
6217fb8ae7SPawel Jakub Dawidek 		return;
6333361bb5SPawel Jakub Dawidek 
64e1237b28SPawel Jakub Dawidek 	/*
65e1237b28SPawel Jakub Dawidek 	 * Walk through the standard places that superblocks hide and look
66e1237b28SPawel Jakub Dawidek 	 * for UFS magic. If we find magic, then check that the size in the
67e1237b28SPawel Jakub Dawidek 	 * superblock corresponds to the size of the underlying provider.
68e1237b28SPawel Jakub Dawidek 	 * Finally, look for a volume label and create an appropriate
69e1237b28SPawel Jakub Dawidek 	 * provider based on that.
70e1237b28SPawel Jakub Dawidek 	 */
71e1237b28SPawel Jakub Dawidek 	for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) {
7204550802SDag-Erling Smørgrav 		/*
7333361bb5SPawel Jakub Dawidek 		 * Take care not to issue an invalid I/O request. The offset of
7433361bb5SPawel Jakub Dawidek 		 * the superblock candidate must be multiples of the provider's
7533361bb5SPawel Jakub Dawidek 		 * sector size, otherwise an FFS can't exist on the provider
7633361bb5SPawel Jakub Dawidek 		 * anyway.
7704550802SDag-Erling Smørgrav 		 */
7833361bb5SPawel Jakub Dawidek 		if (superblock % cp->provider->sectorsize != 0)
7904550802SDag-Erling Smørgrav 			continue;
8004550802SDag-Erling Smørgrav 
8133361bb5SPawel Jakub Dawidek 		fs = (struct fs *)g_read_data(cp, superblock, SBLOCKSIZE, NULL);
828a4a44b5SMaxim Sobolev 		if (fs == NULL)
83e1237b28SPawel Jakub Dawidek 			continue;
84e1237b28SPawel Jakub Dawidek 		/* Check for magic and make sure things are the right size */
85f8aa16c6SPawel Jakub Dawidek 		if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 &&
86f8aa16c6SPawel Jakub Dawidek 		    pp->mediasize / fs->fs_fsize == fs->fs_old_size) {
8799c889fcSPawel Jakub Dawidek 		    	/* Valid UFS1. */
8899c889fcSPawel Jakub Dawidek 		} else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 &&
8999c889fcSPawel Jakub Dawidek 		    pp->mediasize / fs->fs_fsize == fs->fs_size) {
9099c889fcSPawel Jakub Dawidek 		    	/* Valid UFS2. */
9199c889fcSPawel Jakub Dawidek 		} else {
92e1237b28SPawel Jakub Dawidek 			g_free(fs);
93e1237b28SPawel Jakub Dawidek 			continue;
94e1237b28SPawel Jakub Dawidek 		}
95c058f512SPawel Jakub Dawidek 		if (fs->fs_sblockloc != superblock || fs->fs_ncg < 1 ||
96c058f512SPawel Jakub Dawidek 		    fs->fs_bsize < MINBSIZE ||
97c058f512SPawel Jakub Dawidek 		    fs->fs_bsize < sizeof(struct fs)) {
98e1237b28SPawel Jakub Dawidek 			g_free(fs);
99e1237b28SPawel Jakub Dawidek 			continue;
100e1237b28SPawel Jakub Dawidek 		}
101c058f512SPawel Jakub Dawidek 		G_LABEL_DEBUG(1, "%s file system detected on %s.",
102c058f512SPawel Jakub Dawidek 		    fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name);
103f7b16839SIvan Voras 		switch (what) {
104f7b16839SIvan Voras 		case G_LABEL_UFS_VOLUME:
105e1237b28SPawel Jakub Dawidek 			/* Check for volume label */
106e1237b28SPawel Jakub Dawidek 			if (fs->fs_volname[0] == '\0') {
107e1237b28SPawel Jakub Dawidek 				g_free(fs);
108e1237b28SPawel Jakub Dawidek 				continue;
109e1237b28SPawel Jakub Dawidek 			}
110e1237b28SPawel Jakub Dawidek 			strlcpy(label, fs->fs_volname, size);
111f7b16839SIvan Voras 			break;
112f7b16839SIvan Voras 		case G_LABEL_UFS_ID:
113f7b16839SIvan Voras 			if (fs->fs_id[0] == 0 && fs->fs_id[1] == 0) {
114f7b16839SIvan Voras 				g_free(fs);
115f7b16839SIvan Voras 				continue;
116f7b16839SIvan Voras 			}
117f7b16839SIvan Voras 			snprintf(label, size, "%08x%08x", fs->fs_id[0],
118f7b16839SIvan Voras 			    fs->fs_id[1]);
119f7b16839SIvan Voras 			break;
120f7b16839SIvan Voras 		}
121e1237b28SPawel Jakub Dawidek 		g_free(fs);
122e1237b28SPawel Jakub Dawidek 		break;
123e1237b28SPawel Jakub Dawidek 	}
124e1237b28SPawel Jakub Dawidek }
125e1237b28SPawel Jakub Dawidek 
126f7b16839SIvan Voras static void
127f7b16839SIvan Voras g_label_ufs_volume_taste(struct g_consumer *cp, char *label, size_t size)
128f7b16839SIvan Voras {
129f7b16839SIvan Voras 
130f7b16839SIvan Voras 	g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_VOLUME);
131f7b16839SIvan Voras }
132f7b16839SIvan Voras 
133f7b16839SIvan Voras static void
134f7b16839SIvan Voras g_label_ufs_id_taste(struct g_consumer *cp, char *label, size_t size)
135f7b16839SIvan Voras {
136f7b16839SIvan Voras 
137f7b16839SIvan Voras 	g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_ID);
138f7b16839SIvan Voras }
139f7b16839SIvan Voras 
1403ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ufs_volume = {
141f7b16839SIvan Voras 	.ld_taste = g_label_ufs_volume_taste,
1423ce9ca89SEdward Tomasz Napierala 	.ld_dir = G_LABEL_UFS_VOLUME_DIR,
1433ce9ca89SEdward Tomasz Napierala 	.ld_enabled = 1
144f7b16839SIvan Voras };
145f7b16839SIvan Voras 
1463ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ufs_id = {
147f7b16839SIvan Voras 	.ld_taste = g_label_ufs_id_taste,
1483ce9ca89SEdward Tomasz Napierala 	.ld_dir = G_LABEL_UFS_ID_DIR,
1493ce9ca89SEdward Tomasz Napierala 	.ld_enabled = 1
150e1237b28SPawel Jakub Dawidek };
1513ce9ca89SEdward Tomasz Napierala 
1523ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ufsid, g_label_ufs_id, "Create device nodes for UFS file system IDs");
1533ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ufs, g_label_ufs_volume, "Create device nodes for UFS volume names");
154