]> Git Repo - J-u-boot.git/blame - fs/ext4/ext4fs.c
Merge commit '0344c602eadc0802776b65ff90f0a02c856cf53c' as 'lib/mbedtls/external...
[J-u-boot.git] / fs / ext4 / ext4fs.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
a1596438
US
2/*
3 * (C) Copyright 2011 - 2012 Samsung Electronics
4 * EXT4 filesystem implementation in Uboot by
5 * Uma Shankar <[email protected]>
6 * Manjunatha C Achar <[email protected]>
7 *
8 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
9 * Ext4 read optimization taken from Open-Moko
10 * Qi bootloader
11 *
12 * (C) Copyright 2004
13 * esd gmbh <www.esd-electronics.com>
14 * Reinhard Arlt <[email protected]>
15 *
16 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
17 * GRUB -- GRand Unified Bootloader
18 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
19 *
ed34f34d 20 * ext4write : Based on generic ext4 protocol.
a1596438
US
21 */
22
e6f6f9e6 23#include <blk.h>
a1596438
US
24#include <ext_common.h>
25#include <ext4fs.h>
a1596438 26#include "ext4_common.h"
9e374e7b 27#include <div64.h>
336d4615 28#include <malloc.h>
e6f6f9e6 29#include <part.h>
58d825fb 30#include <u-boot/uuid.h>
a1596438
US
31
32int ext4fs_symlinknest;
94501062 33struct ext_filesystem ext_fs;
a1596438
US
34
35struct ext_filesystem *get_fs(void)
36{
94501062 37 return &ext_fs;
a1596438
US
38}
39
40void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
41{
42 if ((node != &ext4fs_root->diropen) && (node != currroot))
43 free(node);
44}
45
46/*
47 * Taken from openmoko-kernel mailing list: By Andy green
48 * Optimized read file API : collects and defers contiguous sector
49 * reads into one potentially more efficient larger sequential read action
50 */
9f12cd0e
SR
51int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
52 loff_t len, char *buf, loff_t *actread)
a1596438 53{
50ce4c07 54 struct ext_filesystem *fs = get_fs();
a1596438 55 int i;
04735e9c 56 lbaint_t blockcnt;
50ce4c07
EE
57 int log2blksz = fs->dev_desc->log2blksz;
58 int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
59 int blocksize = (1 << (log2_fs_blocksize + log2blksz));
7f101be3 60 unsigned int filesize = le32_to_cpu(node->inode.size);
04735e9c
FL
61 lbaint_t previous_block_number = -1;
62 lbaint_t delayed_start = 0;
63 lbaint_t delayed_extent = 0;
64 lbaint_t delayed_skipfirst = 0;
65 lbaint_t delayed_next = 0;
a1596438 66 char *delayed_buf = NULL;
e205896c 67 char *start_buf = buf;
a1596438 68 short status;
d5aee659
SW
69 struct ext_block_cache cache;
70
71 ext_cache_init(&cache);
a1596438
US
72
73 /* Adjust len so it we can't read past the end of the file. */
66a47ff2
SB
74 if (len + pos > filesize)
75 len = (filesize - pos);
a1596438 76
878269db
PE
77 if (blocksize <= 0 || len <= 0) {
78 ext_cache_fini(&cache);
79 return -1;
80 }
81
9e374e7b 82 blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
a1596438 83
9e374e7b 84 for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
509b498a 85 long int blknr;
9e374e7b 86 int blockoff = pos - (blocksize * i);
a1596438
US
87 int blockend = blocksize;
88 int skipfirst = 0;
d5aee659
SW
89 blknr = read_allocated_block(&node->inode, i, &cache);
90 if (blknr < 0) {
91 ext_cache_fini(&cache);
715b56fe 92 return -1;
d5aee659 93 }
a1596438 94
50ce4c07 95 blknr = blknr << log2_fs_blocksize;
a1596438
US
96
97 /* Last block. */
98 if (i == blockcnt - 1) {
9e374e7b 99 blockend = (len + pos) - (blocksize * i);
a1596438
US
100
101 /* The last portion is exactly blocksize. */
102 if (!blockend)
103 blockend = blocksize;
104 }
105
106 /* First block. */
9e374e7b 107 if (i == lldiv(pos, blocksize)) {
a1596438
US
108 skipfirst = blockoff;
109 blockend -= skipfirst;
110 }
111 if (blknr) {
112 int status;
113
114 if (previous_block_number != -1) {
115 if (delayed_next == blknr) {
116 delayed_extent += blockend;
50ce4c07 117 delayed_next += blockend >> log2blksz;
a1596438
US
118 } else { /* spill */
119 status = ext4fs_devread(delayed_start,
120 delayed_skipfirst,
121 delayed_extent,
122 delayed_buf);
d5aee659
SW
123 if (status == 0) {
124 ext_cache_fini(&cache);
715b56fe 125 return -1;
d5aee659 126 }
a1596438
US
127 previous_block_number = blknr;
128 delayed_start = blknr;
129 delayed_extent = blockend;
130 delayed_skipfirst = skipfirst;
131 delayed_buf = buf;
132 delayed_next = blknr +
50ce4c07 133 (blockend >> log2blksz);
a1596438
US
134 }
135 } else {
136 previous_block_number = blknr;
137 delayed_start = blknr;
138 delayed_extent = blockend;
139 delayed_skipfirst = skipfirst;
140 delayed_buf = buf;
141 delayed_next = blknr +
50ce4c07 142 (blockend >> log2blksz);
a1596438
US
143 }
144 } else {
ecdfb419 145 int n;
e205896c 146 int n_left;
a1596438
US
147 if (previous_block_number != -1) {
148 /* spill */
149 status = ext4fs_devread(delayed_start,
150 delayed_skipfirst,
151 delayed_extent,
152 delayed_buf);
d5aee659
SW
153 if (status == 0) {
154 ext_cache_fini(&cache);
715b56fe 155 return -1;
d5aee659 156 }
a1596438
US
157 previous_block_number = -1;
158 }
ecdfb419
IR
159 /* Zero no more than `len' bytes. */
160 n = blocksize - skipfirst;
e205896c
PE
161 n_left = len - ( buf - start_buf );
162 if (n > n_left)
163 n = n_left;
ecdfb419 164 memset(buf, 0, n);
a1596438
US
165 }
166 buf += blocksize - skipfirst;
167 }
168 if (previous_block_number != -1) {
169 /* spill */
170 status = ext4fs_devread(delayed_start,
171 delayed_skipfirst, delayed_extent,
172 delayed_buf);
d5aee659
SW
173 if (status == 0) {
174 ext_cache_fini(&cache);
715b56fe 175 return -1;
d5aee659 176 }
a1596438
US
177 previous_block_number = -1;
178 }
179
9f12cd0e 180 *actread = len;
d5aee659 181 ext_cache_fini(&cache);
9f12cd0e 182 return 0;
a1596438
US
183}
184
185int ext4fs_ls(const char *dirname)
186{
e71a969c 187 struct ext2fs_node *dirnode = NULL;
a1596438
US
188 int status;
189
190 if (dirname == NULL)
191 return 0;
192
193 status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
194 FILETYPE_DIRECTORY);
195 if (status != 1) {
196 printf("** Can not find directory. **\n");
e71a969c
EH
197 if (dirnode)
198 ext4fs_free_node(dirnode, &ext4fs_root->diropen);
a1596438
US
199 return 1;
200 }
201
202 ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
203 ext4fs_free_node(dirnode, &ext4fs_root->diropen);
204
205 return 0;
206}
207
55af5c93
SW
208int ext4fs_exists(const char *filename)
209{
e70f04fb
HS
210 struct ext2fs_node *dirnode = NULL;
211 int filetype;
55af5c93 212
e70f04fb
HS
213 if (!filename)
214 return 0;
215
216 return ext4fs_find_file1(filename, &ext4fs_root->diropen, &dirnode,
217 &filetype);
55af5c93
SW
218}
219
d455d878 220int ext4fs_size(const char *filename, loff_t *size)
cf659819 221{
d455d878 222 return ext4fs_open(filename, size);
cf659819
SW
223}
224
66a47ff2 225int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread)
a1596438
US
226{
227 if (ext4fs_root == NULL || ext4fs_file == NULL)
66a47ff2 228 return -1;
a1596438 229
66a47ff2 230 return ext4fs_read_file(ext4fs_file, offset, len, buf, actread);
a1596438 231}
e6d52415 232
4101f687 233int ext4fs_probe(struct blk_desc *fs_dev_desc,
0528979f 234 struct disk_partition *fs_partition)
e6d52415
SG
235{
236 ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
237
7667bdeb 238 if (!ext4fs_mount()) {
e6d52415
SG
239 ext4fs_close();
240 return -1;
241 }
242
243 return 0;
244}
245
d455d878
SR
246int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
247 loff_t *len_read)
e6d52415 248{
9f12cd0e 249 loff_t file_len;
9f12cd0e 250 int ret;
e6d52415 251
9f12cd0e
SR
252 ret = ext4fs_open(filename, &file_len);
253 if (ret < 0) {
e6d52415
SG
254 printf("** File not found %s **\n", filename);
255 return -1;
256 }
257
258 if (len == 0)
259 len = file_len;
260
66a47ff2 261 return ext4fs_read(buf, offset, len, len_read);
e6d52415 262}
59e890ef
CG
263
264int ext4fs_uuid(char *uuid_str)
265{
266 if (ext4fs_root == NULL)
267 return -1;
268
269#ifdef CONFIG_LIB_UUID
270 uuid_bin_to_str((unsigned char *)ext4fs_root->sblock.unique_id,
271 uuid_str, UUID_STR_FORMAT_STD);
272
273 return 0;
274#else
275 return -ENOSYS;
276#endif
277}
d5aee659
SW
278
279void ext_cache_init(struct ext_block_cache *cache)
280{
281 memset(cache, 0, sizeof(*cache));
282}
283
284void ext_cache_fini(struct ext_block_cache *cache)
285{
286 free(cache->buf);
287 ext_cache_init(cache);
288}
289
290int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size)
291{
292 /* This could be more lenient, but this is simple and enough for now */
293 if (cache->buf && cache->block == block && cache->size == size)
294 return 1;
295 ext_cache_fini(cache);
7b83060b 296 cache->buf = memalign(ARCH_DMA_MINALIGN, size);
d5aee659
SW
297 if (!cache->buf)
298 return 0;
299 if (!ext4fs_devread(block, 0, size, cache->buf)) {
6e5a79de 300 ext_cache_fini(cache);
d5aee659
SW
301 return 0;
302 }
303 cache->block = block;
304 cache->size = size;
305 return 1;
306}
This page took 0.448786 seconds and 4 git commands to generate.