add the ability to have read-only virtio-fs shares

Signed-off-by: MJ Pooladkhay <mj@pooladkhay.com>
This commit is contained in:
MJ Pooladkhay 2026-10-29 20:03:41 +00:00 committed by MJ Pooladkhay
parent 2507029d26
commit 261905728f
2 changed files with 20 additions and 8 deletions

View File

@ -5,16 +5,18 @@
# make qemu share="tag_1=/path/a tag_2=/path/b" # several shares: tag=dir ... # make qemu share="tag_1=/path/a tag_2=/path/b" # several shares: tag=dir ...
# make qemu share=redox # this build tree, tag "redox" # make qemu share=redox # this build tree, tag "redox"
# make qemu share="redox=/other/path" # ordinary share, tag "redox" # make qemu share="redox=/other/path" # ordinary share, tag "redox"
# make qemu share=/path/to/dir:ro # read-only, also tag=dir:ro and redox:ro
# make ch share=... # the same, on Cloud Hypervisor # make ch share=... # the same, on Cloud Hypervisor
# #
# Each share gets its own host-side virtiofsd daemon (started and stopped by # Each share gets its own host-side virtiofsd daemon (started and stopped by
# scripts/virtiofs-run.sh), a vhost-user-fs device, and a virtio-fsd scheme # scripts/virtiofs-run.sh), a vhost-user-fs device, and a virtio-fsd scheme
# process on Redox. In the guest, a share appears at /scheme/virtio-fsd.<tag>. # process on Redox. In the guest, a share appears at /scheme/virtio-fsd.<tag>.
# The emulator flags for each share are added in mk/qemu.mk and mk/ch.mk. # The emulator flags for each share are added in mk/qemu.mk and mk/ch.mk.
# Shared directories must exist. The guest cannot change anything in a :ro share.
# #
# WARNING: share=redox exposes the whole build tree to the guest, including # WARNING: share=redox exposes the whole build tree to the guest, including
# the harddrive.img Redox is booted from, .git and .config. Writing to them # the harddrive.img Redox is booted from, .git and .config. Writing to them
# from Redox can corrupt the build system. # from Redox can corrupt the build system. share=redox:ro avoids that.
share?= share?=
share_tag?=host share_tag?=host
@ -22,7 +24,7 @@ share_sockdir?=$(BUILD)
VIRTIOFS_RUN= VIRTIOFS_RUN=
ifneq ($(strip $(share)),) ifneq ($(strip $(share)),)
share_norm:=$(foreach s,$(share),$(if $(filter redox,$(s)),redox=$(ROOT),$(s))) share_norm:=$(foreach s,$(share),$(if $(filter redox redox:ro,$(s)),redox=$(ROOT)$(if $(filter %:ro,$(s)),:ro),$(s)))
ifeq ($(words $(share_norm)),1) ifeq ($(words $(share_norm)),1)
share_list:=$(if $(findstring =,$(share_norm)),$(share_norm),$(share_tag)=$(share_norm)) share_list:=$(if $(findstring =,$(share_norm)),$(share_norm),$(share_tag)=$(share_norm))
else else

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Runs a command next to one virtiofsd per shared directory, for # Runs a command next to one virtiofsd per shared directory, for
# `make qemu share=...` and `make ch share=...`. # `make qemu share=...` and `make ch share=...`.
# virtiofs-run.sh --share <socket>.sock <tag>=<dir> [--share ...] -- <command...> # virtiofs-run.sh --share <socket>.sock <tag>=<dir>[:ro] [--share ...] -- <command...>
set -euo pipefail set -euo pipefail
@ -13,19 +13,27 @@ die() {
} }
usage() { usage() {
echo "usage: $0 --share <socket>.sock <tag>=<dir> [--share ...] -- <command...>" >&2 echo "usage: $0 --share <socket>.sock <tag>=<dir>[:ro] [--share ...] -- <command...>" >&2
exit 2 exit 2
} }
SOCKS=() SOCKS=()
TAGS=() TAGS=()
DIRS=() DIRS=()
OPTS=()
LABELS=()
while [[ "${1:-}" == --share ]]; do while [[ "${1:-}" == --share ]]; do
[[ $# -ge 3 ]] || usage [[ $# -ge 3 ]] || usage
[[ "$3" == *=* ]] || die "share '$3': expected <tag>=<dir>" [[ "$3" == *=* ]] || die "share '$3': expected <tag>=<dir>"
entry="$3" opt="" label=""
if [[ "${entry}" == *:ro ]]; then
entry="${entry%:ro}" opt=--readonly label=" (read-only)"
fi
OPTS+=("${opt}")
LABELS+=("${label}")
SOCKS+=("$2") SOCKS+=("$2")
TAGS+=("${3%%=*}") TAGS+=("${entry%%=*}")
DIRS+=("${3#*=}") DIRS+=("${entry#*=}")
shift 3 shift 3
done done
[[ ${#SOCKS[@]} -gt 0 && "${1:-}" == -- && $# -ge 2 ]] || usage [[ ${#SOCKS[@]} -gt 0 && "${1:-}" == -- && $# -ge 2 ]] || usage
@ -48,6 +56,7 @@ validate_share() {
[[ -n "${dir}" ]] || die "share '${tag}': empty directory" [[ -n "${dir}" ]] || die "share '${tag}': empty directory"
[[ "${dir}" != *[[:space:]]* ]] \ [[ "${dir}" != *[[:space:]]* ]] \
|| die "share '${tag}': directories containing whitespace are not supported ('${dir}')" || die "share '${tag}': directories containing whitespace are not supported ('${dir}')"
[[ -d "${dir}" ]] || die "share '${tag}': ${dir} is not a directory"
[[ "${sock}" == *.sock ]] || die "socket '${sock}' must end in .sock" [[ "${sock}" == *.sock ]] || die "socket '${sock}' must end in .sock"
[[ ${#sock} -lt 108 ]] \ [[ ${#sock} -lt 108 ]] \
|| die "socket path too long (${#sock} bytes): ${sock}; use a shorter share_sockdir" || die "socket path too long (${#sock} bytes): ${sock}; use a shorter share_sockdir"
@ -93,7 +102,7 @@ trap 'exit 143' TERM
declare -A SHARED_DIRS=() declare -A SHARED_DIRS=()
start_virtiofsd() { start_virtiofsd() {
local sock="${SOCKS[$1]}" dir local sock="${SOCKS[$1]}" dir
mkdir -p "${DIRS[$1]}" "$(dirname "${sock}")" mkdir -p "$(dirname "${sock}")"
dir="$(cd "${DIRS[$1]}" && pwd)" dir="$(cd "${DIRS[$1]}" && pwd)"
if [[ -n "${SHARED_DIRS[${dir}]:-}" ]]; then if [[ -n "${SHARED_DIRS[${dir}]:-}" ]]; then
echo "virtiofs: warning: ${dir} is shared more than once; the instances do not share caches" >&2 echo "virtiofs: warning: ${dir} is shared more than once; the instances do not share caches" >&2
@ -107,6 +116,7 @@ start_virtiofsd() {
--log-level warn \ --log-level warn \
--translate-uid="map:0:$(id -u):1" \ --translate-uid="map:0:$(id -u):1" \
--translate-gid="map:0:$(id -g):1" \ --translate-gid="map:0:$(id -g):1" \
${OPTS[$1]} \
</dev/null >"${sock%.sock}.log" 2>&1 & </dev/null >"${sock%.sock}.log" 2>&1 &
PIDS+=("$!") PIDS+=("$!")
} }
@ -133,7 +143,7 @@ for i in "${!SOCKS[@]}"; do
done done
wait_for_sockets wait_for_sockets
for i in "${!SOCKS[@]}"; do for i in "${!SOCKS[@]}"; do
echo "virtiofs: sharing '${TAGS[$i]}' = ${DIRS[$i]} (log: ${SOCKS[$i]%.sock}.log)" >&2 echo "virtiofs: sharing '${TAGS[$i]}' = ${DIRS[$i]}${LABELS[$i]} (log: ${SOCKS[$i]%.sock}.log)" >&2
done done
# Not exec'd, so cleanup runs when the command ends. # Not exec'd, so cleanup runs when the command ends.