[U-Boot] [PATCH 0/11] sandbox: Add filesystem support

This series adds support for filesystems to sandbox. While we don't yet have access to host machine block devices, we can access files on the host through a new 'host' filesystem type and the new sandbox command 'sb'.
For example:
sb load host 0 1000 foo.bar
will load foo.bar from the host into memory at address 1000. The '0' parameter is the device number, currently unused.
While doing this work, I noticed that fs.c had code that probably belongs more in the filesystems themselves. So this series moves fat/ext4 code into those files. This removes most of the #ifdefs from this file, as well as the #defines of functions to 'unsupported'. Now there is a list of filesystems that we support, and if we don't find the one we need, we automatically fall back to the 'unsupported' one.
Finally, the ext4 write support is moved into a separate file since ext4fs.c was over 3500 lines and the write support seems entirely separate from the main function in that file.
Simon Glass (11): ext4: Split write support into its own file fs: Fully populate the filesystem method struct fs: Use filesystem methods instead of switch() fs: Tell probe functions where to put their results fs: Use map_sysmem() on read fs: Move ls and read methods into ext4, fat sandbox: Add a way of obtaining directory listings sandbox: Add host filesystem sandbox: Add 'sb' command to access filesystem features sandbox: Enable ext4 and fat filesystems sandbox: config: Enable sandbox command
Makefile | 1 + README | 1 + arch/sandbox/cpu/os.c | 101 +++++ common/Makefile | 1 + common/cmd_sandbox.c | 63 +++ disk/part.c | 17 + fs/ext4/Makefile | 2 +- fs/ext4/ext4_write.c | 996 +++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/ext4fs.c | 962 +------------------------------------------ fs/fat/fat.c | 17 + fs/fs.c | 237 +++++------- fs/sandbox/Makefile | 47 +++ fs/sandbox/sandboxfs.c | 83 ++++ include/config_cmd_all.h | 1 + include/configs/sandbox.h | 9 + include/ext4fs.h | 3 + include/fat.h | 2 + include/fs.h | 1 + include/os.h | 48 +++ include/sandboxfs.h | 30 ++ 20 files changed, 1533 insertions(+), 1089 deletions(-) create mode 100644 common/cmd_sandbox.c create mode 100644 fs/ext4/ext4_write.c create mode 100644 fs/sandbox/Makefile create mode 100644 fs/sandbox/sandboxfs.c create mode 100644 include/sandboxfs.h

