1e1237b28SPawel Jakub Dawidek /*- 2*3728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*3728855aSPedro 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/cdefs.h> 31e1237b28SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 32e1237b28SPawel Jakub Dawidek 33e1237b28SPawel Jakub Dawidek #include <sys/param.h> 34e1237b28SPawel Jakub Dawidek #include <sys/systm.h> 35e1237b28SPawel Jakub Dawidek #include <sys/kernel.h> 36e1237b28SPawel Jakub Dawidek #include <sys/malloc.h> 37e1237b28SPawel Jakub Dawidek 38e1237b28SPawel Jakub Dawidek #include <ufs/ufs/dinode.h> 39e1237b28SPawel Jakub Dawidek #include <ufs/ffs/fs.h> 40e1237b28SPawel Jakub Dawidek 41e1237b28SPawel Jakub Dawidek #include <geom/geom.h> 42e1237b28SPawel Jakub Dawidek #include <geom/label/g_label.h> 43e1237b28SPawel Jakub Dawidek 44f7b16839SIvan Voras #define G_LABEL_UFS_VOLUME_DIR "ufs" 45f7b16839SIvan Voras #define G_LABEL_UFS_ID_DIR "ufsid" 46f7b16839SIvan Voras 47f7b16839SIvan Voras #define G_LABEL_UFS_VOLUME 0 48f7b16839SIvan Voras #define G_LABEL_UFS_ID 1 49e1237b28SPawel Jakub Dawidek 5055f9588aSMaxim Sobolev /* 5155f9588aSMaxim Sobolev * G_LABEL_UFS_CMP returns true if difference between provider mediasize 5255f9588aSMaxim Sobolev * and filesystem size is less than G_LABEL_UFS_MAXDIFF sectors 5355f9588aSMaxim Sobolev */ 5455f9588aSMaxim Sobolev #define G_LABEL_UFS_CMP(prov, fsys, size) \ 5555f9588aSMaxim Sobolev ( abs( ((fsys)->size) - ( (prov)->mediasize / (fsys)->fs_fsize )) \ 5655f9588aSMaxim Sobolev < G_LABEL_UFS_MAXDIFF ) 5755f9588aSMaxim Sobolev #define G_LABEL_UFS_MAXDIFF 0x100 5855f9588aSMaxim Sobolev 59e1237b28SPawel Jakub Dawidek static const int superblocks[] = SBLOCKSEARCH; 60e1237b28SPawel Jakub Dawidek 61e1237b28SPawel Jakub Dawidek static void 62f7b16839SIvan Voras g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int what) 63e1237b28SPawel Jakub Dawidek { 64e1237b28SPawel Jakub Dawidek struct g_provider *pp; 65b53a1cf3SMaxim Sobolev int sb, superblock; 66e1237b28SPawel Jakub Dawidek struct fs *fs; 67e1237b28SPawel Jakub Dawidek 68e1237b28SPawel Jakub Dawidek g_topology_assert_not(); 69e1237b28SPawel Jakub Dawidek pp = cp->provider; 70e1237b28SPawel Jakub Dawidek label[0] = '\0'; 7133361bb5SPawel Jakub Dawidek 7233361bb5SPawel Jakub Dawidek if (SBLOCKSIZE % cp->provider->sectorsize != 0) 7317fb8ae7SPawel Jakub Dawidek return; 7433361bb5SPawel Jakub Dawidek 75e1237b28SPawel Jakub Dawidek /* 76e1237b28SPawel Jakub Dawidek * Walk through the standard places that superblocks hide and look 77e1237b28SPawel Jakub Dawidek * for UFS magic. If we find magic, then check that the size in the 78e1237b28SPawel Jakub Dawidek * superblock corresponds to the size of the underlying provider. 79e1237b28SPawel Jakub Dawidek * Finally, look for a volume label and create an appropriate 80e1237b28SPawel Jakub Dawidek * provider based on that. 81e1237b28SPawel Jakub Dawidek */ 82e1237b28SPawel Jakub Dawidek for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) { 8304550802SDag-Erling Smørgrav /* 8433361bb5SPawel Jakub Dawidek * Take care not to issue an invalid I/O request. The offset of 8533361bb5SPawel Jakub Dawidek * the superblock candidate must be multiples of the provider's 8633361bb5SPawel Jakub Dawidek * sector size, otherwise an FFS can't exist on the provider 8733361bb5SPawel Jakub Dawidek * anyway. 8804550802SDag-Erling Smørgrav */ 8933361bb5SPawel Jakub Dawidek if (superblock % cp->provider->sectorsize != 0) 9004550802SDag-Erling Smørgrav continue; 9104550802SDag-Erling Smørgrav 9233361bb5SPawel Jakub Dawidek fs = (struct fs *)g_read_data(cp, superblock, SBLOCKSIZE, NULL); 938a4a44b5SMaxim Sobolev if (fs == NULL) 94e1237b28SPawel Jakub Dawidek continue; 95c7c7d7d0SEdward Tomasz Napierala /* 9655f9588aSMaxim Sobolev * Check for magic. We also need to check if file system size 9755f9588aSMaxim Sobolev * is almost equal to providers size, because sysinstall(8) 9855f9588aSMaxim Sobolev * used to bogusly put first partition at offset 0 9955f9588aSMaxim Sobolev * instead of 16, and glabel/ufs would find file system on slice 10055f9588aSMaxim Sobolev * instead of partition. 10155f9588aSMaxim Sobolev * 10255f9588aSMaxim Sobolev * In addition, media size can be a bit bigger than file system 10355f9588aSMaxim Sobolev * size. For instance, mkuzip can append bytes to align data 10455f9588aSMaxim Sobolev * to large sector size (it improves compression rates). 105d87e5588SEdward Tomasz Napierala */ 10655f9588aSMaxim Sobolev switch (fs->fs_magic){ 10755f9588aSMaxim Sobolev case FS_UFS1_MAGIC: 10855f9588aSMaxim Sobolev case FS_UFS2_MAGIC: 10955f9588aSMaxim Sobolev G_LABEL_DEBUG(1, "%s %s params: %jd, %d, %d, %jd\n", 11055f9588aSMaxim Sobolev fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", 11155f9588aSMaxim Sobolev pp->name, pp->mediasize, fs->fs_fsize, 11255f9588aSMaxim Sobolev fs->fs_old_size, fs->fs_providersize); 11355f9588aSMaxim Sobolev break; 11455f9588aSMaxim Sobolev default: 11555f9588aSMaxim Sobolev break; 11655f9588aSMaxim Sobolev } 11755f9588aSMaxim Sobolev 118d87e5588SEdward Tomasz Napierala if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 && 11955f9588aSMaxim Sobolev ( G_LABEL_UFS_CMP(pp, fs, fs_old_size) 12055f9588aSMaxim Sobolev || G_LABEL_UFS_CMP(pp, fs, fs_providersize))) { 12199c889fcSPawel Jakub Dawidek /* Valid UFS1. */ 122d87e5588SEdward Tomasz Napierala } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 && 12355f9588aSMaxim Sobolev ( G_LABEL_UFS_CMP(pp, fs, fs_size) 12455f9588aSMaxim Sobolev || G_LABEL_UFS_CMP(pp, fs, fs_providersize))) { 12599c889fcSPawel Jakub Dawidek /* Valid UFS2. */ 12699c889fcSPawel Jakub Dawidek } else { 127e1237b28SPawel Jakub Dawidek g_free(fs); 128e1237b28SPawel Jakub Dawidek continue; 129e1237b28SPawel Jakub Dawidek } 130c058f512SPawel Jakub Dawidek if (fs->fs_sblockloc != superblock || fs->fs_ncg < 1 || 131c058f512SPawel Jakub Dawidek fs->fs_bsize < MINBSIZE || 132c058f512SPawel Jakub Dawidek fs->fs_bsize < sizeof(struct fs)) { 133e1237b28SPawel Jakub Dawidek g_free(fs); 134e1237b28SPawel Jakub Dawidek continue; 135e1237b28SPawel Jakub Dawidek } 136c058f512SPawel Jakub Dawidek G_LABEL_DEBUG(1, "%s file system detected on %s.", 137c058f512SPawel Jakub Dawidek fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name); 138f7b16839SIvan Voras switch (what) { 139f7b16839SIvan Voras case G_LABEL_UFS_VOLUME: 140e1237b28SPawel Jakub Dawidek /* Check for volume label */ 141e1237b28SPawel Jakub Dawidek if (fs->fs_volname[0] == '\0') { 142e1237b28SPawel Jakub Dawidek g_free(fs); 143e1237b28SPawel Jakub Dawidek continue; 144e1237b28SPawel Jakub Dawidek } 145e1237b28SPawel Jakub Dawidek strlcpy(label, fs->fs_volname, size); 146f7b16839SIvan Voras break; 147f7b16839SIvan Voras case G_LABEL_UFS_ID: 148f7b16839SIvan Voras if (fs->fs_id[0] == 0 && fs->fs_id[1] == 0) { 149f7b16839SIvan Voras g_free(fs); 150f7b16839SIvan Voras continue; 151f7b16839SIvan Voras } 152f7b16839SIvan Voras snprintf(label, size, "%08x%08x", fs->fs_id[0], 153f7b16839SIvan Voras fs->fs_id[1]); 154f7b16839SIvan Voras break; 155f7b16839SIvan Voras } 156e1237b28SPawel Jakub Dawidek g_free(fs); 157e1237b28SPawel Jakub Dawidek break; 158e1237b28SPawel Jakub Dawidek } 159e1237b28SPawel Jakub Dawidek } 160e1237b28SPawel Jakub Dawidek 161f7b16839SIvan Voras static void 162f7b16839SIvan Voras g_label_ufs_volume_taste(struct g_consumer *cp, char *label, size_t size) 163f7b16839SIvan Voras { 164f7b16839SIvan Voras 165f7b16839SIvan Voras g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_VOLUME); 166f7b16839SIvan Voras } 167f7b16839SIvan Voras 168f7b16839SIvan Voras static void 169f7b16839SIvan Voras g_label_ufs_id_taste(struct g_consumer *cp, char *label, size_t size) 170f7b16839SIvan Voras { 171f7b16839SIvan Voras 172f7b16839SIvan Voras g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_ID); 173f7b16839SIvan Voras } 174f7b16839SIvan Voras 1753ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ufs_volume = { 176f7b16839SIvan Voras .ld_taste = g_label_ufs_volume_taste, 1773ce9ca89SEdward Tomasz Napierala .ld_dir = G_LABEL_UFS_VOLUME_DIR, 1783ce9ca89SEdward Tomasz Napierala .ld_enabled = 1 179f7b16839SIvan Voras }; 180f7b16839SIvan Voras 1813ce9ca89SEdward Tomasz Napierala struct g_label_desc g_label_ufs_id = { 182f7b16839SIvan Voras .ld_taste = g_label_ufs_id_taste, 1833ce9ca89SEdward Tomasz Napierala .ld_dir = G_LABEL_UFS_ID_DIR, 1843ce9ca89SEdward Tomasz Napierala .ld_enabled = 1 185e1237b28SPawel Jakub Dawidek }; 1863ce9ca89SEdward Tomasz Napierala 1873ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ufsid, g_label_ufs_id, "Create device nodes for UFS file system IDs"); 1883ce9ca89SEdward Tomasz Napierala G_LABEL_INIT(ufs, g_label_ufs_volume, "Create device nodes for UFS volume names"); 189