| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (c) 2021 Google |
| * All Rights Reserved. |
| * |
| * checkpoint_journal.c |
| * |
| * Flush journal log and checkpoint journal for ext4 file system and |
| * optionally, issue discard or zeroout for the journal log blocks. |
| * |
| * Arguments: |
| * 1) mount point for device |
| * 2) flags (optional) |
| * set --erase=discard to enable discarding journal blocks |
| * set --erase=zeroout to enable zero-filling journal blocks |
| * set --dry-run flag to only perform input checking |
| */ |
| |
| #include <sys/ioctl.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <linux/fs.h> |
| #include <getopt.h> |
| |
| #if !defined(EXT4_IOC_CHECKPOINT) |
| #define EXT4_IOC_CHECKPOINT _IOW('f', 43, __u32) |
| #endif |
| |
| #if !defined(EXT4_IOC_CHECKPOINT_FLAG_DISCARD) |
| #define EXT4_IOC_CHECKPOINT_FLAG_DISCARD 1 |
| #define EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT 2 |
| #define EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN 4 |
| #endif |
| |
| int main(int argc, char** argv) { |
| int fd, c, ret = 0, option_index = 0; |
| char* rpath; |
| unsigned int flags = 0; |
| |
| static struct option long_options[] = |
| { |
| {"dry-run", no_argument, 0, 'd'}, |
| {"erase", required_argument, 0, 'e'}, |
| {0, 0, 0, 0} |
| }; |
| |
| /* get optional flags */ |
| while ((c = getopt_long(argc, argv, "de:", long_options, |
| &option_index)) != -1) { |
| switch (c) { |
| case 'd': |
| flags |= EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN; |
| break; |
| case 'e': |
| if (strcmp(optarg, "discard") == 0) { |
| flags |= EXT4_IOC_CHECKPOINT_FLAG_DISCARD; |
| } else if (strcmp(optarg, "zeroout") == 0) { |
| flags |= EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT; |
| } else { |
| fprintf(stderr, "Error: invalid erase option\n"); |
| return 1; |
| } |
| break; |
| default: |
| return 1; |
| } |
| } |
| |
| if (optind != argc - 1) { |
| fprintf(stderr, "Error: invalid number of arguments\n"); |
| return 1; |
| } |
| |
| /* get fd to file system */ |
| rpath = realpath(argv[optind], NULL); |
| fd = open(rpath, O_RDONLY); |
| free(rpath); |
| |
| if (fd == -1) { |
| fprintf(stderr, "Error: unable to open device %s: %s\n", |
| argv[optind], strerror(errno)); |
| return 1; |
| } |
| |
| ret = ioctl(fd, EXT4_IOC_CHECKPOINT, &flags); |
| |
| if (ret) |
| fprintf(stderr, "checkpoint ioctl returned error: %s\n", strerror(errno)); |
| |
| close(fd); |
| return ret; |
| } |
| |