This code seems to be entirely othogonal, so remove the #ifdef and put the condition in the Makefile instead.
Signed-off-by: Simon Glass sjg@chromium.org --- fs/ext4/Makefile | 2 +- fs/ext4/ext4_write.c | 996 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/ext4fs.c | 963 ------------------------------------------------ 3 files changed, 997 insertions(+), 964 deletions(-) create mode 100644 fs/ext4/ext4_write.c
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index bb801f9..3bde824 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -31,7 +31,7 @@ LIB = $(obj)libext4fs.o
AOBJS = COBJS-$(CONFIG_FS_EXT4) := ext4fs.o ext4_common.o dev.o -COBJS-$(CONFIG_EXT4_WRITE) += ext4_journal.o crc16.o +COBJS-$(CONFIG_EXT4_WRITE) += ext4_write.o ext4_journal.o crc16.o
SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y)) diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c new file mode 100644 index 0000000..c4e399c --- /dev/null +++ b/fs/ext4/ext4_write.c @@ -0,0 +1,996 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar uma.shankar@samsung.com + * Manjunatha C Achar a.manjunatha@samsung.com + * + * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. + * Ext4 read optimization taken from Open-Moko + * Qi bootloader + * + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt reinhard.arlt@esd-electronics.com + * + * based on code from grub2 fs/ext2.c and fs/fshelp.c by + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * + * ext4write : Based on generic ext4 protocol. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include <common.h> +#include <linux/stat.h> +#include <div64.h> +#include "ext4_common.h" + +static void ext4fs_update(void) +{ + short i; + ext4fs_update_journal(); + struct ext_filesystem *fs = get_fs(); + + /* update super block */ + put_ext4((uint64_t)(SUPERBLOCK_SIZE), + (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); + + /* update block groups */ + for (i = 0; i < fs->no_blkgrp; i++) { + fs->bgd[i].bg_checksum = ext4fs_checksum_update(i); + put_ext4((uint64_t)(fs->bgd[i].block_id * fs->blksz), + fs->blk_bmaps[i], fs->blksz); + } + + /* update inode table groups */ + for (i = 0; i < fs->no_blkgrp; i++) { + put_ext4((uint64_t) (fs->bgd[i].inode_id * fs->blksz), + fs->inode_bmaps[i], fs->blksz); + } + + /* update the block group descriptor table */ + put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz), + (struct ext2_block_group *)fs->gdtable, + (fs->blksz * fs->no_blk_pergdt)); + + ext4fs_dump_metadata(); + + gindex = 0; + gd_index = 0; +} + +int ext4fs_get_bgdtable(void) +{ + int status; + int grp_desc_size; + struct ext_filesystem *fs = get_fs(); + grp_desc_size = sizeof(struct ext2_block_group); + fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz; + if ((fs->no_blkgrp * grp_desc_size) % fs->blksz) + fs->no_blk_pergdt++; + + /* allocate memory for gdtable */ + fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt); + if (!fs->gdtable) + return -ENOMEM; + /* read the group descriptor table */ + status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0, + fs->blksz * fs->no_blk_pergdt, fs->gdtable); + if (status == 0) + goto fail; + + if (ext4fs_log_gdt(fs->gdtable)) { + printf("Error in ext4fs_log_gdt\n"); + return -1; + } + + return 0; +fail: + free(fs->gdtable); + fs->gdtable = NULL; + + return -1; +} + +static void delete_single_indirect_block(struct ext2_inode *inode) +{ + struct ext2_block_group *bgd = NULL; + static int prev_bg_bmap_idx = -1; + long int blknr; + int remainder; + int bg_idx; + int status; + unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; + struct ext_filesystem *fs = get_fs(); + char *journal_buffer = zalloc(fs->blksz); + if (!journal_buffer) { + printf("No memory\n"); + return; + } + /* get block group descriptor table */ + bgd = (struct ext2_block_group *)fs->gdtable; + + /* deleting the single indirect block associated with inode */ + if (inode->b.blocks.indir_block != 0) { + debug("SIPB releasing %u\n", inode->b.blocks.indir_block); + blknr = inode->b.blocks.indir_block; + if (fs->blksz != 1024) { + bg_idx = blknr / blk_per_grp; + } else { + bg_idx = blknr / blk_per_grp; + remainder = blknr % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + status = + ext4fs_devread(bgd[bg_idx].block_id * + fs->sect_perblk, 0, fs->blksz, + journal_buffer); + if (status == 0) + goto fail; + if (ext4fs_log_journal + (journal_buffer, bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + } +fail: + free(journal_buffer); +} + +static void delete_double_indirect_block(struct ext2_inode *inode) +{ + int i; + short status; + static int prev_bg_bmap_idx = -1; + long int blknr; + int remainder; + int bg_idx; + unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; + unsigned int *di_buffer = NULL; + unsigned int *DIB_start_addr = NULL; + struct ext2_block_group *bgd = NULL; + struct ext_filesystem *fs = get_fs(); + char *journal_buffer = zalloc(fs->blksz); + if (!journal_buffer) { + printf("No memory\n"); + return; + } + /* get the block group descriptor table */ + bgd = (struct ext2_block_group *)fs->gdtable; + + if (inode->b.blocks.double_indir_block != 0) { + di_buffer = zalloc(fs->blksz); + if (!di_buffer) { + printf("No memory\n"); + return; + } + DIB_start_addr = (unsigned int *)di_buffer; + blknr = inode->b.blocks.double_indir_block; + status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, + (char *)di_buffer); + for (i = 0; i < fs->blksz / sizeof(int); i++) { + if (*di_buffer == 0) + break; + + debug("DICB releasing %u\n", *di_buffer); + if (fs->blksz != 1024) { + bg_idx = (*di_buffer) / blk_per_grp; + } else { + bg_idx = (*di_buffer) / blk_per_grp; + remainder = (*di_buffer) % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(*di_buffer, + fs->blk_bmaps[bg_idx], bg_idx); + di_buffer++; + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + status = ext4fs_devread(bgd[bg_idx].block_id + * fs->sect_perblk, 0, + fs->blksz, + journal_buffer); + if (status == 0) + goto fail; + + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + } + + /* removing the parent double indirect block */ + blknr = inode->b.blocks.double_indir_block; + if (fs->blksz != 1024) { + bg_idx = blknr / blk_per_grp; + } else { + bg_idx = blknr / blk_per_grp; + remainder = blknr % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + memset(journal_buffer, '\0', fs->blksz); + status = ext4fs_devread(bgd[bg_idx].block_id * + fs->sect_perblk, 0, fs->blksz, + journal_buffer); + if (status == 0) + goto fail; + + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + debug("DIPB releasing %ld\n", blknr); + } +fail: + free(DIB_start_addr); + free(journal_buffer); +} + +static void delete_triple_indirect_block(struct ext2_inode *inode) +{ + int i, j; + short status; + static int prev_bg_bmap_idx = -1; + long int blknr; + int remainder; + int bg_idx; + unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; + unsigned int *tigp_buffer = NULL; + unsigned int *tib_start_addr = NULL; + unsigned int *tip_buffer = NULL; + unsigned int *tipb_start_addr = NULL; + struct ext2_block_group *bgd = NULL; + struct ext_filesystem *fs = get_fs(); + char *journal_buffer = zalloc(fs->blksz); + if (!journal_buffer) { + printf("No memory\n"); + return; + } + /* get block group descriptor table */ + bgd = (struct ext2_block_group *)fs->gdtable; + + if (inode->b.blocks.triple_indir_block != 0) { + tigp_buffer = zalloc(fs->blksz); + if (!tigp_buffer) { + printf("No memory\n"); + return; + } + tib_start_addr = (unsigned int *)tigp_buffer; + blknr = inode->b.blocks.triple_indir_block; + status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, + (char *)tigp_buffer); + for (i = 0; i < fs->blksz / sizeof(int); i++) { + if (*tigp_buffer == 0) + break; + debug("tigp buffer releasing %u\n", *tigp_buffer); + + tip_buffer = zalloc(fs->blksz); + if (!tip_buffer) + goto fail; + tipb_start_addr = (unsigned int *)tip_buffer; + status = ext4fs_devread((*tigp_buffer) * + fs->sect_perblk, 0, fs->blksz, + (char *)tip_buffer); + for (j = 0; j < fs->blksz / sizeof(int); j++) { + if (*tip_buffer == 0) + break; + if (fs->blksz != 1024) { + bg_idx = (*tip_buffer) / blk_per_grp; + } else { + bg_idx = (*tip_buffer) / blk_per_grp; + + remainder = (*tip_buffer) % blk_per_grp; + if (!remainder) + bg_idx--; + } + + ext4fs_reset_block_bmap(*tip_buffer, + fs->blk_bmaps[bg_idx], + bg_idx); + + tip_buffer++; + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + status = + ext4fs_devread( + bgd[bg_idx].block_id * + fs->sect_perblk, 0, + fs->blksz, + journal_buffer); + if (status == 0) + goto fail; + + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx]. + block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + } + free(tipb_start_addr); + tipb_start_addr = NULL; + + /* + * removing the grand parent blocks + * which is connected to inode + */ + if (fs->blksz != 1024) { + bg_idx = (*tigp_buffer) / blk_per_grp; + } else { + bg_idx = (*tigp_buffer) / blk_per_grp; + + remainder = (*tigp_buffer) % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(*tigp_buffer, + fs->blk_bmaps[bg_idx], bg_idx); + + tigp_buffer++; + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + memset(journal_buffer, '\0', fs->blksz); + status = + ext4fs_devread(bgd[bg_idx].block_id * + fs->sect_perblk, 0, + fs->blksz, journal_buffer); + if (status == 0) + goto fail; + + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + } + + /* removing the grand parent triple indirect block */ + blknr = inode->b.blocks.triple_indir_block; + if (fs->blksz != 1024) { + bg_idx = blknr / blk_per_grp; + } else { + bg_idx = blknr / blk_per_grp; + remainder = blknr % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + memset(journal_buffer, '\0', fs->blksz); + status = ext4fs_devread(bgd[bg_idx].block_id * + fs->sect_perblk, 0, fs->blksz, + journal_buffer); + if (status == 0) + goto fail; + + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + debug("tigp buffer itself releasing %ld\n", blknr); + } +fail: + free(tib_start_addr); + free(tipb_start_addr); + free(journal_buffer); +} + +static int ext4fs_delete_file(int inodeno) +{ + struct ext2_inode inode; + short status; + int i; + int remainder; + long int blknr; + int bg_idx; + int ibmap_idx; + char *read_buffer = NULL; + char *start_block_address = NULL; + unsigned int no_blocks; + + static int prev_bg_bmap_idx = -1; + unsigned int inodes_per_block; + long int blkno; + unsigned int blkoff; + unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; + unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group; + struct ext2_inode *inode_buffer = NULL; + struct ext2_block_group *bgd = NULL; + struct ext_filesystem *fs = get_fs(); + char *journal_buffer = zalloc(fs->blksz); + if (!journal_buffer) + return -ENOMEM; + /* get the block group descriptor table */ + bgd = (struct ext2_block_group *)fs->gdtable; + status = ext4fs_read_inode(ext4fs_root, inodeno, &inode); + if (status == 0) + goto fail; + + /* read the block no allocated to a file */ + no_blocks = inode.size / fs->blksz; + if (inode.size % fs->blksz) + no_blocks++; + + if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { + struct ext2fs_node *node_inode = + zalloc(sizeof(struct ext2fs_node)); + if (!node_inode) + goto fail; + node_inode->data = ext4fs_root; + node_inode->ino = inodeno; + node_inode->inode_read = 0; + memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode)); + + for (i = 0; i < no_blocks; i++) { + blknr = read_allocated_block(&(node_inode->inode), i); + if (fs->blksz != 1024) { + bg_idx = blknr / blk_per_grp; + } else { + bg_idx = blknr / blk_per_grp; + remainder = blknr % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], + bg_idx); + debug("EXT4_EXTENTS Block releasing %ld: %d\n", + blknr, bg_idx); + + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + status = + ext4fs_devread(bgd[bg_idx].block_id * + fs->sect_perblk, 0, + fs->blksz, journal_buffer); + if (status == 0) + goto fail; + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + } + if (node_inode) { + free(node_inode); + node_inode = NULL; + } + } else { + + delete_single_indirect_block(&inode); + delete_double_indirect_block(&inode); + delete_triple_indirect_block(&inode); + + /* read the block no allocated to a file */ + no_blocks = inode.size / fs->blksz; + if (inode.size % fs->blksz) + no_blocks++; + for (i = 0; i < no_blocks; i++) { + blknr = read_allocated_block(&inode, i); + if (fs->blksz != 1024) { + bg_idx = blknr / blk_per_grp; + } else { + bg_idx = blknr / blk_per_grp; + remainder = blknr % blk_per_grp; + if (!remainder) + bg_idx--; + } + ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], + bg_idx); + debug("ActualB releasing %ld: %d\n", blknr, bg_idx); + + bgd[bg_idx].free_blocks++; + fs->sb->free_blocks++; + /* journal backup */ + if (prev_bg_bmap_idx != bg_idx) { + memset(journal_buffer, '\0', fs->blksz); + status = ext4fs_devread(bgd[bg_idx].block_id + * fs->sect_perblk, + 0, fs->blksz, + journal_buffer); + if (status == 0) + goto fail; + if (ext4fs_log_journal(journal_buffer, + bgd[bg_idx].block_id)) + goto fail; + prev_bg_bmap_idx = bg_idx; + } + } + } + + /* from the inode no to blockno */ + inodes_per_block = fs->blksz / fs->inodesz; + ibmap_idx = inodeno / inode_per_grp; + + /* get the block no */ + inodeno--; + blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) + + (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block; + + /* get the offset of the inode */ + blkoff = ((inodeno) % inodes_per_block) * fs->inodesz; + + /* read the block no containing the inode */ + read_buffer = zalloc(fs->blksz); + if (!read_buffer) + goto fail; + start_block_address = read_buffer; + status = ext4fs_devread(blkno * fs->sect_perblk, + 0, fs->blksz, read_buffer); + if (status == 0) + goto fail; + + if (ext4fs_log_journal(read_buffer, blkno)) + goto fail; + + read_buffer = read_buffer + blkoff; + inode_buffer = (struct ext2_inode *)read_buffer; + memset(inode_buffer, '\0', sizeof(struct ext2_inode)); + + /* write the inode to original position in inode table */ + if (ext4fs_put_metadata(start_block_address, blkno)) + goto fail; + + /* update the respective inode bitmaps */ + inodeno++; + ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx); + bgd[ibmap_idx].free_inodes++; + fs->sb->free_inodes++; + /* journal backup */ + memset(journal_buffer, '\0', fs->blksz); + status = ext4fs_devread(bgd[ibmap_idx].inode_id * + fs->sect_perblk, 0, fs->blksz, journal_buffer); + if (status == 0) + goto fail; + if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id)) + goto fail; + + ext4fs_update(); + ext4fs_deinit(); + + if (ext4fs_init() != 0) { + printf("error in File System init\n"); + goto fail; + } + + free(start_block_address); + free(journal_buffer); + + return 0; +fail: + free(start_block_address); + free(journal_buffer); + + return -1; +} + +int ext4fs_init(void) +{ + short status; + int i; + unsigned int real_free_blocks = 0; + struct ext_filesystem *fs = get_fs(); + + /* populate fs */ + fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root); + fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root); + fs->sect_perblk = fs->blksz / SECTOR_SIZE; + + /* get the superblock */ + fs->sb = zalloc(SUPERBLOCK_SIZE); + if (!fs->sb) + return -ENOMEM; + if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, + (char *)fs->sb)) + goto fail; + + /* init journal */ + if (ext4fs_init_journal()) + goto fail; + + /* get total no of blockgroups */ + fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( + (ext4fs_root->sblock.total_blocks - + ext4fs_root->sblock.first_data_block), + ext4fs_root->sblock.blocks_per_group); + + /* get the block group descriptor table */ + fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); + if (ext4fs_get_bgdtable() == -1) { + printf("Error in getting the block group descriptor table\n"); + goto fail; + } + fs->bgd = (struct ext2_block_group *)fs->gdtable; + + /* load all the available bitmap block of the partition */ + fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); + if (!fs->blk_bmaps) + goto fail; + for (i = 0; i < fs->no_blkgrp; i++) { + fs->blk_bmaps[i] = zalloc(fs->blksz); + if (!fs->blk_bmaps[i]) + goto fail; + } + + for (i = 0; i < fs->no_blkgrp; i++) { + status = + ext4fs_devread(fs->bgd[i].block_id * fs->sect_perblk, 0, + fs->blksz, (char *)fs->blk_bmaps[i]); + if (status == 0) + goto fail; + } + + /* load all the available inode bitmap of the partition */ + fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); + if (!fs->inode_bmaps) + goto fail; + for (i = 0; i < fs->no_blkgrp; i++) { + fs->inode_bmaps[i] = zalloc(fs->blksz); + if (!fs->inode_bmaps[i]) + goto fail; + } + + for (i = 0; i < fs->no_blkgrp; i++) { + status = ext4fs_devread(fs->bgd[i].inode_id * fs->sect_perblk, + 0, fs->blksz, + (char *)fs->inode_bmaps[i]); + if (status == 0) + goto fail; + } + + /* + * check filesystem consistency with free blocks of file system + * some time we observed that superblock freeblocks does not match + * with the blockgroups freeblocks when improper + * reboot of a linux kernel + */ + for (i = 0; i < fs->no_blkgrp; i++) + real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks; + if (real_free_blocks != fs->sb->free_blocks) + fs->sb->free_blocks = real_free_blocks; + + return 0; +fail: + ext4fs_deinit(); + + return -1; +} + +void ext4fs_deinit(void) +{ + int i; + struct ext2_inode inode_journal; + struct journal_superblock_t *jsb; + long int blknr; + struct ext_filesystem *fs = get_fs(); + + /* free journal */ + char *temp_buff = zalloc(fs->blksz); + if (temp_buff) { + ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, + &inode_journal); + blknr = read_allocated_block(&inode_journal, + EXT2_JOURNAL_SUPERBLOCK); + ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, + temp_buff); + jsb = (struct journal_superblock_t *)temp_buff; + jsb->s_start = cpu_to_be32(0); + put_ext4((uint64_t) (blknr * fs->blksz), + (struct journal_superblock_t *)temp_buff, fs->blksz); + free(temp_buff); + } + ext4fs_free_journal(); + + /* get the superblock */ + ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb); + fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; + put_ext4((uint64_t)(SUPERBLOCK_SIZE), + (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); + free(fs->sb); + fs->sb = NULL; + + if (fs->blk_bmaps) { + for (i = 0; i < fs->no_blkgrp; i++) { + free(fs->blk_bmaps[i]); + fs->blk_bmaps[i] = NULL; + } + free(fs->blk_bmaps); + fs->blk_bmaps = NULL; + } + + if (fs->inode_bmaps) { + for (i = 0; i < fs->no_blkgrp; i++) { + free(fs->inode_bmaps[i]); + fs->inode_bmaps[i] = NULL; + } + free(fs->inode_bmaps); + fs->inode_bmaps = NULL; + } + + + free(fs->gdtable); + fs->gdtable = NULL; + fs->bgd = NULL; + /* + * reinitiliazed the global inode and + * block bitmap first execution check variables + */ + fs->first_pass_ibmap = 0; + fs->first_pass_bbmap = 0; + fs->curr_inode_no = 0; + fs->curr_blkno = 0; +} + +static int ext4fs_write_file(struct ext2_inode *file_inode, + int pos, unsigned int len, char *buf) +{ + int i; + int blockcnt; + int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root); + unsigned int filesize = __le32_to_cpu(file_inode->size); + struct ext_filesystem *fs = get_fs(); + int previous_block_number = -1; + int delayed_start = 0; + int delayed_extent = 0; + int delayed_next = 0; + char *delayed_buf = NULL; + + /* Adjust len so it we can't read past the end of the file. */ + if (len > filesize) + len = filesize; + + blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; + + for (i = pos / fs->blksz; i < blockcnt; i++) { + long int blknr; + int blockend = fs->blksz; + int skipfirst = 0; + blknr = read_allocated_block(file_inode, i); + if (blknr < 0) + return -1; + + blknr = blknr << log2blocksize; + + if (blknr) { + if (previous_block_number != -1) { + if (delayed_next == blknr) { + delayed_extent += blockend; + delayed_next += blockend >> SECTOR_BITS; + } else { /* spill */ + put_ext4((uint64_t) (delayed_start * + SECTOR_SIZE), + delayed_buf, + (uint32_t) delayed_extent); + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_buf = buf; + delayed_next = blknr + + (blockend >> SECTOR_BITS); + } + } else { + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_buf = buf; + delayed_next = blknr + + (blockend >> SECTOR_BITS); + } + } else { + if (previous_block_number != -1) { + /* spill */ + put_ext4((uint64_t) (delayed_start * + SECTOR_SIZE), delayed_buf, + (uint32_t) delayed_extent); + previous_block_number = -1; + } + memset(buf, 0, fs->blksz - skipfirst); + } + buf += fs->blksz - skipfirst; + } + if (previous_block_number != -1) { + /* spill */ + put_ext4((uint64_t) (delayed_start * SECTOR_SIZE), + delayed_buf, (uint32_t) delayed_extent); + previous_block_number = -1; + } + + return len; +} + +int ext4fs_write(const char *fname, unsigned char *buffer, + unsigned long sizebytes) +{ + int ret = 0; + struct ext2_inode *file_inode = NULL; + unsigned char *inode_buffer = NULL; + int parent_inodeno; + int inodeno; + time_t timestamp = 0; + + uint64_t bytes_reqd_for_file; + unsigned int blks_reqd_for_file; + unsigned int blocks_remaining; + int existing_file_inodeno; + char *temp_ptr = NULL; + long int itable_blkno; + long int parent_itable_blkno; + long int blkoff; + struct ext2_sblock *sblock = &(ext4fs_root->sblock); + unsigned int inodes_per_block; + unsigned int ibmap_idx; + struct ext_filesystem *fs = get_fs(); + ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); + memset(filename, 0x00, sizeof(filename)); + + g_parent_inode = zalloc(sizeof(struct ext2_inode)); + if (!g_parent_inode) + goto fail; + + if (ext4fs_init() != 0) { + printf("error in File System init\n"); + return -1; + } + inodes_per_block = fs->blksz / fs->inodesz; + parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); + if (parent_inodeno == -1) + goto fail; + if (ext4fs_iget(parent_inodeno, g_parent_inode)) + goto fail; + /* check if the filename is already present in root */ + existing_file_inodeno = ext4fs_filename_check(filename); + if (existing_file_inodeno != -1) { + ret = ext4fs_delete_file(existing_file_inodeno); + fs->first_pass_bbmap = 0; + fs->curr_blkno = 0; + + fs->first_pass_ibmap = 0; + fs->curr_inode_no = 0; + if (ret) + goto fail; + } + /* calucalate how many blocks required */ + bytes_reqd_for_file = sizebytes; + blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); + if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { + blks_reqd_for_file++; + debug("total bytes for a file %u\n", blks_reqd_for_file); + } + blocks_remaining = blks_reqd_for_file; + /* test for available space in partition */ + if (fs->sb->free_blocks < blks_reqd_for_file) { + printf("Not enough space on partition !!!\n"); + goto fail; + } + + ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG); + /* prepare file inode */ + inode_buffer = zalloc(fs->inodesz); + if (!inode_buffer) + goto fail; + file_inode = (struct ext2_inode *)inode_buffer; + file_inode->mode = S_IFREG | S_IRWXU | + S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH; + /* ToDo: Update correct time */ + file_inode->mtime = timestamp; + file_inode->atime = timestamp; + file_inode->ctime = timestamp; + file_inode->nlinks = 1; + file_inode->size = sizebytes; + + /* Allocate data blocks */ + ext4fs_allocate_blocks(file_inode, blocks_remaining, + &blks_reqd_for_file); + file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE; + + temp_ptr = zalloc(fs->blksz); + if (!temp_ptr) + goto fail; + ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group; + inodeno--; + itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + + (inodeno % __le32_to_cpu(sblock->inodes_per_group)) / + inodes_per_block; + blkoff = (inodeno % inodes_per_block) * fs->inodesz; + ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr); + if (ext4fs_log_journal(temp_ptr, itable_blkno)) + goto fail; + + memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz); + if (ext4fs_put_metadata(temp_ptr, itable_blkno)) + goto fail; + /* copy the file content into data blocks */ + if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { + printf("Error in copying content\n"); + goto fail; + } + ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group; + parent_inodeno--; + parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + + (parent_inodeno % + __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; + blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz; + if (parent_itable_blkno != itable_blkno) { + memset(temp_ptr, '\0', fs->blksz); + ext4fs_devread(parent_itable_blkno * fs->sect_perblk, + 0, fs->blksz, temp_ptr); + if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) + goto fail; + + memcpy(temp_ptr + blkoff, g_parent_inode, + sizeof(struct ext2_inode)); + if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) + goto fail; + free(temp_ptr); + } else { + /* + * If parent and child fall in same inode table block + * both should be kept in 1 buffer + */ + memcpy(temp_ptr + blkoff, g_parent_inode, + sizeof(struct ext2_inode)); + gd_index--; + if (ext4fs_put_metadata(temp_ptr, itable_blkno)) + goto fail; + free(temp_ptr); + } + ext4fs_update(); + ext4fs_deinit(); + + fs->first_pass_bbmap = 0; + fs->curr_blkno = 0; + fs->first_pass_ibmap = 0; + fs->curr_inode_no = 0; + free(inode_buffer); + free(g_parent_inode); + g_parent_inode = NULL; + + return 0; +fail: + ext4fs_deinit(); + free(inode_buffer); + free(g_parent_inode); + g_parent_inode = NULL; + + return -1; +} diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index f02c215..7fdb463 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -34,13 +34,8 @@ */
#include <common.h> -#include <malloc.h> #include <ext_common.h> #include <ext4fs.h> -#include <linux/stat.h> -#include <linux/time.h> -#include <asm/byteorder.h> -#include <div64.h> #include "ext4_common.h"
int ext4fs_symlinknest; @@ -196,961 +191,3 @@ int ext4fs_read(char *buf, unsigned len)
return ext4fs_read_file(ext4fs_file, 0, len, buf); } - -#if defined(CONFIG_EXT4_WRITE) -static void ext4fs_update(void) -{ - short i; - ext4fs_update_journal(); - struct ext_filesystem *fs = get_fs(); - - /* update super block */ - put_ext4((uint64_t)(SUPERBLOCK_SIZE), - (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); - - /* update block groups */ - for (i = 0; i < fs->no_blkgrp; i++) { - fs->bgd[i].bg_checksum = ext4fs_checksum_update(i); - put_ext4((uint64_t)(fs->bgd[i].block_id * fs->blksz), - fs->blk_bmaps[i], fs->blksz); - } - - /* update inode table groups */ - for (i = 0; i < fs->no_blkgrp; i++) { - put_ext4((uint64_t) (fs->bgd[i].inode_id * fs->blksz), - fs->inode_bmaps[i], fs->blksz); - } - - /* update the block group descriptor table */ - put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz), - (struct ext2_block_group *)fs->gdtable, - (fs->blksz * fs->no_blk_pergdt)); - - ext4fs_dump_metadata(); - - gindex = 0; - gd_index = 0; -} - -int ext4fs_get_bgdtable(void) -{ - int status; - int grp_desc_size; - struct ext_filesystem *fs = get_fs(); - grp_desc_size = sizeof(struct ext2_block_group); - fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz; - if ((fs->no_blkgrp * grp_desc_size) % fs->blksz) - fs->no_blk_pergdt++; - - /* allocate memory for gdtable */ - fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt); - if (!fs->gdtable) - return -ENOMEM; - /* read the group descriptor table */ - status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0, - fs->blksz * fs->no_blk_pergdt, fs->gdtable); - if (status == 0) - goto fail; - - if (ext4fs_log_gdt(fs->gdtable)) { - printf("Error in ext4fs_log_gdt\n"); - return -1; - } - - return 0; -fail: - free(fs->gdtable); - fs->gdtable = NULL; - - return -1; -} - -static void delete_single_indirect_block(struct ext2_inode *inode) -{ - struct ext2_block_group *bgd = NULL; - static int prev_bg_bmap_idx = -1; - long int blknr; - int remainder; - int bg_idx; - int status; - unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; - struct ext_filesystem *fs = get_fs(); - char *journal_buffer = zalloc(fs->blksz); - if (!journal_buffer) { - printf("No memory\n"); - return; - } - /* get block group descriptor table */ - bgd = (struct ext2_block_group *)fs->gdtable; - - /* deleting the single indirect block associated with inode */ - if (inode->b.blocks.indir_block != 0) { - debug("SIPB releasing %u\n", inode->b.blocks.indir_block); - blknr = inode->b.blocks.indir_block; - if (fs->blksz != 1024) { - bg_idx = blknr / blk_per_grp; - } else { - bg_idx = blknr / blk_per_grp; - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - status = - ext4fs_devread(bgd[bg_idx].block_id * - fs->sect_perblk, 0, fs->blksz, - journal_buffer); - if (status == 0) - goto fail; - if (ext4fs_log_journal - (journal_buffer, bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } -fail: - free(journal_buffer); -} - -static void delete_double_indirect_block(struct ext2_inode *inode) -{ - int i; - short status; - static int prev_bg_bmap_idx = -1; - long int blknr; - int remainder; - int bg_idx; - unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; - unsigned int *di_buffer = NULL; - unsigned int *DIB_start_addr = NULL; - struct ext2_block_group *bgd = NULL; - struct ext_filesystem *fs = get_fs(); - char *journal_buffer = zalloc(fs->blksz); - if (!journal_buffer) { - printf("No memory\n"); - return; - } - /* get the block group descriptor table */ - bgd = (struct ext2_block_group *)fs->gdtable; - - if (inode->b.blocks.double_indir_block != 0) { - di_buffer = zalloc(fs->blksz); - if (!di_buffer) { - printf("No memory\n"); - return; - } - DIB_start_addr = (unsigned int *)di_buffer; - blknr = inode->b.blocks.double_indir_block; - status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, - (char *)di_buffer); - for (i = 0; i < fs->blksz / sizeof(int); i++) { - if (*di_buffer == 0) - break; - - debug("DICB releasing %u\n", *di_buffer); - if (fs->blksz != 1024) { - bg_idx = (*di_buffer) / blk_per_grp; - } else { - bg_idx = (*di_buffer) / blk_per_grp; - remainder = (*di_buffer) % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(*di_buffer, - fs->blk_bmaps[bg_idx], bg_idx); - di_buffer++; - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - status = ext4fs_devread(bgd[bg_idx].block_id - * fs->sect_perblk, 0, - fs->blksz, - journal_buffer); - if (status == 0) - goto fail; - - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } - - /* removing the parent double indirect block */ - blknr = inode->b.blocks.double_indir_block; - if (fs->blksz != 1024) { - bg_idx = blknr / blk_per_grp; - } else { - bg_idx = blknr / blk_per_grp; - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - memset(journal_buffer, '\0', fs->blksz); - status = ext4fs_devread(bgd[bg_idx].block_id * - fs->sect_perblk, 0, fs->blksz, - journal_buffer); - if (status == 0) - goto fail; - - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - debug("DIPB releasing %ld\n", blknr); - } -fail: - free(DIB_start_addr); - free(journal_buffer); -} - -static void delete_triple_indirect_block(struct ext2_inode *inode) -{ - int i, j; - short status; - static int prev_bg_bmap_idx = -1; - long int blknr; - int remainder; - int bg_idx; - unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; - unsigned int *tigp_buffer = NULL; - unsigned int *tib_start_addr = NULL; - unsigned int *tip_buffer = NULL; - unsigned int *tipb_start_addr = NULL; - struct ext2_block_group *bgd = NULL; - struct ext_filesystem *fs = get_fs(); - char *journal_buffer = zalloc(fs->blksz); - if (!journal_buffer) { - printf("No memory\n"); - return; - } - /* get block group descriptor table */ - bgd = (struct ext2_block_group *)fs->gdtable; - - if (inode->b.blocks.triple_indir_block != 0) { - tigp_buffer = zalloc(fs->blksz); - if (!tigp_buffer) { - printf("No memory\n"); - return; - } - tib_start_addr = (unsigned int *)tigp_buffer; - blknr = inode->b.blocks.triple_indir_block; - status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, - (char *)tigp_buffer); - for (i = 0; i < fs->blksz / sizeof(int); i++) { - if (*tigp_buffer == 0) - break; - debug("tigp buffer releasing %u\n", *tigp_buffer); - - tip_buffer = zalloc(fs->blksz); - if (!tip_buffer) - goto fail; - tipb_start_addr = (unsigned int *)tip_buffer; - status = ext4fs_devread((*tigp_buffer) * - fs->sect_perblk, 0, fs->blksz, - (char *)tip_buffer); - for (j = 0; j < fs->blksz / sizeof(int); j++) { - if (*tip_buffer == 0) - break; - if (fs->blksz != 1024) { - bg_idx = (*tip_buffer) / blk_per_grp; - } else { - bg_idx = (*tip_buffer) / blk_per_grp; - - remainder = (*tip_buffer) % blk_per_grp; - if (!remainder) - bg_idx--; - } - - ext4fs_reset_block_bmap(*tip_buffer, - fs->blk_bmaps[bg_idx], - bg_idx); - - tip_buffer++; - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - status = - ext4fs_devread( - bgd[bg_idx].block_id * - fs->sect_perblk, 0, - fs->blksz, - journal_buffer); - if (status == 0) - goto fail; - - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx]. - block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } - free(tipb_start_addr); - tipb_start_addr = NULL; - - /* - * removing the grand parent blocks - * which is connected to inode - */ - if (fs->blksz != 1024) { - bg_idx = (*tigp_buffer) / blk_per_grp; - } else { - bg_idx = (*tigp_buffer) / blk_per_grp; - - remainder = (*tigp_buffer) % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(*tigp_buffer, - fs->blk_bmaps[bg_idx], bg_idx); - - tigp_buffer++; - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - memset(journal_buffer, '\0', fs->blksz); - status = - ext4fs_devread(bgd[bg_idx].block_id * - fs->sect_perblk, 0, - fs->blksz, journal_buffer); - if (status == 0) - goto fail; - - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } - - /* removing the grand parent triple indirect block */ - blknr = inode->b.blocks.triple_indir_block; - if (fs->blksz != 1024) { - bg_idx = blknr / blk_per_grp; - } else { - bg_idx = blknr / blk_per_grp; - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - memset(journal_buffer, '\0', fs->blksz); - status = ext4fs_devread(bgd[bg_idx].block_id * - fs->sect_perblk, 0, fs->blksz, - journal_buffer); - if (status == 0) - goto fail; - - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - debug("tigp buffer itself releasing %ld\n", blknr); - } -fail: - free(tib_start_addr); - free(tipb_start_addr); - free(journal_buffer); -} - -static int ext4fs_delete_file(int inodeno) -{ - struct ext2_inode inode; - short status; - int i; - int remainder; - long int blknr; - int bg_idx; - int ibmap_idx; - char *read_buffer = NULL; - char *start_block_address = NULL; - unsigned int no_blocks; - - static int prev_bg_bmap_idx = -1; - unsigned int inodes_per_block; - long int blkno; - unsigned int blkoff; - unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; - unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group; - struct ext2_inode *inode_buffer = NULL; - struct ext2_block_group *bgd = NULL; - struct ext_filesystem *fs = get_fs(); - char *journal_buffer = zalloc(fs->blksz); - if (!journal_buffer) - return -ENOMEM; - /* get the block group descriptor table */ - bgd = (struct ext2_block_group *)fs->gdtable; - status = ext4fs_read_inode(ext4fs_root, inodeno, &inode); - if (status == 0) - goto fail; - - /* read the block no allocated to a file */ - no_blocks = inode.size / fs->blksz; - if (inode.size % fs->blksz) - no_blocks++; - - if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { - struct ext2fs_node *node_inode = - zalloc(sizeof(struct ext2fs_node)); - if (!node_inode) - goto fail; - node_inode->data = ext4fs_root; - node_inode->ino = inodeno; - node_inode->inode_read = 0; - memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode)); - - for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(&(node_inode->inode), i); - if (fs->blksz != 1024) { - bg_idx = blknr / blk_per_grp; - } else { - bg_idx = blknr / blk_per_grp; - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], - bg_idx); - debug("EXT4_EXTENTS Block releasing %ld: %d\n", - blknr, bg_idx); - - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - status = - ext4fs_devread(bgd[bg_idx].block_id * - fs->sect_perblk, 0, - fs->blksz, journal_buffer); - if (status == 0) - goto fail; - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } - if (node_inode) { - free(node_inode); - node_inode = NULL; - } - } else { - - delete_single_indirect_block(&inode); - delete_double_indirect_block(&inode); - delete_triple_indirect_block(&inode); - - /* read the block no allocated to a file */ - no_blocks = inode.size / fs->blksz; - if (inode.size % fs->blksz) - no_blocks++; - for (i = 0; i < no_blocks; i++) { - blknr = read_allocated_block(&inode, i); - if (fs->blksz != 1024) { - bg_idx = blknr / blk_per_grp; - } else { - bg_idx = blknr / blk_per_grp; - remainder = blknr % blk_per_grp; - if (!remainder) - bg_idx--; - } - ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], - bg_idx); - debug("ActualB releasing %ld: %d\n", blknr, bg_idx); - - bgd[bg_idx].free_blocks++; - fs->sb->free_blocks++; - /* journal backup */ - if (prev_bg_bmap_idx != bg_idx) { - memset(journal_buffer, '\0', fs->blksz); - status = ext4fs_devread(bgd[bg_idx].block_id - * fs->sect_perblk, - 0, fs->blksz, - journal_buffer); - if (status == 0) - goto fail; - if (ext4fs_log_journal(journal_buffer, - bgd[bg_idx].block_id)) - goto fail; - prev_bg_bmap_idx = bg_idx; - } - } - } - - /* from the inode no to blockno */ - inodes_per_block = fs->blksz / fs->inodesz; - ibmap_idx = inodeno / inode_per_grp; - - /* get the block no */ - inodeno--; - blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) + - (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block; - - /* get the offset of the inode */ - blkoff = ((inodeno) % inodes_per_block) * fs->inodesz; - - /* read the block no containing the inode */ - read_buffer = zalloc(fs->blksz); - if (!read_buffer) - goto fail; - start_block_address = read_buffer; - status = ext4fs_devread(blkno * fs->sect_perblk, - 0, fs->blksz, read_buffer); - if (status == 0) - goto fail; - - if (ext4fs_log_journal(read_buffer, blkno)) - goto fail; - - read_buffer = read_buffer + blkoff; - inode_buffer = (struct ext2_inode *)read_buffer; - memset(inode_buffer, '\0', sizeof(struct ext2_inode)); - - /* write the inode to original position in inode table */ - if (ext4fs_put_metadata(start_block_address, blkno)) - goto fail; - - /* update the respective inode bitmaps */ - inodeno++; - ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx); - bgd[ibmap_idx].free_inodes++; - fs->sb->free_inodes++; - /* journal backup */ - memset(journal_buffer, '\0', fs->blksz); - status = ext4fs_devread(bgd[ibmap_idx].inode_id * - fs->sect_perblk, 0, fs->blksz, journal_buffer); - if (status == 0) - goto fail; - if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id)) - goto fail; - - ext4fs_update(); - ext4fs_deinit(); - - if (ext4fs_init() != 0) { - printf("error in File System init\n"); - goto fail; - } - - free(start_block_address); - free(journal_buffer); - - return 0; -fail: - free(start_block_address); - free(journal_buffer); - - return -1; -} - -int ext4fs_init(void) -{ - short status; - int i; - unsigned int real_free_blocks = 0; - struct ext_filesystem *fs = get_fs(); - - /* populate fs */ - fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root); - fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root); - fs->sect_perblk = fs->blksz / SECTOR_SIZE; - - /* get the superblock */ - fs->sb = zalloc(SUPERBLOCK_SIZE); - if (!fs->sb) - return -ENOMEM; - if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, - (char *)fs->sb)) - goto fail; - - /* init journal */ - if (ext4fs_init_journal()) - goto fail; - - /* get total no of blockgroups */ - fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( - (ext4fs_root->sblock.total_blocks - - ext4fs_root->sblock.first_data_block), - ext4fs_root->sblock.blocks_per_group); - - /* get the block group descriptor table */ - fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); - if (ext4fs_get_bgdtable() == -1) { - printf("Error in getting the block group descriptor table\n"); - goto fail; - } - fs->bgd = (struct ext2_block_group *)fs->gdtable; - - /* load all the available bitmap block of the partition */ - fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); - if (!fs->blk_bmaps) - goto fail; - for (i = 0; i < fs->no_blkgrp; i++) { - fs->blk_bmaps[i] = zalloc(fs->blksz); - if (!fs->blk_bmaps[i]) - goto fail; - } - - for (i = 0; i < fs->no_blkgrp; i++) { - status = - ext4fs_devread(fs->bgd[i].block_id * fs->sect_perblk, 0, - fs->blksz, (char *)fs->blk_bmaps[i]); - if (status == 0) - goto fail; - } - - /* load all the available inode bitmap of the partition */ - fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); - if (!fs->inode_bmaps) - goto fail; - for (i = 0; i < fs->no_blkgrp; i++) { - fs->inode_bmaps[i] = zalloc(fs->blksz); - if (!fs->inode_bmaps[i]) - goto fail; - } - - for (i = 0; i < fs->no_blkgrp; i++) { - status = ext4fs_devread(fs->bgd[i].inode_id * fs->sect_perblk, - 0, fs->blksz, - (char *)fs->inode_bmaps[i]); - if (status == 0) - goto fail; - } - - /* - * check filesystem consistency with free blocks of file system - * some time we observed that superblock freeblocks does not match - * with the blockgroups freeblocks when improper - * reboot of a linux kernel - */ - for (i = 0; i < fs->no_blkgrp; i++) - real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks; - if (real_free_blocks != fs->sb->free_blocks) - fs->sb->free_blocks = real_free_blocks; - - return 0; -fail: - ext4fs_deinit(); - - return -1; -} - -void ext4fs_deinit(void) -{ - int i; - struct ext2_inode inode_journal; - struct journal_superblock_t *jsb; - long int blknr; - struct ext_filesystem *fs = get_fs(); - - /* free journal */ - char *temp_buff = zalloc(fs->blksz); - if (temp_buff) { - ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, - &inode_journal); - blknr = read_allocated_block(&inode_journal, - EXT2_JOURNAL_SUPERBLOCK); - ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, - temp_buff); - jsb = (struct journal_superblock_t *)temp_buff; - jsb->s_start = cpu_to_be32(0); - put_ext4((uint64_t) (blknr * fs->blksz), - (struct journal_superblock_t *)temp_buff, fs->blksz); - free(temp_buff); - } - ext4fs_free_journal(); - - /* get the superblock */ - ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb); - fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; - put_ext4((uint64_t)(SUPERBLOCK_SIZE), - (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); - free(fs->sb); - fs->sb = NULL; - - if (fs->blk_bmaps) { - for (i = 0; i < fs->no_blkgrp; i++) { - free(fs->blk_bmaps[i]); - fs->blk_bmaps[i] = NULL; - } - free(fs->blk_bmaps); - fs->blk_bmaps = NULL; - } - - if (fs->inode_bmaps) { - for (i = 0; i < fs->no_blkgrp; i++) { - free(fs->inode_bmaps[i]); - fs->inode_bmaps[i] = NULL; - } - free(fs->inode_bmaps); - fs->inode_bmaps = NULL; - } - - - free(fs->gdtable); - fs->gdtable = NULL; - fs->bgd = NULL; - /* - * reinitiliazed the global inode and - * block bitmap first execution check variables - */ - fs->first_pass_ibmap = 0; - fs->first_pass_bbmap = 0; - fs->curr_inode_no = 0; - fs->curr_blkno = 0; -} - -static int ext4fs_write_file(struct ext2_inode *file_inode, - int pos, unsigned int len, char *buf) -{ - int i; - int blockcnt; - int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root); - unsigned int filesize = __le32_to_cpu(file_inode->size); - struct ext_filesystem *fs = get_fs(); - int previous_block_number = -1; - int delayed_start = 0; - int delayed_extent = 0; - int delayed_next = 0; - char *delayed_buf = NULL; - - /* Adjust len so it we can't read past the end of the file. */ - if (len > filesize) - len = filesize; - - blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; - - for (i = pos / fs->blksz; i < blockcnt; i++) { - long int blknr; - int blockend = fs->blksz; - int skipfirst = 0; - blknr = read_allocated_block(file_inode, i); - if (blknr < 0) - return -1; - - blknr = blknr << log2blocksize; - - if (blknr) { - if (previous_block_number != -1) { - if (delayed_next == blknr) { - delayed_extent += blockend; - delayed_next += blockend >> SECTOR_BITS; - } else { /* spill */ - put_ext4((uint64_t) (delayed_start * - SECTOR_SIZE), - delayed_buf, - (uint32_t) delayed_extent); - previous_block_number = blknr; - delayed_start = blknr; - delayed_extent = blockend; - delayed_buf = buf; - delayed_next = blknr + - (blockend >> SECTOR_BITS); - } - } else { - previous_block_number = blknr; - delayed_start = blknr; - delayed_extent = blockend; - delayed_buf = buf; - delayed_next = blknr + - (blockend >> SECTOR_BITS); - } - } else { - if (previous_block_number != -1) { - /* spill */ - put_ext4((uint64_t) (delayed_start * - SECTOR_SIZE), delayed_buf, - (uint32_t) delayed_extent); - previous_block_number = -1; - } - memset(buf, 0, fs->blksz - skipfirst); - } - buf += fs->blksz - skipfirst; - } - if (previous_block_number != -1) { - /* spill */ - put_ext4((uint64_t) (delayed_start * SECTOR_SIZE), - delayed_buf, (uint32_t) delayed_extent); - previous_block_number = -1; - } - - return len; -} - -int ext4fs_write(const char *fname, unsigned char *buffer, - unsigned long sizebytes) -{ - int ret = 0; - struct ext2_inode *file_inode = NULL; - unsigned char *inode_buffer = NULL; - int parent_inodeno; - int inodeno; - time_t timestamp = 0; - - uint64_t bytes_reqd_for_file; - unsigned int blks_reqd_for_file; - unsigned int blocks_remaining; - int existing_file_inodeno; - char *temp_ptr = NULL; - long int itable_blkno; - long int parent_itable_blkno; - long int blkoff; - struct ext2_sblock *sblock = &(ext4fs_root->sblock); - unsigned int inodes_per_block; - unsigned int ibmap_idx; - struct ext_filesystem *fs = get_fs(); - ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); - memset(filename, 0x00, sizeof(filename)); - - g_parent_inode = zalloc(sizeof(struct ext2_inode)); - if (!g_parent_inode) - goto fail; - - if (ext4fs_init() != 0) { - printf("error in File System init\n"); - return -1; - } - inodes_per_block = fs->blksz / fs->inodesz; - parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); - if (parent_inodeno == -1) - goto fail; - if (ext4fs_iget(parent_inodeno, g_parent_inode)) - goto fail; - /* check if the filename is already present in root */ - existing_file_inodeno = ext4fs_filename_check(filename); - if (existing_file_inodeno != -1) { - ret = ext4fs_delete_file(existing_file_inodeno); - fs->first_pass_bbmap = 0; - fs->curr_blkno = 0; - - fs->first_pass_ibmap = 0; - fs->curr_inode_no = 0; - if (ret) - goto fail; - } - /* calucalate how many blocks required */ - bytes_reqd_for_file = sizebytes; - blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); - if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { - blks_reqd_for_file++; - debug("total bytes for a file %u\n", blks_reqd_for_file); - } - blocks_remaining = blks_reqd_for_file; - /* test for available space in partition */ - if (fs->sb->free_blocks < blks_reqd_for_file) { - printf("Not enough space on partition !!!\n"); - goto fail; - } - - ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG); - /* prepare file inode */ - inode_buffer = zalloc(fs->inodesz); - if (!inode_buffer) - goto fail; - file_inode = (struct ext2_inode *)inode_buffer; - file_inode->mode = S_IFREG | S_IRWXU | - S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH; - /* ToDo: Update correct time */ - file_inode->mtime = timestamp; - file_inode->atime = timestamp; - file_inode->ctime = timestamp; - file_inode->nlinks = 1; - file_inode->size = sizebytes; - - /* Allocate data blocks */ - ext4fs_allocate_blocks(file_inode, blocks_remaining, - &blks_reqd_for_file); - file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE; - - temp_ptr = zalloc(fs->blksz); - if (!temp_ptr) - goto fail; - ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group; - inodeno--; - itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + - (inodeno % __le32_to_cpu(sblock->inodes_per_group)) / - inodes_per_block; - blkoff = (inodeno % inodes_per_block) * fs->inodesz; - ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr); - if (ext4fs_log_journal(temp_ptr, itable_blkno)) - goto fail; - - memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz); - if (ext4fs_put_metadata(temp_ptr, itable_blkno)) - goto fail; - /* copy the file content into data blocks */ - if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { - printf("Error in copying content\n"); - goto fail; - } - ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group; - parent_inodeno--; - parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + - (parent_inodeno % - __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; - blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz; - if (parent_itable_blkno != itable_blkno) { - memset(temp_ptr, '\0', fs->blksz); - ext4fs_devread(parent_itable_blkno * fs->sect_perblk, - 0, fs->blksz, temp_ptr); - if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) - goto fail; - - memcpy(temp_ptr + blkoff, g_parent_inode, - sizeof(struct ext2_inode)); - if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) - goto fail; - free(temp_ptr); - } else { - /* - * If parent and child fall in same inode table block - * both should be kept in 1 buffer - */ - memcpy(temp_ptr + blkoff, g_parent_inode, - sizeof(struct ext2_inode)); - gd_index--; - if (ext4fs_put_metadata(temp_ptr, itable_blkno)) - goto fail; - free(temp_ptr); - } - ext4fs_update(); - ext4fs_deinit(); - - fs->first_pass_bbmap = 0; - fs->curr_blkno = 0; - fs->first_pass_ibmap = 0; - fs->curr_inode_no = 0; - free(inode_buffer); - free(g_parent_inode); - g_parent_inode = NULL; - - return 0; -fail: - ext4fs_deinit(); - free(inode_buffer); - free(g_parent_inode); - g_parent_inode = NULL; - - return -1; -} -#endif

