From cb9c09d4871015be5710c7bae29b06218ddc3509 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 28 Oct 2010 14:09:22 +0200 Subject: [PATCH 1/5] UBIFS: Add ubifsumount command to unmount an active volume This new ubifsumount command allows the user to unmount a previously mounted UBIFS volume. Signed-off-by: Stefan Roese --- common/cmd_ubifs.c | 31 +++++++++++++++++++++++++++++++ fs/ubifs/super.c | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/common/cmd_ubifs.c b/common/cmd_ubifs.c index a0ec18448..30b23d310 100644 --- a/common/cmd_ubifs.c +++ b/common/cmd_ubifs.c @@ -33,12 +33,17 @@ #include #include +#include "../fs/ubifs/ubifs.h" + static int ubifs_initialized; static int ubifs_mounted; +extern struct super_block *ubifs_sb; + /* Prototypes */ int ubifs_init(void); int ubifs_mount(char *vol_name); +void ubifs_umount(struct ubifs_info *c); int ubifs_ls(char *dir_name); int ubifs_load(char *filename, u32 addr, u32 size); @@ -67,6 +72,26 @@ int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } +int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc != 1) + return cmd_usage(cmdtp); + + if (ubifs_initialized == 0) { + printf("No UBIFS volume mounted!\n"); + return -1; + } + + if (ubifs_sb) + ubifs_umount(ubifs_sb->s_fs_info); + + ubifs_sb = NULL; + ubifs_mounted = 0; + ubifs_initialized = 0; + + return 0; +} + int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *filename = "/"; @@ -131,6 +156,12 @@ U_BOOT_CMD( " - mount 'volume-name' volume" ); +U_BOOT_CMD( + ubifsumount, 1, 0, do_ubifs_umount, + "unmount UBIFS volume", + " - unmount current volume" +); + U_BOOT_CMD( ubifsls, 2, 0, do_ubifs_ls, "list files in a directory", diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 39e3efec8..63b2164d3 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -824,7 +824,7 @@ out_free: * through mounting (error path cleanup function). So it has to make sure the * resource was actually allocated before freeing it. */ -static void ubifs_umount(struct ubifs_info *c) +void ubifs_umount(struct ubifs_info *c) { dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, c->vi.vol_id); From 9a2ea578bc2f556fd92a3bcb9127d3fc9c6ee1bd Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 28 Oct 2010 14:09:29 +0200 Subject: [PATCH 2/5] UBIFS: Change "ubifs mount" to "ubifsmount" in ubifsls output Signed-off-by: Stefan Roese --- common/cmd_ubifs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/cmd_ubifs.c b/common/cmd_ubifs.c index 30b23d310..9526780cd 100644 --- a/common/cmd_ubifs.c +++ b/common/cmd_ubifs.c @@ -98,7 +98,7 @@ int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) int ret; if (!ubifs_mounted) { - printf("UBIFS not mounted, use ubifs mount to mount volume first!\n"); + printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); return -1; } From b1a14f8a1c2e72d5c58269d0200f722d8eec19c4 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 1 Nov 2010 17:28:00 +0100 Subject: [PATCH 3/5] UBIFS: Change ubifsload to not read beyond the requested size Until now ubifsload pads the destination with 0 up to a multiple of UBIFS_BLOCK_SIZE (4KiB) while reading a file to memory. This patch changes this behaviour to only read to the requested length. This is either the file length or the length/size provided as parameter to the ubifsload command. Signed-off-by: Stefan Roese --- fs/ubifs/ubifs.c | 71 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index 1cc31a968..d16d2b06a 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006-2008 Nokia Corporation. * - * (C) Copyright 2008-2009 + * (C) Copyright 2008-2010 * Stefan Roese, DENX Software Engineering, sr@denx.de. * * This program is free software; you can redistribute it and/or modify it @@ -567,7 +567,8 @@ dump: return -EINVAL; } -static int do_readpage(struct ubifs_info *c, struct inode *inode, struct page *page) +static int do_readpage(struct ubifs_info *c, struct inode *inode, + struct page *page, int last_block_size) { void *addr; int err = 0, i; @@ -601,17 +602,54 @@ static int do_readpage(struct ubifs_info *c, struct inode *inode, struct page *p err = -ENOENT; memset(addr, 0, UBIFS_BLOCK_SIZE); } else { - ret = read_block(inode, addr, block, dn); - if (ret) { - err = ret; - if (err != -ENOENT) - break; - } else if (block + 1 == beyond) { - int dlen = le32_to_cpu(dn->size); - int ilen = i_size & (UBIFS_BLOCK_SIZE - 1); + /* + * Reading last block? Make sure to not write beyond + * the requested size in the destination buffer. + */ + if (((block + 1) == beyond) || last_block_size) { + void *buff; + int dlen; - if (ilen && ilen < dlen) - memset(addr + ilen, 0, dlen - ilen); + /* + * We need to buffer the data locally for the + * last block. This is to not pad the + * destination area to a multiple of + * UBIFS_BLOCK_SIZE. + */ + buff = malloc(UBIFS_BLOCK_SIZE); + if (!buff) { + printf("%s: Error, malloc fails!\n", + __func__); + err = -ENOMEM; + break; + } + + /* Read block-size into temp buffer */ + ret = read_block(inode, buff, block, dn); + if (ret) { + err = ret; + if (err != -ENOENT) { + free(buff); + break; + } + } + + if (last_block_size) + dlen = last_block_size; + else + dlen = le32_to_cpu(dn->size); + + /* Now copy required size back to dest */ + memcpy(addr, buff, dlen); + + free(buff); + } else { + ret = read_block(inode, addr, block, dn); + if (ret) { + err = ret; + if (err != -ENOENT) + break; + } } } if (++i >= UBIFS_BLOCKS_PER_PAGE) @@ -649,6 +687,7 @@ int ubifs_load(char *filename, u32 addr, u32 size) int err = 0; int i; int count; + int last_block_size = 0; c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY); /* ubifs_findfile will resolve symlinks, so we know that we get @@ -684,7 +723,13 @@ int ubifs_load(char *filename, u32 addr, u32 size) page.index = 0; page.inode = inode; for (i = 0; i < count; i++) { - err = do_readpage(c, inode, &page); + /* + * Make sure to not read beyond the requested size + */ + if (((i + 1) == count) && (size < inode->i_size)) + last_block_size = size - (i * PAGE_SIZE); + + err = do_readpage(c, inode, &page, last_block_size); if (err) break; From 2f15cfd187f1cf7a0606a1ec3e637954311a735a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 1 Nov 2010 17:28:22 +0100 Subject: [PATCH 4/5] UBI/UBIFS: Automatically unmount UBIFS volume upon UBI partition change Automatically unmount UBIFS partition when user changes the UBI device. Otherwise the following UBIFS commands will crash. Signed-off-by: Stefan Roese --- common/cmd_ubi.c | 15 +++++++++++++++ common/cmd_ubifs.c | 26 ++++++++++++++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/common/cmd_ubi.c b/common/cmd_ubi.c index 7692ac771..b486ca8fe 100644 --- a/common/cmd_ubi.c +++ b/common/cmd_ubi.c @@ -42,6 +42,11 @@ struct selected_dev { static struct selected_dev ubi_dev; +#ifdef CONFIG_CMD_UBIFS +int ubifs_is_mounted(void); +void cmd_ubifs_umount(void); +#endif + static void ubi_dump_vol_info(const struct ubi_volume *vol) { ubi_msg("volume information dump:"); @@ -472,6 +477,16 @@ static int do_ubi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) if (argc < 3) return cmd_usage(cmdtp); +#ifdef CONFIG_CMD_UBIFS + /* + * Automatically unmount UBIFS partition when user + * changes the UBI device. Otherwise the following + * UBIFS commands will crash. + */ + if (ubifs_is_mounted()) + cmd_ubifs_umount(); +#endif + /* todo: get dev number for NAND... */ ubi_dev.nr = 0; diff --git a/common/cmd_ubifs.c b/common/cmd_ubifs.c index 9526780cd..3cd2d8fa8 100644 --- a/common/cmd_ubifs.c +++ b/common/cmd_ubifs.c @@ -72,6 +72,25 @@ int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } +int ubifs_is_mounted(void) +{ + return ubifs_mounted; +} + +void cmd_ubifs_umount(void) +{ + + if (ubifs_sb) { + printf("Unmounting UBIFS volume %s!\n", + ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name); + ubifs_umount(ubifs_sb->s_fs_info); + } + + ubifs_sb = NULL; + ubifs_mounted = 0; + ubifs_initialized = 0; +} + int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc != 1) @@ -82,12 +101,7 @@ int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return -1; } - if (ubifs_sb) - ubifs_umount(ubifs_sb->s_fs_info); - - ubifs_sb = NULL; - ubifs_mounted = 0; - ubifs_initialized = 0; + cmd_ubifs_umount(); return 0; } From 64b68178489b6845bcf460e9c6e618cb81740faf Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Thu, 2 Dec 2010 15:02:35 +0100 Subject: [PATCH 5/5] ubifs.c: BUG: Error following links The link_name variable is declared inside the if block and it is used outside it through the name pointer. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Stefan Roese --- fs/ubifs/ubifs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index d16d2b06a..5a5c739b5 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -384,6 +384,7 @@ static unsigned long ubifs_findfile(struct super_block *sb, char *filename) unsigned long root_inum = 1; unsigned long inum; int symlink_count = 0; /* Don't allow symlink recursion */ + char link_name[64]; strcpy(fpath, filename); @@ -420,7 +421,6 @@ static unsigned long ubifs_findfile(struct super_block *sb, char *filename) ui = ubifs_inode(inode); if ((inode->i_mode & S_IFMT) == S_IFLNK) { - char link_name[64]; char buf[128]; /* We have some sort of symlink recursion, bail out */