diff options
author | 2007-05-04 03:44:41 +0000 | |
---|---|---|
committer | 2007-05-04 03:44:41 +0000 | |
commit | 7dc861ca7d5ad85aff399300ad2329522e4e56c5 (patch) | |
tree | e80d7fcc31d46566a75a418deb59bd0c392853e7 /sys/kern/subr_disk.c | |
parent | do not call vic_init() on ENETRESET in the ioctl handler, use (diff) | |
download | wireguard-openbsd-7dc861ca7d5ad85aff399300ad2329522e4e56c5.tar.xz wireguard-openbsd-7dc861ca7d5ad85aff399300ad2329522e4e56c5.zip |
setroot() was a ugly mix of MI and MD code, with different bugs on different
machines. Instead -- build one solid clean MI version, and thenchange all
the architectures to use it. ok various people, tested on almost all cases.
(it is a 10094 line diff..)
Diffstat (limited to 'sys/kern/subr_disk.c')
-rw-r--r-- | sys/kern/subr_disk.c | 267 |
1 files changed, 266 insertions, 1 deletions
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c index 9f42ca832fd..9f0836e9ea3 100644 --- a/sys/kern/subr_disk.c +++ b/sys/kern/subr_disk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_disk.c,v 1.34 2007/03/30 00:38:56 dlg Exp $ */ +/* $OpenBSD: subr_disk.c,v 1.35 2007/05/04 03:44:45 deraadt Exp $ */ /* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */ /* @@ -46,16 +46,20 @@ #include <sys/buf.h> #include <sys/stat.h> #include <sys/syslog.h> +#include <sys/device.h> #include <sys/time.h> #include <sys/disklabel.h> #include <sys/conf.h> #include <sys/lock.h> #include <sys/disk.h> +#include <sys/reboot.h> #include <sys/dkio.h> #include <sys/dkstat.h> /* XXX */ #include <sys/proc.h> +#include <uvm/uvm_extern.h> #include <dev/rndvar.h> +#include <dev/cons.h> /* * A global list of all disks attached to the system. May grow or @@ -548,3 +552,264 @@ bufq_default_get(struct bufq *bq) head->b_actf = bp->b_actf; return (bp); } + +#ifdef RAMDISK_HOOKS +static struct device fakerdrootdev = { DV_DISK, {}, NULL, 0, "rd0", NULL }; +#endif + +struct device * +getdisk(char *str, int len, int defpart, dev_t *devp) +{ + struct device *dv; + + if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { + printf("use one of: exit"); +#ifdef RAMDISK_HOOKS + printf(" %s[a-p]", fakerdrootdev.dv_xname); +#endif + TAILQ_FOREACH(dv, &alldevs, dv_list) { + if (dv->dv_class == DV_DISK) + printf(" %s[a-p]", dv->dv_xname); +#if defined(NFSCLIENT) + if (dv->dv_class == DV_IFNET) + printf(" %s", dv->dv_xname); +#endif + } + printf("\n"); + } + return (dv); +} + +struct device * +parsedisk(char *str, int len, int defpart, dev_t *devp) +{ + struct device *dv; + char *cp, c; + int majdev, part; + + if (len == 0) + return (NULL); + cp = str + len - 1; + c = *cp; + if (c >= 'a' && (c - 'a') < MAXPARTITIONS) { + part = c - 'a'; + *cp = '\0'; + } else + part = defpart; + +#ifdef RAMDISK_HOOKS + if (strcmp(str, fakerdrootdev.dv_xname) == 0) { + dv = &fakerdrootdev; + goto gotdisk; + } +#endif + + TAILQ_FOREACH(dv, &alldevs, dv_list) { + if (dv->dv_class == DV_DISK && + strcmp(str, dv->dv_xname) == 0) { +#ifdef RAMDISK_HOOKS +gotdisk: +#endif + majdev = findblkmajor(dv); + if (majdev < 0) + panic("parsedisk"); + *devp = MAKEDISKDEV(majdev, dv->dv_unit, part); + break; + } +#if defined(NFSCLIENT) + if (dv->dv_class == DV_IFNET && + strcmp(str, dv->dv_xname) == 0) { + *devp = NODEV; + break; + } +#endif + } + + *cp = c; + return (dv); +} + +void +setroot(struct device *bootdv, int part, int exitflags) +{ + int majdev, unit, len, s; + struct swdevt *swp; + struct device *rootdv, *dv; + dev_t nrootdev, nswapdev = NODEV, temp = NODEV; + char buf[128]; +#if defined(NFSCLIENT) + extern char *nfsbootdevname; +#endif + + if (boothowto & RB_DFLTROOT) + return; + +#ifdef RAMDISK_HOOKS + bootdv = &fakerdrootdev; + part = 0; +#endif + + /* + * If `swap generic' and we couldn't determine boot device, + * ask the user. + */ + if (mountroot == NULL && bootdv == NULL) + boothowto |= RB_ASKNAME; + if (boothowto & RB_ASKNAME) { + while (1) { + printf("root device"); + if (bootdv != NULL) { + printf(" (default %s", bootdv->dv_xname); + if (bootdv->dv_class == DV_DISK) + printf("%c", 'a' + part); + printf(")"); + } + printf(": "); + s = splhigh(); + cnpollc(TRUE); + len = getsn(buf, sizeof(buf)); + cnpollc(FALSE); + splx(s); + if (strcmp(buf, "exit") == 0) + boot(exitflags); + if (len == 0 && bootdv != NULL) { + strlcpy(buf, bootdv->dv_xname, sizeof buf); + len = strlen(buf); + } + if (len > 0 && buf[len - 1] == '*') { + buf[--len] = '\0'; + dv = getdisk(buf, len, part, &nrootdev); + if (dv != NULL) { + rootdv = dv; + nswapdev = nrootdev; + goto gotswap; + } + } + dv = getdisk(buf, len, part, &nrootdev); + if (dv != NULL) { + rootdv = dv; + break; + } + } + + if (rootdv->dv_class == DV_IFNET) + goto gotswap; + + /* try to build swap device out of new root device */ + while (1) { + printf("swap device"); + if (rootdv != NULL) + printf(" (default %s%s)", rootdv->dv_xname, + rootdv->dv_class == DV_DISK ? "b" : ""); + printf(": "); + s = splhigh(); + cnpollc(TRUE); + len = getsn(buf, sizeof(buf)); + cnpollc(FALSE); + splx(s); + if (strcmp(buf, "exit") == 0) + boot(exitflags); + if (len == 0 && rootdv != NULL) { + switch (rootdv->dv_class) { + case DV_IFNET: + nswapdev = NODEV; + break; + case DV_DISK: + nswapdev = MAKEDISKDEV(major(nrootdev), + DISKUNIT(nrootdev), 1); + if (nswapdev == nrootdev) + continue; + break; + default: + break; + } + break; + } + dv = getdisk(buf, len, 1, &nswapdev); + if (dv) { + if (dv->dv_class == DV_IFNET) + nswapdev = NODEV; + if (nswapdev == nrootdev) + continue; + break; + } + } +gotswap: + rootdev = nrootdev; + dumpdev = nswapdev; + swdevt[0].sw_dev = nswapdev; + swdevt[1].sw_dev = NODEV; +#if defined(NFSCLIENT) + } else if (mountroot == nfs_mountroot) { + rootdev = dumpdev = swapdev = NODEV; +#endif + } else if (mountroot == NULL) { + /* `swap generic': Use the device the ROM told us to use */ + rootdv = bootdv; + majdev = findblkmajor(rootdv); + if (majdev >= 0) { + /* + * Root and swap are on the disk. + * Assume swap is on partition b. + */ + rootdev = MAKEDISKDEV(majdev, rootdv->dv_unit, part); + nswapdev = MAKEDISKDEV(majdev, rootdv->dv_unit, 1); + dumpdev = nswapdev; + } else { + /* + * Root and swap are on a net. + */ + nswapdev = dumpdev = NODEV; + } + swdevt[0].sw_dev = nswapdev; + /* swdevt[1].sw_dev = NODEV; */ + } else { + /* Completely pre-configured, but we want rootdv .. */ + majdev = major(rootdev); + if (findblkname(majdev) == NULL) + return; + unit = DISKUNIT(rootdev); + part = DISKPART(rootdev); + snprintf(buf, sizeof buf, "%s%d%c", + findblkname(majdev), unit, 'a' + part); + rootdv = parsedisk(buf, strlen(buf), 0, &nrootdev); + } + + switch (rootdv->dv_class) { +#if defined(NFSCLIENT) + case DV_IFNET: + mountroot = nfs_mountroot; + nfsbootdevname = rootdv->dv_xname; + return; +#endif + case DV_DISK: + mountroot = dk_mountroot; + part = DISKPART(rootdev); + printf("root on %s%c\n", rootdv->dv_xname, 'a' + part); + break; + default: + printf("can't figure root, hope your kernel is right\n"); + return; + } + + /* + * Make the swap partition on the root drive the primary swap. + */ + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (major(rootdev) == major(swp->sw_dev) && + DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) { + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev != NODEV) { + /* + * If dumpdev was the same as the old primary swap device, + * move it to the new primary swap device. + */ + if (temp == dumpdev) + dumpdev = swdevt[0].sw_dev; + } +} |