Hi Simon,
This code seems to be entirely othogonal, so remove the #ifdef and put the condition in the Makefile instead.
I'm fully with you in respect of cleaning/refactoring the ext4 u-boot code.
I will test this change when I only find some time ...

Hi Simon,
This code seems to be entirely othogonal, so remove the #ifdef and put the condition in the Makefile instead.
I'm fully with you in respect of cleaning/refactoring the ext4 u-boot code.
I will test this change when I only find some time ...
Are you doing any work on ext4 code refactoring/rewritting at u-boot?

Hi Lukasz,
On Thu, Feb 7, 2013 at 3:35 AM, Lukasz Majewski l.majewski@samsung.com wrote:
Hi Simon,
This code seems to be entirely othogonal, so remove the #ifdef and put the condition in the Makefile instead.
I'm fully with you in respect of cleaning/refactoring the ext4 u-boot code.
I will test this change when I only find some time ...
Are you doing any work on ext4 code refactoring/rewritting at u-boot?
No, just the fs layer, so that I could get sandbox to work. Plus I split up the file a bit. But I have no other plans.
Regards, Simon
-- Best regards,
Lukasz Majewski
Samsung R&D Poland (SRPOL) | Linux Platform Group

Hi Simon,
Hi Lukasz,
On Thu, Feb 7, 2013 at 3:35 AM, Lukasz Majewski l.majewski@samsung.com wrote:
Hi Simon,
This code seems to be entirely othogonal, so remove the #ifdef and put the condition in the Makefile instead.
I'm fully with you in respect of cleaning/refactoring the ext4 u-boot code.
I will test this change when I only find some time ...
Are you doing any work on ext4 code refactoring/rewritting at u-boot?
No, just the fs layer, so that I could get sandbox to work. Plus I split up the file a bit. But I have no other plans.
Ok, thanks for info.
Regards, Simon
-- Best regards,
Lukasz Majewski
Samsung R&D Poland (SRPOL) | Linux Platform Group

