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