2 * f2fs_io.c - f2fs ioctl utility
4 * Author: Jaegeuk Kim <jaegeuk@kernel.org>
6 * Copied portion of the code from ../f2fscrypt.c
12 #ifndef _LARGEFILE_SOURCE
13 #define _LARGEFILE_SOURCE
15 #ifndef _LARGEFILE64_SOURCE
16 #define _LARGEFILE64_SOURCE
21 #ifndef __SANE_USERSPACE_TYPES__
22 #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
38 #include <sys/sendfile.h>
40 #include <sys/types.h>
48 #include <android_config.h>
54 void (*cmd_func)(int, char **, const struct cmd_desc *);
60 static void __attribute__((noreturn))
61 do_die(const char *format, va_list va, int err)
63 vfprintf(stderr, format, va);
65 fprintf(stderr, ": %s", strerror(err));
70 static void __attribute__((noreturn, format(printf, 1, 2)))
71 die_errno(const char *format, ...)
76 do_die(format, va, errno);
80 static void __attribute__((noreturn, format(printf, 1, 2)))
81 die(const char *format, ...)
86 do_die(format, va, 0);
90 static void *xmalloc(size_t size)
92 void *p = malloc(size);
95 die("Memory alloc failed (requested %zu bytes)", size);
99 static void *aligned_xalloc(size_t alignment, size_t size)
101 void *p = aligned_alloc(alignment, size);
104 die("Memory alloc failed (requested %zu bytes)", size);
108 static int xopen(const char *pathname, int flags, mode_t mode)
110 int fd = open(pathname, flags, mode);
113 die_errno("Failed to open %s", pathname);
117 static ssize_t xread(int fd, void *buf, size_t count)
119 ssize_t ret = read(fd, buf, count);
122 die_errno("read failed");
126 static void full_write(int fd, const void *buf, size_t count)
129 ssize_t ret = write(fd, buf, count);
132 die_errno("write failed");
133 buf = (char *)buf + ret;
138 #ifdef HAVE_MACH_TIME_H
139 static u64 get_current_us()
141 return mach_absolute_time() / 1000;
143 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME)
144 static u64 get_current_us()
147 t.tv_sec = t.tv_nsec = 0;
148 clock_gettime(CLOCK_BOOTTIME, &t);
149 return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000;
152 static u64 get_current_us()
158 #define fsync_desc "fsync"
160 "f2fs_io fsync [file]\n\n" \
161 "fsync given the file\n" \
163 static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd)
168 fputs("Excess arguments\n\n", stderr);
169 fputs(cmd->cmd_help, stderr);
173 fd = xopen(argv[1], O_WRONLY, 0);
176 die_errno("fsync failed");
178 printf("fsync a file\n");
182 #define set_verity_desc "Set fs-verity"
183 #define set_verity_help \
184 "f2fs_io set_verity [file]\n\n" \
185 "Set fsverity bit given a file\n" \
187 static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd)
192 fputs("Excess arguments\n\n", stderr);
193 fputs(cmd->cmd_help, stderr);
197 fd = open(argv[1], O_RDWR);
199 ret = ioctl(fd, FS_IOC_ENABLE_VERITY);
201 perror("FS_IOC_ENABLE_VERITY");
205 printf("Set fsverity bit to %s\n", argv[1]);
209 #define getflags_desc "getflags ioctl"
210 #define getflags_help \
211 "f2fs_io getflags [file]\n\n" \
212 "get a flag given the file\n" \
223 static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd)
230 fputs("Excess arguments\n\n", stderr);
231 fputs(cmd->cmd_help, stderr);
235 fd = xopen(argv[1], O_RDONLY, 0);
237 ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
238 printf("get a flag on %s ret=%d, flags=", argv[1], ret);
239 if (flag & FS_CASEFOLD_FL) {
243 if (flag & FS_COMPR_FL) {
246 printf("compression");
249 if (flag & FS_NOCOMP_FL) {
252 printf("nocompression");
255 if (flag & FS_ENCRYPT_FL) {
261 if (flag & FS_VERITY_FL) {
267 if (flag & FS_INLINE_DATA_FL) {
270 printf("inline_data");
273 if (flag & FS_NOCOW_FL) {
276 printf("nocow(pinned)");
279 if (flag & FS_IMMUTABLE_FL) {
291 #define setflags_desc "setflags ioctl"
292 #define setflags_help \
293 "f2fs_io setflags [flag] [file]\n\n" \
294 "set a flag given the file\n" \
301 static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd)
307 fputs("Excess arguments\n\n", stderr);
308 fputs(cmd->cmd_help, stderr);
312 fd = xopen(argv[2], O_RDONLY, 0);
314 ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag);
315 printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag);
317 die_errno("F2FS_IOC_GETFLAGS failed");
319 if (!strcmp(argv[1], "casefold"))
320 flag |= FS_CASEFOLD_FL;
321 else if (!strcmp(argv[1], "compression"))
323 else if (!strcmp(argv[1], "nocompression"))
324 flag |= FS_NOCOMP_FL;
325 else if (!strcmp(argv[1], "noimmutable"))
326 flag &= ~FS_IMMUTABLE_FL;
328 ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag);
329 printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]);
333 #define shutdown_desc "shutdown filesystem"
334 #define shutdown_help \
335 "f2fs_io shutdown [level] [dir]\n\n" \
336 "Freeze and stop all IOs given mount point\n" \
338 " 0 : going down with full sync\n" \
339 " 1 : going down with checkpoint only\n" \
340 " 2 : going down with no sync\n" \
341 " 3 : going down with metadata flush\n" \
342 " 4 : going down with fsck mark\n"
344 static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd)
350 fputs("Excess arguments\n\n", stderr);
351 fputs(cmd->cmd_help, stderr);
355 flag = atoi(argv[1]);
356 if (flag >= F2FS_GOING_DOWN_MAX) {
357 fputs("Wrong level\n\n", stderr);
358 fputs(cmd->cmd_help, stderr);
361 fd = xopen(argv[2], O_RDONLY, 0);
363 ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
365 die_errno("F2FS_IOC_SHUTDOWN failed");
367 printf("Shutdown %s with level=%d\n", argv[2], flag);
371 #define pinfile_desc "pin file control"
372 #define pinfile_help \
373 "f2fs_io pinfile [get|set] [file]\n\n" \
374 "get/set pinning given the file\n" \
376 static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd)
382 fputs("Excess arguments\n\n", stderr);
383 fputs(cmd->cmd_help, stderr);
387 fd = xopen(argv[2], O_RDONLY, 0);
390 if (!strcmp(argv[1], "set")) {
392 ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin);
394 die_errno("F2FS_IOC_SET_PIN_FILE failed");
395 printf("set_pin_file: %u blocks moved in %s\n", ret, argv[2]);
396 } else if (!strcmp(argv[1], "get")) {
399 ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin);
401 die_errno("F2FS_IOC_GET_PIN_FILE failed");
403 ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags);
405 die_errno("F2FS_IOC_GETFLAGS failed");
407 printf("get_pin_file: %s with %u blocks moved in %s\n",
408 (flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned",
414 #define fallocate_desc "fallocate"
415 #define fallocate_help \
416 "f2fs_io fallocate [keep_size] [offset] [length] [file]\n\n" \
417 "fallocate given the file\n" \
418 " [keep_size] : 1 or 0\n" \
420 static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd)
423 off_t offset, length;
428 fputs("Excess arguments\n\n", stderr);
429 fputs(cmd->cmd_help, stderr);
433 if (!strcmp(argv[1], "1"))
434 mode |= FALLOC_FL_KEEP_SIZE;
436 offset = atoi(argv[2]);
437 length = atoll(argv[3]);
439 fd = xopen(argv[4], O_RDWR, 0);
441 if (fallocate(fd, mode, offset, length) != 0)
442 die_errno("fallocate failed");
444 if (fstat(fd, &sb) != 0)
445 die_errno("fstat failed");
447 printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks);
451 #define erase_desc "erase a block device"
453 "f2fs_io erase [block_device_path]\n\n" \
454 "Send DISCARD | BLKSECDISCARD comamnd to" \
455 "block device in block_device_path\n" \
457 static void do_erase(int argc, char **argv, const struct cmd_desc *cmd)
464 fputs("Excess arguments\n\n", stderr);
465 fputs(cmd->cmd_help, stderr);
469 if (stat(argv[1], &st) != 0) {
470 fputs("stat error\n", stderr);
474 if (!S_ISBLK(st.st_mode)) {
475 fputs(argv[1], stderr);
476 fputs(" is not a block device\n", stderr);
480 fd = xopen(argv[1], O_WRONLY, 0);
483 ret = ioctl(fd, BLKGETSIZE64, &range[1]);
485 fputs("get size failed\n", stderr);
489 ret = ioctl(fd, BLKSECDISCARD, &range);
491 ret = ioctl(fd, BLKDISCARD, &range);
493 fputs("Discard failed\n", stderr);
501 #define write_desc "write data into file"
503 "f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path] {delay}\n\n" \
504 "Write given patten data in file_path\n" \
507 " inc_num : incrementing numbers\n" \
508 " rand : random numbers\n" \
510 " buffered : buffered IO\n" \
511 " dio : O_DIRECT\n" \
512 " dsync : O_DIRECT | O_DSYNC\n" \
513 " osync : O_SYNC\n" \
514 " atomic_commit : atomic write & commit\n" \
515 " atomic_abort : atomic write & abort\n" \
516 " atomic_rcommit: atomic replace & commit\n" \
517 " atomic_rabort : atomic replace & abort\n" \
518 "{delay} is in ms unit and optional only for atomic operations\n"
520 static void do_write(int argc, char **argv, const struct cmd_desc *cmd)
522 u64 buf_size = 0, inc_num = 0, written = 0;
525 unsigned bs, count, i;
528 u64 total_time = 0, max_time = 0, max_time_t = 0;
529 bool atomic_commit = false, atomic_abort = false, replace = false;
534 if (argc < 7 || argc > 8) {
535 fputs("Excess arguments\n\n", stderr);
536 fputs(cmd->cmd_help, stderr);
542 die("Too big chunk size - limit: 4MB");
544 buf_size = bs * 4096;
546 offset = atoi(argv[2]) * buf_size;
548 buf = aligned_xalloc(4096, buf_size);
549 count = atoi(argv[3]);
551 if (!strcmp(argv[4], "zero"))
552 memset(buf, 0, buf_size);
553 else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand"))
554 die("Wrong pattern type");
556 if (!strcmp(argv[5], "dio")) {
558 } else if (!strcmp(argv[5], "dsync")) {
559 flags |= O_DIRECT | O_DSYNC;
560 } else if (!strcmp(argv[5], "osync")) {
562 } else if (!strcmp(argv[5], "atomic_commit")) {
563 atomic_commit = true;
564 } else if (!strcmp(argv[5], "atomic_abort")) {
566 } else if (!strcmp(argv[5], "atomic_rcommit")) {
567 atomic_commit = true;
569 } else if (!strcmp(argv[5], "atomic_rabort")) {
572 } else if (strcmp(argv[5], "buffered")) {
573 die("Wrong IO type");
576 fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755);
578 if (atomic_commit || atomic_abort) {
582 useconds = atoi(argv[7]) * 1000;
585 ret = ioctl(fd, F2FS_IOC_START_ATOMIC_REPLACE);
587 ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
590 fputs("setting atomic file mode failed\n", stderr);
595 total_time = get_current_us();
596 for (i = 0; i < count; i++) {
599 if (!strcmp(argv[4], "inc_num"))
600 *(int *)buf = inc_num++;
601 else if (!strcmp(argv[4], "rand"))
602 *(int *)buf = rand();
605 max_time_t = get_current_us();
606 ret = pwrite(fd, buf, buf_size, offset + buf_size * i);
607 max_time_t = get_current_us() - max_time_t;
608 if (max_time < max_time_t)
609 max_time = max_time_t;
621 ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
623 fputs("committing atomic write failed\n", stderr);
626 } else if (atomic_abort) {
629 ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
631 fputs("aborting atomic write failed\n", stderr);
636 printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n",
638 get_current_us() - total_time,
643 #define read_desc "read data from file"
645 "f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\n\n" \
646 "Read data in file_path and print nbytes\n" \
648 " buffered : buffered IO\n" \
649 " dio : direct IO\n" \
650 " mmap : mmap IO\n" \
652 static void do_read(int argc, char **argv, const struct cmd_desc *cmd)
654 u64 buf_size = 0, ret = 0, read_cnt = 0;
658 char *print_buf = NULL;
659 unsigned bs, count, i, print_bytes;
665 fputs("Excess arguments\n\n", stderr);
666 fputs(cmd->cmd_help, stderr);
672 die("Too big chunk size - limit: 4MB");
673 buf_size = bs * 4096;
675 offset = atoi(argv[2]) * buf_size;
677 buf = aligned_xalloc(4096, buf_size);
679 count = atoi(argv[3]);
680 if (!strcmp(argv[4], "dio"))
682 else if (!strcmp(argv[4], "mmap"))
684 else if (strcmp(argv[4], "buffered"))
685 die("Wrong IO type");
687 print_bytes = atoi(argv[5]);
688 if (print_bytes > buf_size)
689 die("Print_nbytes should be less then chunk_size in kb");
691 print_buf = xmalloc(print_bytes);
693 fd = xopen(argv[6], O_RDONLY | flags, 0);
696 data = mmap(NULL, count * buf_size, PROT_READ,
697 MAP_SHARED, fd, offset);
698 if (data == MAP_FAILED)
702 for (i = 0; i < count; i++) {
704 memcpy(buf, data + offset + buf_size * i, buf_size);
707 ret = pread(fd, buf, buf_size, offset + buf_size * i);
714 memcpy(print_buf, buf, print_bytes);
716 printf("Read %"PRIu64" bytes and print %u bytes:\n", read_cnt, print_bytes);
717 printf("%08"PRIx64" : ", offset);
718 for (i = 1; i <= print_bytes; i++) {
719 printf("%02x", print_buf[i - 1]);
721 printf("\n%08"PRIx64" : ", offset + 16 * i);
729 #define randread_desc "random read data from file"
730 #define randread_help \
731 "f2fs_io randread [chunk_size in 4kb] [count] [IO] [file_path]\n\n" \
732 "Do random read data in file_path\n" \
734 " buffered : buffered IO\n" \
735 " dio : direct IO\n" \
737 static void do_randread(int argc, char **argv, const struct cmd_desc *cmd)
739 u64 buf_size = 0, ret = 0, read_cnt = 0;
740 u64 idx, end_idx, aligned_size;
742 unsigned bs, count, i;
749 fputs("Excess arguments\n\n", stderr);
750 fputs(cmd->cmd_help, stderr);
756 die("Too big chunk size - limit: 4MB");
757 buf_size = bs * 4096;
759 buf = aligned_xalloc(4096, buf_size);
761 count = atoi(argv[2]);
762 if (!strcmp(argv[3], "dio"))
764 else if (strcmp(argv[3], "buffered"))
765 die("Wrong IO type");
767 fd = xopen(argv[4], O_RDONLY | flags, 0);
769 if (fstat(fd, &stbuf) != 0)
770 die_errno("fstat of source file failed");
772 aligned_size = (u64)stbuf.st_size & ~((u64)(4096 - 1));
773 if (aligned_size < buf_size)
774 die("File is too small to random read");
775 end_idx = (u64)(aligned_size - buf_size) / (u64)4096 + 1;
777 srand((unsigned) time(&t));
779 for (i = 0; i < count; i++) {
780 idx = rand() % end_idx;
782 ret = pread(fd, buf, buf_size, 4096 * idx);
788 printf("Read %"PRIu64" bytes\n", read_cnt);
792 #define fiemap_desc "get block address in file"
793 #define fiemap_help \
794 "f2fs_io fiemap [offset in 4kb] [count] [file_path]\n\n"\
796 #if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H)
797 static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd)
800 int fd, extents_mem_size;
803 struct fiemap *fm = xmalloc(sizeof(struct fiemap));
806 fputs("Excess arguments\n\n", stderr);
807 fputs(cmd->cmd_help, stderr);
811 memset(fm, 0, sizeof(struct fiemap));
812 start = atoi(argv[1]) * F2FS_BLKSIZE;
813 length = atoi(argv[2]) * F2FS_BLKSIZE;
814 fm->fm_start = start;
815 fm->fm_length = length;
817 fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0);
819 printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n",
820 start / F2FS_BLKSIZE, length / F2FS_BLKSIZE);
821 if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
822 die_errno("FIEMAP failed");
824 mapped_extents = fm->fm_mapped_extents;
825 extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents;
827 fm = xmalloc(sizeof(struct fiemap) + extents_mem_size);
829 memset(fm, 0, sizeof(struct fiemap) + extents_mem_size);
830 fm->fm_start = start;
831 fm->fm_length = length;
832 fm->fm_extent_count = mapped_extents;
834 if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0)
835 die_errno("FIEMAP failed");
837 printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags");
838 for (i = 0; i < fm->fm_mapped_extents; i++) {
839 printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i,
840 fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical,
841 fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags);
843 if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST)
851 static void do_fiemap(int UNUSED(argc), char **UNUSED(argv),
852 const struct cmd_desc *UNUSED(cmd))
854 die("Not support for this platform");
858 #define gc_urgent_desc "start/end/run gc_urgent for given time period"
859 #define gc_urgent_help \
860 "f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\
861 " - f2fs_io gc_urgent sda21 start\n" \
862 " - f2fs_io gc_urgent sda21 end\n" \
863 " - f2fs_io gc_urgent sda21 run 10\n" \
865 static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd)
869 if (argc == 3 && !strcmp(argv[2], "start")) {
870 printf("gc_urgent: start on %s\n", argv[1]);
871 sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
874 } else if (argc == 3 && !strcmp(argv[2], "end")) {
875 printf("gc_urgent: end on %s\n", argv[1]);
876 sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
879 } else if (argc == 4 && !strcmp(argv[2], "run")) {
880 printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3]));
881 sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]);
884 sleep(atoi(argv[3]));
885 printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3]));
886 sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]);
890 fputs("Excess arguments\n\n", stderr);
891 fputs(cmd->cmd_help, stderr);
896 #define defrag_file_desc "do defragment on file"
897 #define defrag_file_help \
898 "f2fs_io defrag_file [start] [length] [file_path]\n\n" \
899 " start : start offset of defragment region, unit: bytes\n" \
900 " length : bytes number of defragment region\n" \
902 static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd)
904 struct f2fs_defragment df;
909 fputs("Excess arguments\n\n", stderr);
910 fputs(cmd->cmd_help, stderr);
914 df.start = atoll(argv[1]);
915 df.len = len = atoll(argv[2]);
917 fd = xopen(argv[3], O_RDWR, 0);
919 ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df);
921 die_errno("F2FS_IOC_DEFRAGMENT failed");
923 printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n",
924 argv[3], df.start, df.start + len);
928 #define copy_desc "copy a file"
930 "f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n" \
931 " src_path : path to source file\n" \
932 " dst_path : path to destination file\n" \
933 " -d : use direct I/O\n" \
934 " -m : mmap the source file\n" \
935 " -s : use sendfile\n" \
937 static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
943 bool mmap_source_file = false;
944 bool use_sendfile = false;
947 while ((c = getopt(argc, argv, "dms")) != -1) {
950 open_flags |= O_DIRECT;
953 mmap_source_file = true;
959 fputs(cmd->cmd_help, stderr);
966 fputs("Wrong number of arguments\n\n", stderr);
967 fputs(cmd->cmd_help, stderr);
970 if (mmap_source_file && use_sendfile)
971 die("-m and -s are mutually exclusive");
973 src_fd = xopen(argv[0], O_RDONLY | open_flags, 0);
974 dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644);
976 if (mmap_source_file) {
980 if (fstat(src_fd, &stbuf) != 0)
981 die_errno("fstat of source file failed");
983 if ((size_t)stbuf.st_size != stbuf.st_size)
984 die("Source file is too large");
986 src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED,
988 if (src_addr == MAP_FAILED)
989 die("mmap of source file failed");
991 full_write(dst_fd, src_addr, stbuf.st_size);
993 munmap(src_addr, stbuf.st_size);
994 } else if (use_sendfile) {
995 while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0)
998 die_errno("sendfile failed");
1000 char *buf = aligned_xalloc(4096, 4096);
1002 while ((ret = xread(src_fd, buf, 4096)) > 0)
1003 full_write(dst_fd, buf, ret);
1010 #define get_cblocks_desc "get number of reserved blocks on compress inode"
1011 #define get_cblocks_help "f2fs_io get_cblocks [file]\n\n"
1013 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1015 unsigned long long blkcnt;
1019 fputs("Excess arguments\n\n", stderr);
1020 fputs(cmd->cmd_help, stderr);
1024 fd = xopen(argv[1], O_RDONLY, 0);
1026 ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
1028 die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
1030 printf("%llu\n", blkcnt);
1035 #define release_cblocks_desc "release reserved blocks on compress inode"
1036 #define release_cblocks_help "f2fs_io release_cblocks [file]\n\n"
1038 static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1040 unsigned long long blkcnt;
1044 fputs("Excess arguments\n\n", stderr);
1045 fputs(cmd->cmd_help, stderr);
1049 fd = xopen(argv[1], O_RDONLY, 0);
1051 ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt);
1053 die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed");
1055 printf("%llu\n", blkcnt);
1060 #define reserve_cblocks_desc "reserve blocks on compress inode"
1061 #define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n"
1063 static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
1065 unsigned long long blkcnt;
1069 fputs("Excess arguments\n\n", stderr);
1070 fputs(cmd->cmd_help, stderr);
1074 fd = xopen(argv[1], O_RDONLY, 0);
1076 ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt);
1078 die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed");
1080 printf("%llu\n", blkcnt);
1085 #define get_coption_desc "get compression option of a compressed file"
1086 #define get_coption_help \
1087 "f2fs_io get_coption [file]\n\n" \
1088 " algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \
1089 " log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1091 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
1093 struct f2fs_comp_option option;
1097 fputs("Excess arguments\n\n", stderr);
1098 fputs(cmd->cmd_help, stderr);
1102 fd = xopen(argv[1], O_RDONLY, 0);
1104 ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
1106 die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
1108 printf("compression algorithm:%u\n", option.algorithm);
1109 printf("compression cluster log size:%u\n", option.log_cluster_size);
1114 #define set_coption_desc "set compression option of a compressed file"
1115 #define set_coption_help \
1116 "f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n" \
1117 " algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \
1118 " log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"
1120 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
1122 struct f2fs_comp_option option;
1126 fputs("Excess arguments\n\n", stderr);
1127 fputs(cmd->cmd_help, stderr);
1131 option.algorithm = atoi(argv[1]);
1132 option.log_cluster_size = atoi(argv[2]);
1134 fd = xopen(argv[3], O_WRONLY, 0);
1136 ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
1138 die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
1140 printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
1141 option.algorithm, option.log_cluster_size);
1145 #define decompress_desc "decompress an already compressed file"
1146 #define decompress_help "f2fs_io decompress [file_path]\n\n"
1148 static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd)
1153 fputs("Excess arguments\n\n", stderr);
1154 fputs(cmd->cmd_help, stderr);
1158 fd = xopen(argv[1], O_WRONLY, 0);
1160 ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE);
1162 die_errno("F2FS_IOC_DECOMPRESS_FILE failed");
1167 #define compress_desc "compress a compression enabled file"
1168 #define compress_help "f2fs_io compress [file_path]\n\n"
1170 static void do_compress(int argc, char **argv, const struct cmd_desc *cmd)
1175 fputs("Excess arguments\n\n", stderr);
1176 fputs(cmd->cmd_help, stderr);
1180 fd = xopen(argv[1], O_WRONLY, 0);
1182 ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE);
1184 die_errno("F2FS_IOC_COMPRESS_FILE failed");
1189 #define get_filename_encrypt_mode_desc "get file name encrypt mode"
1190 #define get_filename_encrypt_mode_help \
1191 "f2fs_io filename_encrypt_mode [file or directory path]\n\n" \
1192 "Get the file name encription mode of the given file/directory.\n" \
1194 static void do_get_filename_encrypt_mode (int argc, char **argv,
1195 const struct cmd_desc *cmd)
1197 static const char *enc_name[] = {
1198 "invalid", /* FSCRYPT_MODE_INVALID (0) */
1199 "aes-256-xts", /* FSCRYPT_MODE_AES_256_XTS (1) */
1200 "aes-256-gcm", /* FSCRYPT_MODE_AES_256_GCM (2) */
1201 "aes-256-cbc", /* FSCRYPT_MODE_AES_256_CBC (3) */
1202 "aes-256-cts", /* FSCRYPT_MODE_AES_256_CTS (4) */
1203 "aes-128-cbc", /* FSCRYPT_MODE_AES_128_CBC (5) */
1204 "aes-128-cts", /* FSCRYPT_MODE_AES_128_CTS (6) */
1205 "speck128-256-xts", /* FSCRYPT_MODE_SPECK128_256_XTS (7) */
1206 "speck128-256-cts", /* FSCRYPT_MODE_SPECK128_256_CTS (8) */
1207 "adiantum", /* FSCRYPT_MODE_ADIANTUM (9) */
1208 "aes-256-hctr2", /* FSCRYPT_MODE_AES_256_HCTR2 (10) */
1211 struct fscrypt_get_policy_ex_arg arg;
1214 fputs("Excess arguments\n\n", stderr);
1215 fputs(cmd->cmd_help, stderr);
1219 fd = xopen(argv[1], O_RDONLY, 0);
1220 arg.policy_size = sizeof(arg.policy);
1221 ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg);
1222 if (ret != 0 && errno == ENOTTY)
1223 ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1);
1227 perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX");
1231 switch (arg.policy.version) {
1232 case FSCRYPT_POLICY_V1:
1233 mode = arg.policy.v1.filenames_encryption_mode;
1235 case FSCRYPT_POLICY_V2:
1236 mode = arg.policy.v2.filenames_encryption_mode;
1239 printf("Do not support policy version: %d\n",
1240 arg.policy.version);
1244 if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) {
1245 printf("Do not support algorithm: %d\n", mode);
1248 printf ("%s\n", enc_name[mode]);
1252 #define rename_desc "rename source to target file with fsync option"
1253 #define rename_help \
1254 "f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n" \
1255 "e.g., f2fs_io rename source dest 1\n" \
1256 " 1. open(source)\n" \
1257 " 2. rename(source, dest)\n" \
1258 " 3. fsync(source)\n" \
1259 " 4. close(source)\n"
1261 static void do_rename(int argc, char **argv, const struct cmd_desc *cmd)
1267 fputs("Excess arguments\n\n", stderr);
1268 fputs(cmd->cmd_help, stderr);
1273 fd = xopen(argv[1], O_WRONLY, 0);
1275 ret = rename(argv[1], argv[2]);
1277 die_errno("rename failed");
1281 die_errno("fsync failed: %s", argv[1]);
1287 #define gc_desc "trigger filesystem GC"
1288 #define gc_help "f2fs_io gc sync_mode [file_path]\n\n"
1290 static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
1296 fputs("Excess arguments\n\n", stderr);
1297 fputs(cmd->cmd_help, stderr);
1301 sync = atoi(argv[1]);
1303 fd = xopen(argv[2], O_RDONLY, 0);
1305 ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, &sync);
1307 die_errno("F2FS_IOC_GARBAGE_COLLECT failed");
1309 printf("trigger %s gc ret=%d\n",
1310 sync ? "synchronous" : "asynchronous", ret);
1314 #define checkpoint_desc "trigger filesystem checkpoint"
1315 #define checkpoint_help "f2fs_io checkpoint [file_path]\n\n"
1317 static void do_checkpoint(int argc, char **argv, const struct cmd_desc *cmd)
1322 fputs("Excess arguments\n\n", stderr);
1323 fputs(cmd->cmd_help, stderr);
1327 fd = xopen(argv[1], O_WRONLY, 0);
1329 ret = ioctl(fd, F2FS_IOC_WRITE_CHECKPOINT);
1331 die_errno("F2FS_IOC_WRITE_CHECKPOINT failed");
1333 printf("trigger filesystem checkpoint ret=%d\n", ret);
1337 #define precache_extents_desc "trigger precache extents"
1338 #define precache_extents_help "f2fs_io precache_extents [file_path]\n\n"
1340 static void do_precache_extents(int argc, char **argv, const struct cmd_desc *cmd)
1345 fputs("Excess arguments\n\n", stderr);
1346 fputs(cmd->cmd_help, stderr);
1350 fd = xopen(argv[1], O_WRONLY, 0);
1352 ret = ioctl(fd, F2FS_IOC_PRECACHE_EXTENTS);
1354 die_errno("F2FS_IOC_PRECACHE_EXTENTS failed");
1356 printf("trigger precache extents ret=%d\n", ret);
1360 #define move_range_desc "moving a range of data blocks from source file to destination file"
1361 #define move_range_help \
1362 "f2fs_io move_range [src_path] [dst_path] [src_start] [dst_start] " \
1364 " src_path : path to source file\n" \
1365 " dst_path : path to destination file\n" \
1366 " src_start : start offset of src file move region, unit: bytes\n" \
1367 " dst_start : start offset of dst file move region, unit: bytes\n" \
1368 " length : size to move\n" \
1370 static void do_move_range(int argc, char **argv, const struct cmd_desc *cmd)
1372 struct f2fs_move_range range;
1376 fputs("Excess arguments\n\n", stderr);
1377 fputs(cmd->cmd_help, stderr);
1381 fd = xopen(argv[1], O_RDWR, 0);
1382 range.dst_fd = xopen(argv[2], O_RDWR | O_CREAT, 0644);
1383 range.pos_in = atoi(argv[3]);
1384 range.pos_out = atoi(argv[4]);
1385 range.len = atoi(argv[5]);
1387 ret = ioctl(fd, F2FS_IOC_MOVE_RANGE, &range);
1389 die_errno("F2FS_IOC_MOVE_RANGE failed");
1391 printf("move range ret=%d\n", ret);
1395 #define CMD_HIDDEN 0x0001
1396 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
1397 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
1399 static void do_help(int argc, char **argv, const struct cmd_desc *cmd);
1400 const struct cmd_desc cmd_list[] = {
1418 CMD(release_cblocks),
1419 CMD(reserve_cblocks),
1424 CMD(get_filename_encrypt_mode),
1428 CMD(precache_extents),
1430 { NULL, NULL, NULL, NULL, 0 }
1433 static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd))
1435 const struct cmd_desc *p;
1438 for (p = cmd_list; p->cmd_name; p++) {
1439 if (p->cmd_flags & CMD_HIDDEN)
1441 if (strcmp(p->cmd_name, argv[1]) == 0) {
1443 fputs("USAGE:\n ", stdout);
1444 fputs(p->cmd_help, stdout);
1448 printf("Unknown command: %s\n\n", argv[1]);
1451 fputs("Available commands:\n", stdout);
1452 for (p = cmd_list; p->cmd_name; p++) {
1453 if (p->cmd_flags & CMD_HIDDEN)
1455 printf(" %-20s %s\n", p->cmd_name, p->cmd_desc);
1457 printf("\nTo get more information on a command, "
1458 "type 'f2fs_io help cmd'\n");
1462 static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo),
1463 void *UNUSED(context))
1468 static void sigcatcher_setup(void)
1470 struct sigaction sa;
1472 memset(&sa, 0, sizeof(struct sigaction));
1473 sa.sa_sigaction = die_signal_handler;
1474 sa.sa_flags = SA_SIGINFO;
1476 sigaction(SIGHUP, &sa, 0);
1477 sigaction(SIGINT, &sa, 0);
1478 sigaction(SIGQUIT, &sa, 0);
1479 sigaction(SIGFPE, &sa, 0);
1480 sigaction(SIGILL, &sa, 0);
1481 sigaction(SIGBUS, &sa, 0);
1482 sigaction(SIGSEGV, &sa, 0);
1483 sigaction(SIGABRT, &sa, 0);
1484 sigaction(SIGPIPE, &sa, 0);
1485 sigaction(SIGALRM, &sa, 0);
1486 sigaction(SIGTERM, &sa, 0);
1487 sigaction(SIGUSR1, &sa, 0);
1488 sigaction(SIGUSR2, &sa, 0);
1489 sigaction(SIGPOLL, &sa, 0);
1490 sigaction(SIGPROF, &sa, 0);
1491 sigaction(SIGSYS, &sa, 0);
1492 sigaction(SIGTRAP, &sa, 0);
1493 sigaction(SIGVTALRM, &sa, 0);
1494 sigaction(SIGXCPU, &sa, 0);
1495 sigaction(SIGXFSZ, &sa, 0);
1498 int main(int argc, char **argv)
1500 const struct cmd_desc *cmd;
1503 do_help(argc, argv, cmd_list);
1506 for (cmd = cmd_list; cmd->cmd_name; cmd++) {
1507 if (strcmp(cmd->cmd_name, argv[1]) == 0) {
1508 cmd->cmd_func(argc - 1, argv + 1, cmd);
1512 printf("Unknown command: %s\n\n", argv[1]);
1513 do_help(1, argv, cmd_list);