1/* 2 * Copyright (c) 1989, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1995 Artisoft, Inc. All Rights Reserved.
| 1/*- 2 * Copyright (c) 1999 Michael Smith 3 * All rights reserved. 4 * Copyright (c) 1999 Poul-Henning Kamp 5 * All rights reserved.
|
5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution.
| 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution.
|
14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission.
| |
21 *
| 15 *
|
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
| 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
| 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
| 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 *
| 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 *
|
34 * @(#)vfs_conf.c 8.8 (Berkeley) 3/31/94 35 * $FreeBSD: head/sys/kern/vfs_mount.c 51388 1999-09-19 06:24:21Z dillon $
| 28 * $FreeBSD: head/sys/kern/vfs_mount.c 52778 1999-11-01 23:51:00Z msmith $
|
36 */ 37 38/*
| 29 */ 30 31/*
|
39 * PURPOSE: This file abstracts the root mounting interface from 40 * the per file system semantics for handling mounts, 41 * the overall intent of which is to move the BSD 42 * internals dependence out of the FS code, both to 43 * make the FS code more portable and to free up some 44 * of the BSD internals so that they may more easily 45 * be changed.
| 32 * Locate and mount the root filesystem.
|
46 *
| 33 *
|
47 * NOTE1: Code is single entry/single exit to aid debugging 48 * and conversion for kernel multithreading.
| 34 * The root filesystem is detailed in the kernel environment variable 35 * vfs.root.mountfrom, which is expected to be in the general format
|
49 *
| 36 *
|
50 * NOTE2: Code notes lock state in headers on entry and exit 51 * as an aid to conversion for kernel multithreading 52 * on SMP reentrancy
| 37 * <vfsname>:[<path>] 38 * vfsname := the name of a VFS known to the kernel and capable 39 * of being mounted as root 40 * path := disk device name or other data used by the filesystem 41 * to locate its physical store 42 *
|
53 */
| 43 */
|
54#include "opt_bootp.h"
| |
55
| 44
|
56#include <sys/param.h> /* dev_t (types.h)*/
| 45#include
|
57#include <sys/kernel.h>
| 46#include <sys/kernel.h>
|
58#include <sys/systm.h> /* rootvp*/ 59#include <sys/proc.h> /* curproc*/ 60#include <sys/vnode.h> /* NULLVP*/ 61#include <sys/mount.h> /* struct mount*/ 62#include <sys/malloc.h> /* M_MOUNT*/
| 47#include 48#include 49#include 50#include 51#include 52#include <sys/reboot.h> 53#include <sys/diskslice.h> 54#include <sys/disklabel.h> 55#include <sys/conf.h> 56#include <sys/cons.h>
|
63
| 57
|
64/* 65 * GLOBALS 66 */
| 58MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
|
67
| 59
|
68MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
| 60#define ROOTNAME "root_device"
|
69
| 61
|
70/* 71 * These define the root filesystem, device, and root filesystem type. 72 */ 73dev_t rootdevs[] = { NODEV, NODEV }; 74char *rootdevnames[2]; 75struct vnode *rootvnode; 76char *mountrootfsname; 77#ifdef BOOTP 78extern void bootpc_init __P((void)); 79#endif
| 62struct vnode *rootvnode;
|
80
| 63
|
81/* 82 * vfs_init() will set maxvfsconf 83 * to the highest defined type number. 84 */ 85int maxvfsconf; 86struct vfsconf *vfsconf;
| 64static void vfs_mountroot(void *junk); 65static int vfs_mountroot_try(char *mountfrom); 66static int vfs_mountroot_ask(void); 67static void gets(char *cp);
|
87
| 68
|
88/* 89 * Common root mount code shared by all filesystems 90 */ 91#define ROOTNAME "root_device"
| 69/* legacy find-root code */ 70char *rootdevnames[2] = {NULL, NULL}; 71static int setrootbyname(char *name);
|
92
| 72
|
| 73SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, vfs_mountroot, NULL); 74
|
93/*
| 75/*
|
94 * vfs_mountrootfs 95 * 96 * Common entry point for root mounts 97 * 98 * PARAMETERS: 99 * NONE 100 * 101 * RETURNS: 0 Success 102 * !0 error number (errno.h) 103 * 104 * LOCK STATE: 105 * ENTRY 106 * <no locks held> 107 * EXIT 108 * <no locks held> 109 * 110 * NOTES: 111 * This code is currently supported only for use for 112 * the FFS file system type. This is a matter of 113 * fixing the other file systems, not this code!
| 76 * Find and mount the root filesystem
|
114 */ 115static void
| 77 */ 78static void
|
116vfs_mountrootfs(void *unused)
| 79vfs_mountroot(void *junk)
|
117{
| 80{
|
118 struct mount *mp; 119 int err; 120 struct proc *p = curproc; /* XXX */ 121 int s; 122 int i; 123 dev_t orootdev; 124 125#ifdef BOOTP 126 bootpc_init();
| 81 /* 82 * The root filesystem information is compiled in, and we are 83 * booted with instructions to use it. 84 */ 85#ifdef ROOTDEVNAME 86 if ((boothowto & RB_DFLTROOT) && 87 !vfs_mountroot_try(ROOTDEVNAME)) 88 return;
|
127#endif
| 89#endif
|
128 /* 129 * New root mount structure
| 90 /* 91 * We are booted with instructions to prompt for the root filesystem, 92 * or to use the compiled-in default when it doesn't exist.
|
130 */
| 93 */
|
131 if ((err = vfs_rootmountalloc(mountrootfsname, ROOTNAME, &mp))) { 132 printf("rootdev=%p error=%d, ", (void *)rootdev, err); 133 panic("cannot mount root\n"); 134 return ;
| 94 if (boothowto & (RB_DFLTROOT | RB_ASKNAME)) { 95 if (!vfs_mountroot_ask()) 96 return;
|
135 }
| 97 }
|
136 mp->mnt_flag |= MNT_ROOTFS;
| |
137 138 /*
| 98 99 /*
|
139 * If we have no idea what the device is because the VFS root mount 140 * initialization code couldn't figure it out, take a guess by 141 * assuming that vfs_getnewfsid() will be called when we try the 142 * mount. For the moment this is necessary for NFS-baesd BOOTP 143 * boots. Ultimately we would like to get rid of 'rootdev' entirely 144 * and go with a linked list of possible roots and device-specific 145 * auxillary data that we do not try to interpret ourselves.
| 100 * Try to use the value read by the loader from /etc/fstab, or 101 * supplied via some other means. This is the preferred 102 * mechanism.
|
146 */
| 103 */
|
147 if (rootdev == NODEV && rootdevs[0] == NODEV) 148 rootdev = vfs_getrootfsid(mp);
| 104 if (!vfs_mountroot_try(getenv("vfs.root.mountfrom"))) 105 return;
|
149
| 106
|
| 107 /* 108 * Try values that may have been computed by the machine-dependant 109 * legacy code. 110 */ 111 if (!vfs_mountroot_try(rootdevnames[0])) 112 return; 113 if (!vfs_mountroot_try(rootdevnames[1])) 114 return; 115
|
150 /*
| 116 /*
|
151 * Attempt the mount. This is rather messy due to many historical 152 * layers. Basically what it comes down to is that 'rootdev' is an 153 * override to the rootdevs[] array. The rootdevs[] array itself 154 * cannot normally be accessed directly by other modules, but FFS 155 * plays with it. NFS, on the otherhand, has no clue what the 156 * device assignment for a mount will be until it actually does it. 157 * 158 * During the loop we set rootdev to rootdevs[i]. This is used 159 * by FFS and a few other modules. It is ignored by NFS.
| 117 * If we have a compiled-in default, and haven't already tried it, try 118 * it now.
|
160 */
| 119 */
|
161 err = ENXIO; 162 orootdev = rootdev; 163 if (rootdevs[0] == NODEV) 164 rootdevs[0] = rootdev; 165 for (i = 0; i < sizeof(rootdevs) / sizeof(rootdevs[0]); i++) { 166 if (rootdevs[i] == NODEV) 167 break; 168 rootdev = rootdevs[i]; 169 if (rootdev != orootdev) { 170 s = splbio(); /* Overkill, but harmless.. */ 171 printf("changing root device to %s\n", rootdevnames[i]); 172 splx(s); 173 orootdev = rootdev; 174 } 175 strncpy(mp->mnt_stat.f_mntfromname, 176 rootdevnames[i] ? rootdevnames[i] : ROOTNAME, MNAMELEN - 1); 177 err = VFS_MOUNT(mp, NULL, NULL, NULL, p); 178 if (err != ENXIO) 179 break; 180 } 181 if (err) { 182 /* 183 * XXX should ask the user for the name in some cases. 184 * Why do we call vfs_unbusy() here and not after ENXIO 185 * is returned above? 186 */ 187 vfs_unbusy(mp, p); 188 /* 189 * free mount struct before failing 190 * (hardly worthwhile with the PANIC eh?) 191 */ 192 free( mp, M_MOUNT); 193 printf("rootdev=%p error=%d, ", (void *)rootdev, err); 194 panic("cannot mount root (2)\n");
| 120#ifdef ROOTDEVNAME 121 if (!(boothowto & RB_DFLTROOT)) 122 !vfs_mountroot_try(ROOTDEVNAME))
|
195 return;
| 123 return;
|
| 124#endif 125 126 /* 127 * Everything so far has failed, prompt on the console if we haven't 128 * already tried that. 129 */ 130 if (!(boothowto & (RB_DFLTROOT | RB_ASKNAME)) && !vfs_mountroot_ask()) 131 return; 132 panic("Root mount failed, startup aborted."); 133} 134 135/* 136 * Mount (mountfrom) as the root filesystem. 137 */ 138static int 139vfs_mountroot_try(char *mountfrom) 140{ 141 struct mount *mp; 142 char *vfsname, *path; 143 int error; 144 char patt[16]; 145 146 vfsname = path = NULL; 147 error = EINVAL; 148 149 if (mountfrom == NULL) 150 goto done; 151 152 printf("Mounting root from %s\n", mountfrom); 153 154 /* parse vfs name and path */ 155 vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK); 156 path = malloc(MNAMELEN, M_MOUNT, M_WAITOK); 157 sprintf(patt, "%%%d[a-z]:%%%ds", MFSNAMELEN, MNAMELEN); 158 if (sscanf(mountfrom, patt, vfsname, path) != 2) 159 goto done; 160 161 /* allocate a root mount */ 162 if ((error = vfs_rootmountalloc(vfsname, ROOTNAME, &mp))) { 163 printf("Can't allocate root mount for filesystem '%s': %d\n", 164 vfsname, error); 165 goto done;
|
196 }
| 166 }
|
| 167 mp->mnt_flag |= MNT_ROOTFS;
|
197
| 168
|
198 simple_lock(&mountlist_slock);
| 169 /* do our best to set rootdev */ 170 if (setrootbyname(path)) 171 printf("setrootbyname failed\n");
|
199
| 172
|
200 /* 201 * Add fs to list of mounted file systems 202 */ 203 CIRCLEQ_INSERT_HEAD(&mountlist, mp, mnt_list);
| 173 strcpy(mp->mnt_stat.f_mntfromname, path); 174 error = VFS_MOUNT(mp, NULL, NULL, NULL, curproc);
|
204
| 175
|
205 simple_unlock(&mountlist_slock); 206 vfs_unbusy(mp, p);
| 176done: 177 free(vfsname, M_MOUNT); 178 free(path, M_MOUNT); 179 if (error != 0) { 180 if (mp != NULL) 181 free(mp, M_MOUNT); 182 printf("Root mount failed: %d\n", error); 183 } else {
|
207
| 184
|
208 /* root mount, update system time from FS specific data*/ 209 inittodr(mp->mnt_time); 210 return;
| 185 /* register with list of mounted filesystems */ 186 simple_lock(&mountlist_slock); 187 CIRCLEQ_INSERT_HEAD(&mountlist, mp, mnt_list); 188 simple_unlock(&mountlist_slock); 189 190 /* sanity check system clock against root filesystem timestamp */ 191 inittodr(mp->mnt_time); 192 } 193 vfs_unbusy(mp, curproc); 194 return(error);
|
211} 212
| 195} 196
|
213SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, vfs_mountrootfs, NULL)
| 197/* 198 * Spin prompting on the console for a suitable root filesystem 199 */ 200static int 201vfs_mountroot_ask(void) 202{ 203 char name[128]; 204 int i; 205 dev_t dev;
|
214
| 206
|
| 207 for(;;) { 208 printf("\nManual root filesystem specification:\n"); 209 printf(" <fstype>:<device> Mount <device> using filesystem <fstype>\n"); 210 printf(" eg. ufs:/dev/da0s1a\n"); 211 printf(" ? List valid disk boot devices\n"); 212 printf(" <empty line> Abort manual input\n"); 213 printf("\n>>> "); 214 gets(name); 215 if (name[0] == 0) 216 return(1); 217 if (name[0] == '?') { 218 printf("Possibly valid devices for 'ufs' root:\n"); 219 for (i = 0; i < NUMCDEVSW; i++) { 220 dev = makebdev(i, 0); 221 if (devsw(dev) != NULL) 222 printf(" \"%s\"", devsw(dev)->d_name); 223 } 224 printf("\n"); 225 continue; 226 } 227 if (!vfs_mountroot_try(name)) 228 return(0); 229 } 230} 231 232static void 233gets(char *cp) 234{ 235 char *lp; 236 int c; 237 238 lp = cp; 239 for (;;) { 240 printf("%c", c = cngetc() & 0177); 241 switch (c) { 242 case -1: 243 case '\n': 244 case '\r': 245 *lp++ = '\0'; 246 return; 247 case '\b': 248 case '\177': 249 if (lp > cp) { 250 printf(" \b"); 251 lp--; 252 } 253 continue; 254 case '#': 255 lp--; 256 if (lp < cp) 257 lp = cp; 258 continue; 259 case '@': 260 case 'u' & 037: 261 lp = cp; 262 printf("%c", '\n'); 263 continue; 264 default: 265 *lp++ = c; 266 } 267 } 268} 269 270/* 271 * Set rootdev to match (name), given that we expect it to 272 * refer to a disk-like device. 273 */ 274static int 275setrootbyname(char *name) 276{ 277 char *cp; 278 int bd, unit, slice, part; 279 dev_t dev; 280 281 slice = 0; 282 part = 0; 283 cp = rindex(name, '/'); 284 if (cp != NULL) { 285 name = cp + 1; 286 } 287 cp = name; 288 while (cp != '\0' && (*cp < '0' || *cp > '9')) 289 cp++; 290 if (cp == name) { 291 printf("missing device name\n"); 292 return(1); 293 } 294 if (*cp == '\0') { 295 printf("missing unit number\n"); 296 return(1); 297 } 298 unit = *cp - '0'; 299 *cp++ = '\0'; 300 for (bd = 0; bd < NUMCDEVSW; bd++) { 301 dev = makebdev(bd, 0); 302 if (devsw(dev) != NULL && 303 strcmp(devsw(dev)->d_name, name) == 0) 304 goto gotit; 305 } 306 printf("no such device '%s'\n", name); 307 return (2); 308gotit: 309 while (*cp >= '0' && *cp <= '9') 310 unit += 10 * unit + *cp++ - '0'; 311 if (*cp == 's' && cp[1] >= '0' && cp[1] <= '9') { 312 slice = cp[1] - '0' + 1; 313 cp += 2; 314 } 315 if (*cp >= 'a' && *cp <= 'h') { 316 part = *cp - 'a'; 317 cp++; 318 } 319 if (*cp != '\0') { 320 printf("junk after name\n"); 321 return (1); 322 } 323 rootdev = makebdev(bd, dkmakeminor(unit, slice, part)); 324 return 0; 325} 326
|
| |