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