diff --git a/antlir/antlir2/antlir2_vm/bzl/defs.bzl b/antlir/antlir2/antlir2_vm/bzl/defs.bzl index 850e4dfd8e..949a4de6ac 100644 --- a/antlir/antlir2/antlir2_vm/bzl/defs.bzl +++ b/antlir/antlir2/antlir2_vm/bzl/defs.bzl @@ -55,6 +55,7 @@ def _machine_json(ctx: AnalysisContext) -> (Artifact, typing.Any): "num_nics": ctx.attrs.num_nics, "serial_index": ctx.attrs.serial_index, "sidecar_services": ctx.attrs.sidecar_services, + "use_legacy_share": ctx.attrs.use_legacy_share, "use_tpm": ctx.attrs.use_tpm, }, with_inputs = True, @@ -131,6 +132,10 @@ _vm_host = rule( "mem_mib": attrs.int(default = 4096, doc = "memory size in MiB"), "num_nics": attrs.int(default = 1), "serial_index": attrs.int(default = 0, doc = "index of the serial port"), + "use_legacy_share": attrs.bool( + default = False, + doc = "use 9p instead of virtiofs for sharing for older kernels", + ), "use_tpm": attrs.bool(default = False, doc = "enable software TPM"), } | { # Non-hardware parameters for the VM diff --git a/antlir/antlir2/antlir2_vm/src/main.rs b/antlir/antlir2/antlir2_vm/src/main.rs index 570b507602..29bf0a7754 100644 --- a/antlir/antlir2/antlir2_vm/src/main.rs +++ b/antlir/antlir2/antlir2_vm/src/main.rs @@ -40,6 +40,7 @@ use crate::isolation::is_isolated; use crate::isolation::isolated; use crate::isolation::Platform; use crate::runtime::set_runtime; +use crate::share::NinePShare; use crate::share::VirtiofsShare; use crate::types::MachineOpts; use crate::types::RuntimeOpts; @@ -106,10 +107,12 @@ fn run(args: &RunCmdArgs) -> Result<()> { set_runtime(args.runtime_spec.clone().into_inner()) .map_err(|_| anyhow!("Failed to set runtime"))?; - Ok( - VM::::new(args.machine_spec.clone().into_inner(), args.vm_args.clone())? - .run()?, - ) + let machine_opts = args.machine_spec.clone().into_inner(); + if machine_opts.use_legacy_share { + Ok(VM::::new(machine_opts, args.vm_args.clone())?.run()?) + } else { + Ok(VM::::new(machine_opts, args.vm_args.clone())?.run()?) + } } /// Enter isolated container and then respawn itself inside it with `run` diff --git a/antlir/antlir2/antlir2_vm/src/share.rs b/antlir/antlir2/antlir2_vm/src/share.rs index 5dec55eac8..7c60c11889 100644 --- a/antlir/antlir2/antlir2_vm/src/share.rs +++ b/antlir/antlir2/antlir2_vm/src/share.rs @@ -233,6 +233,55 @@ impl VirtiofsShare { } } +/// `9pShare` for older kernels +#[derive(Debug, Default)] +pub(crate) struct NinePShare { + /// User specified options for the share + opts: ShareOpts, + /// Index of the share, used to generate unique mount tag, chardev name + /// and socket file. + id: usize, + /// Mount type + mount_type: &'static str, +} + +impl Share for NinePShare { + share_getters!(); + + fn new(opts: ShareOpts, id: usize, _state_dir: PathBuf) -> Self { + Self { + opts, + id, + mount_type: "9p", + } + } + + fn setup(&self) -> Result<()> { + Ok(()) + } + fn mount_options(&self) -> String { + format!( + "version=9p2000.L,posixacl,cache={cache},{ro_rw},msize=209715200", + cache = if self.opts.read_only { "loose" } else { "none" }, + ro_rw = if self.opts.read_only { "ro" } else { "rw" }, + ) + } + + fn qemu_args(&self) -> Vec { + let mut args = vec!["-virtfs".into()]; + args.push( + format!( + "local,path={path},security_model=none,multidevs=remap,mount_tag={tag},readonly={ro}", + path = self.opts.path.to_str().expect("Path should be valid string"), + tag = self.mount_tag(), + ro = if self.opts.read_only { "on" } else { "off" }, + + ).into() + ); + args + } +} + /// In order to mount shares, we have to share something into the VM /// that contains various mount units for mount generator. This struct /// represents the initial trojan horse into the VM. @@ -332,6 +381,8 @@ mod test { let share = VirtiofsShare::new(opts, 3, PathBuf::from("/tmp/test")); assert_eq!(&share.mount_tag(), "fs3"); + assert_eq!(share.get_mount_type(), "virtiofs"); + assert_eq!(&share.mount_options(), "ro"); assert_eq!(&share.chardev_node(), "fs_chardev3"); assert_eq!(share.socket_path(), PathBuf::from("/tmp/test/fs3")); assert_eq!( @@ -390,6 +441,37 @@ Options=rw"#; ); } + #[test] + fn test_9p_share() { + let opts = ShareOpts { + path: PathBuf::from("/this/is/a/test"), + read_only: true, + mount_tag: None, + }; + let mut share = NinePShare::new(opts, 3, PathBuf::from("/tmp/test")); + + assert_eq!(&share.mount_tag(), "fs3"); + assert_eq!(share.get_mount_type(), "9p"); + assert_eq!( + &share.mount_options(), + "version=9p2000.L,posixacl,cache=loose,ro,msize=209715200", + ); + assert_eq!( + &share.qemu_args().join(OsStr::new(" ")), + "-virtfs local,path=/this/is/a/test,security_model=none,multidevs=remap,mount_tag=fs3,readonly=on", + ); + + share.opts.read_only = false; + assert_eq!( + &share.mount_options(), + "version=9p2000.L,posixacl,cache=none,rw,msize=209715200", + ); + assert_eq!( + &share.qemu_args().join(OsStr::new(" ")), + "-virtfs local,path=/this/is/a/test,security_model=none,multidevs=remap,mount_tag=fs3,readonly=off", + ); + } + #[test] fn test_shares() { let opts = ShareOpts { diff --git a/antlir/antlir2/antlir2_vm/src/types.rs b/antlir/antlir2/antlir2_vm/src/types.rs index 717875004c..7f1d0b16c3 100644 --- a/antlir/antlir2/antlir2_vm/src/types.rs +++ b/antlir/antlir2/antlir2_vm/src/types.rs @@ -179,6 +179,8 @@ pub(crate) struct MachineOpts { pub(crate) sidecar_services: Vec>, /// Enables TPM 2.0 support pub(crate) use_tpm: bool, + /// Use 9p instead of virtiofs for sharing. This is required for kernel older than 5.4. + pub(crate) use_legacy_share: bool, } /// Location of various binary and data we need to operate the VM