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 * 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. 23 * 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. 28 * 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. 32 */ 33 34 #include <common.h> 35 #include <malloc.h> 36 #include <ext_common.h> 37 #include <ext4fs.h> 38 #include <linux/stat.h> 39 #include <linux/time.h> 40 #include <asm/byteorder.h> 41 #include "ext4_common.h" 42 43 int ext4fs_symlinknest; 44 block_dev_desc_t *ext4_dev_desc; 45 46 struct ext_filesystem *get_fs(void) 47 { 48 if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL) 49 printf("Invalid Input Arguments %s\n", __func__); 50 51 return ext4_dev_desc->priv; 52 } 53 54 int init_fs(block_dev_desc_t *dev_desc) 55 { 56 struct ext_filesystem *fs; 57 if (dev_desc == NULL) { 58 printf("Invalid Input Arguments %s\n", __func__); 59 return -EINVAL; 60 } 61 62 fs = zalloc(sizeof(struct ext_filesystem)); 63 if (fs == NULL) { 64 printf("malloc failed: %s\n", __func__); 65 return -ENOMEM; 66 } 67 68 fs->dev_desc = dev_desc; 69 dev_desc->priv = fs; 70 71 return 0; 72 } 73 74 void deinit_fs(block_dev_desc_t *dev_desc) 75 { 76 if (dev_desc == NULL) { 77 printf("Invalid Input Arguments %s\n", __func__); 78 return; 79 } 80 free(dev_desc->priv); 81 dev_desc->priv = NULL; 82 } 83 84 void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) 85 { 86 if ((node != &ext4fs_root->diropen) && (node != currroot)) 87 free(node); 88 } 89 90 /* 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 94 */ 95 int ext4fs_read_file(struct ext2fs_node *node, int pos, 96 unsigned int len, char *buf) 97 { 98 int i; 99 int blockcnt; 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; 109 short status; 110 111 /* Adjust len so it we can't read past the end of the file. */ 112 if (len > filesize) 113 len = filesize; 114 115 blockcnt = ((len + pos) + blocksize - 1) / blocksize; 116 117 for (i = pos / blocksize; i < blockcnt; i++) { 118 int blknr; 119 int blockoff = pos % blocksize; 120 int blockend = blocksize; 121 int skipfirst = 0; 122 blknr = read_allocated_block(&(node->inode), i); 123 if (blknr < 0) 124 return -1; 125 126 blknr = blknr << log2blocksize; 127 128 /* Last block. */ 129 if (i == blockcnt - 1) { 130 blockend = (len + pos) % blocksize; 131 132 /* The last portion is exactly blocksize. */ 133 if (!blockend) 134 blockend = blocksize; 135 } 136 137 /* First block. */ 138 if (i == pos / blocksize) { 139 skipfirst = blockoff; 140 blockend -= skipfirst; 141 } 142 if (blknr) { 143 int status; 144 145 if (previous_block_number != -1) { 146 if (delayed_next == blknr) { 147 delayed_extent += blockend; 148 delayed_next += blockend >> SECTOR_BITS; 149 } else { /* spill */ 150 status = ext4fs_devread(delayed_start, 151 delayed_skipfirst, 152 delayed_extent, 153 delayed_buf); 154 if (status == 0) 155 return -1; 156 previous_block_number = blknr; 157 delayed_start = blknr; 158 delayed_extent = blockend; 159 delayed_skipfirst = skipfirst; 160 delayed_buf = buf; 161 delayed_next = blknr + 162 (blockend >> SECTOR_BITS); 163 } 164 } else { 165 previous_block_number = blknr; 166 delayed_start = blknr; 167 delayed_extent = blockend; 168 delayed_skipfirst = skipfirst; 169 delayed_buf = buf; 170 delayed_next = blknr + 171 (blockend >> SECTOR_BITS); 172 } 173 } else { 174 if (previous_block_number != -1) { 175 /* spill */ 176 status = ext4fs_devread(delayed_start, 177 delayed_skipfirst, 178 delayed_extent, 179 delayed_buf); 180 if (status == 0) 181 return -1; 182 previous_block_number = -1; 183 } 184 memset(buf, 0, blocksize - skipfirst); 185 } 186 buf += blocksize - skipfirst; 187 } 188 if (previous_block_number != -1) { 189 /* spill */ 190 status = ext4fs_devread(delayed_start, 191 delayed_skipfirst, delayed_extent, 192 delayed_buf); 193 if (status == 0) 194 return -1; 195 previous_block_number = -1; 196 } 197 198 return len; 199 } 200 201 int ext4fs_ls(const char *dirname) 202 { 203 struct ext2fs_node *dirnode; 204 int status; 205 206 if (dirname == NULL) 207 return 0; 208 209 status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, 210 FILETYPE_DIRECTORY); 211 if (status != 1) { 212 printf("** Can not find directory. **\n"); 213 return 1; 214 } 215 216 ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); 217 ext4fs_free_node(dirnode, &ext4fs_root->diropen); 218 219 return 0; 220 } 221 222 int ext4fs_read(char *buf, unsigned len) 223 { 224 if (ext4fs_root == NULL || ext4fs_file == NULL) 225 return 0; 226 227 return ext4fs_read_file(ext4fs_file, 0, len, buf); 228 } 229