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