xref: /aosp_15_r20/external/f2fs-tools/tools/f2fs_io/f2fs_io.c (revision 59bfda1f02d633cd6b8b69f31eee485d40f6eef6)
1 /*
2  * f2fs_io.c - f2fs ioctl utility
3  *
4  * Author: Jaegeuk Kim <[email protected]>
5  *
6  * Copied portion of the code from ../f2fscrypt.c
7  */
8 
9 #ifndef _GNU_SOURCE
10 #define _GNU_SOURCE
11 #endif
12 #ifndef O_LARGEFILE
13 #define O_LARGEFILE 0
14 #endif
15 #ifndef __SANE_USERSPACE_TYPES__
16 #define __SANE_USERSPACE_TYPES__       /* For PPC64, to get LL64 types */
17 #endif
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <inttypes.h>
23 #include <limits.h>
24 #include <linux/fs.h>
25 #include <signal.h>
26 #include <stdarg.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/mman.h>
32 #include <sys/sendfile.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <termios.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <sys/xattr.h>
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 #include <android_config.h>
44 
45 #include "f2fs_io.h"
46 
47 struct cmd_desc {
48 	const char *cmd_name;
49 	void (*cmd_func)(int, char **, const struct cmd_desc *);
50 	const char *cmd_desc;
51 	const char *cmd_help;
52 	int cmd_flags;
53 };
54 
55 static void __attribute__((noreturn))
do_die(const char * format,va_list va,int err)56 do_die(const char *format, va_list va, int err)
57 {
58 	vfprintf(stderr, format, va);
59 	if (err)
60 		fprintf(stderr, ": %s", strerror(err));
61 	putc('\n', stderr);
62 	exit(1);
63 }
64 
65 static void __attribute__((noreturn, format(printf, 1, 2)))
die_errno(const char * format,...)66 die_errno(const char *format, ...)
67 {
68 	va_list va;
69 
70 	va_start(va, format);
71 	do_die(format, va, errno);
72 	va_end(va);
73 }
74 
75 static void __attribute__((noreturn, format(printf, 1, 2)))
die(const char * format,...)76 die(const char *format, ...)
77 {
78 	va_list va;
79 
80 	va_start(va, format);
81 	do_die(format, va, 0);
82 	va_end(va);
83 }
84 
xmalloc(size_t size)85 static void *xmalloc(size_t size)
86 {
87 	void *p = malloc(size);
88 
89 	if (!p)
90 		die("Memory alloc failed (requested %zu bytes)", size);
91 	return p;
92 }
93 
aligned_xalloc(size_t alignment,size_t size)94 static void *aligned_xalloc(size_t alignment, size_t size)
95 {
96 	void *p = aligned_alloc(alignment, size);
97 
98 	if (!p)
99 		die("Memory alloc failed (requested %zu bytes)", size);
100 	return p;
101 }
102 
xopen(const char * pathname,int flags,mode_t mode)103 static int xopen(const char *pathname, int flags, mode_t mode)
104 {
105 	int fd = open(pathname, flags, mode);
106 
107 	if (fd < 0)
108 		die_errno("Failed to open %s", pathname);
109 	return fd;
110 }
111 
xread(int fd,void * buf,size_t count)112 static ssize_t xread(int fd, void *buf, size_t count)
113 {
114 	ssize_t ret = read(fd, buf, count);
115 
116 	if (ret < 0)
117 		die_errno("read failed");
118 	return ret;
119 }
120 
full_write(int fd,const void * buf,size_t count)121 static void full_write(int fd, const void *buf, size_t count)
122 {
123 	while (count) {
124 		ssize_t ret = write(fd, buf, count);
125 
126 		if (ret < 0)
127 			die_errno("write failed");
128 		buf = (char *)buf + ret;
129 		count -= ret;
130 	}
131 }
132 
133 #ifdef HAVE_MACH_TIME_H
get_current_us()134 static u64 get_current_us()
135 {
136 	return mach_absolute_time() / 1000;
137 }
138 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME)
get_current_us()139 static u64 get_current_us()
140 {
141 	struct timespec t;
142 	t.tv_sec = t.tv_nsec = 0;
143 	clock_gettime(CLOCK_BOOTTIME, &t);
144 	return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
145 }
146 #else
get_current_us()147 static u64 get_current_us()
148 {
149 	return 0;
150 }
151 #endif
152 
153 #define fsync_desc "fsync"
154 #define fsync_help						\
155 "f2fs_io fsync [file]\n\n"					\
156 "fsync given the file\n"					\
157 
do_fsync(int argc,char ** argv,const struct cmd_desc * cmd)158 static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
159 {
160 	int fd;
161 
162 	if (argc != 2) {
163 		fputs("Excess arguments\n\n", stderr);
164 		fputs(cmd->cmd_help, stderr);
165 		exit(1);
166 	}
167 
168 	fd = xopen(argv[1], O_WRONLY, 0);
169 
170 	if (fsync(fd) != 0)
171 		die_errno("fsync failed");
172 
173 	printf("fsync a file\n");
174 	exit(0);
175 }
176 
177 #define fdatasync_desc "fdatasync"
178 #define fdatasync_help						\
179 "f2fs_io fdatasync [file]\n\n"					\
180 "fdatasync given the file\n"					\
181 
do_fdatasync(int argc,char ** argv,const struct cmd_desc * cmd)182 static void do_fdatasync(int argc, char **argv, const struct cmd_desc *cmd)
183 {
184 	int fd;
185 
186 	if (argc != 2) {
187 		fputs("Excess arguments\n\n", stderr);
188 		fputs(cmd->cmd_help, stderr);
189 		exit(1);
190 	}
191 
192 	fd = xopen(argv[1], O_WRONLY, 0);
193 
194 	if (fdatasync(fd) != 0)
195 		die_errno("fdatasync failed");
196 
197 	printf("fdatasync a file\n");
198 	exit(0);
199 }
200 
201 #define set_verity_desc "Set fs-verity"
202 #define set_verity_help					\
203 "f2fs_io set_verity [file]\n\n"				\
204 "Set fsverity bit given a file\n"			\
205 
do_set_verity(int argc,char ** argv,const struct cmd_desc * cmd)206 static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
207 {
208 	int ret, fd;
209 	struct fsverity_enable_arg args = {.version = 1};
210 
211 	args.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
212 	args.block_size = F2FS_DEFAULT_BLKSIZE;
213 
214 	if (argc != 2) {
215 		fputs("Excess arguments\n\n", stderr);
216 		fputs(cmd->cmd_help, stderr);
217 		exit(1);
218 	}
219 	fd = open(argv[1], O_RDONLY);
220 
221 	ret = ioctl(fd, FS_IOC_ENABLE_VERITY, &args);
222 	if (ret < 0) {
223 		perror("FS_IOC_ENABLE_VERITY");
224 		exit(1);
225 	}
226 
227 	printf("Set fsverity bit to %s\n", argv[1]);
228 	exit(0);
229 }
230 
231 #define getflags_desc "getflags ioctl"
232 #define getflags_help						\
233 "f2fs_io getflags [file]\n\n"					\
234 "get a flag given the file\n"					\
235 "flag can show \n"						\
236 "  encryption\n"						\
237 "  nocow(pinned)\n"						\
238 "  inline_data\n"						\
239 "  verity\n"							\
240 "  casefold\n"							\
241 "  compression\n"						\
242 "  nocompression\n"						\
243 "  immutable\n"
244 
do_getflags(int argc,char ** argv,const struct cmd_desc * cmd)245 static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
246 {
247 	long flag = 0;
248 	int ret, fd;
249 	int exist = 0;
250 
251 	if (argc != 2) {
252 		fputs("Excess arguments\n\n", stderr);
253 		fputs(cmd->cmd_help, stderr);
254 		exit(1);
255 	}
256 
257 	fd = xopen(argv[1], O_RDONLY, 0);
258 
259 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
260 	printf("get a flag on %s ret=%d, flags=", argv[1], ret);
261 	if (flag & FS_CASEFOLD_FL) {
262 		printf("casefold");
263 		exist = 1;
264 	}
265 	if (flag & FS_COMPR_FL) {
266 		if (exist)
267 			printf(",");
268 		printf("compression");
269 		exist = 1;
270 	}
271 	if (flag & FS_NOCOMP_FL) {
272 		if (exist)
273 			printf(",");
274 		printf("nocompression");
275 		exist = 1;
276 	}
277 	if (flag & FS_ENCRYPT_FL) {
278 		if (exist)
279 			printf(",");
280 		printf("encrypt");
281 		exist = 1;
282 	}
283 	if (flag & FS_VERITY_FL) {
284 		if (exist)
285 			printf(",");
286 		printf("verity");
287 		exist = 1;
288 	}
289 	if (flag & FS_INLINE_DATA_FL) {
290 		if (exist)
291 			printf(",");
292 		printf("inline_data");
293 		exist = 1;
294 	}
295 	if (flag & FS_NOCOW_FL) {
296 		if (exist)
297 			printf(",");
298 		printf("nocow(pinned)");
299 		exist = 1;
300 	}
301 	if (flag & FS_IMMUTABLE_FL) {
302 		if (exist)
303 			printf(",");
304 		printf("immutable");
305 		exist = 1;
306 	}
307 	if (!exist)
308 		printf("none");
309 	printf("\n");
310 	exit(0);
311 }
312 
313 #define setflags_desc "setflags ioctl"
314 #define setflags_help						\
315 "f2fs_io setflags [flag] [file]\n\n"				\
316 "set a flag given the file\n"					\
317 "flag can be\n"							\
318 "  casefold\n"							\
319 "  compression\n"						\
320 "  nocompression\n"						\
321 "  immutable\n"							\
322 "  nocow\n"
323 
do_setflags(int argc,char ** argv,const struct cmd_desc * cmd)324 static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
325 {
326 	long flag = 0;
327 	int ret, fd;
328 
329 	if (argc != 3) {
330 		fputs("Excess arguments\n\n", stderr);
331 		fputs(cmd->cmd_help, stderr);
332 		exit(1);
333 	}
334 
335 	fd = xopen(argv[2], O_RDONLY, 0);
336 
337 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
338 	printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
339 	if (ret)
340 		die_errno("F2FS_IOC_GETFLAGS failed");
341 
342 	if (!strcmp(argv[1], "casefold"))
343 		flag |= FS_CASEFOLD_FL;
344 	else if (!strcmp(argv[1], "compression"))
345 		flag |= FS_COMPR_FL;
346 	else if (!strcmp(argv[1], "nocompression"))
347 		flag |= FS_NOCOMP_FL;
348 	else if (!strcmp(argv[1], "immutable"))
349 		flag |= FS_IMMUTABLE_FL;
350 	else if (!strcmp(argv[1], "nocow"))
351 		flag |= FS_NOCOW_FL;
352 
353 	ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
354 	printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
355 	exit(0);
356 }
357 
358 #define clearflags_desc "clearflags ioctl"
359 #define clearflags_help						\
360 "f2fs_io clearflags [flag] [file]\n\n"				\
361 "clear a flag given the file\n"					\
362 "flag can be\n"							\
363 "  compression\n"						\
364 "  nocompression\n"						\
365 "  immutable\n"							\
366 "  nocow\n"
367 
do_clearflags(int argc,char ** argv,const struct cmd_desc * cmd)368 static void do_clearflags(int argc, char **argv, const struct cmd_desc *cmd)
369 {
370 	long flag = 0;
371 	int ret, fd;
372 
373 	if (argc != 3) {
374 		fputs("Excess arguments\n\n", stderr);
375 		fputs(cmd->cmd_help, stderr);
376 		exit(1);
377 	}
378 
379 	fd = xopen(argv[2], O_RDONLY, 0);
380 
381 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
382 	printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
383 	if (ret)
384 		die_errno("F2FS_IOC_GETFLAGS failed");
385 
386 	if (!strcmp(argv[1], "compression"))
387 		flag &= ~FS_COMPR_FL;
388 	else if (!strcmp(argv[1], "nocompression"))
389 		flag &= ~FS_NOCOMP_FL;
390 	else if (!strcmp(argv[1], "immutable"))
391 		flag &= ~FS_IMMUTABLE_FL;
392 	else if (!strcmp(argv[1], "nocow"))
393 		flag &= ~FS_NOCOW_FL;
394 
395 	ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
396 	printf("clear a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
397 	exit(0);
398 }
399 
400 #define shutdown_desc "shutdown filesystem"
401 #define shutdown_help					\
402 "f2fs_io shutdown [level] [dir]\n\n"			\
403 "Freeze and stop all IOs given mount point\n"		\
404 "level can be\n"					\
405 "  0 : going down with full sync\n"			\
406 "  1 : going down with checkpoint only\n"		\
407 "  2 : going down with no sync\n"			\
408 "  3 : going down with metadata flush\n"		\
409 "  4 : going down with fsck mark\n"
410 
do_shutdown(int argc,char ** argv,const struct cmd_desc * cmd)411 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
412 {
413 	u32 flag;
414 	int ret, fd;
415 
416 	if (argc != 3) {
417 		fputs("Excess arguments\n\n", stderr);
418 		fputs(cmd->cmd_help, stderr);
419 		exit(1);
420 	}
421 
422 	flag = atoi(argv[1]);
423 	if (flag >= F2FS_GOING_DOWN_MAX) {
424 		fputs("Wrong level\n\n", stderr);
425 		fputs(cmd->cmd_help, stderr);
426 		exit(1);
427 	}
428 	fd = xopen(argv[2], O_RDONLY, 0);
429 
430 	ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
431 	if (ret < 0)
432 		die_errno("F2FS_IOC_SHUTDOWN failed");
433 
434 	printf("Shutdown %s with level=%d\n", argv[2], flag);
435 	exit(0);
436 }
437 
438 #define fadvise_desc "fadvise"
439 #define fadvise_help						\
440 "f2fs_io fadvise [advice] [offset] [length] [file]\n\n"		\
441 "fadvice given the file\n"					\
442 "advice can be\n"						\
443 " willneed\n"							\
444 " sequential\n"							\
445 
do_fadvise(int argc,char ** argv,const struct cmd_desc * cmd)446 static void do_fadvise(int argc, char **argv, const struct cmd_desc *cmd)
447 {
448 	int fd, advice;
449 	off_t offset, length;
450 
451 	if (argc != 5) {
452 		fputs("Excess arguments\n\n", stderr);
453 		fputs(cmd->cmd_help, stderr);
454 		exit(1);
455 	}
456 
457 	fd = xopen(argv[4], O_RDWR, 0);
458 
459 	if (!strcmp(argv[1], "willneed")) {
460 		advice = POSIX_FADV_WILLNEED;
461 	} else if (!strcmp(argv[1], "sequential")) {
462 		advice = POSIX_FADV_SEQUENTIAL;
463 	} else {
464 		fputs("Wrong advice\n\n", stderr);
465 		fputs(cmd->cmd_help, stderr);
466 		exit(1);
467 	}
468 
469 	offset = atoi(argv[2]);
470 	length = atoll(argv[3]);
471 
472 	if (posix_fadvise(fd, offset, length, advice) != 0)
473 		die_errno("fadvise failed");
474 
475 	printf("fadvice %s to a file: %s\n", argv[1], argv[4]);
476 	exit(0);
477 }
478 
479 #define pinfile_desc "pin file control"
480 #define pinfile_help						\
481 "f2fs_io pinfile [get|set|unset] [file]\n\n"			\
482 "get/set pinning given the file\n"				\
483 
do_pinfile(int argc,char ** argv,const struct cmd_desc * cmd)484 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
485 {
486 	u32 pin;
487 	int ret, fd;
488 
489 	if (argc != 3) {
490 		fputs("Excess arguments\n\n", stderr);
491 		fputs(cmd->cmd_help, stderr);
492 		exit(1);
493 	}
494 
495 	fd = xopen(argv[2], O_RDONLY, 0);
496 
497 	ret = -1;
498 	if (!strcmp(argv[1], "set")) {
499 		pin = 1;
500 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
501 		if (ret != 0)
502 			die_errno("F2FS_IOC_SET_PIN_FILE failed");
503 		printf("%s pinfile: %u blocks moved in %s\n",
504 					argv[1], ret, argv[2]);
505 	} else if (!strcmp(argv[1], "unset")) {
506 		pin = 0;
507 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
508 		if (ret != 0)
509 			die_errno("F2FS_IOC_SET_PIN_FILE failed");
510 		printf("%s pinfile in %s\n", argv[1], argv[2]);
511 	} else if (!strcmp(argv[1], "get")) {
512 		unsigned int flags;
513 
514 		ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
515 		if (ret < 0)
516 			die_errno("F2FS_IOC_GET_PIN_FILE failed");
517 
518 		ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
519 		if (ret < 0)
520 			die_errno("F2FS_IOC_GETFLAGS failed");
521 
522 		printf("get_pin_file: %s with %u blocks moved in %s\n",
523 				(flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
524 				pin, argv[2]);
525 	}
526 	exit(0);
527 }
528 
529 #define fallocate_desc "fallocate"
530 #define fallocate_help						\
531 "f2fs_io fallocate [-c] [-i] [-p] [-z] [keep_size] [offset] [length] [file]\n\n"	\
532 "fallocate given the file\n"					\
533 " [keep_size] : 1 or 0\n"					\
534 " -c : collapse range\n"					\
535 " -i : insert range\n"						\
536 " -p : punch hole\n"						\
537 " -z : zero range\n"						\
538 
do_fallocate(int argc,char ** argv,const struct cmd_desc * cmd)539 static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
540 {
541 	int fd;
542 	off_t offset, length;
543 	struct stat sb;
544 	int mode = 0;
545 	int c;
546 
547 	while ((c = getopt(argc, argv, "cipz")) != -1) {
548 		switch (c) {
549 		case 'c':
550 			mode |= FALLOC_FL_COLLAPSE_RANGE;
551 			break;
552 		case 'i':
553 			mode |= FALLOC_FL_INSERT_RANGE;
554 			break;
555 		case 'p':
556 			mode |= FALLOC_FL_PUNCH_HOLE;
557 			break;
558 		case 'z':
559 			mode |= FALLOC_FL_ZERO_RANGE;
560 			break;
561 		default:
562 			fputs(cmd->cmd_help, stderr);
563 			exit(2);
564 		}
565 	}
566 	argc -= optind;
567 	argv += optind;
568 
569 	if (argc != 4) {
570 		fputs("Excess arguments\n\n", stderr);
571 		fputs(cmd->cmd_help, stderr);
572 		exit(1);
573 	}
574 
575 	if (!strcmp(argv[0], "1"))
576 		mode |= FALLOC_FL_KEEP_SIZE;
577 
578 	offset = atoll(argv[1]);
579 	length = atoll(argv[2]);
580 
581 	fd = xopen(argv[3], O_RDWR, 0);
582 
583 	if (fallocate(fd, mode, offset, length) != 0)
584 		die_errno("fallocate failed");
585 
586 	if (fstat(fd, &sb) != 0)
587 		die_errno("fstat failed");
588 
589 	printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
590 	exit(0);
591 }
592 
593 #define erase_desc "erase a block device"
594 #define erase_help				\
595 "f2fs_io erase [block_device_path]\n\n"		\
596 "Send DISCARD | BLKSECDISCARD comamnd to"	\
597 "block device in block_device_path\n"		\
598 
do_erase(int argc,char ** argv,const struct cmd_desc * cmd)599 static void do_erase(int argc, char **argv, const struct cmd_desc *cmd)
600 {
601 	int fd, ret;
602 	struct stat st;
603 	u64 range[2];
604 
605 	if (argc != 2) {
606 		fputs("Excess arguments\n\n", stderr);
607 		fputs(cmd->cmd_help, stderr);
608 		exit(1);
609 	}
610 
611 	if (stat(argv[1], &st) != 0) {
612 		fputs("stat error\n", stderr);
613 		exit(1);
614 	}
615 
616 	if (!S_ISBLK(st.st_mode)) {
617 		fputs(argv[1], stderr);
618 		fputs(" is not a block device\n", stderr);
619 		exit(1);
620 	}
621 
622 	fd = xopen(argv[1], O_WRONLY, 0);
623 
624 	range[0] = 0;
625 	ret = ioctl(fd, BLKGETSIZE64, &range[1]);
626 	if (ret < 0) {
627 		fputs("get size failed\n", stderr);
628 		exit(1);
629 	}
630 
631 	ret = ioctl(fd, BLKSECDISCARD, &range);
632 	if (ret < 0) {
633 		ret = ioctl(fd, BLKDISCARD, &range);
634 		if (ret < 0) {
635 			fputs("Discard failed\n", stderr);
636 			exit(1);
637 		}
638 	}
639 
640 	exit(0);
641 }
642 
do_write_with_advice(int argc,char ** argv,const struct cmd_desc * cmd,bool with_advice)643 static void do_write_with_advice(int argc, char **argv,
644 			const struct cmd_desc *cmd, bool with_advice)
645 {
646 	u64 buf_size = 0, inc_num = 0, written = 0;
647 	u64 offset;
648 	char *buf = NULL;
649 	unsigned bs, count, i;
650 	int flags = 0;
651 	int fd;
652 	u64 total_time = 0, max_time = 0, max_time_t = 0;
653 	bool atomic_commit = false, atomic_abort = false, replace = false;
654 	int useconds = 0;
655 
656 	srand(time(0));
657 
658 	bs = atoi(argv[1]);
659 	if (bs > 1024)
660 		die("Too big chunk size - limit: 4MB");
661 
662 	buf_size = bs * F2FS_DEFAULT_BLKSIZE;
663 
664 	offset = atoi(argv[2]) * buf_size;
665 
666 	buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, buf_size);
667 	count = atoi(argv[3]);
668 
669 	if (!strcmp(argv[4], "zero"))
670 		memset(buf, 0, buf_size);
671 	else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
672 		die("Wrong pattern type");
673 
674 	if (!strcmp(argv[5], "dio")) {
675 		flags |= O_DIRECT;
676 	} else if (!strcmp(argv[5], "dsync")) {
677 		flags |= O_DIRECT | O_DSYNC;
678 	} else if (!strcmp(argv[5], "osync")) {
679 		flags |= O_SYNC;
680 	} else if (!strcmp(argv[5], "atomic_commit")) {
681 		atomic_commit = true;
682 	} else if (!strcmp(argv[5], "atomic_abort")) {
683 		atomic_abort = true;
684 	} else if (!strcmp(argv[5], "atomic_rcommit")) {
685 		atomic_commit = true;
686 		replace = true;
687 	} else if (!strcmp(argv[5], "atomic_rabort")) {
688 		atomic_abort = true;
689 		replace = true;
690 	} else if (strcmp(argv[5], "buffered")) {
691 		die("Wrong IO type");
692 	}
693 
694 	if (!with_advice) {
695 		fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
696 	} else {
697 		unsigned char advice;
698 		int ret;
699 
700 		if (!strcmp(argv[6], "hot"))
701 			advice = FADVISE_HOT_BIT;
702 		else if (!strcmp(argv[6], "cold"))
703 			advice = FADVISE_COLD_BIT;
704 		else
705 			die("Wrong Advise type");
706 
707 		fd = xopen(argv[7], O_CREAT | O_WRONLY | flags, 0755);
708 
709 		ret = fsetxattr(fd, F2FS_SYSTEM_ADVISE_NAME,
710 				    (char *)&advice, 1, XATTR_CREATE);
711 		if (ret) {
712 			fputs("fsetxattr advice failed\n", stderr);
713 			exit(1);
714 		}
715 	}
716 
717 	if (atomic_commit || atomic_abort) {
718 		int ret;
719 
720 		if (argc == 8)
721 			useconds = atoi(argv[7]) * 1000;
722 
723 		if (replace)
724 			ret = ioctl(fd, F2FS_IOC_START_ATOMIC_REPLACE);
725 		else
726 			ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
727 
728 		if (ret < 0) {
729 			fputs("setting atomic file mode failed\n", stderr);
730 			exit(1);
731 		}
732 	}
733 
734 	total_time = get_current_us();
735 	for (i = 0; i < count; i++) {
736 		uint64_t ret;
737 
738 		if (!strcmp(argv[4], "inc_num"))
739 			*(int *)buf = inc_num++;
740 		else if (!strcmp(argv[4], "rand"))
741 			*(int *)buf = rand();
742 
743 		/* write data */
744 		max_time_t = get_current_us();
745 		ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
746 		max_time_t = get_current_us() - max_time_t;
747 		if (max_time < max_time_t)
748 			max_time = max_time_t;
749 		if (ret != buf_size)
750 			break;
751 		written += ret;
752 	}
753 
754 	if (useconds)
755 		usleep(useconds);
756 
757 	if (atomic_commit) {
758 		int ret;
759 
760 		ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
761 		if (ret < 0) {
762 			fputs("committing atomic write failed\n", stderr);
763 			exit(1);
764 		}
765 	} else if (atomic_abort) {
766 		int ret;
767 
768 		ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
769 		if (ret < 0) {
770 			fputs("aborting atomic write failed\n", stderr);
771 			exit(1);
772 		}
773 	}
774 
775 	printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
776 				written, argv[4],
777 				get_current_us() - total_time,
778 				max_time);
779 	exit(0);
780 }
781 
782 #define write_desc "write data into file"
783 #define write_help					\
784 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path] {delay}\n\n"	\
785 "Write given patten data in file_path\n"		\
786 "pattern can be\n"					\
787 "  zero          : zeros\n"				\
788 "  inc_num       : incrementing numbers\n"		\
789 "  rand          : random numbers\n"			\
790 "IO can be\n"						\
791 "  buffered      : buffered IO\n"			\
792 "  dio           : O_DIRECT\n"				\
793 "  dsync         : O_DIRECT | O_DSYNC\n"		\
794 "  osync         : O_SYNC\n"				\
795 "  atomic_commit : atomic write & commit\n"		\
796 "  atomic_abort  : atomic write & abort\n"		\
797 "  atomic_rcommit: atomic replace & commit\n"		\
798 "  atomic_rabort : atomic replace & abort\n"		\
799 "{delay} is in ms unit and optional only for atomic operations\n"
800 
do_write(int argc,char ** argv,const struct cmd_desc * cmd)801 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
802 {
803 	if (argc < 7 || argc > 8) {
804 		fputs("Excess arguments\n\n", stderr);
805 		fputs(cmd->cmd_help, stderr);
806 		exit(1);
807 	}
808 	do_write_with_advice(argc, argv, cmd, false);
809 }
810 
811 #define write_advice_desc "write data into file with a hint"
812 #define write_advice_help					\
813 "f2fs_io write_advice [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [advise] [file_path] {delay}\n\n"	\
814 "Write given patten data in file_path\n"		\
815 "pattern can be\n"					\
816 "  zero          : zeros\n"				\
817 "  inc_num       : incrementing numbers\n"		\
818 "  rand          : random numbers\n"			\
819 "IO can be\n"						\
820 "  buffered      : buffered IO\n"			\
821 "  dio           : O_DIRECT\n"				\
822 "  dsync         : O_DIRECT | O_DSYNC\n"		\
823 "  osync         : O_SYNC\n"				\
824 "  atomic_commit : atomic write & commit\n"		\
825 "  atomic_abort  : atomic write & abort\n"		\
826 "  atomic_rcommit: atomic replace & commit\n"		\
827 "  atomic_rabort : atomic replace & abort\n"		\
828 "advise can be\n"					\
829 "  cold : indicate a cold file\n"			\
830 "  hot  : indicate a hot file\n"			\
831 "{delay} is in ms unit and optional only for atomic operations\n"
832 
do_write_advice(int argc,char ** argv,const struct cmd_desc * cmd)833 static void do_write_advice(int argc, char **argv, const struct cmd_desc *cmd)
834 {
835 	if (argc < 8 || argc > 9) {
836 		fputs("Excess arguments\n\n", stderr);
837 		fputs(cmd->cmd_help, stderr);
838 		exit(1);
839 	}
840 	do_write_with_advice(argc, argv, cmd, true);
841 }
842 
843 #define read_desc "read data from file"
844 #define read_help					\
845 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [advice] [print_nbytes] [file_path]\n\n"	\
846 "Read data in file_path and print nbytes\n"		\
847 "IO can be\n"						\
848 "  buffered : buffered IO\n"				\
849 "  dio      : direct IO\n"				\
850 "  mmap     : mmap IO\n"				\
851 "advice can be\n"					\
852 " 1 : set sequential|willneed\n"			\
853 " 0 : none\n"						\
854 
do_read(int argc,char ** argv,const struct cmd_desc * cmd)855 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
856 {
857 	u64 buf_size = 0, ret = 0, read_cnt = 0;
858 	u64 offset;
859 	char *buf = NULL;
860 	char *data;
861 	char *print_buf = NULL;
862 	unsigned bs, count, i, print_bytes;
863 	u64 total_time = 0;
864 	int flags = 0;
865 	int do_mmap = 0;
866 	int fd, advice;
867 
868 	if (argc != 8) {
869 		fputs("Excess arguments\n\n", stderr);
870 		fputs(cmd->cmd_help, stderr);
871 		exit(1);
872 	}
873 
874 	bs = atoi(argv[1]);
875 	if (bs > 256 * 1024)
876 		die("Too big chunk size - limit: 1GB");
877 	buf_size = bs * F2FS_DEFAULT_BLKSIZE;
878 
879 	offset = atoi(argv[2]) * buf_size;
880 
881 	buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, buf_size);
882 
883 	count = atoi(argv[3]);
884 	if (!strcmp(argv[4], "dio"))
885 		flags |= O_DIRECT;
886 	else if (!strcmp(argv[4], "mmap"))
887 		do_mmap = 1;
888 	else if (strcmp(argv[4], "buffered"))
889 		die("Wrong IO type");
890 
891 	print_bytes = atoi(argv[6]);
892 	if (print_bytes > buf_size)
893 		die("Print_nbytes should be less then chunk_size in kb");
894 
895 	print_buf = xmalloc(print_bytes);
896 
897 	fd = xopen(argv[7], O_RDONLY | flags, 0);
898 
899 	advice = atoi(argv[5]);
900 	if (advice) {
901 		if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE,
902 				POSIX_FADV_SEQUENTIAL) != 0)
903 			die_errno("fadvise failed");
904 		if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE,
905 				POSIX_FADV_WILLNEED) != 0)
906 			die_errno("fadvise failed");
907 		printf("fadvise SEQUENTIAL|WILLNEED to a file: %s\n", argv[7]);
908 	}
909 
910 	total_time = get_current_us();
911 	if (do_mmap) {
912 		data = mmap(NULL, count * buf_size, PROT_READ,
913 						MAP_SHARED | MAP_POPULATE, fd, offset);
914 		if (data == MAP_FAILED)
915 			die("Mmap failed");
916 	}
917 	if (!do_mmap) {
918 		for (i = 0; i < count; i++) {
919 			ret = pread(fd, buf, buf_size, offset + buf_size * i);
920 			if (ret != buf_size) {
921 				printf("pread expected: %"PRIu64", readed: %"PRIu64"\n",
922 						buf_size, ret);
923 				if (ret > 0) {
924 					read_cnt += ret;
925 					memcpy(print_buf, buf, print_bytes);
926 				}
927 				break;
928 			}
929 
930 			read_cnt += ret;
931 			if (i == 0)
932 				memcpy(print_buf, buf, print_bytes);
933 		}
934 	} else {
935 		read_cnt = count * buf_size;
936 		memcpy(print_buf, data, print_bytes);
937 	}
938 	printf("Read %"PRIu64" bytes total_time = %"PRIu64" us, BW = %.Lf MB/s print %u bytes:\n",
939 		read_cnt, get_current_us() - total_time,
940 		((long double)read_cnt / (get_current_us() - total_time)), print_bytes);
941 	printf("%08"PRIx64" : ", offset);
942 	for (i = 1; i <= print_bytes; i++) {
943 		printf("%02x", print_buf[i - 1]);
944 		if (i % 16 == 0)
945 			printf("\n%08"PRIx64" : ", offset + 16 * i);
946 		else if (i % 2 == 0)
947 			printf(" ");
948 	}
949 	printf("\n");
950 	exit(0);
951 }
952 
953 #define randread_desc "random read data from file"
954 #define randread_help					\
955 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [advise] [file_path]\n\n"	\
956 "Do random read data in file_path\n"		\
957 "IO can be\n"						\
958 "  buffered : buffered IO\n"				\
959 "  dio      : direct IO\n"				\
960 "  mmap     : mmap IO\n"				\
961 "advice can be\n"					\
962 " 1 : set random|willneed\n"				\
963 " 0 : none\n"						\
964 
do_randread(int argc,char ** argv,const struct cmd_desc * cmd)965 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
966 {
967 	u64 buf_size = 0, ret = 0, read_cnt = 0;
968 	u64 idx, end_idx, aligned_size;
969 	char *buf = NULL;
970 	char *data;
971 	unsigned bs, count, i, j;
972 	u64 total_time = 0, elapsed_time = 0;
973 	int flags = 0;
974 	int do_mmap = 0;
975 	int fd, advice;
976 	time_t t;
977 	struct stat stbuf;
978 
979 	if (argc != 6) {
980 		fputs("Excess arguments\n\n", stderr);
981 		fputs(cmd->cmd_help, stderr);
982 		exit(1);
983 	}
984 
985 	bs = atoi(argv[1]);
986 	if (bs > 1024)
987 		die("Too big chunk size - limit: 4MB");
988 	buf_size = bs * F2FS_DEFAULT_BLKSIZE;
989 
990 	buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, buf_size);
991 
992 	count = atoi(argv[2]);
993 	if (!strcmp(argv[3], "dio"))
994 		flags |= O_DIRECT;
995 	else if (!strcmp(argv[3], "mmap"))
996 		do_mmap = 1;
997 	else if (strcmp(argv[3], "buffered"))
998 		die("Wrong IO type");
999 
1000 	fd = xopen(argv[5], O_RDONLY | flags, 0);
1001 
1002 	advice = atoi(argv[4]);
1003 	if (advice) {
1004 		if (posix_fadvise(fd, 0, stbuf.st_size, POSIX_FADV_RANDOM) != 0)
1005 			die_errno("fadvise failed");
1006 		if (posix_fadvise(fd, 0, 4096, POSIX_FADV_WILLNEED) != 0)
1007 			die_errno("fadvise failed");
1008 		printf("fadvise RANDOM|WILLNEED to a file: %s\n", argv[5]);
1009 	}
1010 
1011 	if (fstat(fd, &stbuf) != 0)
1012 		die_errno("fstat of source file failed");
1013 
1014 	aligned_size = (u64)stbuf.st_size & ~((u64)(F2FS_DEFAULT_BLKSIZE - 1));
1015 	if (aligned_size < buf_size)
1016 		die("File is too small to random read");
1017 	end_idx = (u64)(aligned_size - buf_size) / (u64)F2FS_DEFAULT_BLKSIZE + 1;
1018 
1019 	if (do_mmap) {
1020 		data = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
1021 		if (data == MAP_FAILED)
1022 			die("Mmap failed");
1023 		if (madvise((void *)data, stbuf.st_size, MADV_RANDOM) != 0)
1024 			die_errno("madvise failed");
1025 	}
1026 
1027 	srand((unsigned) time(&t));
1028 
1029 	total_time = get_current_us();
1030 
1031 	for (i = 0; i < count; i++) {
1032 		idx = rand() % end_idx;
1033 
1034 		if (!do_mmap) {
1035 			ret = pread(fd, buf, buf_size, 4096 * idx);
1036 			if (ret != buf_size)
1037 				break;
1038 		} else {
1039 			for (j = 0; j < bs; j++)
1040 				*buf = data[4096 * (idx + j)];
1041 		}
1042 		read_cnt += buf_size;
1043 	}
1044 	elapsed_time = get_current_us() - total_time;
1045 
1046 	printf("Read %"PRIu64" bytes total_time = %"PRIu64" us, avg. latency = %.Lf us, IOPs= %.Lf, BW = %.Lf MB/s\n",
1047 		read_cnt, elapsed_time,
1048 		(long double)elapsed_time / count,
1049 		(long double)count * 1000 * 1000 / elapsed_time,
1050 		(long double)read_cnt / elapsed_time);
1051 	exit(0);
1052 }
1053 
1054 #define fiemap_desc "get block address in file"
1055 #define fiemap_help					\
1056 "f2fs_io fiemap [offset in 4kb] [count in 4kb] [file_path]\n\n"\
1057 
1058 #if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)1059 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
1060 {
1061 	unsigned int i;
1062 	int fd, extents_mem_size;
1063 	u64 start, length;
1064 	u32 mapped_extents;
1065 	struct fiemap *fm = xmalloc(sizeof(struct fiemap));
1066 
1067 	if (argc != 4) {
1068 		fputs("Excess arguments\n\n", stderr);
1069 		fputs(cmd->cmd_help, stderr);
1070 		exit(1);
1071 	}
1072 
1073 	memset(fm, 0, sizeof(struct fiemap));
1074 	start = (u64)atoi(argv[1]) * F2FS_DEFAULT_BLKSIZE;
1075 	length = (u64)atoi(argv[2]) * F2FS_DEFAULT_BLKSIZE;
1076 	fm->fm_start = start;
1077 	fm->fm_length = length;
1078 
1079 	fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
1080 
1081 	printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n",
1082 				start / F2FS_DEFAULT_BLKSIZE,
1083 				length / F2FS_DEFAULT_BLKSIZE);
1084 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
1085 		die_errno("FIEMAP failed");
1086 
1087 	mapped_extents = fm->fm_mapped_extents;
1088 	extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents;
1089 	free(fm);
1090 	fm = xmalloc(sizeof(struct fiemap) + extents_mem_size);
1091 
1092 	memset(fm, 0, sizeof(struct fiemap) + extents_mem_size);
1093 	fm->fm_start = start;
1094 	fm->fm_length = length;
1095 	fm->fm_extent_count = mapped_extents;
1096 
1097 	if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
1098 		die_errno("FIEMAP failed");
1099 
1100 	printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags");
1101 	for (i = 0; i < fm->fm_mapped_extents; i++) {
1102 		printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i,
1103 		    fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical,
1104 		    fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags);
1105 
1106 		if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST)
1107 			break;
1108 	}
1109 	printf("\n");
1110 	free(fm);
1111 	exit(0);
1112 }
1113 #else
do_fiemap(int UNUSED (argc),char ** UNUSED (argv),const struct cmd_desc * UNUSED (cmd))1114 static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
1115 			const struct cmd_desc *UNUSED(cmd))
1116 {
1117 	die("Not support for this platform");
1118 }
1119 #endif
1120 
1121 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
1122 #define gc_urgent_help					\
1123 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
1124 " - f2fs_io gc_urgent sda21 start\n"		\
1125 " - f2fs_io gc_urgent sda21 end\n"		\
1126 " - f2fs_io gc_urgent sda21 run 10\n"		\
1127 
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)1128 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
1129 {
1130 	char command[255];
1131 
1132 	if (argc == 3 && !strcmp(argv[2], "start")) {
1133 		printf("gc_urgent: start on %s\n", argv[1]);
1134 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
1135 		if (system(command))
1136 			exit(1);
1137 	} else if (argc == 3 && !strcmp(argv[2], "end")) {
1138 		printf("gc_urgent: end on %s\n", argv[1]);
1139 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
1140 		if (system(command))
1141 			exit(1);
1142 	} else if (argc == 4 && !strcmp(argv[2], "run")) {
1143 		printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
1144 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
1145 		if (system(command))
1146 			exit(1);
1147 		sleep(atoi(argv[3]));
1148 		printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
1149 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
1150 		if (system(command))
1151 			exit(1);
1152 	} else {
1153 		fputs("Excess arguments\n\n", stderr);
1154 		fputs(cmd->cmd_help, stderr);
1155 		exit(1);
1156 	}
1157 }
1158 
1159 #define defrag_file_desc "do defragment on file"
1160 #define defrag_file_help						\
1161 "f2fs_io defrag_file [start] [length] [file_path]\n\n"		\
1162 "  start     : start offset of defragment region, unit: bytes\n"	\
1163 "  length    : bytes number of defragment region\n"			\
1164 
do_defrag_file(int argc,char ** argv,const struct cmd_desc * cmd)1165 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
1166 {
1167 	struct f2fs_defragment df;
1168 	u64 len;
1169 	int ret, fd;
1170 
1171 	if (argc != 4) {
1172 		fputs("Excess arguments\n\n", stderr);
1173 		fputs(cmd->cmd_help, stderr);
1174 		exit(1);
1175 	}
1176 
1177 	df.start = atoll(argv[1]);
1178 	df.len = len = atoll(argv[2]);
1179 
1180 	fd = xopen(argv[3], O_RDWR, 0);
1181 
1182 	ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
1183 	if (ret < 0)
1184 		die_errno("F2FS_IOC_DEFRAGMENT failed");
1185 
1186 	printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
1187 			argv[3], df.start, df.start + len);
1188 	exit(0);
1189 }
1190 
1191 #define copy_desc "copy a file"
1192 #define copy_help							\
1193 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n"			\
1194 "  src_path  : path to source file\n"					\
1195 "  dst_path  : path to destination file\n"				\
1196 "  -d        : use direct I/O\n"					\
1197 "  -m        : mmap the source file\n"					\
1198 "  -s        : use sendfile\n"						\
1199 
do_copy(int argc,char ** argv,const struct cmd_desc * cmd)1200 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
1201 {
1202 	int c;
1203 	int src_fd;
1204 	int dst_fd;
1205 	int open_flags = 0;
1206 	bool mmap_source_file = false;
1207 	bool use_sendfile = false;
1208 	ssize_t ret;
1209 
1210 	while ((c = getopt(argc, argv, "dms")) != -1) {
1211 		switch (c) {
1212 		case 'd':
1213 			open_flags |= O_DIRECT;
1214 			break;
1215 		case 'm':
1216 			mmap_source_file = true;
1217 			break;
1218 		case 's':
1219 			use_sendfile = true;
1220 			break;
1221 		default:
1222 			fputs(cmd->cmd_help, stderr);
1223 			exit(2);
1224 		}
1225 	}
1226 	argc -= optind;
1227 	argv += optind;
1228 	if (argc != 2) {
1229 		fputs("Wrong number of arguments\n\n", stderr);
1230 		fputs(cmd->cmd_help, stderr);
1231 		exit(2);
1232 	}
1233 	if (mmap_source_file && use_sendfile)
1234 		die("-m and -s are mutually exclusive");
1235 
1236 	src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
1237 	dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
1238 
1239 	if (mmap_source_file) {
1240 		struct stat stbuf;
1241 		void *src_addr;
1242 
1243 		if (fstat(src_fd, &stbuf) != 0)
1244 			die_errno("fstat of source file failed");
1245 
1246 		if ((size_t)stbuf.st_size != stbuf.st_size)
1247 			die("Source file is too large");
1248 
1249 		src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
1250 				src_fd, 0);
1251 		if (src_addr == MAP_FAILED)
1252 			die("mmap of source file failed");
1253 
1254 		full_write(dst_fd, src_addr, stbuf.st_size);
1255 
1256 		munmap(src_addr, stbuf.st_size);
1257 	} else if (use_sendfile) {
1258 		while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
1259 			;
1260 		if (ret < 0)
1261 			die_errno("sendfile failed");
1262 	} else {
1263 		char *buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, F2FS_DEFAULT_BLKSIZE);
1264 
1265 		while ((ret = xread(src_fd, buf, F2FS_DEFAULT_BLKSIZE)) > 0)
1266 			full_write(dst_fd, buf, ret);
1267 		free(buf);
1268 	}
1269 	close(src_fd);
1270 	close(dst_fd);
1271 }
1272 
1273 #define get_cblocks_desc "get number of reserved blocks on compress inode"
1274 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
1275 
do_get_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1276 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1277 {
1278 	unsigned long long blkcnt;
1279 	int ret, fd;
1280 
1281 	if (argc != 2) {
1282 		fputs("Excess arguments\n\n", stderr);
1283 		fputs(cmd->cmd_help, stderr);
1284 		exit(1);
1285 	}
1286 
1287 	fd = xopen(argv[1], O_RDONLY, 0);
1288 
1289 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
1290 	if (ret < 0)
1291 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
1292 
1293 	printf("%llu\n", blkcnt);
1294 
1295 	exit(0);
1296 }
1297 
1298 #define release_cblocks_desc "release reserved blocks on compress inode"
1299 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
1300 
do_release_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1301 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1302 {
1303 	unsigned long long blkcnt;
1304 	int ret, fd;
1305 
1306 	if (argc != 2) {
1307 		fputs("Excess arguments\n\n", stderr);
1308 		fputs(cmd->cmd_help, stderr);
1309 		exit(1);
1310 	}
1311 
1312 	fd = xopen(argv[1], O_RDONLY, 0);
1313 
1314 	ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
1315 	if (ret < 0)
1316 		die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
1317 
1318 	printf("%llu\n", blkcnt);
1319 
1320 	exit(0);
1321 }
1322 
1323 #define reserve_cblocks_desc "reserve blocks on compress inode"
1324 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
1325 
do_reserve_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)1326 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1327 {
1328 	unsigned long long blkcnt;
1329 	int ret, fd;
1330 
1331 	if (argc != 2) {
1332 		fputs("Excess arguments\n\n", stderr);
1333 		fputs(cmd->cmd_help, stderr);
1334 		exit(1);
1335 	}
1336 
1337 	fd = xopen(argv[1], O_RDONLY, 0);
1338 
1339 	ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
1340 	if (ret < 0)
1341 		die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
1342 
1343 	printf("%llu\n", blkcnt);
1344 
1345 	exit(0);
1346 }
1347 
1348 #define get_coption_desc "get compression option of a compressed file"
1349 #define get_coption_help						\
1350 "f2fs_io get_coption [file]\n\n"	\
1351 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1352 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1353 
do_get_coption(int argc,char ** argv,const struct cmd_desc * cmd)1354 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
1355 {
1356 	struct f2fs_comp_option option;
1357 	int ret, fd;
1358 
1359 	if (argc != 2) {
1360 		fputs("Excess arguments\n\n", stderr);
1361 		fputs(cmd->cmd_help, stderr);
1362 		exit(1);
1363 	}
1364 
1365 	fd = xopen(argv[1], O_RDONLY, 0);
1366 
1367 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
1368 	if (ret < 0)
1369 		die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
1370 
1371 	printf("compression algorithm:%u\n", option.algorithm);
1372 	printf("compression cluster log size:%u\n", option.log_cluster_size);
1373 
1374 	exit(0);
1375 }
1376 
1377 #define set_coption_desc "set compression option of a compressed file"
1378 #define set_coption_help						\
1379 "f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n"	\
1380 "  algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
1381 "  log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1382 
do_set_coption(int argc,char ** argv,const struct cmd_desc * cmd)1383 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
1384 {
1385 	struct f2fs_comp_option option;
1386 	int fd, ret;
1387 
1388 	if (argc != 4) {
1389 		fputs("Excess arguments\n\n", stderr);
1390 		fputs(cmd->cmd_help, stderr);
1391 		exit(1);
1392 	}
1393 
1394 	option.algorithm = atoi(argv[1]);
1395 	option.log_cluster_size = atoi(argv[2]);
1396 
1397 	fd = xopen(argv[3], O_WRONLY, 0);
1398 
1399 	ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
1400 	if (ret < 0)
1401 		die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
1402 
1403 	printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
1404 			option.algorithm, option.log_cluster_size);
1405 	exit(0);
1406 }
1407 
1408 #define decompress_desc "decompress an already compressed file"
1409 #define decompress_help "f2fs_io decompress [file_path]\n\n"
1410 
do_decompress(int argc,char ** argv,const struct cmd_desc * cmd)1411 static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
1412 {
1413 	int fd, ret;
1414 
1415 	if (argc != 2) {
1416 		fputs("Excess arguments\n\n", stderr);
1417 		fputs(cmd->cmd_help, stderr);
1418 		exit(1);
1419 	}
1420 
1421 	fd = xopen(argv[1], O_WRONLY, 0);
1422 
1423 	ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
1424 	if (ret < 0)
1425 		die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
1426 
1427 	exit(0);
1428 }
1429 
1430 #define compress_desc "compress a compression enabled file"
1431 #define compress_help "f2fs_io compress [file_path]\n\n"
1432 
do_compress(int argc,char ** argv,const struct cmd_desc * cmd)1433 static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
1434 {
1435 	int fd, ret;
1436 
1437 	if (argc != 2) {
1438 		fputs("Excess arguments\n\n", stderr);
1439 		fputs(cmd->cmd_help, stderr);
1440 		exit(1);
1441 	}
1442 
1443 	fd = xopen(argv[1], O_WRONLY, 0);
1444 
1445 	ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
1446 	if (ret < 0)
1447 		die_errno("F2FS_IOC_COMPRESS_FILE failed");
1448 
1449 	exit(0);
1450 }
1451 
1452 #define get_filename_encrypt_mode_desc "get file name encrypt mode"
1453 #define get_filename_encrypt_mode_help					\
1454 "f2fs_io filename_encrypt_mode [file or directory path]\n\n"		\
1455 "Get the file name encription mode of the given file/directory.\n"	\
1456 
do_get_filename_encrypt_mode(int argc,char ** argv,const struct cmd_desc * cmd)1457 static void do_get_filename_encrypt_mode (int argc, char **argv,
1458 						const struct cmd_desc *cmd)
1459 {
1460 	static const char *enc_name[] = {
1461 		"invalid", /* FSCRYPT_MODE_INVALID (0) */
1462 		"aes-256-xts", /* FSCRYPT_MODE_AES_256_XTS (1) */
1463 		"aes-256-gcm", /* FSCRYPT_MODE_AES_256_GCM (2) */
1464 		"aes-256-cbc", /* FSCRYPT_MODE_AES_256_CBC (3) */
1465 		"aes-256-cts", /* FSCRYPT_MODE_AES_256_CTS (4) */
1466 		"aes-128-cbc", /* FSCRYPT_MODE_AES_128_CBC (5) */
1467 		"aes-128-cts", /* FSCRYPT_MODE_AES_128_CTS (6) */
1468 		"speck128-256-xts", /* FSCRYPT_MODE_SPECK128_256_XTS (7) */
1469 		"speck128-256-cts", /* FSCRYPT_MODE_SPECK128_256_CTS (8) */
1470 		"adiantum", /* FSCRYPT_MODE_ADIANTUM (9) */
1471 		"aes-256-hctr2", /* FSCRYPT_MODE_AES_256_HCTR2 (10) */
1472 	};
1473 	int fd, mode, ret;
1474 	struct fscrypt_get_policy_ex_arg arg;
1475 
1476 	if (argc != 2) {
1477 		fputs("Excess arguments\n\n", stderr);
1478 		fputs(cmd->cmd_help, stderr);
1479 		exit(1);
1480 	}
1481 
1482 	fd = xopen(argv[1], O_RDONLY, 0);
1483 	arg.policy_size = sizeof(arg.policy);
1484 	ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
1485 	if (ret != 0 && errno == ENOTTY)
1486 		ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
1487 	close(fd);
1488 
1489 	if (ret) {
1490 		perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
1491 		exit(1);
1492 	}
1493 
1494 	switch (arg.policy.version) {
1495 	case FSCRYPT_POLICY_V1:
1496 		mode = arg.policy.v1.filenames_encryption_mode;
1497 		break;
1498 	case FSCRYPT_POLICY_V2:
1499 		mode = arg.policy.v2.filenames_encryption_mode;
1500 		break;
1501 	default:
1502 		printf("Do not support policy version: %d\n",
1503 							arg.policy.version);
1504 		exit(1);
1505 	}
1506 
1507 	if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
1508 		printf("Do not support algorithm: %d\n", mode);
1509 		exit(1);
1510 	}
1511 	printf ("%s\n", enc_name[mode]);
1512 	exit(0);
1513 }
1514 
1515 #define rename_desc "rename source to target file with fsync option"
1516 #define rename_help							\
1517 "f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n"	\
1518 "e.g., f2fs_io rename source dest 1\n"					\
1519 "      1. open(source)\n"						\
1520 "      2. rename(source, dest)\n"					\
1521 "      3. fsync(source)\n"						\
1522 "      4. close(source)\n"
1523 
do_rename(int argc,char ** argv,const struct cmd_desc * cmd)1524 static void do_rename(int argc, char **argv, const struct cmd_desc *cmd)
1525 {
1526 	int fd = -1;
1527 	int ret;
1528 
1529 	if (argc != 4) {
1530 		fputs("Excess arguments\n\n", stderr);
1531 		fputs(cmd->cmd_help, stderr);
1532 		exit(1);
1533 	}
1534 
1535 	if (atoi(argv[3]))
1536 		fd = xopen(argv[1], O_WRONLY, 0);
1537 
1538 	ret = rename(argv[1], argv[2]);
1539 	if (ret < 0)
1540 		die_errno("rename failed");
1541 
1542 	if (fd >= 0) {
1543 		if (fsync(fd) != 0)
1544 			die_errno("fsync failed: %s", argv[1]);
1545 		close(fd);
1546 	}
1547 	exit(0);
1548 }
1549 
1550 #define gc_desc "trigger filesystem GC"
1551 #define gc_help "f2fs_io gc sync_mode [file_path]\n\n"
1552 
do_gc(int argc,char ** argv,const struct cmd_desc * cmd)1553 static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
1554 {
1555 	u32 sync;
1556 	int ret, fd;
1557 
1558 	if (argc != 3) {
1559 		fputs("Excess arguments\n\n", stderr);
1560 		fputs(cmd->cmd_help, stderr);
1561 		exit(1);
1562 	}
1563 
1564 	sync = atoi(argv[1]);
1565 
1566 	fd = xopen(argv[2], O_RDONLY, 0);
1567 
1568 	ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, &sync);
1569 	if (ret < 0)
1570 		die_errno("F2FS_IOC_GARBAGE_COLLECT failed");
1571 
1572 	printf("trigger %s gc ret=%d\n",
1573 		sync ? "synchronous" : "asynchronous", ret);
1574 	exit(0);
1575 }
1576 
1577 #define checkpoint_desc "trigger filesystem checkpoint"
1578 #define checkpoint_help "f2fs_io checkpoint [file_path]\n\n"
1579 
do_checkpoint(int argc,char ** argv,const struct cmd_desc * cmd)1580 static void do_checkpoint(int argc, char **argv, const struct cmd_desc *cmd)
1581 {
1582 	int ret, fd;
1583 
1584 	if (argc != 2) {
1585 		fputs("Excess arguments\n\n", stderr);
1586 		fputs(cmd->cmd_help, stderr);
1587 		exit(1);
1588 	}
1589 
1590 	fd = xopen(argv[1], O_WRONLY, 0);
1591 
1592 	ret = ioctl(fd, F2FS_IOC_WRITE_CHECKPOINT);
1593 	if (ret < 0)
1594 		die_errno("F2FS_IOC_WRITE_CHECKPOINT failed");
1595 
1596 	printf("trigger filesystem checkpoint ret=%d\n", ret);
1597 	exit(0);
1598 }
1599 
1600 #define precache_extents_desc "trigger precache extents"
1601 #define precache_extents_help "f2fs_io precache_extents [file_path]\n\n"
1602 
do_precache_extents(int argc,char ** argv,const struct cmd_desc * cmd)1603 static void do_precache_extents(int argc, char **argv, const struct cmd_desc *cmd)
1604 {
1605 	int ret, fd;
1606 
1607 	if (argc != 2) {
1608 		fputs("Excess arguments\n\n", stderr);
1609 		fputs(cmd->cmd_help, stderr);
1610 		exit(1);
1611 	}
1612 
1613 	fd = xopen(argv[1], O_WRONLY, 0);
1614 
1615 	ret = ioctl(fd, F2FS_IOC_PRECACHE_EXTENTS);
1616 	if (ret < 0)
1617 		die_errno("F2FS_IOC_PRECACHE_EXTENTS failed");
1618 
1619 	printf("trigger precache extents ret=%d\n", ret);
1620 	exit(0);
1621 }
1622 
1623 #define move_range_desc "moving a range of data blocks from source file to destination file"
1624 #define move_range_help						\
1625 "f2fs_io move_range [src_path] [dst_path] [src_start] [dst_start] "	\
1626 "[length]\n\n"								\
1627 "  src_path  : path to source file\n"					\
1628 "  dst_path  : path to destination file\n"				\
1629 "  src_start : start offset of src file move region, unit: bytes\n"	\
1630 "  dst_start : start offset of dst file move region, unit: bytes\n"	\
1631 "  length    : size to move\n"						\
1632 
do_move_range(int argc,char ** argv,const struct cmd_desc * cmd)1633 static void do_move_range(int argc, char **argv, const struct cmd_desc *cmd)
1634 {
1635 	struct f2fs_move_range range;
1636 	int ret, fd;
1637 
1638 	if (argc != 6) {
1639 		fputs("Excess arguments\n\n", stderr);
1640 		fputs(cmd->cmd_help, stderr);
1641 		exit(1);
1642 	}
1643 
1644 	fd = xopen(argv[1], O_RDWR, 0);
1645 	range.dst_fd = xopen(argv[2], O_RDWR | O_CREAT, 0644);
1646 	range.pos_in = atoll(argv[3]);
1647 	range.pos_out = atoll(argv[4]);
1648 	range.len = atoll(argv[5]);
1649 
1650 	ret = ioctl(fd, F2FS_IOC_MOVE_RANGE, &range);
1651 	if (ret < 0)
1652 		die_errno("F2FS_IOC_MOVE_RANGE failed");
1653 
1654 	printf("move range ret=%d\n", ret);
1655 	exit(0);
1656 }
1657 
1658 #define gc_range_desc "trigger filesystem gc_range"
1659 #define gc_range_help "f2fs_io gc_range [sync_mode] [start] [length] [file_path]\n\n"\
1660 "  sync_mode : 0: asynchronous, 1: synchronous\n"			\
1661 "  start     : start offset of defragment region, unit: 4kb\n"	\
1662 "  length    : bytes number of defragment region, unit: 4kb\n"	\
1663 
do_gc_range(int argc,char ** argv,const struct cmd_desc * cmd)1664 static void do_gc_range(int argc, char **argv, const struct cmd_desc *cmd)
1665 {
1666 	struct f2fs_gc_range range;
1667 	int ret, fd;
1668 
1669 	if (argc != 5) {
1670 		fputs("Excess arguments\n\n", stderr);
1671 		fputs(cmd->cmd_help, stderr);
1672 		exit(1);
1673 	}
1674 
1675 	range.sync = atoi(argv[1]);
1676 	range.start = (u64)atoi(argv[2]);
1677 	range.len = (u64)atoi(argv[3]);
1678 
1679 	fd = xopen(argv[4], O_RDWR, 0);
1680 
1681 	ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT_RANGE, &range);
1682 	if (ret < 0) {
1683 		die_errno("F2FS_IOC_GARBAGE_COLLECT_RANGE failed");
1684 	}
1685 
1686 	printf("trigger %s gc_range [%"PRIu64", %"PRIu64"] ret=%d\n",
1687 		range.sync ? "synchronous" : "asynchronous",
1688 		range.start, range.len, ret);
1689 	exit(0);
1690 }
1691 
1692 #define listxattr_desc "listxattr"
1693 #define listxattr_help "f2fs_io listxattr [file_path]\n\n"
1694 
do_listxattr(int argc,char ** argv,const struct cmd_desc * cmd)1695 static void do_listxattr(int argc, char **argv, const struct cmd_desc *cmd)
1696 {
1697 	char *buf, *key, *val;
1698 	ssize_t buflen, vallen, keylen;
1699 
1700 	if (argc != 2) {
1701 		fputs("Excess arguments\n\n", stderr);
1702 		fputs(cmd->cmd_help, stderr);
1703 		exit(1);
1704 	}
1705 
1706 	buflen = listxattr(argv[1], NULL, 0);
1707 	if (buflen == -1) {
1708 		perror("listxattr");
1709 		exit(1);
1710 	}
1711 	if (buflen == 0) {
1712 		printf("%s has no attributes.\n", argv[1]);
1713 		exit(0);
1714 	}
1715 	buf = xmalloc(buflen);
1716 	buflen = listxattr(argv[1], buf, buflen);
1717 	if (buflen == -1) {
1718 		perror("listxattr");
1719 		exit(1);
1720 	}
1721 
1722 	key = buf;
1723 	while (buflen > 0) {
1724 		printf("%s: ", key);
1725 		vallen = getxattr(argv[1], key, NULL, 0);
1726 		if (vallen == -1) {
1727 			perror("getxattr");
1728 			exit(1);
1729 		}
1730 		if (vallen == 0) {
1731 			printf("<no value>");
1732 		} else {
1733 			val = xmalloc(vallen + 1);
1734 			vallen = getxattr(argv[1], key, val, vallen);
1735 			if (vallen == -1) {
1736 				perror("getxattr");
1737 				exit(1);
1738 			}
1739 			val[vallen] = 0;
1740 			printf("%s", val);
1741 			free(val);
1742 		}
1743 		printf("\n");
1744 		keylen = strlen(key) + 1;
1745 		buflen -= keylen;
1746 		key += keylen;
1747 	}
1748 	exit(0);
1749 }
1750 
1751 #define setxattr_desc "setxattr"
1752 #define setxattr_help "f2fs_io setxattr [name] [value] [file_path]\n\n"
1753 
do_setxattr(int argc,char ** argv,const struct cmd_desc * cmd)1754 static void do_setxattr(int argc, char **argv, const struct cmd_desc *cmd)
1755 {
1756 	int ret;
1757 	char *value;
1758 	unsigned char tmp;
1759 
1760 	if (argc != 4) {
1761 		fputs("Excess arguments\n\n", stderr);
1762 		fputs(cmd->cmd_help, stderr);
1763 		exit(1);
1764 	}
1765 
1766 	if (!strcmp(argv[1], F2FS_SYSTEM_ADVISE_NAME)) {
1767 		tmp = strtoul(argv[2], NULL, 0);
1768 		value = (char *)&tmp;
1769 	} else {
1770 		value = argv[2];
1771 	}
1772 
1773 	ret = setxattr(argv[3], argv[1], value, strlen(argv[2]), XATTR_CREATE);
1774 	printf("setxattr %s CREATE: name: %s, value: %s: ret=%d\n",
1775 			argv[3], argv[1], argv[2], ret);
1776 	if (ret < 0 && errno == EEXIST) {
1777 		ret = setxattr(argv[3], argv[1], value, strlen(argv[2]), XATTR_REPLACE);
1778 		printf("setxattr %s REPLACE: name: %s, value: %s: ret=%d\n",
1779 				argv[3], argv[1], argv[2], ret);
1780 	}
1781 	if (ret < 0)
1782 		perror("setxattr");
1783 	exit(0);
1784 }
1785 
1786 #define removexattr_desc "removexattr"
1787 #define removexattr_help "f2fs_io removexattr [name] [file_path]\n\n"
1788 
do_removexattr(int argc,char ** argv,const struct cmd_desc * cmd)1789 static void do_removexattr(int argc, char **argv, const struct cmd_desc *cmd)
1790 {
1791 	int ret;
1792 
1793 	if (argc != 3) {
1794 		fputs("Excess arguments\n\n", stderr);
1795 		fputs(cmd->cmd_help, stderr);
1796 		exit(1);
1797 	}
1798 
1799 	ret = removexattr(argv[2], argv[1]);
1800 	printf("removexattr %s REMOVE: name: %s: ret=%d\n", argv[1], argv[2], ret);
1801 	exit(0);
1802 }
1803 
1804 #define lseek_desc "do lseek for a file"
1805 #define lseek_help					\
1806 "f2fs_io lseek [whence] [offset] [file_path]\n\n"	\
1807 "Do lseek file data in file_path and return the adjusted file offset\n"	\
1808 "whence can be\n"					\
1809 "  set  : SEEK_SET, The file offset is set to offset bytes\n"	\
1810 "  cur  : SEEK_CUR, The file offset is set to its current location plus offset bytes\n"	\
1811 "  end  : SEEK_END, The file offset is set to the size of the file plus offset bytes\n"	\
1812 "  data : SEEK_DATA, set the file offset to the next data location from offset\n"	\
1813 "  hole : SEEK_HOLE, set the file offset to the next hole from offset\n"
1814 
do_lseek(int argc,char ** argv,const struct cmd_desc * cmd)1815 static void do_lseek(int argc, char **argv, const struct cmd_desc *cmd)
1816 {
1817 	int fd, whence;
1818 	off_t offset, ret;
1819 
1820 	if (argc != 4) {
1821 		fputs("Excess arguments\n\n", stderr);
1822 		fputs(cmd->cmd_help, stderr);
1823 		exit(1);
1824 	}
1825 
1826 	offset = atoll(argv[2]);
1827 
1828 	if (!strcmp(argv[1], "set"))
1829 		whence = SEEK_SET;
1830 	else if (!strcmp(argv[1], "cur"))
1831 		whence = SEEK_CUR;
1832 	else if (!strcmp(argv[1], "end"))
1833 		whence = SEEK_END;
1834 	else if (!strcmp(argv[1], "data"))
1835 		whence = SEEK_DATA;
1836 	else if (!strcmp(argv[1], "hole"))
1837 		whence = SEEK_HOLE;
1838 	else
1839 		die("Wrong whence type");
1840 
1841 	fd = xopen(argv[3], O_RDONLY, 0);
1842 
1843 	ret = lseek(fd, offset, whence);
1844 	if (ret < 0)
1845 		die_errno("lseek failed");
1846 	printf("returned offset=%lld\n", (long long)ret);
1847 	exit(0);
1848 }
1849 
1850 #define get_advise_desc "get_advise"
1851 #define get_advise_help "f2fs_io get_advise [file_path]\n\n"
1852 
do_get_advise(int argc,char ** argv,const struct cmd_desc * cmd)1853 static void do_get_advise(int argc, char **argv, const struct cmd_desc *cmd)
1854 {
1855 	int ret;
1856 	unsigned char value;
1857 
1858 	if (argc != 2) {
1859 		fputs("Excess arguments\n\n", stderr);
1860 		fputs(cmd->cmd_help, stderr);
1861 		exit(1);
1862 	}
1863 
1864 	ret = getxattr(argv[1], F2FS_SYSTEM_ADVISE_NAME, &value, sizeof(value));
1865 	if (ret != sizeof(value)) {
1866 		perror("getxattr");
1867 		exit(1);
1868 	}
1869 
1870 	printf("i_advise=0x%x, advise_type: ", value);
1871 	if (value & FADVISE_COLD_BIT)
1872 		printf("cold ");
1873 	if (value & FADVISE_LOST_PINO_BIT)
1874 		printf("lost_pino ");
1875 	if (value & FADVISE_ENCRYPT_BIT)
1876 		printf("encrypt ");
1877 	if (value & FADVISE_ENC_NAME_BIT)
1878 		printf("enc_name ");
1879 	if (value & FADVISE_KEEP_SIZE_BIT)
1880 		printf("keep_size ");
1881 	if (value & FADVISE_HOT_BIT)
1882 		printf("hot ");
1883 	if (value & FADVISE_VERITY_BIT)
1884 		printf("verity ");
1885 	if (value & FADVISE_TRUNC_BIT)
1886 		printf("trunc ");
1887 	printf("\n");
1888 }
1889 
1890 #define CMD_HIDDEN 	0x0001
1891 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
1892 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
1893 
1894 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
1895 const struct cmd_desc cmd_list[] = {
1896 	_CMD(help),
1897 	CMD(fsync),
1898 	CMD(fdatasync),
1899 	CMD(set_verity),
1900 	CMD(getflags),
1901 	CMD(setflags),
1902 	CMD(clearflags),
1903 	CMD(shutdown),
1904 	CMD(pinfile),
1905 	CMD(fadvise),
1906 	CMD(fallocate),
1907 	CMD(erase),
1908 	CMD(write),
1909 	CMD(write_advice),
1910 	CMD(read),
1911 	CMD(randread),
1912 	CMD(fiemap),
1913 	CMD(gc_urgent),
1914 	CMD(defrag_file),
1915 	CMD(copy),
1916 	CMD(get_cblocks),
1917 	CMD(release_cblocks),
1918 	CMD(reserve_cblocks),
1919 	CMD(get_coption),
1920 	CMD(set_coption),
1921 	CMD(decompress),
1922 	CMD(compress),
1923 	CMD(get_filename_encrypt_mode),
1924 	CMD(rename),
1925 	CMD(gc),
1926 	CMD(checkpoint),
1927 	CMD(precache_extents),
1928 	CMD(move_range),
1929 	CMD(gc_range),
1930 	CMD(listxattr),
1931 	CMD(setxattr),
1932 	CMD(removexattr),
1933 	CMD(lseek),
1934 	CMD(get_advise),
1935 	{ NULL, NULL, NULL, NULL, 0 }
1936 };
1937 
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))1938 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
1939 {
1940 	const struct cmd_desc *p;
1941 
1942 	if (argc > 1) {
1943 		for (p = cmd_list; p->cmd_name; p++) {
1944 			if (p->cmd_flags & CMD_HIDDEN)
1945 				continue;
1946 			if (strcmp(p->cmd_name, argv[1]) == 0) {
1947 				putc('\n', stdout);
1948 				fputs("USAGE:\n  ", stdout);
1949 				fputs(p->cmd_help, stdout);
1950 				exit(0);
1951 			}
1952 		}
1953 		printf("Unknown command: %s\n\n", argv[1]);
1954 	}
1955 
1956 	fputs("Available commands:\n", stdout);
1957 	for (p = cmd_list; p->cmd_name; p++) {
1958 		if (p->cmd_flags & CMD_HIDDEN)
1959 			continue;
1960 		printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
1961 	}
1962 	printf("\nTo get more information on a command, "
1963 	       "type 'f2fs_io help cmd'\n");
1964 	exit(0);
1965 }
1966 
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))1967 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
1968 				void *UNUSED(context))
1969 {
1970 	exit(-1);
1971 }
1972 
sigcatcher_setup(void)1973 static void sigcatcher_setup(void)
1974 {
1975 	struct sigaction	sa;
1976 
1977 	memset(&sa, 0, sizeof(struct sigaction));
1978 	sa.sa_sigaction = die_signal_handler;
1979 	sa.sa_flags = SA_SIGINFO;
1980 
1981 	sigaction(SIGHUP, &sa, 0);
1982 	sigaction(SIGINT, &sa, 0);
1983 	sigaction(SIGQUIT, &sa, 0);
1984 	sigaction(SIGFPE, &sa, 0);
1985 	sigaction(SIGILL, &sa, 0);
1986 	sigaction(SIGBUS, &sa, 0);
1987 	sigaction(SIGSEGV, &sa, 0);
1988 	sigaction(SIGABRT, &sa, 0);
1989 	sigaction(SIGPIPE, &sa, 0);
1990 	sigaction(SIGALRM, &sa, 0);
1991 	sigaction(SIGTERM, &sa, 0);
1992 	sigaction(SIGUSR1, &sa, 0);
1993 	sigaction(SIGUSR2, &sa, 0);
1994 	sigaction(SIGPOLL, &sa, 0);
1995 	sigaction(SIGPROF, &sa, 0);
1996 	sigaction(SIGSYS, &sa, 0);
1997 	sigaction(SIGTRAP, &sa, 0);
1998 	sigaction(SIGVTALRM, &sa, 0);
1999 	sigaction(SIGXCPU, &sa, 0);
2000 	sigaction(SIGXFSZ, &sa, 0);
2001 }
2002 
main(int argc,char ** argv)2003 int main(int argc, char **argv)
2004 {
2005 	const struct cmd_desc *cmd;
2006 
2007 	if (argc < 2)
2008 		do_help(argc, argv, cmd_list);
2009 
2010 	sigcatcher_setup();
2011 	for (cmd = cmd_list; cmd->cmd_name; cmd++) {
2012 		if (strcmp(cmd->cmd_name, argv[1]) == 0) {
2013 			cmd->cmd_func(argc - 1, argv + 1, cmd);
2014 			exit(0);
2015 		}
2016 	}
2017 	printf("Unknown command: %s\n\n", argv[1]);
2018 	do_help(1, argv, cmd_list);
2019 	return 0;
2020 }
2021