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