• 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 #ifndef __SANE_USERSPACE_TYPES__
22 #define __SANE_USERSPACE_TYPES__       /* For PPC64, to get LL64 types */
23 #endif
24 
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <getopt.h>
28 #include <inttypes.h>
29 #include <limits.h>
30 #include <linux/fs.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/mman.h>
38 #include <sys/sendfile.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <termios.h>
42 #include <time.h>
43 #include <unistd.h>
44 
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 #include <android_config.h>
49 
50 #include "f2fs_io.h"
51 
52 struct cmd_desc {
53 	const char *cmd_name;
54 	void (*cmd_func)(int, char **, const struct cmd_desc *);
55 	const char *cmd_desc;
56 	const char *cmd_help;
57 	int cmd_flags;
58 };
59 
60 static void __attribute__((noreturn))
do_die(const char * format,va_list va,int err)61 do_die(const char *format, va_list va, int err)
62 {
63 	vfprintf(stderr, format, va);
64 	if (err)
65 		fprintf(stderr, ": %s", strerror(err));
66 	putc('\n', stderr);
67 	exit(1);
68 }
69 
70 static void __attribute__((noreturn, format(printf, 1, 2)))
die_errno(const char * format,...)71 die_errno(const char *format, ...)
72 {
73 	va_list va;
74 
75 	va_start(va, format);
76 	do_die(format, va, errno);
77 	va_end(va);
78 }
79 
80 static void __attribute__((noreturn, format(printf, 1, 2)))
die(const char * format,...)81 die(const char *format, ...)
82 {
83 	va_list va;
84 
85 	va_start(va, format);
86 	do_die(format, va, 0);
87 	va_end(va);
88 }
89 
xmalloc(size_t size)90 static void *xmalloc(size_t size)
91 {
92 	void *p = malloc(size);
93 
94 	if (!p)
95 		die("Memory alloc failed (requested %zu bytes)", size);
96 	return p;
97 }
98 
aligned_xalloc(size_t alignment,size_t size)99 static void *aligned_xalloc(size_t alignment, size_t size)
100 {
101 	void *p = aligned_alloc(alignment, size);
102 
103 	if (!p)
104 		die("Memory alloc failed (requested %zu bytes)", size);
105 	return p;
106 }
107 
xopen(const char * pathname,int flags,mode_t mode)108 static int xopen(const char *pathname, int flags, mode_t mode)
109 {
110 	int fd = open(pathname, flags, mode);
111 
112 	if (fd < 0)
113 		die_errno("Failed to open %s", pathname);
114 	return fd;
115 }
116 
xread(int fd,void * buf,size_t count)117 static ssize_t xread(int fd, void *buf, size_t count)
118 {
119 	ssize_t ret = read(fd, buf, count);
120 
121 	if (ret < 0)
122 		die_errno("read failed");
123 	return ret;
124 }
125 
full_write(int fd,const void * buf,size_t count)126 static void full_write(int fd, const void *buf, size_t count)
127 {
128 	while (count) {
129 		ssize_t ret = write(fd, buf, count);
130 
131 		if (ret < 0)
132 			die_errno("write failed");
133 		buf = (char *)buf + ret;
134 		count -= ret;
135 	}
136 }
137 
138 #ifdef HAVE_MACH_TIME_H
get_current_us()139 static u64 get_current_us()
140 {
141 	return mach_absolute_time() / 1000;
142 }
143 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME)
get_current_us()144 static u64 get_current_us()
145 {
146 	struct timespec t;
147 	t.tv_sec = t.tv_nsec = 0;
148 	clock_gettime(CLOCK_BOOTTIME, &t);
149 	return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
150 }
151 #else
get_current_us()152 static u64 get_current_us()
153 {
154 	return 0;
155 }
156 #endif
157 
158 #define fsync_desc "fsync"
159 #define fsync_help						\
160 "f2fs_io fsync [file]\n\n"					\
161 "fsync given the file\n"					\
162 
do_fsync(int argc,char ** argv,const struct cmd_desc * cmd)163 static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
164 {
165 	int fd;
166 
167 	if (argc != 2) {
168 		fputs("Excess arguments\n\n", stderr);
169 		fputs(cmd->cmd_help, stderr);
170 		exit(1);
171 	}
172 
173 	fd = xopen(argv[1], O_WRONLY, 0);
174 
175 	if (fsync(fd) != 0)
176 		die_errno("fsync failed");
177 
178 	printf("fsync a file\n");
179 	exit(0);
180 }
181 
182 #define set_verity_desc "Set fs-verity"
183 #define set_verity_help					\
184 "f2fs_io set_verity [file]\n\n"				\
185 "Set fsverity bit given a file\n"			\
186 
do_set_verity(int argc,char ** argv,const struct cmd_desc * cmd)187 static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
188 {
189 	int ret, fd;
190 
191 	if (argc != 2) {
192 		fputs("Excess arguments\n\n", stderr);
193 		fputs(cmd->cmd_help, stderr);
194 		exit(1);
195 	}
196 
197 	fd = open(argv[1], O_RDWR);
198 
199 	ret = ioctl(fd, FS_IOC_ENABLE_VERITY);
200 	if (ret < 0) {
201 		perror("FS_IOC_ENABLE_VERITY");
202 		exit(1);
203 	}
204 
205 	printf("Set fsverity bit to %s\n", argv[1]);
206 	exit(0);
207 }
208 
209 #define getflags_desc "getflags ioctl"
210 #define getflags_help						\
211 "f2fs_io getflags [file]\n\n"					\
212 "get a flag given the file\n"					\
213 "flag can show \n"						\
214 "  encryption\n"						\
215 "  nocow(pinned)\n"						\
216 "  inline_data\n"						\
217 "  verity\n"							\
218 "  casefold\n"							\
219 "  compression\n"						\
220 "  nocompression\n"						\
221 "  immutable\n"
222 
do_getflags(int argc,char ** argv,const struct cmd_desc * cmd)223 static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
224 {
225 	long flag = 0;
226 	int ret, fd;
227 	int exist = 0;
228 
229 	if (argc != 2) {
230 		fputs("Excess arguments\n\n", stderr);
231 		fputs(cmd->cmd_help, stderr);
232 		exit(1);
233 	}
234 
235 	fd = xopen(argv[1], O_RDONLY, 0);
236 
237 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
238 	printf("get a flag on %s ret=%d, flags=", argv[1], ret);
239 	if (flag & FS_CASEFOLD_FL) {
240 		printf("casefold");
241 		exist = 1;
242 	}
243 	if (flag & FS_COMPR_FL) {
244 		if (exist)
245 			printf(",");
246 		printf("compression");
247 		exist = 1;
248 	}
249 	if (flag & FS_NOCOMP_FL) {
250 		if (exist)
251 			printf(",");
252 		printf("nocompression");
253 		exist = 1;
254 	}
255 	if (flag & FS_ENCRYPT_FL) {
256 		if (exist)
257 			printf(",");
258 		printf("encrypt");
259 		exist = 1;
260 	}
261 	if (flag & FS_VERITY_FL) {
262 		if (exist)
263 			printf(",");
264 		printf("verity");
265 		exist = 1;
266 	}
267 	if (flag & FS_INLINE_DATA_FL) {
268 		if (exist)
269 			printf(",");
270 		printf("inline_data");
271 		exist = 1;
272 	}
273 	if (flag & FS_NOCOW_FL) {
274 		if (exist)
275 			printf(",");
276 		printf("nocow(pinned)");
277 		exist = 1;
278 	}
279 	if (flag & FS_IMMUTABLE_FL) {
280 		if (exist)
281 			printf(",");
282 		printf("immutable");
283 		exist = 1;
284 	}
285 	if (!exist)
286 		printf("none");
287 	printf("\n");
288 	exit(0);
289 }
290 
291 #define setflags_desc "setflags ioctl"
292 #define setflags_help						\
293 "f2fs_io setflags [flag] [file]\n\n"				\
294 "set a flag given the file\n"					\
295 "flag can be\n"							\
296 "  casefold\n"							\
297 "  compression\n"						\
298 "  nocompression\n"						\
299 "  noimmutable\n"
300 
do_setflags(int argc,char ** argv,const struct cmd_desc * cmd)301 static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
302 {
303 	long flag = 0;
304 	int ret, fd;
305 
306 	if (argc != 3) {
307 		fputs("Excess arguments\n\n", stderr);
308 		fputs(cmd->cmd_help, stderr);
309 		exit(1);
310 	}
311 
312 	fd = xopen(argv[2], O_RDONLY, 0);
313 
314 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
315 	printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
316 	if (ret)
317 		die_errno("F2FS_IOC_GETFLAGS failed");
318 
319 	if (!strcmp(argv[1], "casefold"))
320 		flag |= FS_CASEFOLD_FL;
321 	else if (!strcmp(argv[1], "compression"))
322 		flag |= FS_COMPR_FL;
323 	else if (!strcmp(argv[1], "nocompression"))
324 		flag |= FS_NOCOMP_FL;
325 	else if (!strcmp(argv[1], "noimmutable"))
326 		flag &= ~FS_IMMUTABLE_FL;
327 
328 	ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
329 	printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
330 	exit(0);
331 }
332 
333 #define shutdown_desc "shutdown filesystem"
334 #define shutdown_help					\
335 "f2fs_io shutdown [level] [dir]\n\n"			\
336 "Freeze and stop all IOs given mount point\n"		\
337 "level can be\n"					\
338 "  0 : going down with full sync\n"			\
339 "  1 : going down with checkpoint only\n"		\
340 "  2 : going down with no sync\n"			\
341 "  3 : going down with metadata flush\n"		\
342 "  4 : going down with fsck mark\n"
343 
do_shutdown(int argc,char ** argv,const struct cmd_desc * cmd)344 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
345 {
346 	u32 flag;
347 	int ret, fd;
348 
349 	if (argc != 3) {
350 		fputs("Excess arguments\n\n", stderr);
351 		fputs(cmd->cmd_help, stderr);
352 		exit(1);
353 	}
354 
355 	flag = atoi(argv[1]);
356 	if (flag >= F2FS_GOING_DOWN_MAX) {
357 		fputs("Wrong level\n\n", stderr);
358 		fputs(cmd->cmd_help, stderr);
359 		exit(1);
360 	}
361 	fd = xopen(argv[2], O_RDONLY, 0);
362 
363 	ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
364 	if (ret < 0)
365 		die_errno("F2FS_IOC_SHUTDOWN failed");
366 
367 	printf("Shutdown %s with level=%d\n", argv[2], flag);
368 	exit(0);
369 }
370 
371 #define pinfile_desc "pin file control"
372 #define pinfile_help						\
373 "f2fs_io pinfile [get|set] [file]\n\n"			\
374 "get/set pinning given the file\n"				\
375 
do_pinfile(int argc,char ** argv,const struct cmd_desc * cmd)376 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
377 {
378 	u32 pin;
379 	int ret, fd;
380 
381 	if (argc != 3) {
382 		fputs("Excess arguments\n\n", stderr);
383 		fputs(cmd->cmd_help, stderr);
384 		exit(1);
385 	}
386 
387 	fd = xopen(argv[2], O_RDONLY, 0);
388 
389 	ret = -1;
390 	if (!strcmp(argv[1], "set")) {
391 		pin = 1;
392 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
393 		if (ret != 0)
394 			die_errno("F2FS_IOC_SET_PIN_FILE failed");
395 		printf("set_pin_file: %u blocks moved in %s\n", ret, argv[2]);
396 	} else if (!strcmp(argv[1], "get")) {
397 		unsigned int flags;
398 
399 		ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
400 		if (ret < 0)
401 			die_errno("F2FS_IOC_GET_PIN_FILE failed");
402 
403 		ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
404 		if (ret < 0)
405 			die_errno("F2FS_IOC_GETFLAGS failed");
406 
407 		printf("get_pin_file: %s with %u blocks moved in %s\n",
408 				(flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
409 				pin, argv[2]);
410 	}
411 	exit(0);
412 }
413 
414 #define fallocate_desc "fallocate"
415 #define fallocate_help						\
416 "f2fs_io fallocate [keep_size] [offset] [length] [file]\n\n"	\
417 "fallocate given the file\n"					\
418 " [keep_size] : 1 or 0\n"					\
419 
do_fallocate(int argc,char ** argv,const struct cmd_desc * cmd)420 static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
421 {
422 	int fd;
423 	off_t offset, length;
424 	struct stat sb;
425 	int mode = 0;
426 
427 	if (argc != 5) {
428 		fputs("Excess arguments\n\n", stderr);
429 		fputs(cmd->cmd_help, stderr);
430 		exit(1);
431 	}
432 
433 	if (!strcmp(argv[1], "1"))
434 		mode |= FALLOC_FL_KEEP_SIZE;
435 
436 	offset = atoi(argv[2]);
437 	length = atoll(argv[3]);
438 
439 	fd = xopen(argv[4], O_RDWR, 0);
440 
441 	if (fallocate(fd, mode, offset, length) != 0)
442 		die_errno("fallocate failed");
443 
444 	if (fstat(fd, &sb) != 0)
445 		die_errno("fstat failed");
446 
447 	printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
448 	exit(0);
449 }
450 
451 #define erase_desc "erase a block device"
452 #define erase_help				\
453 "f2fs_io erase [block_device_path]\n\n"		\
454 "Send DISCARD | BLKSECDISCARD comamnd to"	\
455 "block device in block_device_path\n"		\
456 
do_erase(int argc,char ** argv,const struct cmd_desc * cmd)457 static void do_erase(int argc, char **argv, const struct cmd_desc *cmd)
458 {
459 	int fd, ret;
460 	struct stat st;
461 	u64 range[2];
462 
463 	if (argc != 2) {
464 		fputs("Excess arguments\n\n", stderr);
465 		fputs(cmd->cmd_help, stderr);
466 		exit(1);
467 	}
468 
469 	if (stat(argv[1], &st) != 0) {
470 		fputs("stat error\n", stderr);
471 		exit(1);
472 	}
473 
474 	if (!S_ISBLK(st.st_mode)) {
475 		fputs(argv[1], stderr);
476 		fputs(" is not a block device\n", stderr);
477 		exit(1);
478 	}
479 
480 	fd = xopen(argv[1], O_WRONLY, 0);
481 
482 	range[0] = 0;
483 	ret = ioctl(fd, BLKGETSIZE64, &range[1]);
484 	if (ret < 0) {
485 		fputs("get size failed\n", stderr);
486 		exit(1);
487 	}
488 
489 	ret = ioctl(fd, BLKSECDISCARD, &range);
490 	if (ret < 0) {
491 		ret = ioctl(fd, BLKDISCARD, &range);
492 		if (ret < 0) {
493 			fputs("Discard failed\n", stderr);
494 			exit(1);
495 		}
496 	}
497 
498 	exit(0);
499 }
500 
501 #define write_desc "write data into file"
502 #define write_help					\
503 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path] {delay}\n\n"	\
504 "Write given patten data in file_path\n"		\
505 "pattern can be\n"					\
506 "  zero          : zeros\n"				\
507 "  inc_num       : incrementing numbers\n"		\
508 "  rand          : random numbers\n"			\
509 "IO can be\n"						\
510 "  buffered      : buffered IO\n"			\
511 "  dio           : O_DIRECT\n"				\
512 "  dsync         : O_DIRECT | O_DSYNC\n"		\
513 "  osync         : O_SYNC\n"				\
514 "  atomic_commit : atomic write & commit\n"		\
515 "  atomic_abort  : atomic write & abort\n"		\
516 "  atomic_rcommit: atomic replace & commit\n"	\
517 "  atomic_rabort : atomic replace & abort\n"	\
518 "{delay} is in ms unit and optional only for atomic operations\n"
519 
do_write(int argc,char ** argv,const struct cmd_desc * cmd)520 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
521 {
522 	u64 buf_size = 0, inc_num = 0, written = 0;
523 	u64 offset;
524 	char *buf = NULL;
525 	unsigned bs, count, i;
526 	int flags = 0;
527 	int fd;
528 	u64 total_time = 0, max_time = 0, max_time_t = 0;
529 	bool atomic_commit = false, atomic_abort = false, replace = false;
530 	int useconds = 0;
531 
532 	srand(time(0));
533 
534 	if (argc < 7 || argc > 8) {
535 		fputs("Excess arguments\n\n", stderr);
536 		fputs(cmd->cmd_help, stderr);
537 		exit(1);
538 	}
539 
540 	bs = atoi(argv[1]);
541 	if (bs > 1024)
542 		die("Too big chunk size - limit: 4MB");
543 
544 	buf_size = bs * 4096;
545 
546 	offset = atoi(argv[2]) * buf_size;
547 
548 	buf = aligned_xalloc(4096, buf_size);
549 	count = atoi(argv[3]);
550 
551 	if (!strcmp(argv[4], "zero"))
552 		memset(buf, 0, buf_size);
553 	else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
554 		die("Wrong pattern type");
555 
556 	if (!strcmp(argv[5], "dio")) {
557 		flags |= O_DIRECT;
558 	} else if (!strcmp(argv[5], "dsync")) {
559 		flags |= O_DIRECT | O_DSYNC;
560 	} else if (!strcmp(argv[5], "osync")) {
561 		flags |= O_SYNC;
562 	} else if (!strcmp(argv[5], "atomic_commit")) {
563 		atomic_commit = true;
564 	} else if (!strcmp(argv[5], "atomic_abort")) {
565 		atomic_abort = true;
566 	} else if (!strcmp(argv[5], "atomic_rcommit")) {
567 		atomic_commit = true;
568 		replace = true;
569 	} else if (!strcmp(argv[5], "atomic_rabort")) {
570 		atomic_abort = true;
571 		replace = true;
572 	} else if (strcmp(argv[5], "buffered")) {
573 		die("Wrong IO type");
574 	}
575 
576 	fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
577 
578 	if (atomic_commit || atomic_abort) {
579 		int ret;
580 
581 		if (argc == 8)
582 			useconds = atoi(argv[7]) * 1000;
583 
584 		if (replace)
585 			ret = ioctl(fd, F2FS_IOC_START_ATOMIC_REPLACE);
586 		else
587 			ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
588 
589 		if (ret < 0) {
590 			fputs("setting atomic file mode failed\n", stderr);
591 			exit(1);
592 		}
593 	}
594 
595 	total_time = get_current_us();
596 	for (i = 0; i < count; i++) {
597 		uint64_t ret;
598 
599 		if (!strcmp(argv[4], "inc_num"))
600 			*(int *)buf = inc_num++;
601 		else if (!strcmp(argv[4], "rand"))
602 			*(int *)buf = rand();
603 
604 		/* write data */
605 		max_time_t = get_current_us();
606 		ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
607 		max_time_t = get_current_us() - max_time_t;
608 		if (max_time < max_time_t)
609 			max_time = max_time_t;
610 		if (ret != buf_size)
611 			break;
612 		written += ret;
613 	}
614 
615 	if (useconds)
616 		usleep(useconds);
617 
618 	if (atomic_commit) {
619 		int ret;
620 
621 		ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
622 		if (ret < 0) {
623 			fputs("committing atomic write failed\n", stderr);
624 			exit(1);
625 		}
626 	} else if (atomic_abort) {
627 		int ret;
628 
629 		ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
630 		if (ret < 0) {
631 			fputs("aborting atomic write failed\n", stderr);
632 			exit(1);
633 		}
634 	}
635 
636 	printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
637 				written, argv[4],
638 				get_current_us() - total_time,
639 				max_time);
640 	exit(0);
641 }
642 
643 #define read_desc "read data from file"
644 #define read_help					\
645 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n"	\
646 "Read data in file_path and print nbytes\n"		\
647 "IO can be\n"						\
648 "  buffered : buffered IO\n"				\
649 "  dio      : direct IO\n"				\
650 "  mmap     : mmap IO\n"				\
651 
do_read(int argc,char ** argv,const struct cmd_desc * cmd)652 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
653 {
654 	u64 buf_size = 0, ret = 0, read_cnt = 0;
655 	u64 offset;
656 	char *buf = NULL;
657 	char *data;
658 	char *print_buf = NULL;
659 	unsigned bs, count, i, print_bytes;
660 	int flags = 0;
661 	int do_mmap = 0;
662 	int fd;
663 
664 	if (argc != 7) {
665 		fputs("Excess arguments\n\n", stderr);
666 		fputs(cmd->cmd_help, stderr);
667 		exit(1);
668 	}
669 
670 	bs = atoi(argv[1]);
671 	if (bs > 1024)
672 		die("Too big chunk size - limit: 4MB");
673 	buf_size = bs * 4096;
674 
675 	offset = atoi(argv[2]) * buf_size;
676 
677 	buf = aligned_xalloc(4096, buf_size);
678 
679 	count = atoi(argv[3]);
680 	if (!strcmp(argv[4], "dio"))
681 		flags |= O_DIRECT;
682 	else if (!strcmp(argv[4], "mmap"))
683 		do_mmap = 1;
684 	else if (strcmp(argv[4], "buffered"))
685 		die("Wrong IO type");
686 
687 	print_bytes = atoi(argv[5]);
688 	if (print_bytes > buf_size)
689 		die("Print_nbytes should be less then chunk_size in kb");
690 
691 	print_buf = xmalloc(print_bytes);
692 
693 	fd = xopen(argv[6], O_RDONLY | flags, 0);
694 
695 	if (do_mmap) {
696 		data = mmap(NULL, count * buf_size, PROT_READ,
697 						MAP_SHARED, fd, offset);
698 		if (data == MAP_FAILED)
699 			die("Mmap failed");
700 	}
701 
702 	for (i = 0; i < count; i++) {
703 		if (do_mmap) {
704 			memcpy(buf, data + offset + buf_size * i, buf_size);
705 			ret = buf_size;
706 		} else {
707 			ret = pread(fd, buf, buf_size, offset + buf_size * i);
708 		}
709 		if (ret != buf_size)
710 			break;
711 
712 		read_cnt += ret;
713 		if (i == 0)
714 			memcpy(print_buf, buf, print_bytes);
715 	}
716 	printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
717 	printf("%08"PRIx64" : ", offset);
718 	for (i = 1; i <= print_bytes; i++) {
719 		printf("%02x", print_buf[i - 1]);
720 		if (i % 16 == 0)
721 			printf("\n%08"PRIx64" : ", offset + 16 * i);
722 		else if (i % 2 == 0)
723 			printf(" ");
724 	}
725 	printf("\n");
726 	exit(0);
727 }
728 
729 #define randread_desc "random read data from file"
730 #define randread_help					\
731 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n"	\
732 "Do random read data in file_path\n"		\
733 "IO can be\n"						\
734 "  buffered : buffered IO\n"				\
735 "  dio      : direct IO\n"				\
736 
do_randread(int argc,char ** argv,const struct cmd_desc * cmd)737 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
738 {
739 	u64 buf_size = 0, ret = 0, read_cnt = 0;
740 	u64 idx, end_idx, aligned_size;
741 	char *buf = NULL;
742 	unsigned bs, count, i;
743 	int flags = 0;
744 	int fd;
745 	time_t t;
746 	struct stat stbuf;
747 
748 	if (argc != 5) {
749 		fputs("Excess arguments\n\n", stderr);
750 		fputs(cmd->cmd_help, stderr);
751 		exit(1);
752 	}
753 
754 	bs = atoi(argv[1]);
755 	if (bs > 1024)
756 		die("Too big chunk size - limit: 4MB");
757 	buf_size = bs * 4096;
758 
759 	buf = aligned_xalloc(4096, buf_size);
760 
761 	count = atoi(argv[2]);
762 	if (!strcmp(argv[3], "dio"))
763 		flags |= O_DIRECT;
764 	else if (strcmp(argv[3], "buffered"))
765 		die("Wrong IO type");
766 
767 	fd = xopen(argv[4], O_RDONLY | flags, 0);
768 
769 	if (fstat(fd, &stbuf) != 0)
770 		die_errno("fstat of source file failed");
771 
772 	aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
773 	if (aligned_size < buf_size)
774 		die("File is too small to random read");
775 	end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
776 
777 	srand((unsigned) time(&t));
778 
779 	for (i = 0; i < count; i++) {
780 		idx = rand() % end_idx;
781 
782 		ret = pread(fd, buf, buf_size, 4096 * idx);
783 		if (ret != buf_size)
784 			break;
785 
786 		read_cnt += ret;
787 	}
788 	printf("Read %"PRIu64" bytes\n", read_cnt);
789 	exit(0);
790 }
791 
792 #define fiemap_desc "get block address in file"
793 #define fiemap_help					\
794 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
795 
796 #if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)797 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
798 {
799 	unsigned int i;
800 	int fd, extents_mem_size;
801 	u64 start, length;
802 	u32 mapped_extents;
803 	struct fiemap *fm = xmalloc(sizeof(struct fiemap));
804 
805 	if (argc != 4) {
806 		fputs("Excess arguments\n\n", stderr);
807 		fputs(cmd->cmd_help, stderr);
808 		exit(1);
809 	}
810 
811 	memset(fm, 0, sizeof(struct fiemap));
812 	start = atoi(argv[1]) * F2FS_BLKSIZE;
813 	length = atoi(argv[2]) * F2FS_BLKSIZE;
814 	fm->fm_start = start;
815 	fm->fm_length = length;
816 
817 	fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
818 
819 	printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n",
820 				start / F2FS_BLKSIZE, length / F2FS_BLKSIZE);
821 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
822 		die_errno("FIEMAP failed");
823 
824 	mapped_extents = fm->fm_mapped_extents;
825 	extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents;
826 	free(fm);
827 	fm = xmalloc(sizeof(struct fiemap) + extents_mem_size);
828 
829 	memset(fm, 0, sizeof(struct fiemap) + extents_mem_size);
830 	fm->fm_start = start;
831 	fm->fm_length = length;
832 	fm->fm_extent_count = mapped_extents;
833 
834 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
835 		die_errno("FIEMAP failed");
836 
837 	printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags");
838 	for (i = 0; i < fm->fm_mapped_extents; i++) {
839 		printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i,
840 		    fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical,
841 		    fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags);
842 
843 		if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST)
844 			break;
845 	}
846 	printf("\n");
847 	free(fm);
848 	exit(0);
849 }
850 #else
do_fiemap(int UNUSED (argc),char ** UNUSED (argv),const struct cmd_desc * UNUSED (cmd))851 static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
852 			const struct cmd_desc *UNUSED(cmd))
853 {
854 	die("Not support for this platform");
855 }
856 #endif
857 
858 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
859 #define gc_urgent_help					\
860 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
861 " - f2fs_io gc_urgent sda21 start\n"		\
862 " - f2fs_io gc_urgent sda21 end\n"		\
863 " - f2fs_io gc_urgent sda21 run 10\n"		\
864 
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)865 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
866 {
867 	char command[255];
868 
869 	if (argc == 3 && !strcmp(argv[2], "start")) {
870 		printf("gc_urgent: start on %s\n", argv[1]);
871 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
872 		if (system(command))
873 			exit(1);
874 	} else if (argc == 3 && !strcmp(argv[2], "end")) {
875 		printf("gc_urgent: end on %s\n", argv[1]);
876 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
877 		if (system(command))
878 			exit(1);
879 	} else if (argc == 4 && !strcmp(argv[2], "run")) {
880 		printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
881 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
882 		if (system(command))
883 			exit(1);
884 		sleep(atoi(argv[3]));
885 		printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
886 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
887 		if (system(command))
888 			exit(1);
889 	} else {
890 		fputs("Excess arguments\n\n", stderr);
891 		fputs(cmd->cmd_help, stderr);
892 		exit(1);
893 	}
894 }
895 
896 #define defrag_file_desc "do defragment on file"
897 #define defrag_file_help						\
898 "f2fs_io defrag_file [start] [length] [file_path]\n\n"		\
899 "  start     : start offset of defragment region, unit: bytes\n"	\
900 "  length    : bytes number of defragment region\n"			\
901 
do_defrag_file(int argc,char ** argv,const struct cmd_desc * cmd)902 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
903 {
904 	struct f2fs_defragment df;
905 	u64 len;
906 	int ret, fd;
907 
908 	if (argc != 4) {
909 		fputs("Excess arguments\n\n", stderr);
910 		fputs(cmd->cmd_help, stderr);
911 		exit(1);
912 	}
913 
914 	df.start = atoll(argv[1]);
915 	df.len = len = atoll(argv[2]);
916 
917 	fd = xopen(argv[3], O_RDWR, 0);
918 
919 	ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
920 	if (ret < 0)
921 		die_errno("F2FS_IOC_DEFRAGMENT failed");
922 
923 	printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
924 			argv[3], df.start, df.start + len);
925 	exit(0);
926 }
927 
928 #define copy_desc "copy a file"
929 #define copy_help							\
930 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n"			\
931 "  src_path  : path to source file\n"					\
932 "  dst_path  : path to destination file\n"				\
933 "  -d        : use direct I/O\n"					\
934 "  -m        : mmap the source file\n"					\
935 "  -s        : use sendfile\n"						\
936 
do_copy(int argc,char ** argv,const struct cmd_desc * cmd)937 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
938 {
939 	int c;
940 	int src_fd;
941 	int dst_fd;
942 	int open_flags = 0;
943 	bool mmap_source_file = false;
944 	bool use_sendfile = false;
945 	ssize_t ret;
946 
947 	while ((c = getopt(argc, argv, "dms")) != -1) {
948 		switch (c) {
949 		case 'd':
950 			open_flags |= O_DIRECT;
951 			break;
952 		case 'm':
953 			mmap_source_file = true;
954 			break;
955 		case 's':
956 			use_sendfile = true;
957 			break;
958 		default:
959 			fputs(cmd->cmd_help, stderr);
960 			exit(2);
961 		}
962 	}
963 	argc -= optind;
964 	argv += optind;
965 	if (argc != 2) {
966 		fputs("Wrong number of arguments\n\n", stderr);
967 		fputs(cmd->cmd_help, stderr);
968 		exit(2);
969 	}
970 	if (mmap_source_file && use_sendfile)
971 		die("-m and -s are mutually exclusive");
972 
973 	src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
974 	dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
975 
976 	if (mmap_source_file) {
977 		struct stat stbuf;
978 		void *src_addr;
979 
980 		if (fstat(src_fd, &stbuf) != 0)
981 			die_errno("fstat of source file failed");
982 
983 		if ((size_t)stbuf.st_size != stbuf.st_size)
984 			die("Source file is too large");
985 
986 		src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
987 				src_fd, 0);
988 		if (src_addr == MAP_FAILED)
989 			die("mmap of source file failed");
990 
991 		full_write(dst_fd, src_addr, stbuf.st_size);
992 
993 		munmap(src_addr, stbuf.st_size);
994 	} else if (use_sendfile) {
995 		while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
996 			;
997 		if (ret < 0)
998 			die_errno("sendfile failed");
999 	} else {
1000 		char *buf = aligned_xalloc(4096, 4096);
1001 
1002 		while ((ret = xread(src_fd, buf, 4096)) > 0)
1003 			full_write(dst_fd, buf, ret);
1004 		free(buf);
1005 	}
1006 	close(src_fd);
1007 	close(dst_fd);
1008 }
1009 
1010 #define get_cblocks_desc "get number of reserved blocks on compress inode"
1011 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
1012 
do_get_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1013 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1014 {
1015 	unsigned long long blkcnt;
1016 	int ret, fd;
1017 
1018 	if (argc != 2) {
1019 		fputs("Excess arguments\n\n", stderr);
1020 		fputs(cmd->cmd_help, stderr);
1021 		exit(1);
1022 	}
1023 
1024 	fd = xopen(argv[1], O_RDONLY, 0);
1025 
1026 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
1027 	if (ret < 0)
1028 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
1029 
1030 	printf("%llu\n", blkcnt);
1031 
1032 	exit(0);
1033 }
1034 
1035 #define release_cblocks_desc "release reserved blocks on compress inode"
1036 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
1037 
do_release_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1038 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1039 {
1040 	unsigned long long blkcnt;
1041 	int ret, fd;
1042 
1043 	if (argc != 2) {
1044 		fputs("Excess arguments\n\n", stderr);
1045 		fputs(cmd->cmd_help, stderr);
1046 		exit(1);
1047 	}
1048 
1049 	fd = xopen(argv[1], O_RDONLY, 0);
1050 
1051 	ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
1052 	if (ret < 0)
1053 		die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
1054 
1055 	printf("%llu\n", blkcnt);
1056 
1057 	exit(0);
1058 }
1059 
1060 #define reserve_cblocks_desc "reserve blocks on compress inode"
1061 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
1062 
do_reserve_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1063 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1064 {
1065 	unsigned long long blkcnt;
1066 	int ret, fd;
1067 
1068 	if (argc != 2) {
1069 		fputs("Excess arguments\n\n", stderr);
1070 		fputs(cmd->cmd_help, stderr);
1071 		exit(1);
1072 	}
1073 
1074 	fd = xopen(argv[1], O_RDONLY, 0);
1075 
1076 	ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
1077 	if (ret < 0)
1078 		die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
1079 
1080 	printf("%llu\n", blkcnt);
1081 
1082 	exit(0);
1083 }
1084 
1085 #define get_coption_desc "get compression option of a compressed file"
1086 #define get_coption_help						\
1087 "f2fs_io get_coption [file]\n\n"	\
1088 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1089 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1090 
do_get_coption(int argc,char ** argv,const struct cmd_desc * cmd)1091 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
1092 {
1093 	struct f2fs_comp_option option;
1094 	int ret, fd;
1095 
1096 	if (argc != 2) {
1097 		fputs("Excess arguments\n\n", stderr);
1098 		fputs(cmd->cmd_help, stderr);
1099 		exit(1);
1100 	}
1101 
1102 	fd = xopen(argv[1], O_RDONLY, 0);
1103 
1104 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
1105 	if (ret < 0)
1106 		die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
1107 
1108 	printf("compression algorithm:%u\n", option.algorithm);
1109 	printf("compression cluster log size:%u\n", option.log_cluster_size);
1110 
1111 	exit(0);
1112 }
1113 
1114 #define set_coption_desc "set compression option of a compressed file"
1115 #define set_coption_help						\
1116 "f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n"	\
1117 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1118 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1119 
do_set_coption(int argc,char ** argv,const struct cmd_desc * cmd)1120 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
1121 {
1122 	struct f2fs_comp_option option;
1123 	int fd, ret;
1124 
1125 	if (argc != 4) {
1126 		fputs("Excess arguments\n\n", stderr);
1127 		fputs(cmd->cmd_help, stderr);
1128 		exit(1);
1129 	}
1130 
1131 	option.algorithm = atoi(argv[1]);
1132 	option.log_cluster_size = atoi(argv[2]);
1133 
1134 	fd = xopen(argv[3], O_WRONLY, 0);
1135 
1136 	ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
1137 	if (ret < 0)
1138 		die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
1139 
1140 	printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
1141 			option.algorithm, option.log_cluster_size);
1142 	exit(0);
1143 }
1144 
1145 #define decompress_desc "decompress an already compressed file"
1146 #define decompress_help "f2fs_io decompress [file_path]\n\n"
1147 
do_decompress(int argc,char ** argv,const struct cmd_desc * cmd)1148 static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
1149 {
1150 	int fd, ret;
1151 
1152 	if (argc != 2) {
1153 		fputs("Excess arguments\n\n", stderr);
1154 		fputs(cmd->cmd_help, stderr);
1155 		exit(1);
1156 	}
1157 
1158 	fd = xopen(argv[1], O_WRONLY, 0);
1159 
1160 	ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
1161 	if (ret < 0)
1162 		die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
1163 
1164 	exit(0);
1165 }
1166 
1167 #define compress_desc "compress a compression enabled file"
1168 #define compress_help "f2fs_io compress [file_path]\n\n"
1169 
do_compress(int argc,char ** argv,const struct cmd_desc * cmd)1170 static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
1171 {
1172 	int fd, ret;
1173 
1174 	if (argc != 2) {
1175 		fputs("Excess arguments\n\n", stderr);
1176 		fputs(cmd->cmd_help, stderr);
1177 		exit(1);
1178 	}
1179 
1180 	fd = xopen(argv[1], O_WRONLY, 0);
1181 
1182 	ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
1183 	if (ret < 0)
1184 		die_errno("F2FS_IOC_COMPRESS_FILE failed");
1185 
1186 	exit(0);
1187 }
1188 
1189 #define get_filename_encrypt_mode_desc "get file name encrypt mode"
1190 #define get_filename_encrypt_mode_help					\
1191 "f2fs_io filename_encrypt_mode [file or directory path]\n\n"		\
1192 "Get the file name encription mode of the given file/directory.\n"	\
1193 
do_get_filename_encrypt_mode(int argc,char ** argv,const struct cmd_desc * cmd)1194 static void do_get_filename_encrypt_mode (int argc, char **argv,
1195 						const struct cmd_desc *cmd)
1196 {
1197 	static const char *enc_name[] = {
1198 		"invalid", /* FSCRYPT_MODE_INVALID (0) */
1199 		"aes-256-xts", /* FSCRYPT_MODE_AES_256_XTS (1) */
1200 		"aes-256-gcm", /* FSCRYPT_MODE_AES_256_GCM (2) */
1201 		"aes-256-cbc", /* FSCRYPT_MODE_AES_256_CBC (3) */
1202 		"aes-256-cts", /* FSCRYPT_MODE_AES_256_CTS (4) */
1203 		"aes-128-cbc", /* FSCRYPT_MODE_AES_128_CBC (5) */
1204 		"aes-128-cts", /* FSCRYPT_MODE_AES_128_CTS (6) */
1205 		"speck128-256-xts", /* FSCRYPT_MODE_SPECK128_256_XTS (7) */
1206 		"speck128-256-cts", /* FSCRYPT_MODE_SPECK128_256_CTS (8) */
1207 		"adiantum", /* FSCRYPT_MODE_ADIANTUM (9) */
1208 		"aes-256-hctr2", /* FSCRYPT_MODE_AES_256_HCTR2 (10) */
1209 	};
1210 	int fd, mode, ret;
1211 	struct fscrypt_get_policy_ex_arg arg;
1212 
1213 	if (argc != 2) {
1214 		fputs("Excess arguments\n\n", stderr);
1215 		fputs(cmd->cmd_help, stderr);
1216 		exit(1);
1217 	}
1218 
1219 	fd = xopen(argv[1], O_RDONLY, 0);
1220 	arg.policy_size = sizeof(arg.policy);
1221 	ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
1222 	if (ret != 0 && errno == ENOTTY)
1223 		ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
1224 	close(fd);
1225 
1226 	if (ret) {
1227 		perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
1228 		exit(1);
1229 	}
1230 
1231 	switch (arg.policy.version) {
1232 	case FSCRYPT_POLICY_V1:
1233 		mode = arg.policy.v1.filenames_encryption_mode;
1234 		break;
1235 	case FSCRYPT_POLICY_V2:
1236 		mode = arg.policy.v2.filenames_encryption_mode;
1237 		break;
1238 	default:
1239 		printf("Do not support policy version: %d\n",
1240 							arg.policy.version);
1241 		exit(1);
1242 	}
1243 
1244 	if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
1245 		printf("Do not support algorithm: %d\n", mode);
1246 		exit(1);
1247 	}
1248 	printf ("%s\n", enc_name[mode]);
1249 	exit(0);
1250 }
1251 
1252 #define rename_desc "rename source to target file with fsync option"
1253 #define rename_help							\
1254 "f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n"	\
1255 "e.g., f2fs_io rename source dest 1\n"					\
1256 "      1. open(source)\n"						\
1257 "      2. rename(source, dest)\n"					\
1258 "      3. fsync(source)\n"						\
1259 "      4. close(source)\n"
1260 
do_rename(int argc,char ** argv,const struct cmd_desc * cmd)1261 static void do_rename(int argc, char **argv, const struct cmd_desc *cmd)
1262 {
1263 	int fd = -1;
1264 	int ret;
1265 
1266 	if (argc != 4) {
1267 		fputs("Excess arguments\n\n", stderr);
1268 		fputs(cmd->cmd_help, stderr);
1269 		exit(1);
1270 	}
1271 
1272 	if (atoi(argv[3]))
1273 		fd = xopen(argv[1], O_WRONLY, 0);
1274 
1275 	ret = rename(argv[1], argv[2]);
1276 	if (ret < 0)
1277 		die_errno("rename failed");
1278 
1279 	if (fd >= 0) {
1280 		if (fsync(fd) != 0)
1281 			die_errno("fsync failed: %s", argv[1]);
1282 		close(fd);
1283 	}
1284 	exit(0);
1285 }
1286 
1287 #define gc_desc "trigger filesystem GC"
1288 #define gc_help "f2fs_io gc sync_mode [file_path]\n\n"
1289 
do_gc(int argc,char ** argv,const struct cmd_desc * cmd)1290 static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
1291 {
1292 	u32 sync;
1293 	int ret, fd;
1294 
1295 	if (argc != 3) {
1296 		fputs("Excess arguments\n\n", stderr);
1297 		fputs(cmd->cmd_help, stderr);
1298 		exit(1);
1299 	}
1300 
1301 	sync = atoi(argv[1]);
1302 
1303 	fd = xopen(argv[2], O_RDONLY, 0);
1304 
1305 	ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, &sync);
1306 	if (ret < 0)
1307 		die_errno("F2FS_IOC_GARBAGE_COLLECT failed");
1308 
1309 	printf("trigger %s gc ret=%d\n",
1310 		sync ? "synchronous" : "asynchronous", ret);
1311 	exit(0);
1312 }
1313 
1314 #define CMD_HIDDEN 	0x0001
1315 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
1316 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
1317 
1318 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
1319 const struct cmd_desc cmd_list[] = {
1320 	_CMD(help),
1321 	CMD(fsync),
1322 	CMD(set_verity),
1323 	CMD(getflags),
1324 	CMD(setflags),
1325 	CMD(shutdown),
1326 	CMD(pinfile),
1327 	CMD(fallocate),
1328 	CMD(erase),
1329 	CMD(write),
1330 	CMD(read),
1331 	CMD(randread),
1332 	CMD(fiemap),
1333 	CMD(gc_urgent),
1334 	CMD(defrag_file),
1335 	CMD(copy),
1336 	CMD(get_cblocks),
1337 	CMD(release_cblocks),
1338 	CMD(reserve_cblocks),
1339 	CMD(get_coption),
1340 	CMD(set_coption),
1341 	CMD(decompress),
1342 	CMD(compress),
1343 	CMD(get_filename_encrypt_mode),
1344 	CMD(rename),
1345 	CMD(gc),
1346 	{ NULL, NULL, NULL, NULL, 0 }
1347 };
1348 
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))1349 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
1350 {
1351 	const struct cmd_desc *p;
1352 
1353 	if (argc > 1) {
1354 		for (p = cmd_list; p->cmd_name; p++) {
1355 			if (p->cmd_flags & CMD_HIDDEN)
1356 				continue;
1357 			if (strcmp(p->cmd_name, argv[1]) == 0) {
1358 				putc('\n', stdout);
1359 				fputs("USAGE:\n  ", stdout);
1360 				fputs(p->cmd_help, stdout);
1361 				exit(0);
1362 			}
1363 		}
1364 		printf("Unknown command: %s\n\n", argv[1]);
1365 	}
1366 
1367 	fputs("Available commands:\n", stdout);
1368 	for (p = cmd_list; p->cmd_name; p++) {
1369 		if (p->cmd_flags & CMD_HIDDEN)
1370 			continue;
1371 		printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
1372 	}
1373 	printf("\nTo get more information on a command, "
1374 	       "type 'f2fs_io help cmd'\n");
1375 	exit(0);
1376 }
1377 
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))1378 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
1379 				void *UNUSED(context))
1380 {
1381 	exit(-1);
1382 }
1383 
sigcatcher_setup(void)1384 static void sigcatcher_setup(void)
1385 {
1386 	struct sigaction	sa;
1387 
1388 	memset(&sa, 0, sizeof(struct sigaction));
1389 	sa.sa_sigaction = die_signal_handler;
1390 	sa.sa_flags = SA_SIGINFO;
1391 
1392 	sigaction(SIGHUP, &sa, 0);
1393 	sigaction(SIGINT, &sa, 0);
1394 	sigaction(SIGQUIT, &sa, 0);
1395 	sigaction(SIGFPE, &sa, 0);
1396 	sigaction(SIGILL, &sa, 0);
1397 	sigaction(SIGBUS, &sa, 0);
1398 	sigaction(SIGSEGV, &sa, 0);
1399 	sigaction(SIGABRT, &sa, 0);
1400 	sigaction(SIGPIPE, &sa, 0);
1401 	sigaction(SIGALRM, &sa, 0);
1402 	sigaction(SIGTERM, &sa, 0);
1403 	sigaction(SIGUSR1, &sa, 0);
1404 	sigaction(SIGUSR2, &sa, 0);
1405 	sigaction(SIGPOLL, &sa, 0);
1406 	sigaction(SIGPROF, &sa, 0);
1407 	sigaction(SIGSYS, &sa, 0);
1408 	sigaction(SIGTRAP, &sa, 0);
1409 	sigaction(SIGVTALRM, &sa, 0);
1410 	sigaction(SIGXCPU, &sa, 0);
1411 	sigaction(SIGXFSZ, &sa, 0);
1412 }
1413 
main(int argc,char ** argv)1414 int main(int argc, char **argv)
1415 {
1416 	const struct cmd_desc *cmd;
1417 
1418 	if (argc < 2)
1419 		do_help(argc, argv, cmd_list);
1420 
1421 	sigcatcher_setup();
1422 	for (cmd = cmd_list; cmd->cmd_name; cmd++) {
1423 		if (strcmp(cmd->cmd_name, argv[1]) == 0) {
1424 			cmd->cmd_func(argc - 1, argv + 1, cmd);
1425 			exit(0);
1426 		}
1427 	}
1428 	printf("Unknown command: %s\n\n", argv[1]);
1429 	do_help(1, argv, cmd_list);
1430 	return 0;
1431 }
1432