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