+static inline size_t journal_super_tag_bytes(journal_superblock_t *jsb)
+{
+ size_t sz;
+
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+ return sizeof(journal_block_tag3_t);
+
+ sz = sizeof(journal_block_tag_t);
+
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+ sz += sizeof(__u16);
+
+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_64BIT))
+ return sz;
+
+ return sz - sizeof(__u32);
+}
+
+static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
+ int transaction, int *fc_done, int dump_old)
+{
+ struct ext4_fc_tl tl;
+ struct ext4_fc_head *head;
+ struct ext4_fc_add_range *add_range;
+ struct ext4_fc_del_range *del_range;
+ struct ext4_fc_dentry_info *dentry_info;
+ struct ext4_fc_tail *tail;
+ struct ext3_extent *ex;
+ __u8 *cur, *val;
+
+ *fc_done = 0;
+ for (cur = (__u8 *)buf; cur < (__u8 *)buf + blocksize;
+ cur = cur + sizeof(tl) + le16_to_cpu(tl.fc_len)) {
+ memcpy(&tl, cur, sizeof(tl));
+ val = cur + sizeof(tl);
+
+ switch (le16_to_cpu(tl.fc_tag)) {
+ case EXT4_FC_TAG_ADD_RANGE:
+ add_range = (struct ext4_fc_add_range *)val;
+ ex = (struct ext3_extent *)add_range->fc_ex;
+ fprintf(out_file,
+ "tag %s, inode %d, lblk %u, pblk %llu, len %lu\n",
+ tag2str(tl.fc_tag),
+ le32_to_cpu(add_range->fc_ino),
+ le32_to_cpu(ex->ee_block),
+ le32_to_cpu(ex->ee_start) +
+ (((unsigned long long) le16_to_cpu(ex->ee_start_hi)) << 32),
+ le16_to_cpu(ex->ee_len) > EXT_INIT_MAX_LEN ?
+ le16_to_cpu(ex->ee_len) - EXT_INIT_MAX_LEN :
+ le16_to_cpu(ex->ee_len));
+ break;
+ case EXT4_FC_TAG_DEL_RANGE:
+ del_range = (struct ext4_fc_del_range *)val;
+ fprintf(out_file, "tag %s, inode %d, lblk %d, len %d\n",
+ tag2str(tl.fc_tag),
+ le32_to_cpu(del_range->fc_ino),
+ le32_to_cpu(del_range->fc_lblk),
+ le32_to_cpu(del_range->fc_len));
+ break;
+ case EXT4_FC_TAG_LINK:
+ case EXT4_FC_TAG_UNLINK:
+ case EXT4_FC_TAG_CREAT:
+ dentry_info = (struct ext4_fc_dentry_info *)val;
+ fprintf(out_file,
+ "tag %s, parent %d, ino %d, name \"%s\"\n",
+ tag2str(tl.fc_tag),
+ le32_to_cpu(dentry_info->fc_parent_ino),
+ le32_to_cpu(dentry_info->fc_ino),
+ dentry_info->fc_dname);
+ break;
+ case EXT4_FC_TAG_INODE:
+ fprintf(out_file, "tag %s, inode %d\n",
+ tag2str(tl.fc_tag),
+ le32_to_cpu(((struct ext4_fc_inode *)val)->fc_ino));
+ break;
+ case EXT4_FC_TAG_PAD:
+ fprintf(out_file, "tag %s\n", tag2str(tl.fc_tag));
+ break;
+ case EXT4_FC_TAG_TAIL:
+ tail = (struct ext4_fc_tail *)val;
+ fprintf(out_file, "tag %s, tid %d\n",
+ tag2str(tl.fc_tag),
+ le32_to_cpu(tail->fc_tid));
+ if (!dump_old &&
+ le32_to_cpu(tail->fc_tid) < transaction) {
+ *fc_done = 1;
+ return;
+ }
+ break;
+ case EXT4_FC_TAG_HEAD:
+ fprintf(out_file, "\n*** Fast Commit Area ***\n");
+ head = (struct ext4_fc_head *)val;
+ fprintf(out_file, "tag %s, features 0x%x, tid %d\n",
+ tag2str(tl.fc_tag),
+ le32_to_cpu(head->fc_features),
+ le32_to_cpu(head->fc_tid));
+ if (!dump_old &&
+ le32_to_cpu(head->fc_tid) < transaction) {
+ *fc_done = 1;
+ return;
+ }
+ break;
+ default:
+ *fc_done = 1;
+ break;
+ }
+ }
+}