1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2010 Red Hat, Inc.
4 */
5
6 /*\
7 * [Description]
8 *
9 * zram: generic RAM based compressed R/W block devices
10 * http://lkml.org/lkml/2010/8/9/227
11 *
12 * This case check whether data read from zram device is consistent with
13 * thoese are written.
14 */
15
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/mman.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include "tst_safe_stdio.h"
25 #include "tst_test.h"
26
27 #define ZRAM_CONTROL_PATH "/sys/class/zram-control"
28 #define HOT_ADD_PATH ZRAM_CONTROL_PATH"/hot_add"
29 #define HOT_REMOVE_PATH ZRAM_CONTROL_PATH"/hot_remove"
30 #define SIZE (512 * 1024 * 1024L)
31
32 static char zram_block_path[100], zram_dev_path[100];
33 static int modprobe, dev_num, hot_add_flag;
34 static const char *const cmd_rmmod[] = {"rmmod", "zram", NULL};
35
set_disksize(void)36 static void set_disksize(void)
37 {
38 char disksize_path[200];
39
40 tst_res(TINFO, "create a zram device with %ld bytes in size", SIZE);
41 sprintf(disksize_path, "%s/disksize", zram_block_path);
42 SAFE_FILE_PRINTF(disksize_path, "%ld", SIZE);
43 }
44
write_device(void)45 static void write_device(void)
46 {
47 int fd;
48 char *s;
49
50 tst_res(TINFO, "map this zram device into memory");
51 fd = SAFE_OPEN(zram_dev_path, O_RDWR);
52 s = SAFE_MMAP(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
53
54 tst_res(TINFO, "write all the memory");
55 memset(s, 'a', SIZE - 1);
56 s[SIZE - 1] = '\0';
57
58 SAFE_MUNMAP(s, SIZE);
59 SAFE_CLOSE(fd);
60 }
61
verify_device(void)62 static void verify_device(void)
63 {
64 int fd;
65 long i = 0, fail = 0;
66 char *s;
67
68 tst_res(TINFO, "verify contents from device");
69 fd = SAFE_OPEN(zram_dev_path, O_RDONLY);
70 s = SAFE_MMAP(NULL, SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
71
72 while (s[i] && i < SIZE - 1) {
73 if (s[i] != 'a')
74 fail++;
75 i++;
76 }
77 if (i != SIZE - 1) {
78 tst_res(TFAIL, "expect size: %ld, actual size: %ld.",
79 SIZE - 1, i);
80 } else if (s[i] != '\0') {
81 tst_res(TFAIL, "zram device seems not null terminated");
82 } else if (fail) {
83 tst_res(TFAIL, "%ld failed bytes found", fail);
84 } else {
85 tst_res(TPASS, "data read from zram device is consistent with those are written");
86 }
87
88 SAFE_MUNMAP(s, SIZE);
89 SAFE_CLOSE(fd);
90 }
91
reset(void)92 static void reset(void)
93 {
94 char reset_path[200];
95
96 tst_res(TINFO, "Reset zram");
97 sprintf(reset_path, "%s/reset", zram_block_path);
98 SAFE_FILE_PRINTF(reset_path, "1");
99 }
100
print(char * string)101 static void print(char *string)
102 {
103 char filename[BUFSIZ], value[BUFSIZ];
104
105 tst_res(TINFO, "%s", zram_block_path);
106 sprintf(filename, "%s/%s", zram_block_path, string);
107 SAFE_FILE_SCANF(filename, "%s", value);
108 tst_res(TINFO, "%s is %s", filename, value);
109 }
110
print_stat(char * nread,char * nwrite)111 static void print_stat(char *nread, char *nwrite)
112 {
113 char nread_val[BUFSIZ], nwrite_val[BUFSIZ];
114 char zram_stat_path[100];
115
116 sprintf(zram_stat_path, "/sys/block/zram%d/stat", dev_num);
117 SAFE_FILE_SCANF(zram_stat_path, "%s %*s %*s %*s %s", nread_val, nwrite_val);
118 tst_res(TINFO, "%s from %s is %s", nread, zram_stat_path, nread_val);
119 tst_res(TINFO, "%s from %s is %s", nwrite, zram_stat_path, nwrite_val);
120 }
121
print_mm_stat(char * orig,char * compr,char * mem,char * zero)122 static void print_mm_stat(char *orig, char *compr, char *mem, char *zero)
123 {
124 char orig_val[BUFSIZ], compr_val[BUFSIZ];
125 char mem_val[BUFSIZ], zero_val[BUFSIZ];
126 char zram_mm_stat_path[100];
127
128 sprintf(zram_mm_stat_path, "/sys/block/zram%d/mm_stat", dev_num);
129 SAFE_FILE_SCANF(zram_mm_stat_path, "%s %s %s %*s %*s %s",
130 orig_val, compr_val, mem_val, zero_val);
131 tst_res(TINFO, "%s from %s is %s", orig, zram_mm_stat_path, orig_val);
132 tst_res(TINFO, "%s from %s is %s", compr, zram_mm_stat_path, compr_val);
133 tst_res(TINFO, "%s from %s is %s", mem, zram_mm_stat_path, mem_val);
134 tst_res(TINFO, "%s from %s is %s", zero, zram_mm_stat_path, zero_val);
135 }
136
dump_info(void)137 static void dump_info(void)
138 {
139 char zram_obsolete_file_path[100];
140
141 sprintf(zram_obsolete_file_path, "/sys/block/zram%d/num_reads", dev_num);
142 print("initstate");
143 print("disksize");
144 if (!access(zram_obsolete_file_path, F_OK)) {
145 print("orig_data_size");
146 print("compr_data_size");
147 print("mem_used_total");
148 print("zero_pages");
149 print("num_reads");
150 print("num_writes");
151 } else {
152 print_mm_stat("orig_data_size", "compr_data_size",
153 "mem_used_total", "zero/same_pages");
154 print_stat("num_reads", "num_writes");
155 }
156 }
157
run(void)158 static void run(void)
159 {
160 set_disksize();
161
162 write_device();
163 dump_info();
164 verify_device();
165
166 reset();
167 dump_info();
168 }
169
setup(void)170 static void setup(void)
171 {
172 const char *const cmd_modprobe[] = {"modprobe", "zram", NULL};
173 const char *const cmd_zramctl[] = {"zramctl", "-f", NULL};
174 const char *zramctl_log_path = "zramctl.log";
175 FILE *file;
176 char line[PATH_MAX];
177 int fd;
178
179 /* zram module was built in or loaded on new kernel */
180 if (!access(ZRAM_CONTROL_PATH, F_OK)) {
181 tst_res(TINFO,
182 "zram module already loaded, kernel supports zram-control interface");
183 SAFE_FILE_SCANF(HOT_ADD_PATH, "%d", &dev_num);
184 hot_add_flag =1;
185 goto fill_path;
186 }
187
188 /* zram module was built in or being used on old kernel */
189 SAFE_CMD(cmd_modprobe, NULL, NULL);
190 file = SAFE_FOPEN("/proc/modules", "r");
191 while (fgets(line, sizeof(line), file)) {
192 if (strstr(line, "zram")) {
193 modprobe = 1;
194 break;
195 }
196 }
197 SAFE_FCLOSE(file);
198 if (access(ZRAM_CONTROL_PATH, F_OK)) {
199 if (modprobe) {
200 tst_res(TINFO,
201 "rmmod zram before test on old kernel without zram-control interface");
202 if (!tst_cmd(cmd_rmmod, NULL, NULL, TST_CMD_PASS_RETVAL)) {
203 SAFE_CMD(cmd_modprobe, NULL, NULL);
204 goto fill_path;
205 }
206 } else {
207 tst_res(TINFO,
208 "zram module is built in old kernel without zram-control interface");
209 }
210
211 modprobe = 0;
212 tst_res(TINFO, "use zramctl -f to find free zram device");
213 fd = SAFE_OPEN(zramctl_log_path, O_CREAT | O_RDWR, 0644);
214 SAFE_CLOSE(fd);
215 if (tst_cmd(cmd_zramctl, zramctl_log_path, NULL, TST_CMD_PASS_RETVAL))
216 tst_brk(TCONF | TERRNO, "zramctl -f failed");
217 else
218 SAFE_FILE_SCANF(zramctl_log_path, "/dev/zram%d", &dev_num);
219 }
220
221 fill_path:
222 sprintf(zram_block_path, "/sys/block/zram%d", dev_num);
223 sprintf(zram_dev_path, "/dev/zram%d", dev_num);
224 }
225
cleanup(void)226 static void cleanup(void)
227 {
228 if (hot_add_flag)
229 SAFE_FILE_PRINTF(HOT_REMOVE_PATH, "%d", dev_num);
230
231 if (modprobe)
232 SAFE_CMD(cmd_rmmod, NULL, NULL);
233 }
234
235 static struct tst_test test = {
236 .test_all = run,
237 .setup = setup,
238 .cleanup = cleanup,
239 .needs_root = 1,
240 .needs_tmpdir = 1,
241 .needs_drivers = (const char *const []) {
242 "zram",
243 NULL
244 },
245 .needs_cmds = (const char *[]) {
246 "modprobe",
247 "rmmod",
248 NULL
249 }
250 };
251