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