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