diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc index bb9ee90152..52c2694d4e 100644 --- a/fs/vfs/main.cc +++ b/fs/vfs/main.cc @@ -2404,6 +2404,30 @@ extern "C" int mount_zfs_rootfs(bool pivot_root, bool extra_zfs_pools) return 0; } +extern "C" int mount_virtiofs_rootfs(bool pivot_root) +{ + constexpr char* mp = "/virtiofs"; + + if (mkdir(mp, 0755) < 0) { + int ret = errno; + kprintf("failed to create %s, error = %s\n", mp, strerror(errno)); + return ret; + } + + int ret = sys_mount("/dev/virtiofs0", mp, "virtiofs", MNT_RDONLY, nullptr); + if (ret) { + kprintf("failed to mount %s, error = %s\n", mp, strerror(ret)); + rmdir(mp); + return ret; + } + + if (pivot_root) { + pivot_rootfs(mp); + } + + return 0; +} + extern "C" void unmount_rootfs(void) { int ret; diff --git a/loader.cc b/loader.cc index 19b47e0e92..9656cf3ba2 100644 --- a/loader.cc +++ b/loader.cc @@ -91,6 +91,7 @@ extern "C" { int mount_zfs_rootfs(bool, bool); int mount_rofs_rootfs(bool); void rofs_disable_cache(); + int mount_virtiofs_rootfs(bool); } void premain() @@ -165,7 +166,7 @@ static void usage() std::cout << " --leak start leak detector after boot\n"; std::cout << " --nomount don't mount the root file system\n"; std::cout << " --nopivot do not pivot the root from bootfs to the root fs\n"; - std::cout << " --rootfs=arg root filesystem to use (zfs, rofs or ramfs)\n"; + std::cout << " --rootfs=arg root filesystem to use (zfs, rofs, ramfs or virtiofs)\n"; std::cout << " --assign-net assign virtio network to the application\n"; std::cout << " --maxnic=arg maximum NIC number\n"; std::cout << " --norandom don't initialize any random device\n"; @@ -435,6 +436,13 @@ void* do_main_thread(void *_main_args) // TODO: Avoid the hack of using pivot_rootfs() just for mounting // the fstab entries. pivot_rootfs("/"); + } else if (opt_rootfs.compare("virtiofs") == 0) { + auto error = mount_virtiofs_rootfs(opt_pivot); + if (error) { + debug("Could not mount virtiofs root filesystem.\n"); + } + + boot_time.event("Virtio-fs mounted"); } else { // Fallback to original behavior for compatibility: try rofs -> zfs if (mount_rofs_rootfs(opt_pivot) == 0) { diff --git a/scripts/build b/scripts/build index 8fa1807175..24e930d3e1 100755 --- a/scripts/build +++ b/scripts/build @@ -24,8 +24,9 @@ usage() { --help|-h Print this help message arch=x64|aarch64 Specify the build architecture; default is x64 mode=release|debug Specify the build mode; default is release - export=none|selected|all If 'selected' or 'all' export the app files to build/export - fs=zfs|rofs|ramfs Specify the filesystem of the image partition + export=none|selected|all If 'selected' or 'all' export the app files to + export_dir= The directory to export the files to; default is build/export + fs=zfs|rofs|ramfs|virtiofs Specify the filesystem of the image partition fs_size=N Specify the size of the image in bytes fs_size_mb=N Specify the size of the image in MiB app_local_exec_tls_size=N Specify the size of app local TLS in bytes; the default is 64 @@ -182,12 +183,17 @@ manifest=bootfs.manifest.skel fs_type=${vars[fs]-zfs} usrskel_arg= case $fs_type in -zfs);; # Nothing to change here. This is our default behavior -rofs) manifest=bootfs_empty.manifest.skel +zfs) + ;; # Nothing to change here. This is our default behavior +rofs|virtiofs) + # Both are read-only (in OSv) and require nothing extra on bootfs to work + manifest=bootfs_empty.manifest.skel usrskel_arg="--usrskel usr_rofs.manifest.skel";; -ramfs) manifest=$OUT/usr.manifest +ramfs) + manifest=$OUT/usr.manifest usrskel_arg="--usrskel usr_ramfs.manifest.skel";; -*) echo "Unknown filesystem \"$fs_type\"" >&2 +*) + echo "Unknown filesystem \"$fs_type\"" >&2 exit 2 esac @@ -312,7 +318,9 @@ rofs) partition_size=`stat --printf %s rofs.img` image_size=$((partition_offset + partition_size)) create_rofs_disk ;; -ramfs) +ramfs|virtiofs) + # No need to create extra fs like above: ramfs is already created (as the + # bootfs) and virtio-fs is specified with virtiofsd at run time qemu-img convert -f raw -O qcow2 loader.img usr.img ;; esac # Prepend the root fs type option to the command line (preserved by run.py)