diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2018-08-31 12:00:34 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2018-08-31 12:00:34 +0000 |
commit | 9b5d9abaa7ded12c3da31ba5f2c72f97a2e40fec (patch) | |
tree | bca29bcf06b0cbd7794971c49581f631965c604c /usr/src | |
parent | 6e567b7bf9c30262784d63ef8e2ad150be55b6c1 (diff) | |
parent | 45bf502ff96d3c90215cf16c25a80d757f276431 (diff) | |
download | illumos-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.mf | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 5 | ||||
-rw-r--r-- | usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio | 15 | ||||
-rw-r--r-- | usr/src/uts/common/krtld/THIRDPARTYLICENSE.bootrd_cpio.descrip | 1 | ||||
-rw-r--r-- | usr/src/uts/common/krtld/bootrd.c | 10 | ||||
-rw-r--r-- | usr/src/uts/common/krtld/bootrd_cpio.c | 484 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.files | 3 |
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 += \ |