Skip to content

Commit 0f4fd58

Browse files
committed
Use /swapfile folder
1 parent 0b3c793 commit 0f4fd58

File tree

1 file changed

+103
-64
lines changed

1 file changed

+103
-64
lines changed

src/main.rs

Lines changed: 103 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ enum Commands {
4343
#[derive(Debug, Clone, Copy, PartialEq)]
4444
enum SwapMode {
4545
Auto,
46-
ZramSwapfc, // zram + writeback to swap files (best for desktop!)
47-
ZswapSwapfc, // zswap + swap files (alternative)
48-
ZramOnly, // zram only (for non-btrfs)
49-
Disabled, // Swap management disabled (service exits cleanly)
46+
ZramSwapfc, // zram + writeback to swap files (best for desktop!)
47+
ZswapSwapfc, // zswap + swap files (alternative)
48+
ZramOnly, // zram only (for non-btrfs)
49+
Disabled, // Swap management disabled (service exits cleanly)
5050
}
5151

5252
fn main() {
@@ -72,11 +72,14 @@ fn main() {
7272
}
7373
}
7474

75-
76-
7775
/// Parse swap_mode from config
7876
fn get_swap_mode(config: &Config) -> SwapMode {
79-
match config.get("swap_mode").unwrap_or("auto").to_lowercase().as_str() {
77+
match config
78+
.get("swap_mode")
79+
.unwrap_or("auto")
80+
.to_lowercase()
81+
.as_str()
82+
{
8083
"zram+swapfc" | "zram_swapfc" => SwapMode::ZramSwapfc,
8184
"zswap+swapfc" | "zswap" | "zswap+swapfile" => SwapMode::ZswapSwapfc,
8285
"zram" | "zram_only" => SwapMode::ZramOnly,
@@ -94,7 +97,7 @@ fn get_swap_mode(config: &Config) -> SwapMode {
9497
/// - Unpredictable memory pressure behavior
9598
fn disable_zswap_for_zram() {
9699
use systemd_swap::zswap;
97-
100+
98101
if zswap::is_available() && zswap::is_enabled() {
99102
info!("Disabling zswap (recommended when using zram)");
100103
let zswap_enabled = "/sys/module/zswap/parameters/enabled";
@@ -110,32 +113,35 @@ fn disable_zswap_for_zram() {
110113
/// Sets min_ttl_ms which protects the working set from premature eviction
111114
fn configure_mglru(config: &Config, recommended: Option<&RecommendedConfig>) {
112115
const MGLRU_MIN_TTL_PATH: &str = "/sys/kernel/mm/lru_gen/min_ttl_ms";
113-
116+
114117
// Check if MGLRU is available
115118
if !Path::new(MGLRU_MIN_TTL_PATH).exists() {
116119
return;
117120
}
118-
121+
119122
// Get configured value, or use recommended value from autoconfig
120-
let min_ttl_ms: u32 = config.get_opt("mglru_min_ttl_ms")
123+
let min_ttl_ms: u32 = config
124+
.get_opt("mglru_min_ttl_ms")
121125
.and_then(|v| v.parse::<u32>().ok())
122126
.unwrap_or_else(|| {
123127
// Use recommended value if available, otherwise default based on RAM
124-
recommended.map(|r| r.mglru_min_ttl_ms)
125-
.unwrap_or_else(|| {
126-
// Fallback: detect RAM and use appropriate value
127-
use systemd_swap::autoconfig::RamProfile;
128-
RamProfile::detect().recommended_mglru_min_ttl()
129-
})
128+
recommended.map(|r| r.mglru_min_ttl_ms).unwrap_or_else(|| {
129+
// Fallback: detect RAM and use appropriate value
130+
use systemd_swap::autoconfig::RamProfile;
131+
RamProfile::detect().recommended_mglru_min_ttl()
132+
})
130133
});
131-
134+
132135
if min_ttl_ms == 0 {
133136
return;
134137
}
135-
138+
136139
// Apply the setting
137140
match fs::write(MGLRU_MIN_TTL_PATH, min_ttl_ms.to_string()) {
138-
Ok(_) => info!("MGLRU: min_ttl_ms = {} (working set protection)", min_ttl_ms),
141+
Ok(_) => info!(
142+
"MGLRU: min_ttl_ms = {} (working set protection)",
143+
min_ttl_ms
144+
),
139145
Err(e) => warn!("MGLRU: failed to set min_ttl_ms: {}", e),
140146
}
141147
}
@@ -147,26 +153,43 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
147153
// Clean up any previous instance
148154
let _ = stop(true);
149155

156+
// Clean up legacy swapfc/swapfile path
157+
let legacy_path = Path::new("/swapfc/swapfile");
158+
if legacy_path.exists() {
159+
info!("Removing legacy path: {}", legacy_path.display());
160+
if legacy_path.is_dir() {
161+
let _ = fs::remove_dir_all(legacy_path);
162+
} else {
163+
let _ = fs::remove_file(legacy_path);
164+
}
165+
}
166+
150167
// Initialize directories
151168
makedirs(WORK_DIR)?;
152-
makedirs(format!("{}/system/local-fs.target.wants", systemd_swap::config::RUN_SYSD))?;
153-
makedirs(format!("{}/system/swap.target.wants", systemd_swap::config::RUN_SYSD))?;
169+
makedirs(format!(
170+
"{}/system/local-fs.target.wants",
171+
systemd_swap::config::RUN_SYSD
172+
))?;
173+
makedirs(format!(
174+
"{}/system/swap.target.wants",
175+
systemd_swap::config::RUN_SYSD
176+
))?;
154177

155178
let mut config = Config::load()?;
156179
let swap_mode = get_swap_mode(&config);
157-
180+
158181
// Detect system capabilities early for autoconfig
159182
let caps = SystemCapabilities::detect();
160183
let recommended = RecommendedConfig::from_capabilities(&caps);
161-
184+
162185
// Configure MGLRU early (protects working set during swap operations)
163186
configure_mglru(&config, Some(&recommended));
164187

165188
// Determine effective mode based on filesystem type
166189
let effective_mode = match swap_mode {
167190
SwapMode::Auto => {
168191
config.apply_autoconfig(&recommended);
169-
192+
170193
if recommended.use_zswap {
171194
info!("Auto-detected: using zswap + swapfc");
172195
SwapMode::ZswapSwapfc
@@ -185,10 +208,10 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
185208
SwapMode::ZramSwapfc => {
186209
// Desktop-optimized mode: zram for speed + swapfc for overflow
187210
// zram is faster than zswap because it's a dedicated block device
188-
211+
189212
// Disable zswap when using zram (per kernel documentation)
190213
disable_zswap_for_zram();
191-
214+
192215
// Set up signal handler
193216
signal_hook::flag::register(
194217
signal_hook::consts::SIGTERM,
@@ -208,7 +231,7 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
208231
if config.get_bool("zram_writeback") {
209232
let wb_config = systemd_swap::zram::ZramWritebackConfig::from_config(&config);
210233
let mut wb_manager = systemd_swap::zram::ZramWritebackManager::new(wb_config);
211-
234+
212235
// Run writeback manager in background thread
213236
std::thread::spawn(move || {
214237
if let Err(e) = wb_manager.run() {
@@ -220,7 +243,7 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
220243
// Create swapfc for overflow/writeback (lower priority)
221244
info!("Setting up swapfc as secondary swap for overflow...");
222245
let mut swapfc = SwapFile::new(&config)?;
223-
246+
224247
// Create initial swap file
225248
swapfc.create_initial_swap()?;
226249

@@ -231,7 +254,7 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
231254
SwapMode::ZswapSwapfc => {
232255
// For zswap: create swap file FIRST, then enable zswap
233256
// zswap needs a backing swap device to work
234-
257+
235258
// Set up signal handler
236259
signal_hook::flag::register(
237260
signal_hook::consts::SIGTERM,
@@ -243,7 +266,7 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
243266

244267
// Create initial swap file and start monitoring
245268
let mut swapfc = SwapFile::new(&config)?;
246-
269+
247270
// Force create first swap chunk immediately (zswap needs backing swap)
248271
info!("Creating initial swap file for zswap backing...");
249272
swapfc.create_initial_swap()?;
@@ -263,10 +286,10 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
263286

264287
SwapMode::ZramOnly => {
265288
// For zram: just set up zram, no swap files needed
266-
289+
267290
// Disable zswap when using zram (per kernel documentation)
268291
disable_zswap_for_zram();
269-
292+
270293
// Set up signal handler for clean shutdown
271294
signal_hook::flag::register(
272295
signal_hook::consts::SIGTERM,
@@ -275,18 +298,18 @@ fn start() -> Result<(), Box<dyn std::error::Error>> {
275298
ctrlc::set_handler(move || {
276299
request_shutdown();
277300
})?;
278-
301+
279302
if let Err(e) = systemd_swap::zram::start(&config) {
280303
error!("Zram: {}", e);
281304
}
282305
notify_ready();
283306
info!("Zram setup complete");
284-
307+
285308
// If writeback is enabled, run the smart writeback manager
286309
if config.get_bool("zram_writeback") {
287310
let wb_config = systemd_swap::zram::ZramWritebackConfig::from_config(&config);
288311
let mut wb_manager = systemd_swap::zram::ZramWritebackManager::new(wb_config);
289-
312+
290313
// This blocks and monitors zram writeback
291314
if let Err(e) = wb_manager.run() {
292315
warn!("Zram writeback manager error: {}", e);
@@ -340,7 +363,7 @@ fn stop(on_init: bool) -> Result<(), Box<dyn std::error::Error>> {
340363
let config = Config::load()?;
341364

342365
// Stop all managed swap units
343-
for subsystem in ["swapfc", "zram"] {
366+
for subsystem in ["swapfile", "zram"] {
344367
for unit_path in find_swap_units() {
345368
if let Ok(content) = read_file(&unit_path) {
346369
if content.to_lowercase().contains(subsystem) {
@@ -349,7 +372,7 @@ fn stop(on_init: bool) -> Result<(), Box<dyn std::error::Error>> {
349372
let _ = swapoff(&dev);
350373
force_remove(&unit_path, true);
351374

352-
if subsystem == "swapfc" && Path::new(&dev).is_file() {
375+
if subsystem == "swapfile" && Path::new(&dev).is_file() {
353376
force_remove(&dev, true);
354377
} else if subsystem == "zram" {
355378
let _ = systemd_swap::zram::release(&dev);
@@ -383,8 +406,7 @@ fn stop(on_init: bool) -> Result<(), Box<dyn std::error::Error>> {
383406
let _ = fs::remove_dir_all(WORK_DIR);
384407

385408
// Remove swap files
386-
let swapfile_path = config.get("swapfile_path")
387-
.unwrap_or("/swapfile");
409+
let swapfile_path = config.get("swapfile_path").unwrap_or("/swapfile");
388410
info!("Removing files in {}...", swapfile_path);
389411
if let Ok(entries) = fs::read_dir(swapfile_path) {
390412
for entry in entries.flatten() {
@@ -419,7 +441,7 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
419441
if usage.zswap_active {
420442
let zswap_original = swap_used.saturating_sub(usage.swap_used_disk);
421443
let zswap_compressed = usage.zswap_pool_bytes;
422-
444+
423445
let ratio = if zswap_original > 0 {
424446
(zswap_compressed as f64 / zswap_original as f64) * 100.0
425447
} else {
@@ -428,22 +450,30 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
428450

429451
println!();
430452
println!(" === Pool Statistics ===");
431-
println!(" pool_size: {:.1} MiB (compressed)", zswap_compressed as f64 / 1024.0 / 1024.0);
432-
println!(" stored_data: {:.1} MiB (original)", zswap_original as f64 / 1024.0 / 1024.0);
453+
println!(
454+
" pool_size: {:.1} MiB (compressed)",
455+
zswap_compressed as f64 / 1024.0 / 1024.0
456+
);
457+
println!(
458+
" stored_data: {:.1} MiB (original)",
459+
zswap_original as f64 / 1024.0 / 1024.0
460+
);
433461
println!(" pool_utilization: {}%", usage.zswap_pool_percent);
434462
println!(" compress_ratio: {:.0}%", ratio);
435463

436464
// If running as root, show additional debugfs stats
437465
if is_root && (zswap.stored_pages > 0 || zswap.written_back_pages > 0) {
438466
let page_size = get_page_size();
439-
467+
440468
println!();
441469
println!(" === Writeback Statistics (debugfs) ===");
442470
println!(" stored_pages: {}", zswap.stored_pages);
443471
println!(" same_filled_pages: {}", zswap.same_filled_pages);
444-
println!(" written_back_pages: {} ({:.1} MiB)",
445-
zswap.written_back_pages,
446-
(zswap.written_back_pages * page_size) as f64 / 1024.0 / 1024.0);
472+
println!(
473+
" written_back_pages: {} ({:.1} MiB)",
474+
zswap.written_back_pages,
475+
(zswap.written_back_pages * page_size) as f64 / 1024.0 / 1024.0
476+
);
447477
println!(" pool_limit_hit: {}", zswap.pool_limit_hit);
448478
println!(" reject_reclaim_fail: {}", zswap.reject_reclaim_fail);
449479
}
@@ -452,9 +482,18 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
452482
if swap_used > 0 {
453483
println!();
454484
println!(" === Effective Swap Usage ===");
455-
println!(" kernel_reported_used: {:.1} MiB", swap_used as f64 / 1024.0 / 1024.0);
456-
println!(" in_zswap_pool (RAM): {:.1} MiB", zswap_original as f64 / 1024.0 / 1024.0);
457-
println!(" actual_disk_used: {:.1} MiB", usage.swap_used_disk as f64 / 1024.0 / 1024.0);
485+
println!(
486+
" kernel_reported_used: {:.1} MiB",
487+
swap_used as f64 / 1024.0 / 1024.0
488+
);
489+
println!(
490+
" in_zswap_pool (RAM): {:.1} MiB",
491+
zswap_original as f64 / 1024.0 / 1024.0
492+
);
493+
println!(
494+
" actual_disk_used: {:.1} MiB",
495+
usage.swap_used_disk as f64 / 1024.0 / 1024.0
496+
);
458497
let percent_in_ram = (zswap_original as f64 / swap_used as f64) * 100.0;
459498
println!(" swap_in_ram: {:.0}%", percent_in_ram);
460499
}
@@ -463,26 +502,27 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
463502
}
464503

465504
// Zram status
466-
let zramctl_output = Command::new("zramctl")
467-
.stdout(Stdio::piped())
468-
.output();
505+
let zramctl_output = Command::new("zramctl").stdout(Stdio::piped()).output();
469506

470507
if let Ok(output) = zramctl_output {
471508
let output_str = String::from_utf8_lossy(&output.stdout);
472509
if output_str.contains("[SWAP]") {
473510
println!("\nZram:");
474511
for line in output_str.lines() {
475512
if line.starts_with("NAME") || line.contains("[SWAP]") {
476-
let line = line.trim_end_matches("[SWAP]").trim_end_matches("MOUNTPOINT").trim();
513+
let line = line
514+
.trim_end_matches("[SWAP]")
515+
.trim_end_matches("MOUNTPOINT")
516+
.trim();
477517
println!(" {}", line);
478518
}
479519
}
480520
}
481521
}
482522

483-
// SwapFC status
484-
if Path::new(&format!("{}/swapfc", WORK_DIR)).is_dir() {
485-
println!("\nswapFC:");
523+
// SwapFile status
524+
if Path::new(&format!("{}/swapfile", WORK_DIR)).is_dir() {
525+
println!("\nswapfile:");
486526
let swapon_output = Command::new("swapon")
487527
.arg("--raw")
488528
.stdout(Stdio::piped())
@@ -501,23 +541,22 @@ fn status() -> Result<(), Box<dyn std::error::Error>> {
501541
/// Show recommended configuration based on system hardware
502542
fn autoconfig() -> Result<(), Box<dyn std::error::Error>> {
503543
println!("Detecting system capabilities...\n");
504-
544+
505545
let caps = SystemCapabilities::detect();
506546
let recommended = RecommendedConfig::from_capabilities(&caps);
507-
547+
508548
println!("=== System Information ===");
509549
println!("Swap path filesystem: {:?}", caps.swap_path_fstype);
510-
550+
511551
println!("\n=== Recommended Configuration ===");
512-
552+
513553
if recommended.use_zswap {
514554
println!("Mode: zswap + swapfc (best for desktop with supported filesystem)");
515555
} else {
516556
println!("Mode: zram only (fallback for unsupported filesystem)");
517557
}
518-
558+
519559
println!("\nNOTE: Specific parameters (compressor, sizes, etc.) are controlled via /etc/systemd/swap.conf");
520-
560+
521561
Ok(())
522562
}
523-

0 commit comments

Comments
 (0)