11 #include "log-writes.h"
13 int log_writes_verbose = 0;
16 * @log: the log to free.
18 * This will close any open fd's the log has and free up its memory.
20 void log_free(struct log *log)
22 if (log->replayfd >= 0)
29 static int discard_range(struct log *log, u64 start, u64 len)
31 u64 range[2] = { start, len };
33 if (ioctl(log->replayfd, BLKDISCARD, &range) < 0) {
34 if (log_writes_verbose)
35 printf("replay device doesn't support discard, "
36 "switching to writing zeros\n");
37 log->flags |= LOG_DISCARD_NOT_SUPP;
42 static int zero_range(struct log *log, u64 start, u64 len)
48 if (log->max_zero_size < len) {
49 if (log_writes_verbose)
50 printf("discard len %llu larger than max %llu\n",
51 (unsigned long long)len,
52 (unsigned long long)log->max_zero_size);
57 buf = malloc(bufsize);
61 fprintf(stderr, "Couldn't allocate zero buffer");
66 memset(buf, 0, bufsize);
68 ret = pwrite(log->replayfd, buf, bufsize, start);
70 fprintf(stderr, "Error zeroing file: %d\n", errno);
82 * @log: the log we are replaying.
83 * @entry: the discard entry.
85 * Discard the given length. If the device supports discard we will call that
86 * ioctl, otherwise we will write 0's to emulate discard. If the discard size
87 * is larger than log->max_zero_size then we will simply skip the zero'ing if
88 * the drive doesn't support discard.
90 int log_discard(struct log *log, struct log_write_entry *entry)
92 u64 start = le64_to_cpu(entry->sector) * log->sectorsize;
93 u64 size = le64_to_cpu(entry->nr_sectors) * log->sectorsize;
94 u64 max_chunk = 1 * 1024 * 1024 * 1024;
96 if (log->flags & LOG_IGNORE_DISCARD)
100 u64 len = size > max_chunk ? max_chunk : size;
104 * Do this check first in case it is our first discard, that way
105 * if we return EOPNOTSUPP we will fall back to the 0 method
108 if (!(log->flags & LOG_DISCARD_NOT_SUPP))
109 ret = discard_range(log, start, len);
110 if (log->flags & LOG_DISCARD_NOT_SUPP)
111 ret = zero_range(log, start, len);
121 * @entry: entry to be replayed.
123 * @return: 1 if the entry is sane, 0 if it is invalid.
125 * Check if this is a sane log entry.
127 int log_entry_valid(struct log_write_entry *entry)
129 u64 flags = le64_to_cpu(entry->flags);
131 /* Suspect all zeroes entry */
132 if (!flags && !entry->nr_sectors)
134 /* Suspect non zero padded entry */
135 if (flags != LOG_MARK_FLAG && entry->data[0] != 0)
141 * @log: the log we are replaying.
142 * @entry: where we put the entry.
143 * @read_data: read the entry data as well, entry must be log->sectorsize sized
146 * @return: 0 if we replayed, 1 if we are at the end, -1 if there was an error.
148 * Replay the next entry in our log onto the replay device.
150 int log_replay_next_entry(struct log *log, struct log_write_entry *entry,
155 size_t read_size = read_data ? log->sectorsize :
156 sizeof(struct log_write_entry);
161 if (log->cur_entry >= log->nr_entries)
164 ret = read(log->logfd, entry, read_size);
165 if (ret != read_size) {
166 fprintf(stderr, "Error reading entry: %d\n", errno);
169 if (!log_entry_valid(entry)) {
170 fprintf(stderr, "Malformed entry @%llu\n",
171 log->cur_pos / log->sectorsize);
176 size = le64_to_cpu(entry->nr_sectors) * log->sectorsize;
177 if (read_size < log->sectorsize) {
178 log->cur_pos = lseek(log->logfd,
179 log->sectorsize - sizeof(struct log_write_entry), SEEK_CUR);
180 if (log->cur_pos == (off_t)-1) {
181 fprintf(stderr, "Error seeking in log: %d\n", errno);
185 log->cur_pos += read_size;
188 if (log_writes_verbose) {
189 printf("replaying %d@%llu: sector %llu, size %llu, flags %llu\n",
190 (int)log->cur_entry - 1, log->cur_pos / log->sectorsize,
191 (unsigned long long)le64_to_cpu(entry->sector),
192 (unsigned long long)size,
193 (unsigned long long)le64_to_cpu(entry->flags));
198 flags = le64_to_cpu(entry->flags);
199 if (flags & LOG_DISCARD_FLAG)
200 return log_discard(log, entry);
204 fprintf(stderr, "Error allocating buffer %llu entry %llu\n", (unsigned long long)size, (unsigned long long)log->cur_entry - 1);
208 ret = read(log->logfd, buf, size);
210 fprintf(stderr, "Error reading data: %d\n", errno);
214 log->cur_pos += size;
216 offset = le64_to_cpu(entry->sector) * log->sectorsize;
217 ret = pwrite(log->replayfd, buf, size, offset);
220 fprintf(stderr, "Error writing data: %d\n", errno);
228 * @log: the log we are manipulating.
229 * @entry_num: the entry we want.
231 * Seek to the given entry in the log, starting at 0 and ending at
232 * log->nr_entries - 1.
234 int log_seek_entry(struct log *log, u64 entry_num)
238 if (entry_num >= log->nr_entries) {
239 fprintf(stderr, "Invalid entry number\n");
243 /* Skip the first sector containing the log super block */
244 log->cur_pos = lseek(log->logfd, log->sectorsize, SEEK_SET);
245 if (log->cur_pos == (off_t)-1) {
246 fprintf(stderr, "Error seeking in file: %d\n", errno);
251 for (i = 0; i < entry_num; i++) {
252 struct log_write_entry entry;
257 ret = read(log->logfd, &entry, sizeof(entry));
258 if (ret != sizeof(entry)) {
259 fprintf(stderr, "Error reading entry: %d\n", errno);
262 if (!log_entry_valid(&entry)) {
263 fprintf(stderr, "Malformed entry @%llu\n",
264 log->cur_pos / log->sectorsize);
267 if (log_writes_verbose > 1)
268 printf("seek entry %d@%llu: %llu, size %llu, flags %llu\n",
269 (int)i, log->cur_pos / log->sectorsize,
270 (unsigned long long)le64_to_cpu(entry.sector),
271 (unsigned long long)le64_to_cpu(entry.nr_sectors),
272 (unsigned long long)le64_to_cpu(entry.flags));
273 flags = le64_to_cpu(entry.flags);
274 seek_size = log->sectorsize - sizeof(entry);
275 if (!(flags & LOG_DISCARD_FLAG))
276 seek_size += le64_to_cpu(entry.nr_sectors) *
278 log->cur_pos = lseek(log->logfd, seek_size, SEEK_CUR);
279 if (log->cur_pos == (off_t)-1) {
280 fprintf(stderr, "Error seeking in file: %d\n", errno);
290 * @log: the log we are manipulating.
291 * @entry: the entry we read.
292 * @read_data: read the extra data for the entry, your entry must be
293 * log->sectorsize large.
295 * @return: 1 if we hit the end of the log, 0 we got the next entry, < 0 if
296 * there was an error.
298 * Seek to the next entry in the log.
300 int log_seek_next_entry(struct log *log, struct log_write_entry *entry,
303 size_t read_size = read_data ? log->sectorsize :
304 sizeof(struct log_write_entry);
308 if (log->cur_entry >= log->nr_entries)
311 ret = read(log->logfd, entry, read_size);
312 if (ret != read_size) {
313 fprintf(stderr, "Error reading entry: %d\n", errno);
316 if (!log_entry_valid(entry)) {
317 fprintf(stderr, "Malformed entry @%llu\n",
318 log->cur_pos / log->sectorsize);
323 if (read_size < log->sectorsize) {
324 log->cur_pos = lseek(log->logfd,
325 log->sectorsize - sizeof(struct log_write_entry), SEEK_CUR);
326 if (log->cur_pos == (off_t)-1) {
327 fprintf(stderr, "Error seeking in log: %d\n", errno);
331 log->cur_pos += read_size;
333 if (log_writes_verbose > 1)
334 printf("seek entry %d@%llu: %llu, size %llu, flags %llu\n",
335 (int)log->cur_entry - 1, log->cur_pos / log->sectorsize,
336 (unsigned long long)le64_to_cpu(entry->sector),
337 (unsigned long long)le64_to_cpu(entry->nr_sectors),
338 (unsigned long long)le64_to_cpu(entry->flags));
340 flags = le64_to_cpu(entry->flags);
341 read_size = le64_to_cpu(entry->nr_sectors) * log->sectorsize;
342 if (!read_size || (flags & LOG_DISCARD_FLAG))
345 log->cur_pos = lseek(log->logfd, read_size, SEEK_CUR);
346 if (log->cur_pos == (off_t)-1) {
347 fprintf(stderr, "Error seeking in log: %d\n", errno);
355 * @logfile: the file that contains the write log.
356 * @replayfile: the file/device to replay onto, can be NULL.
358 * Opens a logfile and makes sure it is valid and returns a struct log.
360 struct log *log_open(char *logfile, char *replayfile)
363 struct log_write_super super;
366 log = malloc(sizeof(struct log));
368 fprintf(stderr, "Couldn't alloc log\n");
374 log->logfd = open(logfile, O_RDONLY);
375 if (log->logfd < 0) {
376 fprintf(stderr, "Couldn't open log %s: %d\n", logfile,
383 log->replayfd = open(replayfile, O_WRONLY);
384 if (log->replayfd < 0) {
385 fprintf(stderr, "Couldn't open replay file %s: %d\n",
392 ret = read(log->logfd, &super, sizeof(struct log_write_super));
393 if (ret < sizeof(struct log_write_super)) {
394 fprintf(stderr, "Error reading super: %d\n", errno);
399 if (le64_to_cpu(super.magic) != WRITE_LOG_MAGIC) {
400 fprintf(stderr, "Magic doesn't match\n");
405 if (le64_to_cpu(super.version) != WRITE_LOG_VERSION) {
406 fprintf(stderr, "Version mismatch, wanted %d, have %d\n",
407 WRITE_LOG_VERSION, (int)le64_to_cpu(super.version));
412 log->sectorsize = le32_to_cpu(super.sectorsize);
413 log->nr_entries = le64_to_cpu(super.nr_entries);
414 log->max_zero_size = 128 * 1024 * 1024;
416 log->cur_pos = lseek(log->logfd, log->sectorsize - sizeof(super), SEEK_CUR);
417 if (log->cur_pos == (off_t) -1) {
418 fprintf(stderr, "Error seeking to first entry: %d\n", errno);