2 * zramctl - control compressed block devices in RAM
4 * Copyright (c) 2014 Timofey Titovets <Nefelim4ag@gmail.com>
5 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <libsmartcols.h>
31 #include "closestream.h"
36 #include "ismounted.h"
38 /*#define CONFIG_ZRAM_DEBUG*/
40 #ifdef CONFIG_ZRAM_DEBUG
41 # define DBG(x) do { fputs("zram: ", stderr); x; fputc('\n', stderr); } while(0)
46 /* status output columns */
66 static const struct colinfo infos
[] = {
67 [COL_NAME
] = { "NAME", 0.25, 0, N_("zram device name") },
68 [COL_DISKSIZE
] = { "DISKSIZE", 5, SCOLS_FL_RIGHT
, N_("limit on the uncompressed amount of data") },
69 [COL_ORIG_SIZE
] = { "DATA", 5, SCOLS_FL_RIGHT
, N_("uncompressed size of stored data") },
70 [COL_COMP_SIZE
] = { "COMPR", 5, SCOLS_FL_RIGHT
, N_("compressed size of stored data") },
71 [COL_ALGORITHM
] = { "ALGORITHM", 3, 0, N_("the selected compression algorithm") },
72 [COL_STREAMS
] = { "STREAMS", 3, SCOLS_FL_RIGHT
, N_("number of concurrent compress operations") },
73 [COL_ZEROPAGES
] = { "ZERO-PAGES", 3, SCOLS_FL_RIGHT
, N_("empty pages with no allocated memory") },
74 [COL_MEMTOTAL
] = { "TOTAL", 5, SCOLS_FL_RIGHT
, N_("all memory including allocator fragmentation and metadata overhead") },
75 [COL_MOUNTPOINT
]= { "MOUNTPOINT",0.10, SCOLS_FL_TRUNC
, N_("where the device is mounted") },
78 static int columns
[ARRAY_SIZE(infos
) * 2] = {-1};
83 struct sysfs_cxt sysfs
;
86 #define ZRAM_EMPTY { .devname = { '\0' }, .sysfs = UL_SYSFSCXT_EMPTY }
88 static unsigned int raw
, no_headings
, inbytes
;
91 static int get_column_id(int num
)
93 assert(num
< ncolumns
);
94 assert(columns
[num
] < (int) ARRAY_SIZE(infos
));
98 static const struct colinfo
*get_column_info(int num
)
100 return &infos
[ get_column_id(num
) ];
103 static int column_name_to_id(const char *name
, size_t namesz
)
107 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++) {
108 const char *cn
= infos
[i
].name
;
110 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
113 warnx(_("unknown column: %s"), name
);
117 static void zram_set_devname(struct zram
*z
, const char *devname
, size_t n
)
122 snprintf(z
->devname
, sizeof(z
->devname
), "/dev/zram%zu", n
);
124 strncpy(z
->devname
, devname
, sizeof(z
->devname
));
125 z
->devname
[sizeof(z
->devname
) - 1] = '\0';
128 DBG(fprintf(stderr
, "set devname: %s", z
->devname
));
129 sysfs_deinit(&z
->sysfs
);
132 static struct zram
*new_zram(const char *devname
)
134 struct zram
*z
= xcalloc(1, sizeof(struct zram
));
136 DBG(fprintf(stderr
, "new: %p", z
));
138 zram_set_devname(z
, devname
, 0);
142 static void free_zram(struct zram
*z
)
146 DBG(fprintf(stderr
, "free: %p", z
));
147 sysfs_deinit(&z
->sysfs
);
151 static struct sysfs_cxt
*zram_get_sysfs(struct zram
*z
)
155 if (!z
->sysfs
.devno
) {
156 dev_t devno
= sysfs_devname_to_devno(z
->devname
, NULL
);
159 if (sysfs_init(&z
->sysfs
, devno
, NULL
))
166 static inline int zram_exist(struct zram
*z
)
170 if (zram_get_sysfs(z
) == NULL
)
173 DBG(fprintf(stderr
, "%s exists", z
->devname
));
177 static int zram_set_u64parm(struct zram
*z
, const char *attr
, uint64_t num
)
179 struct sysfs_cxt
*sysfs
= zram_get_sysfs(z
);
182 DBG(fprintf(stderr
, "%s writing %ju to %s", z
->devname
, num
, attr
));
183 return sysfs_write_u64(sysfs
, attr
, num
);
186 static int zram_set_strparm(struct zram
*z
, const char *attr
, const char *str
)
188 struct sysfs_cxt
*sysfs
= zram_get_sysfs(z
);
191 DBG(fprintf(stderr
, "%s writing %s to %s", z
->devname
, str
, attr
));
192 return sysfs_write_string(sysfs
, attr
, str
);
196 static int zram_used(struct zram
*z
)
199 struct sysfs_cxt
*sysfs
= zram_get_sysfs(z
);
202 sysfs_read_u64(sysfs
, "disksize", &size
) == 0 &&
205 DBG(fprintf(stderr
, "%s used", z
->devname
));
208 DBG(fprintf(stderr
, "%s unused", z
->devname
));
212 static struct zram
*find_free_zram(void)
214 struct zram
*z
= new_zram(NULL
);
218 for (i
= 0; isfree
== 0; i
++) {
219 DBG(fprintf(stderr
, "find free: checking zram%zu", i
));
220 zram_set_devname(z
, NULL
, i
);
223 isfree
= !zram_used(z
);
232 static void fill_table_row(struct libscols_table
*tb
, struct zram
*z
)
234 static struct libscols_line
*ln
;
235 struct sysfs_cxt
*sysfs
;
242 DBG(fprintf(stderr
, "%s: filling status table", z
->devname
));
244 sysfs
= zram_get_sysfs(z
);
248 ln
= scols_table_new_line(tb
, NULL
);
250 err(EXIT_FAILURE
, _("failed to initialize output line"));
252 for (i
= 0; i
< (size_t) ncolumns
; i
++) {
255 switch (get_column_id(i
)) {
257 str
= xstrdup(z
->devname
);
261 str
= sysfs_strdup(sysfs
, "disksize");
262 else if (sysfs_read_u64(sysfs
, "disksize", &num
) == 0)
263 str
= size_to_human_string(SIZE_SUFFIX_1LETTER
, num
);
267 str
= sysfs_strdup(sysfs
, "orig_data_size");
268 else if (sysfs_read_u64(sysfs
, "orig_data_size", &num
) == 0)
269 str
= size_to_human_string(SIZE_SUFFIX_1LETTER
, num
);
273 str
= sysfs_strdup(sysfs
, "compr_data_size");
274 else if (sysfs_read_u64(sysfs
, "compr_data_size", &num
) == 0)
275 str
= size_to_human_string(SIZE_SUFFIX_1LETTER
, num
);
279 char *alg
= sysfs_strdup(sysfs
, "comp_algorithm");
282 if (strstr(alg
, "[lzo]") == NULL
) {
283 if (strstr(alg
, "[lz4]") == NULL
)
286 str
= xstrdup("lz4");
288 str
= xstrdup("lzo");
294 char path
[PATH_MAX
] = { '\0' };
297 check_mount_point(z
->devname
, &fl
, path
, sizeof(path
));
303 str
= sysfs_strdup(sysfs
, "max_comp_streams");
306 str
= sysfs_strdup(sysfs
, "zero_pages");
310 str
= sysfs_strdup(sysfs
, "mem_used_total");
311 else if (sysfs_read_u64(sysfs
, "mem_used_total", &num
) == 0)
312 str
= size_to_human_string(SIZE_SUFFIX_1LETTER
, num
);
317 scols_line_refer_data(ln
, i
, str
);
321 static void status(struct zram
*z
)
323 struct libscols_table
*tb
;
328 tb
= scols_new_table();
330 err(EXIT_FAILURE
, _("failed to initialize output table"));
332 scols_table_enable_raw(tb
, raw
);
333 scols_table_enable_noheadings(tb
, no_headings
);
335 for (i
= 0; i
< (size_t) ncolumns
; i
++) {
336 const struct colinfo
*col
= get_column_info(i
);
338 if (!scols_table_new_column(tb
, col
->name
, col
->whint
, col
->flags
))
339 err(EXIT_FAILURE
, _("failed to initialize output column"));
343 fill_table_row(tb
, z
); /* just one device specified */
345 size_t i
; /* list all used devices */
349 zram_set_devname(z
, NULL
, i
);
353 fill_table_row(tb
, z
);
358 scols_print_table(tb
);
359 scols_unref_table(tb
);
362 static void __attribute__ ((__noreturn__
)) usage(FILE * out
)
366 fputs(USAGE_HEADER
, out
);
367 fprintf(out
, _( " %1$s [options] <device>\n"
368 " %1$s -r <device> [...]\n"
369 " %1$s [options] -f | <device> -s <size>\n"),
370 program_invocation_short_name
);
372 fputs(USAGE_OPTIONS
, out
);
373 fputs(_(" -a, --algorithm lzo|lz4 compression algorithm to use\n"), out
);
374 fputs(_(" -b, --bytes print sizes in bytes rather than in human readable format\n"), out
);
375 fputs(_(" -f, --find find a free device\n"), out
);
376 fputs(_(" -n, --noheadings don't print headings\n"), out
);
377 fputs(_(" -o, --output <list> columns to use for status output\n"), out
);
378 fputs(_(" --raw use raw status output format\n"), out
);
379 fputs(_(" -r, --reset reset all specified devices\n"), out
);
380 fputs(_(" -s, --size <size> device size\n"), out
);
381 fputs(_(" -t, --streams <number> number of compression streams\n"), out
);
383 fputs(USAGE_SEPARATOR
, out
);
384 fputs(USAGE_HELP
, out
);
385 fputs(USAGE_VERSION
, out
);
387 fputs(_("\nAvailable columns (for --output):\n"), out
);
388 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++)
389 fprintf(out
, " %11s %s\n", infos
[i
].name
, _(infos
[i
].help
));
391 fprintf(out
, USAGE_MAN_TAIL("zramctl(8)"));
392 exit(out
== stderr
? 1 : EXIT_SUCCESS
);
404 int main(int argc
, char **argv
)
406 uintmax_t size
= 0, nstreams
= 0;
407 char *algorithm
= NULL
;
408 int rc
= 0, c
, find
= 0, act
= A_NONE
;
409 struct zram
*zram
= NULL
;
411 enum { OPT_RAW
= CHAR_MAX
+ 1 };
413 static const struct option longopts
[] = {
414 { "algorithm", required_argument
, NULL
, 'a' },
415 { "bytes", no_argument
, NULL
, 'b' },
416 { "find", no_argument
, NULL
, 'f' },
417 { "help", no_argument
, NULL
, 'h' },
418 { "output", required_argument
, NULL
, 'o' },
419 { "noheadings",no_argument
, NULL
, 'n' },
420 { "reset", no_argument
, NULL
, 'r' },
421 { "raw", no_argument
, NULL
, OPT_RAW
},
422 { "size", required_argument
, NULL
, 's' },
423 { "streams", required_argument
, NULL
, 't' },
424 { "version", no_argument
, NULL
, 'V' },
428 static const ul_excl_t excl
[] = {
433 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
435 setlocale(LC_ALL
, "");
436 bindtextdomain(PACKAGE
, LOCALEDIR
);
438 atexit(close_stdout
);
440 while ((c
= getopt_long(argc
, argv
, "a:bfho:nrs:t:V", longopts
, NULL
)) != -1) {
442 err_exclusive_options(c
, longopts
, excl
, excl_st
);
446 if (strcmp(optarg
,"lzo") && strcmp(optarg
,"lz4"))
447 errx(EXIT_FAILURE
, _("unsupported algorithm: %s"),
458 ncolumns
= string_to_idarray(optarg
,
459 columns
, ARRAY_SIZE(columns
),
465 size
= strtosize_or_err(optarg
, _("failed to parse size"));
469 nstreams
= strtou64_or_err(optarg
, _("failed to parse streams"));
481 printf(UTIL_LINUX_VERSION
);
490 if (find
&& optind
< argc
)
491 errx(EXIT_FAILURE
, _("option --find is mutually exclusive "
494 act
= find
? A_FINDONLY
: A_STATUS
;
496 if (act
!= A_RESET
&& optind
+ 1 < argc
)
497 usage(stderr
); /* only --reset holds more devices */
501 if (algorithm
|| find
|| nstreams
)
502 errx(EXIT_FAILURE
, _("options --algorithm, --find and "
503 "--streams are mutually exclusive"));
504 if (!ncolumns
) { /* default columns */
505 columns
[ncolumns
++] = COL_NAME
;
506 columns
[ncolumns
++] = COL_ALGORITHM
;
507 columns
[ncolumns
++] = COL_DISKSIZE
;
508 columns
[ncolumns
++] = COL_ORIG_SIZE
;
509 columns
[ncolumns
++] = COL_COMP_SIZE
;
510 columns
[ncolumns
++] = COL_MEMTOTAL
;
511 columns
[ncolumns
++] = COL_STREAMS
;
512 columns
[ncolumns
++] = COL_MOUNTPOINT
;
515 zram
= new_zram(argv
[optind
++]);
521 errx(EXIT_FAILURE
, _("no device specified"));
522 while (optind
< argc
) {
523 zram
= new_zram(argv
[optind
]);
524 if (zram_set_u64parm(zram
, "reset", 1)) {
525 warn(_("%s: failed to reset"), zram
->devname
);
533 zram
= find_free_zram();
535 errx(EXIT_FAILURE
, _("no free zram device found"));
536 printf("%s\n", zram
->devname
);
541 zram
= find_free_zram();
543 errx(EXIT_FAILURE
, _("no free zram device found"));
544 } else if (optind
== argc
)
545 errx(EXIT_FAILURE
, _("no device specified"));
547 zram
= new_zram(argv
[optind
]);
549 if (zram_set_u64parm(zram
, "reset", 1))
550 err(EXIT_FAILURE
, _("%s: failed to reset"), zram
->devname
);
553 zram_set_u64parm(zram
, "max_comp_streams", nstreams
))
554 err(EXIT_FAILURE
, _("%s: failed to set number of streams"), zram
->devname
);
557 zram_set_strparm(zram
, "comp_algorithm", algorithm
))
558 err(EXIT_FAILURE
, _("%s: failed to set algorithm"), zram
->devname
);
560 if (zram_set_u64parm(zram
, "disksize", size
))
561 err(EXIT_FAILURE
, _("%s: failed to set disksize (%ju bytes)"),
562 zram
->devname
, size
);
564 printf("%s\n", zram
->devname
);
569 return rc
? EXIT_FAILURE
: EXIT_SUCCESS
;