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 * 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
  30int ext4fs_symlinknest;
  31struct ext_filesystem ext_fs;
  32
  33struct ext_filesystem *get_fs(void)
  34{
  35        return &ext_fs;
  36}
  37
  38void 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 */
  49int 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 + pos > filesize)
  69                len = (filesize - pos);
  70
  71        blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
  72
  73        for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
  74                long int 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
 158int 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                ext4fs_free_node(dirnode, &ext4fs_root->diropen);
 171                return 1;
 172        }
 173
 174        ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
 175        ext4fs_free_node(dirnode, &ext4fs_root->diropen);
 176
 177        return 0;
 178}
 179
 180int ext4fs_exists(const char *filename)
 181{
 182        loff_t file_len;
 183        int ret;
 184
 185        ret = ext4fs_open(filename, &file_len);
 186        return ret == 0;
 187}
 188
 189int ext4fs_size(const char *filename, loff_t *size)
 190{
 191        return ext4fs_open(filename, size);
 192}
 193
 194int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread)
 195{
 196        if (ext4fs_root == NULL || ext4fs_file == NULL)
 197                return -1;
 198
 199        return ext4fs_read_file(ext4fs_file, offset, len, buf, actread);
 200}
 201
 202int ext4fs_probe(struct blk_desc *fs_dev_desc,
 203                 disk_partition_t *fs_partition)
 204{
 205        ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
 206
 207        if (!ext4fs_mount(fs_partition->size)) {
 208                ext4fs_close();
 209                return -1;
 210        }
 211
 212        return 0;
 213}
 214
 215int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
 216                   loff_t *len_read)
 217{
 218        loff_t file_len;
 219        int ret;
 220
 221        ret = ext4fs_open(filename, &file_len);
 222        if (ret < 0) {
 223                printf("** File not found %s **\n", filename);
 224                return -1;
 225        }
 226
 227        if (len == 0)
 228                len = file_len;
 229
 230        return ext4fs_read(buf, offset, len, len_read);
 231}
 232
 233int ext4fs_uuid(char *uuid_str)
 234{
 235        if (ext4fs_root == NULL)
 236                return -1;
 237
 238#ifdef CONFIG_LIB_UUID
 239        uuid_bin_to_str((unsigned char *)ext4fs_root->sblock.unique_id,
 240                        uuid_str, UUID_STR_FORMAT_STD);
 241
 242        return 0;
 243#else
 244        return -ENOSYS;
 245#endif
 246}
 247