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