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