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