X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=fs%2Fubifs%2Fubifs.c;h=47fa41ad1dd329fdc5ee595e0436fd192779d6c6;hb=87deefeccc49756ee33b5c0fb6dbe331dfdff487;hp=44be3f53e078ec3ac2fb7379946825f6a9fe6640;hpb=cd40a66c197fd43f761fa398cf785ff1a86250de;p=u-boot diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index 44be3f53e0..47fa41ad1d 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * This file is part of UBIFS. * @@ -6,26 +7,18 @@ * (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 - * 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., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * * Authors: Artem Bityutskiy (Битюцкий Артём) * Adrian Hunter */ +#include +#include #include "ubifs.h" #include +#include +#include + DECLARE_GLOBAL_DATA_PTR; /* compress.c */ @@ -44,20 +37,27 @@ static int gzip_decompress(const unsigned char *in, size_t in_len, /* Fake description object for the "none" compressor */ static struct ubifs_compressor none_compr = { .compr_type = UBIFS_COMPR_NONE, - .name = "no compression", + .name = "none", .capi_name = "", .decompress = NULL, }; static struct ubifs_compressor lzo_compr = { .compr_type = UBIFS_COMPR_LZO, - .name = "LZO", +#ifndef __UBOOT__ + .comp_mutex = &lzo_mutex, +#endif + .name = "lzo", .capi_name = "lzo", .decompress = lzo1x_decompress_safe, }; static struct ubifs_compressor zlib_compr = { .compr_type = UBIFS_COMPR_ZLIB, +#ifndef __UBOOT__ + .comp_mutex = &deflate_mutex, + .decomp_mutex = &inflate_mutex, +#endif .name = "zlib", .capi_name = "deflate", .decompress = gzip_decompress, @@ -66,6 +66,89 @@ static struct ubifs_compressor zlib_compr = { /* All UBIFS compressors */ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; + +#ifdef __UBOOT__ +/* from mm/util.c */ + +/** + * kmemdup - duplicate region of memory + * + * @src: memory region to duplicate + * @len: memory region length + * @gfp: GFP mask to use + */ +void *kmemdup(const void *src, size_t len, gfp_t gfp) +{ + void *p; + + p = kmalloc(len, gfp); + if (p) + memcpy(p, src, len); + return p; +} + +struct crypto_comp { + int compressor; +}; + +static inline struct crypto_comp +*crypto_alloc_comp(const char *alg_name, u32 type, u32 mask) +{ + struct ubifs_compressor *comp; + struct crypto_comp *ptr; + int i = 0; + + ptr = malloc_cache_aligned(sizeof(struct crypto_comp)); + while (i < UBIFS_COMPR_TYPES_CNT) { + comp = ubifs_compressors[i]; + if (!comp) { + i++; + continue; + } + if (strncmp(alg_name, comp->capi_name, strlen(alg_name)) == 0) { + ptr->compressor = i; + return ptr; + } + i++; + } + if (i >= UBIFS_COMPR_TYPES_CNT) { + dbg_gen("invalid compression type %s", alg_name); + free (ptr); + return NULL; + } + return ptr; +} +static inline int +crypto_comp_decompress(const struct ubifs_info *c, struct crypto_comp *tfm, + const u8 *src, unsigned int slen, u8 *dst, + unsigned int *dlen) +{ + struct ubifs_compressor *compr = ubifs_compressors[tfm->compressor]; + int err; + + if (compr->compr_type == UBIFS_COMPR_NONE) { + memcpy(dst, src, slen); + *dlen = slen; + return 0; + } + + err = compr->decompress(src, slen, dst, (size_t *)dlen); + if (err) + ubifs_err(c, "cannot decompress %d bytes, compressor %s, " + "error %d", slen, compr->name, err); + + return err; + + return 0; +} + +/* from shrinker.c */ + +/* Global clean znode counter (for all mounted UBIFS instances) */ +atomic_long_t ubifs_clean_zn_cnt; + +#endif + /** * ubifs_decompress - decompress data. * @in_buf: data to decompress @@ -78,21 +161,21 @@ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; * The length of the uncompressed data is returned in @out_len. This functions * returns %0 on success or a negative error code on failure. */ -int ubifs_decompress(const void *in_buf, int in_len, void *out_buf, - int *out_len, int compr_type) +int ubifs_decompress(const struct ubifs_info *c, const void *in_buf, + int in_len, void *out_buf, int *out_len, int compr_type) { int err; struct ubifs_compressor *compr; if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) { - ubifs_err("invalid compression type %d", compr_type); + ubifs_err(c, "invalid compression type %d", compr_type); return -EINVAL; } compr = ubifs_compressors[compr_type]; if (unlikely(!compr->capi_name)) { - ubifs_err("%s compression is not compiled in", compr->name); + ubifs_err(c, "%s compression is not compiled in", compr->name); return -EINVAL; } @@ -102,10 +185,15 @@ int ubifs_decompress(const void *in_buf, int in_len, void *out_buf, return 0; } - err = compr->decompress(in_buf, in_len, out_buf, (size_t *)out_len); + if (compr->decomp_mutex) + mutex_lock(compr->decomp_mutex); + err = crypto_comp_decompress(c, compr->cc, in_buf, in_len, out_buf, + (unsigned int *)out_len); + if (compr->decomp_mutex) + mutex_unlock(compr->decomp_mutex); if (err) - ubifs_err("cannot decompress %d bytes, compressor %s, " - "error %d", in_len, compr->name, err); + ubifs_err(c, "cannot decompress %d bytes, compressor %s," + " error %d", in_len, compr->name, err); return err; } @@ -127,6 +215,16 @@ static int __init compr_init(struct ubifs_compressor *compr) ubifs_compressors[compr->compr_type]->decompress += gd->reloc_off; #endif + if (compr->capi_name) { + compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0); + if (IS_ERR(compr->cc)) { + dbg_gen("cannot initialize compressor %s," + " error %ld", compr->name, + PTR_ERR(compr->cc)); + return PTR_ERR(compr->cc); + } + } + return 0; } @@ -188,7 +286,9 @@ static int filldir(struct ubifs_info *c, const char *name, int namlen, } ctime_r((time_t *)&inode->i_mtime, filetime); printf("%9lld %24.24s ", inode->i_size, filetime); +#ifndef __UBOOT__ ubifs_iput(inode); +#endif printf("%s\n", name); @@ -249,7 +349,9 @@ static int ubifs_printdir(struct file *file, void *dirent) dbg_gen("feed '%s', ino %llu, new f_pos %#x", dent->name, (unsigned long long)le64_to_cpu(dent->inum), key_hash_flash(c, &dent->key)); +#ifndef __UBOOT__ ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); +#endif nm.len = le16_to_cpu(dent->nlen); over = filldir(c, (char *)dent->name, nm.len, @@ -274,7 +376,7 @@ static int ubifs_printdir(struct file *file, void *dirent) out: if (err != -ENOENT) { - ubifs_err("cannot find next direntry, error %d", err); + ubifs_err(c, "cannot find next direntry, error %d", err); return err; } @@ -331,7 +433,9 @@ static int ubifs_finddir(struct super_block *sb, char *dirname, dbg_gen("feed '%s', ino %llu, new f_pos %#x", dent->name, (unsigned long long)le64_to_cpu(dent->inum), key_hash_flash(c, &dent->key)); +#ifndef __UBOOT__ ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); +#endif nm.len = le16_to_cpu(dent->nlen); if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) && @@ -358,17 +462,13 @@ static int ubifs_finddir(struct super_block *sb, char *dirname, out: if (err != -ENOENT) - ubifs_err("cannot find next direntry, error %d", err); + dbg_gen("cannot find next direntry, error %d", err); out_free: - if (file->private_data) - kfree(file->private_data); - if (file) - free(file); - if (dentry) - free(dentry); - if (dir) - free(dir); + kfree(file->private_data); + free(file); + free(dentry); + free(dir); return ret; } @@ -460,7 +560,26 @@ static unsigned long ubifs_findfile(struct super_block *sb, char *filename) return 0; } -int ubifs_ls(char *filename) +int ubifs_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info) +{ + if (rbdd) { + debug("UBIFS cannot be used with normal block devices\n"); + return -1; + } + + /* + * Should never happen since blk_get_device_part_str() already checks + * this, but better safe then sorry. + */ + if (!ubifs_is_mounted()) { + debug("UBIFS not mounted, use ubifsmount to mount volume first!\n"); + return -1; + } + + return 0; +} + +int ubifs_ls(const char *filename) { struct ubifs_info *c = ubifs_sb->s_fs_info; struct file *file; @@ -471,7 +590,7 @@ int ubifs_ls(char *filename) int ret = 0; c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY); - inum = ubifs_findfile(ubifs_sb, filename); + inum = ubifs_findfile(ubifs_sb, (char *)filename); if (!inum) { ret = -1; goto out; @@ -508,6 +627,48 @@ out: return ret; } +int ubifs_exists(const char *filename) +{ + struct ubifs_info *c = ubifs_sb->s_fs_info; + unsigned long inum; + + c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY); + inum = ubifs_findfile(ubifs_sb, (char *)filename); + ubi_close_volume(c->ubi); + + return inum != 0; +} + +int ubifs_size(const char *filename, loff_t *size) +{ + struct ubifs_info *c = ubifs_sb->s_fs_info; + unsigned long inum; + struct inode *inode; + int err = 0; + + c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY); + + inum = ubifs_findfile(ubifs_sb, (char *)filename); + if (!inum) { + err = -1; + goto out; + } + + inode = ubifs_iget(ubifs_sb, inum); + if (IS_ERR(inode)) { + printf("%s: Error reading inode %ld!\n", __func__, inum); + err = PTR_ERR(inode); + goto out; + } + + *size = inode->i_size; + + ubifs_iput(inode); +out: + ubi_close_volume(c->ubi); + return err; +} + /* * ubifsload... */ @@ -544,7 +705,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block, dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; out_len = UBIFS_BLOCK_SIZE; - err = ubifs_decompress(&dn->data, dlen, addr, &out_len, + err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len, le16_to_cpu(dn->compr_type)); if (err || len != out_len) goto dump; @@ -560,9 +721,9 @@ static int read_block(struct inode *inode, void *addr, unsigned int block, return 0; dump: - ubifs_err("bad data node (block %u, inode %lu)", + ubifs_err(c, "bad data node (block %u, inode %lu)", block, inode->i_ino); - dbg_dump_node(c, dn); + ubifs_dump_node(c, dn); return -EINVAL; } @@ -615,7 +776,7 @@ static int do_readpage(struct ubifs_info *c, struct inode *inode, * destination area to a multiple of * UBIFS_BLOCK_SIZE. */ - buff = malloc(UBIFS_BLOCK_SIZE); + buff = malloc_cache_aligned(UBIFS_BLOCK_SIZE); if (!buff) { printf("%s: Error, malloc fails!\n", __func__); @@ -662,7 +823,7 @@ static int do_readpage(struct ubifs_info *c, struct inode *inode, dbg_gen("hole"); goto out_free; } - ubifs_err("cannot read page %lu of inode %lu, error %d", + ubifs_err(c, "cannot read page %lu of inode %lu, error %d", page->index, inode->i_ino, err); goto error; } @@ -677,7 +838,8 @@ error: return err; } -int ubifs_load(char *filename, u32 addr, u32 size) +int ubifs_read(const char *filename, void *buf, loff_t offset, + loff_t size, loff_t *actread) { struct ubifs_info *c = ubifs_sb->s_fs_info; unsigned long inum; @@ -687,12 +849,19 @@ int ubifs_load(char *filename, u32 addr, u32 size) int i; int count; int last_block_size = 0; - char buf [10]; + + *actread = 0; + + if (offset & (PAGE_SIZE - 1)) { + printf("ubifs: Error offset must be a multiple of %d\n", + PAGE_SIZE); + return -1; + } 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 * the real file here */ - inum = ubifs_findfile(ubifs_sb, filename); + inum = ubifs_findfile(ubifs_sb, (char *)filename); if (!inum) { err = -1; goto out; @@ -708,19 +877,24 @@ int ubifs_load(char *filename, u32 addr, u32 size) goto out; } + if (offset > inode->i_size) { + printf("ubifs: Error offset (%lld) > file-size (%lld)\n", + offset, size); + err = -1; + goto put_inode; + } + /* * If no size was specified or if size bigger than filesize * set size to filesize */ - if ((size == 0) || (size > inode->i_size)) - size = inode->i_size; + if ((size == 0) || (size > (inode->i_size - offset))) + size = inode->i_size - offset; count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT; - printf("Loading file '%s' to addr 0x%08x with size %d (0x%08x)...\n", - filename, addr, size, size); - page.addr = (void *)addr; - page.index = 0; + page.addr = buf; + page.index = offset / PAGE_SIZE; page.inode = inode; for (i = 0; i < count; i++) { /* @@ -737,17 +911,48 @@ int ubifs_load(char *filename, u32 addr, u32 size) page.index++; } - if (err) + if (err) { printf("Error reading file '%s'\n", filename); - else { - sprintf(buf, "%X", size); - setenv("filesize", buf); - printf("Done\n"); + *actread = i * PAGE_SIZE; + } else { + *actread = size; } +put_inode: ubifs_iput(inode); out: ubi_close_volume(c->ubi); return err; } + +void ubifs_close(void) +{ +} + +/* Compat wrappers for common/cmd_ubifs.c */ +int ubifs_load(char *filename, u32 addr, u32 size) +{ + loff_t actread; + int err; + + printf("Loading file '%s' to addr 0x%08x...\n", filename, addr); + + err = ubifs_read(filename, (void *)(uintptr_t)addr, 0, size, &actread); + if (err == 0) { + env_set_hex("filesize", actread); + printf("Done\n"); + } + + return err; +} + +void uboot_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; + } +}