@@ -6,6 +6,7 @@ use std::{
66 collections:: { BTreeMap , BTreeSet } ,
77 ops:: Deref ,
88 path:: { Path , PathBuf } ,
9+ str:: FromStr ,
910} ;
1011
1112use anyhow:: { anyhow, bail, Context , Result } ;
@@ -77,6 +78,58 @@ struct InstanceInfo {
7778 app_id : Vec < u8 > ,
7879}
7980
81+ #[ derive( Debug , Clone , Copy , PartialEq , Default ) ]
82+ enum FsType {
83+ #[ default]
84+ Zfs ,
85+ Ext4 ,
86+ }
87+
88+ impl FromStr for FsType {
89+ type Err = anyhow:: Error ;
90+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
91+ match s. to_lowercase ( ) . as_str ( ) {
92+ "zfs" => Ok ( FsType :: Zfs ) ,
93+ "ext4" => Ok ( FsType :: Ext4 ) ,
94+ _ => bail ! ( "Invalid filesystem type: {s}, supported types: zfs, ext4" ) ,
95+ }
96+ }
97+ }
98+
99+ #[ derive( Debug , Clone , Default ) ]
100+ struct DstackOptions {
101+ storage_encrypted : bool ,
102+ storage_fs : FsType ,
103+ }
104+
105+ fn parse_dstack_options ( shared : & HostShared ) -> Result < DstackOptions > {
106+ let cmdline = fs:: read_to_string ( "/proc/cmdline" ) . context ( "Failed to read /proc/cmdline" ) ?;
107+
108+ let mut options = DstackOptions {
109+ storage_encrypted : true , // Default to encryption enabled
110+ storage_fs : FsType :: Zfs , // Default to ZFS
111+ } ;
112+
113+ for param in cmdline. split_whitespace ( ) {
114+ if let Some ( value) = param. strip_prefix ( "dstack.storage_encrypted=" ) {
115+ match value {
116+ "0" | "false" | "no" | "off" => options. storage_encrypted = false ,
117+ "1" | "true" | "yes" | "on" => options. storage_encrypted = true ,
118+ _ => {
119+ bail ! ( "Invalid value for dstack.storage_encrypted: {value}" ) ;
120+ }
121+ }
122+ } else if let Some ( value) = param. strip_prefix ( "dstack.storage_fs=" ) {
123+ options. storage_fs = value. parse ( ) . context ( "Failed to parse dstack.storage_fs" ) ?;
124+ }
125+ }
126+
127+ if let Some ( fs) = & shared. app_compose . storage_fs {
128+ options. storage_fs = fs. parse ( ) . context ( "Failed to parse storage_fs" ) ?;
129+ }
130+ Ok ( options)
131+ }
132+
80133impl InstanceInfo {
81134 fn is_initialized ( & self ) -> bool {
82135 !self . instance_id_seed . is_empty ( )
@@ -433,36 +486,86 @@ impl<'a> Stage0<'a> {
433486 }
434487 }
435488
436- async fn mount_data_disk ( & self , initialized : bool , disk_crypt_key : & str ) -> Result < ( ) > {
489+ async fn mount_data_disk (
490+ & self ,
491+ initialized : bool ,
492+ disk_crypt_key : & str ,
493+ opts : & DstackOptions ,
494+ ) -> Result < ( ) > {
437495 let name = "dstack_data_disk" ;
438- let fs_dev = "/dev/mapper/" . to_string ( ) + name;
439496 let mount_point = & self . args . mount_point ;
497+
498+ // Determine the device to use based on encryption settings
499+ let fs_dev = if opts. storage_encrypted {
500+ format ! ( "/dev/mapper/{name}" )
501+ } else {
502+ self . args . device . to_string_lossy ( ) . to_string ( )
503+ } ;
504+
440505 if !initialized {
441506 self . vmm
442507 . notify_q ( "boot.progress" , "initializing data disk" )
443508 . await ;
444- info ! ( "Setting up disk encryption" ) ;
445- self . luks_setup ( disk_crypt_key, name) ?;
509+
510+ if opts. storage_encrypted {
511+ info ! ( "Setting up disk encryption" ) ;
512+ self . luks_setup ( disk_crypt_key, name) ?;
513+ } else {
514+ info ! ( "Skipping disk encryption as requested by kernel cmdline" ) ;
515+ }
516+
446517 cmd ! {
447518 mkdir -p $mount_point;
448- zpool create -o autoexpand=on dstack $fs_dev;
449- zfs create -o mountpoint=$mount_point -o atime=off -o checksum=blake3 dstack/data;
519+ } ?;
520+
521+ match opts. storage_fs {
522+ FsType :: Zfs => {
523+ info ! ( "Creating ZFS filesystem" ) ;
524+ cmd ! {
525+ zpool create -o autoexpand=on dstack $fs_dev;
526+ zfs create -o mountpoint=$mount_point -o atime=off -o checksum=blake3 dstack/data;
527+ }
528+ . context ( "Failed to create zpool" ) ?;
529+ }
530+ FsType :: Ext4 => {
531+ info ! ( "Creating ext4 filesystem" ) ;
532+ cmd ! {
533+ mkfs. ext4 -F $fs_dev;
534+ mount $fs_dev $mount_point;
535+ }
536+ . context ( "Failed to create ext4 filesystem" ) ?;
537+ }
450538 }
451- . context ( "Failed to create zpool" ) ?;
452539 } else {
453540 self . vmm
454541 . notify_q ( "boot.progress" , "mounting data disk" )
455542 . await ;
456- info ! ( "Mounting encrypted data disk" ) ;
457- self . open_encrypted_volume ( disk_crypt_key , name ) ? ;
458- cmd ! {
459- zpool import dstack ;
460- zpool status dstack ;
461- zpool online -e dstack $fs_dev ; // triggers autoexpand
543+
544+ if opts . storage_encrypted {
545+ info ! ( "Mounting encrypted data disk" ) ;
546+ self . open_encrypted_volume ( disk_crypt_key , name ) ? ;
547+ } else {
548+ info ! ( "Mounting unencrypted data disk" ) ;
462549 }
463- . context ( "Failed to import zpool" ) ?;
464- if cmd ! ( mountpoint -q $mount_point) . is_err ( ) {
465- cmd ! ( zfs mount dstack/data) . context ( "Failed to mount zpool" ) ?;
550+
551+ match opts. storage_fs {
552+ FsType :: Zfs => {
553+ cmd ! {
554+ zpool import dstack;
555+ zpool status dstack;
556+ zpool online -e dstack $fs_dev; // triggers autoexpand
557+ }
558+ . context ( "Failed to import zpool" ) ?;
559+ if cmd ! ( mountpoint -q $mount_point) . is_err ( ) {
560+ cmd ! ( zfs mount dstack/data) . context ( "Failed to mount zpool" ) ?;
561+ }
562+ }
563+ FsType :: Ext4 => {
564+ if cmd ! ( mountpoint -q $mount_point) . is_err ( ) {
565+ cmd ! ( mount $fs_dev $mount_point)
566+ . context ( "Failed to mount ext4 filesystem" ) ?;
567+ }
568+ }
466569 }
467570 }
468571 Ok ( ( ) )
@@ -614,9 +717,20 @@ impl<'a> Stage0<'a> {
614717 let keys_json = serde_json:: to_string ( & app_keys) . context ( "Failed to serialize app keys" ) ?;
615718 fs:: write ( self . app_keys_file ( ) , keys_json) . context ( "Failed to write app keys" ) ?;
616719
720+ // Parse kernel command line options
721+ let opts = parse_dstack_options ( & self . shared ) . context ( "Failed to parse kernel cmdline" ) ?;
722+ info ! (
723+ "Filesystem options: encryption={}, filesystem={:?}" ,
724+ opts. storage_encrypted, opts. storage_fs
725+ ) ;
726+
617727 self . vmm . notify_q ( "boot.progress" , "unsealing env" ) . await ;
618- self . mount_data_disk ( is_initialized, & hex:: encode ( & app_keys. disk_crypt_key ) )
619- . await ?;
728+ self . mount_data_disk (
729+ is_initialized,
730+ & hex:: encode ( & app_keys. disk_crypt_key ) ,
731+ & opts,
732+ )
733+ . await ?;
620734 self . vmm
621735 . notify_q (
622736 "instance.info" ,
0 commit comments