2 * do_journal.c --- Scribble onto the journal!
4 * Copyright (C) 2014 Oracle. This file may be redistributed
5 * under the terms of the GNU Public License.
18 #ifdef HAVE_SYS_TIME_H
24 #include "ext2fs/kernel-jbd.h"
27 errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j);
28 errcode_t ext2fs_close_journal(ext2_filsys fs, journal_t **j);
29 errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
30 void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh);
31 void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh);
32 void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh);
33 void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
34 struct buffer_head *bh, __u32 sequence);
39 # define dbg_printf(f, a...) do {printf("JFS DEBUG: " f, ## a); \
43 # define dbg_printf(f, a...)
46 #define JOURNAL_CHECK_TRANS_MAGIC(x) \
48 if ((x)->magic != J_TRANS_MAGIC) \
49 return EXT2_ET_INVALID_ARGUMENT; \
52 #define J_TRANS_MAGIC 0xD15EA5ED
53 #define J_TRANS_OPEN 1
54 #define J_TRANS_COMMITTED 2
55 struct journal_transaction_s {
65 typedef struct journal_transaction_s journal_transaction_t;
67 static journal_t *current_journal = NULL;
69 static void journal_dump_trans(journal_transaction_t *trans EXT2FS_ATTR((unused)),
70 const char *tag EXT2FS_ATTR((unused)))
72 dbg_printf("TRANS %p(%s): tid=%d start=%llu block=%llu end=%llu "
73 "flags=0x%x\n", trans, tag, trans->tid, trans->start,
74 trans->block, trans->end, trans->flags);
77 static errcode_t journal_commit_trans(journal_transaction_t *trans)
79 struct buffer_head *bh, *cbh = NULL;
80 struct commit_header *commit;
81 #ifdef HAVE_SYS_TIME_H
86 JOURNAL_CHECK_TRANS_MAGIC(trans);
88 if ((trans->flags & J_TRANS_COMMITTED) ||
89 !(trans->flags & J_TRANS_OPEN))
90 return EXT2_ET_INVALID_ARGUMENT;
92 bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize);
96 /* write the descriptor block header */
97 commit = (struct commit_header *)bh->b_data;
98 commit->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
99 commit->h_blocktype = ext2fs_cpu_to_be32(JFS_COMMIT_BLOCK);
100 commit->h_sequence = ext2fs_cpu_to_be32(trans->tid);
101 if (JFS_HAS_COMPAT_FEATURE(trans->journal,
102 JFS_FEATURE_COMPAT_CHECKSUM)) {
106 cbh = getblk(trans->journal->j_dev, 0,
107 trans->journal->j_blocksize);
113 for (cblk = trans->start; cblk < trans->block; cblk++) {
114 err = journal_bmap(trans->journal, cblk,
118 mark_buffer_uptodate(cbh, 0);
119 ll_rw_block(READ, 1, &cbh);
123 csum_v1 = ext2fs_crc32_be(csum_v1,
124 (unsigned char const *)cbh->b_data,
128 commit->h_chksum_type = JFS_CRC32_CHKSUM;
129 commit->h_chksum_size = JFS_CRC32_CHKSUM_SIZE;
130 commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1);
132 commit->h_chksum_type = 0;
133 commit->h_chksum_size = 0;
134 commit->h_chksum[0] = 0;
136 #ifdef HAVE_SYS_TIME_H
137 gettimeofday(&tv, NULL);
138 commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec);
139 commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000);
141 commit->h_commit_sec = 0;
142 commit->h_commit_nsec = 0;
146 jbd2_commit_block_csum_set(trans->journal, bh);
147 err = journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
151 dbg_printf("Writing commit block at %llu:%llu\n", trans->block,
153 mark_buffer_dirty(bh);
154 ll_rw_block(WRITE, 1, &bh);
158 trans->flags |= J_TRANS_COMMITTED;
159 trans->flags &= ~J_TRANS_OPEN;
162 trans->fs->super->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
163 ext2fs_mark_super_dirty(trans->fs);
171 static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans,
172 blk64_t *revoke_list,
175 journal_revoke_header_t *jrb;
179 int sz, csum_size = 0;
180 struct buffer_head *bh;
183 JOURNAL_CHECK_TRANS_MAGIC(trans);
185 if ((trans->flags & J_TRANS_COMMITTED) ||
186 !(trans->flags & J_TRANS_OPEN))
187 return EXT2_ET_INVALID_ARGUMENT;
192 /* Do we need to leave space at the end for a checksum? */
193 if (journal_has_csum_v2or3(trans->journal))
194 csum_size = sizeof(struct journal_revoke_tail);
196 curr_blk = trans->block;
198 bh = getblk(trans->journal->j_dev, curr_blk,
199 trans->journal->j_blocksize);
202 jrb = buf = bh->b_data;
203 jrb->r_header.h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
204 jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK);
205 jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid);
206 offset = sizeof(*jrb);
208 if (JFS_HAS_INCOMPAT_FEATURE(trans->journal,
209 JFS_FEATURE_INCOMPAT_64BIT))
214 for (i = 0; i < revoke_len; i++) {
215 /* Block full, write to journal */
216 if (offset + sz > trans->journal->j_blocksize - csum_size) {
217 jrb->r_count = ext2fs_cpu_to_be32(offset);
218 jbd2_revoke_csum_set(trans->journal, bh);
220 err = journal_bmap(trans->journal, curr_blk,
224 dbg_printf("Writing revoke block at %llu:%llu\n",
225 curr_blk, bh->b_blocknr);
226 mark_buffer_dirty(bh);
227 ll_rw_block(WRITE, 1, &bh);
232 offset = sizeof(*jrb);
236 if (revoke_list[i] >=
237 ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
238 err = EXT2_ET_BAD_BLOCK_NUM;
242 if (JFS_HAS_INCOMPAT_FEATURE(trans->journal,
243 JFS_FEATURE_INCOMPAT_64BIT))
244 *((__u64 *)(&((char *)buf)[offset])) =
245 ext2fs_cpu_to_be64(revoke_list[i]);
247 *((__u32 *)(&((char *)buf)[offset])) =
248 ext2fs_cpu_to_be32(revoke_list[i]);
253 jrb->r_count = ext2fs_cpu_to_be32(offset);
254 jbd2_revoke_csum_set(trans->journal, bh);
256 err = journal_bmap(trans->journal, curr_blk, &bh->b_blocknr);
259 dbg_printf("Writing revoke block at %llu:%llu\n",
260 curr_blk, bh->b_blocknr);
261 mark_buffer_dirty(bh);
262 ll_rw_block(WRITE, 1, &bh);
270 trans->block = curr_blk;
275 static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans,
276 blk64_t *block_list, size_t block_len,
279 blk64_t curr_blk, jdb_blk;
282 journal_header_t *jdb;
283 journal_block_tag_t *jdbt;
285 void *buf = NULL, *jdb_buf = NULL;
286 struct buffer_head *bh = NULL, *data_bh;
289 JOURNAL_CHECK_TRANS_MAGIC(trans);
291 if ((trans->flags & J_TRANS_COMMITTED) ||
292 !(trans->flags & J_TRANS_OPEN))
293 return EXT2_ET_INVALID_ARGUMENT;
298 /* Do we need to leave space at the end for a checksum? */
299 if (journal_has_csum_v2or3(trans->journal))
300 csum_size = sizeof(struct journal_block_tail);
302 curr_blk = jdb_blk = trans->block;
304 data_bh = getblk(trans->journal->j_dev, curr_blk,
305 trans->journal->j_blocksize);
308 buf = data_bh->b_data;
310 /* write the descriptor block header */
311 bh = getblk(trans->journal->j_dev, curr_blk,
312 trans->journal->j_blocksize);
317 jdb = jdb_buf = bh->b_data;
318 jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER);
319 jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK);
320 jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid);
321 jdbt = (journal_block_tag_t *)(jdb + 1);
324 for (i = 0; i < block_len; i++) {
325 j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp);
331 tag_bytes = journal_tag_bytes(trans->journal);
333 /* No space left in descriptor block, write it out */
334 if ((char *)jdbt + tag_bytes >
335 (char *)jdb_buf + trans->journal->j_blocksize - csum_size) {
336 jbd2_descr_block_csum_set(trans->journal, bh);
337 err = journal_bmap(trans->journal, jdb_blk,
341 dbg_printf("Writing descriptor block at %llu:%llu\n",
342 jdb_blk, bh->b_blocknr);
343 mark_buffer_dirty(bh);
344 ll_rw_block(WRITE, 1, &bh);
349 jdbt = (journal_block_tag_t *)(jdb + 1);
355 ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
356 err = EXT2_ET_BAD_BLOCK_NUM;
360 /* Fill out the block tag */
361 jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF);
363 if (jdbt != (journal_block_tag_t *)(jdb + 1))
364 jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID);
366 memcpy(jdbt + tag_bytes,
367 trans->journal->j_superblock->s_uuid,
368 sizeof(trans->journal->j_superblock->s_uuid));
371 if (i == block_len - 1)
372 jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG);
373 if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
375 jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE);
377 if (JFS_HAS_INCOMPAT_FEATURE(trans->journal,
378 JFS_FEATURE_INCOMPAT_64BIT))
379 jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32);
380 jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh,
383 /* Write the data block */
384 err = journal_bmap(trans->journal, curr_blk,
385 &data_bh->b_blocknr);
388 dbg_printf("Writing data block %llu at %llu:%llu tag %d\n",
389 block_list[i], curr_blk, data_bh->b_blocknr,
391 mark_buffer_dirty(data_bh);
392 ll_rw_block(WRITE, 1, &data_bh);
393 err = data_bh->b_err;
398 jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes);
401 /* Write out the last descriptor block */
402 if (jdbt != (journal_block_tag_t *)(jdb + 1)) {
403 jbd2_descr_block_csum_set(trans->journal, bh);
404 err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr);
407 dbg_printf("Writing descriptor block at %llu:%llu\n",
408 jdb_blk, bh->b_blocknr);
409 mark_buffer_dirty(bh);
410 ll_rw_block(WRITE, 1, &bh);
417 trans->block = curr_blk;
424 static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks,
425 blk64_t revoke_blocks)
430 /* Estimate # of revoke blocks */
431 bs = journal->j_blocksize;
432 if (journal_has_csum_v2or3(journal))
433 bs -= sizeof(struct journal_revoke_tail);
434 sz = JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) ?
435 sizeof(__u64) : sizeof(__u32);
436 ret += revoke_blocks * sz / bs;
438 /* Estimate # of data blocks */
439 bs = journal->j_blocksize - 16;
440 if (journal_has_csum_v2or3(journal))
441 bs -= sizeof(struct journal_block_tail);
442 sz = journal_tag_bytes(journal);
443 ret += data_blocks * sz / bs;
450 static errcode_t journal_open_trans(journal_t *journal,
451 journal_transaction_t *trans,
454 trans->fs = journal->j_fs_dev->k_fs;
455 trans->journal = journal;
456 trans->flags = J_TRANS_OPEN;
458 if (journal->j_tail == 0) {
459 /* Clean journal, start at the tail */
460 trans->tid = journal->j_tail_sequence;
461 trans->start = journal->j_first;
463 /* Put new transaction at the head of the list */
464 trans->tid = journal->j_transaction_sequence;
465 trans->start = journal->j_head;
468 trans->block = trans->start;
469 if (trans->start + blocks > journal->j_last)
471 trans->end = trans->block + blocks;
472 journal_dump_trans(trans, "new transaction");
474 trans->magic = J_TRANS_MAGIC;
478 static errcode_t journal_close_trans(journal_transaction_t *trans)
482 JOURNAL_CHECK_TRANS_MAGIC(trans);
484 if (!(trans->flags & J_TRANS_COMMITTED))
487 journal = trans->journal;
488 if (journal->j_tail == 0) {
489 /* Update the tail */
490 journal->j_tail_sequence = trans->tid;
491 journal->j_tail = trans->start;
492 journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start);
495 /* Update the head */
496 journal->j_head = trans->end + 1;
497 journal->j_transaction_sequence = trans->tid + 1;
501 /* Mark ourselves as needing recovery */
502 if (!(EXT2_HAS_INCOMPAT_FEATURE(trans->fs->super,
503 EXT3_FEATURE_INCOMPAT_RECOVER))) {
504 trans->fs->super->s_feature_incompat |=
505 EXT3_FEATURE_INCOMPAT_RECOVER;
506 ext2fs_mark_super_dirty(trans->fs);
512 #define JOURNAL_WRITE_NO_COMMIT 1
513 static errcode_t journal_write(journal_t *journal,
514 int flags, blk64_t *block_list,
515 size_t block_len, blk64_t *revoke_list,
516 size_t revoke_len, FILE *fp)
519 journal_transaction_t trans;
522 if (revoke_len > 0) {
523 journal->j_superblock->s_feature_incompat |=
524 ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_REVOKE);
525 mark_buffer_dirty(journal->j_sb_buffer);
528 blocks = journal_guess_blocks(journal, block_len, revoke_len);
529 err = journal_open_trans(journal, &trans, blocks);
533 err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp);
537 err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len);
541 if (!(flags & JOURNAL_WRITE_NO_COMMIT)) {
542 err = journal_commit_trans(&trans);
547 err = journal_close_trans(&trans);
554 void do_journal_write(int argc, char *argv[])
556 blk64_t *blist = NULL, *rlist = NULL;
557 size_t bn = 0, rn = 0;
563 if (current_journal == NULL) {
564 printf("Journal not open.\n");
569 while ((opt = getopt(argc, argv, "b:r:c")) != -1) {
572 err = read_list(optarg, &blist, &bn);
574 com_err(argv[0], err,
575 "while reading block list");
578 err = read_list(optarg, &rlist, &rn);
580 com_err(argv[0], err,
581 "while reading revoke list");
584 flags |= JOURNAL_WRITE_NO_COMMIT;
587 printf("%s [-b blocks] [-r revoke] [-c] file\n",
589 printf("-b: Write these blocks into transaction.\n");
590 printf("-c: Do not commit transaction.\n");
591 printf("-r: Revoke these blocks from transaction.\n");
597 if (bn > 0 && optind != argc - 1) {
598 printf("Need a file to read blocks from.\n");
603 fp = fopen(argv[optind], "r");
605 com_err(argv[0], errno,
606 "while opening journal data file");
611 err = journal_write(current_journal, flags, blist, bn,
614 com_err("journal_write", err, "while writing journal");
625 /* Make sure we wrap around the log correctly! */
626 #define wrap(journal, var) \
628 if (var >= (journal)->j_last) \
629 var -= ((journal)->j_last - (journal)->j_first); \
633 * Count the number of in-use tags in a journal descriptor block.
636 static int count_tags(journal_t *journal, char *buf)
639 journal_block_tag_t *tag;
640 int nr = 0, size = journal->j_blocksize;
641 int tag_bytes = journal_tag_bytes(journal);
643 if (journal_has_csum_v2or3(journal))
644 size -= sizeof(struct journal_block_tail);
646 tagp = buf + sizeof(journal_header_t);
648 while ((tagp - buf + tag_bytes) <= size) {
649 tag = (journal_block_tag_t *) tagp;
653 if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID)))
656 if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG))
663 errcode_t journal_find_head(journal_t *journal)
665 unsigned int next_commit_ID;
666 blk64_t next_log_block, head_block;
668 journal_superblock_t *sb;
669 journal_header_t *tmp;
670 struct buffer_head *bh;
671 unsigned int sequence;
675 * First thing is to establish what we expect to find in the log
676 * (in terms of transaction IDs), and where (in terms of log
677 * block offsets): query the superblock.
680 sb = journal->j_superblock;
681 next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
682 next_log_block = ext2fs_be32_to_cpu(sb->s_start);
683 head_block = next_log_block;
685 if (next_log_block == 0)
688 bh = getblk(journal->j_dev, 0, journal->j_blocksize);
693 * Now we walk through the log, transaction by transaction,
694 * making sure that each transaction has a commit block in the
695 * expected place. Each complete transaction gets replayed back
696 * into the main filesystem.
699 dbg_printf("Scanning for sequence ID %u at %lu/%lu\n",
700 next_commit_ID, (unsigned long)next_log_block,
703 /* Skip over each chunk of the transaction looking
704 * either the next descriptor block or the final commit
706 err = journal_bmap(journal, next_log_block, &bh->b_blocknr);
709 mark_buffer_uptodate(bh, 0);
710 ll_rw_block(READ, 1, &bh);
716 wrap(journal, next_log_block);
718 /* What kind of buffer is it?
720 * If it is a descriptor block, check that it has the
721 * expected sequence number. Otherwise, we're all done
724 tmp = (journal_header_t *)bh->b_data;
726 if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) {
727 dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
731 blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
732 sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
733 dbg_printf("Found magic %d, sequence %d\n",
734 blocktype, sequence);
736 if (sequence != next_commit_ID) {
737 dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n",
738 sequence, next_commit_ID);
742 /* OK, we have a valid descriptor block which matches
743 * all of the sequence number checks. What are we going
744 * to do with it? That depends on the pass... */
747 case JFS_DESCRIPTOR_BLOCK:
748 next_log_block += count_tags(journal, bh->b_data);
749 wrap(journal, next_log_block);
752 case JFS_COMMIT_BLOCK:
753 head_block = next_log_block;
757 case JFS_REVOKE_BLOCK:
761 dbg_printf("Unrecognised magic %d, end of scan.\n",
770 dbg_printf("head seq=%d blk=%llu\n", next_commit_ID,
772 journal->j_transaction_sequence = next_commit_ID;
773 journal->j_head = head_block;
779 static void update_journal_csum(journal_t *journal, int ver)
781 journal_superblock_t *jsb;
783 if (journal->j_format_version < 2)
786 if (journal->j_tail != 0 ||
787 EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
788 EXT3_FEATURE_INCOMPAT_RECOVER)) {
789 printf("Journal needs recovery, will not add csums.\n");
793 /* metadata_csum implies journal csum v3 */
794 jsb = journal->j_superblock;
795 if (EXT2_HAS_RO_COMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
796 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
797 printf("Setting csum v%d\n", ver);
800 journal->j_superblock->s_feature_incompat &=
801 ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V3);
802 journal->j_superblock->s_feature_incompat |=
803 ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2);
804 journal->j_superblock->s_feature_compat &=
805 ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM);
808 journal->j_superblock->s_feature_incompat &=
809 ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V2);
810 journal->j_superblock->s_feature_incompat |=
811 ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3);
812 journal->j_superblock->s_feature_compat &=
813 ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM);
816 printf("Unknown checksum v%d\n", ver);
819 journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
820 journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
821 sizeof(jsb->s_uuid));
823 journal->j_superblock->s_feature_compat |=
824 ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM);
825 journal->j_superblock->s_feature_incompat &=
826 ext2fs_cpu_to_be32(~(JFS_FEATURE_INCOMPAT_CSUM_V2 |
827 JFS_FEATURE_INCOMPAT_CSUM_V3));
831 static void update_uuid(journal_t *journal)
836 if (journal->j_format_version < 2)
839 for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
840 if (journal->j_superblock->s_uuid[z])
845 fs = journal->j_fs_dev->k_fs;
846 if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
847 EXT4_FEATURE_INCOMPAT_64BIT))
850 if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) &&
851 EXT2_HAS_INCOMPAT_FEATURE(fs->super,
852 EXT4_FEATURE_INCOMPAT_64BIT))
855 if (journal->j_tail != 0 ||
856 EXT2_HAS_INCOMPAT_FEATURE(fs->super,
857 EXT3_FEATURE_INCOMPAT_RECOVER)) {
858 printf("Journal needs recovery, will not set 64bit.\n");
862 memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
863 sizeof(fs->super->s_uuid));
866 static void update_64bit_flag(journal_t *journal)
868 if (journal->j_format_version < 2)
871 if (!EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
872 EXT4_FEATURE_INCOMPAT_64BIT))
875 if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) &&
876 EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
877 EXT4_FEATURE_INCOMPAT_64BIT))
880 if (journal->j_tail != 0 ||
881 EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super,
882 EXT3_FEATURE_INCOMPAT_RECOVER)) {
883 printf("Journal needs recovery, will not set 64bit.\n");
887 journal->j_superblock->s_feature_incompat |=
888 ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_64BIT);
891 void do_journal_open(int argc, char *argv[])
893 int opt, enable_csum = 0, csum_ver = 3;
897 if (check_fs_open(argv[0]))
899 if (check_fs_read_write(argv[0]))
901 if (check_fs_bitmaps(argv[0]))
903 if (current_journal) {
904 printf("Journal is already open.\n");
907 if (!EXT2_HAS_COMPAT_FEATURE(current_fs->super,
908 EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
909 printf("Journalling is not enabled on this filesystem.\n");
914 while ((opt = getopt(argc, argv, "cv:f:")) != -1) {
920 if (current_fs->journal_name)
921 free(current_fs->journal_name);
922 current_fs->journal_name = strdup(optarg);
925 csum_ver = atoi(optarg);
926 if (csum_ver != 2 && csum_ver != 3) {
927 printf("Unknown journal csum v%d\n", csum_ver);
932 printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]);
933 printf("-c: Enable journal checksumming.\n");
934 printf("-v: Use this version checksum format.\n");
935 printf("-j: Load this external journal.\n");
939 err = ext2fs_open_journal(current_fs, ¤t_journal);
941 com_err(argv[0], err, "while opening journal");
944 journal = current_journal;
946 dbg_printf("JOURNAL: seq=%d tailseq=%d start=%lu first=%lu "
947 "maxlen=%lu\n", journal->j_tail_sequence,
948 journal->j_transaction_sequence, journal->j_tail,
949 journal->j_first, journal->j_last);
951 update_uuid(journal);
952 update_64bit_flag(journal);
954 update_journal_csum(journal, csum_ver);
956 err = journal_find_head(journal);
958 com_err(argv[0], err, "while examining journal");
961 void do_journal_close(int argc EXT2FS_ATTR((unused)),
962 char *argv[] EXT2FS_ATTR((unused)))
964 if (current_journal == NULL) {
965 printf("Journal not open.\n");
969 ext2fs_close_journal(current_fs, ¤t_journal);
972 void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[])
976 if (check_fs_open(argv[0]))
978 if (check_fs_read_write(argv[0]))
980 if (check_fs_bitmaps(argv[0]))
982 if (current_journal) {
983 printf("Please close the journal before recovering it.\n");
987 err = ext2fs_run_ext3_journal(¤t_fs);
989 com_err("journal_run", err, "while recovering journal");
991 current_fs->super->s_feature_incompat &=
992 ~EXT3_FEATURE_INCOMPAT_RECOVER;
993 ext2fs_mark_super_dirty(current_fs);