ext4: test journal checkpoint ioctl
[xfstests-dev.git] / src / checkpoint_journal.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2021 Google
4  * All Rights Reserved.
5  *
6  * checkpoint_journal.c
7  *
8  * Flush journal log and checkpoint journal for ext4 file system and
9  * optionally, issue discard or zeroout for the journal log blocks.
10  *
11  * Arguments:
12  * 1) mount point for device
13  * 2) flags (optional)
14  *      set --erase=discard to enable discarding journal blocks
15  *      set --erase=zeroout to enable zero-filling journal blocks
16  *      set --dry-run flag to only perform input checking
17  */
18
19 #include <sys/ioctl.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <linux/fs.h>
27 #include <getopt.h>
28
29 #if !defined(EXT4_IOC_CHECKPOINT)
30 #define EXT4_IOC_CHECKPOINT     _IOW('f', 43, __u32)
31 #endif
32
33 #if !defined(EXT4_IOC_CHECKPOINT_FLAG_DISCARD)
34 #define EXT4_IOC_CHECKPOINT_FLAG_DISCARD                1
35 #define EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT                2
36 #define EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN                4
37 #endif
38
39 int main(int argc, char** argv) {
40         int fd, c, ret = 0, option_index = 0;
41         char* rpath;
42         unsigned int flags = 0;
43
44         static struct option long_options[] =
45         {
46                 {"dry-run", no_argument, 0, 'd'},
47                 {"erase", required_argument, 0, 'e'},
48                 {0, 0, 0, 0}
49         };
50
51         /* get optional flags */
52         while ((c = getopt_long(argc, argv, "de:", long_options,
53                                 &option_index)) != -1) {
54                 switch (c) {
55                 case 'd':
56                         flags |= EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN;
57                         break;
58                 case 'e':
59                         if (strcmp(optarg, "discard") == 0) {
60                                 flags |= EXT4_IOC_CHECKPOINT_FLAG_DISCARD;
61                         } else if (strcmp(optarg, "zeroout") == 0) {
62                                 flags |= EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT;
63                         } else {
64                                 fprintf(stderr, "Error: invalid erase option\n");
65                                 return 1;
66                         }
67                         break;
68                 default:
69                         return 1;
70                 }
71         }
72
73         if (optind != argc - 1) {
74                 fprintf(stderr, "Error: invalid number of arguments\n");
75                 return 1;
76         }
77
78         /* get fd to file system */
79         rpath = realpath(argv[optind], NULL);
80         fd = open(rpath, O_RDONLY);
81         free(rpath);
82
83         if (fd == -1) {
84                 fprintf(stderr, "Error: unable to open device %s: %s\n",
85                         argv[optind], strerror(errno));
86                 return 1;
87         }
88
89         ret = ioctl(fd, EXT4_IOC_CHECKPOINT, &flags);
90
91         if (ret)
92                 fprintf(stderr, "checkpoint ioctl returned error: %s\n", strerror(errno));
93
94         close(fd);
95         return ret;
96 }
97