From nobody Tue Jan 24 22:12:57 2023 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4P1h6y00rDz3bg6n; Tue, 24 Jan 2023 22:12:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4P1h6x4Kmtz3F8N; Tue, 24 Jan 2023 22:12:57 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1674598377; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=LpxdUbCXRUg8urHozWOWrD3f4cDJgy7/YHXJFX2pU5Y=; b=Zu775aP7DL5pdeNdCxLBWrenZxKZ5g2VUQ1oXBCPcbc+17GqC6fye+aC53JVNvobe1TKES vUtrWdxfJr4Ky8YhYV4msmvJeQ6hXDoAGLLL0pdNDvzC/Inji5pHVQBkyUuoRdZ54wI/uF MB3TwqKnivZlmi5T6WFhN+yM53mORnxa1LryXzMKYOnxknMpqKXav6Y4AbK4BfvC2Eqzld Jl9cGciuvXlB3Qvw8W7o2ZMFXMlYHf72Y2by19AuCA/8j9kP7xIzh03iIpyR2qEJTnd9M/ nNn+syFjKfbyl63uTzU9BO3FFLmr1SHBYbIvD/KnyYNZA7OIfEdRSy6DZqiCZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1674598377; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=LpxdUbCXRUg8urHozWOWrD3f4cDJgy7/YHXJFX2pU5Y=; b=sSDFEawQ+FsiCpDeFH1TPkJP74PCFW/zRrRC3sBqntQqv/96NgttrxB4NB4P+GqRSAIBgz kXN4nwe/8QjlaSSIPTkd5PDn64/sopi2kwhs6DXdPnNoN84z6Q67cWP5a0dqAFzYguFm8P nsdeZxOgpNFD8zKAHZP0cTrTGwlYpfYhJb5F7oOY2C0xx14HL5xwL0mdPEgouZMt/9/Qlr A1wU9hseuLcEMMGDCW7lVIJggKwxYkKI8Dy5ug/7JQ9WrwbbPWGhpfpid1WldxUfCkvqDt bxcOb1w0x2ne0M97WQLLucItP+dxrA3Bh6dBvVQnGX6qhhBW+nPzPM0LHzGhqA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1674598377; a=rsa-sha256; cv=none; b=qVLDfCqUALHQcqgUUK9OPpsYZvkfmqj6R1vlmmGKiCecn6cvc5drOaIkeAeBVPqMt5Tdv2 +07dwxwz0Xkp0pw5JDD6syJe83s9PGybk7oYZPKv/TIOHXG6ECoamWvBPUvYfnzhCJXYCQ 1JjepUwNKOIAPgTDOLorbesxsBzPQ0hKwIG//eLqmnzZryVHSipKfeAee2s4hPDazqQZ4V H9uE+9Go8essTEtBdQ5UO3W1sXHP9rbJquLsCTGnghVaUC8ZO0vpeHueCklrfMSXI8kR3w oqkWpjsf6HsPrETh6FZ7OOitF4e+keCB07drmFsZN6Ng2GBcywnaXxgvUQ15Ww== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4P1h6x3QklzQVl; Tue, 24 Jan 2023 22:12:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 30OMCvcp087746; Tue, 24 Jan 2023 22:12:57 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 30OMCvDA087745; Tue, 24 Jan 2023 22:12:57 GMT (envelope-from git) Date: Tue, 24 Jan 2023 22:12:57 GMT Message-Id: <202301242212.30OMCvDA087745@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Warner Losh Subject: git: f811057b2a7f - stable/13 - kboot: Add hostfs List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: f811057b2a7fabaf47700c3788f136466248d0ae Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=f811057b2a7fabaf47700c3788f136466248d0ae commit f811057b2a7fabaf47700c3788f136466248d0ae Author: Warner Losh AuthorDate: 2022-10-27 17:37:54 +0000 Commit: Warner Losh CommitDate: 2023-01-24 21:49:36 +0000 kboot: Add hostfs Add hostfs for the Linux environment. We can't use the userboot one that's kinda similar because the Linux system calls we have in kboot are not quite POSIX compliant (Linux takes care of providing the POSIX interface in libc), so we have to cope with a number of quirks in that area. Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D36607 (cherry picked from commit 02dba4f75f86f3d5ae5a6a438b5bcfdc667929bb) --- stand/kboot/Makefile | 1 + stand/kboot/conf.c | 5 + stand/kboot/hostfs.c | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++ stand/kboot/kboot.h | 2 + stand/kboot/main.c | 4 +- 5 files changed, 291 insertions(+), 1 deletion(-) diff --git a/stand/kboot/Makefile b/stand/kboot/Makefile index 518e945a596e..c8bd313d1d1d 100644 --- a/stand/kboot/Makefile +++ b/stand/kboot/Makefile @@ -25,6 +25,7 @@ SRCS= \ host_syscalls.c \ hostcons.c \ hostdisk.c \ + hostfs.c \ init.c \ kbootfdt.c \ main.c \ diff --git a/stand/kboot/conf.c b/stand/kboot/conf.c index b840d008a347..26788342c4b9 100644 --- a/stand/kboot/conf.c +++ b/stand/kboot/conf.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #endif extern struct devsw hostdisk; +extern struct devsw host_dev; /* * We could use linker sets for some or all of these, but @@ -53,9 +54,12 @@ struct devsw *devsw[] = { #if defined(LOADER_NET_SUPPORT) &netdev, #endif + &host_dev, NULL }; +extern struct fs_ops hostfs_fsops; + struct fs_ops *file_system[] = { #if defined(LOADER_UFS_SUPPORT) &ufs_fsops, @@ -79,6 +83,7 @@ struct fs_ops *file_system[] = { &bzipfs_fsops, #endif &dosfs_fsops, + &hostfs_fsops, NULL }; diff --git a/stand/kboot/hostfs.c b/stand/kboot/hostfs.c new file mode 100644 index 000000000000..08f532999abe --- /dev/null +++ b/stand/kboot/hostfs.c @@ -0,0 +1,280 @@ +/*- + * Copyright (c) 2022 Netflix, Inc + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "stand.h" +#include "host_syscall.h" +#include "kboot.h" + +#define HOST_PATH_MAX 1025 + +extern struct devsw host_dev; + +const char *hostfs_root = "/"; + +enum FTYPE { + regular, + dir, +}; + +typedef struct _hostfs_file { + enum FTYPE hf_type; + int hf_fd; + /* The following are only used for FTYPE == dir */ + char hf_dents[2048]; + char *hf_curdent; + int hf_dentlen; /* Valid part of hf_dents */ +} hostfs_file; + +static hostfs_file * +hostfs_alloc(void) +{ + hostfs_file *hf; + + hf = malloc(sizeof(*hf)); + if (hf != NULL) + memset(hf, 0, sizeof(*hf)); + return (hf); +} + +static void +hostfs_free(hostfs_file *hf) +{ + free(hf); +} + +static int +hostfs_open(const char *fn, struct open_file *f) +{ + hostfs_file *hf; + struct host_kstat ksb; + char path[HOST_PATH_MAX]; + + if (f->f_dev != &host_dev) { + return (EINVAL); + } + + /* + * Normally, we root everything at hostfs_root. However, there are two + * exceptions that make it easier to write code. First is /sys and /proc + * are special Linux filesystems, so we pass those paths + * through. Second, if the path starts with //, then we strip off the + * first / and pass it through (in a weird way, this is actually in + * POSIX: hosts are allowed to do specail things with paths that start + * with two //, but one or three or more are required to be treated as + * one). + */ + if (strncmp("/sys/", fn, 5) == 0 || strncmp("/proc/", fn, 6) == 0) + strlcpy(path, fn, sizeof(path)); + else if (fn[0] == '/' && fn[1] == '/' && fn[2] != '/') + strlcpy(path, fn + 1, sizeof(path)); + else + snprintf(path, sizeof(path), "%s/%s", hostfs_root, fn); + hf = hostfs_alloc(); + hf->hf_fd = host_open(path, HOST_O_RDONLY, 0); + if (hf->hf_fd < 0) { + hostfs_free(hf); + return (EINVAL); + } + + if (host_fstat(hf->hf_fd, &ksb) < 0) { + hostfs_free(hf); + return (EINVAL); + } + if (S_ISDIR(hf->hf_fd)) { + hf->hf_type = dir; + } else { + hf->hf_type = regular; + } + f->f_fsdata = hf; + return (0); +} + +static int +hostfs_close(struct open_file *f) +{ + hostfs_file *hf = f->f_fsdata; + + host_close(hf->hf_fd); + hostfs_free(hf); + f->f_fsdata = NULL; + + return (0); +} + +static int +hostfs_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + hostfs_file *hf = f->f_fsdata; + ssize_t sz; + + sz = host_read(hf->hf_fd, start, size); + if (sz < 0) { + return (EINVAL); + } + *resid = size - sz; + + return (0); +} + +static off_t +hostfs_seek(struct open_file *f, off_t offset, int whence) +{ + hostfs_file *hf = f->f_fsdata; + uint32_t offl, offh; + int err; + uint64_t res; + + /* + * Assumes Linux host with 'reduced' system call wrappers. Also assume + * host and libstand have same whence encoding (safe since it all comes + * from V7 later ISO-C). Also assumes we have to support powerpc still, + * it's interface is weird for legacy reasons.... + */ + offl = offset & 0xffffffff; + offh = (offset >> 32) & 0xffffffff; + err = host_llseek(hf->hf_fd, offh, offl, &res, whence); + if (err < 0) + return (err); + return (res); +} + +static int +hostfs_stat(struct open_file *f, struct stat *sb) +{ + struct host_kstat ksb; + hostfs_file *hf = f->f_fsdata; + + if (host_fstat(hf->hf_fd, &ksb) < 0) + return (EINVAL); + /* + * Translate Linux stat info to lib stand's notion (which uses FreeBSD's + * stat structure, missing fields are zero and commented below). + */ + memset(sb, 0, sizeof(*sb)); + sb->st_dev = ksb.st_dev; + sb->st_ino = ksb.st_ino; + sb->st_nlink = ksb.st_nlink; + sb->st_mode = ksb.st_mode; + sb->st_uid = ksb.st_uid; + sb->st_gid = ksb.st_gid; + sb->st_rdev = ksb.st_rdev; + /* No st_?time_ext on i386 */ + sb->st_atim.tv_sec = ksb.st_atime_sec; + sb->st_atim.tv_nsec = ksb.st_atime_nsec; + sb->st_mtim.tv_sec = ksb.st_mtime_sec; + sb->st_mtim.tv_nsec = ksb.st_mtime_nsec; + sb->st_ctim.tv_sec = ksb.st_ctime_sec; + sb->st_ctim.tv_nsec = ksb.st_ctime_nsec; + /* No st_birthtim */ + sb->st_size = ksb.st_size; + sb->st_blocks = ksb.st_blocks; + sb->st_blksize = ksb.st_blksize; + /* no st_flags */ + /* no st_get */ + + return (0); +} + +static int +hostfs_readdir(struct open_file *f, struct dirent *d) +{ + hostfs_file *hf = f->f_fsdata; + int dentlen; + struct host_dirent64 *dent; + + if (hf->hf_curdent == NULL) { + dentlen = host_getdents64(hf->hf_fd, hf->hf_dents, sizeof(hf->hf_dents)); + if (dentlen <= 0) + return (EINVAL); + hf->hf_dentlen = dentlen; + hf->hf_curdent = hf->hf_dents; + } + dent = (struct host_dirent64 *)hf->hf_curdent; + d->d_fileno = dent->d_ino; + d->d_type = dent->d_type; /* HOST_DT_XXXX == DX_XXXX for all values */ + strlcpy(d->d_name, dent->d_name, sizeof(d->d_name)); /* d_name is NUL terminated */ + d->d_namlen = strlen(d->d_name); + hf->hf_curdent += dent->d_reclen; + if (hf->hf_curdent >= hf->hf_dents + hf->hf_dentlen) { + hf->hf_curdent = NULL; + hf->hf_dentlen = 0; + } + + return (0); +} + +struct fs_ops hostfs_fsops = { + .fs_name = "host", + .fo_open = hostfs_open, + .fo_close = hostfs_close, + .fo_read = hostfs_read, + .fo_write = null_write, + .fo_seek = hostfs_seek, + .fo_stat = hostfs_stat, + .fo_readdir = hostfs_readdir +}; + +/* + * Generic "null" host device. This goes hand and hand with the host fs object + * + * XXXX This and userboot for bhyve both use exactly the same code, modulo some + * formatting nits. Make them common. We mostly use it to 'gate' the open of the + * filesystem to only this device. + */ + +static int +host_dev_init(void) +{ + return (0); +} + +static int +host_dev_print(int verbose) +{ + char line[80]; + + printf("%s devices:", host_dev.dv_name); + if (pager_output("\n") != 0) + return (1); + + snprintf(line, sizeof(line), " host%d: Host filesystem\n", 0); + return (pager_output(line)); +} + +/* + * 'Open' the host device. + */ +static int +host_dev_open(struct open_file *f, ...) +{ + return (0); +} + +static int +host_dev_close(struct open_file *f) +{ + return (0); +} + +static int +host_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + return (ENOSYS); +} + +struct devsw host_dev = { + .dv_name = "host", + .dv_type = DEVT_NET, + .dv_init = host_dev_init, + .dv_strategy = host_dev_strategy, + .dv_open = host_dev_open, + .dv_close = host_dev_close, + .dv_ioctl = noioctl, + .dv_print = host_dev_print, + .dv_cleanup = NULL +}; diff --git a/stand/kboot/kboot.h b/stand/kboot/kboot.h index 81bd18faa893..5441c90eaecc 100644 --- a/stand/kboot/kboot.h +++ b/stand/kboot/kboot.h @@ -11,6 +11,8 @@ void do_init(void); +extern const char *hostfs_root; + /* Per-platform fdt fixup */ void fdt_arch_fixups(void *fdtp); diff --git a/stand/kboot/main.c b/stand/kboot/main.c index 10dd6b05194b..23211ce9df4c 100644 --- a/stand/kboot/main.c +++ b/stand/kboot/main.c @@ -120,8 +120,10 @@ main(int argc, const char **argv) bootdev = argv[1]; else bootdev = ""; + if (argc > 2) + hostfs_root = argv[2]; - printf("Boot device: %s\n", bootdev); + printf("Boot device: %s with hostfs_root %s\n", bootdev, hostfs_root); archsw.arch_getdev = kboot_getdev; archsw.arch_copyin = kboot_copyin;