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