6 #include "ext4_config.h"
7 #include "ext4_types.h"
9 #include "ext4_super.h"
10 #include "ext4_errno.h"
11 #include "ext4_blockdev.h"
12 #include "ext4_crc32c.h"
13 #include "ext4_debug.h"
19 int jbd_inode_bmap(struct jbd_fs *jbd_fs,
21 ext4_fsblk_t *fblock);
23 int jbd_sb_write(struct jbd_fs *jbd_fs, struct jbd_sb *s)
26 struct ext4_fs *fs = jbd_fs->inode_ref.fs;
29 rc = jbd_inode_bmap(jbd_fs, 0, &fblock);
33 offset = fblock * ext4_sb_get_block_size(&fs->sb);
34 return ext4_block_writebytes(fs->bdev, offset, s,
35 EXT4_SUPERBLOCK_SIZE);
38 int jbd_sb_read(struct jbd_fs *jbd_fs, struct jbd_sb *s)
41 struct ext4_fs *fs = jbd_fs->inode_ref.fs;
44 rc = jbd_inode_bmap(jbd_fs, 0, &fblock);
48 offset = fblock * ext4_sb_get_block_size(&fs->sb);
49 return ext4_block_readbytes(fs->bdev, offset, s,
50 EXT4_SUPERBLOCK_SIZE);
53 static bool jbd_verify_sb(struct jbd_sb *sb)
55 struct jbd_bhdr *header = &sb->header;
56 if (jbd_get32(header, magic) != JBD_MAGIC_NUMBER)
59 if (jbd_get32(header, blocktype) != JBD_SUPERBLOCK &&
60 jbd_get32(header, blocktype) != JBD_SUPERBLOCK_V2)
66 int jbd_get_fs(struct ext4_fs *fs,
67 struct jbd_fs *jbd_fs)
72 memset(jbd_fs, 0, sizeof(struct jbd_fs));
73 journal_ino = ext4_get32(&fs->sb, journal_inode_number);
75 rc = ext4_fs_get_inode_ref(fs,
79 memset(jbd_fs, 0, sizeof(struct jbd_fs));
82 rc = jbd_sb_read(jbd_fs, &jbd_fs->sb);
84 memset(jbd_fs, 0, sizeof(struct jbd_fs));
85 ext4_fs_put_inode_ref(&jbd_fs->inode_ref);
91 int jbd_put_fs(struct jbd_fs *jbd_fs)
94 rc = ext4_fs_put_inode_ref(&jbd_fs->inode_ref);
98 int jbd_inode_bmap(struct jbd_fs *jbd_fs,
100 ext4_fsblk_t *fblock)
102 int rc = ext4_fs_get_inode_data_block_index(
110 int jbd_block_get(struct jbd_fs *jbd_fs,
111 struct ext4_block *block,
114 /* TODO: journal device. */
116 ext4_lblk_t iblock = (ext4_lblk_t)fblock;
117 rc = jbd_inode_bmap(jbd_fs, iblock,
122 struct ext4_blockdev *bdev = jbd_fs->inode_ref.fs->bdev;
123 rc = ext4_block_get(bdev, block, fblock);
127 int jbd_block_get_noread(struct jbd_fs *jbd_fs,
128 struct ext4_block *block,
131 /* TODO: journal device. */
133 ext4_lblk_t iblock = (ext4_lblk_t)fblock;
134 rc = jbd_inode_bmap(jbd_fs, iblock,
139 struct ext4_blockdev *bdev = jbd_fs->inode_ref.fs->bdev;
140 rc = ext4_block_get_noread(bdev, block, fblock);
144 int jbd_block_set(struct jbd_fs *jbd_fs,
145 struct ext4_block *block)
147 return ext4_block_set(jbd_fs->inode_ref.fs->bdev,
152 * helper functions to deal with 32 or 64bit block numbers.
154 int jbd_tag_bytes(struct jbd_fs *jbd_fs)
158 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
159 JBD_FEATURE_INCOMPAT_CSUM_V3))
160 return sizeof(struct jbd_block_tag3);
162 size = sizeof(struct jbd_block_tag);
164 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
165 JBD_FEATURE_INCOMPAT_CSUM_V2))
166 size += sizeof(uint16_t);
168 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
169 JBD_FEATURE_INCOMPAT_64BIT))
172 return size - sizeof(uint32_t);
176 jbd_extract_block_tag(struct jbd_fs *jbd_fs,
187 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
188 JBD_FEATURE_INCOMPAT_CSUM_V3)) {
189 struct jbd_block_tag3 *tag = __tag;
190 *block = jbd_get32(tag, blocknr);
191 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
192 JBD_FEATURE_INCOMPAT_64BIT))
193 *block |= (uint64_t)jbd_get32(tag, blocknr_high) << 32;
195 if (jbd_get32(tag, flags) & JBD_FLAG_ESCAPE)
198 if (!(jbd_get32(tag, flags) & JBD_FLAG_SAME_UUID)) {
199 uuid_start = (char *)tag + tag_bytes;
201 memcpy(uuid, uuid_start, UUID_SIZE);
204 if (jbd_get32(tag, flags) & JBD_FLAG_LAST_TAG)
208 struct jbd_block_tag *tag = __tag;
209 *block = jbd_get32(tag, blocknr);
210 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
211 JBD_FEATURE_INCOMPAT_64BIT))
212 *block |= (uint64_t)jbd_get32(tag, blocknr_high) << 32;
214 if (jbd_get16(tag, flags) & JBD_FLAG_ESCAPE)
217 if (!(jbd_get16(tag, flags) & JBD_FLAG_SAME_UUID)) {
218 uuid_start = (char *)tag + tag_bytes;
220 memcpy(uuid, uuid_start, UUID_SIZE);
223 if (jbd_get16(tag, flags) & JBD_FLAG_LAST_TAG)
230 jbd_iterate_block_table(struct jbd_fs *jbd_fs,
232 uint32_t tag_tbl_size,
233 void (*func)(struct jbd_fs * jbd_fs,
239 ext4_fsblk_t block = 0;
240 uint8_t uuid[UUID_SIZE];
241 char *tag_start, *tag_ptr;
242 uint32_t tag_bytes = jbd_tag_bytes(jbd_fs);
243 tag_start = __tag_start;
246 if (JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
247 JBD_FEATURE_INCOMPAT_CSUM_V2) ||
248 JBD_HAS_INCOMPAT_FEATURE(&jbd_fs->sb,
249 JBD_FEATURE_INCOMPAT_CSUM_V3))
250 tag_tbl_size -= sizeof(struct jbd_block_tail);
252 while (tag_ptr - tag_start + tag_bytes <= tag_tbl_size) {
255 jbd_extract_block_tag(jbd_fs,
263 func(jbd_fs, block, uuid, arg);
268 tag_ptr += tag_bytes;
270 tag_ptr += UUID_SIZE;
275 static void jbd_display_block_tags(struct jbd_fs *jbd_fs,
280 uint32_t *iblock = arg;
281 ext4_dbg(DEBUG_JBD, "Block in block_tag: %" PRIu64 "\n", block);
288 struct revoke_entry {
291 RB_ENTRY(revoke_entry) revoke_node;
294 /* Make sure we wrap around the log correctly! */
295 #define wrap(sb, var) \
297 if (var >= jbd_get32((sb), maxlen)) \
298 var -= (jbd_get32((sb), maxlen) - jbd_get32((sb), first)); \
301 #define ACTION_SCAN 0
302 #define ACTION_REVOKE 1
303 #define ACTION_RECOVER 2
305 struct recover_info {
306 uint32_t start_trans_id;
307 uint32_t last_trans_id;
308 RB_HEAD(jbd_revoke, revoke_entry) revoke_root;
311 static void jbd_build_revoke_root(struct jbd_fs *jbd_fs,
312 struct jbd_bhdr *header,
313 struct recover_info *info)
315 struct jbd_revoke_header *revoke_hdr =
316 (struct jbd_revoke_header *)header;
318 jbd_iterate_block_table(jbd_fs,
320 jbd_get32(&jbd_fs->sb, blocksize) -
321 sizeof(struct jbd_revoke_header),
322 jbd_display_block_tags,
328 static void jbd_debug_descriptor_block(struct jbd_fs *jbd_fs,
329 struct jbd_bhdr *header,
332 jbd_iterate_block_table(jbd_fs,
334 jbd_get32(&jbd_fs->sb, blocksize) -
335 sizeof(struct jbd_bhdr),
336 jbd_display_block_tags,
340 int jbd_iterate_log(struct jbd_fs *jbd_fs,
341 struct recover_info *info,
345 bool log_end = false;
346 struct jbd_sb *sb = &jbd_fs->sb;
347 uint32_t start_trans_id, this_trans_id;
348 uint32_t start_block, this_block;
350 start_trans_id = this_trans_id = jbd_get32(sb, sequence);
351 start_block = this_block = jbd_get32(sb, start);
353 ext4_dbg(DEBUG_JBD, "Start of journal at trans id: %" PRIu32 "\n",
357 struct ext4_block block;
358 struct jbd_bhdr *header;
359 if (action != ACTION_SCAN)
360 if (this_trans_id > info->last_trans_id) {
365 r = jbd_block_get(jbd_fs, &block, this_block);
369 header = (struct jbd_bhdr *)block.data;
370 if (jbd_get32(header, magic) != JBD_MAGIC_NUMBER) {
371 jbd_block_set(jbd_fs, &block);
376 if (jbd_get32(header, sequence) != this_trans_id) {
377 if (action != ACTION_SCAN)
380 jbd_block_set(jbd_fs, &block);
385 switch (jbd_get32(header, blocktype)) {
386 case JBD_DESCRIPTOR_BLOCK:
387 ext4_dbg(DEBUG_JBD, "Descriptor block: %u, "
389 this_block, this_trans_id);
390 jbd_debug_descriptor_block(jbd_fs, header, &this_block);
392 case JBD_COMMIT_BLOCK:
393 ext4_dbg(DEBUG_JBD, "Commit block: %u, "
395 this_block, this_trans_id);
398 case JBD_REVOKE_BLOCK:
399 ext4_dbg(DEBUG_JBD, "Revoke block: %u, "
401 this_block, this_trans_id);
402 jbd_build_revoke_root(jbd_fs, header, info);
408 jbd_block_set(jbd_fs, &block);
410 wrap(sb, this_block);
411 if (this_block == start_block)
415 ext4_dbg(DEBUG_JBD, "End of journal.\n");
416 if (r == EOK && action == ACTION_SCAN) {
417 info->start_trans_id = start_trans_id;
418 if (this_trans_id > start_trans_id)
419 info->last_trans_id = this_trans_id - 1;
421 info->last_trans_id = this_trans_id;
427 int jbd_recover(struct jbd_fs *jbd_fs)
430 struct recover_info info;
431 struct jbd_sb *sb = &jbd_fs->sb;
435 r = jbd_iterate_log(jbd_fs, &info, ACTION_SCAN);