]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - debugfs/do_journal.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / debugfs / do_journal.c
CommitLineData
463eb921
DW
1/*
2 * do_journal.c --- Scribble onto the journal!
3 *
4 * Copyright (C) 2014 Oracle. This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8#include "config.h"
9#include <stdio.h>
10#ifdef HAVE_GETOPT_H
11#include <getopt.h>
12#else
13extern int optind;
14extern char *optarg;
15#endif
16#include <ctype.h>
17#include <unistd.h>
18#ifdef HAVE_SYS_TIME_H
19#include <sys/time.h>
20#endif
21
22#include "debugfs.h"
463eb921 23#include "ext2fs/kernel-jbd.h"
df0b907e 24#include "journal.h"
463eb921
DW
25
26#undef DEBUG
27
28#ifdef DEBUG
29# define dbg_printf(f, a...) do {printf("JFS DEBUG: " f, ## a); \
30 fflush(stdout); \
31} while (0)
32#else
33# define dbg_printf(f, a...)
34#endif
35
36#define JOURNAL_CHECK_TRANS_MAGIC(x) \
37 do { \
38 if ((x)->magic != J_TRANS_MAGIC) \
39 return EXT2_ET_INVALID_ARGUMENT; \
40 } while (0)
41
42#define J_TRANS_MAGIC 0xD15EA5ED
43#define J_TRANS_OPEN 1
44#define J_TRANS_COMMITTED 2
45struct journal_transaction_s {
46 unsigned int magic;
47 ext2_filsys fs;
48 journal_t *journal;
49 blk64_t block;
50 blk64_t start, end;
51 tid_t tid;
52 int flags;
53};
54
55typedef struct journal_transaction_s journal_transaction_t;
56
57static journal_t *current_journal = NULL;
58
25f291c9
TT
59static void journal_dump_trans(journal_transaction_t *trans EXT2FS_ATTR((unused)),
60 const char *tag EXT2FS_ATTR((unused)))
463eb921 61{
c707fb6c 62 dbg_printf("TRANS %p(%s): tid=%u start=%llu block=%llu end=%llu "
463eb921
DW
63 "flags=0x%x\n", trans, tag, trans->tid, trans->start,
64 trans->block, trans->end, trans->flags);
65}
66
67static errcode_t journal_commit_trans(journal_transaction_t *trans)
68{
69 struct buffer_head *bh, *cbh = NULL;
70 struct commit_header *commit;
71#ifdef HAVE_SYS_TIME_H
72 struct timeval tv;
73#endif
74 errcode_t err;
75
76 JOURNAL_CHECK_TRANS_MAGIC(trans);
77
78 if ((trans->flags & J_TRANS_COMMITTED) ||
79 !(trans->flags & J_TRANS_OPEN))
80 return EXT2_ET_INVALID_ARGUMENT;
81
82 bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize);
83 if (bh == NULL)
84 return ENOMEM;
85
86 /* write the descriptor block header */
87 commit = (struct commit_header *)bh->b_data;
8335d3c5
TT
88 commit->h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
89 commit->h_blocktype = ext2fs_cpu_to_be32(JBD2_COMMIT_BLOCK);
463eb921 90 commit->h_sequence = ext2fs_cpu_to_be32(trans->tid);
8335d3c5 91 if (jbd2_has_feature_checksum(trans->journal)) {
463eb921
DW
92 __u32 csum_v1 = ~0;
93 blk64_t cblk;
94
95 cbh = getblk(trans->journal->j_dev, 0,
96 trans->journal->j_blocksize);
97 if (cbh == NULL) {
98 err = ENOMEM;
99 goto error;
100 }
101
102 for (cblk = trans->start; cblk < trans->block; cblk++) {
8335d3c5
TT
103 err = jbd2_journal_bmap(trans->journal, cblk,
104 &cbh->b_blocknr);
463eb921
DW
105 if (err)
106 goto error;
107 mark_buffer_uptodate(cbh, 0);
db113c0e 108 ll_rw_block(REQ_OP_READ, 0, 1, &cbh);
463eb921
DW
109 err = cbh->b_err;
110 if (err)
111 goto error;
112 csum_v1 = ext2fs_crc32_be(csum_v1,
113 (unsigned char const *)cbh->b_data,
114 cbh->b_size);
115 }
116
8335d3c5
TT
117 commit->h_chksum_type = JBD2_CRC32_CHKSUM;
118 commit->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE;
463eb921
DW
119 commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1);
120 } else {
121 commit->h_chksum_type = 0;
122 commit->h_chksum_size = 0;
123 commit->h_chksum[0] = 0;
124 }
125#ifdef HAVE_SYS_TIME_H
126 gettimeofday(&tv, NULL);
127 commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec);
128 commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000);
129#else
130 commit->h_commit_sec = 0;
131 commit->h_commit_nsec = 0;
132#endif
133
134 /* Write block */
135 jbd2_commit_block_csum_set(trans->journal, bh);
8335d3c5 136 err = jbd2_journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
463eb921
DW
137 if (err)
138 goto error;
139
140 dbg_printf("Writing commit block at %llu:%llu\n", trans->block,
141 bh->b_blocknr);
142 mark_buffer_dirty(bh);
db113c0e 143 ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
463eb921
DW
144 err = bh->b_err;
145 if (err)
146 goto error;
147 trans->flags |= J_TRANS_COMMITTED;
148 trans->flags &= ~J_TRANS_OPEN;
149 trans->block++;
150
4ee26699 151 ext2fs_set_feature_journal_needs_recovery(trans->fs->super);
53c5d606 152 ext2fs_mark_super_dirty(trans->fs);
463eb921
DW
153error:
154 if (cbh)
155 brelse(cbh);
156 brelse(bh);
157 return err;
158}
159
160static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans,
161 blk64_t *revoke_list,
162 size_t revoke_len)
163{
8335d3c5 164 jbd2_journal_revoke_header_t *jrb;
463eb921
DW
165 void *buf;
166 size_t i, offset;
167 blk64_t curr_blk;
478360f5
TT
168 unsigned int sz;
169 unsigned csum_size = 0;
463eb921
DW
170 struct buffer_head *bh;
171 errcode_t err;
172
173 JOURNAL_CHECK_TRANS_MAGIC(trans);
174
175 if ((trans->flags & J_TRANS_COMMITTED) ||
176 !(trans->flags & J_TRANS_OPEN))
177 return EXT2_ET_INVALID_ARGUMENT;
178
179 if (revoke_len == 0)
180 return 0;
181
182 /* Do we need to leave space at the end for a checksum? */
8335d3c5 183 if (jbd2_journal_has_csum_v2or3(trans->journal))
1942e33c 184 csum_size = sizeof(struct jbd2_journal_block_tail);
463eb921
DW
185
186 curr_blk = trans->block;
187
188 bh = getblk(trans->journal->j_dev, curr_blk,
189 trans->journal->j_blocksize);
190 if (bh == NULL)
191 return ENOMEM;
192 jrb = buf = bh->b_data;
8335d3c5
TT
193 jrb->r_header.h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
194 jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JBD2_REVOKE_BLOCK);
463eb921
DW
195 jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid);
196 offset = sizeof(*jrb);
197
8335d3c5 198 if (jbd2_has_feature_64bit(trans->journal))
04c66cb2
DW
199 sz = 8;
200 else
201 sz = 4;
202
463eb921
DW
203 for (i = 0; i < revoke_len; i++) {
204 /* Block full, write to journal */
04c66cb2 205 if (offset + sz > trans->journal->j_blocksize - csum_size) {
463eb921
DW
206 jrb->r_count = ext2fs_cpu_to_be32(offset);
207 jbd2_revoke_csum_set(trans->journal, bh);
208
8335d3c5
TT
209 err = jbd2_journal_bmap(trans->journal, curr_blk,
210 &bh->b_blocknr);
463eb921
DW
211 if (err)
212 goto error;
213 dbg_printf("Writing revoke block at %llu:%llu\n",
214 curr_blk, bh->b_blocknr);
215 mark_buffer_dirty(bh);
db113c0e 216 ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
463eb921
DW
217 err = bh->b_err;
218 if (err)
219 goto error;
220
221 offset = sizeof(*jrb);
222 curr_blk++;
223 }
224
225 if (revoke_list[i] >=
226 ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
227 err = EXT2_ET_BAD_BLOCK_NUM;
228 goto error;
229 }
230
8335d3c5 231 if (jbd2_has_feature_64bit(trans->journal))
463eb921
DW
232 *((__u64 *)(&((char *)buf)[offset])) =
233 ext2fs_cpu_to_be64(revoke_list[i]);
04c66cb2 234 else
463eb921
DW
235 *((__u32 *)(&((char *)buf)[offset])) =
236 ext2fs_cpu_to_be32(revoke_list[i]);
04c66cb2 237 offset += sz;
463eb921
DW
238 }
239
240 if (offset > 0) {
241 jrb->r_count = ext2fs_cpu_to_be32(offset);
242 jbd2_revoke_csum_set(trans->journal, bh);
243
8335d3c5
TT
244 err = jbd2_journal_bmap(trans->journal, curr_blk,
245 &bh->b_blocknr);
463eb921
DW
246 if (err)
247 goto error;
248 dbg_printf("Writing revoke block at %llu:%llu\n",
249 curr_blk, bh->b_blocknr);
250 mark_buffer_dirty(bh);
db113c0e 251 ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
463eb921
DW
252 err = bh->b_err;
253 if (err)
254 goto error;
255 curr_blk++;
256 }
257
258error:
259 trans->block = curr_blk;
260 brelse(bh);
261 return err;
262}
263
264static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans,
265 blk64_t *block_list, size_t block_len,
266 FILE *fp)
267{
268 blk64_t curr_blk, jdb_blk;
269 size_t i, j;
270 int csum_size = 0;
271 journal_header_t *jdb;
272 journal_block_tag_t *jdbt;
273 int tag_bytes;
274 void *buf = NULL, *jdb_buf = NULL;
275 struct buffer_head *bh = NULL, *data_bh;
276 errcode_t err;
277
278 JOURNAL_CHECK_TRANS_MAGIC(trans);
279
280 if ((trans->flags & J_TRANS_COMMITTED) ||
281 !(trans->flags & J_TRANS_OPEN))
282 return EXT2_ET_INVALID_ARGUMENT;
283
284 if (block_len == 0)
285 return 0;
286
287 /* Do we need to leave space at the end for a checksum? */
8335d3c5
TT
288 if (jbd2_journal_has_csum_v2or3(trans->journal))
289 csum_size = sizeof(struct jbd2_journal_block_tail);
463eb921
DW
290
291 curr_blk = jdb_blk = trans->block;
292
293 data_bh = getblk(trans->journal->j_dev, curr_blk,
294 trans->journal->j_blocksize);
295 if (data_bh == NULL)
296 return ENOMEM;
297 buf = data_bh->b_data;
298
299 /* write the descriptor block header */
300 bh = getblk(trans->journal->j_dev, curr_blk,
301 trans->journal->j_blocksize);
302 if (bh == NULL) {
303 err = ENOMEM;
304 goto error;
305 }
306 jdb = jdb_buf = bh->b_data;
8335d3c5
TT
307 jdb->h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
308 jdb->h_blocktype = ext2fs_cpu_to_be32(JBD2_DESCRIPTOR_BLOCK);
463eb921
DW
309 jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid);
310 jdbt = (journal_block_tag_t *)(jdb + 1);
311
312 curr_blk++;
313 for (i = 0; i < block_len; i++) {
314 j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp);
315 if (j != 1) {
316 err = errno;
317 goto error;
318 }
319
320 tag_bytes = journal_tag_bytes(trans->journal);
321
322 /* No space left in descriptor block, write it out */
323 if ((char *)jdbt + tag_bytes >
324 (char *)jdb_buf + trans->journal->j_blocksize - csum_size) {
325 jbd2_descr_block_csum_set(trans->journal, bh);
8335d3c5 326 err = jbd2_journal_bmap(trans->journal, jdb_blk,
463eb921
DW
327 &bh->b_blocknr);
328 if (err)
329 goto error;
330 dbg_printf("Writing descriptor block at %llu:%llu\n",
331 jdb_blk, bh->b_blocknr);
332 mark_buffer_dirty(bh);
db113c0e 333 ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
463eb921
DW
334 err = bh->b_err;
335 if (err)
336 goto error;
337
338 jdbt = (journal_block_tag_t *)(jdb + 1);
339 jdb_blk = curr_blk;
340 curr_blk++;
341 }
342
343 if (block_list[i] >=
344 ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
345 err = EXT2_ET_BAD_BLOCK_NUM;
346 goto error;
347 }
348
349 /* Fill out the block tag */
350 jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF);
351 jdbt->t_flags = 0;
352 if (jdbt != (journal_block_tag_t *)(jdb + 1))
8335d3c5 353 jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_SAME_UUID);
463eb921
DW
354 else {
355 memcpy(jdbt + tag_bytes,
356 trans->journal->j_superblock->s_uuid,
357 sizeof(trans->journal->j_superblock->s_uuid));
358 tag_bytes += 16;
359 }
360 if (i == block_len - 1)
8335d3c5
TT
361 jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_LAST_TAG);
362 if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER)) {
463eb921 363 *((__u32 *)buf) = 0;
8335d3c5 364 jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_ESCAPE);
463eb921 365 }
8335d3c5 366 if (jbd2_has_feature_64bit(trans->journal))
463eb921
DW
367 jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32);
368 jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh,
369 trans->tid);
370
371 /* Write the data block */
8335d3c5
TT
372 err = jbd2_journal_bmap(trans->journal, curr_blk,
373 &data_bh->b_blocknr);
463eb921
DW
374 if (err)
375 goto error;
376 dbg_printf("Writing data block %llu at %llu:%llu tag %d\n",
377 block_list[i], curr_blk, data_bh->b_blocknr,
378 tag_bytes);
379 mark_buffer_dirty(data_bh);
db113c0e 380 ll_rw_block(REQ_OP_WRITE, 0, 1, &data_bh);
463eb921
DW
381 err = data_bh->b_err;
382 if (err)
383 goto error;
384
385 curr_blk++;
386 jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes);
387 }
388
389 /* Write out the last descriptor block */
390 if (jdbt != (journal_block_tag_t *)(jdb + 1)) {
391 jbd2_descr_block_csum_set(trans->journal, bh);
8335d3c5
TT
392 err = jbd2_journal_bmap(trans->journal, jdb_blk,
393 &bh->b_blocknr);
463eb921
DW
394 if (err)
395 goto error;
396 dbg_printf("Writing descriptor block at %llu:%llu\n",
397 jdb_blk, bh->b_blocknr);
398 mark_buffer_dirty(bh);
db113c0e 399 ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
463eb921
DW
400 err = bh->b_err;
401 if (err)
402 goto error;
403 }
404
405error:
406 trans->block = curr_blk;
407 if (bh)
408 brelse(bh);
409 brelse(data_bh);
410 return err;
411}
412
413static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks,
414 blk64_t revoke_blocks)
415{
416 blk64_t ret = 1;
417 unsigned int bs, sz;
418
419 /* Estimate # of revoke blocks */
420 bs = journal->j_blocksize;
8335d3c5 421 if (jbd2_journal_has_csum_v2or3(journal))
1942e33c 422 bs -= sizeof(struct jbd2_journal_block_tail);
8335d3c5 423 sz = jbd2_has_feature_64bit(journal) ? sizeof(__u64) : sizeof(__u32);
463eb921
DW
424 ret += revoke_blocks * sz / bs;
425
426 /* Estimate # of data blocks */
427 bs = journal->j_blocksize - 16;
8335d3c5
TT
428 if (jbd2_journal_has_csum_v2or3(journal))
429 bs -= sizeof(struct jbd2_journal_block_tail);
463eb921
DW
430 sz = journal_tag_bytes(journal);
431 ret += data_blocks * sz / bs;
432
433 ret += data_blocks;
434
435 return ret;
436}
437
438static errcode_t journal_open_trans(journal_t *journal,
439 journal_transaction_t *trans,
440 blk64_t blocks)
441{
442 trans->fs = journal->j_fs_dev->k_fs;
443 trans->journal = journal;
444 trans->flags = J_TRANS_OPEN;
445
446 if (journal->j_tail == 0) {
447 /* Clean journal, start at the tail */
448 trans->tid = journal->j_tail_sequence;
449 trans->start = journal->j_first;
450 } else {
451 /* Put new transaction at the head of the list */
452 trans->tid = journal->j_transaction_sequence;
453 trans->start = journal->j_head;
454 }
455
456 trans->block = trans->start;
457 if (trans->start + blocks > journal->j_last)
458 return ENOSPC;
459 trans->end = trans->block + blocks;
460 journal_dump_trans(trans, "new transaction");
461
462 trans->magic = J_TRANS_MAGIC;
463 return 0;
464}
465
466static errcode_t journal_close_trans(journal_transaction_t *trans)
467{
468 journal_t *journal;
469
470 JOURNAL_CHECK_TRANS_MAGIC(trans);
471
472 if (!(trans->flags & J_TRANS_COMMITTED))
473 return 0;
474
475 journal = trans->journal;
476 if (journal->j_tail == 0) {
477 /* Update the tail */
478 journal->j_tail_sequence = trans->tid;
479 journal->j_tail = trans->start;
480 journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start);
481 }
482
483 /* Update the head */
484 journal->j_head = trans->end + 1;
485 journal->j_transaction_sequence = trans->tid + 1;
486
487 trans->magic = 0;
488
489 /* Mark ourselves as needing recovery */
4ee26699
DW
490 if (!ext2fs_has_feature_journal_needs_recovery(trans->fs->super)) {
491 ext2fs_set_feature_journal_needs_recovery(trans->fs->super);
463eb921
DW
492 ext2fs_mark_super_dirty(trans->fs);
493 }
494
495 return 0;
496}
497
498#define JOURNAL_WRITE_NO_COMMIT 1
499static errcode_t journal_write(journal_t *journal,
500 int flags, blk64_t *block_list,
501 size_t block_len, blk64_t *revoke_list,
502 size_t revoke_len, FILE *fp)
503{
504 blk64_t blocks;
505 journal_transaction_t trans;
506 errcode_t err;
507
508 if (revoke_len > 0) {
8335d3c5 509 jbd2_set_feature_revoke(journal);
463eb921
DW
510 mark_buffer_dirty(journal->j_sb_buffer);
511 }
512
513 blocks = journal_guess_blocks(journal, block_len, revoke_len);
514 err = journal_open_trans(journal, &trans, blocks);
515 if (err)
516 goto error;
517
518 err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp);
519 if (err)
520 goto error;
521
522 err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len);
523 if (err)
524 goto error;
525
526 if (!(flags & JOURNAL_WRITE_NO_COMMIT)) {
527 err = journal_commit_trans(&trans);
528 if (err)
529 goto error;
530 }
531
532 err = journal_close_trans(&trans);
533 if (err)
534 goto error;
535error:
536 return err;
537}
538
2fcbcb1b
TT
539void do_journal_write(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
540 void *infop EXT2FS_ATTR((unused)))
463eb921
DW
541{
542 blk64_t *blist = NULL, *rlist = NULL;
543 size_t bn = 0, rn = 0;
544 FILE *fp = NULL;
545 int opt;
546 int flags = 0;
547 errcode_t err;
548
549 if (current_journal == NULL) {
550 printf("Journal not open.\n");
551 return;
552 }
553
554 reset_getopt();
555 while ((opt = getopt(argc, argv, "b:r:c")) != -1) {
556 switch (opt) {
557 case 'b':
558 err = read_list(optarg, &blist, &bn);
559 if (err)
560 com_err(argv[0], err,
561 "while reading block list");
562 break;
563 case 'r':
564 err = read_list(optarg, &rlist, &rn);
565 if (err)
566 com_err(argv[0], err,
567 "while reading revoke list");
568 break;
569 case 'c':
570 flags |= JOURNAL_WRITE_NO_COMMIT;
571 break;
572 default:
573 printf("%s [-b blocks] [-r revoke] [-c] file\n",
574 argv[0]);
575 printf("-b: Write these blocks into transaction.\n");
576 printf("-c: Do not commit transaction.\n");
577 printf("-r: Revoke these blocks from transaction.\n");
578
579 goto out;
580 }
581 }
582
583 if (bn > 0 && optind != argc - 1) {
584 printf("Need a file to read blocks from.\n");
585 return;
586 }
587
588 if (bn > 0) {
589 fp = fopen(argv[optind], "r");
590 if (fp == NULL) {
591 com_err(argv[0], errno,
592 "while opening journal data file");
593 goto out;
594 }
595 }
596
597 err = journal_write(current_journal, flags, blist, bn,
598 rlist, rn, fp);
599 if (err)
600 com_err("journal_write", err, "while writing journal");
601
602 if (fp)
603 fclose(fp);
604out:
605 if (blist)
606 free(blist);
607 if (rlist)
608 free(rlist);
609}
610
611/* Make sure we wrap around the log correctly! */
612#define wrap(journal, var) \
613do { \
614 if (var >= (journal)->j_last) \
615 var -= ((journal)->j_last - (journal)->j_first); \
616} while (0)
617
618/*
619 * Count the number of in-use tags in a journal descriptor block.
620 */
621
622static int count_tags(journal_t *journal, char *buf)
623{
624 char *tagp;
625 journal_block_tag_t *tag;
626 int nr = 0, size = journal->j_blocksize;
627 int tag_bytes = journal_tag_bytes(journal);
628
8335d3c5
TT
629 if (jbd2_journal_has_csum_v2or3(journal))
630 size -= sizeof(struct jbd2_journal_block_tail);
463eb921
DW
631
632 tagp = buf + sizeof(journal_header_t);
633
634 while ((tagp - buf + tag_bytes) <= size) {
635 tag = (journal_block_tag_t *) tagp;
636
637 nr++;
638 tagp += tag_bytes;
8335d3c5 639 if (!(tag->t_flags & ext2fs_cpu_to_be16(JBD2_FLAG_SAME_UUID)))
463eb921
DW
640 tagp += 16;
641
8335d3c5 642 if (tag->t_flags & ext2fs_cpu_to_be16(JBD2_FLAG_LAST_TAG))
463eb921
DW
643 break;
644 }
645
646 return nr;
647}
648
df0b907e 649static errcode_t journal_find_head(journal_t *journal)
463eb921
DW
650{
651 unsigned int next_commit_ID;
652 blk64_t next_log_block, head_block;
653 int err;
654 journal_superblock_t *sb;
655 journal_header_t *tmp;
656 struct buffer_head *bh;
657 unsigned int sequence;
658 int blocktype;
659
660 /*
661 * First thing is to establish what we expect to find in the log
662 * (in terms of transaction IDs), and where (in terms of log
663 * block offsets): query the superblock.
664 */
665
666 sb = journal->j_superblock;
667 next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
668 next_log_block = ext2fs_be32_to_cpu(sb->s_start);
669 head_block = next_log_block;
670
671 if (next_log_block == 0)
672 return 0;
673
674 bh = getblk(journal->j_dev, 0, journal->j_blocksize);
675 if (bh == NULL)
676 return ENOMEM;
677
678 /*
679 * Now we walk through the log, transaction by transaction,
680 * making sure that each transaction has a commit block in the
681 * expected place. Each complete transaction gets replayed back
682 * into the main filesystem.
683 */
684 while (1) {
685 dbg_printf("Scanning for sequence ID %u at %lu/%lu\n",
686 next_commit_ID, (unsigned long)next_log_block,
687 journal->j_last);
688
689 /* Skip over each chunk of the transaction looking
690 * either the next descriptor block or the final commit
691 * record. */
8335d3c5
TT
692 err = jbd2_journal_bmap(journal, next_log_block,
693 &bh->b_blocknr);
463eb921
DW
694 if (err)
695 goto err;
696 mark_buffer_uptodate(bh, 0);
db113c0e 697 ll_rw_block(REQ_OP_READ, 0, 1, &bh);
463eb921
DW
698 err = bh->b_err;
699 if (err)
700 goto err;
701
702 next_log_block++;
703 wrap(journal, next_log_block);
704
705 /* What kind of buffer is it?
706 *
707 * If it is a descriptor block, check that it has the
708 * expected sequence number. Otherwise, we're all done
709 * here. */
710
711 tmp = (journal_header_t *)bh->b_data;
712
8335d3c5 713 if (tmp->h_magic != ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER)) {
463eb921
DW
714 dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
715 goto err;
716 }
717
718 blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
719 sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
720 dbg_printf("Found magic %d, sequence %d\n",
721 blocktype, sequence);
722
723 if (sequence != next_commit_ID) {
724 dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n",
725 sequence, next_commit_ID);
726 goto err;
727 }
728
729 /* OK, we have a valid descriptor block which matches
730 * all of the sequence number checks. What are we going
731 * to do with it? That depends on the pass... */
732
733 switch (blocktype) {
8335d3c5 734 case JBD2_DESCRIPTOR_BLOCK:
463eb921
DW
735 next_log_block += count_tags(journal, bh->b_data);
736 wrap(journal, next_log_block);
737 continue;
738
8335d3c5 739 case JBD2_COMMIT_BLOCK:
463eb921
DW
740 head_block = next_log_block;
741 next_commit_ID++;
742 continue;
743
8335d3c5 744 case JBD2_REVOKE_BLOCK:
463eb921
DW
745 continue;
746
747 default:
748 dbg_printf("Unrecognised magic %d, end of scan.\n",
749 blocktype);
750 err = -EINVAL;
751 goto err;
752 }
753 }
754
755err:
756 if (err == 0) {
757 dbg_printf("head seq=%d blk=%llu\n", next_commit_ID,
758 head_block);
759 journal->j_transaction_sequence = next_commit_ID;
760 journal->j_head = head_block;
761 }
762 brelse(bh);
763 return err;
764}
765
766static void update_journal_csum(journal_t *journal, int ver)
767{
768 journal_superblock_t *jsb;
769
770 if (journal->j_format_version < 2)
771 return;
772
773 if (journal->j_tail != 0 ||
4ee26699
DW
774 ext2fs_has_feature_journal_needs_recovery(
775 journal->j_fs_dev->k_fs->super)) {
463eb921
DW
776 printf("Journal needs recovery, will not add csums.\n");
777 return;
778 }
779
780 /* metadata_csum implies journal csum v3 */
781 jsb = journal->j_superblock;
4ee26699 782 if (ext2fs_has_feature_metadata_csum(journal->j_fs_dev->k_fs->super)) {
463eb921
DW
783 printf("Setting csum v%d\n", ver);
784 switch (ver) {
785 case 2:
8335d3c5
TT
786 jbd2_clear_feature_csum3(journal);
787 jbd2_set_feature_csum2(journal);
788 jbd2_clear_feature_checksum(journal);
463eb921
DW
789 break;
790 case 3:
8335d3c5
TT
791 jbd2_set_feature_csum3(journal);
792 jbd2_clear_feature_csum2(journal);
793 jbd2_clear_feature_checksum(journal);
463eb921
DW
794 break;
795 default:
796 printf("Unknown checksum v%d\n", ver);
797 break;
798 }
799 journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
800 journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
801 sizeof(jsb->s_uuid));
802 } else {
8335d3c5
TT
803 jbd2_clear_feature_csum3(journal);
804 jbd2_clear_feature_csum2(journal);
805 jbd2_set_feature_checksum(journal);
463eb921
DW
806 }
807}
808
809static void update_uuid(journal_t *journal)
810{
811 size_t z;
812 ext2_filsys fs;
813
814 if (journal->j_format_version < 2)
815 return;
816
817 for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
818 if (journal->j_superblock->s_uuid[z])
819 break;
820 if (z == 0)
821 return;
822
823 fs = journal->j_fs_dev->k_fs;
4ee26699 824 if (!ext2fs_has_feature_64bit(fs->super))
463eb921
DW
825 return;
826
8335d3c5 827 if (jbd2_has_feature_64bit(journal) &&
4ee26699 828 ext2fs_has_feature_64bit(fs->super))
463eb921
DW
829 return;
830
831 if (journal->j_tail != 0 ||
4ee26699 832 ext2fs_has_feature_journal_needs_recovery(fs->super)) {
463eb921
DW
833 printf("Journal needs recovery, will not set 64bit.\n");
834 return;
835 }
836
837 memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
838 sizeof(fs->super->s_uuid));
839}
840
841static void update_64bit_flag(journal_t *journal)
842{
843 if (journal->j_format_version < 2)
844 return;
845
4ee26699 846 if (!ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
463eb921
DW
847 return;
848
8335d3c5 849 if (jbd2_has_feature_64bit(journal) &&
4ee26699 850 ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
463eb921
DW
851 return;
852
853 if (journal->j_tail != 0 ||
4ee26699
DW
854 ext2fs_has_feature_journal_needs_recovery(
855 journal->j_fs_dev->k_fs->super)) {
463eb921
DW
856 printf("Journal needs recovery, will not set 64bit.\n");
857 return;
858 }
859
8335d3c5 860 jbd2_set_feature_64bit(journal);
463eb921
DW
861}
862
2fcbcb1b
TT
863void do_journal_open(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
864 void *infop EXT2FS_ATTR((unused)))
463eb921
DW
865{
866 int opt, enable_csum = 0, csum_ver = 3;
867 journal_t *journal;
868 errcode_t err;
869
870 if (check_fs_open(argv[0]))
871 return;
872 if (check_fs_read_write(argv[0]))
873 return;
874 if (check_fs_bitmaps(argv[0]))
875 return;
876 if (current_journal) {
877 printf("Journal is already open.\n");
878 return;
879 }
4ee26699 880 if (!ext2fs_has_feature_journal(current_fs->super)) {
463eb921
DW
881 printf("Journalling is not enabled on this filesystem.\n");
882 return;
883 }
884
885 reset_getopt();
886 while ((opt = getopt(argc, argv, "cv:f:")) != -1) {
887 switch (opt) {
888 case 'c':
889 enable_csum = 1;
890 break;
891 case 'f':
892 if (current_fs->journal_name)
893 free(current_fs->journal_name);
894 current_fs->journal_name = strdup(optarg);
895 break;
896 case 'v':
897 csum_ver = atoi(optarg);
898 if (csum_ver != 2 && csum_ver != 3) {
899 printf("Unknown journal csum v%d\n", csum_ver);
900 csum_ver = 3;
901 }
902 break;
903 default:
cac40d06 904 printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]);
463eb921
DW
905 printf("-c: Enable journal checksumming.\n");
906 printf("-v: Use this version checksum format.\n");
7600aa0f 907 printf("-f: Load this external journal.\n");
463eb921
DW
908 }
909 }
910
911 err = ext2fs_open_journal(current_fs, &current_journal);
912 if (err) {
913 com_err(argv[0], err, "while opening journal");
914 return;
915 }
916 journal = current_journal;
917
c707fb6c 918 dbg_printf("JOURNAL: seq=%u tailseq=%u start=%lu first=%lu "
463eb921
DW
919 "maxlen=%lu\n", journal->j_tail_sequence,
920 journal->j_transaction_sequence, journal->j_tail,
921 journal->j_first, journal->j_last);
922
923 update_uuid(journal);
924 update_64bit_flag(journal);
925 if (enable_csum)
926 update_journal_csum(journal, csum_ver);
927
928 err = journal_find_head(journal);
929 if (err)
930 com_err(argv[0], err, "while examining journal");
931}
932
25f291c9 933void do_journal_close(int argc EXT2FS_ATTR((unused)),
2fcbcb1b
TT
934 char *argv[] EXT2FS_ATTR((unused)),
935 int sci_idx EXT2FS_ATTR((unused)),
936 void *infop EXT2FS_ATTR((unused)))
463eb921
DW
937{
938 if (current_journal == NULL) {
939 printf("Journal not open.\n");
940 return;
941 }
942
943 ext2fs_close_journal(current_fs, &current_journal);
944}
945
2fcbcb1b
TT
946void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[],
947 int sci_idx EXT2FS_ATTR((unused)),
948 void *infop EXT2FS_ATTR((unused)))
463eb921
DW
949{
950 errcode_t err;
951
952 if (check_fs_open(argv[0]))
953 return;
954 if (check_fs_read_write(argv[0]))
955 return;
956 if (check_fs_bitmaps(argv[0]))
957 return;
958 if (current_journal) {
959 printf("Please close the journal before recovering it.\n");
960 return;
961 }
962
963 err = ext2fs_run_ext3_journal(&current_fs);
964 if (err)
965 com_err("journal_run", err, "while recovering journal");
53c5d606 966 else {
4ee26699 967 ext2fs_clear_feature_journal_needs_recovery(current_fs->super);
53c5d606
DW
968 ext2fs_mark_super_dirty(current_fs);
969 }
463eb921 970}