]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - fs/ubifs/ubifs.c
Add more SPDX-License-Identifier tags
[people/ms/u-boot.git] / fs / ubifs / ubifs.c
index b91a6fd26f261118516ba6c49938c9ac2419ed49..a992a00c8f272727d6058b2e8079830d9d7c73b7 100644 (file)
@@ -6,27 +6,17 @@
  * (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>
 
-#define __UBOOT__
 #include <linux/err.h>
 #include <linux/lzo.h>
 
@@ -102,14 +92,14 @@ struct crypto_comp {
        int compressor;
 };
 
-static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name,
-                                               u32 type, u32 mask)
+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(sizeof(struct crypto_comp));
+       ptr = malloc_cache_aligned(sizeof(struct crypto_comp));
        while (i < UBIFS_COMPR_TYPES_CNT) {
                comp = ubifs_compressors[i];
                if (!comp) {
@@ -123,15 +113,16 @@ static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name,
                i++;
        }
        if (i >= UBIFS_COMPR_TYPES_CNT) {
-               ubifs_err("invalid compression type %s", alg_name);
+               dbg_gen("invalid compression type %s", alg_name);
                free (ptr);
                return NULL;
        }
        return ptr;
 }
-static inline int crypto_comp_decompress(struct crypto_comp *tfm,
-                               const u8 *src, unsigned int slen,
-                               u8 *dst, unsigned int *dlen)
+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;
@@ -144,13 +135,19 @@ static inline int crypto_comp_decompress(struct crypto_comp *tfm,
 
        err = compr->decompress(src, slen, dst, (size_t *)dlen);
        if (err)
-               ubifs_err("cannot decompress %d bytes, compressor %s, "
+               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
 
 /**
@@ -165,21 +162,21 @@ static inline int crypto_comp_decompress(struct crypto_comp *tfm,
  * 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;
        }
 
@@ -191,13 +188,13 @@ int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
 
        if (compr->decomp_mutex)
                mutex_lock(compr->decomp_mutex);
-       err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
+       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;
 }
@@ -222,8 +219,9 @@ static int __init compr_init(struct ubifs_compressor *compr)
        if (compr->capi_name) {
                compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
                if (IS_ERR(compr->cc)) {
-                       ubifs_err("cannot initialize compressor %s, error %ld",
-                                 compr->name, PTR_ERR(compr->cc));
+                       dbg_gen("cannot initialize compressor %s,"
+                                 " error %ld", compr->name,
+                                 PTR_ERR(compr->cc));
                        return PTR_ERR(compr->cc);
                }
        }
@@ -377,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;
        }
 
@@ -461,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)
@@ -563,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(block_dev_desc_t *rbdd, disk_partition_t *info)
+{
+       if (rbdd) {
+               debug("UBIFS cannot be used with normal block devices\n");
+               return -1;
+       }
+
+       /*
+        * Should never happen since get_device_and_partition() 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;
@@ -574,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;
@@ -611,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...
  */
@@ -647,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;
@@ -663,7 +722,7 @@ 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);
        ubifs_dump_node(c, dn);
        return -EINVAL;
@@ -718,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__);
@@ -765,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;
        }
@@ -780,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;
@@ -791,10 +851,18 @@ int ubifs_load(char *filename, u32 addr, u32 size)
        int count;
        int last_block_size = 0;
 
+       *actread = 0;
+
+       if (offset & (PAGE_SIZE - 1)) {
+               printf("ubifs: Error offset must be a multple 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;
@@ -810,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++) {
                /*
@@ -839,16 +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 {
-               setenv_hex("filesize", size);
-               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 *)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;
+       }
+}