Skip to content

Commit 0fb828f

Browse files
nabijaczlewelikeszybz
authored andcommitted
compression-algorithm=algo(param,param) recompalgo(param,param) (global,recomp,params)
Ref: #178 (comment)
1 parent ed0b421 commit 0fb828f

File tree

7 files changed

+160
-19
lines changed

7 files changed

+160
-19
lines changed

man/zram-generator.conf.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,14 @@ Devices with the final size of *0* will be discarded.
7272

7373
Specifies the algorithm used to compress the zram device.
7474

75-
This takes a literal string, representing the algorithm to use.<br />
76-
Consult */sys/block/zram0/comp_algorithm* for a list of currently loaded compression algorithms, but note that additional ones may be loaded on demand.
75+
This takes a whitespace-separated list string, representing the algorithms to use, and parameters in parenteses.<br />
76+
Consult */sys/block/zram0/comp_algorithm* (and *.../recomp_algorithm*) for a list of currently loaded compression algorithms, but note that additional ones may be loaded on demand.
7777

78-
If unset, none will be configured and the kernel's default will be used.
78+
If unset, none will be configured and the kernel's default will be used.<br />
79+
If more than one is given, and recompression is enabled in the kernel, subsequent ones will be set as the recompression algorithms, with decreasing priority.
80+
81+
If a compression algorithm is suffixed with a parenthesised comma-separated list of parameters, those are given to `.../algorithm_params` (and `.../recompress`).
82+
A parenthesised parameter list *without* a compression algorithm is set as the global recompression parameters.
7983

8084
* `writeback-device`=
8185

src/config.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub struct Device {
2222

2323
/// Default: `DEFAULT_ZRAM_SIZE`
2424
pub zram_size: Option<(String, fasteval::ExpressionI, fasteval::Slab)>,
25-
pub compression_algorithm: Option<String>,
25+
pub compression_algorithms: Algorithms,
2626
pub writeback_dev: Option<PathBuf>,
2727
pub disksize: u64,
2828

@@ -50,7 +50,7 @@ impl Device {
5050
name,
5151
host_memory_limit_mb: None,
5252
zram_size: None,
53-
compression_algorithm: None,
53+
compression_algorithms: Default::default(),
5454
writeback_dev: None,
5555
disksize: 0,
5656
zram_resident_limit: None,
@@ -165,7 +165,7 @@ impl fmt::Display for Device {
165165
.as_ref()
166166
.map(|zs| &zs.0[..])
167167
.unwrap_or(DEFAULT_RESIDENT_LIMIT),
168-
self.compression_algorithm.as_deref().unwrap_or("<default>"),
168+
self.compression_algorithms,
169169
self.writeback_dev.as_deref().unwrap_or_else(|| Path::new("<none>")).display(),
170170
self.options
171171
)?;
@@ -196,6 +196,35 @@ impl fmt::Display for OptMB {
196196
}
197197
}
198198

199+
#[derive(Default, Debug, PartialEq, Eq)]
200+
pub struct Algorithms {
201+
pub compression_algorithms: Vec<(String, String)>, // algorithm, params; first one is real compression, later ones are recompression
202+
pub recompression_global: String, // params
203+
}
204+
impl fmt::Display for Algorithms {
205+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206+
match &self.compression_algorithms[..] {
207+
[] => f.write_str("<default>")?,
208+
[(first, firstparams), more @ ..] => {
209+
f.write_str(first)?;
210+
if !firstparams.is_empty() {
211+
write!(f, " ({})", firstparams)?;
212+
}
213+
for (algo, params) in more {
214+
write!(f, " then {}", algo)?;
215+
if !params.is_empty() {
216+
write!(f, " ({})", params)?;
217+
}
218+
}
219+
}
220+
}
221+
if !self.recompression_global.is_empty() {
222+
write!(f, "(global recompress: {})", self.recompression_global)?;
223+
}
224+
Ok(())
225+
}
226+
}
227+
199228
struct RamNs(f64);
200229
impl fasteval::EvalNamespace for RamNs {
201230
fn lookup(&mut self, name: &str, args: Vec<f64>, _: &mut String) -> Option<f64> {
@@ -360,6 +389,19 @@ fn parse_size_expr(
360389
))
361390
}
362391

