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