1110290Sgordon/*- 2110290Sgordon * Copyright (c) 2002, 2003 Gordon Tetlow 3110290Sgordon * All rights reserved. 4110290Sgordon * 5110290Sgordon * Redistribution and use in source and binary forms, with or without 6110290Sgordon * modification, are permitted provided that the following conditions 7110290Sgordon * are met: 8110290Sgordon * 1. Redistributions of source code must retain the above copyright 9110290Sgordon * notice, this list of conditions and the following disclaimer. 10110290Sgordon * 2. Redistributions in binary form must reproduce the above copyright 11110290Sgordon * notice, this list of conditions and the following disclaimer in the 12110290Sgordon * documentation and/or other materials provided with the distribution. 13110290Sgordon * 14110290Sgordon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15110290Sgordon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16110290Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17110290Sgordon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18110290Sgordon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19110290Sgordon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20110290Sgordon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21110290Sgordon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22110290Sgordon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23110290Sgordon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24110290Sgordon * SUCH DAMAGE. 25110290Sgordon */ 26110290Sgordon 27116196Sobrien#include <sys/cdefs.h> 28116196Sobrien__FBSDID("$FreeBSD$"); 29116196Sobrien 30110290Sgordon#include <sys/param.h> 31110290Sgordon#include <sys/errno.h> 32110290Sgordon#include <sys/systm.h> 33219029Snetchild#include <sys/sysctl.h> 34110290Sgordon#include <sys/kernel.h> 35110290Sgordon#include <sys/malloc.h> 36110290Sgordon#include <sys/bio.h> 37110290Sgordon#include <sys/lock.h> 38110290Sgordon#include <sys/mutex.h> 39110290Sgordon 40110290Sgordon#include <ufs/ufs/dinode.h> 41110290Sgordon#include <ufs/ffs/fs.h> 42110290Sgordon 43110290Sgordon#include <geom/geom.h> 44110290Sgordon#include <geom/geom_slice.h> 45110290Sgordon 46219029SnetchildFEATURE(geom_vol, "GEOM support for volume names from UFS superblock"); 47219029Snetchild 48110290Sgordon#define VOL_FFS_CLASS_NAME "VOL_FFS" 49110290Sgordon 50110290Sgordonstatic int superblocks[] = SBLOCKSEARCH; 51110290Sgordon 52110290Sgordonstruct g_vol_ffs_softc { 53110290Sgordon char * vol; 54110290Sgordon}; 55110290Sgordon 56110290Sgordonstatic int 57110290Sgordong_vol_ffs_start(struct bio *bp __unused) 58110290Sgordon{ 59110290Sgordon return(0); 60110290Sgordon} 61110290Sgordon 62110290Sgordonstatic struct g_geom * 63110290Sgordong_vol_ffs_taste(struct g_class *mp, struct g_provider *pp, int flags) 64110290Sgordon{ 65110290Sgordon struct g_geom *gp; 66110290Sgordon struct g_consumer *cp; 67110290Sgordon struct g_vol_ffs_softc *ms; 68152971Ssobomax int sb, superblock; 69110290Sgordon struct fs *fs; 70110290Sgordon 71110290Sgordon g_trace(G_T_TOPOLOGY, "vol_taste(%s,%s)", mp->name, pp->name); 72110290Sgordon g_topology_assert(); 73110290Sgordon 74110513Sgordon /* 75110513Sgordon * XXX This is a really weak way to make sure we don't recurse. 76110513Sgordon * Probably ought to use BIO_GETATTR to check for this. 77110513Sgordon */ 78110290Sgordon if (flags == G_TF_NORMAL && 79110290Sgordon !strcmp(pp->geom->class->name, VOL_FFS_CLASS_NAME)) 80110290Sgordon return (NULL); 81110290Sgordon 82110290Sgordon gp = g_slice_new(mp, 1, pp, &cp, &ms, sizeof(*ms), g_vol_ffs_start); 83110290Sgordon if (gp == NULL) 84110290Sgordon return (NULL); 85110290Sgordon g_topology_unlock(); 86110290Sgordon /* 87110290Sgordon * Walk through the standard places that superblocks hide and look 88110290Sgordon * for UFS magic. If we find magic, then check that the size in the 89110290Sgordon * superblock corresponds to the size of the underlying provider. 90110291Sgordon * Finally, look for a volume label and create an appropriate 91110291Sgordon * provider based on that. 92110290Sgordon */ 93110290Sgordon for (sb=0; (superblock = superblocks[sb]) != -1; sb++) { 94141498Sdes /* 95141498Sdes * Take care not to issue an invalid I/O request. The 96141498Sdes * offset and size of the superblock candidate must be 97141498Sdes * multiples of the provider's sector size, otherwise an 98141498Sdes * FFS can't exist on the provider anyway. 99141498Sdes */ 100141498Sdes if (superblock % cp->provider->sectorsize != 0 || 101141498Sdes SBLOCKSIZE % cp->provider->sectorsize != 0) 102141498Sdes continue; 103141498Sdes 104110290Sgordon fs = (struct fs *) g_read_data(cp, superblock, 105152971Ssobomax SBLOCKSIZE, NULL); 106152967Ssobomax if (fs == NULL) 107110290Sgordon continue; 108110290Sgordon /* Check for magic and make sure things are the right size */ 109110290Sgordon if (fs->fs_magic == FS_UFS1_MAGIC) { 110110290Sgordon if (fs->fs_old_size * fs->fs_fsize != 111110290Sgordon (int32_t) pp->mediasize) { 112110290Sgordon g_free(fs); 113110290Sgordon continue; 114110290Sgordon } 115110290Sgordon } else if (fs->fs_magic == FS_UFS2_MAGIC) { 116110290Sgordon if (fs->fs_size * fs->fs_fsize != 117110290Sgordon (int64_t) pp->mediasize) { 118110290Sgordon g_free(fs); 119110290Sgordon continue; 120110290Sgordon } 121110290Sgordon } else { 122110290Sgordon g_free(fs); 123110290Sgordon continue; 124110290Sgordon } 125110290Sgordon /* Check for volume label */ 126110290Sgordon if (fs->fs_volname[0] == '\0') { 127110290Sgordon g_free(fs); 128110290Sgordon continue; 129110290Sgordon } 130110513Sgordon /* XXX We need to check for namespace conflicts. */ 131110513Sgordon /* XXX How do you handle a mirror set? */ 132110513Sgordon /* XXX We don't validate the volume name. */ 133110290Sgordon g_topology_lock(); 134110290Sgordon /* Alright, we have a label and a volume name, reconfig. */ 135110290Sgordon g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t) 0, 136110290Sgordon pp->mediasize, pp->sectorsize, "vol/%s", 137110290Sgordon fs->fs_volname); 138110290Sgordon g_free(fs); 139110290Sgordon g_topology_unlock(); 140110290Sgordon break; 141110290Sgordon } 142110290Sgordon g_topology_lock(); 143125755Sphk g_access(cp, -1, 0, 0); 144110290Sgordon if (LIST_EMPTY(&gp->provider)) { 145114518Sphk g_slice_spoiled(cp); 146110290Sgordon return (NULL); 147110290Sgordon } 148110290Sgordon return (gp); 149110290Sgordon} 150110290Sgordon 151110290Sgordonstatic struct g_class g_vol_ffs_class = { 152112552Sphk .name = VOL_FFS_CLASS_NAME, 153133318Sphk .version = G_VERSION, 154112552Sphk .taste = g_vol_ffs_taste, 155110290Sgordon}; 156110290Sgordon 157110290SgordonDECLARE_GEOM_CLASS(g_vol_ffs_class, g_vol_ffs); 158