1 // SPDX-License-Identifier: GPL-2.0
12 #include "log-writes.h"
14 int log_writes_verbose = 0;
17 * @log: the log to free.
19 * This will close any open fd's the log has and free up its memory.
21 void log_free(struct log *log)
23 if (log->replayfd >= 0)
30 static int discard_range(struct log *log, u64 start, u64 len)
32 u64 range[2] = { start, len };
34 if (ioctl(log->replayfd, BLKDISCARD, &range) < 0) {
35 if (log_writes_verbose)
36 printf("replay device doesn't support discard, "
37 "switching to writing zeros\n");
38 log->flags |= LOG_DISCARD_NOT_SUPP;
43 static int zero_range(struct log *log, u64 start, u64 len)
49 if (log->max_zero_size < len) {
50 if (log_writes_verbose)
51 printf("discard len %llu larger than max %llu\n",
52 (unsigned long long)len,
53 (unsigned long long)log->max_zero_size);
58 buf = malloc(bufsize);
62 fprintf(stderr, "Couldn't allocate zero buffer");
67 memset(buf, 0, bufsize);
72 ret = pwrite(log->replayfd, buf, bufsize, start);
74 fprintf(stderr, "Error zeroing file: %d\n", errno);
86 * @log: the log we are replaying.
87 * @entry: the discard entry.
89 * Discard the given length. If the device supports discard we will call that
90 * ioctl, otherwise we will write 0's to emulate discard. If the discard size
91 * is larger than log->max_zero_size then we will simply skip the zero'ing if
92 * the drive doesn't support discard.
94 int log_discard(struct log *log, struct log_write_entry *entry)
96 u64 start = le64_to_cpu(entry->sector) * log->sectorsize;
97 u64 size = le64_to_cpu(entry->nr_sectors) * log->sectorsize;
98 u64 max_chunk = 1 * 1024 * 1024 * 1024;
100 if (log->flags & LOG_IGNORE_DISCARD)
104 u64 len = size > max_chunk ? max_chunk : size;
108 * Do this check first in case it is our first discard, that way
109 * if we return EOPNOTSUPP we will fall back to the 0 method
112 if (!(log->flags & LOG_DISCARD_NOT_SUPP))
113 ret = discard_range(log, start, len);
114 if (log->flags & LOG_DISCARD_NOT_SUPP)
115 ret = zero_range(log, start, len);
124 #define DEFINE_LOG_FLAGS_STR_ENTRY(x) \
127 struct flags_to_str_entry {
130 } log_flags_table[] = {
131 DEFINE_LOG_FLAGS_STR_ENTRY(FLUSH),
132 DEFINE_LOG_FLAGS_STR_ENTRY(FUA),
133 DEFINE_LOG_FLAGS_STR_ENTRY(DISCARD),
134 DEFINE_LOG_FLAGS_STR_ENTRY(MARK),
135 DEFINE_LOG_FLAGS_STR_ENTRY(METADATA)
138 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
139 #define LOG_FLAGS_BUF_SIZE 128
141 * Convert numeric flags to human readable flags.
142 * @flags: numeric flags
143 * @buf: output buffer for human readable string.
144 * must have enough space (LOG_FLAGS_BUF_SIZE) to contain all
147 static void entry_flags_to_str(u64 flags, char *buf)
154 for (i = 0; i < ARRAY_SIZE(log_flags_table); i++) {
155 if (flags & log_flags_table[i].flags) {
157 strncat(buf, "|", LOG_FLAGS_BUF_SIZE);
159 strncat(buf, log_flags_table[i].str, LOG_FLAGS_BUF_SIZE);
160 flags &= ~log_flags_table[i].flags;
165 strncat(buf, "|", LOG_FLAGS_BUF_SIZE);
167 left_len = LOG_FLAGS_BUF_SIZE - strnlen(buf,
170 snprintf(buf + strnlen(buf, LOG_FLAGS_BUF_SIZE),
171 left_len, "UNKNOWN.0x%llx", flags);
174 strncpy(buf, "NONE", LOG_FLAGS_BUF_SIZE);
178 * @log: the log we are replaying.
179 * @entry: entry to be replayed.
181 * @return: 0 if we should replay the entry, > 0 if we should skip it.
183 * Should we skip the entry in our log or replay onto the replay device.
185 int log_should_skip(struct log *log, struct log_write_entry *entry)
187 u64 sector = le64_to_cpu(entry->sector);
188 u64 nr_sectors = le64_to_cpu(entry->nr_sectors);
192 if (sector + nr_sectors <= log->start_sector ||
193 sector > log->end_sector)
199 * @entry: entry to be replayed.
201 * @return: 1 if the entry is sane, 0 if it is invalid.
203 * Check if this is a sane log entry.
205 int log_entry_valid(struct log_write_entry *entry)
207 u64 flags = le64_to_cpu(entry->flags);
209 /* Suspect all zeroes entry */
210 if (!flags && !entry->nr_sectors)
212 /* Suspect non zero padded entry */
213 if (flags != LOG_MARK_FLAG && entry->data[0] != 0)
219 * @log: the log we are replaying.
220 * @entry: where we put the entry.
221 * @read_data: read the entry data as well, entry must be log->sectorsize sized
224 * @return: 0 if we replayed, 1 if we are at the end, -1 if there was an error.
226 * Replay the next entry in our log onto the replay device.
228 int log_replay_next_entry(struct log *log, struct log_write_entry *entry,
233 size_t read_size = read_data ? log->sectorsize :
234 sizeof(struct log_write_entry);
236 char flags_buf[LOG_FLAGS_BUF_SIZE];
241 if (log->cur_entry >= log->nr_entries)
244 ret = read(log->logfd, entry, read_size);
245 if (ret != read_size) {
246 fprintf(stderr, "Error reading entry: %d\n", errno);
249 if (!log_entry_valid(entry)) {
250 fprintf(stderr, "Malformed entry @%llu\n",
251 log->cur_pos / log->sectorsize);
256 size = le64_to_cpu(entry->nr_sectors) * log->sectorsize;
257 if (read_size < log->sectorsize) {
258 log->cur_pos = lseek(log->logfd,
259 log->sectorsize - sizeof(struct log_write_entry), SEEK_CUR);
260 if (log->cur_pos == (off_t)-1) {
261 fprintf(stderr, "Error seeking in log: %d\n", errno);
265 log->cur_pos += read_size;
268 flags = le64_to_cpu(entry->flags);
269 entry_flags_to_str(flags, flags_buf);
270 skip = log_should_skip(log, entry);
271 if (log_writes_verbose > 1 || (log_writes_verbose && !skip)) {
272 printf("%s %d@%llu: sector %llu, size %llu, flags 0x%llx(%s)\n",
273 skip ? "skipping" : "replaying",
274 (int)log->cur_entry - 1, log->cur_pos / log->sectorsize,
275 (unsigned long long)le64_to_cpu(entry->sector),
276 (unsigned long long)size,
277 (unsigned long long)flags, flags_buf);
282 if (flags & LOG_DISCARD_FLAG)
283 return log_discard(log, entry);
286 log->cur_pos = lseek(log->logfd, size, SEEK_CUR);
287 if (log->cur_pos == (off_t)-1) {
288 fprintf(stderr, "Error seeking in log: %d\n", errno);
296 fprintf(stderr, "Error allocating buffer %llu entry %llu\n", (unsigned long long)size, (unsigned long long)log->cur_entry - 1);
300 ret = read(log->logfd, buf, size);
302 fprintf(stderr, "Error reading data: %d\n", errno);
306 log->cur_pos += size;
308 offset = le64_to_cpu(entry->sector) * log->sectorsize;
309 ret = pwrite(log->replayfd, buf, size, offset);
312 fprintf(stderr, "Error writing data: %d\n", errno);
320 * @log: the log we are manipulating.
321 * @entry_num: the entry we want.
323 * Seek to the given entry in the log, starting at 0 and ending at
324 * log->nr_entries - 1.
326 int log_seek_entry(struct log *log, u64 entry_num)
330 if (entry_num >= log->nr_entries) {
331 fprintf(stderr, "Invalid entry number\n");
335 /* Skip the first sector containing the log super block */
336 log->cur_pos = lseek(log->logfd, log->sectorsize, SEEK_SET);
337 if (log->cur_pos == (off_t)-1) {
338 fprintf(stderr, "Error seeking in file: %d\n", errno);
343 for (i = 0; i < entry_num; i++) {
344 struct log_write_entry entry;
349 ret = read(log->logfd, &entry, sizeof(entry));
350 if (ret != sizeof(entry)) {
351 fprintf(stderr, "Error reading entry: %d\n", errno);
354 if (!log_entry_valid(&entry)) {
355 fprintf(stderr, "Malformed entry @%llu\n",
356 log->cur_pos / log->sectorsize);
359 if (log_writes_verbose > 1)
360 printf("seek entry %d@%llu: %llu, size %llu, flags 0x%llx\n",
361 (int)i, log->cur_pos / log->sectorsize,
362 (unsigned long long)le64_to_cpu(entry.sector),
363 (unsigned long long)le64_to_cpu(entry.nr_sectors),
364 (unsigned long long)le64_to_cpu(entry.flags));
365 flags = le64_to_cpu(entry.flags);
366 seek_size = log->sectorsize - sizeof(entry);
367 if (!(flags & LOG_DISCARD_FLAG))
368 seek_size += le64_to_cpu(entry.nr_sectors) *
370 log->cur_pos = lseek(log->logfd, seek_size, SEEK_CUR);
371 if (log->cur_pos == (off_t)-1) {
372 fprintf(stderr, "Error seeking in file: %d\n", errno);
382 * @log: the log we are manipulating.
383 * @entry: the entry we read.
384 * @read_data: read the extra data for the entry, your entry must be
385 * log->sectorsize large.
387 * @return: 1 if we hit the end of the log, 0 we got the next entry, < 0 if
388 * there was an error.
390 * Seek to the next entry in the log.
392 int log_seek_next_entry(struct log *log, struct log_write_entry *entry,
395 size_t read_size = read_data ? log->sectorsize :
396 sizeof(struct log_write_entry);
398 char flags_buf[LOG_FLAGS_BUF_SIZE];
401 if (log->cur_entry >= log->nr_entries)
404 ret = read(log->logfd, entry, read_size);
405 if (ret != read_size) {
406 fprintf(stderr, "Error reading entry: %d\n", errno);
409 if (!log_entry_valid(entry)) {
410 fprintf(stderr, "Malformed entry @%llu\n",
411 log->cur_pos / log->sectorsize);
416 if (read_size < log->sectorsize) {
417 log->cur_pos = lseek(log->logfd,
418 log->sectorsize - sizeof(struct log_write_entry), SEEK_CUR);
419 if (log->cur_pos == (off_t)-1) {
420 fprintf(stderr, "Error seeking in log: %d\n", errno);
424 log->cur_pos += read_size;
426 flags = le64_to_cpu(entry->flags);
427 entry_flags_to_str(flags, flags_buf);
428 if (log_writes_verbose > 1)
429 printf("seek entry %d@%llu: %llu, size %llu, flags 0x%llx(%s)\n",
430 (int)log->cur_entry - 1, log->cur_pos / log->sectorsize,
431 (unsigned long long)le64_to_cpu(entry->sector),
432 (unsigned long long)le64_to_cpu(entry->nr_sectors),
433 (unsigned long long)flags, flags_buf);
435 read_size = le64_to_cpu(entry->nr_sectors) * log->sectorsize;
436 if (!read_size || (flags & LOG_DISCARD_FLAG))
439 log->cur_pos = lseek(log->logfd, read_size, SEEK_CUR);
440 if (log->cur_pos == (off_t)-1) {
441 fprintf(stderr, "Error seeking in log: %d\n", errno);
449 * @logfile: the file that contains the write log.
450 * @replayfile: the file/device to replay onto, can be NULL.
452 * Opens a logfile and makes sure it is valid and returns a struct log.
454 struct log *log_open(char *logfile, char *replayfile)
457 struct log_write_super super;
460 log = malloc(sizeof(struct log));
462 fprintf(stderr, "Couldn't alloc log\n");
468 log->logfd = open(logfile, O_RDONLY);
469 if (log->logfd < 0) {
470 fprintf(stderr, "Couldn't open log %s: %d\n", logfile,
477 log->replayfd = open(replayfile, O_WRONLY);
478 if (log->replayfd < 0) {
479 fprintf(stderr, "Couldn't open replay file %s: %d\n",
486 ret = read(log->logfd, &super, sizeof(struct log_write_super));
487 if (ret < sizeof(struct log_write_super)) {
488 fprintf(stderr, "Error reading super: %d\n", errno);
493 if (le64_to_cpu(super.magic) != WRITE_LOG_MAGIC) {
494 fprintf(stderr, "Magic doesn't match\n");
499 if (le64_to_cpu(super.version) != WRITE_LOG_VERSION) {
500 fprintf(stderr, "Version mismatch, wanted %d, have %d\n",
501 WRITE_LOG_VERSION, (int)le64_to_cpu(super.version));
506 log->sectorsize = le32_to_cpu(super.sectorsize);
507 log->nr_entries = le64_to_cpu(super.nr_entries);
508 log->max_zero_size = 128 * 1024 * 1024;
510 log->cur_pos = lseek(log->logfd, log->sectorsize - sizeof(super), SEEK_CUR);
511 if (log->cur_pos == (off_t) -1) {
512 fprintf(stderr, "Error seeking to first entry: %d\n", errno);