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