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