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