summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2018-08-31 12:00:34 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2018-08-31 12:00:34 +0000
commit9b5d9abaa7ded12c3da31ba5f2c72f97a2e40fec (patch)
treebca29bcf06b0cbd7794971c49581f631965c604c /usr/src
parent6e567b7bf9c30262784d63ef8e2ad150be55b6c1 (diff)
parent45bf502ff96d3c90215cf16c25a80d757f276431 (diff)
downloadillumos-joyent-9b5d9abaa7ded12c3da31ba5f2c72f97a2e40fec.tar.gz
[illumos-gate merge]
commit 45bf502ff96d3c90215cf16c25a80d757f276431 9720 kernel: support for booting with cpio-based boot_archive commit 82f63c3c2bf5e4378706e8dcfccf717d67371be9 9700 ZFS resilvered mirror does not balance reads
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/pkg/manifests/system-kernel-platform.mf2
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c5
-rw-r--r--usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio15
-rw-r--r--usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio.descrip1
-rw-r--r--usr/src/uts/common/krtld/bootrd.c10
-rw-r--r--usr/src/uts/common/krtld/bootrd_cpio.c484
-rw-r--r--usr/src/uts/intel/Makefile.files3
7 files changed, 516 insertions, 4 deletions
diff --git a/usr/src/pkg/manifests/system-kernel-platform.mf b/usr/src/pkg/manifests/system-kernel-platform.mf
index f0e584041f..5b21578e0b 100644
--- a/usr/src/pkg/manifests/system-kernel-platform.mf
+++ b/usr/src/pkg/manifests/system-kernel-platform.mf
@@ -1140,6 +1140,8 @@ license usr/src/cmd/mdb/common/libstand/THIRDPARTYLICENSE \
license usr/src/common/bzip2/LICENSE license=usr/src/common/bzip2/LICENSE
$(sparc_ONLY)license usr/src/stand/lib/tcp/THIRDPARTYLICENSE \
license=usr/src/stand/lib/tcp/THIRDPARTYLICENSE
+license usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio \
+ license=usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio
license usr/src/uts/common/sys/THIRDPARTYLICENSE.unicode \
license=usr/src/uts/common/sys/THIRDPARTYLICENSE.unicode
license usr/src/uts/common/zmod/THIRDPARTYLICENSE \
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index b71710bbd7..599ae9fade 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -27,7 +27,7 @@
* Copyright 2013 Saso Kiselkov. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Toomas Soome <tsoome@me.com>
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2018 Joyent, Inc.
* Copyright (c) 2017 Datto Inc.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -6535,6 +6535,7 @@ spa_vdev_resilver_done_hunt(vdev_t *vd)
/*
* Check for a completed resilver with the 'unspare' flag set.
+ * Also potentially update faulted state.
*/
if (vd->vdev_ops == &vdev_spare_ops) {
vdev_t *first = vd->vdev_child[0];
@@ -6556,6 +6557,8 @@ spa_vdev_resilver_done_hunt(vdev_t *vd)
!vdev_dtl_required(oldvd))
return (oldvd);
+ vdev_propagate_state(vd);
+
/*
* If there are more than two spares attached to a disk,
* and those spares are not required, then we want to
diff --git a/usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio b/usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio
new file mode 100644
index 0000000000..c6305a38ed
--- /dev/null
+++ b/usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2011-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio.descrip b/usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio.descrip
new file mode 100644
index 0000000000..c37afc6e5f
--- /dev/null
+++ b/usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio.descrip
@@ -0,0 +1 @@
+bootrd_cpio
diff --git a/usr/src/uts/common/krtld/bootrd.c b/usr/src/uts/common/krtld/bootrd.c
index 35ad67da96..91d9d863be 100644
--- a/usr/src/uts/common/krtld/bootrd.c
+++ b/usr/src/uts/common/krtld/bootrd.c
@@ -37,12 +37,14 @@
extern void (*_kobj_printf)(void *, const char *fmt, ...);
extern int get_weakish_int(int *);
extern struct bootops *ops;
-extern struct boot_fs_ops bufs_ops, bhsfs_ops, bbootfs_ops;
+extern struct boot_fs_ops bufs_ops, bhsfs_ops, bbootfs_ops, bcpio_ops;
extern int kmem_ready;
static uint64_t rd_start, rd_end;
struct boot_fs_ops *bfs_ops;
-struct boot_fs_ops *bfs_tab[] = {&bufs_ops, &bhsfs_ops, &bbootfs_ops, NULL};
+struct boot_fs_ops *bfs_tab[] = {
+ &bufs_ops, &bhsfs_ops, &bbootfs_ops, &bcpio_ops, NULL,
+};
static uintptr_t scratch_max = 0;
@@ -176,11 +178,15 @@ kobj_boot_mountroot()
"ramdisk range: 0x%llx-%llx\n", rd_start, rd_end);
#endif
+ /*
+ * We have a range of virtual addresses which are the boot archive.
+ */
for (i = 0; bfs_tab[i] != NULL; i++) {
bfs_ops = bfs_tab[i];
if (BRD_MOUNTROOT(bfs_ops, "dummy") == 0)
return (0);
}
+
_kobj_printf(ops, "failed to mount ramdisk from boot\n");
return (-1);
}
diff --git a/usr/src/uts/common/krtld/bootrd_cpio.c b/usr/src/uts/common/krtld/bootrd_cpio.c
new file mode 100644
index 0000000000..01d3348022
--- /dev/null
+++ b/usr/src/uts/common/krtld/bootrd_cpio.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright 2011-2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stdbool.h>
+#include <sys/sysmacros.h>
+#include <sys/bootvfs.h>
+#include <sys/filep.h>
+#include <sys/sunddi.h>
+#include <sys/ccompile.h>
+#include <sys/queue.h>
+
+/*
+ * A cpio archive is just a sequence of files, each consisting of a header
+ * (struct cpio_hdr) and the file contents.
+ */
+
+struct cpio_hdr {
+ uint8_t magic[6];
+ uint8_t dev[6];
+ uint8_t ino[6];
+ uint8_t mode[6];
+ uint8_t uid[6];
+ uint8_t gid[6];
+ uint8_t nlink[6];
+ uint8_t rdev[6];
+ uint8_t mtime[11];
+ uint8_t namesize[6];
+ uint8_t filesize[11];
+ char data[];
+};
+
+/*
+ * This structure represents an open file. The list of all open files is
+ * rooted in the open_files global.
+ */
+struct cpio_file {
+ /* pointers into the archive */
+ const struct cpio_hdr *hdr;
+ const char *path; /* pointer into the archive */
+ const void *data; /* pointer into the archive */
+
+ int fd;
+ off_t off;
+ struct bootstat stat;
+
+ SLIST_ENTRY(cpio_file) next;
+};
+
+extern void *bkmem_alloc(size_t);
+extern void bkmem_free(void *, size_t);
+
+static void cpio_closeall(int flag);
+
+static bool mounted;
+static SLIST_HEAD(cpio_file_list, cpio_file)
+ open_files = SLIST_HEAD_INITIALIZER(open_files);
+
+static int
+cpio_strcmp(const char *a, const char *b)
+{
+ while ((*a != '\0') && (*b != '\0') && (*a == *b)) {
+ a++;
+ b++;
+ }
+
+ if (*a == *b)
+ return (0);
+ if (*a < *b)
+ return (-1);
+ return (1);
+}
+
+/*
+ * Returns the parsed number on success, or UINT64_MAX on error. This is
+ * ok because we will never deal with numbers that large in a cpio archive.
+ */
+static uint64_t
+__get_uint64(const uint8_t *str, size_t len, const size_t output_size)
+{
+ uint64_t v;
+
+ /* check that we can represent every number */
+ if (len * 3 > output_size)
+ return (UINT64_MAX);
+
+ for (v = 0; len > 0; len--, str++) {
+ const uint8_t c = *str;
+
+ if ((c < '0') || (c > '7'))
+ return (UINT64_MAX);
+
+ v = (v * 8) + (c - '0');
+ }
+
+ return (v);
+}
+
+static bool
+get_uint64(const uint8_t *str, size_t len, uint64_t *out)
+{
+ *out = __get_uint64(str, len, NBBY * sizeof (*out));
+ return (*out != UINT64_MAX);
+}
+
+static bool
+get_int64(const uint8_t *str, size_t len, int64_t *out)
+{
+ uint64_t tmp;
+
+ tmp = __get_uint64(str, len, NBBY * sizeof (*out) - 1);
+
+ *out = tmp;
+
+ return (tmp != UINT64_MAX);
+}
+
+static bool
+get_uint32(const uint8_t *str, size_t len, uint32_t *out)
+{
+ uint64_t tmp;
+
+ tmp = __get_uint64(str, len, NBBY * sizeof (*out));
+
+ *out = tmp;
+
+ return (tmp != UINT64_MAX);
+}
+
+static bool
+get_int32(const uint8_t *str, size_t len, int32_t *out)
+{
+ uint64_t tmp;
+
+ tmp = __get_uint64(str, len, NBBY * sizeof (*out) - 1);
+
+ *out = tmp;
+
+ return (tmp != UINT64_MAX);
+}
+
+static void
+add_open_file(struct cpio_file *file)
+{
+ SLIST_INSERT_HEAD(&open_files, file, next);
+}
+
+static void
+remove_open_file(struct cpio_file *file)
+{
+ SLIST_REMOVE(&open_files, file, cpio_file, next);
+}
+
+static struct cpio_file *
+find_open_file(int fd)
+{
+ struct cpio_file *file;
+
+ if (fd < 0)
+ return (NULL);
+
+ SLIST_FOREACH(file, &open_files, next)
+ if (file->fd == fd)
+ return (file);
+
+ return (NULL);
+}
+
+static const void *
+read_ramdisk(size_t off, size_t len)
+{
+ const size_t first_block_offset = off % DEV_BSIZE;
+ fileid_t tmpfile;
+
+ /* return a dummy non-NULL pointer */
+ if (len == 0)
+ return ("");
+
+ /* we have to read the stuff before the desired location as well */
+ len += first_block_offset;
+
+ tmpfile.fi_blocknum = off / DEV_BSIZE;
+ tmpfile.fi_count = P2ROUNDUP_TYPED(len, DEV_BSIZE, size_t);
+ tmpfile.fi_memp = NULL;
+
+ if (diskread(&tmpfile) != 0)
+ return (NULL);
+
+ return (tmpfile.fi_memp + first_block_offset);
+}
+
+static bool
+parse_stat(const struct cpio_hdr *hdr, struct bootstat *stat)
+{
+ if (!get_uint64(hdr->dev, sizeof (hdr->dev), &stat->st_dev))
+ return (false);
+ if (!get_uint64(hdr->ino, sizeof (hdr->ino), &stat->st_ino))
+ return (false);
+ if (!get_uint32(hdr->mode, sizeof (hdr->mode), &stat->st_mode))
+ return (false);
+ if (!get_int32(hdr->uid, sizeof (hdr->uid), &stat->st_uid))
+ return (false);
+ if (!get_int32(hdr->gid, sizeof (hdr->gid), &stat->st_gid))
+ return (false);
+ if (!get_uint32(hdr->nlink, sizeof (hdr->nlink), &stat->st_nlink))
+ return (false);
+ if (!get_uint64(hdr->rdev, sizeof (hdr->rdev), &stat->st_rdev))
+ return (false);
+
+ stat->st_mtim.tv_nsec = 0;
+ if (!get_int64(hdr->mtime, sizeof (hdr->mtime), &stat->st_mtim.tv_sec))
+ return (false);
+
+ stat->st_atim = stat->st_mtim;
+ stat->st_ctim = stat->st_mtim;
+
+ if (!get_uint64(hdr->filesize, sizeof (hdr->filesize), &stat->st_size))
+ return (false);
+
+ stat->st_blksize = DEV_BSIZE;
+ stat->st_blocks = P2ROUNDUP(stat->st_size, DEV_BSIZE);
+
+ return (true);
+}
+
+/*
+ * Check if specified header is for a file with a specific path. If so,
+ * fill in the file struct and return 0. If not, return number of bytes to
+ * skip over to get to the next header. If an error occurs, -1 is returned.
+ * If end of archive is reached, return -2 instead.
+ */
+static ssize_t
+scan_archive_hdr(const struct cpio_hdr *hdr, size_t off,
+ struct cpio_file *file, const char *wanted_path)
+{
+ struct bootstat stat;
+ uint32_t namesize;
+ uint64_t filesize;
+ const char *path;
+ const void *data;
+
+ if ((hdr->magic[0] != '0') || (hdr->magic[1] != '7') ||
+ (hdr->magic[2] != '0') || (hdr->magic[3] != '7') ||
+ (hdr->magic[4] != '0') || (hdr->magic[5] != '7'))
+ return (-1);
+
+ if (!get_uint32(hdr->namesize, sizeof (hdr->namesize), &namesize))
+ return (-1);
+ if (!get_uint64(hdr->filesize, sizeof (hdr->filesize), &filesize))
+ return (-1);
+
+ /*
+ * We have the two sizes, let's try to read the name and file
+ * contents to make sure they are part of the ramdisk.
+ */
+
+ off += offsetof(struct cpio_hdr, data[0]);
+ path = read_ramdisk(off, namesize);
+ data = read_ramdisk(off + namesize, filesize);
+
+ /* either read failing is fatal */
+ if (path == NULL || data == NULL)
+ return (-1);
+
+ if (cpio_strcmp(path, "TRAILER!!!") == 0)
+ return (-2);
+
+ if (cpio_strcmp(path, wanted_path) != 0)
+ return (offsetof(struct cpio_hdr, data[namesize + filesize]));
+
+ /*
+ * This is the file we want!
+ */
+
+ if (!parse_stat(hdr, &stat))
+ return (-1);
+
+ file->hdr = hdr;
+ file->path = path;
+ file->data = data;
+ file->stat = stat;
+
+ return (0);
+}
+
+static int
+find_filename(char *path, struct cpio_file *file)
+{
+ size_t off;
+
+ /*
+ * The paths in the cpio boot archive omit the leading '/'. So,
+ * skip checking for it. If the searched for path does not include
+ * the leading path (it's a relative path), fail the lookup.
+ */
+ if (path[0] != '/')
+ return (-1);
+
+ path++;
+
+ /* now scan the archive for the relevant file */
+
+ off = 0;
+
+ for (;;) {
+ const struct cpio_hdr *hdr;
+ ssize_t size;
+
+ hdr = read_ramdisk(off, sizeof (struct cpio_hdr));
+ if (hdr == NULL)
+ return (-1);
+
+ size = scan_archive_hdr(hdr, off, file, path);
+ if (size <= 0)
+ return (size);
+
+ off += size;
+ }
+}
+
+/* ARGSUSED */
+static int
+bcpio_mountroot(char *str __unused)
+{
+ if (mounted)
+ return (-1);
+
+ mounted = true;
+
+ return (0);
+}
+
+static int
+bcpio_unmountroot(void)
+{
+ if (!mounted)
+ return (-1);
+
+ mounted = false;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+bcpio_open(char *path, int flags __unused)
+{
+ static int filedes = 1;
+ struct cpio_file temp_file;
+ struct cpio_file *file;
+
+ if (find_filename(path, &temp_file) != 0)
+ return (-1);
+
+ file = bkmem_alloc(sizeof (struct cpio_file));
+ file->hdr = temp_file.hdr;
+ file->path = temp_file.path;
+ file->data = temp_file.data;
+ file->stat = temp_file.stat;
+ file->fd = filedes++;
+ file->off = 0;
+
+ add_open_file(file);
+
+ return (file->fd);
+}
+
+static int
+bcpio_close(int fd)
+{
+ struct cpio_file *file;
+
+ file = find_open_file(fd);
+ if (file == NULL)
+ return (-1);
+
+ remove_open_file(file);
+
+ bkmem_free(file, sizeof (struct cpio_file));
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+bcpio_closeall(int flag __unused)
+{
+ struct cpio_file *file;
+
+ while (!SLIST_EMPTY(&open_files)) {
+ file = SLIST_FIRST(&open_files);
+
+ if (bcpio_close(file->fd) != 0)
+ printf("closeall invoked close(%d) failed\n", file->fd);
+ }
+}
+
+static ssize_t
+bcpio_read(int fd, caddr_t buf, size_t size)
+{
+ struct cpio_file *file;
+
+ file = find_open_file(fd);
+ if (file == NULL)
+ return (-1);
+
+ if (size == 0)
+ return (0);
+
+ if (file->off + size > file->stat.st_size)
+ size = file->stat.st_size - file->off;
+
+ bcopy((void *)((uintptr_t)file->data + file->off), buf, size);
+
+ file->off += size;
+
+ return (size);
+}
+
+static off_t
+bcpio_lseek(int fd, off_t addr, int whence)
+{
+ struct cpio_file *file;
+
+ file = find_open_file(fd);
+ if (file == NULL)
+ return (-1);
+
+ switch (whence) {
+ case SEEK_CUR:
+ file->off += addr;
+ break;
+ case SEEK_SET:
+ file->off = addr;
+ break;
+ case SEEK_END:
+ file->off = file->stat.st_size;
+ break;
+ default:
+ printf("lseek(): invalid whence value %d\n", whence);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+bcpio_fstat(int fd, struct bootstat *buf)
+{
+ const struct cpio_file *file;
+
+ file = find_open_file(fd);
+ if (file == NULL)
+ return (-1);
+
+ *buf = file->stat;
+
+ return (0);
+}
+
+struct boot_fs_ops bcpio_ops = {
+ .fsw_name = "boot_cpio",
+ .fsw_mountroot = bcpio_mountroot,
+ .fsw_unmountroot = bcpio_unmountroot,
+ .fsw_open = bcpio_open,
+ .fsw_close = bcpio_close,
+ .fsw_closeall = bcpio_closeall,
+ .fsw_read = bcpio_read,
+ .fsw_lseek = bcpio_lseek,
+ .fsw_fstat = bcpio_fstat,
+};
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index 6fea629961..00daa87959 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -188,6 +188,7 @@ VGATEXT_OBJS += vgatext.o vgasubr.o
KRTLD_OBJS += \
bootfsops.o \
bootrd.o \
+ bootrd_cpio.o \
ufsops.o \
hsfs.o \
doreloc.o \
@@ -365,7 +366,7 @@ LX_BRAND_OBJS = \
#
# special files
#
-MODSTUB_OBJ += \
+MODSTUB_OBJ += \
modstubs.o
BOOTDEV_OBJS += \