Whamcloud - gitweb
resize: remove calculation of unused variable
[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 "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
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
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
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
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
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
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
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
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
537 void do_journal_write(int argc, char *argv[])
538 {
539         blk64_t *blist = NULL, *rlist = NULL;
540         size_t bn = 0, rn = 0;
541         FILE *fp = NULL;
542         int opt;
543         int flags = 0;
544         errcode_t err;
545
546         if (current_journal == NULL) {
547                 printf("Journal not open.\n");
548                 return;
549         }
550
551         reset_getopt();
552         while ((opt = getopt(argc, argv, "b:r:c")) != -1) {
553                 switch (opt) {
554                 case 'b':
555                         err = read_list(optarg, &blist, &bn);
556                         if (err)
557                                 com_err(argv[0], err,
558                                         "while reading block list");
559                         break;
560                 case 'r':
561                         err = read_list(optarg, &rlist, &rn);
562                         if (err)
563                                 com_err(argv[0], err,
564                                         "while reading revoke list");
565                         break;
566                 case 'c':
567                         flags |= JOURNAL_WRITE_NO_COMMIT;
568                         break;
569                 default:
570                         printf("%s [-b blocks] [-r revoke] [-c] file\n",
571                                argv[0]);
572                         printf("-b: Write these blocks into transaction.\n");
573                         printf("-c: Do not commit transaction.\n");
574                         printf("-r: Revoke these blocks from transaction.\n");
575
576                         goto out;
577                 }
578         }
579
580         if (bn > 0 && optind != argc - 1) {
581                 printf("Need a file to read blocks from.\n");
582                 return;
583         }
584
585         if (bn > 0) {
586                 fp = fopen(argv[optind], "r");
587                 if (fp == NULL) {
588                         com_err(argv[0], errno,
589                                 "while opening journal data file");
590                         goto out;
591                 }
592         }
593
594         err = journal_write(current_journal, flags, blist, bn,
595                             rlist, rn, fp);
596         if (err)
597                 com_err("journal_write", err, "while writing journal");
598
599         if (fp)
600                 fclose(fp);
601 out:
602         if (blist)
603                 free(blist);
604         if (rlist)
605                 free(rlist);
606 }
607
608 /* Make sure we wrap around the log correctly! */
609 #define wrap(journal, var)                                              \
610 do {                                                                    \
611         if (var >= (journal)->j_last)                                   \
612                 var -= ((journal)->j_last - (journal)->j_first);        \
613 } while (0)
614
615 /*
616  * Count the number of in-use tags in a journal descriptor block.
617  */
618
619 static int count_tags(journal_t *journal, char *buf)
620 {
621         char                    *tagp;
622         journal_block_tag_t     *tag;
623         int                     nr = 0, size = journal->j_blocksize;
624         int                     tag_bytes = journal_tag_bytes(journal);
625
626         if (journal_has_csum_v2or3(journal))
627                 size -= sizeof(struct journal_block_tail);
628
629         tagp = buf + sizeof(journal_header_t);
630
631         while ((tagp - buf + tag_bytes) <= size) {
632                 tag = (journal_block_tag_t *) tagp;
633
634                 nr++;
635                 tagp += tag_bytes;
636                 if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID)))
637                         tagp += 16;
638
639                 if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG))
640                         break;
641         }
642
643         return nr;
644 }
645
646 static errcode_t journal_find_head(journal_t *journal)
647 {
648         unsigned int            next_commit_ID;
649         blk64_t                 next_log_block, head_block;
650         int                     err;
651         journal_superblock_t    *sb;
652         journal_header_t        *tmp;
653         struct buffer_head      *bh;
654         unsigned int            sequence;
655         int                     blocktype;
656
657         /*
658          * First thing is to establish what we expect to find in the log
659          * (in terms of transaction IDs), and where (in terms of log
660          * block offsets): query the superblock.
661          */
662
663         sb = journal->j_superblock;
664         next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
665         next_log_block = ext2fs_be32_to_cpu(sb->s_start);
666         head_block = next_log_block;
667
668         if (next_log_block == 0)
669                 return 0;
670
671         bh = getblk(journal->j_dev, 0, journal->j_blocksize);
672         if (bh == NULL)
673                 return ENOMEM;
674
675         /*
676          * Now we walk through the log, transaction by transaction,
677          * making sure that each transaction has a commit block in the
678          * expected place.  Each complete transaction gets replayed back
679          * into the main filesystem.
680          */
681         while (1) {
682                 dbg_printf("Scanning for sequence ID %u at %lu/%lu\n",
683                           next_commit_ID, (unsigned long)next_log_block,
684                           journal->j_last);
685
686                 /* Skip over each chunk of the transaction looking
687                  * either the next descriptor block or the final commit
688                  * record. */
689                 err = journal_bmap(journal, next_log_block, &bh->b_blocknr);
690                 if (err)
691                         goto err;
692                 mark_buffer_uptodate(bh, 0);
693                 ll_rw_block(READ, 1, &bh);
694                 err = bh->b_err;
695                 if (err)
696                         goto err;
697
698                 next_log_block++;
699                 wrap(journal, next_log_block);
700
701                 /* What kind of buffer is it?
702                  *
703                  * If it is a descriptor block, check that it has the
704                  * expected sequence number.  Otherwise, we're all done
705                  * here. */
706
707                 tmp = (journal_header_t *)bh->b_data;
708
709                 if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
710                         dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
711                         goto err;
712                 }
713
714                 blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
715                 sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
716                 dbg_printf("Found magic %d, sequence %d\n",
717                           blocktype, sequence);
718
719                 if (sequence != next_commit_ID) {
720                         dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n",
721                                    sequence, next_commit_ID);
722                         goto err;
723                 }
724
725                 /* OK, we have a valid descriptor block which matches
726                  * all of the sequence number checks.  What are we going
727                  * to do with it?  That depends on the pass... */
728
729                 switch (blocktype) {
730                 case JFS_DESCRIPTOR_BLOCK:
731                         next_log_block += count_tags(journal, bh->b_data);
732                         wrap(journal, next_log_block);
733                         continue;
734
735                 case JFS_COMMIT_BLOCK:
736                         head_block = next_log_block;
737                         next_commit_ID++;
738                         continue;
739
740                 case JFS_REVOKE_BLOCK:
741                         continue;
742
743                 default:
744                         dbg_printf("Unrecognised magic %d, end of scan.\n",
745                                   blocktype);
746                         err = -EINVAL;
747                         goto err;
748                 }
749         }
750
751 err:
752         if (err == 0) {
753                 dbg_printf("head seq=%d blk=%llu\n", next_commit_ID,
754                            head_block);
755                 journal->j_transaction_sequence = next_commit_ID;
756                 journal->j_head = head_block;
757         }
758         brelse(bh);
759         return err;
760 }
761
762 static void update_journal_csum(journal_t *journal, int ver)
763 {
764         journal_superblock_t *jsb;
765
766         if (journal->j_format_version < 2)
767                 return;
768
769         if (journal->j_tail != 0 ||
770             ext2fs_has_feature_journal_needs_recovery(
771                                         journal->j_fs_dev->k_fs->super)) {
772                 printf("Journal needs recovery, will not add csums.\n");
773                 return;
774         }
775
776         /* metadata_csum implies journal csum v3 */
777         jsb = journal->j_superblock;
778         if (ext2fs_has_feature_metadata_csum(journal->j_fs_dev->k_fs->super)) {
779                 printf("Setting csum v%d\n", ver);
780                 switch (ver) {
781                 case 2:
782                         jfs_clear_feature_csum3(journal);
783                         jfs_set_feature_csum2(journal);
784                         jfs_clear_feature_checksum(journal);
785                         break;
786                 case 3:
787                         jfs_set_feature_csum3(journal);
788                         jfs_clear_feature_csum2(journal);
789                         jfs_clear_feature_checksum(journal);
790                         break;
791                 default:
792                         printf("Unknown checksum v%d\n", ver);
793                         break;
794                 }
795                 journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
796                 journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
797                                                    sizeof(jsb->s_uuid));
798         } else {
799                 jfs_clear_feature_csum3(journal);
800                 jfs_clear_feature_csum2(journal);
801                 jfs_set_feature_checksum(journal);
802         }
803 }
804
805 static void update_uuid(journal_t *journal)
806 {
807         size_t z;
808         ext2_filsys fs;
809
810         if (journal->j_format_version < 2)
811                 return;
812
813         for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
814                 if (journal->j_superblock->s_uuid[z])
815                         break;
816         if (z == 0)
817                 return;
818
819         fs = journal->j_fs_dev->k_fs;
820         if (!ext2fs_has_feature_64bit(fs->super))
821                 return;
822
823         if (jfs_has_feature_64bit(journal) &&
824             ext2fs_has_feature_64bit(fs->super))
825                 return;
826
827         if (journal->j_tail != 0 ||
828             ext2fs_has_feature_journal_needs_recovery(fs->super)) {
829                 printf("Journal needs recovery, will not set 64bit.\n");
830                 return;
831         }
832
833         memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
834                sizeof(fs->super->s_uuid));
835 }
836
837 static void update_64bit_flag(journal_t *journal)
838 {
839         if (journal->j_format_version < 2)
840                 return;
841
842         if (!ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
843                 return;
844
845         if (jfs_has_feature_64bit(journal) &&
846             ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
847                 return;
848
849         if (journal->j_tail != 0 ||
850             ext2fs_has_feature_journal_needs_recovery(
851                                 journal->j_fs_dev->k_fs->super)) {
852                 printf("Journal needs recovery, will not set 64bit.\n");
853                 return;
854         }
855
856         jfs_set_feature_64bit(journal);
857 }
858
859 void do_journal_open(int argc, char *argv[])
860 {
861         int opt, enable_csum = 0, csum_ver = 3;
862         journal_t *journal;
863         errcode_t err;
864
865         if (check_fs_open(argv[0]))
866                 return;
867         if (check_fs_read_write(argv[0]))
868                 return;
869         if (check_fs_bitmaps(argv[0]))
870                 return;
871         if (current_journal) {
872                 printf("Journal is already open.\n");
873                 return;
874         }
875         if (!ext2fs_has_feature_journal(current_fs->super)) {
876                 printf("Journalling is not enabled on this filesystem.\n");
877                 return;
878         }
879
880         reset_getopt();
881         while ((opt = getopt(argc, argv, "cv:f:")) != -1) {
882                 switch (opt) {
883                 case 'c':
884                         enable_csum = 1;
885                         break;
886                 case 'f':
887                         if (current_fs->journal_name)
888                                 free(current_fs->journal_name);
889                         current_fs->journal_name = strdup(optarg);
890                         break;
891                 case 'v':
892                         csum_ver = atoi(optarg);
893                         if (csum_ver != 2 && csum_ver != 3) {
894                                 printf("Unknown journal csum v%d\n", csum_ver);
895                                 csum_ver = 3;
896                         }
897                         break;
898                 default:
899                         printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]);
900                         printf("-c: Enable journal checksumming.\n");
901                         printf("-v: Use this version checksum format.\n");
902                         printf("-f: Load this external journal.\n");
903                 }
904         }
905
906         err = ext2fs_open_journal(current_fs, &current_journal);
907         if (err) {
908                 com_err(argv[0], err, "while opening journal");
909                 return;
910         }
911         journal = current_journal;
912
913         dbg_printf("JOURNAL: seq=%d tailseq=%d start=%lu first=%lu "
914                    "maxlen=%lu\n", journal->j_tail_sequence,
915                    journal->j_transaction_sequence, journal->j_tail,
916                    journal->j_first, journal->j_last);
917
918         update_uuid(journal);
919         update_64bit_flag(journal);
920         if (enable_csum)
921                 update_journal_csum(journal, csum_ver);
922
923         err = journal_find_head(journal);
924         if (err)
925                 com_err(argv[0], err, "while examining journal");
926 }
927
928 void do_journal_close(int argc EXT2FS_ATTR((unused)),
929                       char *argv[] EXT2FS_ATTR((unused)))
930 {
931         if (current_journal == NULL) {
932                 printf("Journal not open.\n");
933                 return;
934         }
935
936         ext2fs_close_journal(current_fs, &current_journal);
937 }
938
939 void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[])
940 {
941         errcode_t err;
942
943         if (check_fs_open(argv[0]))
944                 return;
945         if (check_fs_read_write(argv[0]))
946                 return;
947         if (check_fs_bitmaps(argv[0]))
948                 return;
949         if (current_journal) {
950                 printf("Please close the journal before recovering it.\n");
951                 return;
952         }
953
954         err = ext2fs_run_ext3_journal(&current_fs);
955         if (err)
956                 com_err("journal_run", err, "while recovering journal");
957         else {
958                 ext2fs_clear_feature_journal_needs_recovery(current_fs->super);
959                 ext2fs_mark_super_dirty(current_fs);
960         }
961 }