• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * f2fs_io.c - f2fs ioctl utility
3  *
4  * Author: Jaegeuk Kim <jaegeuk@kernel.org>
5  *
6  * Copied portion of the code from ../f2fscrypt.c
7  */
8 
9 #ifndef _GNU_SOURCE
10 #define _GNU_SOURCE
11 #endif
12 #ifndef _LARGEFILE_SOURCE
13 #define _LARGEFILE_SOURCE
14 #endif
15 #ifndef _LARGEFILE64_SOURCE
16 #define _LARGEFILE64_SOURCE
17 #endif
18 #ifndef O_LARGEFILE
19 #define O_LARGEFILE 0
20 #endif
21 
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <time.h>
28 #include <inttypes.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <termios.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 #include "f2fs_io.h"
39 
40 struct cmd_desc {
41 	const char *cmd_name;
42 	void (*cmd_func)(int, char **, const struct cmd_desc *);
43 	const char *cmd_desc;
44 	const char *cmd_help;
45 	int cmd_flags;
46 };
47 
48 #define shutdown_desc "shutdown filesystem"
49 #define shutdown_help					\
50 "f2fs_io shutdown [level] [dir]\n\n"			\
51 "Freeze and stop all IOs given mount point\n"		\
52 "level can be\n"					\
53 "  0 : going down with full sync\n"			\
54 "  1 : going down with checkpoint only\n"		\
55 "  2 : going down with no sync\n"			\
56 "  3 : going down with metadata flush\n"		\
57 "  4 : going down with fsck mark\n"
58 
do_shutdown(int argc,char ** argv,const struct cmd_desc * cmd)59 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
60 {
61 	u32 flag;
62 	int ret, fd;
63 
64 	if (argc != 3) {
65 		fputs("Excess arguments\n\n", stderr);
66 		fputs(cmd->cmd_help, stderr);
67 		exit(1);
68 	}
69 
70 	flag = atoi(argv[1]);
71 	if (flag >= F2FS_GOING_DOWN_MAX) {
72 		fputs("Wrong level\n\n", stderr);
73 		fputs(cmd->cmd_help, stderr);
74 		exit(1);
75 	}
76 	fd = open(argv[2], O_RDONLY);
77 	if (fd == -1) {
78 		fputs("Open failed\n\n", stderr);
79 		fputs(cmd->cmd_help, stderr);
80 		exit(1);
81 	}
82 
83 	ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
84 	if (ret < 0) {
85 		perror("F2FS_IOC_SHUTDOWN");
86 		exit(1);
87 	}
88 	printf("Shutdown %s with level=%d\n", argv[2], flag);
89 	exit(0);
90 }
91 
92 #define pinfile_desc "pin file control"
93 #define pinfile_help						\
94 "f2fs_io pinfile [get|set] [file]\n\n"			\
95 "get/set pinning given the file\n"				\
96 
do_pinfile(int argc,char ** argv,const struct cmd_desc * cmd)97 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
98 {
99 	u32 pin;
100 	int ret, fd;
101 
102 	if (argc != 3) {
103 		fputs("Excess arguments\n\n", stderr);
104 		fputs(cmd->cmd_help, stderr);
105 		exit(1);
106 	}
107 
108 	fd = open(argv[2], O_RDWR);
109 	if (fd == -1) {
110 		fputs("Open failed\n\n", stderr);
111 		fputs(cmd->cmd_help, stderr);
112 		exit(1);
113 	}
114 
115 	ret = -1;
116 	if (!strcmp(argv[1], "set")) {
117 		pin = 1;
118 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
119 		if (ret != 0) {
120 			perror("set_pin_file failed");
121 			exit(1);
122 		}
123 		printf("set_pin_file: %u blocks moved in %s\n", ret, argv[2]);
124 	} else if (!strcmp(argv[1], "get")) {
125 		unsigned int flags;
126 
127 		ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
128 		if (ret < 0) {
129 			perror("pin_file failed");
130 			exit(1);
131 		}
132 		ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
133 		if (ret < 0) {
134 			perror("get flags failed");
135 			exit(1);
136 		}
137 		printf("get_pin_file: %s with %u blocks moved in %s\n",
138 				(flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
139 				pin, argv[2]);
140 	}
141 	exit(0);
142 }
143 
144 #define write_desc "write data into file"
145 #define write_help					\
146 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path]\n\n"	\
147 "Write given patten data in file_path\n"		\
148 "pattern can be\n"					\
149 "  zero     : zeros\n"					\
150 "  inc_num  : incrementing numbers\n"			\
151 "  rand     : random numbers\n"				\
152 "IO can be\n"						\
153 "  buffered : buffered IO\n"				\
154 "  dio      : direct IO\n"				\
155 
do_write(int argc,char ** argv,const struct cmd_desc * cmd)156 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
157 {
158 	u64 buf_size = 0, inc_num = 0, ret = 0, written = 0;
159 	u64 offset;
160 	char *buf = NULL;
161 	unsigned bs, count, i;
162 	int flags = 0;
163 	int fd;
164 
165 	srand(time(0));
166 
167 	if (argc != 7) {
168 		fputs("Excess arguments\n\n", stderr);
169 		fputs(cmd->cmd_help, stderr);
170 		exit(1);
171 	}
172 
173 	bs = atoi(argv[1]);
174 	if (bs > 1024) {
175 		fputs("Too big chunk size - limit: 4MB\n\n", stderr);
176 		exit(1);
177 	}
178 	buf_size = bs * 4096;
179 
180 	offset = atoi(argv[2]) * buf_size;
181 
182 	buf = aligned_alloc(4096, buf_size);
183 	if (!buf) {
184 		fputs("Memory alloc failed\n\n", stderr);
185 		exit(1);
186 	}
187 	count = atoi(argv[3]);
188 
189 	if (!strcmp(argv[4], "zero")) {
190 		memset(buf, 0, buf_size);
191 	} else if (strcmp(argv[4], "inc_num") &&
192 			strcmp(argv[4], "rand")) {
193 		fputs("Wrong pattern type\n\n", stderr);
194 		exit(1);
195 	}
196 
197 	if (!strcmp(argv[5], "buffered")) {
198 		flags |= O_DIRECT;
199 	} else if (strcmp(argv[5], "dio")) {
200 		fputs("Wrong IO type\n\n", stderr);
201 		exit(1);
202 	}
203 
204 	fd = open(argv[6], O_CREAT | O_WRONLY | flags, 0755);
205 	if (fd == -1) {
206 		fputs("Open failed\n\n", stderr);
207 		exit(1);
208 	}
209 
210 	for (i = 0; i < count; i++) {
211 		if (!strcmp(argv[4], "inc_num"))
212 			*(int *)buf = inc_num++;
213 		else if (!strcmp(argv[4], "rand"))
214 			*(int *)buf = rand();
215 
216 		/* write data */
217 		ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
218 		if (ret != buf_size)
219 			break;
220 		written += ret;
221 	}
222 
223 	printf("Written %"PRIu64" bytes with pattern=%s\n", written, argv[4]);
224 	exit(0);
225 }
226 
227 #define read_desc "read data from file"
228 #define read_help					\
229 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n"	\
230 "Read data in file_path and print nbytes\n"		\
231 "IO can be\n"						\
232 "  buffered : buffered IO\n"				\
233 "  dio      : direct IO\n"				\
234 
do_read(int argc,char ** argv,const struct cmd_desc * cmd)235 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
236 {
237 	u64 buf_size = 0, ret = 0, read_cnt = 0;
238 	u64 offset;
239 	char *buf = NULL;
240 	char *print_buf = NULL;
241 	unsigned bs, count, i, print_bytes;
242 	int flags = 0;
243 	int fd;
244 
245 	if (argc != 7) {
246 		fputs("Excess arguments\n\n", stderr);
247 		fputs(cmd->cmd_help, stderr);
248 		exit(1);
249 	}
250 
251 	bs = atoi(argv[1]);
252 	if (bs > 1024) {
253 		fputs("Too big chunk size - limit: 4MB\n\n", stderr);
254 		exit(1);
255 	}
256 	buf_size = bs * 4096;
257 
258 	offset = atoi(argv[2]) * buf_size;
259 
260 	buf = aligned_alloc(4096, buf_size);
261 	if (!buf) {
262 		fputs("Memory alloc failed\n\n", stderr);
263 		exit(1);
264 	}
265 	count = atoi(argv[3]);
266 	if (!strcmp(argv[4], "buffered")) {
267 		flags |= O_DIRECT;
268 	} else if (strcmp(argv[4], "dio")) {
269 		fputs("Wrong IO type\n\n", stderr);
270 		exit(1);
271 	}
272 
273 	print_bytes = atoi(argv[5]);
274 	if (print_bytes > buf_size) {
275 		fputs("Print_nbytes should be less then chunk_size in kb\n\n", stderr);
276 		exit(1);
277 	}
278 	print_buf = malloc(print_bytes);
279 	if (!print_buf) {
280 		fputs("Memory alloc failed\n\n", stderr);
281 		exit(1);
282 	}
283 
284 	fd = open(argv[6], O_RDONLY | flags);
285 	if (fd == -1) {
286 		fputs("Open failed\n\n", stderr);
287 		exit(1);
288 	}
289 
290 	for (i = 0; i < count; i++) {
291 		ret = pread(fd, buf, buf_size, offset + buf_size * i);
292 		if (ret != buf_size)
293 			break;
294 
295 		read_cnt += ret;
296 		if (i == 0)
297 			memcpy(print_buf, buf, print_bytes);
298 	}
299 	printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
300 	printf("%08"PRIx64" : ", offset);
301 	for (i = 1; i <= print_bytes; i++) {
302 		printf("%02x", print_buf[i - 1]);
303 		if (i % 16 == 0)
304 			printf("\n%08"PRIx64" : ", offset + 16 * i);
305 		else if (i % 2 == 0)
306 			printf(" ");
307 	}
308 	printf("\n");
309 	exit(0);
310 }
311 
312 struct file_ext {
313 	__u32 f_pos;
314 	__u32 start_blk;
315 	__u32 end_blk;
316 	__u32 blk_count;
317 };
318 
319 #ifndef FIBMAP
320 #define FIBMAP          _IO(0x00, 1)    /* bmap access */
321 #endif
322 
323 #define fiemap_desc "get block address in file"
324 #define fiemap_help					\
325 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
326 
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)327 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
328 {
329 	u64 offset;
330 	u32 blknum;
331 	unsigned count, i;
332 	int fd;
333 
334 	if (argc != 4) {
335 		fputs("Excess arguments\n\n", stderr);
336 		fputs(cmd->cmd_help, stderr);
337 		exit(1);
338 	}
339 
340 	offset = atoi(argv[1]);
341 	count = atoi(argv[2]);
342 
343 	fd = open(argv[3], O_RDONLY | O_LARGEFILE);
344 	if (fd == -1) {
345 		fputs("Open failed\n\n", stderr);
346 		exit(1);
347 	}
348 
349 	printf("Fiemap: offset = %08"PRIx64" len = %d\n", offset, count);
350 	for (i = 0; i < count; i++) {
351 		blknum = offset + i;
352 
353 		if (ioctl(fd, FIBMAP, &blknum) < 0) {
354 			fputs("FIBMAP failed\n\n", stderr);
355 			exit(1);
356 		}
357 		printf("%u ", blknum);
358 	}
359 	printf("\n");
360 	exit(0);
361 }
362 
363 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
364 #define gc_urgent_help					\
365 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
366 " - f2fs_io gc_urgent sda21 start\n"		\
367 " - f2fs_io gc_urgent sda21 end\n"		\
368 " - f2fs_io gc_urgent sda21 run 10\n"		\
369 
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)370 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
371 {
372 	char command[255];
373 
374 	if (argc == 3 && !strcmp(argv[2], "start")) {
375 		printf("gc_urgent: start on %s\n", argv[1]);
376 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
377 		if (system(command))
378 			exit(1);
379 	} else if (argc == 3 && !strcmp(argv[2], "end")) {
380 		printf("gc_urgent: end on %s\n", argv[1]);
381 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
382 		if (system(command))
383 			exit(1);
384 	} else if (argc == 4 && !strcmp(argv[2], "run")) {
385 		printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
386 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
387 		if (system(command))
388 			exit(1);
389 		sleep(atoi(argv[3]));
390 		printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
391 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
392 		if (system(command))
393 			exit(1);
394 	} else {
395 		fputs("Excess arguments\n\n", stderr);
396 		fputs(cmd->cmd_help, stderr);
397 		exit(1);
398 	}
399 }
400 
401 #define CMD_HIDDEN 	0x0001
402 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
403 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
404 
405 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
406 const struct cmd_desc cmd_list[] = {
407 	_CMD(help),
408 	CMD(shutdown),
409 	CMD(pinfile),
410 	CMD(write),
411 	CMD(read),
412 	CMD(fiemap),
413 	CMD(gc_urgent),
414 	{ NULL, NULL, NULL, NULL, 0 }
415 };
416 
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))417 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
418 {
419 	const struct cmd_desc *p;
420 
421 	if (argc > 1) {
422 		for (p = cmd_list; p->cmd_name; p++) {
423 			if (p->cmd_flags & CMD_HIDDEN)
424 				continue;
425 			if (strcmp(p->cmd_name, argv[1]) == 0) {
426 				putc('\n', stdout);
427 				fputs("USAGE:\n  ", stdout);
428 				fputs(p->cmd_help, stdout);
429 				exit(0);
430 			}
431 		}
432 		printf("Unknown command: %s\n\n", argv[1]);
433 	}
434 
435 	fputs("Available commands:\n", stdout);
436 	for (p = cmd_list; p->cmd_name; p++) {
437 		if (p->cmd_flags & CMD_HIDDEN)
438 			continue;
439 		printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
440 	}
441 	printf("\nTo get more information on a command, "
442 	       "type 'f2fs_io help cmd'\n");
443 	exit(0);
444 }
445 
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))446 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
447 				void *UNUSED(context))
448 {
449 	exit(-1);
450 }
451 
sigcatcher_setup(void)452 static void sigcatcher_setup(void)
453 {
454 	struct sigaction	sa;
455 
456 	memset(&sa, 0, sizeof(struct sigaction));
457 	sa.sa_sigaction = die_signal_handler;
458 	sa.sa_flags = SA_SIGINFO;
459 
460 	sigaction(SIGHUP, &sa, 0);
461 	sigaction(SIGINT, &sa, 0);
462 	sigaction(SIGQUIT, &sa, 0);
463 	sigaction(SIGFPE, &sa, 0);
464 	sigaction(SIGILL, &sa, 0);
465 	sigaction(SIGBUS, &sa, 0);
466 	sigaction(SIGSEGV, &sa, 0);
467 	sigaction(SIGABRT, &sa, 0);
468 	sigaction(SIGPIPE, &sa, 0);
469 	sigaction(SIGALRM, &sa, 0);
470 	sigaction(SIGTERM, &sa, 0);
471 	sigaction(SIGUSR1, &sa, 0);
472 	sigaction(SIGUSR2, &sa, 0);
473 	sigaction(SIGPOLL, &sa, 0);
474 	sigaction(SIGPROF, &sa, 0);
475 	sigaction(SIGSYS, &sa, 0);
476 	sigaction(SIGTRAP, &sa, 0);
477 	sigaction(SIGVTALRM, &sa, 0);
478 	sigaction(SIGXCPU, &sa, 0);
479 	sigaction(SIGXFSZ, &sa, 0);
480 }
481 
main(int argc,char ** argv)482 int main(int argc, char **argv)
483 {
484 	const struct cmd_desc *cmd;
485 
486 	if (argc < 2)
487 		do_help(argc, argv, cmd_list);
488 
489 	sigcatcher_setup();
490 	for (cmd = cmd_list; cmd->cmd_name; cmd++) {
491 		if (strcmp(cmd->cmd_name, argv[1]) == 0) {
492 			cmd->cmd_func(argc - 1, argv + 1, cmd);
493 			exit(0);
494 		}
495 	}
496 	printf("Unknown command: %s\n\n", argv[1]);
497 	do_help(1, argv, cmd_list);
498 	return 0;
499 }
500