]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/ext4/ext4fs.c
mmc: omap_hsmmc: enable 8bit interface for eMMC for AM43xx
[karo-tx-uboot.git] / fs / ext4 / ext4fs.c
1 /*
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>
6  *
7  * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8  *                     Ext4 read optimization taken from Open-Moko
9  *                     Qi bootloader
10  *
11  * (C) Copyright 2004
12  * esd gmbh <www.esd-electronics.com>
13  * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
14  *
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.
18  *
19  * ext4write : Based on generic ext4 protocol.
20  *
21  * SPDX-License-Identifier:     GPL-2.0+
22  */
23
24 #include <common.h>
25 #include <ext_common.h>
26 #include <ext4fs.h>
27 #include "ext4_common.h"
28 #include <div64.h>
29
30 int ext4fs_symlinknest;
31 struct ext_filesystem ext_fs;
32
33 struct ext_filesystem *get_fs(void)
34 {
35         return &ext_fs;
36 }
37
38 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
39 {
40         if ((node != &ext4fs_root->diropen) && (node != currroot))
41                 free(node);
42 }
43
44 /*
45  * Taken from openmoko-kernel mailing list: By Andy green
46  * Optimized read file API : collects and defers contiguous sector
47  * reads into one potentially more efficient larger sequential read action
48  */
49 int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
50                 loff_t len, char *buf, loff_t *actread)
51 {
52         struct ext_filesystem *fs = get_fs();
53         int i;
54         lbaint_t blockcnt;
55         int log2blksz = fs->dev_desc->log2blksz;
56         int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz;
57         int blocksize = (1 << (log2_fs_blocksize + log2blksz));
58         unsigned int filesize = __le32_to_cpu(node->inode.size);
59         lbaint_t previous_block_number = -1;
60         lbaint_t delayed_start = 0;
61         lbaint_t delayed_extent = 0;
62         lbaint_t delayed_skipfirst = 0;
63         lbaint_t delayed_next = 0;
64         char *delayed_buf = NULL;
65         short status;
66
67         /* Adjust len so it we can't read past the end of the file. */
68         if (len > filesize)
69                 len = filesize;
70
71         blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
72
73         for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
74                 lbaint_t blknr;
75                 int blockoff = pos - (blocksize * i);
76                 int blockend = blocksize;
77                 int skipfirst = 0;
78                 blknr = read_allocated_block(&(node->inode), i);
79                 if (blknr < 0)
80                         return -1;
81
82                 blknr = blknr << log2_fs_blocksize;
83
84                 /* Last block.  */
85                 if (i == blockcnt - 1) {
86                         blockend = (len + pos) - (blocksize * i);
87
88                         /* The last portion is exactly blocksize. */
89                         if (!blockend)
90                                 blockend = blocksize;
91                 }
92
93                 /* First block. */
94                 if (i == lldiv(pos, blocksize)) {
95                         skipfirst = blockoff;
96                         blockend -= skipfirst;
97                 }
98                 if (blknr) {
99                         int status;
100
101                         if (previous_block_number != -1) {
102                                 if (delayed_next == blknr) {
103                                         delayed_extent += blockend;
104                                         delayed_next += blockend >> log2blksz;
105                                 } else {        /* spill */
106                                         status = ext4fs_devread(delayed_start,
107                                                         delayed_skipfirst,
108                                                         delayed_extent,
109                                                         delayed_buf);
110                                         if (status == 0)
111                                                 return -1;
112                                         previous_block_number = blknr;
113                                         delayed_start = blknr;
114                                         delayed_extent = blockend;
115                                         delayed_skipfirst = skipfirst;
116                                         delayed_buf = buf;
117                                         delayed_next = blknr +
118                                                 (blockend >> log2blksz);
119                                 }
120                         } else {
121                                 previous_block_number = blknr;
122                                 delayed_start = blknr;
123                                 delayed_extent = blockend;
124                                 delayed_skipfirst = skipfirst;
125                                 delayed_buf = buf;
126                                 delayed_next = blknr +
127                                         (blockend >> log2blksz);
128                         }
129                 } else {
130                         if (previous_block_number != -1) {
131                                 /* spill */
132                                 status = ext4fs_devread(delayed_start,
133                                                         delayed_skipfirst,
134                                                         delayed_extent,
135                                                         delayed_buf);
136                                 if (status == 0)
137                                         return -1;
138                                 previous_block_number = -1;
139                         }
140                         memset(buf, 0, blocksize - skipfirst);
141                 }
142                 buf += blocksize - skipfirst;
143         }
144         if (previous_block_number != -1) {
145                 /* spill */
146                 status = ext4fs_devread(delayed_start,
147                                         delayed_skipfirst, delayed_extent,
148                                         delayed_buf);
149                 if (status == 0)
150                         return -1;
151                 previous_block_number = -1;
152         }
153
154         *actread  = len;
155         return 0;
156 }
157
158 int ext4fs_ls(const char *dirname)
159 {
160         struct ext2fs_node *dirnode;
161         int status;
162
163         if (dirname == NULL)
164                 return 0;
165
166         status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
167                                   FILETYPE_DIRECTORY);
168         if (status != 1) {
169                 printf("** Can not find directory. **\n");
170                 return 1;
171         }
172
173         ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
174         ext4fs_free_node(dirnode, &ext4fs_root->diropen);
175
176         return 0;
177 }
178
179 int ext4fs_exists(const char *filename)
180 {
181         loff_t file_len;
182         int ret;
183
184         ret = ext4fs_open(filename, &file_len);
185         return ret == 0;
186 }
187
188 int ext4fs_size(const char *filename, loff_t *size)
189 {
190         return ext4fs_open(filename, size);
191 }
192
193 int ext4fs_read(char *buf, loff_t len, loff_t *actread)
194 {
195         if (ext4fs_root == NULL || ext4fs_file == NULL)
196                 return 0;
197
198         return ext4fs_read_file(ext4fs_file, 0, len, buf, actread);
199 }
200
201 int ext4fs_probe(block_dev_desc_t *fs_dev_desc,
202                  disk_partition_t *fs_partition)
203 {
204         ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
205
206         if (!ext4fs_mount(fs_partition->size)) {
207                 ext4fs_close();
208                 return -1;
209         }
210
211         return 0;
212 }
213
214 int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
215                    loff_t *len_read)
216 {
217         loff_t file_len;
218         int ret;
219
220         if (offset != 0) {
221                 printf("** Cannot support non-zero offset **\n");
222                 return -1;
223         }
224
225         ret = ext4fs_open(filename, &file_len);
226         if (ret < 0) {
227                 printf("** File not found %s **\n", filename);
228                 return -1;
229         }
230
231         if (len == 0)
232                 len = file_len;
233
234         return ext4fs_read(buf, len, len_read);
235 }
236
237 int ext4fs_uuid(char *uuid_str)
238 {
239         if (ext4fs_root == NULL)
240                 return -1;
241
242 #ifdef CONFIG_LIB_UUID
243         uuid_bin_to_str((unsigned char *)ext4fs_root->sblock.unique_id,
244                         uuid_str, UUID_STR_FORMAT_STD);
245
246         return 0;
247 #else
248         return -ENOSYS;
249 #endif
250 }