392+
fn parse_compression_algorithm_params(whole: &str) -> (String, String) {
393+
if let Some(paren) = whole.find('(') {
394+
let (algo, mut params) = whole.split_at(paren);
395+
params = &params[1..];
396+
if params.ends_with(')') {
397+
params = &params[..params.len() - 1];
398+
}
399+
(algo.to_string(), params.replace(',', " "))
400+
} else {
401+
(whole.to_string(), String::new())
402+
}
403+
}
404+
363405
fn parse_line(dev: &mut Device, key: &str, value: &str) -> Result<()> {
364406
match key {
365407
"host-memory-limit" | "memory-limit" => {
@@ -376,7 +418,18 @@ fn parse_line(dev: &mut Device, key: &str, value: &str) -> Result<()> {
376418
}
377419

378420
"compression-algorithm" => {
379-
dev.compression_algorithm = Some(value.to_string());
421+
dev.compression_algorithms =
422+
value
423+
.split_whitespace()
424+
.fold(Default::default(), |mut algos, s| {
425+
let (algo, params) = parse_compression_algorithm_params(s);
426+
if algo.is_empty() {
427+
algos.recompression_global = params;
428+
} else {
429+
algos.compression_algorithms.push((algo, params));
430+
}
431+
algos
432+
});
380433
}
381434

382435
"writeback-device" => {

src/generator.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,13 @@ pub fn run_generator(devices: &[Device], output_directory: &Path, fake_mode: boo
117117

118118
let compressors: BTreeSet<_> = devices
119119
.iter()
120-
.flat_map(|device| device.compression_algorithm.as_deref())
120+
.flat_map(|device| {
121+
device
122+
.compression_algorithms
123+
.compression_algorithms
124+
.iter()
125+
.map(|(a, _)| a.as_ref())
126+
})
121127
.collect();
122128

123129
if !compressors.is_empty() {

src/setup.rs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,71 @@ pub fn run_device_setup(device: Option<Device>, device_name: &str) -> Result<()>
2424

2525
let device_sysfs_path = Path::new("/sys/block").join(device_name);
2626

27-
if let Some(ref compression_algorithm) = device.compression_algorithm {
28-
let comp_algorithm_path = device_sysfs_path.join("comp_algorithm");
29-
match fs::write(&comp_algorithm_path, compression_algorithm) {
30-
Ok(_) => {}
27+
for (prio, (algo, params)) in device
28+
.compression_algorithms
29+
.compression_algorithms
30+
.iter()
31+
.enumerate()
32+
{
33+
let params = if params.is_empty() {
34+
None
35+
} else {
36+
Some(params)
37+
};
38+
let (path, data, add_pathdata) = if prio == 0 {
39+
(
40+
device_sysfs_path.join("comp_algorithm"),
41+
algo,
42+
params.as_ref().map(|p| {
43+
(
44+
device_sysfs_path.join("algorithm_params"),
45+
format!("algo={} {}", algo, p),
46+
)
47+
}),
48+
)
49+
} else {
50+
(
51+
device_sysfs_path.join("recomp_algorithm"),
52+
&format!("algo={} priority={}", algo, prio),
53+
params.as_ref().map(|p| {
54+
(
55+
device_sysfs_path.join("recompress"),
56+
format!("{} priority={}", p, prio),
57+
)
58+
}),
59+
)
60+
};
61+
62+
match fs::write(&path, data) {
63+
Ok(_) => {
64+
if let Some((add_path, add_data)) = add_pathdata {
65+
match fs::write(add_path, add_data) {
66+
Ok(_) => {}
67+
Err(err) => {
68+
warn!(
69+
"Warning: algorithm {:?} supplemental data {:?} not written: {}",
70+
algo, data, err,
71+
);
72+
}
73+
}
74+
}
75+
}
3176
Err(err) if err.kind() == ErrorKind::InvalidInput => {
3277
warn!(
3378
"Warning: algorithm {:?} not recognised; consult {} for a list of available ones",
34-
compression_algorithm, comp_algorithm_path.display(),
79+
algo, path.display(),
80+
);
81+
}
82+
Err(err) if err.kind() == ErrorKind::PermissionDenied && prio != 0 => {
83+
warn!(
84+
"Warning: recompression algorithm {:?} requested but recompression not available ({} doesn't exist)",
85+
algo, path.display(),
3586
);
3687
}
3788
err @ Err(_) => err.with_context(|| {
3889
format!(
3990
"Failed to configure compression algorithm into {}",
40-
comp_algorithm_path.display()
91+
path.display()
4192
)
4293
})?,
4394
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[zram0]
2-
compression-algorithm = zstd
2+
compression-algorithm = zstd(dictionary=/etc/gaming,level=9) (recompargs)
33
host-memory-limit = 2050
44
zram-size = min(0.75 * ram, 6000)

tests/test_cases.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,13 @@ fn test_02_zstd() {
124124
assert!(d.is_swap());
125125
assert_eq!(d.host_memory_limit_mb, Some(2050));
126126
assert_eq!(d.zram_size.as_ref().map(z_s_name), Some("ram * 0.75"));
127-
assert_eq!(d.compression_algorithm.as_ref().unwrap(), "zstd");
127+
assert_eq!(
128+
d.compression_algorithms,
129+
config::Algorithms {
130+
compression_algorithms: vec![("zstd".into(), "".into())],
131+
..Default::default()
132+
}
133+
);
128134
assert_eq!(d.options, "discard");
129135
}
130136

@@ -259,7 +265,13 @@ fn test_09_zram_size() {
259265
d.zram_size.as_ref().map(z_s_name),
260266
Some("min(0.75 * ram, 6000)")
261267
);
262-
assert_eq!(d.compression_algorithm.as_ref().unwrap(), "zstd");
268+
assert_eq!(
269+
d.compression_algorithms,
270+
config::Algorithms {
271+
compression_algorithms: vec![("zstd".into(), "dictionary=/etc/gaming level=9".into())],
272+
recompression_global: "recompargs".into()
273+
}
274+
);
263275
}
264276

265277
#[test]
@@ -283,7 +295,16 @@ fn test_10_example() {
283295
d.zram_size.as_ref().map(z_s_name),
284296
Some("min(ram / 10, 2048)")
285297
);
286-
assert_eq!(d.compression_algorithm.as_deref(), Some("lzo-rle"));
298+
assert_eq!(
299+
d.compression_algorithms,
300+
config::Algorithms {
301+
compression_algorithms: vec![
302+
("lzo-rle".into(), "".into()),
303+
("zstd".into(), "level=3".into())
304+
],
305+
recompression_global: "type=idle".into(),
306+
}
307+
);
287308
assert_eq!(d.options, "");
288309
}
289310
"zram1" => {

zram-generator.conf.example

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ zram-resident-limit = 0
2929

3030
# The compression algorithm to use for the zram device,
3131
# or leave unspecified to keep the kernel default.
32-
compression-algorithm = lzo-rle
32+
#
33+
# Subsequent algorithms are used for recompression.
34+
# Comma-separated parameters may be specified in parentheses.
35+
#
36+
# Parameters without a compression algorithm are set as
37+
# global recompression parameters.
38+
compression-algorithm = lzo-rle zstd(level=3) (type=idle)
3339

3440
# By default, file systems and swap areas are trimmed on-the-go
3541
# by setting "discard".

0 commit comments

Comments
 (0)