]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - fs/ubifs/ubifs.c
arcv2: Set IOC aperture so it covers available DDR
[people/ms/u-boot.git] / fs / ubifs / ubifs.c
index 44be3f53e078ec3ac2fb7379946825f6a9fe6640..db29489eca7517c4a21151fcd91dbdc53b270dfc 100644 (file)
@@ -6,26 +6,20 @@
  * (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
+ *
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
+#include <common.h>
+#include <memalign.h>
 #include "ubifs.h"
 #include <u-boot/zlib.h>
 
+#include <linux/err.h>
+#include <linux/lzo.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /* compress.c */
@@ -44,20 +38,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 +67,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 +162,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 +186,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 +216,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 +287,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);
 
@@ -274,7 +375,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;
        }
 
@@ -358,7 +459,7 @@ 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)
@@ -460,7 +561,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 +591,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 +628,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 +706,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 +722,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 +777,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 +824,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 +839,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 +850,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 +878,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 +912,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) {
+               setenv_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;
+       }
+}