1 /*
2 * zram: generic RAM based compressed R/W block devices
3 * http://lkml.org/lkml/2010/8/9/227
4 *
5 * Copyright (C) 2010 Red Hat, Inc.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * Further, this software is distributed without any warranty that it
15 * is free of the rightful claim of any third person regarding
16 * infringement or the like. Any license provided herein, whether
17 * implied or otherwise, applies only to this software file. Patent
18 * licenses, if any, provided herein do not apply to combinations of
19 * this program with other software, or any other product whatsoever.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * 02110-1301, USA.
25 */
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/mman.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include "test.h"
37 #include "safe_macros.h"
38
39 char *TCID = "zram03";
40 int TST_TOTAL = 1;
41
42 #define PATH_ZRAM "/sys/block/zram0"
43 #define OBSOLETE_ZRAM_FILE "/sys/block/zram0/num_reads"
44 #define PATH_ZRAM_STAT "/sys/block/zram0/stat"
45 #define PATH_ZRAM_MM_STAT "/sys/block/zram0/mm_stat"
46 #define SIZE (512 * 1024 * 1024L)
47 #define DEVICE "/dev/zram0"
48
49 static int modprobe;
50
51 static void set_disksize(void);
52 static void write_device(void);
53 static void verify_device(void);
54 static void reset(void);
55 static void setup(void);
56 static void cleanup(void);
57 static void print(char *string);
58 static void dump_info(void);
59
main(int argc,char * argv[])60 int main(int argc, char *argv[])
61 {
62 int lc;
63
64 tst_parse_opts(argc, argv, NULL, NULL);
65
66 setup();
67
68 for (lc = 0; TEST_LOOPING(lc); lc++) {
69 tst_count = 0;
70
71 set_disksize();
72
73 write_device();
74 dump_info();
75 verify_device();
76
77 reset();
78 dump_info();
79 }
80 cleanup();
81 tst_exit();
82 }
83
set_disksize(void)84 static void set_disksize(void)
85 {
86 tst_resm(TINFO, "create a zram device with %ld bytes in size.", SIZE);
87 SAFE_FILE_PRINTF(cleanup, PATH_ZRAM "/disksize", "%ld", SIZE);
88 }
89
write_device(void)90 static void write_device(void)
91 {
92 int fd;
93 char *s;
94
95 tst_resm(TINFO, "map this zram device into memory.");
96 fd = SAFE_OPEN(cleanup, DEVICE, O_RDWR);
97 s = SAFE_MMAP(cleanup, NULL, SIZE, PROT_READ | PROT_WRITE,
98 MAP_SHARED, fd, 0);
99
100 tst_resm(TINFO, "write all the memory.");
101 memset(s, 'a', SIZE - 1);
102 s[SIZE - 1] = '\0';
103
104 SAFE_MUNMAP(cleanup, s, SIZE);
105 SAFE_CLOSE(cleanup, fd);
106 }
107
verify_device(void)108 static void verify_device(void)
109 {
110 int fd;
111 long i = 0, fail = 0;
112 char *s;
113
114 tst_resm(TINFO, "verify contents from device.");
115 fd = SAFE_OPEN(cleanup, DEVICE, O_RDONLY);
116 s = SAFE_MMAP(cleanup, NULL, SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
117
118 while (s[i] && i < SIZE - 1) {
119 if (s[i] != 'a')
120 fail++;
121 i++;
122 }
123 if (i != SIZE - 1) {
124 tst_resm(TFAIL, "expect size: %ld, actual size: %ld.",
125 SIZE - 1, i);
126 } else if (s[i] != '\0') {
127 tst_resm(TFAIL, "zram device seems not null terminated");
128 } else if (fail) {
129 tst_resm(TFAIL, "%ld failed bytes found.", fail);
130 } else {
131 tst_resm(TPASS, "data read from zram device is consistent "
132 "with those are written");
133 }
134
135 SAFE_MUNMAP(cleanup, s, SIZE);
136 SAFE_CLOSE(cleanup, fd);
137 }
138
reset(void)139 static void reset(void)
140 {
141 tst_resm(TINFO, "reset it.");
142 SAFE_FILE_PRINTF(cleanup, PATH_ZRAM "/reset", "1");
143 }
144
setup(void)145 static void setup(void)
146 {
147 int retried = 0;
148
149 tst_require_root();
150
151 retry:
152 if (access(PATH_ZRAM, F_OK) == -1) {
153 if (errno == ENOENT) {
154 if (retried) {
155 tst_brkm(TCONF, NULL,
156 "system has no zram device.");
157 }
158 if (system("modprobe zram") == -1) {
159 tst_brkm(TBROK | TERRNO, cleanup,
160 "system(modprobe zram) failed");
161 }
162 modprobe = 1;
163 retried = 1;
164 goto retry;
165 } else
166 tst_brkm(TBROK | TERRNO, NULL, "access");
167 }
168
169 tst_sig(FORK, DEF_HANDLER, cleanup);
170 TEST_PAUSE;
171 }
172
cleanup(void)173 static void cleanup(void)
174 {
175 if (modprobe == 1 && system("rmmod zram") == -1)
176 tst_resm(TWARN | TERRNO, "system(rmmod zram) failed");
177 }
178
print(char * string)179 static void print(char *string)
180 {
181 char filename[BUFSIZ], value[BUFSIZ];
182
183 sprintf(filename, "%s/%s", PATH_ZRAM, string);
184 SAFE_FILE_SCANF(cleanup, filename, "%s", value);
185 tst_resm(TINFO, "%s is %s", filename, value);
186 }
187
print_stat(char * nread,char * nwrite)188 static void print_stat(char *nread, char *nwrite)
189 {
190 char nread_val[BUFSIZ], nwrite_val[BUFSIZ];
191
192 SAFE_FILE_SCANF(cleanup, PATH_ZRAM_STAT, "%s %*s %*s %*s %s",
193 nread_val, nwrite_val);
194 tst_resm(TINFO, "%s from %s is %s", nread, PATH_ZRAM_STAT,
195 nread_val);
196 tst_resm(TINFO, "%s from %s is %s", nwrite, PATH_ZRAM_STAT,
197 nwrite_val);
198 }
199
print_mm_stat(char * orig,char * compr,char * mem,char * zero)200 static void print_mm_stat(char *orig, char *compr, char *mem, char *zero)
201 {
202 char orig_val[BUFSIZ], compr_val[BUFSIZ];
203 char mem_val[BUFSIZ], zero_val[BUFSIZ];
204
205 SAFE_FILE_SCANF(cleanup, PATH_ZRAM_MM_STAT, "%s %s %s %*s %*s %s",
206 orig_val, compr_val, mem_val, zero_val);
207 tst_resm(TINFO, "%s from %s is %s", orig, PATH_ZRAM_MM_STAT,
208 orig_val);
209 tst_resm(TINFO, "%s from %s is %s", compr, PATH_ZRAM_MM_STAT,
210 compr_val);
211 tst_resm(TINFO, "%s from %s is %s", mem, PATH_ZRAM_MM_STAT,
212 mem_val);
213 tst_resm(TINFO, "%s from %s is %s", zero, PATH_ZRAM_MM_STAT,
214 zero_val);
215 }
216
dump_info(void)217 static void dump_info(void)
218 {
219 print("initstate");
220 print("disksize");
221 if (!access(OBSOLETE_ZRAM_FILE, F_OK)) {
222 print("orig_data_size");
223 print("compr_data_size");
224 print("mem_used_total");
225 print("zero_pages");
226 print("num_reads");
227 print("num_writes");
228 } else {
229 print_mm_stat("orig_data_size", "compr_data_size",
230 "mem_used_total", "zero/same_pages");
231 print_stat("num_reads", "num_writes");
232 }
233 }
234