@@ -15,36 +15,50 @@ use std::path::Path;
1515pub async fn configure_erofs_snapshotter ( config : & Config , configuration_file : & Path ) -> Result < ( ) > {
1616 info ! ( "Configuring erofs-snapshotter" ) ;
1717
18+ // "unmerged" mode keeps each image layer as its own per-layer `layer.erofs`
19+ // (containerd's default, non-fsmerged layout), which is the only layout the
20+ // Go runtime can consume. In the default "merged" mode we force containerd
21+ // to merge layers into a single `fsmeta.erofs`, which is runtime-rs only.
22+ let unmerged = config. erofs_merge_mode . as_deref ( ) == Some ( "unmerged" ) ;
23+
1824 // The Go runtime does not support fsmerged EROFS (fsmeta.erofs).
1925 // If the snapshotter handler mapping explicitly pairs a Go shim with
20- // erofs, that is a hard misconfiguration — bail out so the operator
21- // fixes the mapping instead of hitting cryptic runtime errors later.
22- if let Some ( mapping) = config. snapshotter_handler_mapping_for_arch . as_ref ( ) {
23- let mut go_shims_on_erofs = Vec :: new ( ) ;
24- for entry in mapping. split ( ',' ) {
25- let parts: Vec < & str > = entry. split ( ':' ) . collect ( ) ;
26- if parts. len ( ) == 2 && parts[ 1 ] == "erofs" && !utils:: is_rust_shim ( parts[ 0 ] ) {
27- go_shims_on_erofs. push ( parts[ 0 ] . to_string ( ) ) ;
26+ // erofs in the (default) merged mode, that is a hard misconfiguration —
27+ // bail out so the operator fixes the mapping instead of hitting cryptic
28+ // runtime errors later. In "unmerged" mode the Go runtime is supported, so
29+ // skip this guard.
30+ if !unmerged {
31+ if let Some ( mapping) = config. snapshotter_handler_mapping_for_arch . as_ref ( ) {
32+ let mut go_shims_on_erofs = Vec :: new ( ) ;
33+ for entry in mapping. split ( ',' ) {
34+ let parts: Vec < & str > = entry. split ( ':' ) . collect ( ) ;
35+ if parts. len ( ) == 2 && parts[ 1 ] == "erofs" && !utils:: is_rust_shim ( parts[ 0 ] ) {
36+ go_shims_on_erofs. push ( parts[ 0 ] . to_string ( ) ) ;
37+ }
2838 }
29- }
30- if !go_shims_on_erofs. is_empty ( ) {
31- warn ! ( "##########################################################################" ) ;
32- warn ! ( "# #" ) ;
33- warn ! ( "# Go runtime shim(s) mapped to the erofs snapshotter: #" ) ;
34- for s in & go_shims_on_erofs {
35- warn ! ( "# - {:<64} #" , s) ;
39+ if !go_shims_on_erofs. is_empty ( ) {
40+ warn ! ( "##########################################################################" ) ;
41+ warn ! ( "# #" ) ;
42+ warn ! ( "# Go runtime shim(s) mapped to the erofs snapshotter: #" ) ;
43+ for s in & go_shims_on_erofs {
44+ warn ! ( "# - {:<64} #" , s) ;
45+ }
46+ warn ! ( "# #" ) ;
47+ warn ! (
48+ "# The Go runtime does NOT support fsmerged EROFS (fsmeta.erofs). #"
49+ ) ;
50+ warn ! ( "# Only runtime-rs shims are supported with merged erofs. Set #" ) ;
51+ warn ! ( "# EROFS_MERGE_MODE=unmerged to use the Go runtime with erofs. #" ) ;
52+ warn ! ( "# #" ) ;
53+ warn ! ( "##########################################################################" ) ;
54+ return Err ( anyhow:: anyhow!(
55+ "erofs snapshotter: Go runtime shim(s) [{}] cannot be mapped to merged erofs. \
56+ The Go runtime does not support fsmerged EROFS. \
57+ Set EROFS_MERGE_MODE=unmerged, remove these shims from \
58+ SNAPSHOTTER_HANDLER_MAPPING, or switch them to runtime-rs.",
59+ go_shims_on_erofs. join( ", " )
60+ ) ) ;
3661 }
37- warn ! ( "# #" ) ;
38- warn ! ( "# The Go runtime does NOT support fsmerged EROFS (fsmeta.erofs). #" ) ;
39- warn ! ( "# Only runtime-rs shims are supported with the erofs snapshotter. #" ) ;
40- warn ! ( "# #" ) ;
41- warn ! ( "##########################################################################" ) ;
42- return Err ( anyhow:: anyhow!(
43- "erofs snapshotter: Go runtime shim(s) [{}] cannot be mapped to erofs. \
44- The Go runtime does not support fsmerged EROFS. \
45- Remove these shims from SNAPSHOTTER_HANDLER_MAPPING or switch them to runtime-rs.",
46- go_shims_on_erofs. join( ", " )
47- ) ) ;
4862 }
4963 }
5064
@@ -88,11 +102,27 @@ pub async fn configure_erofs_snapshotter(config: &Config, configuration_file: &P
88102 ".plugins.\" io.containerd.snapshotter.v1.erofs\" .default_size" ,
89103 "\" 10G\" " ,
90104 ) ?;
91- toml_utils:: set_toml_value (
92- configuration_file,
93- ".plugins.\" io.containerd.snapshotter.v1.erofs\" .max_unmerged_layers" ,
94- "0" ,
95- ) ?;
105+ // In the default "merged" mode, force containerd to merge all layers into a
106+ // single fsmeta.erofs (max_unmerged_layers = 0). In "unmerged" mode we delete
107+ // any previously-written value so each layer stays a separate layer.erofs,
108+ // which the Go runtime requires.
109+ //
110+ // Because kata-deploy edits the containerd config in place, switching from
111+ // merged to unmerged must actively remove the old `max_unmerged_layers = 0`
112+ // left behind by a previous install. Otherwise the stale `0` would keep
113+ // forcing the merged layout and break Go-runtime compatibility.
114+ if !unmerged {
115+ toml_utils:: set_toml_value (
116+ configuration_file,
117+ ".plugins.\" io.containerd.snapshotter.v1.erofs\" .max_unmerged_layers" ,
118+ "0" ,
119+ ) ?;
120+ } else {
121+ toml_utils:: delete_toml_value (
122+ configuration_file,
123+ ".plugins.\" io.containerd.snapshotter.v1.erofs\" .max_unmerged_layers" ,
124+ ) ?;
125+ }
96126
97127 Ok ( ( ) )
98128}
0 commit comments