Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / sys / kern / vfs_conf.c
1 /*-
2  * Copyright (c) 1999 Michael Smith
3  * All rights reserved.
4  * Copyright (c) 1999 Poul-Henning Kamp
5  * All rights reserved.
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.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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  *
28  *      $FreeBSD: src/sys/kern/vfs_conf.c,v 1.49.2.5 2003/01/07 11:56:53 joerg Exp $
29  *      $DragonFly: src/sys/kern/vfs_conf.c,v 1.34 2008/05/24 19:08:28 dillon Exp $
30  */
31
32 /*
33  * Locate and mount the root filesystem.
34  *
35  * The root filesystem is detailed in the kernel environment variable
36  * vfs.root.mountfrom, which is expected to be in the general format
37  *
38  * <vfsname>:[<path>]
39  * vfsname   := the name of a VFS known to the kernel and capable
40  *              of being mounted as root
41  * path      := disk device name or other data used by the filesystem
42  *              to locate its physical store
43  *
44  */
45
46 #include "opt_rootdevname.h"
47
48 #include <sys/param.h>
49 #include <sys/kernel.h>
50 #include <sys/systm.h>
51 #include <sys/proc.h>
52 #include <sys/vnode.h>
53 #include <sys/mount.h>
54 #include <sys/malloc.h>
55 #include <sys/reboot.h>
56 #include <sys/diskslice.h>
57 #include <sys/conf.h>
58 #include <sys/cons.h>
59 #include <sys/device.h>
60 #include <sys/disk.h>
61 #include <sys/namecache.h>
62 #include <sys/paths.h>
63 #include <sys/thread2.h>
64 #include <sys/nlookup.h>
65 #include <vfs/devfs/devfs.h>
66
67 #include "opt_ddb.h"
68 #ifdef DDB
69 #include <ddb/ddb.h>
70 #endif
71
72 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
73
74 #define ROOTNAME        "root_device"
75
76 struct vnode    *rootvnode;
77 struct nchandle rootnch;
78
79 /* 
80  * The root specifiers we will try if RB_CDROM is specified.  Note that
81  * with DEVFS we do not use the compatibility slice's whole-disk 'c'
82  * partition.  Instead we just use the whole disk, e.g. cd0 or cd0s0.
83  */
84 static char *cdrom_rootdevnames[] = {
85         "cd9660:cd0",
86         "cd9660:acd0",
87         "cd9660:cd1",
88         "cd9660:acd1",
89         NULL
90 };
91
92 int vfs_mountroot_devfs(void);
93 static void     vfs_mountroot(void *junk);
94 static int      vfs_mountroot_try(const char *mountfrom);
95 static int      vfs_mountroot_ask(void);
96 static int      getline(char *cp, int limit);
97
98 /* legacy find-root code */
99 char            *rootdevnames[2] = {NULL, NULL};
100 static int      setrootbyname(char *name);
101
102 SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_SECOND, vfs_mountroot, NULL);
103         
104 /*
105  * Find and mount the root filesystem
106  */
107 static void
108 vfs_mountroot(void *junk)
109 {
110         int     i;
111         cdev_t  save_rootdev = rootdev;
112         
113         /*
114          * Make sure all disk devices created so far have also been probed,
115          * and also make sure that the newly created device nodes for
116          * probed disks are ready, too.
117          */
118         disk_config(NULL);
119         devfs_config();
120
121         /* 
122          * The root filesystem information is compiled in, and we are
123          * booted with instructions to use it.
124          */
125 #ifdef ROOTDEVNAME
126         if ((boothowto & RB_DFLTROOT) && 
127             !vfs_mountroot_try(ROOTDEVNAME))
128                 return;
129 #endif
130         /* 
131          * We are booted with instructions to prompt for the root filesystem,
132          * or to use the compiled-in default when it doesn't exist.
133          */
134         if (boothowto & (RB_DFLTROOT | RB_ASKNAME)) {
135                 if (!vfs_mountroot_ask())
136                         return;
137         }
138
139         /*
140          * We've been given the generic "use CDROM as root" flag.  This is
141          * necessary because one media may be used in many different
142          * devices, so we need to search for them.
143          */
144         if (boothowto & RB_CDROM) {
145                 for (i = 0; cdrom_rootdevnames[i] != NULL; i++) {
146                         if (!vfs_mountroot_try(cdrom_rootdevnames[i]))
147                                 return;
148                 }
149         }
150
151         /*
152          * Try to use the value read by the loader from /etc/fstab, or
153          * supplied via some other means.  This is the preferred 
154          * mechanism.
155          */
156         if (!vfs_mountroot_try(kgetenv("vfs.root.mountfrom")))
157                 return;
158
159         /*
160          * If a vfs set rootdev, try it (XXX VINUM HACK!)
161          */
162         if (save_rootdev != NULL) {
163                 rootdev = save_rootdev;
164                 if (!vfs_mountroot_try(""))
165                         return;
166         }
167
168         /* 
169          * Try values that may have been computed by the machine-dependant
170          * legacy code.
171          */
172         if (rootdevnames[0] && !vfs_mountroot_try(rootdevnames[0]))
173                 return;
174         if (rootdevnames[1] && !vfs_mountroot_try(rootdevnames[1]))
175                 return;
176
177         /*
178          * If we have a compiled-in default, and haven't already tried it, try
179          * it now.
180          */
181 #ifdef ROOTDEVNAME
182         if (!(boothowto & RB_DFLTROOT))
183                 if (!vfs_mountroot_try(ROOTDEVNAME))
184                         return;
185 #endif
186
187         /* 
188          * Everything so far has failed, prompt on the console if we haven't
189          * already tried that.
190          */
191         if (!(boothowto & (RB_DFLTROOT | RB_ASKNAME)) && !vfs_mountroot_ask())
192                 return;
193         panic("Root mount failed, startup aborted.");
194 }
195
196
197 int
198 vfs_mountroot_devfs(void)
199 {
200         struct vnode *vp;
201         struct nchandle nch;
202         struct nlookupdata nd;
203         struct mount *mp;
204         struct vfsconf *vfsp;
205         int error;
206         struct ucred *cred = proc0.p_ucred;
207
208         /*
209          * Lookup the requested path and extract the nch and vnode.
210          */
211         error = nlookup_init_raw(&nd,
212              "/dev", UIO_SYSSPACE, NLC_FOLLOW,
213              cred, &rootnch);
214
215         if (error == 0) {
216                 devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup_init is ok...\n");
217                 if ((error = nlookup(&nd)) == 0) {
218                         devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup is ok...\n");
219                         if (nd.nl_nch.ncp->nc_vp == NULL) {
220                                 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup: simply not found\n");
221                                 error = ENOENT;
222                         }
223                 }
224         }
225         if (error) {
226                 nlookup_done(&nd);
227                 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup failed, error: %d\n", error);
228                 return (error);
229         }
230
231         /*
232          * Extract the locked+refd ncp and cleanup the nd structure
233          */
234         nch = nd.nl_nch;
235         cache_zero(&nd.nl_nch);
236         nlookup_done(&nd);
237
238         /*
239          * now we have the locked ref'd nch and unreferenced vnode.
240          */
241         vp = nch.ncp->nc_vp;
242         if ((error = vget(vp, LK_EXCLUSIVE)) != 0) {
243                 cache_put(&nch);
244                 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vget failed\n");
245                 return (error);
246         }
247         cache_unlock(&nch);
248
249         if ((error = vinvalbuf(vp, V_SAVE, 0, 0)) != 0) {
250                 cache_drop(&nch);
251                 vput(vp);
252                 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vinvalbuf failed\n");
253                 return (error);
254         }
255         if (vp->v_type != VDIR) {
256                 cache_drop(&nch);
257                 vput(vp);
258                 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vp is not VDIR\n");
259                 return (ENOTDIR);
260         }
261
262         vfsp = vfsconf_find_by_name("devfs");
263         vp->v_flag |= VMOUNT;
264
265         /*
266          * Allocate and initialize the filesystem.
267          */
268         mp = kmalloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK);
269         TAILQ_INIT(&mp->mnt_nvnodelist);
270         TAILQ_INIT(&mp->mnt_reservedvnlist);
271         TAILQ_INIT(&mp->mnt_jlist);
272         mp->mnt_nvnodelistsize = 0;
273         lockinit(&mp->mnt_lock, "vfslock", 0, 0);
274         vfs_busy(mp, LK_NOWAIT);
275         mp->mnt_op = vfsp->vfc_vfsops;
276         mp->mnt_vfc = vfsp;
277         vfsp->vfc_refcount++;
278         mp->mnt_stat.f_type = vfsp->vfc_typenum;
279         mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
280         strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
281         mp->mnt_stat.f_owner = cred->cr_uid;
282         mp->mnt_iosize_max = DFLTPHYS;
283         vn_unlock(vp);
284
285         /*
286          * Mount the filesystem.
287          */
288         error = VFS_MOUNT(mp, "/dev", NULL, cred);
289
290         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
291
292         /*
293          * Put the new filesystem on the mount list after root.  The mount
294          * point gets its own mnt_ncmountpt (unless the VFS already set one
295          * up) which represents the root of the mount.  The lookup code
296          * detects the mount point going forward and checks the root of
297          * the mount going backwards.
298          *
299          * It is not necessary to invalidate or purge the vnode underneath
300          * because elements under the mount will be given their own glue
301          * namecache record.
302          */
303         if (!error) {
304                 if (mp->mnt_ncmountpt.ncp == NULL) {
305                         /*
306                          * allocate, then unlock, but leave the ref intact
307                          */
308                         cache_allocroot(&mp->mnt_ncmountpt, mp, NULL);
309                         cache_unlock(&mp->mnt_ncmountpt);
310                 }
311                 mp->mnt_ncmounton = nch;                /* inherits ref */
312                 nch.ncp->nc_flag |= NCF_ISMOUNTPT;
313
314                 /* XXX get the root of the fs and cache_setvp(mnt_ncmountpt...) */
315                 vp->v_flag &= ~VMOUNT;
316                 mountlist_insert(mp, MNTINS_LAST);
317                 vn_unlock(vp);
318                 //checkdirs(&mp->mnt_ncmounton, &mp->mnt_ncmountpt);
319                 error = vfs_allocate_syncvnode(mp);
320                 if (error) {
321                         devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vfs_allocate_syncvnode failed\n");
322                 }
323                 vfs_unbusy(mp);
324                 error = VFS_START(mp, 0);
325                 vrele(vp);
326         } else {
327                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_coherency_ops);
328                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_journal_ops);
329                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_norm_ops);
330                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_spec_ops);
331                 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_fifo_ops);
332                 vp->v_flag &= ~VMOUNT;
333                 mp->mnt_vfc->vfc_refcount--;
334                 vfs_unbusy(mp);
335                 kfree(mp, M_MOUNT);
336                 cache_drop(&nch);
337                 vput(vp);
338                 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: mount failed\n");
339         }
340
341         devfs_debug(DEVFS_DEBUG_DEBUG, "rootmount_devfs done with error: %d\n", error);
342         return (error);
343 }
344
345
346 /*
347  * Mount (mountfrom) as the root filesystem.
348  */
349 static int
350 vfs_mountroot_try(const char *mountfrom)
351 {
352         struct mount    *mp, *mp2;
353         char            *vfsname, *devname;
354         int             error;
355         char            patt[32];
356
357         vfsname = NULL;
358         devname = NULL;
359         mp      = NULL;
360         mp2             = NULL;
361         error   = EINVAL;
362
363         if (mountfrom == NULL)
364                 return(error);          /* don't complain */
365
366         crit_enter();
367         kprintf("Mounting root from %s\n", mountfrom);
368         crit_exit();
369
370         /* parse vfs name and devname */
371         vfsname = kmalloc(MFSNAMELEN, M_MOUNT, M_WAITOK);
372         devname = kmalloc(MNAMELEN, M_MOUNT, M_WAITOK);
373         vfsname[0] = devname[0] = 0;
374         ksprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN);
375         if (ksscanf(mountfrom, patt, vfsname, devname) < 1)
376                 goto done;
377
378         /* allocate a root mount */
379         error = vfs_rootmountalloc(vfsname, 
380                         devname[0] != 0 ? devname : ROOTNAME, &mp);
381         if (error != 0) {
382                 kprintf("Can't allocate root mount for filesystem '%s': %d\n",
383                        vfsname, error);
384                 goto done;
385         }
386         mp->mnt_flag |= MNT_ROOTFS;
387
388         /* do our best to set rootdev */
389         if ((devname[0] != 0) && setrootbyname(devname))
390                 kprintf("setrootbyname failed\n");
391
392         /* If the root device is a type "memory disk", mount RW */
393         if (rootdev != NULL && dev_is_good(rootdev) &&
394             (dev_dflags(rootdev) & D_MEMDISK)) {
395                 mp->mnt_flag &= ~MNT_RDONLY;
396         }
397
398         error = VFS_MOUNT(mp, NULL, NULL, proc0.p_ucred);
399
400         if (!error) {
401                 //kprintf("Trying vfs_mountroot_devfs!\n");
402                 //vfs_mountroot_devfs();
403         }
404
405 done:
406         if (vfsname != NULL)
407                 kfree(vfsname, M_MOUNT);
408         if (devname != NULL)
409                 kfree(devname, M_MOUNT);
410         if (error == 0) {
411                 /* register with list of mounted filesystems */
412                 mountlist_insert(mp, MNTINS_FIRST);
413
414                 /* sanity check system clock against root fs timestamp */
415                 inittodr(mp->mnt_time);
416                 vfs_unbusy(mp);
417                 if (mp->mnt_syncer == NULL) {
418                         error = vfs_allocate_syncvnode(mp);
419                         if (error)
420                                 kprintf("Warning: no syncer vp for root!\n");
421                         error = 0;
422                 }
423         } else {
424                 if (mp != NULL) {
425                         vfs_unbusy(mp);
426                         kfree(mp, M_MOUNT);
427                 }
428                 kprintf("Root mount failed: %d\n", error);
429         }
430         return(error);
431 }
432
433
434 static void vfs_mountroot_ask_callback(cdev_t);
435
436 /*
437  * Spin prompting on the console for a suitable root filesystem
438  */
439
440 static int
441 vfs_mountroot_ask(void)
442 {
443         char name[128];
444         int llimit = 100;
445
446         kprintf("\nManual root filesystem specification:\n");
447         kprintf("  <fstype>:<device>  Specify root (e.g. ufs:da0s1a)\n");
448         kprintf("  ?                  List valid disk boot devices\n");
449         kprintf("  panic              Just panic\n");
450         kprintf("  abort              Abort manual input\n");
451         while (llimit--) {
452                 kprintf("\nmountroot> ");
453
454                 if (getline(name, 128) < 0)
455                         break;
456                 if (name[0] == 0) {
457                         ;
458                 } else if (name[0] == '?') {
459                         kprintf("Possibly valid devices for root FS:\n");
460                         //enumerate all disk devices
461                         devfs_scan_callback(vfs_mountroot_ask_callback);
462                         kprintf("\n");
463                         continue;
464                 } else if (strcmp(name, "panic") == 0) {
465                         panic("panic from console");
466                 } else if (strcmp(name, "abort") == 0) {
467                         break;
468                 } else if (vfs_mountroot_try(name) == 0) {
469                         return(0);
470                 }
471         }
472         return(1);
473 }
474
475
476 static void
477 vfs_mountroot_ask_callback(cdev_t dev)
478 {
479         if (dev_is_good(dev) && (dev_dflags(dev) & D_DISK))
480                 kprintf(" \"%s\" ", dev->si_name);
481 }
482
483
484 static int
485 getline(char *cp, int limit)
486 {
487         char *lp;
488         int c;
489
490         lp = cp;
491         for (;;) {
492                 c = cngetc();
493
494                 switch (c) {
495                 case -1:
496                         return(-1);
497                 case '\n':
498                 case '\r':
499                         kprintf("\n");
500                         *lp++ = '\0';
501                         return(0);
502                 case '\b':
503                 case '\177':
504                         if (lp > cp) {
505                                 kprintf("\b \b");
506                                 lp--;
507                         } else {
508                                 kprintf("%c", 7);
509                         }
510                         continue;
511                 case '#':
512                         kprintf("#");
513                         lp--;
514                         if (lp < cp)
515                                 lp = cp;
516                         continue;
517                 case '@':
518                 case 'u' & 037:
519                         lp = cp;
520                         kprintf("%c", '\n');
521                         continue;
522                 default:
523                         if (lp - cp >= limit - 1) {
524                                 kprintf("%c", 7);
525                         } else {
526                                 kprintf("%c", c);
527                                 *lp++ = c;
528                         }
529                         continue;
530                 }
531         }
532 }
533
534 /*
535  * Convert a given name to the cdev_t of the disk-like device
536  * it refers to.
537  */
538 struct kdbn_info {
539         const char *name;
540         int nlen;
541         int minor;
542         cdev_t dev;
543 };
544
545
546 cdev_t
547 kgetdiskbyname(const char *name) 
548 {
549         char *cp;
550         cdev_t rdev;
551
552         /*
553          * Get the base name of the device
554          */
555         if (strncmp(name, __SYS_PATH_DEV, sizeof(__SYS_PATH_DEV) - 1) == 0)
556                 name += sizeof(__SYS_PATH_DEV) - 1;
557         cp = __DECONST(char *, name);
558
559         /*
560          * Locate the device
561          */
562         kprintf("tryroot %s\n", name);
563         rdev = devfs_find_device_by_name(name);
564         if (rdev == NULL) {
565                 kprintf("no disk named '%s'\n", name);
566         }
567         /*
568          * FOUND DEVICE
569          */
570         return(rdev);
571 }
572
573 /*
574  * Set rootdev to match (name), given that we expect it to
575  * refer to a disk-like device.
576  */
577 static int
578 setrootbyname(char *name)
579 {
580         cdev_t diskdev;
581
582         diskdev = kgetdiskbyname(name);
583         if (diskdev != NULL) {
584                 rootdev = diskdev;
585                 return (0);
586         }
587         /* set to NULL if kgetdiskbyname() fails so that if the first rootdev is
588          * found by fails to mount and the second one isn't found, mountroot_try
589          * doesn't try again with the first one
590          */
591         rootdev = NULL;
592         return (1);
593 }
594
595 #ifdef DDB
596 DB_SHOW_COMMAND(disk, db_getdiskbyname)
597 {
598         cdev_t dev;
599
600         if (modif[0] == '\0') {
601                 db_error("usage: show disk/devicename");
602                 return;
603         }
604         dev = kgetdiskbyname(modif);
605         if (dev != NULL)
606                 db_printf("cdev_t = %p\n", dev);
607         else
608                 db_printf("No disk device matched.\n");
609 }
610 #endif