xref: /openbmc/u-boot/fs/ext4/ext4fs.c (revision e6d52415)
1a1596438SUma Shankar /*
2a1596438SUma Shankar  * (C) Copyright 2011 - 2012 Samsung Electronics
3a1596438SUma Shankar  * EXT4 filesystem implementation in Uboot by
4a1596438SUma Shankar  * Uma Shankar <uma.shankar@samsung.com>
5a1596438SUma Shankar  * Manjunatha C Achar <a.manjunatha@samsung.com>
6a1596438SUma Shankar  *
7a1596438SUma Shankar  * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8a1596438SUma Shankar  *		       Ext4 read optimization taken from Open-Moko
9a1596438SUma Shankar  *		       Qi bootloader
10a1596438SUma Shankar  *
11a1596438SUma Shankar  * (C) Copyright 2004
12a1596438SUma Shankar  * esd gmbh <www.esd-electronics.com>
13a1596438SUma Shankar  * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
14a1596438SUma Shankar  *
15a1596438SUma Shankar  * based on code from grub2 fs/ext2.c and fs/fshelp.c by
16a1596438SUma Shankar  * GRUB  --  GRand Unified Bootloader
17a1596438SUma Shankar  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
18a1596438SUma Shankar  *
19ed34f34dSUma Shankar  * ext4write : Based on generic ext4 protocol.
20ed34f34dSUma Shankar  *
21a1596438SUma Shankar  * This program is free software; you can redistribute it and/or modify
22a1596438SUma Shankar  * it under the terms of the GNU General Public License as published by
23a1596438SUma Shankar  * the Free Software Foundation; either version 2 of the License, or
24a1596438SUma Shankar  * (at your option) any later version.
25a1596438SUma Shankar  *
26a1596438SUma Shankar  * This program is distributed in the hope that it will be useful,
27a1596438SUma Shankar  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28a1596438SUma Shankar  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29a1596438SUma Shankar  * GNU General Public License for more details.
30a1596438SUma Shankar  *
31a1596438SUma Shankar  * You should have received a copy of the GNU General Public License
32a1596438SUma Shankar  * along with this program; if not, write to the Free Software
33a1596438SUma Shankar  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34a1596438SUma Shankar  */
35a1596438SUma Shankar 
36a1596438SUma Shankar #include <common.h>
37a1596438SUma Shankar #include <ext_common.h>
38a1596438SUma Shankar #include <ext4fs.h>
39a1596438SUma Shankar #include "ext4_common.h"
40a1596438SUma Shankar 
41a1596438SUma Shankar int ext4fs_symlinknest;
4294501062SRob Herring struct ext_filesystem ext_fs;
43a1596438SUma Shankar 
44a1596438SUma Shankar struct ext_filesystem *get_fs(void)
45a1596438SUma Shankar {
4694501062SRob Herring 	return &ext_fs;
47a1596438SUma Shankar }
48a1596438SUma Shankar 
49a1596438SUma Shankar void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
50a1596438SUma Shankar {
51a1596438SUma Shankar 	if ((node != &ext4fs_root->diropen) && (node != currroot))
52a1596438SUma Shankar 		free(node);
53a1596438SUma Shankar }
54a1596438SUma Shankar 
55a1596438SUma Shankar /*
56a1596438SUma Shankar  * Taken from openmoko-kernel mailing list: By Andy green
57a1596438SUma Shankar  * Optimized read file API : collects and defers contiguous sector
58a1596438SUma Shankar  * reads into one potentially more efficient larger sequential read action
59a1596438SUma Shankar  */
60a1596438SUma Shankar int ext4fs_read_file(struct ext2fs_node *node, int pos,
61a1596438SUma Shankar 		unsigned int len, char *buf)
62a1596438SUma Shankar {
63a1596438SUma Shankar 	int i;
64a1596438SUma Shankar 	int blockcnt;
65a1596438SUma Shankar 	int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
66a1596438SUma Shankar 	int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
67a1596438SUma Shankar 	unsigned int filesize = __le32_to_cpu(node->inode.size);
68a1596438SUma Shankar 	int previous_block_number = -1;
69a1596438SUma Shankar 	int delayed_start = 0;
70a1596438SUma Shankar 	int delayed_extent = 0;
71a1596438SUma Shankar 	int delayed_skipfirst = 0;
72a1596438SUma Shankar 	int delayed_next = 0;
73a1596438SUma Shankar 	char *delayed_buf = NULL;
74a1596438SUma Shankar 	short status;
75a1596438SUma Shankar 
76a1596438SUma Shankar 	/* Adjust len so it we can't read past the end of the file. */
77a1596438SUma Shankar 	if (len > filesize)
78a1596438SUma Shankar 		len = filesize;
79a1596438SUma Shankar 
80a1596438SUma Shankar 	blockcnt = ((len + pos) + blocksize - 1) / blocksize;
81a1596438SUma Shankar 
82a1596438SUma Shankar 	for (i = pos / blocksize; i < blockcnt; i++) {
83a1596438SUma Shankar 		int blknr;
84a1596438SUma Shankar 		int blockoff = pos % blocksize;
85a1596438SUma Shankar 		int blockend = blocksize;
86a1596438SUma Shankar 		int skipfirst = 0;
87a1596438SUma Shankar 		blknr = read_allocated_block(&(node->inode), i);
88a1596438SUma Shankar 		if (blknr < 0)
89a1596438SUma Shankar 			return -1;
90a1596438SUma Shankar 
91a1596438SUma Shankar 		blknr = blknr << log2blocksize;
92a1596438SUma Shankar 
93a1596438SUma Shankar 		/* Last block.  */
94a1596438SUma Shankar 		if (i == blockcnt - 1) {
95a1596438SUma Shankar 			blockend = (len + pos) % blocksize;
96a1596438SUma Shankar 
97a1596438SUma Shankar 			/* The last portion is exactly blocksize. */
98a1596438SUma Shankar 			if (!blockend)
99a1596438SUma Shankar 				blockend = blocksize;
100a1596438SUma Shankar 		}
101a1596438SUma Shankar 
102a1596438SUma Shankar 		/* First block. */
103a1596438SUma Shankar 		if (i == pos / blocksize) {
104a1596438SUma Shankar 			skipfirst = blockoff;
105a1596438SUma Shankar 			blockend -= skipfirst;
106a1596438SUma Shankar 		}
107a1596438SUma Shankar 		if (blknr) {
108a1596438SUma Shankar 			int status;
109a1596438SUma Shankar 
110a1596438SUma Shankar 			if (previous_block_number != -1) {
111a1596438SUma Shankar 				if (delayed_next == blknr) {
112a1596438SUma Shankar 					delayed_extent += blockend;
113a1596438SUma Shankar 					delayed_next += blockend >> SECTOR_BITS;
114a1596438SUma Shankar 				} else {	/* spill */
115a1596438SUma Shankar 					status = ext4fs_devread(delayed_start,
116a1596438SUma Shankar 							delayed_skipfirst,
117a1596438SUma Shankar 							delayed_extent,
118a1596438SUma Shankar 							delayed_buf);
119a1596438SUma Shankar 					if (status == 0)
120a1596438SUma Shankar 						return -1;
121a1596438SUma Shankar 					previous_block_number = blknr;
122a1596438SUma Shankar 					delayed_start = blknr;
123a1596438SUma Shankar 					delayed_extent = blockend;
124a1596438SUma Shankar 					delayed_skipfirst = skipfirst;
125a1596438SUma Shankar 					delayed_buf = buf;
126a1596438SUma Shankar 					delayed_next = blknr +
127a1596438SUma Shankar 						(blockend >> SECTOR_BITS);
128a1596438SUma Shankar 				}
129a1596438SUma Shankar 			} else {
130a1596438SUma Shankar 				previous_block_number = blknr;
131a1596438SUma Shankar 				delayed_start = blknr;
132a1596438SUma Shankar 				delayed_extent = blockend;
133a1596438SUma Shankar 				delayed_skipfirst = skipfirst;
134a1596438SUma Shankar 				delayed_buf = buf;
135a1596438SUma Shankar 				delayed_next = blknr +
136a1596438SUma Shankar 					(blockend >> SECTOR_BITS);
137a1596438SUma Shankar 			}
138a1596438SUma Shankar 		} else {
139a1596438SUma Shankar 			if (previous_block_number != -1) {
140a1596438SUma Shankar 				/* spill */
141a1596438SUma Shankar 				status = ext4fs_devread(delayed_start,
142a1596438SUma Shankar 							delayed_skipfirst,
143a1596438SUma Shankar 							delayed_extent,
144a1596438SUma Shankar 							delayed_buf);
145a1596438SUma Shankar 				if (status == 0)
146a1596438SUma Shankar 					return -1;
147a1596438SUma Shankar 				previous_block_number = -1;
148a1596438SUma Shankar 			}
149a1596438SUma Shankar 			memset(buf, 0, blocksize - skipfirst);
150a1596438SUma Shankar 		}
151a1596438SUma Shankar 		buf += blocksize - skipfirst;
152a1596438SUma Shankar 	}
153a1596438SUma Shankar 	if (previous_block_number != -1) {
154a1596438SUma Shankar 		/* spill */
155a1596438SUma Shankar 		status = ext4fs_devread(delayed_start,
156a1596438SUma Shankar 					delayed_skipfirst, delayed_extent,
157a1596438SUma Shankar 					delayed_buf);
158a1596438SUma Shankar 		if (status == 0)
159a1596438SUma Shankar 			return -1;
160a1596438SUma Shankar 		previous_block_number = -1;
161a1596438SUma Shankar 	}
162a1596438SUma Shankar 
163a1596438SUma Shankar 	return len;
164a1596438SUma Shankar }
165a1596438SUma Shankar 
166a1596438SUma Shankar int ext4fs_ls(const char *dirname)
167a1596438SUma Shankar {
168a1596438SUma Shankar 	struct ext2fs_node *dirnode;
169a1596438SUma Shankar 	int status;
170a1596438SUma Shankar 
171a1596438SUma Shankar 	if (dirname == NULL)
172a1596438SUma Shankar 		return 0;
173a1596438SUma Shankar 
174a1596438SUma Shankar 	status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
175a1596438SUma Shankar 				  FILETYPE_DIRECTORY);
176a1596438SUma Shankar 	if (status != 1) {
177a1596438SUma Shankar 		printf("** Can not find directory. **\n");
178a1596438SUma Shankar 		return 1;
179a1596438SUma Shankar 	}
180a1596438SUma Shankar 
181a1596438SUma Shankar 	ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
182a1596438SUma Shankar 	ext4fs_free_node(dirnode, &ext4fs_root->diropen);
183a1596438SUma Shankar 
184a1596438SUma Shankar 	return 0;
185a1596438SUma Shankar }
186a1596438SUma Shankar 
187a1596438SUma Shankar int ext4fs_read(char *buf, unsigned len)
188a1596438SUma Shankar {
189a1596438SUma Shankar 	if (ext4fs_root == NULL || ext4fs_file == NULL)
190a1596438SUma Shankar 		return 0;
191a1596438SUma Shankar 
192a1596438SUma Shankar 	return ext4fs_read_file(ext4fs_file, 0, len, buf);
193a1596438SUma Shankar }
194*e6d52415SSimon Glass 
195*e6d52415SSimon Glass int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
196*e6d52415SSimon Glass 		 disk_partition_t *fs_partition)
197*e6d52415SSimon Glass {
198*e6d52415SSimon Glass 	ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
199*e6d52415SSimon Glass 
200*e6d52415SSimon Glass 	if (!ext4fs_mount(fs_partition->size)) {
201*e6d52415SSimon Glass 		ext4fs_close();
202*e6d52415SSimon Glass 		return -1;
203*e6d52415SSimon Glass 	}
204*e6d52415SSimon Glass 
205*e6d52415SSimon Glass 	return 0;
206*e6d52415SSimon Glass }
207*e6d52415SSimon Glass 
208*e6d52415SSimon Glass int ext4_read_file(const char *filename, void *buf, int offset, int len)
209*e6d52415SSimon Glass {
210*e6d52415SSimon Glass 	int file_len;
211*e6d52415SSimon Glass 	int len_read;
212*e6d52415SSimon Glass 
213*e6d52415SSimon Glass 	if (offset != 0) {
214*e6d52415SSimon Glass 		printf("** Cannot support non-zero offset **\n");
215*e6d52415SSimon Glass 		return -1;
216*e6d52415SSimon Glass 	}
217*e6d52415SSimon Glass 
218*e6d52415SSimon Glass 	file_len = ext4fs_open(filename);
219*e6d52415SSimon Glass 	if (file_len < 0) {
220*e6d52415SSimon Glass 		printf("** File not found %s **\n", filename);
221*e6d52415SSimon Glass 		return -1;
222*e6d52415SSimon Glass 	}
223*e6d52415SSimon Glass 
224*e6d52415SSimon Glass 	if (len == 0)
225*e6d52415SSimon Glass 		len = file_len;
226*e6d52415SSimon Glass 
227*e6d52415SSimon Glass 	len_read = ext4fs_read(buf, len);
228*e6d52415SSimon Glass 
229*e6d52415SSimon Glass 	return len_read;
230*e6d52415SSimon Glass }
231