On Wed, Dec 26, 2012 at 11:53:28AM -0800, Simon Glass wrote:
This code seems to be entirely othogonal, so remove the #ifdef and put the condition in the Makefile instead.
Signed-off-by: Simon Glass sjg@chromium.org
Reveiwed-by: Tom Rini trini@ti.com

There is a structure in fs.c with just a probe method. By adding methods for other operations, we can avoid lots of #ifdefs and switch()s. As a first step, create the structure ready for use.
Signed-off-by: Simon Glass sjg@chromium.org --- fs/fs.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/fs/fs.c b/fs/fs.c index 2c9f2c5..66835e2 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -27,6 +27,12 @@ static block_dev_desc_t *fs_dev_desc; static disk_partition_t fs_partition; static int fs_type = FS_TYPE_ANY;
+static inline int fs_probe_unsupported(void) +{ + printf("** Unrecognized filesystem type **\n"); + return -1; +} + static inline int fs_ls_unsupported(const char *dirname) { printf("** Unrecognized filesystem type **\n"); @@ -40,6 +46,10 @@ static inline int fs_read_unsupported(const char *filename, ulong addr, return -1; }
+static inline void fs_close_unsupported(void) +{ +} + #ifdef CONFIG_FS_FAT static int fs_probe_fat(void) { @@ -143,29 +153,57 @@ static inline void fs_close_ext(void) #define fs_read_ext fs_read_unsupported #endif
-static struct { +struct fstype_info { int fstype; int (*probe)(void); -} fstypes[] = { + int (*ls)(const char *dirname); + int (*read)(const char *filename, ulong addr, int offset, int len); + void (*close)(void); +}; + +static struct fstype_info fstypes[] = { +#ifdef CONFIG_FS_FAT { .fstype = FS_TYPE_FAT, .probe = fs_probe_fat, + .close = fs_close_fat, + .ls = file_fat_ls, + .read = fs_read_fat, }, +#endif +#ifdef CONFIG_FS_EXT4 { .fstype = FS_TYPE_EXT, .probe = fs_probe_ext, + .close = fs_close_ext, + .ls = ext4fs_ls, + .read = fs_read_ext, + }, +#endif + { + .fstype = FS_TYPE_ANY, + .probe = fs_probe_unsupported, + .close = fs_close_unsupported, + .ls = fs_ls_unsupported, + .read = fs_read_unsupported, }, };
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) { + struct fstype_info *info; int part, i; #ifdef CONFIG_NEEDS_MANUAL_RELOC static int relocated;
if (!relocated) { - for (i = 0; i < ARRAY_SIZE(fstypes); i++) - fstypes[i].probe += gd->reloc_off; + for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); + i++, info++) { + info->probe += gd->reloc_off; + info->close += gd->reloc_off; + info->ls += gd->reloc_off; + info->read += gd->reloc_off; + } relocated = 1; } #endif @@ -175,17 +213,17 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) if (part < 0) return -1;
- for (i = 0; i < ARRAY_SIZE(fstypes); i++) { - if ((fstype != FS_TYPE_ANY) && (fstype != fstypes[i].fstype)) + for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { + if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY && + fstype != info->fstype) continue;
- if (!fstypes[i].probe()) { - fs_type = fstypes[i].fstype; + if (!info->probe()) { + fs_type = info->fstype; return 0; } }
- printf("** Unrecognized filesystem type **\n"); return -1; }

On Wed, Dec 26, 2012 at 11:53:29AM -0800, Simon Glass wrote:
There is a structure in fs.c with just a probe method. By adding methods for other operations, we can avoid lots of #ifdefs and switch()s. As a first step, create the structure ready for use.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

We can use the available methods and avoid using switch(). When the filesystem is not supported, we fall through to the 'unsupported' methods: fs_probe_unsupported() prints an error, so the others do not need to.
Signed-off-by: Simon Glass sjg@chromium.org --- fs/fs.c | 60 ++++++++++++++++++++++++++---------------------------------- 1 files changed, 26 insertions(+), 34 deletions(-)
diff --git a/fs/fs.c b/fs/fs.c index 66835e2..856d8ba 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -35,14 +35,12 @@ static inline int fs_probe_unsupported(void)
static inline int fs_ls_unsupported(const char *dirname) { - printf("** Unrecognized filesystem type **\n"); return -1; }
static inline int fs_read_unsupported(const char *filename, ulong addr, int offset, int len) { - printf("** Unrecognized filesystem type **\n"); return -1; }
@@ -189,6 +187,20 @@ static struct fstype_info fstypes[] = { }, };
+static struct fstype_info *fs_get_info(int fstype) +{ + struct fstype_info *info; + int i; + + for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) { + if (fstype == info->fstype) + return info; + } + + /* Return the 'unsupported' sentinel */ + return info; +} + int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) { struct fstype_info *info; @@ -229,17 +241,9 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
static void fs_close(void) { - switch (fs_type) { - case FS_TYPE_FAT: - fs_close_fat(); - break; - case FS_TYPE_EXT: - fs_close_ext(); - break; - default: - break; - } + struct fstype_info *info = fs_get_info(fs_type);
+ info->close(); fs_type = FS_TYPE_ANY; }
@@ -247,17 +251,9 @@ int fs_ls(const char *dirname) { int ret;
- switch (fs_type) { - case FS_TYPE_FAT: - ret = fs_ls_fat(dirname); - break; - case FS_TYPE_EXT: - ret = fs_ls_ext(dirname); - break; - default: - ret = fs_ls_unsupported(dirname); - break; - } + struct fstype_info *info = fs_get_info(fs_type); + + ret = info->ls(dirname);
fs_close();
@@ -266,20 +262,16 @@ int fs_ls(const char *dirname)
int fs_read(const char *filename, ulong addr, int offset, int len) { + struct fstype_info *info = fs_get_info(fs_type); int ret;
- switch (fs_type) { - case FS_TYPE_FAT: - ret = fs_read_fat(filename, addr, offset, len); - break; - case FS_TYPE_EXT: - ret = fs_read_ext(filename, addr, offset, len); - break; - default: - ret = fs_read_unsupported(filename, addr, offset, len); - break; - } + ret = info->read(filename, addr, offset, len);
+ /* If we requested a specific number of bytes, check we got it */ + if (ret >= 0 && len && ret != len) { + printf("** Unable to read file %s **\n", filename); + ret = -1; + } fs_close();
return ret;

On Wed, Dec 26, 2012 at 11:53:30AM -0800, Simon Glass wrote:
We can use the available methods and avoid using switch(). When the filesystem is not supported, we fall through to the 'unsupported' methods: fs_probe_unsupported() prints an error, so the others do not need to.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

Rather than rely on global variables for the probe functions, pass in the information that we need filled in. This allows us to potentially keep the variables private to fs.c in the future, and the meaning of the probe function is clearer.
Signed-off-by: Simon Glass sjg@chromium.org --- fs/fs.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/fs/fs.c b/fs/fs.c index 856d8ba..3561727 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -27,7 +27,8 @@ static block_dev_desc_t *fs_dev_desc; static disk_partition_t fs_partition; static int fs_type = FS_TYPE_ANY;
-static inline int fs_probe_unsupported(void) +static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc, + disk_partition_t *fs_partition) { printf("** Unrecognized filesystem type **\n"); return -1; @@ -49,9 +50,10 @@ static inline void fs_close_unsupported(void) }
#ifdef CONFIG_FS_FAT -static int fs_probe_fat(void) +static int fs_probe_fat(block_dev_desc_t *fs_dev_desc, + disk_partition_t *fs_partition) { - return fat_set_blk_dev(fs_dev_desc, &fs_partition); + return fat_set_blk_dev(fs_dev_desc, fs_partition); }
static void fs_close_fat(void) @@ -88,11 +90,12 @@ static inline void fs_close_fat(void) #endif
#ifdef CONFIG_FS_EXT4 -static int fs_probe_ext(void) +static int fs_probe_ext(block_dev_desc_t *fs_dev_desc, + disk_partition_t *fs_partition) { - ext4fs_set_blk_dev(fs_dev_desc, &fs_partition); + ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
- if (!ext4fs_mount(fs_partition.size)) { + if (!ext4fs_mount(fs_partition->size)) { ext4fs_close(); return -1; } @@ -153,7 +156,8 @@ static inline void fs_close_ext(void)
struct fstype_info { int fstype; - int (*probe)(void); + int (*probe)(block_dev_desc_t *fs_dev_desc, + disk_partition_t *fs_partition); int (*ls)(const char *dirname); int (*read)(const char *filename, ulong addr, int offset, int len); void (*close)(void); @@ -230,7 +234,7 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) fstype != info->fstype) continue;
- if (!info->probe()) { + if (!info->probe(fs_dev_desc, &fs_partition)) { fs_type = info->fstype; return 0; }

On Wed, Dec 26, 2012 at 11:53:31AM -0800, Simon Glass wrote:
Rather than rely on global variables for the probe functions, pass in the information that we need filled in. This allows us to potentially keep the variables private to fs.c in the future, and the meaning of the probe function is clearer.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

This allows us to use filesystems on sandbox. It has no effect on other architectures.
Signed-off-by: Simon Glass sjg@chromium.org --- fs/fs.c | 23 +++++++++++++++-------- 1 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/fs/fs.c b/fs/fs.c index 3561727..0cbec99 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -20,6 +20,7 @@ #include <ext4fs.h> #include <fat.h> #include <fs.h> +#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -39,7 +40,7 @@ static inline int fs_ls_unsupported(const char *dirname) return -1; }
-static inline int fs_read_unsupported(const char *filename, ulong addr, +static inline int fs_read_unsupported(const char *filename, void *buf, int offset, int len) { return -1; @@ -62,12 +63,11 @@ static void fs_close_fat(void)
#define fs_ls_fat file_fat_ls
-static int fs_read_fat(const char *filename, ulong addr, int offset, int len) +static int fs_read_fat(const char *filename, void *buf, int offset, int len) { int len_read;
- len_read = file_fat_read_at(filename, offset, - (unsigned char *)addr, len); + len_read = file_fat_read_at(filename, offset, buf, len); if (len_read == -1) { printf("** Unable to read file %s **\n", filename); return -1; @@ -110,7 +110,7 @@ static void fs_close_ext(void)
#define fs_ls_ext ext4fs_ls
-static int fs_read_ext(const char *filename, ulong addr, int offset, int len) +static int fs_read_ext(const char *filename, void *buf, int offset, int len) { int file_len; int len_read; @@ -130,7 +130,7 @@ static int fs_read_ext(const char *filename, ulong addr, int offset, int len) if (len == 0) len = file_len;
- len_read = ext4fs_read((char *)addr, len); + len_read = ext4fs_read(buf, len); ext4fs_close();
if (len_read != len) { @@ -159,7 +159,7 @@ struct fstype_info { int (*probe)(block_dev_desc_t *fs_dev_desc, disk_partition_t *fs_partition); int (*ls)(const char *dirname); - int (*read)(const char *filename, ulong addr, int offset, int len); + int (*read)(const char *filename, void *buf, int offset, int len); void (*close)(void); };
@@ -267,9 +267,16 @@ int fs_ls(const char *dirname) int fs_read(const char *filename, ulong addr, int offset, int len) { struct fstype_info *info = fs_get_info(fs_type); + void *buf; int ret;
- ret = info->read(filename, addr, offset, len); + /* + * We don't actually know how many bytes are being read, since len==0 + * means read the whole file. + */ + buf = map_sysmem(addr, len); + ret = info->read(filename, buf, offset, len); + unmap_sysmem(buf);
/* If we requested a specific number of bytes, check we got it */ if (ret >= 0 && len && ret != len) {

On Wed, Dec 26, 2012 at 11:53:32AM -0800, Simon Glass wrote:
This allows us to use filesystems on sandbox. It has no effect on other architectures.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

It doesn't make a lot of sense to have these methods in fs.c. They are filesystem-specific, not generic code. Add each to the relevant filesystem and remove the associated #ifdefs in fs.c.
Signed-off-by: Simon Glass sjg@chromium.org --- fs/ext4/ext4fs.c | 37 +++++++++++++++++ fs/fat/fat.c | 17 ++++++++ fs/fs.c | 118 ++++-------------------------------------------------- include/ext4fs.h | 3 + include/fat.h | 2 + 5 files changed, 67 insertions(+), 110 deletions(-)
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c index 7fdb463..4dddde2 100644 --- a/fs/ext4/ext4fs.c +++ b/fs/ext4/ext4fs.c @@ -191,3 +191,40 @@ int ext4fs_read(char *buf, unsigned len)
return ext4fs_read_file(ext4fs_file, 0, len, buf); } + +int ext4fs_probe(block_dev_desc_t *fs_dev_desc, + disk_partition_t *fs_partition) +{ + ext4fs_set_blk_dev(fs_dev_desc, fs_partition); + + if (!ext4fs_mount(fs_partition->size)) { + ext4fs_close(); + return -1; + } + + return 0; +} + +int ext4_read_file(const char *filename, void *buf, int offset, int len) +{ + int file_len; + int len_read; + + if (offset != 0) { + printf("** Cannot support non-zero offset **\n"); + return -1; + } + + file_len = ext4fs_open(filename); + if (file_len < 0) { + printf("** File not found %s **\n", filename); + return -1; + } + + if (len == 0) + len = file_len; + + len_read = ext4fs_read(buf, len); + + return len_read; +} diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 393c378..82135b5 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -1256,3 +1256,20 @@ long file_fat_read(const char *filename, void *buffer, unsigned long maxsize) { return file_fat_read_at(filename, 0, buffer, maxsize); } + +int fat_read_file(const char *filename, void *buf, int offset, int len) +{ + int len_read; + + len_read = file_fat_read_at(filename, offset, buf, len); + if (len_read == -1) { + printf("** Unable to read file %s **\n", filename); + return -1; + } + + return len_read; +} + +void fat_close(void) +{ +} diff --git a/fs/fs.c b/fs/fs.c index 0cbec99..95c882e 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -50,110 +50,6 @@ static inline void fs_close_unsupported(void) { }
-#ifdef CONFIG_FS_FAT -static int fs_probe_fat(block_dev_desc_t *fs_dev_desc, - disk_partition_t *fs_partition) -{ - return fat_set_blk_dev(fs_dev_desc, fs_partition); -} - -static void fs_close_fat(void) -{ -} - -#define fs_ls_fat file_fat_ls - -static int fs_read_fat(const char *filename, void *buf, int offset, int len) -{ - int len_read; - - len_read = file_fat_read_at(filename, offset, buf, len); - if (len_read == -1) { - printf("** Unable to read file %s **\n", filename); - return -1; - } - - return len_read; -} -#else -static inline int fs_probe_fat(void) -{ - return -1; -} - -static inline void fs_close_fat(void) -{ -} - -#define fs_ls_fat fs_ls_unsupported -#define fs_read_fat fs_read_unsupported -#endif - -#ifdef CONFIG_FS_EXT4 -static int fs_probe_ext(block_dev_desc_t *fs_dev_desc, - disk_partition_t *fs_partition) -{ - ext4fs_set_blk_dev(fs_dev_desc, fs_partition); - - if (!ext4fs_mount(fs_partition->size)) { - ext4fs_close(); - return -1; - } - - return 0; -} - -static void fs_close_ext(void) -{ - ext4fs_close(); -} - -#define fs_ls_ext ext4fs_ls - -static int fs_read_ext(const char *filename, void *buf, int offset, int len) -{ - int file_len; - int len_read; - - if (offset != 0) { - printf("** Cannot support non-zero offset **\n"); - return -1; - } - - file_len = ext4fs_open(filename); - if (file_len < 0) { - printf("** File not found %s **\n", filename); - ext4fs_close(); - return -1; - } - - if (len == 0) - len = file_len; - - len_read = ext4fs_read(buf, len); - ext4fs_close(); - - if (len_read != len) { - printf("** Unable to read file %s **\n", filename); - return -1; - } - - return len_read; -} -#else -static inline int fs_probe_ext(void) -{ - return -1; -} - -static inline void fs_close_ext(void) -{ -} - -#define fs_ls_ext fs_ls_unsupported -#define fs_read_ext fs_read_unsupported -#endif - struct fstype_info { int fstype; int (*probe)(block_dev_desc_t *fs_dev_desc, @@ -167,19 +63,19 @@ static struct fstype_info fstypes[] = { #ifdef CONFIG_FS_FAT { .fstype = FS_TYPE_FAT, - .probe = fs_probe_fat, - .close = fs_close_fat, + .probe = fat_set_blk_dev, + .close = fat_close, .ls = file_fat_ls, - .read = fs_read_fat, + .read = fat_read_file, }, #endif #ifdef CONFIG_FS_EXT4 { .fstype = FS_TYPE_EXT, - .probe = fs_probe_ext, - .close = fs_close_ext, + .probe = ext4fs_probe, + .close = ext4fs_close, .ls = ext4fs_ls, - .read = fs_read_ext, + .read = ext4_read_file, }, #endif { @@ -248,6 +144,7 @@ static void fs_close(void) struct fstype_info *info = fs_get_info(fs_type);
info->close(); + fs_type = FS_TYPE_ANY; }
@@ -259,6 +156,7 @@ int fs_ls(const char *dirname)
ret = info->ls(dirname);
+ fs_type = FS_TYPE_ANY; fs_close();
return ret; diff --git a/include/ext4fs.h b/include/ext4fs.h index 3b59d15..025a2e8 100644 --- a/include/ext4fs.h +++ b/include/ext4fs.h @@ -138,4 +138,7 @@ void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot); int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf); void ext4fs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info); long int read_allocated_block(struct ext2_inode *inode, int fileblock); +int ext4fs_probe(block_dev_desc_t *fs_dev_desc, + disk_partition_t *fs_partition); +int ext4_read_file(const char *filename, void *buf, int offset, int len); #endif diff --git a/include/fat.h b/include/fat.h index 706cd7a..0b9017e 100644 --- a/include/fat.h +++ b/include/fat.h @@ -216,4 +216,6 @@ int fat_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info); int fat_register_device(block_dev_desc_t *dev_desc, int part_no);
int file_fat_write(const char *filename, void *buffer, unsigned long maxsize); +int fat_read_file(const char *filename, void *buf, int offset, int len); +void fat_close(void); #endif /* _FAT_H_ */

On Wed, Dec 26, 2012 at 11:53:33AM -0800, Simon Glass wrote:
It doesn't make a lot of sense to have these methods in fs.c. They are filesystem-specific, not generic code. Add each to the relevant filesystem and remove the associated #ifdefs in fs.c.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

This implementation uses opendir()/readdir() to access the directory information and then puts it in a linked list for the caller's use.
Signed-off-by: Simon Glass sjg@chromium.org --- arch/sandbox/cpu/os.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 48 +++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 3e37c93..d075407 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -19,10 +19,13 @@ * MA 02111-1307 USA */
+#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include <termios.h> #include <time.h> #include <unistd.h> @@ -261,3 +264,101 @@ int os_parse_args(struct sandbox_state *state, int argc, char *argv[])
return 0; } + +void os_dirent_free(struct os_dirent_node *node) +{ + struct os_dirent_node *next; + + while (node) { + next = node->next; + free(node); + node = next; + } +} + +int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) +{ + struct dirent entry, *result; + struct os_dirent_node *head, *node, *next; + struct stat buf; + DIR *dir; + int ret; + char *fname; + int len; + + *headp = NULL; + dir = opendir(dirname); + if (!dir) + return -1; + + /* Create a buffer for the maximum filename length */ + len = sizeof(entry.d_name) + strlen(dirname) + 2; + fname = malloc(len); + if (!fname) { + ret = -ENOMEM; + goto done; + } + + for (node = head = NULL;; node = next) { + ret = readdir_r(dir, &entry, &result); + if (ret || !result) + break; + next = malloc(sizeof(*node) + strlen(entry.d_name) + 1); + if (!next) { + os_dirent_free(head); + ret = -ENOMEM; + goto done; + } + strcpy(next->name, entry.d_name); + switch (entry.d_type) { + case DT_REG: + next->type = OS_FILET_REG; + break; + case DT_DIR: + next->type = OS_FILET_DIR; + break; + case DT_LNK: + next->type = OS_FILET_LNK; + break; + } + next->size = 0; + snprintf(fname, len, "%s/%s", dirname, next->name); + if (!stat(fname, &buf)) + next->size = buf.st_size; + if (node) + node->next = next; + if (!head) + head = node; + } + *headp = head; + +done: + closedir(dir); + return ret; +} + +const char *os_dirent_typename[OS_FILET_COUNT] = { + " ", + "SYM", + "DIR", + "???", +}; + +const char *os_dirent_get_typename(enum os_dirent_t type) +{ + if (type >= 0 && type < OS_FILET_COUNT) + return os_dirent_typename[type]; + + return os_dirent_typename[OS_FILET_UNKNOWN]; +} + +ssize_t os_get_filesize(const char *fname) +{ + struct stat buf; + int ret; + + ret = stat(fname, &buf); + if (ret) + return ret; + return buf.st_size; +} diff --git a/include/os.h b/include/os.h index c452d1b..038aba9 100644 --- a/include/os.h +++ b/include/os.h @@ -146,4 +146,52 @@ u64 os_get_nsec(void); */ int os_parse_args(struct sandbox_state *state, int argc, char *argv[]);
+/* + * Types of directory entry that we support. See also os_dirent_typename in + * the C file. + */ +enum os_dirent_t { + OS_FILET_REG, /* Regular file */ + OS_FILET_LNK, /* Symbolic link */ + OS_FILET_DIR, /* Directory */ + OS_FILET_UNKNOWN, /* Something else */ + + OS_FILET_COUNT, +}; + +/** A directory entry node, containing information about a single dirent */ +struct os_dirent_node { + struct os_dirent_node *next; /* Pointer to next node, or NULL */ + ulong size; /* Size of file in bytes */ + enum os_dirent_t type; /* Type of entry */ + char name[0]; /* Name of entry */ +}; + +/** + * Get a directionry listing + * + * This allocates and returns a linked list containing the directory listing. + * + * @param dirname Directory to examine + * @param headp Returns pointer to head of linked list, or NULL if none + * @return 0 if ok, -ve on error + */ +int os_dirent_ls(const char *dirname, struct os_dirent_node **headp); + +/** + * Get the name of a directory entry type + * + * @param type Type to cehck + * @return string containing the name of that type, or "???" if none/invalid + */ +const char *os_dirent_get_typename(enum os_dirent_t type); + +/** + * Get the size of a file + * + * @param fname Filename to check + * @return size of file, or -1 if an error ocurred + */ +ssize_t os_get_filesize(const char *fname); + #endif

On Wed, Dec 26, 2012 at 11:53:34AM -0800, Simon Glass wrote:
This implementation uses opendir()/readdir() to access the directory information and then puts it in a linked list for the caller's use.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/os.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 48 +++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
Since the code looks fine,
Reviewed-by: Tom Rini trini@ti.com
But a question. Do you really want this in cpu/os.c rather than some new file for filesystem stuff (since this is the arch side of sandboxfs) ? I can see you saying it should stay here since it's all OS interaction related stuff.

Hi Tom,
On Fri, Mar 1, 2013 at 9:37 AM, Tom Rini trini@ti.com wrote:
On Wed, Dec 26, 2012 at 11:53:34AM -0800, Simon Glass wrote:
This implementation uses opendir()/readdir() to access the directory information and then puts it in a linked list for the caller's use.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/os.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 48 +++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
Since the code looks fine,
Reviewed-by: Tom Rini trini@ti.com
But a question. Do you really want this in cpu/os.c rather than some new file for filesystem stuff (since this is the arch side of sandboxfs) ? I can see you saying it should stay here since it's all OS interaction related stuff.
Thanks for reviewing. The practical reason why everything is in os.c is that this file is the interface between files which include common.h and files which include system headers. But logically speaking, I have tended to make os.c hold anything that interfaces with or calls a Linux API function.
We could certainly create something like os_filedir,c or similar if os.c is getting a bit large. But it would still need to include system headers. I don't think we want anything like this in in drivers/ at present.
Regards, Simon
-- Tom

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 03/01/2013 01:21 PM, Simon Glass wrote:
Hi Tom,
On Fri, Mar 1, 2013 at 9:37 AM, Tom Rini trini@ti.com wrote:
On Wed, Dec 26, 2012 at 11:53:34AM -0800, Simon Glass wrote:
This implementation uses opendir()/readdir() to access the directory information and then puts it in a linked list for the caller's use.
Signed-off-by: Simon Glass sjg@chromium.org --- arch/sandbox/cpu/os.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 48 +++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
Since the code looks fine,
Reviewed-by: Tom Rini trini@ti.com
But a question. Do you really want this in cpu/os.c rather than some new file for filesystem stuff (since this is the arch side of sandboxfs) ? I can see you saying it should stay here since it's all OS interaction related stuff.
Thanks for reviewing. The practical reason why everything is in os.c is that this file is the interface between files which include common.h and files which include system headers. But logically speaking, I have tended to make os.c hold anything that interfaces with or calls a Linux API function.
We could certainly create something like os_filedir,c or similar if os.c is getting a bit large. But it would still need to include system headers. I don't think we want anything like this in in drivers/ at present.
I agree with not putting this into drivers/ as it's sandbox-side stuff. If os.c isn't yet unwieldy to you, OK, we can go as-is. But I'll ask next time you add another big hunk to os.c I'll ask if it's unwieldy yet.
- -- Tom

Hi Tom,
On Fri, Mar 1, 2013 at 10:26 AM, Tom Rini trini@ti.com wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 03/01/2013 01:21 PM, Simon Glass wrote:
Hi Tom,
On Fri, Mar 1, 2013 at 9:37 AM, Tom Rini trini@ti.com wrote:
On Wed, Dec 26, 2012 at 11:53:34AM -0800, Simon Glass wrote:
This implementation uses opendir()/readdir() to access the directory information and then puts it in a linked list for the caller's use.
Signed-off-by: Simon Glass sjg@chromium.org --- arch/sandbox/cpu/os.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ include/os.h | 48 +++++++++++++++++++++++ 2 files changed, 149 insertions(+), 0 deletions(-)
Since the code looks fine,
Reviewed-by: Tom Rini trini@ti.com
But a question. Do you really want this in cpu/os.c rather than some new file for filesystem stuff (since this is the arch side of sandboxfs) ? I can see you saying it should stay here since it's all OS interaction related stuff.
Thanks for reviewing. The practical reason why everything is in os.c is that this file is the interface between files which include common.h and files which include system headers. But logically speaking, I have tended to make os.c hold anything that interfaces with or calls a Linux API function.
We could certainly create something like os_filedir,c or similar if os.c is getting a bit large. But it would still need to include system headers. I don't think we want anything like this in in drivers/ at present.
I agree with not putting this into drivers/ as it's sandbox-side stuff. If os.c isn't yet unwieldy to you, OK, we can go as-is. But I'll ask next time you add another big hunk to os.c I'll ask if it's unwieldy yet.
Understood, thanks.
Regards, Simon

This allows reading of files from the host filesystem in sandbox.
Signed-off-by: Simon Glass sjg@chromium.org --- Makefile | 1 + disk/part.c | 17 ++++++++++ fs/fs.c | 10 ++++++ fs/sandbox/Makefile | 47 +++++++++++++++++++++++++++ fs/sandbox/sandboxfs.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 1 + include/sandboxfs.h | 30 +++++++++++++++++ 7 files changed, 189 insertions(+), 0 deletions(-) create mode 100644 fs/sandbox/Makefile create mode 100644 fs/sandbox/sandboxfs.c create mode 100644 include/sandboxfs.h
diff --git a/Makefile b/Makefile index a7b6cd1..ee21b24 100644 --- a/Makefile +++ b/Makefile @@ -268,6 +268,7 @@ LIBS-y += fs/libfs.o \ fs/fdos/libfdos.o \ fs/jffs2/libjffs2.o \ fs/reiserfs/libreiserfs.o \ + fs/sandbox/libsandboxfs.o \ fs/ubifs/libubifs.o \ fs/yaffs2/libyaffs2.o \ fs/zfs/libzfs.o diff --git a/disk/part.c b/disk/part.c index 7bdc90e..58a4563 100644 --- a/disk/part.c +++ b/disk/part.c @@ -472,6 +472,23 @@ int get_device_and_partition(const char *ifname, const char *dev_part_str, int part; disk_partition_t tmpinfo;
+ /* + * For now, we have a special case for sandbox, since there is no + * real block device support. + */ + if (0 == strcmp(ifname, "host")) { + *dev_desc = NULL; + info->start = info->size = info->blksz = 0; + info->bootable = 0; + strcpy((char *)info->type, BOOT_PART_TYPE); + strcpy((char *)info->name, "Sandbox host"); +#ifdef CONFIG_PARTITION_UUIDS + info->uuid[0] = 0; +#endif + + return 0; + } + /* If no dev_part_str, use bootdevice environment variable */ if (!dev_part_str || !strlen(dev_part_str) || !strcmp(dev_part_str, "-")) diff --git a/fs/fs.c b/fs/fs.c index 95c882e..6f5063c 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -20,6 +20,7 @@ #include <ext4fs.h> #include <fat.h> #include <fs.h> +#include <sandboxfs.h> #include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR; @@ -78,6 +79,15 @@ static struct fstype_info fstypes[] = { .read = ext4_read_file, }, #endif +#ifdef CONFIG_SANDBOX + { + .fstype = FS_TYPE_SANDBOX, + .probe = sandbox_fs_set_blk_dev, + .close = sandbox_fs_close, + .ls = sandbox_fs_ls, + .read = fs_read_sandbox, + }, +#endif { .fstype = FS_TYPE_ANY, .probe = fs_probe_unsupported, diff --git a/fs/sandbox/Makefile b/fs/sandbox/Makefile new file mode 100644 index 0000000..b3155b0 --- /dev/null +++ b/fs/sandbox/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (c) 2012, Google Inc. +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2003 +# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)libsandboxfs.o + +COBJS-$(CONFIG_SANDBOX) := sandboxfs.o + +SRCS := $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y)) + +all: $(LIB) $(AOBJS) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/fs/sandbox/sandboxfs.c b/fs/sandbox/sandboxfs.c new file mode 100644 index 0000000..02d26ff --- /dev/null +++ b/fs/sandbox/sandboxfs.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <fs.h> +#include <os.h> + +int sandbox_fs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info) +{ + return 0; +} + +long sandbox_fs_read_at(const char *filename, unsigned long pos, + void *buffer, unsigned long maxsize) +{ + ssize_t size; + int fd, ret; + + fd = os_open(filename, OS_O_RDONLY); + if (fd < 0) + return fd; + ret = os_lseek(fd, pos, OS_SEEK_SET); + if (ret == -1) { + os_close(fd); + return ret; + } + if (!maxsize) + maxsize = os_get_filesize(filename); + size = os_read(fd, buffer, maxsize); + os_close(fd); + + return size; +} + +int sandbox_fs_ls(const char *dirname) +{ + struct os_dirent_node *head, *node; + int ret; + + ret = os_dirent_ls(dirname, &head); + if (ret) + return ret; + + for (node = head; node; node = node->next) { + printf("%s %10lu %s\n", os_dirent_get_typename(node->type), + node->size, node->name); + } + + return 0; +} + +void sandbox_fs_close(void) +{ +} + +int fs_read_sandbox(const char *filename, void *buf, int offset, int len) +{ + int len_read; + + len_read = sandbox_fs_read_at(filename, offset, buf, len); + if (len_read == -1) { + printf("** Unable to read file %s **\n", filename); + return -1; + } + + return len_read; +} diff --git a/include/fs.h b/include/fs.h index 4f30a38..b6d69e5 100644 --- a/include/fs.h +++ b/include/fs.h @@ -21,6 +21,7 @@ #define FS_TYPE_ANY 0 #define FS_TYPE_FAT 1 #define FS_TYPE_EXT 2 +#define FS_TYPE_SANDBOX 3
/* * Tell the fs layer which block device an partition to use for future diff --git a/include/sandboxfs.h b/include/sandboxfs.h new file mode 100644 index 0000000..f5213ac --- /dev/null +++ b/include/sandboxfs.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012, Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __SANDBOX_FS__ +#define __SANDBOX_FS__ + +int sandbox_fs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info); + +long sandbox_fs_read_at(const char *filename, unsigned long pos, + void *buffer, unsigned long maxsize); + +void sandbox_fs_close(void); +int sandbox_fs_ls(const char *dirname); +int fs_read_sandbox(const char *filename, void *buf, int offset, int len); + +#endif

On Wed, Dec 26, 2012 at 11:53:35AM -0800, Simon Glass wrote:
This allows reading of files from the host filesystem in sandbox.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

The new 'sb' command is intended to deal with sandbox-specific features that have no parallel in other archs. This commit adds two sub-commands to list a directory and read a file from the host filesystem.
Signed-off-by: Simon Glass sjg@chromium.org --- README | 1 + common/Makefile | 1 + common/cmd_sandbox.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ include/config_cmd_all.h | 1 + 4 files changed, 66 insertions(+), 0 deletions(-) create mode 100644 common/cmd_sandbox.c
diff --git a/README b/README index 8dd3867..e54279e 100644 --- a/README +++ b/README @@ -867,6 +867,7 @@ The following options need to be configured: CONFIG_CMD_READ * Read raw data from partition CONFIG_CMD_REGINFO * Register dump CONFIG_CMD_RUN run command in env variable + CONFIG_CMD_SANDBOX * sb command to access sandbox features CONFIG_CMD_SAVES * save S record dump CONFIG_CMD_SCSI * SCSI Support CONFIG_CMD_SDRAM * print SDRAM configuration information diff --git a/common/Makefile b/common/Makefile index 54fcc81..719fc23 100644 --- a/common/Makefile +++ b/common/Makefile @@ -152,6 +152,7 @@ COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o COBJS-$(CONFIG_CMD_READ) += cmd_read.o COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o +COBJS-$(CONFIG_SANDBOX) += cmd_sandbox.o COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o COBJS-$(CONFIG_CMD_SF) += cmd_sf.o COBJS-$(CONFIG_CMD_SCSI) += cmd_scsi.o diff --git a/common/cmd_sandbox.c b/common/cmd_sandbox.c new file mode 100644 index 0000000..206a486 --- /dev/null +++ b/common/cmd_sandbox.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <fs.h> + +static int do_sandbox_load(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return do_load(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX, 16); +} + +static int do_sandbox_ls(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return do_ls(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX); +} + +static cmd_tbl_t cmd_sandbox_sub[] = { + U_BOOT_CMD_MKENT(load, 3, 0, do_sandbox_load, "", ""), + U_BOOT_CMD_MKENT(ls, 3, 0, do_sandbox_ls, "", ""), +}; + +static int do_sandbox(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + cmd_tbl_t *c; + + /* Skip past 'sandbox' */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_sandbox_sub, + ARRAY_SIZE(cmd_sandbox_sub)); + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +U_BOOT_CMD( + sb, 6, 1, do_sandbox, + "Miscellaneous sandbox commands", + "load host <addr> <filename> [<bytes> <offset>] - load a file from host\n" + "sb ls host <filename> - save a file to host" +); diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h index e82f642..61c302e 100644 --- a/include/config_cmd_all.h +++ b/include/config_cmd_all.h @@ -75,6 +75,7 @@ #define CONFIG_CMD_RARP /* rarpboot support */ #define CONFIG_CMD_READ /* Read data from partition */ #define CONFIG_CMD_RUN /* run command in env variable */ +#define CONFIG_CMD_SANDBOX /* sb command to access sandbox features */ #define CONFIG_CMD_SAVEENV /* saveenv */ #define CONFIG_CMD_SAVES /* save S record dump */ #define CONFIG_CMD_SCSI /* SCSI Support */

On Wed, Dec 26, 2012 at 11:53:36AM -0800, Simon Glass wrote:
The new 'sb' command is intended to deal with sandbox-specific features that have no parallel in other archs. This commit adds two sub-commands to list a directory and read a file from the host filesystem.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

These are useful for build-testing code, at least.
Signed-off-by: Simon Glass sjg@chromium.org --- include/configs/sandbox.h | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 9f51a0b..2a45c7b 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -32,6 +32,13 @@ #define CONFIG_OF_LIBFDT #define CONFIG_LMB
+#define CONFIG_FS_FAT +#define CONFIG_FS_EXT4 +#define CONFIG_EXT4_WRITE +#define CONFIG_CMD_FAT +#define CONFIG_CMD_EXT4 +#define CONFIG_CMD_EXT4_WRITE + #define CONFIG_SYS_VSNPRINTF
#define CONFIG_CMD_GPIO

On Wed, Dec 26, 2012 at 11:53:37AM -0800, Simon Glass wrote:
These are useful for build-testing code, at least.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

The 'sb' command allows loading files from the host, and listing directories.
Signed-off-by: Simon Glass sjg@chromium.org --- include/configs/sandbox.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 2a45c7b..406da43 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -97,6 +97,8 @@ #define CONFIG_SHA1 #define CONFIG_SHA256
+#define CONFIG_CMD_SANDBOX + #define CONFIG_BOOTARGS ""
#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \

On Wed, Dec 26, 2012 at 11:53:38AM -0800, Simon Glass wrote:
The 'sb' command allows loading files from the host, and listing directories.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@ti.com

Hi,
On Wed, Dec 26, 2012 at 11:53 AM, Simon Glass sjg@chromium.org wrote:
This series adds support for filesystems to sandbox. While we don't yet have access to host machine block devices, we can access files on the host through a new 'host' filesystem type and the new sandbox command 'sb'.
For example:
sb load host 0 1000 foo.bar
will load foo.bar from the host into memory at address 1000. The '0' parameter is the device number, currently unused.
While doing this work, I noticed that fs.c had code that probably belongs more in the filesystems themselves. So this series moves fat/ext4 code into those files. This removes most of the #ifdefs from this file, as well as the #defines of functions to 'unsupported'. Now there is a list of filesystems that we support, and if we don't find the one we need, we automatically fall back to the 'unsupported' one.
Finally, the ext4 write support is moved into a separate file since ext4fs.c was over 3500 lines and the write support seems entirely separate from the main function in that file.
Are there any comments on this series please? It adds new methods to the filesystem interface, and a new 'host' filesystem type for sandbox.
Regards, Simon
Simon Glass (11): ext4: Split write support into its own file fs: Fully populate the filesystem method struct fs: Use filesystem methods instead of switch() fs: Tell probe functions where to put their results fs: Use map_sysmem() on read fs: Move ls and read methods into ext4, fat sandbox: Add a way of obtaining directory listings sandbox: Add host filesystem sandbox: Add 'sb' command to access filesystem features sandbox: Enable ext4 and fat filesystems sandbox: config: Enable sandbox command
Makefile | 1 + README | 1 + arch/sandbox/cpu/os.c | 101 +++++ common/Makefile | 1 + common/cmd_sandbox.c | 63 +++ disk/part.c | 17 + fs/ext4/Makefile | 2 +- fs/ext4/ext4_write.c | 996 +++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/ext4fs.c | 962 +------------------------------------------ fs/fat/fat.c | 17 + fs/fs.c | 237 +++++------- fs/sandbox/Makefile | 47 +++ fs/sandbox/sandboxfs.c | 83 ++++ include/config_cmd_all.h | 1 + include/configs/sandbox.h | 9 + include/ext4fs.h | 3 + include/fat.h | 2 + include/fs.h | 1 + include/os.h | 48 +++ include/sandboxfs.h | 30 ++ 20 files changed, 1533 insertions(+), 1089 deletions(-) create mode 100644 common/cmd_sandbox.c create mode 100644 fs/ext4/ext4_write.c create mode 100644 fs/sandbox/Makefile create mode 100644 fs/sandbox/sandboxfs.c create mode 100644 include/sandboxfs.h
-- 1.7.7.3

On Sun, Feb 24, 2013 at 09:35:42AM -0800, Simon Glass wrote:
Hi,
On Wed, Dec 26, 2012 at 11:53 AM, Simon Glass sjg@chromium.org wrote:
This series adds support for filesystems to sandbox. While we don't yet have access to host machine block devices, we can access files on the host through a new 'host' filesystem type and the new sandbox command 'sb'.
For example:
sb load host 0 1000 foo.bar
will load foo.bar from the host into memory at address 1000. The '0' parameter is the device number, currently unused.
While doing this work, I noticed that fs.c had code that probably belongs more in the filesystems themselves. So this series moves fat/ext4 code into those files. This removes most of the #ifdefs from this file, as well as the #defines of functions to 'unsupported'. Now there is a list of filesystems that we support, and if we don't find the one we need, we automatically fall back to the 'unsupported' one.
Finally, the ext4 write support is moved into a separate file since ext4fs.c was over 3500 lines and the write support seems entirely separate from the main function in that file.
Are there any comments on this series please? It adds new methods to the filesystem interface, and a new 'host' filesystem type for sandbox.
Applied to u-boot/master, thanks!
participants (3)
-
Lukasz Majewski
-
Simon Glass
-
Tom Rini