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