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