1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2011 - 2012 Samsung Electronics
4 * EXT4 filesystem implementation in Uboot by
5 * Uma Shankar <uma.shankar@samsung.com>
6 * Manjunatha C Achar <a.manjunatha@samsung.com>
7 *
8 * Journal data structures and headers for Journaling feature of ext4
9 * have been referred from JBD2 (Journaling Block device 2)
10 * implementation in Linux Kernel.
11 * Written by Stephen C. Tweedie <sct@redhat.com>
12 *
13 * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
14 */
15
16#include <common.h>
17#include <blk.h>
18#include <ext4fs.h>
19#include <log.h>
20#include <malloc.h>
21#include <ext_common.h>
22#include "ext4_common.h"
23
24static struct revoke_blk_list *revk_blk_list;
25static struct revoke_blk_list *prev_node;
26static int first_node = true;
27
28int gindex;
29int gd_index;
30int jrnl_blk_idx;
31struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
32struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
33
34int ext4fs_init_journal(void)
35{
36	int i;
37	char *temp = NULL;
38	struct ext_filesystem *fs = get_fs();
39
40	/* init globals */
41	revk_blk_list = NULL;
42	prev_node = NULL;
43	gindex = 0;
44	gd_index = 0;
45	jrnl_blk_idx = 1;
46
47	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
48		journal_ptr[i] = zalloc(sizeof(struct journal_log));
49		if (!journal_ptr[i])
50			goto fail;
51		dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
52		if (!dirty_block_ptr[i])
53			goto fail;
54		journal_ptr[i]->buf = NULL;
55		journal_ptr[i]->blknr = -1;
56
57		dirty_block_ptr[i]->buf = NULL;
58		dirty_block_ptr[i]->blknr = -1;
59	}
60
61	if (fs->blksz == 4096) {
62		temp = zalloc(fs->blksz);
63		if (!temp)
64			goto fail;
65		journal_ptr[gindex]->buf = zalloc(fs->blksz);
66		if (!journal_ptr[gindex]->buf)
67			goto fail;
68		ext4fs_devread(0, 0, fs->blksz, temp);
69		memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
70		memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
71		journal_ptr[gindex++]->blknr = 0;
72		free(temp);
73	} else {
74		journal_ptr[gindex]->buf = zalloc(fs->blksz);
75		if (!journal_ptr[gindex]->buf)
76			goto fail;
77		memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
78		journal_ptr[gindex++]->blknr = 1;
79	}
80
81	/* Check the file system state using journal super block */
82	if (ext4fs_check_journal_state(SCAN))
83		goto fail;
84	/* Check the file system state using journal super block */
85	if (ext4fs_check_journal_state(RECOVER))
86		goto fail;
87
88	return 0;
89fail:
90	return -1;
91}
92
93void ext4fs_dump_metadata(void)
94{
95	struct ext_filesystem *fs = get_fs();
96	int i;
97	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
98		if (dirty_block_ptr[i]->blknr == -1)
99			break;
100		put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
101				(uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
102								fs->blksz);
103	}
104}
105
106void ext4fs_free_journal(void)
107{
108	int i;
109	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
110		if (dirty_block_ptr[i]->blknr == -1)
111			break;
112		free(dirty_block_ptr[i]->buf);
113	}
114
115	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
116		if (journal_ptr[i]->blknr == -1)
117			break;
118		free(journal_ptr[i]->buf);
119	}
120
121	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
122		free(journal_ptr[i]);
123		free(dirty_block_ptr[i]);
124	}
125	gindex = 0;
126	gd_index = 0;
127	jrnl_blk_idx = 1;
128}
129
130int ext4fs_log_gdt(char *gd_table)
131{
132	struct ext_filesystem *fs = get_fs();
133	short i;
134	long int var = fs->gdtable_blkno;
135	for (i = 0; i < fs->no_blk_pergdt; i++) {
136		journal_ptr[gindex]->buf = zalloc(fs->blksz);
137		if (!journal_ptr[gindex]->buf)
138			return -ENOMEM;
139		memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
140		gd_table += fs->blksz;
141		journal_ptr[gindex++]->blknr = var++;
142	}
143
144	return 0;
145}
146
147/*
148 * This function stores the backup copy of meta data in RAM
149 * journal_buffer -- Buffer containing meta data
150 * blknr -- Block number on disk of the meta data buffer
151 */
152int ext4fs_log_journal(char *journal_buffer, uint32_t blknr)
153{
154	struct ext_filesystem *fs = get_fs();
155	short i;
156
157	if (!journal_buffer) {
158		printf("Invalid input arguments %s\n", __func__);
159		return -EINVAL;
160	}
161
162	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
163		if (journal_ptr[i]->blknr == -1)
164			break;
165		if (journal_ptr[i]->blknr == blknr)
166			return 0;
167	}
168
169	journal_ptr[gindex]->buf = zalloc(fs->blksz);
170	if (!journal_ptr[gindex]->buf)
171		return -ENOMEM;
172
173	memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
174	journal_ptr[gindex++]->blknr = blknr;
175
176	return 0;
177}
178
179/*
180 * This function stores the modified meta data in RAM
181 * metadata_buffer -- Buffer containing meta data
182 * blknr -- Block number on disk of the meta data buffer
183 */
184int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
185{
186	struct ext_filesystem *fs = get_fs();
187	if (!metadata_buffer) {
188		printf("Invalid input arguments %s\n", __func__);
189		return -EINVAL;
190	}
191	if (dirty_block_ptr[gd_index]->buf)
192		assert(dirty_block_ptr[gd_index]->blknr == blknr);
193	else
194		dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
195
196	if (!dirty_block_ptr[gd_index]->buf)
197		return -ENOMEM;
198	memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
199	dirty_block_ptr[gd_index++]->blknr = blknr;
200
201	return 0;
202}
203
204void print_revoke_blks(char *revk_blk)
205{
206	int offset;
207	int max;
208	long int blocknr;
209	struct journal_revoke_header_t *header;
210
211	if (revk_blk == NULL)
212		return;
213
214	header = (struct journal_revoke_header_t *) revk_blk;
215	offset = sizeof(struct journal_revoke_header_t);
216	max = be32_to_cpu(header->r_count);
217	printf("total bytes %d\n", max);
218
219	while (offset < max) {
220		blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
221		printf("revoke blknr is %ld\n", blocknr);
222		offset += 4;
223	}
224}
225
226static struct revoke_blk_list *_get_node(void)
227{
228	struct revoke_blk_list *tmp_node;
229	tmp_node = zalloc(sizeof(struct revoke_blk_list));
230	if (tmp_node == NULL)
231		return NULL;
232	tmp_node->content = NULL;
233	tmp_node->next = NULL;
234
235	return tmp_node;
236}
237
238void ext4fs_push_revoke_blk(char *buffer)
239{
240	struct revoke_blk_list *node = NULL;
241	struct ext_filesystem *fs = get_fs();
242	if (buffer == NULL) {
243		printf("buffer ptr is NULL\n");
244		return;
245	}
246	node = _get_node();
247	if (!node) {
248		printf("_get_node: malloc failed\n");
249		return;
250	}
251
252	node->content = zalloc(fs->blksz);
253	if (node->content == NULL)
254		return;
255	memcpy(node->content, buffer, fs->blksz);
256
257	if (first_node == true) {
258		revk_blk_list = node;
259		prev_node = node;
260		 first_node = false;
261	} else {
262		prev_node->next = node;
263		prev_node = node;
264	}
265}
266
267void ext4fs_free_revoke_blks(void)
268{
269	struct revoke_blk_list *tmp_node = revk_blk_list;
270	struct revoke_blk_list *next_node = NULL;
271
272	while (tmp_node != NULL) {
273		free(tmp_node->content);
274		tmp_node = tmp_node->next;
275	}
276
277	tmp_node = revk_blk_list;
278	while (tmp_node != NULL) {
279		next_node = tmp_node->next;
280		free(tmp_node);
281		tmp_node = next_node;
282	}
283
284	revk_blk_list = NULL;
285	prev_node = NULL;
286	first_node = true;
287}
288
289int check_blknr_for_revoke(long int blknr, int sequence_no)
290{
291	struct journal_revoke_header_t *header;
292	int offset;
293	int max;
294	long int blocknr;
295	char *revk_blk;
296	struct revoke_blk_list *tmp_revk_node = revk_blk_list;
297	while (tmp_revk_node != NULL) {
298		revk_blk = tmp_revk_node->content;
299
300		header = (struct journal_revoke_header_t *) revk_blk;
301		if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
302			offset = sizeof(struct journal_revoke_header_t);
303			max = be32_to_cpu(header->r_count);
304
305			while (offset < max) {
306				blocknr = be32_to_cpu(*((__be32 *)
307						  (revk_blk + offset)));
308				if (blocknr == blknr)
309					goto found;
310				offset += 4;
311			}
312		}
313		tmp_revk_node = tmp_revk_node->next;
314	}
315
316	return -1;
317
318found:
319	return 0;
320}
321
322/*
323 * This function parses the journal blocks and replays the
324 * suceessful transactions. A transaction is successfull
325 * if commit block is found for a descriptor block
326 * The tags in descriptor block contain the disk block
327 * numbers of the metadata  to be replayed
328 */
329void recover_transaction(int prev_desc_logical_no)
330{
331	struct ext2_inode inode_journal;
332	struct ext_filesystem *fs = get_fs();
333	struct journal_header_t *jdb;
334	long int blknr;
335	char *p_jdb;
336	int ofs, flags;
337	int i;
338	struct ext3_journal_block_tag *tag;
339	char *temp_buff = zalloc(fs->blksz);
340	char *metadata_buff = zalloc(fs->blksz);
341	if (!temp_buff || !metadata_buff)
342		goto fail;
343	i = prev_desc_logical_no;
344	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
345			  (struct ext2_inode *)&inode_journal);
346	blknr = read_allocated_block((struct ext2_inode *)
347				     &inode_journal, i, NULL);
348	ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
349		       temp_buff);
350	p_jdb = (char *)temp_buff;
351	jdb = (struct journal_header_t *) temp_buff;
352	ofs = sizeof(struct journal_header_t);
353
354	do {
355		tag = (struct ext3_journal_block_tag *)(p_jdb + ofs);
356		ofs += sizeof(struct ext3_journal_block_tag);
357
358		if (ofs > fs->blksz)
359			break;
360
361		flags = be32_to_cpu(tag->flags);
362		if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
363			ofs += 16;
364
365		i++;
366		debug("\t\ttag %u\n", be32_to_cpu(tag->block));
367		if (revk_blk_list != NULL) {
368			if (check_blknr_for_revoke(be32_to_cpu(tag->block),
369				be32_to_cpu(jdb->h_sequence)) == 0)
370				continue;
371		}
372		blknr = read_allocated_block(&inode_journal, i, NULL);
373		ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
374			       fs->blksz, metadata_buff);
375		put_ext4((uint64_t)((uint64_t)be32_to_cpu(tag->block) * (uint64_t)fs->blksz),
376			 metadata_buff, (uint32_t) fs->blksz);
377	} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
378fail:
379	free(temp_buff);
380	free(metadata_buff);
381}
382
383void print_jrnl_status(int recovery_flag)
384{
385	if (recovery_flag == RECOVER)
386		printf("Journal Recovery Completed\n");
387	else
388		printf("Journal Scan Completed\n");
389}
390
391int ext4fs_check_journal_state(int recovery_flag)
392{
393	int i;
394	int DB_FOUND = NO;
395	long int blknr;
396	int transaction_state = TRANSACTION_COMPLETE;
397	int prev_desc_logical_no = 0;
398	int curr_desc_logical_no = 0;
399	int ofs, flags;
400	struct ext2_inode inode_journal;
401	struct journal_superblock_t *jsb = NULL;
402	struct journal_header_t *jdb = NULL;
403	char *p_jdb = NULL;
404	struct ext3_journal_block_tag *tag = NULL;
405	char *temp_buff = NULL;
406	char *temp_buff1 = NULL;
407	struct ext_filesystem *fs = get_fs();
408
409	if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
410		return 0;
411
412	temp_buff = zalloc(fs->blksz);
413	if (!temp_buff)
414		return -ENOMEM;
415	temp_buff1 = zalloc(fs->blksz);
416	if (!temp_buff1) {
417		free(temp_buff);
418		return -ENOMEM;
419	}
420
421	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
422	blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK,
423				     NULL);
424	ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
425		       temp_buff);
426	jsb = (struct journal_superblock_t *) temp_buff;
427
428	if (le32_to_cpu(fs->sb->feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
429		if (recovery_flag == RECOVER)
430			printf("Recovery required\n");
431	} else {
432		if (recovery_flag == RECOVER)
433			log_debug("File System is consistent\n");
434		goto end;
435	}
436
437	if (be32_to_cpu(jsb->s_start) == 0)
438		goto end;
439
440	if (!(jsb->s_feature_compat &
441				cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
442		jsb->s_feature_compat |=
443				cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
444
445	i = be32_to_cpu(jsb->s_first);
446	while (1) {
447		blknr = read_allocated_block(&inode_journal, i, NULL);
448		memset(temp_buff1, '\0', fs->blksz);
449		ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
450			       0, fs->blksz, temp_buff1);
451		jdb = (struct journal_header_t *) temp_buff1;
452
453		if (be32_to_cpu(jdb->h_blocktype) ==
454		    EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
455			if (be32_to_cpu(jdb->h_sequence) !=
456			    be32_to_cpu(jsb->s_sequence)) {
457				print_jrnl_status(recovery_flag);
458				break;
459			}
460
461			curr_desc_logical_no = i;
462			if (transaction_state == TRANSACTION_COMPLETE)
463				transaction_state = TRANSACTION_RUNNING;
464			else
465				return -1;
466			p_jdb = (char *)temp_buff1;
467			ofs = sizeof(struct journal_header_t);
468			do {
469				tag = (struct ext3_journal_block_tag *)
470				    (p_jdb + ofs);
471				ofs += sizeof(struct ext3_journal_block_tag);
472				if (ofs > fs->blksz)
473					break;
474				flags = be32_to_cpu(tag->flags);
475				if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
476					ofs += 16;
477				i++;
478				debug("\t\ttag %u\n", be32_to_cpu(tag->block));
479			} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
480			i++;
481			DB_FOUND = YES;
482		} else if (be32_to_cpu(jdb->h_blocktype) ==
483				EXT3_JOURNAL_COMMIT_BLOCK) {
484			if (be32_to_cpu(jdb->h_sequence) !=
485			     be32_to_cpu(jsb->s_sequence)) {
486				print_jrnl_status(recovery_flag);
487				break;
488			}
489
490			if (transaction_state == TRANSACTION_RUNNING ||
491					(DB_FOUND == NO)) {
492				transaction_state = TRANSACTION_COMPLETE;
493				i++;
494				jsb->s_sequence =
495					cpu_to_be32(be32_to_cpu(
496						jsb->s_sequence) + 1);
497			}
498			prev_desc_logical_no = curr_desc_logical_no;
499			if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
500				recover_transaction(prev_desc_logical_no);
501
502			DB_FOUND = NO;
503		} else if (be32_to_cpu(jdb->h_blocktype) ==
504				EXT3_JOURNAL_REVOKE_BLOCK) {
505			if (be32_to_cpu(jdb->h_sequence) !=
506			    be32_to_cpu(jsb->s_sequence)) {
507				print_jrnl_status(recovery_flag);
508				break;
509			}
510			if (recovery_flag == SCAN)
511				ext4fs_push_revoke_blk((char *)jdb);
512			i++;
513		} else {
514			debug("Else Case\n");
515			if (be32_to_cpu(jdb->h_sequence) !=
516			    be32_to_cpu(jsb->s_sequence)) {
517				print_jrnl_status(recovery_flag);
518				break;
519			}
520		}
521	}
522
523end:
524	if (recovery_flag == RECOVER) {
525		uint32_t new_feature_incompat;
526		jsb->s_start = cpu_to_be32(1);
527		jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
528		/* get the superblock */
529		ext4_read_superblock((char *)fs->sb);
530		new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
531		new_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
532		fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
533
534		/* Update the super block */
535		put_ext4((uint64_t) (SUPERBLOCK_SIZE),
536			 (struct ext2_sblock *)fs->sb,
537			 (uint32_t) SUPERBLOCK_SIZE);
538		ext4_read_superblock((char *)fs->sb);
539
540		blknr = read_allocated_block(&inode_journal,
541					 EXT2_JOURNAL_SUPERBLOCK, NULL);
542		put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
543			 (struct journal_superblock_t *)temp_buff,
544			 (uint32_t) fs->blksz);
545		ext4fs_free_revoke_blks();
546	}
547	free(temp_buff);
548	free(temp_buff1);
549
550	return 0;
551}
552
553static void update_descriptor_block(long int blknr)
554{
555	int i;
556	long int jsb_blknr;
557	struct journal_header_t jdb;
558	struct ext3_journal_block_tag tag;
559	struct ext2_inode inode_journal;
560	struct journal_superblock_t *jsb = NULL;
561	char *buf = NULL;
562	char *temp = NULL;
563	struct ext_filesystem *fs = get_fs();
564	char *temp_buff = zalloc(fs->blksz);
565	if (!temp_buff)
566		return;
567
568	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
569	jsb_blknr = read_allocated_block(&inode_journal,
570					 EXT2_JOURNAL_SUPERBLOCK, NULL);
571	ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
572		       temp_buff);
573	jsb = (struct journal_superblock_t *) temp_buff;
574
575	jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
576	jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
577	jdb.h_sequence = jsb->s_sequence;
578	buf = zalloc(fs->blksz);
579	if (!buf) {
580		free(temp_buff);
581		return;
582	}
583	temp = buf;
584	memcpy(buf, &jdb, sizeof(struct journal_header_t));
585	temp += sizeof(struct journal_header_t);
586
587	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
588		if (journal_ptr[i]->blknr == -1)
589			break;
590
591		tag.block = cpu_to_be32(journal_ptr[i]->blknr);
592		tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
593		memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
594		temp = temp + sizeof(struct ext3_journal_block_tag);
595	}
596
597	tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
598	tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
599	memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
600	       sizeof(struct ext3_journal_block_tag));
601	put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
602
603	free(temp_buff);
604	free(buf);
605}
606
607static void update_commit_block(long int blknr)
608{
609	struct journal_header_t jdb;
610	struct ext_filesystem *fs = get_fs();
611	char *buf = NULL;
612	struct ext2_inode inode_journal;
613	struct journal_superblock_t *jsb;
614	long int jsb_blknr;
615	char *temp_buff = zalloc(fs->blksz);
616	if (!temp_buff)
617		return;
618
619	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
620			  &inode_journal);
621	jsb_blknr = read_allocated_block(&inode_journal,
622					 EXT2_JOURNAL_SUPERBLOCK, NULL);
623	ext4fs_devread((lbaint_t)jsb_blknr * fs->sect_perblk, 0, fs->blksz,
624		       temp_buff);
625	jsb = (struct journal_superblock_t *) temp_buff;
626
627	jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
628	jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
629	jdb.h_sequence = jsb->s_sequence;
630	buf = zalloc(fs->blksz);
631	if (!buf) {
632		free(temp_buff);
633		return;
634	}
635	memcpy(buf, &jdb, sizeof(struct journal_header_t));
636	put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), buf, (uint32_t) fs->blksz);
637
638	free(temp_buff);
639	free(buf);
640}
641
642void ext4fs_update_journal(void)
643{
644	struct ext2_inode inode_journal;
645	struct ext_filesystem *fs = get_fs();
646	long int blknr;
647	int i;
648
649	if (!(fs->sb->feature_compatibility & EXT4_FEATURE_COMPAT_HAS_JOURNAL))
650		return;
651
652	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
653	blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
654	update_descriptor_block(blknr);
655	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
656		if (journal_ptr[i]->blknr == -1)
657			break;
658		blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++,
659					     NULL);
660		put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
661			 journal_ptr[i]->buf, fs->blksz);
662	}
663	blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++, NULL);
664	update_commit_block(blknr);
665	printf("update journal finished\n");
666}
667