2 * (C) Copyright 2011 - 2012 Samsung Electronics
3 * EXT4 filesystem implementation in Uboot by
4 * Uma Shankar <uma.shankar@samsung.com>
5 * Manjunatha C Achar <a.manjunatha@samsung.com>
7 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8 * Ext4 read optimization taken from Open-Moko
12 * esd gmbh <www.esd-electronics.com>
13 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
15 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
16 * GRUB -- GRand Unified Bootloader
17 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 #include <ext_common.h>
38 #include <linux/stat.h>
39 #include <linux/time.h>
40 #include <asm/byteorder.h>
41 #include "ext4_common.h"
43 int ext4fs_symlinknest;
44 block_dev_desc_t *ext4_dev_desc;
46 struct ext_filesystem *get_fs(void)
48 if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL)
49 printf("Invalid Input Arguments %s\n", __func__);
51 return ext4_dev_desc->priv;
54 int init_fs(block_dev_desc_t *dev_desc)
56 struct ext_filesystem *fs;
57 if (dev_desc == NULL) {
58 printf("Invalid Input Arguments %s\n", __func__);
62 fs = zalloc(sizeof(struct ext_filesystem));
64 printf("malloc failed: %s\n", __func__);
68 fs->dev_desc = dev_desc;
74 void deinit_fs(block_dev_desc_t *dev_desc)
76 if (dev_desc == NULL) {
77 printf("Invalid Input Arguments %s\n", __func__);
81 dev_desc->priv = NULL;
84 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
86 if ((node != &ext4fs_root->diropen) && (node != currroot))
91 * Taken from openmoko-kernel mailing list: By Andy green
92 * Optimized read file API : collects and defers contiguous sector
93 * reads into one potentially more efficient larger sequential read action
95 int ext4fs_read_file(struct ext2fs_node *node, int pos,
96 unsigned int len, char *buf)
100 int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
101 int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
102 unsigned int filesize = __le32_to_cpu(node->inode.size);
103 int previous_block_number = -1;
104 int delayed_start = 0;
105 int delayed_extent = 0;
106 int delayed_skipfirst = 0;
107 int delayed_next = 0;
108 char *delayed_buf = NULL;
111 /* Adjust len so it we can't read past the end of the file. */
115 blockcnt = ((len + pos) + blocksize - 1) / blocksize;
117 for (i = pos / blocksize; i < blockcnt; i++) {
119 int blockoff = pos % blocksize;
120 int blockend = blocksize;
122 blknr = read_allocated_block(&(node->inode), i);
126 blknr = blknr << log2blocksize;
129 if (i == blockcnt - 1) {
130 blockend = (len + pos) % blocksize;
132 /* The last portion is exactly blocksize. */
134 blockend = blocksize;
138 if (i == pos / blocksize) {
139 skipfirst = blockoff;
140 blockend -= skipfirst;
145 if (previous_block_number != -1) {
146 if (delayed_next == blknr) {
147 delayed_extent += blockend;
148 delayed_next += blockend >> SECTOR_BITS;
150 status = ext4fs_devread(delayed_start,
156 previous_block_number = blknr;
157 delayed_start = blknr;
158 delayed_extent = blockend;
159 delayed_skipfirst = skipfirst;
161 delayed_next = blknr +
162 (blockend >> SECTOR_BITS);
165 previous_block_number = blknr;
166 delayed_start = blknr;
167 delayed_extent = blockend;
168 delayed_skipfirst = skipfirst;
170 delayed_next = blknr +
171 (blockend >> SECTOR_BITS);
174 if (previous_block_number != -1) {
176 status = ext4fs_devread(delayed_start,
182 previous_block_number = -1;
184 memset(buf, 0, blocksize - skipfirst);
186 buf += blocksize - skipfirst;
188 if (previous_block_number != -1) {
190 status = ext4fs_devread(delayed_start,
191 delayed_skipfirst, delayed_extent,
195 previous_block_number = -1;
201 int ext4fs_ls(const char *dirname)
203 struct ext2fs_node *dirnode;
209 status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
212 printf("** Can not find directory. **\n");
216 ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
217 ext4fs_free_node(dirnode, &ext4fs_root->diropen);
222 int ext4fs_read(char *buf, unsigned len)
224 if (ext4fs_root == NULL || ext4fs_file == NULL)
227 return ext4fs_read_file(ext4fs_file, 0, len, buf);