6 #include "log-writes.h"
25 static struct option long_options[] = {
26 {"next-flush", no_argument, NULL, 0},
27 {"next-fua", no_argument, NULL, 0},
28 {"start-entry", required_argument, NULL, 0},
29 {"end-mark", required_argument, NULL, 0},
30 {"log", required_argument, NULL, 0},
31 {"replay", required_argument, NULL, 0},
32 {"limit", required_argument, NULL, 0},
33 {"verbose", no_argument, NULL, 'v'},
34 {"find", no_argument, NULL, 0},
35 {"num-entries", no_argument, NULL, 0},
36 {"no-discard", no_argument, NULL, 0},
37 {"fsck", required_argument, NULL, 0},
38 {"check", required_argument, NULL, 0},
39 {"start-mark", required_argument, NULL, 0},
43 static void usage(void)
45 fprintf(stderr, "Usage: replay-log --log <logfile> [options]\n");
46 fprintf(stderr, "\t--replay <device> - replay onto a specific "
48 fprintf(stderr, "\t--limit <number> - number of entries to replay\n");
49 fprintf(stderr, "\t--next-flush - replay to/find the next flush\n");
50 fprintf(stderr, "\t--next-fua - replay to/find the next fua\n");
51 fprintf(stderr, "\t--start-entry <entry> - start at the given "
53 fprintf(stderr, "\t--start-mark <mark> - mark to start from\n");
54 fprintf(stderr, "\t--end-mark <mark> - replay to/find the given mark\n");
55 fprintf(stderr, "\t--find - put replay-log in find mode, will search "
56 "based on the other options\n");
57 fprintf(stderr, "\t--number-entries - print the number of entries in "
59 fprintf(stderr, "\t--no-discard - don't process discard entries\n");
60 fprintf(stderr, "\t--fsck - the fsck command to run, must specify "
62 fprintf(stderr, "\t--check [<number>|flush|fua] when to check the "
63 "file system, mush specify --fsck\n");
68 * Check if the log entry flag matches one of the stop_flags.
69 * If stop_flag has LOG_MARK, then looking also for match of
72 static int should_stop(struct log_write_entry *entry, u64 stop_flags,
75 u64 flags = le64_to_cpu(entry->flags);
76 int check_mark = (stop_flags & LOG_MARK_FLAG);
77 /* mark data begins after entry header */
78 char *buf = (char *)(entry + 1);
79 /* entry buffer is padded with at least 1 zero after data_len */
80 u64 buflen = le64_to_cpu(entry->data_len) + 1;
82 if (flags & stop_flags) {
85 if ((flags & LOG_MARK_FLAG) &&
86 !strncmp(mark, buf, buflen))
92 static int run_fsck(struct log *log, char *fsck_command)
94 int ret = fsync(log->replayfd);
97 ret = system(fsck_command);
99 ret = WEXITSTATUS(ret);
103 enum log_replay_check_mode {
109 static int seek_to_mark(struct log *log, struct log_write_entry *entry,
114 while ((ret = log_seek_next_entry(log, entry, 1)) == 0) {
115 if (should_stop(entry, LOG_MARK_FLAG, mark))
119 fprintf(stderr, "Couldn't find starting mark\n");
126 int main(int argc, char **argv)
128 char *logfile = NULL, *replayfile = NULL, *fsck_command = NULL;
129 struct log_write_entry *entry;
134 u64 check_number = 0;
135 char *end_mark = NULL, *start_mark = NULL;
142 int print_num_entries = 0;
144 enum log_replay_check_mode check_mode = 0;
146 while ((c = getopt_long(argc, argv, "v", long_options,
150 log_writes_verbose++;
158 stop_flags |= LOG_FLUSH_FLAG;
161 stop_flags |= LOG_FUA_FLAG;
164 start_entry = strtoull(optarg, &tmp, 0);
165 if (tmp && *tmp != '\0') {
166 fprintf(stderr, "Invalid entry number\n");
173 * Biggest sectorsize is 4k atm, so limit the mark to 4k
174 * minus the size of the entry. Say 4097 since we want
175 * an extra slot for \0.
177 start_mark = strndup(optarg, 4097 -
178 sizeof(struct log_write_entry));
180 fprintf(stderr, "Couldn't allocate memory\n");
186 * Biggest sectorsize is 4k atm, so limit the mark to 4k
187 * minus the size of the entry. Say 4097 since we want
188 * an extra slot for \0.
190 end_mark = strndup(optarg, 4097 -
191 sizeof(struct log_write_entry));
193 fprintf(stderr, "Couldn't allocate memory\n");
196 stop_flags |= LOG_MARK_FLAG;
199 logfile = strdup(optarg);
201 fprintf(stderr, "Couldn't allocate memory\n");
206 replayfile = strdup(optarg);
208 fprintf(stderr, "Couldn't allocate memory\n");
213 run_limit = strtoull(optarg, &tmp, 0);
214 if (tmp && *tmp != '\0') {
215 fprintf(stderr, "Invalid entry number\n");
224 print_num_entries = 1;
230 fsck_command = strdup(optarg);
232 fprintf(stderr, "Couldn't allocate memory\n");
237 if (!strcmp(optarg, "flush")) {
238 check_mode = CHECK_FLUSH;
239 } else if (!strcmp(optarg, "fua")) {
240 check_mode = CHECK_FUA;
242 check_mode = CHECK_NUMBER;
243 check_number = strtoull(optarg, &tmp, 0);
244 if (!check_number || (tmp && *tmp != '\0')) {
246 "Invalid entry number\n");
260 log = log_open(logfile, replayfile);
267 log->flags |= LOG_IGNORE_DISCARD;
269 entry = malloc(log->sectorsize);
271 fprintf(stderr, "Couldn't allocate buffer\n");
277 ret = seek_to_mark(log, entry, start_mark);
282 ret = log_seek_entry(log, start_entry);
287 if ((fsck_command && !check_mode) || (!fsck_command && check_mode))
290 /* We just want to find a given entry */
292 while ((ret = log_seek_next_entry(log, entry, 1)) == 0) {
294 if ((run_limit && num_entries == run_limit) ||
295 should_stop(entry, stop_flags, end_mark)) {
297 (unsigned long long)log->cur_entry - 1);
305 fprintf(stderr, "Couldn't find entry\n");
309 /* Used for scripts, just print the number of entries in the log */
310 if (print_num_entries) {
311 printf("%llu\n", (unsigned long long)log->nr_entries);
316 /* No replay, just spit out the log info. */
318 printf("Log version=%d, sectorsize=%lu, entries=%llu\n",
319 WRITE_LOG_VERSION, (unsigned long)log->sectorsize,
320 (unsigned long long)log->nr_entries);
325 while ((ret = log_replay_next_entry(log, entry, 1)) == 0) {
328 if ((check_mode == CHECK_NUMBER) &&
329 !(num_entries % check_number))
330 ret = run_fsck(log, fsck_command);
331 else if ((check_mode == CHECK_FUA) &&
332 should_stop(entry, LOG_FUA_FLAG, NULL))
333 ret = run_fsck(log, fsck_command);
334 else if ((check_mode == CHECK_FLUSH) &&
335 should_stop(entry, LOG_FLUSH_FLAG, NULL))
336 ret = run_fsck(log, fsck_command);
340 fprintf(stderr, "Fsck errored out on entry "
342 (unsigned long long)log->cur_entry - 1);
347 if ((run_limit && num_entries == run_limit) ||
348 should_stop(entry, stop_flags, end_mark))
351 fsync(log->replayfd);