Deleted Added
full compact
vfs_mount.c (51388) vfs_mount.c (52778)
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