• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * f2fs_io.c - f2fs ioctl utility
3  *
4  * Author: Jaegeuk Kim <jaegeuk@kernel.org>
5  *
6  * Copied portion of the code from ../f2fscrypt.c
7  */
8 
9 #ifndef _GNU_SOURCE
10 #define _GNU_SOURCE
11 #endif
12 #ifndef _LARGEFILE_SOURCE
13 #define _LARGEFILE_SOURCE
14 #endif
15 #ifndef _LARGEFILE64_SOURCE
16 #define _LARGEFILE64_SOURCE
17 #endif
18 #ifndef O_LARGEFILE
19 #define O_LARGEFILE 0
20 #endif
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <getopt.h>
25 #include <inttypes.h>
26 #include <limits.h>
27 #include <signal.h>
28 #include <stdarg.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <string.h>
34 #include <sys/mman.h>
35 #include <sys/sendfile.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <termios.h>
39 #include <time.h>
40 #include <unistd.h>
41 
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
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 #if defined(__APPLE__)
get_current_us()134 static u64 get_current_us()
135 {
136 #ifdef HAVE_MACH_TIME_H
137 	return mach_absolute_time() / 1000;
138 #else
139 	return 0;
140 #endif
141 }
142 #else
get_current_us()143 static u64 get_current_us()
144 {
145 	struct timespec t;
146 	t.tv_sec = t.tv_nsec = 0;
147 	clock_gettime(CLOCK_BOOTTIME, &t);
148 	return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
149 }
150 #endif
151 
152 #define fsync_desc "fsync"
153 #define fsync_help						\
154 "f2fs_io fsync [file]\n\n"					\
155 "fsync given the file\n"					\
156 
do_fsync(int argc,char ** argv,const struct cmd_desc * cmd)157 static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
158 {
159 	int fd;
160 
161 	if (argc != 2) {
162 		fputs("Excess arguments\n\n", stderr);
163 		fputs(cmd->cmd_help, stderr);
164 		exit(1);
165 	}
166 
167 	fd = xopen(argv[1], O_WRONLY, 0);
168 
169 	if (fsync(fd) != 0)
170 		die_errno("fsync failed");
171 
172 	printf("fsync a file\n");
173 	exit(0);
174 }
175 
176 #define set_verity_desc "Set fs-verity"
177 #define set_verity_help					\
178 "f2fs_io set_verity [file]\n\n"				\
179 "Set fsverity bit given a file\n"			\
180 
do_set_verity(int argc,char ** argv,const struct cmd_desc * cmd)181 static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
182 {
183 	int ret, fd;
184 
185 	if (argc != 2) {
186 		fputs("Excess arguments\n\n", stderr);
187 		fputs(cmd->cmd_help, stderr);
188 		exit(1);
189 	}
190 
191 	fd = open(argv[1], O_RDWR);
192 
193 	ret = ioctl(fd, FS_IOC_ENABLE_VERITY);
194 	if (ret < 0) {
195 		perror("FS_IOC_ENABLE_VERITY");
196 		exit(1);
197 	}
198 
199 	printf("Set fsverity bit to %s\n", argv[1]);
200 	exit(0);
201 }
202 
203 #define getflags_desc "getflags ioctl"
204 #define getflags_help						\
205 "f2fs_io getflags [file]\n\n"					\
206 "get a flag given the file\n"					\
207 "flag can show \n"						\
208 "  encryption\n"						\
209 "  nocow(pinned)\n"						\
210 "  inline_data\n"						\
211 "  verity\n"							\
212 "  casefold\n"							\
213 "  compression\n"						\
214 "  nocompression\n"
215 
do_getflags(int argc,char ** argv,const struct cmd_desc * cmd)216 static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
217 {
218 	long flag = 0;
219 	int ret, fd;
220 	int exist = 0;
221 
222 	if (argc != 2) {
223 		fputs("Excess arguments\n\n", stderr);
224 		fputs(cmd->cmd_help, stderr);
225 		exit(1);
226 	}
227 
228 	fd = xopen(argv[1], O_RDONLY, 0);
229 
230 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
231 	printf("get a flag on %s ret=%d, flags=", argv[1], ret);
232 	if (flag & FS_CASEFOLD_FL) {
233 		printf("casefold");
234 		exist = 1;
235 	}
236 	if (flag & FS_COMPR_FL) {
237 		if (exist)
238 			printf(",");
239 		printf("compression");
240 		exist = 1;
241 	}
242 	if (flag & FS_NOCOMP_FL) {
243 		if (exist)
244 			printf(",");
245 		printf("nocompression");
246 		exist = 1;
247 	}
248 	if (flag & FS_ENCRYPT_FL) {
249 		if (exist)
250 			printf(",");
251 		printf("encrypt");
252 		exist = 1;
253 	}
254 	if (flag & FS_VERITY_FL) {
255 		if (exist)
256 			printf(",");
257 		printf("verity");
258 		exist = 1;
259 	}
260 	if (flag & FS_INLINE_DATA_FL) {
261 		if (exist)
262 			printf(",");
263 		printf("inline_data");
264 		exist = 1;
265 	}
266 	if (flag & FS_NOCOW_FL) {
267 		if (exist)
268 			printf(",");
269 		printf("nocow(pinned)");
270 		exist = 1;
271 	}
272 	if (!exist)
273 		printf("none");
274 	printf("\n");
275 	exit(0);
276 }
277 
278 #define setflags_desc "setflags ioctl"
279 #define setflags_help						\
280 "f2fs_io setflags [flag] [file]\n\n"				\
281 "set a flag given the file\n"					\
282 "flag can be\n"							\
283 "  casefold\n"							\
284 "  compression\n"						\
285 "  nocompression\n"
286 
do_setflags(int argc,char ** argv,const struct cmd_desc * cmd)287 static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
288 {
289 	long flag = 0;
290 	int ret, fd;
291 
292 	if (argc != 3) {
293 		fputs("Excess arguments\n\n", stderr);
294 		fputs(cmd->cmd_help, stderr);
295 		exit(1);
296 	}
297 
298 	fd = xopen(argv[2], O_RDONLY, 0);
299 
300 	ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
301 	printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
302 	if (ret)
303 		die_errno("F2FS_IOC_GETFLAGS failed");
304 
305 	if (!strcmp(argv[1], "casefold"))
306 		flag |= FS_CASEFOLD_FL;
307 	else if (!strcmp(argv[1], "compression"))
308 		flag |= FS_COMPR_FL;
309 	else if (!strcmp(argv[1], "nocompression"))
310 		flag |= FS_NOCOMP_FL;
311 
312 	ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
313 	printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
314 	exit(0);
315 }
316 
317 #define shutdown_desc "shutdown filesystem"
318 #define shutdown_help					\
319 "f2fs_io shutdown [level] [dir]\n\n"			\
320 "Freeze and stop all IOs given mount point\n"		\
321 "level can be\n"					\
322 "  0 : going down with full sync\n"			\
323 "  1 : going down with checkpoint only\n"		\
324 "  2 : going down with no sync\n"			\
325 "  3 : going down with metadata flush\n"		\
326 "  4 : going down with fsck mark\n"
327 
do_shutdown(int argc,char ** argv,const struct cmd_desc * cmd)328 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
329 {
330 	u32 flag;
331 	int ret, fd;
332 
333 	if (argc != 3) {
334 		fputs("Excess arguments\n\n", stderr);
335 		fputs(cmd->cmd_help, stderr);
336 		exit(1);
337 	}
338 
339 	flag = atoi(argv[1]);
340 	if (flag >= F2FS_GOING_DOWN_MAX) {
341 		fputs("Wrong level\n\n", stderr);
342 		fputs(cmd->cmd_help, stderr);
343 		exit(1);
344 	}
345 	fd = xopen(argv[2], O_RDONLY, 0);
346 
347 	ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
348 	if (ret < 0)
349 		die_errno("F2FS_IOC_SHUTDOWN failed");
350 
351 	printf("Shutdown %s with level=%d\n", argv[2], flag);
352 	exit(0);
353 }
354 
355 #define pinfile_desc "pin file control"
356 #define pinfile_help						\
357 "f2fs_io pinfile [get|set] [file]\n\n"			\
358 "get/set pinning given the file\n"				\
359 
do_pinfile(int argc,char ** argv,const struct cmd_desc * cmd)360 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
361 {
362 	u32 pin;
363 	int ret, fd;
364 
365 	if (argc != 3) {
366 		fputs("Excess arguments\n\n", stderr);
367 		fputs(cmd->cmd_help, stderr);
368 		exit(1);
369 	}
370 
371 	fd = xopen(argv[2], O_RDONLY, 0);
372 
373 	ret = -1;
374 	if (!strcmp(argv[1], "set")) {
375 		pin = 1;
376 		ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
377 		if (ret != 0)
378 			die_errno("F2FS_IOC_SET_PIN_FILE failed");
379 		printf("set_pin_file: %u blocks moved in %s\n", ret, argv[2]);
380 	} else if (!strcmp(argv[1], "get")) {
381 		unsigned int flags;
382 
383 		ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
384 		if (ret < 0)
385 			die_errno("F2FS_IOC_GET_PIN_FILE failed");
386 
387 		ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
388 		if (ret < 0)
389 			die_errno("F2FS_IOC_GETFLAGS failed");
390 
391 		printf("get_pin_file: %s with %u blocks moved in %s\n",
392 				(flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
393 				pin, argv[2]);
394 	}
395 	exit(0);
396 }
397 
398 #define fallocate_desc "fallocate"
399 #define fallocate_help						\
400 "f2fs_io fallocate [keep_size] [offset] [length] [file]\n\n"	\
401 "fallocate given the file\n"					\
402 " [keep_size] : 1 or 0\n"					\
403 
do_fallocate(int argc,char ** argv,const struct cmd_desc * cmd)404 static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
405 {
406 	int fd;
407 	off_t offset, length;
408 	struct stat sb;
409 	int mode = 0;
410 
411 	if (argc != 5) {
412 		fputs("Excess arguments\n\n", stderr);
413 		fputs(cmd->cmd_help, stderr);
414 		exit(1);
415 	}
416 
417 	if (!strcmp(argv[1], "1"))
418 		mode |= FALLOC_FL_KEEP_SIZE;
419 
420 	offset = atoi(argv[2]);
421 	length = atoll(argv[3]);
422 
423 	fd = xopen(argv[4], O_RDWR, 0);
424 
425 	if (fallocate(fd, mode, offset, length) != 0)
426 		die_errno("fallocate failed");
427 
428 	if (fstat(fd, &sb) != 0)
429 		die_errno("fstat failed");
430 
431 	printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
432 	exit(0);
433 }
434 
435 #define write_desc "write data into file"
436 #define write_help					\
437 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path]\n\n"	\
438 "Write given patten data in file_path\n"		\
439 "pattern can be\n"					\
440 "  zero     : zeros\n"					\
441 "  inc_num  : incrementing numbers\n"			\
442 "  rand     : random numbers\n"				\
443 "IO can be\n"						\
444 "  buffered : buffered IO\n"				\
445 "  dio      : direct IO\n"				\
446 "  osync    : O_SYNC\n"					\
447 
do_write(int argc,char ** argv,const struct cmd_desc * cmd)448 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
449 {
450 	u64 buf_size = 0, inc_num = 0, ret = 0, written = 0;
451 	u64 offset;
452 	char *buf = NULL;
453 	unsigned bs, count, i;
454 	int flags = 0;
455 	int fd;
456 	u64 total_time = 0, max_time = 0, max_time_t = 0;
457 
458 	srand(time(0));
459 
460 	if (argc != 7) {
461 		fputs("Excess arguments\n\n", stderr);
462 		fputs(cmd->cmd_help, stderr);
463 		exit(1);
464 	}
465 
466 	bs = atoi(argv[1]);
467 	if (bs > 1024)
468 		die("Too big chunk size - limit: 4MB");
469 
470 	buf_size = bs * 4096;
471 
472 	offset = atoi(argv[2]) * buf_size;
473 
474 	buf = aligned_xalloc(4096, buf_size);
475 	count = atoi(argv[3]);
476 
477 	if (!strcmp(argv[4], "zero"))
478 		memset(buf, 0, buf_size);
479 	else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
480 		die("Wrong pattern type");
481 
482 	if (!strcmp(argv[5], "dio"))
483 		flags |= O_DIRECT;
484 	else if (!strcmp(argv[5], "osync"))
485 		flags |= O_SYNC;
486 	else if (strcmp(argv[5], "buffered"))
487 		die("Wrong IO type");
488 
489 	fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
490 
491 	total_time = get_current_us();
492 	for (i = 0; i < count; i++) {
493 		if (!strcmp(argv[4], "inc_num"))
494 			*(int *)buf = inc_num++;
495 		else if (!strcmp(argv[4], "rand"))
496 			*(int *)buf = rand();
497 
498 		/* write data */
499 		max_time_t = get_current_us();
500 		ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
501 		max_time_t = get_current_us() - max_time_t;
502 		if (max_time < max_time_t)
503 			max_time = max_time_t;
504 		if (ret != buf_size)
505 			break;
506 		written += ret;
507 	}
508 
509 	printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
510 				written, argv[4],
511 				get_current_us() - total_time,
512 				max_time);
513 	exit(0);
514 }
515 
516 #define read_desc "read data from file"
517 #define read_help					\
518 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n"	\
519 "Read data in file_path and print nbytes\n"		\
520 "IO can be\n"						\
521 "  buffered : buffered IO\n"				\
522 "  dio      : direct IO\n"				\
523 "  mmap     : mmap IO\n"				\
524 
do_read(int argc,char ** argv,const struct cmd_desc * cmd)525 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
526 {
527 	u64 buf_size = 0, ret = 0, read_cnt = 0;
528 	u64 offset;
529 	char *buf = NULL;
530 	char *data;
531 	char *print_buf = NULL;
532 	unsigned bs, count, i, print_bytes;
533 	int flags = 0;
534 	int do_mmap = 0;
535 	int fd;
536 
537 	if (argc != 7) {
538 		fputs("Excess arguments\n\n", stderr);
539 		fputs(cmd->cmd_help, stderr);
540 		exit(1);
541 	}
542 
543 	bs = atoi(argv[1]);
544 	if (bs > 1024)
545 		die("Too big chunk size - limit: 4MB");
546 	buf_size = bs * 4096;
547 
548 	offset = atoi(argv[2]) * buf_size;
549 
550 	buf = aligned_xalloc(4096, buf_size);
551 
552 	count = atoi(argv[3]);
553 	if (!strcmp(argv[4], "dio"))
554 		flags |= O_DIRECT;
555 	else if (!strcmp(argv[4], "mmap"))
556 		do_mmap = 1;
557 	else if (strcmp(argv[4], "buffered"))
558 		die("Wrong IO type");
559 
560 	print_bytes = atoi(argv[5]);
561 	if (print_bytes > buf_size)
562 		die("Print_nbytes should be less then chunk_size in kb");
563 
564 	print_buf = xmalloc(print_bytes);
565 
566 	fd = xopen(argv[6], O_RDONLY | flags, 0);
567 
568 	if (do_mmap) {
569 		data = mmap(NULL, count * buf_size, PROT_READ,
570 						MAP_SHARED, fd, offset);
571 		if (data == MAP_FAILED)
572 			die("Mmap failed");
573 	}
574 
575 	for (i = 0; i < count; i++) {
576 		if (do_mmap) {
577 			memcpy(buf, data + offset + buf_size * i, buf_size);
578 			ret = buf_size;
579 		} else {
580 			ret = pread(fd, buf, buf_size, offset + buf_size * i);
581 		}
582 		if (ret != buf_size)
583 			break;
584 
585 		read_cnt += ret;
586 		if (i == 0)
587 			memcpy(print_buf, buf, print_bytes);
588 	}
589 	printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
590 	printf("%08"PRIx64" : ", offset);
591 	for (i = 1; i <= print_bytes; i++) {
592 		printf("%02x", print_buf[i - 1]);
593 		if (i % 16 == 0)
594 			printf("\n%08"PRIx64" : ", offset + 16 * i);
595 		else if (i % 2 == 0)
596 			printf(" ");
597 	}
598 	printf("\n");
599 	exit(0);
600 }
601 
602 #define randread_desc "random read data from file"
603 #define randread_help					\
604 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n"	\
605 "Do random read data in file_path\n"		\
606 "IO can be\n"						\
607 "  buffered : buffered IO\n"				\
608 "  dio      : direct IO\n"				\
609 
do_randread(int argc,char ** argv,const struct cmd_desc * cmd)610 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
611 {
612 	u64 buf_size = 0, ret = 0, read_cnt = 0;
613 	u64 idx, end_idx, aligned_size;
614 	char *buf = NULL;
615 	unsigned bs, count, i;
616 	int flags = 0;
617 	int fd;
618 	time_t t;
619 	struct stat stbuf;
620 
621 	if (argc != 5) {
622 		fputs("Excess arguments\n\n", stderr);
623 		fputs(cmd->cmd_help, stderr);
624 		exit(1);
625 	}
626 
627 	bs = atoi(argv[1]);
628 	if (bs > 1024)
629 		die("Too big chunk size - limit: 4MB");
630 	buf_size = bs * 4096;
631 
632 	buf = aligned_xalloc(4096, buf_size);
633 
634 	count = atoi(argv[2]);
635 	if (!strcmp(argv[3], "dio"))
636 		flags |= O_DIRECT;
637 	else if (strcmp(argv[3], "buffered"))
638 		die("Wrong IO type");
639 
640 	fd = xopen(argv[4], O_RDONLY | flags, 0);
641 
642 	if (fstat(fd, &stbuf) != 0)
643 		die_errno("fstat of source file failed");
644 
645 	aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
646 	if (aligned_size < buf_size)
647 		die("File is too small to random read");
648 	end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
649 
650 	srand((unsigned) time(&t));
651 
652 	for (i = 0; i < count; i++) {
653 		idx = rand() % end_idx;
654 
655 		ret = pread(fd, buf, buf_size, 4096 * idx);
656 		if (ret != buf_size)
657 			break;
658 
659 		read_cnt += ret;
660 	}
661 	printf("Read %"PRIu64" bytes\n", read_cnt);
662 	exit(0);
663 }
664 
665 struct file_ext {
666 	__u32 f_pos;
667 	__u32 start_blk;
668 	__u32 end_blk;
669 	__u32 blk_count;
670 };
671 
672 #ifndef FIBMAP
673 #define FIBMAP          _IO(0x00, 1)    /* bmap access */
674 #endif
675 
676 #define fiemap_desc "get block address in file"
677 #define fiemap_help					\
678 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
679 
do_fiemap(int argc,char ** argv,const struct cmd_desc * cmd)680 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
681 {
682 	u64 offset;
683 	u32 blknum;
684 	unsigned count, i;
685 	int fd;
686 
687 	if (argc != 4) {
688 		fputs("Excess arguments\n\n", stderr);
689 		fputs(cmd->cmd_help, stderr);
690 		exit(1);
691 	}
692 
693 	offset = atoi(argv[1]);
694 	count = atoi(argv[2]);
695 
696 	fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
697 
698 	printf("Fiemap: offset = %08"PRIx64" len = %d\n", offset, count);
699 	for (i = 0; i < count; i++) {
700 		blknum = offset + i;
701 
702 		if (ioctl(fd, FIBMAP, &blknum) < 0)
703 			die_errno("FIBMAP failed");
704 
705 		printf("%u ", blknum);
706 	}
707 	printf("\n");
708 	exit(0);
709 }
710 
711 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
712 #define gc_urgent_help					\
713 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
714 " - f2fs_io gc_urgent sda21 start\n"		\
715 " - f2fs_io gc_urgent sda21 end\n"		\
716 " - f2fs_io gc_urgent sda21 run 10\n"		\
717 
do_gc_urgent(int argc,char ** argv,const struct cmd_desc * cmd)718 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
719 {
720 	char command[255];
721 
722 	if (argc == 3 && !strcmp(argv[2], "start")) {
723 		printf("gc_urgent: start on %s\n", argv[1]);
724 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
725 		if (system(command))
726 			exit(1);
727 	} else if (argc == 3 && !strcmp(argv[2], "end")) {
728 		printf("gc_urgent: end on %s\n", argv[1]);
729 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
730 		if (system(command))
731 			exit(1);
732 	} else if (argc == 4 && !strcmp(argv[2], "run")) {
733 		printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
734 		sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
735 		if (system(command))
736 			exit(1);
737 		sleep(atoi(argv[3]));
738 		printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
739 		sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
740 		if (system(command))
741 			exit(1);
742 	} else {
743 		fputs("Excess arguments\n\n", stderr);
744 		fputs(cmd->cmd_help, stderr);
745 		exit(1);
746 	}
747 }
748 
749 #define defrag_file_desc "do defragment on file"
750 #define defrag_file_help						\
751 "f2fs_io defrag_file [start] [length] [file_path]\n\n"		\
752 "  start     : start offset of defragment region, unit: bytes\n"	\
753 "  length    : bytes number of defragment region\n"			\
754 
do_defrag_file(int argc,char ** argv,const struct cmd_desc * cmd)755 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
756 {
757 	struct f2fs_defragment df;
758 	u64 len;
759 	int ret, fd;
760 
761 	if (argc != 4) {
762 		fputs("Excess arguments\n\n", stderr);
763 		fputs(cmd->cmd_help, stderr);
764 		exit(1);
765 	}
766 
767 	df.start = atoll(argv[1]);
768 	df.len = len = atoll(argv[2]);
769 
770 	fd = xopen(argv[3], O_RDWR, 0);
771 
772 	ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
773 	if (ret < 0)
774 		die_errno("F2FS_IOC_DEFRAGMENT failed");
775 
776 	printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
777 			argv[3], df.start, df.start + len);
778 	exit(0);
779 }
780 
781 #define copy_desc "copy a file"
782 #define copy_help							\
783 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n"			\
784 "  src_path  : path to source file\n"					\
785 "  dst_path  : path to destination file\n"				\
786 "  -d        : use direct I/O\n"					\
787 "  -m        : mmap the source file\n"					\
788 "  -s        : use sendfile\n"						\
789 
do_copy(int argc,char ** argv,const struct cmd_desc * cmd)790 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
791 {
792 	int c;
793 	int src_fd;
794 	int dst_fd;
795 	int open_flags = 0;
796 	bool mmap_source_file = false;
797 	bool use_sendfile = false;
798 	ssize_t ret;
799 
800 	while ((c = getopt(argc, argv, "dms")) != -1) {
801 		switch (c) {
802 		case 'd':
803 			open_flags |= O_DIRECT;
804 			break;
805 		case 'm':
806 			mmap_source_file = true;
807 			break;
808 		case 's':
809 			use_sendfile = true;
810 			break;
811 		default:
812 			fputs(cmd->cmd_help, stderr);
813 			exit(2);
814 		}
815 	}
816 	argc -= optind;
817 	argv += optind;
818 	if (argc != 2) {
819 		fputs("Wrong number of arguments\n\n", stderr);
820 		fputs(cmd->cmd_help, stderr);
821 		exit(2);
822 	}
823 	if (mmap_source_file && use_sendfile)
824 		die("-m and -s are mutually exclusive");
825 
826 	src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
827 	dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
828 
829 	if (mmap_source_file) {
830 		struct stat stbuf;
831 		void *src_addr;
832 
833 		if (fstat(src_fd, &stbuf) != 0)
834 			die_errno("fstat of source file failed");
835 
836 		if ((size_t)stbuf.st_size != stbuf.st_size)
837 			die("Source file is too large");
838 
839 		src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
840 				src_fd, 0);
841 		if (src_addr == MAP_FAILED)
842 			die("mmap of source file failed");
843 
844 		full_write(dst_fd, src_addr, stbuf.st_size);
845 
846 		munmap(src_addr, stbuf.st_size);
847 	} else if (use_sendfile) {
848 		while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
849 			;
850 		if (ret < 0)
851 			die_errno("sendfile failed");
852 	} else {
853 		char *buf = aligned_xalloc(4096, 4096);
854 
855 		while ((ret = xread(src_fd, buf, 4096)) > 0)
856 			full_write(dst_fd, buf, ret);
857 		free(buf);
858 	}
859 	close(src_fd);
860 	close(dst_fd);
861 }
862 
863 #define get_cblocks_desc "get number of reserved blocks on compress inode"
864 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
865 
do_get_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)866 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
867 {
868 	unsigned long long blkcnt;
869 	int ret, fd;
870 
871 	if (argc != 2) {
872 		fputs("Excess arguments\n\n", stderr);
873 		fputs(cmd->cmd_help, stderr);
874 		exit(1);
875 	}
876 
877 	fd = xopen(argv[1], O_RDONLY, 0);
878 
879 	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
880 	if (ret < 0)
881 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
882 
883 	printf("%llu\n", blkcnt);
884 
885 	exit(0);
886 }
887 
888 #define release_cblocks_desc "release reserved blocks on compress inode"
889 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
890 
do_release_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)891 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
892 {
893 	unsigned long long blkcnt;
894 	int ret, fd;
895 
896 	if (argc != 2) {
897 		fputs("Excess arguments\n\n", stderr);
898 		fputs(cmd->cmd_help, stderr);
899 		exit(1);
900 	}
901 
902 	fd = xopen(argv[1], O_RDONLY, 0);
903 
904 	ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
905 	if (ret < 0)
906 		die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
907 
908 	printf("%llu\n", blkcnt);
909 
910 	exit(0);
911 }
912 
913 #define reserve_cblocks_desc "reserve blocks on compress inode"
914 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
915 
do_reserve_cblocks(int argc,char ** argv,const struct cmd_desc * cmd)916 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
917 {
918 	unsigned long long blkcnt;
919 	int ret, fd;
920 
921 	if (argc != 2) {
922 		fputs("Excess arguments\n\n", stderr);
923 		fputs(cmd->cmd_help, stderr);
924 		exit(1);
925 	}
926 
927 	fd = xopen(argv[1], O_RDONLY, 0);
928 
929 	ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
930 	if (ret < 0)
931 		die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
932 
933 	printf("%llu\n", blkcnt);
934 
935 	exit(0);
936 }
937 
938 
939 #define CMD_HIDDEN 	0x0001
940 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
941 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
942 
943 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
944 const struct cmd_desc cmd_list[] = {
945 	_CMD(help),
946 	CMD(fsync),
947 	CMD(set_verity),
948 	CMD(getflags),
949 	CMD(setflags),
950 	CMD(shutdown),
951 	CMD(pinfile),
952 	CMD(fallocate),
953 	CMD(write),
954 	CMD(read),
955 	CMD(randread),
956 	CMD(fiemap),
957 	CMD(gc_urgent),
958 	CMD(defrag_file),
959 	CMD(copy),
960 	CMD(get_cblocks),
961 	CMD(release_cblocks),
962 	CMD(reserve_cblocks),
963 	{ NULL, NULL, NULL, NULL, 0 }
964 };
965 
do_help(int argc,char ** argv,const struct cmd_desc * UNUSED (cmd))966 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
967 {
968 	const struct cmd_desc *p;
969 
970 	if (argc > 1) {
971 		for (p = cmd_list; p->cmd_name; p++) {
972 			if (p->cmd_flags & CMD_HIDDEN)
973 				continue;
974 			if (strcmp(p->cmd_name, argv[1]) == 0) {
975 				putc('\n', stdout);
976 				fputs("USAGE:\n  ", stdout);
977 				fputs(p->cmd_help, stdout);
978 				exit(0);
979 			}
980 		}
981 		printf("Unknown command: %s\n\n", argv[1]);
982 	}
983 
984 	fputs("Available commands:\n", stdout);
985 	for (p = cmd_list; p->cmd_name; p++) {
986 		if (p->cmd_flags & CMD_HIDDEN)
987 			continue;
988 		printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
989 	}
990 	printf("\nTo get more information on a command, "
991 	       "type 'f2fs_io help cmd'\n");
992 	exit(0);
993 }
994 
die_signal_handler(int UNUSED (signum),siginfo_t * UNUSED (siginfo),void * UNUSED (context))995 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
996 				void *UNUSED(context))
997 {
998 	exit(-1);
999 }
1000 
sigcatcher_setup(void)1001 static void sigcatcher_setup(void)
1002 {
1003 	struct sigaction	sa;
1004 
1005 	memset(&sa, 0, sizeof(struct sigaction));
1006 	sa.sa_sigaction = die_signal_handler;
1007 	sa.sa_flags = SA_SIGINFO;
1008 
1009 	sigaction(SIGHUP, &sa, 0);
1010 	sigaction(SIGINT, &sa, 0);
1011 	sigaction(SIGQUIT, &sa, 0);
1012 	sigaction(SIGFPE, &sa, 0);
1013 	sigaction(SIGILL, &sa, 0);
1014 	sigaction(SIGBUS, &sa, 0);
1015 	sigaction(SIGSEGV, &sa, 0);
1016 	sigaction(SIGABRT, &sa, 0);
1017 	sigaction(SIGPIPE, &sa, 0);
1018 	sigaction(SIGALRM, &sa, 0);
1019 	sigaction(SIGTERM, &sa, 0);
1020 	sigaction(SIGUSR1, &sa, 0);
1021 	sigaction(SIGUSR2, &sa, 0);
1022 	sigaction(SIGPOLL, &sa, 0);
1023 	sigaction(SIGPROF, &sa, 0);
1024 	sigaction(SIGSYS, &sa, 0);
1025 	sigaction(SIGTRAP, &sa, 0);
1026 	sigaction(SIGVTALRM, &sa, 0);
1027 	sigaction(SIGXCPU, &sa, 0);
1028 	sigaction(SIGXFSZ, &sa, 0);
1029 }
1030 
main(int argc,char ** argv)1031 int main(int argc, char **argv)
1032 {
1033 	const struct cmd_desc *cmd;
1034 
1035 	if (argc < 2)
1036 		do_help(argc, argv, cmd_list);
1037 
1038 	sigcatcher_setup();
1039 	for (cmd = cmd_list; cmd->cmd_name; cmd++) {
1040 		if (strcmp(cmd->cmd_name, argv[1]) == 0) {
1041 			cmd->cmd_func(argc - 1, argv + 1, cmd);
1042 			exit(0);
1043 		}
1044 	}
1045 	printf("Unknown command: %s\n\n", argv[1]);
1046 	do_help(1, argv, cmd_list);
1047 	return 0;
1048 }
1049