diff --git a/OAT.xml b/OAT.xml index dc080fc80df049c7b0b0159a95009ea19a1f8a5c..edfeff4f184122714e3f052ebcf46b0e08f952fd 100644 --- a/OAT.xml +++ b/OAT.xml @@ -15,7 +15,7 @@ --> @@ -23,7 +23,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/README.md b/README.md index a702347e47a68fedc9532ef6cf58eb69e75b4d2e..5cbeeb591ea3631692378e9ec3ba414b953ba04a 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,8 @@ ### 四大码仓发布 | 源码同步官方 内核注解同时在 [gitee](https://gitee.com/weharmony/kernel_liteos_a_note) | [github](https://github.com/kuangyufei/kernel_liteos_a_note) | [coding](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) | [gitcode](https://gitcode.net/kuangyufei/kernel_liteos_a_note) 发布,并与官方源码按月保持同步,同步历史如下: + +* `2022/06/03` -- 增加 jffs2 编译选项 * `2022/05/09` -- 标准库(musl , newlib) 目录调整 * `2022/04/16` -- 任务调度模块有很大更新 * `2022/03/23` -- 新增各CPU核自主管理中断, 定时器模块较大调整 diff --git a/fs/BUILD.gn b/fs/BUILD.gn index 16bb77782d69f4dc627e18d651b974be41a6dcea..26b27df37799339a16b8f3e77d435fb154674f90 100644 --- a/fs/BUILD.gn +++ b/fs/BUILD.gn @@ -33,6 +33,7 @@ group("fs") { deps = [ "fat", "fat/virpart", + "jffs2", "nfs", "patchfs", "proc", diff --git a/fs/jffs2/BUILD.gn b/fs/jffs2/BUILD.gn index 283c9eb1194a976c135cc1ed6b4594b7783f8059..dea3bd7c377076cb91ba80762b16dadd2c24e493 100644 --- a/fs/jffs2/BUILD.gn +++ b/fs/jffs2/BUILD.gn @@ -31,19 +31,86 @@ import("//kernel/liteos_a/liteos.gni") module_switch = defined(LOSCFG_FS_JFFS) module_name = get_path_info(rebase_path("."), "name") +linux_path = rebase_path("//kernel/linux/linux-5.10") +out_path = rebase_path(target_out_dir) + kernel_module(module_name) { + patch_path = rebase_path(".") + cmd = "if [ -d ${out_path}/jffs2_build ]; then rm -r ${out_path}/jffs2_build; fi && mkdir -p ${out_path}/jffs2_build/fs" + cmd += " && cp ${linux_path}/fs/jffs2 ${out_path}/jffs2_build/fs/. -r" + cmd += " && pushd ${out_path}/jffs2_build/" + cmd += " && patch -p1 < ${patch_path}/jffs2.patch && popd" + exec_script("//build/lite/run_shell_cmd.py", [ cmd ]) + sources = [ "src/jffs2_hash.c", "src/vfs_jffs2.c", ] - sources += LINUX_KERNEL_FS_JFFS2_SRC_FILES + sources += [ + "${out_path}/jffs2_build/fs/jffs2/background.c", + "${out_path}/jffs2_build/fs/jffs2/build.c", + "${out_path}/jffs2_build/fs/jffs2/compr.c", + "${out_path}/jffs2_build/fs/jffs2/compr_rtime.c", + "${out_path}/jffs2_build/fs/jffs2/compr_rubin.c", + "${out_path}/jffs2_build/fs/jffs2/compr_zlib.c", + "${out_path}/jffs2_build/fs/jffs2/debug.c", + "${out_path}/jffs2_build/fs/jffs2/dir.c", + "${out_path}/jffs2_build/fs/jffs2/erase.c", + "${out_path}/jffs2_build/fs/jffs2/file.c", + "${out_path}/jffs2_build/fs/jffs2/fs.c", + "${out_path}/jffs2_build/fs/jffs2/gc.c", + "${out_path}/jffs2_build/fs/jffs2/malloc.c", + "${out_path}/jffs2_build/fs/jffs2/nodelist.c", + "${out_path}/jffs2_build/fs/jffs2/nodemgmt.c", + "${out_path}/jffs2_build/fs/jffs2/read.c", + "${out_path}/jffs2_build/fs/jffs2/readinode.c", + "${out_path}/jffs2_build/fs/jffs2/scan.c", + "${out_path}/jffs2_build/fs/jffs2/summary.c", + "${out_path}/jffs2_build/fs/jffs2/super.c", + "${out_path}/jffs2_build/fs/jffs2/write.c", + "${out_path}/jffs2_build/fs/jffs2/writev.c", + ] - include_dirs = LINUX_KERNEL_FS_JFFS2_INCLUDE_DIRS + include_dirs = [ + "${out_path}/jffs2_build/fs", + "${out_path}/jffs2_build/fs/jffs2", + ] public_configs = [ ":public" ] + + deps = [ ":cp_jffs2_src" ] } config("public") { include_dirs = [ "include" ] } + +action("cp_jffs2_src") { + script = "//build/lite/run_shell_cmd.py" + + outputs = [ + "${target_out_dir}/jffs2_build/fs/jffs2/background.c", + "${target_out_dir}/jffs2_build/fs/jffs2/build.c", + "${target_out_dir}/jffs2_build/fs/jffs2/compr.c", + "${target_out_dir}/jffs2_build/fs/jffs2/compr_rtime.c", + "${target_out_dir}/jffs2_build/fs/jffs2/compr_rubin.c", + "${target_out_dir}/jffs2_build/fs/jffs2/compr_zlib.c", + "${target_out_dir}/jffs2_build/fs/jffs2/debug.c", + "${target_out_dir}/jffs2_build/fs/jffs2/dir.c", + "${target_out_dir}/jffs2_build/fs/jffs2/erase.c", + "${target_out_dir}/jffs2_build/fs/jffs2/file.c", + "${target_out_dir}/jffs2_build/fs/jffs2/fs.c", + "${target_out_dir}/jffs2_build/fs/jffs2/gc.c", + "${target_out_dir}/jffs2_build/fs/jffs2/malloc.c", + "${target_out_dir}/jffs2_build/fs/jffs2/nodelist.c", + "${target_out_dir}/jffs2_build/fs/jffs2/nodemgmt.c", + "${target_out_dir}/jffs2_build/fs/jffs2/read.c", + "${target_out_dir}/jffs2_build/fs/jffs2/readinode.c", + "${target_out_dir}/jffs2_build/fs/jffs2/scan.c", + "${target_out_dir}/jffs2_build/fs/jffs2/summary.c", + "${target_out_dir}/jffs2_build/fs/jffs2/super.c", + "${target_out_dir}/jffs2_build/fs/jffs2/write.c", + "${target_out_dir}/jffs2_build/fs/jffs2/writev.c", + ] +} diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 38a6daac7a86c87b7f8eec1a107d3ebce8347c6a..338db4cc2ef32b43d9162ef8e74b8c8c82e4fc4c 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -31,13 +31,51 @@ include $(LITEOSTOPDIR)/config.mk MODULE_NAME := $(notdir $(shell pwd)) -LOCAL_SRCS := $(wildcard src/*.c) \ - $(wildcard $(LITEOSTOPDIR)/../linux/linux-5.10/fs/jffs2/*.c) +LINUX_PATH := $(LITEOSTOPDIR)/../linux/linux-5.10 +LOCAL_PATH := $(shell pwd) +TEMP_SRC_PATH := $(OUT)/jffs2_build + +LOCAL_SRCS := \ + $(TEMP_SRC_PATH)/fs/jffs2/background.c \ + $(TEMP_SRC_PATH)/fs/jffs2/build.c \ + $(TEMP_SRC_PATH)/fs/jffs2/compr.c \ + $(TEMP_SRC_PATH)/fs/jffs2/compr_rtime.c \ + $(TEMP_SRC_PATH)/fs/jffs2/compr_rubin.c \ + $(TEMP_SRC_PATH)/fs/jffs2/compr_zlib.c \ + $(TEMP_SRC_PATH)/fs/jffs2/debug.c \ + $(TEMP_SRC_PATH)/fs/jffs2/dir.c \ + $(TEMP_SRC_PATH)/fs/jffs2/erase.c \ + $(TEMP_SRC_PATH)/fs/jffs2/file.c \ + $(TEMP_SRC_PATH)/fs/jffs2/fs.c \ + $(TEMP_SRC_PATH)/fs/jffs2/gc.c \ + $(TEMP_SRC_PATH)/fs/jffs2/malloc.c \ + $(TEMP_SRC_PATH)/fs/jffs2/nodelist.c \ + $(TEMP_SRC_PATH)/fs/jffs2/nodemgmt.c \ + $(TEMP_SRC_PATH)/fs/jffs2/read.c \ + $(TEMP_SRC_PATH)/fs/jffs2/readinode.c \ + $(TEMP_SRC_PATH)/fs/jffs2/scan.c \ + $(TEMP_SRC_PATH)/fs/jffs2/summary.c \ + $(TEMP_SRC_PATH)/fs/jffs2/super.c \ + $(TEMP_SRC_PATH)/fs/jffs2/write.c \ + $(TEMP_SRC_PATH)/fs/jffs2/writev.c \ + $(LOCAL_PATH)/src/jffs2_hash.c \ + $(LOCAL_PATH)/src/vfs_jffs2.c \ + LOCAL_INCLUDE := \ -I $(LITEOSTOPDIR)/fs/jffs2/include \ - -I $(LITEOSTOPDIR)/../linux/linux-5.10/fs/jffs2 \ - -I $(LITEOSTOPDIR)/../linux/linux-5.10/fs + -I $(TEMP_SRC_PATH)/fs/jffs2 \ + -I $(TEMP_SRC_PATH)/fs LOCAL_FLAGS := $(LOCAL_INCLUDE) +.PHONY: patch patch_clean +$(LOCAL_SRCS): patch + +patch: patch_clean + cp $(LINUX_PATH)/fs/jffs2 $(TEMP_SRC_PATH)/fs/. -r + cd $(TEMP_SRC_PATH) && patch -p1 < $(LOCAL_PATH)/jffs2.patch + +patch_clean: + $(HIDE) $(RM) -rf $(TEMP_SRC_PATH) + include $(MODULE) diff --git a/fs/jffs2/jffs2.patch b/fs/jffs2/jffs2.patch new file mode 100644 index 0000000000000000000000000000000000000000..907d3f329ca610c3dc09949174cd6e9370a6991b --- /dev/null +++ b/fs/jffs2/jffs2.patch @@ -0,0 +1,9927 @@ +diff -Nupr old/fs/jffs2/acl.c new/fs/jffs2/acl.c +--- old/fs/jffs2/acl.c 2022-05-09 17:15:24.350000000 +0800 ++++ new/fs/jffs2/acl.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,307 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2006 NEC Corporation +- * +- * Created by KaiGai Kohei +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "nodelist.h" +- +-static size_t jffs2_acl_size(int count) +-{ +- if (count <= 4) { +- return sizeof(struct jffs2_acl_header) +- + count * sizeof(struct jffs2_acl_entry_short); +- } else { +- return sizeof(struct jffs2_acl_header) +- + 4 * sizeof(struct jffs2_acl_entry_short) +- + (count - 4) * sizeof(struct jffs2_acl_entry); +- } +-} +- +-static int jffs2_acl_count(size_t size) +-{ +- size_t s; +- +- size -= sizeof(struct jffs2_acl_header); +- if (size < 4 * sizeof(struct jffs2_acl_entry_short)) { +- if (size % sizeof(struct jffs2_acl_entry_short)) +- return -1; +- return size / sizeof(struct jffs2_acl_entry_short); +- } else { +- s = size - 4 * sizeof(struct jffs2_acl_entry_short); +- if (s % sizeof(struct jffs2_acl_entry)) +- return -1; +- return s / sizeof(struct jffs2_acl_entry) + 4; +- } +-} +- +-static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size) +-{ +- void *end = value + size; +- struct jffs2_acl_header *header = value; +- struct jffs2_acl_entry *entry; +- struct posix_acl *acl; +- uint32_t ver; +- int i, count; +- +- if (!value) +- return NULL; +- if (size < sizeof(struct jffs2_acl_header)) +- return ERR_PTR(-EINVAL); +- ver = je32_to_cpu(header->a_version); +- if (ver != JFFS2_ACL_VERSION) { +- JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver); +- return ERR_PTR(-EINVAL); +- } +- +- value += sizeof(struct jffs2_acl_header); +- count = jffs2_acl_count(size); +- if (count < 0) +- return ERR_PTR(-EINVAL); +- if (count == 0) +- return NULL; +- +- acl = posix_acl_alloc(count, GFP_KERNEL); +- if (!acl) +- return ERR_PTR(-ENOMEM); +- +- for (i=0; i < count; i++) { +- entry = value; +- if (value + sizeof(struct jffs2_acl_entry_short) > end) +- goto fail; +- acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag); +- acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm); +- switch (acl->a_entries[i].e_tag) { +- case ACL_USER_OBJ: +- case ACL_GROUP_OBJ: +- case ACL_MASK: +- case ACL_OTHER: +- value += sizeof(struct jffs2_acl_entry_short); +- break; +- +- case ACL_USER: +- value += sizeof(struct jffs2_acl_entry); +- if (value > end) +- goto fail; +- acl->a_entries[i].e_uid = +- make_kuid(&init_user_ns, +- je32_to_cpu(entry->e_id)); +- break; +- case ACL_GROUP: +- value += sizeof(struct jffs2_acl_entry); +- if (value > end) +- goto fail; +- acl->a_entries[i].e_gid = +- make_kgid(&init_user_ns, +- je32_to_cpu(entry->e_id)); +- break; +- +- default: +- goto fail; +- } +- } +- if (value != end) +- goto fail; +- return acl; +- fail: +- posix_acl_release(acl); +- return ERR_PTR(-EINVAL); +-} +- +-static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) +-{ +- struct jffs2_acl_header *header; +- struct jffs2_acl_entry *entry; +- void *e; +- size_t i; +- +- *size = jffs2_acl_size(acl->a_count); +- header = kmalloc(struct_size(header, a_entries, acl->a_count), +- GFP_KERNEL); +- if (!header) +- return ERR_PTR(-ENOMEM); +- header->a_version = cpu_to_je32(JFFS2_ACL_VERSION); +- e = header + 1; +- for (i=0; i < acl->a_count; i++) { +- const struct posix_acl_entry *acl_e = &acl->a_entries[i]; +- entry = e; +- entry->e_tag = cpu_to_je16(acl_e->e_tag); +- entry->e_perm = cpu_to_je16(acl_e->e_perm); +- switch(acl_e->e_tag) { +- case ACL_USER: +- entry->e_id = cpu_to_je32( +- from_kuid(&init_user_ns, acl_e->e_uid)); +- e += sizeof(struct jffs2_acl_entry); +- break; +- case ACL_GROUP: +- entry->e_id = cpu_to_je32( +- from_kgid(&init_user_ns, acl_e->e_gid)); +- e += sizeof(struct jffs2_acl_entry); +- break; +- +- case ACL_USER_OBJ: +- case ACL_GROUP_OBJ: +- case ACL_MASK: +- case ACL_OTHER: +- e += sizeof(struct jffs2_acl_entry_short); +- break; +- +- default: +- goto fail; +- } +- } +- return header; +- fail: +- kfree(header); +- return ERR_PTR(-EINVAL); +-} +- +-struct posix_acl *jffs2_get_acl(struct inode *inode, int type) +-{ +- struct posix_acl *acl; +- char *value = NULL; +- int rc, xprefix; +- +- switch (type) { +- case ACL_TYPE_ACCESS: +- xprefix = JFFS2_XPREFIX_ACL_ACCESS; +- break; +- case ACL_TYPE_DEFAULT: +- xprefix = JFFS2_XPREFIX_ACL_DEFAULT; +- break; +- default: +- BUG(); +- } +- rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); +- if (rc > 0) { +- value = kmalloc(rc, GFP_KERNEL); +- if (!value) +- return ERR_PTR(-ENOMEM); +- rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); +- } +- if (rc > 0) { +- acl = jffs2_acl_from_medium(value, rc); +- } else if (rc == -ENODATA || rc == -ENOSYS) { +- acl = NULL; +- } else { +- acl = ERR_PTR(rc); +- } +- kfree(value); +- return acl; +-} +- +-static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl) +-{ +- char *value = NULL; +- size_t size = 0; +- int rc; +- +- if (acl) { +- value = jffs2_acl_to_medium(acl, &size); +- if (IS_ERR(value)) +- return PTR_ERR(value); +- } +- rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); +- if (!value && rc == -ENODATA) +- rc = 0; +- kfree(value); +- +- return rc; +-} +- +-int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) +-{ +- int rc, xprefix; +- +- switch (type) { +- case ACL_TYPE_ACCESS: +- xprefix = JFFS2_XPREFIX_ACL_ACCESS; +- if (acl) { +- umode_t mode; +- +- rc = posix_acl_update_mode(inode, &mode, &acl); +- if (rc) +- return rc; +- if (inode->i_mode != mode) { +- struct iattr attr; +- +- attr.ia_valid = ATTR_MODE | ATTR_CTIME; +- attr.ia_mode = mode; +- attr.ia_ctime = current_time(inode); +- rc = jffs2_do_setattr(inode, &attr); +- if (rc < 0) +- return rc; +- } +- } +- break; +- case ACL_TYPE_DEFAULT: +- xprefix = JFFS2_XPREFIX_ACL_DEFAULT; +- if (!S_ISDIR(inode->i_mode)) +- return acl ? -EACCES : 0; +- break; +- default: +- return -EINVAL; +- } +- rc = __jffs2_set_acl(inode, xprefix, acl); +- if (!rc) +- set_cached_acl(inode, type, acl); +- return rc; +-} +- +-int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) +-{ +- struct posix_acl *default_acl, *acl; +- int rc; +- +- cache_no_acl(inode); +- +- rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl); +- if (rc) +- return rc; +- +- if (default_acl) { +- set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); +- posix_acl_release(default_acl); +- } +- if (acl) { +- set_cached_acl(inode, ACL_TYPE_ACCESS, acl); +- posix_acl_release(acl); +- } +- return 0; +-} +- +-int jffs2_init_acl_post(struct inode *inode) +-{ +- int rc; +- +- if (inode->i_default_acl) { +- rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl); +- if (rc) +- return rc; +- } +- +- if (inode->i_acl) { +- rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl); +- if (rc) +- return rc; +- } +- +- return 0; +-} +diff -Nupr old/fs/jffs2/acl.h new/fs/jffs2/acl.h +--- old/fs/jffs2/acl.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/acl.h 2022-05-10 14:52:22.930000000 +0800 +@@ -8,6 +8,8 @@ + * For licensing information, see the file 'LICENCE' in this directory. + * + */ ++#ifndef _JFFS2_ACL_H_ ++#define _JFFS2_ACL_H_ + + struct jffs2_acl_entry { + jint16_t e_tag; +@@ -27,11 +29,6 @@ struct jffs2_acl_header { + + #ifdef CONFIG_JFFS2_FS_POSIX_ACL + +-struct posix_acl *jffs2_get_acl(struct inode *inode, int type); +-int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); +-extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *); +-extern int jffs2_init_acl_post(struct inode *); +- + #else + + #define jffs2_get_acl (NULL) +@@ -40,3 +37,4 @@ extern int jffs2_init_acl_post(struct in + #define jffs2_init_acl_post(inode) (0) + + #endif /* CONFIG_JFFS2_FS_POSIX_ACL */ ++#endif /* _JFFS2_ACL_H_ */ +diff -Nupr old/fs/jffs2/background.c new/fs/jffs2/background.c +--- old/fs/jffs2/background.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/background.c 2022-05-10 14:53:26.200000000 +0800 +@@ -10,156 +10,113 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include +-#include +-#include +-#include +-#include +-#include +-#include ++#include + #include "nodelist.h" ++#include "vfs_jffs2.h" ++#include "mtd_partition.h" + ++#define GC_THREAD_FLAG_TRIG 1 ++#define GC_THREAD_FLAG_STOP 2 ++#define GC_THREAD_FLAG_HAS_EXIT 4 + +-static int jffs2_garbage_collect_thread(void *); ++extern struct MtdNorDev jffs2_dev_list[CONFIG_MTD_PATTITION_NUM]; ++static void jffs2_garbage_collect_thread(unsigned long data); + + void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) + { +- assert_spin_locked(&c->erase_completion_lock); +- if (c->gc_task && jffs2_thread_should_wake(c)) +- send_sig(SIGHUP, c->gc_task, 1); ++ struct super_block *sb = OFNI_BS_2SFFJ(c); ++ /* Wake up the thread */ ++ jffs2_dbg(1, "jffs2_garbage_collect_trigger\n"); ++ LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_TRIG); + } + + /* This must only ever be called when no GC thread is currently running */ +-int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) ++void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) + { +- struct task_struct *tsk; +- int ret = 0; ++ struct super_block *sb = OFNI_BS_2SFFJ(c); ++ TSK_INIT_PARAM_S stGcTask; + +- BUG_ON(c->gc_task); ++ if (c == NULL) ++ return; + +- init_completion(&c->gc_thread_start); +- init_completion(&c->gc_thread_exit); ++ if (sb->s_root == NULL) ++ return; + +- tsk = kthread_run(jffs2_garbage_collect_thread, c, "jffs2_gcd_mtd%d", c->mtd->index); +- if (IS_ERR(tsk)) { +- pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n", +- -PTR_ERR(tsk)); +- complete(&c->gc_thread_exit); +- ret = PTR_ERR(tsk); +- } else { +- /* Wait for it... */ +- jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid); +- wait_for_completion(&c->gc_thread_start); +- ret = tsk->pid; ++ LOS_EventInit(&sb->s_gc_thread_flags); ++ ++ /* Start the thread. Doesn't matter if it fails -- it's only an ++ * optimisation anyway */ ++ (void)memset_s(&stGcTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); ++ ++ stGcTask.pfnTaskEntry = (TSK_ENTRY_FUNC)jffs2_garbage_collect_thread; ++ stGcTask.auwArgs[0] = (UINTPTR)c; ++ stGcTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; ++ stGcTask.pcName = "jffs2_gc_thread"; ++#ifdef LOSCFG_KERNEL_SMP ++ unsigned int i; ++ for (i = 0; i < CONFIG_MTD_PATTITION_NUM; i++) { ++ if (sb->s_dev == &jffs2_dev_list[i]) ++ break; + } ++ stGcTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(i % LOSCFG_KERNEL_CORE_NUM); ++#endif ++ stGcTask.usTaskPrio = JFFS2_GC_THREAD_PRIORITY; + +- return ret; ++ if (LOS_TaskCreate(&sb->s_gc_thread, &stGcTask)) ++ JFFS2_ERROR("Create gc task failed!!!\n"); + } + + void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) + { +- int wait = 0; +- spin_lock(&c->erase_completion_lock); +- if (c->gc_task) { +- jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid); +- send_sig(SIGKILL, c->gc_task, 1); +- wait = 1; +- } +- spin_unlock(&c->erase_completion_lock); +- if (wait) +- wait_for_completion(&c->gc_thread_exit); ++ struct super_block *sb = OFNI_BS_2SFFJ(c); ++ ++ JFFS2_DEBUG("jffs2_stop_garbage_collect_thread\n"); ++ /* Stop the thread and wait for it if necessary */ ++ ++ LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_STOP); ++ ++ JFFS2_DEBUG("jffs2_stop_garbage_collect_thread wait\n"); ++ ++ (void)LOS_EventRead(&sb->s_gc_thread_flags, ++ GC_THREAD_FLAG_HAS_EXIT, ++ LOS_WAITMODE_OR | LOS_WAITMODE_CLR, ++ LOS_WAIT_FOREVER); ++ ++ // Kill and free the resources ... this is safe due to the flag ++ // from the thread. ++ (void)LOS_TaskDelete(sb->s_gc_thread); ++ (void)LOS_EventWrite(&sb->s_gc_thread_flags, 0xFFFFFFFF); + } + +-static int jffs2_garbage_collect_thread(void *_c) ++static void jffs2_garbage_collect_thread(unsigned long data) + { +- struct jffs2_sb_info *c = _c; +- sigset_t hupmask; ++ struct jffs2_sb_info *c = (struct jffs2_sb_info *)data; ++ struct super_block *sb = OFNI_BS_2SFFJ(c); ++ unsigned int flag = 0; ++ ++ jffs2_dbg(1, "jffs2_garbage_collect_thread START\n"); ++ while(1) { ++ flag = LOS_EventRead(&sb->s_gc_thread_flags, ++ GC_THREAD_FLAG_TRIG | GC_THREAD_FLAG_STOP, ++ LOS_WAITMODE_OR | LOS_WAITMODE_CLR, ++ LOS_WAIT_FOREVER ++ ); ++ if (flag & GC_THREAD_FLAG_STOP) ++ break; + +- siginitset(&hupmask, sigmask(SIGHUP)); +- allow_signal(SIGKILL); +- allow_signal(SIGSTOP); +- allow_signal(SIGHUP); +- +- c->gc_task = current; +- complete(&c->gc_thread_start); +- +- set_user_nice(current, 10); +- +- set_freezable(); +- for (;;) { +- sigprocmask(SIG_UNBLOCK, &hupmask, NULL); +- again: +- spin_lock(&c->erase_completion_lock); +- if (!jffs2_thread_should_wake(c)) { +- set_current_state (TASK_INTERRUPTIBLE); +- spin_unlock(&c->erase_completion_lock); +- jffs2_dbg(1, "%s(): sleeping...\n", __func__); +- schedule(); +- } else { +- spin_unlock(&c->erase_completion_lock); +- } +- /* Problem - immediately after bootup, the GCD spends a lot +- * of time in places like jffs2_kill_fragtree(); so much so +- * that userspace processes (like gdm and X) are starved +- * despite plenty of cond_resched()s and renicing. Yield() +- * doesn't help, either (presumably because userspace and GCD +- * are generally competing for a higher latency resource - +- * disk). +- * This forces the GCD to slow the hell down. Pulling an +- * inode in with read_inode() is much preferable to having +- * the GC thread get there first. */ +- schedule_timeout_interruptible(msecs_to_jiffies(50)); +- +- if (kthread_should_stop()) { +- jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__); +- goto die; +- } ++ jffs2_dbg(1, "jffs2: GC THREAD GC BEGIN\n"); + +- /* Put_super will send a SIGKILL and then wait on the sem. +- */ +- while (signal_pending(current) || freezing(current)) { +- unsigned long signr; +- +- if (try_to_freeze()) +- goto again; +- +- signr = kernel_dequeue_signal(); +- +- switch(signr) { +- case SIGSTOP: +- jffs2_dbg(1, "%s(): SIGSTOP received\n", +- __func__); +- kernel_signal_stop(); +- break; +- +- case SIGKILL: +- jffs2_dbg(1, "%s(): SIGKILL received\n", +- __func__); +- goto die; +- +- case SIGHUP: +- jffs2_dbg(1, "%s(): SIGHUP received\n", +- __func__); +- break; +- default: +- jffs2_dbg(1, "%s(): signal %ld received\n", +- __func__, signr); +- } +- } +- /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ +- sigprocmask(SIG_BLOCK, &hupmask, NULL); ++ if (sb->s_root == NULL) ++ return; + +- jffs2_dbg(1, "%s(): pass\n", __func__); + if (jffs2_garbage_collect_pass(c) == -ENOSPC) { +- pr_notice("No space for garbage collection. Aborting GC thread\n"); +- goto die; ++ PRINTK("No space for garbage collection. " ++ "Aborting JFFS2 GC thread\n"); ++ break; + } ++ jffs2_dbg(1, "jffs2: GC THREAD GC END\n"); + } +- die: +- spin_lock(&c->erase_completion_lock); +- c->gc_task = NULL; +- spin_unlock(&c->erase_completion_lock); +- complete_and_exit(&c->gc_thread_exit, 0); ++ JFFS2_DEBUG("jffs2_garbage_collect_thread EXIT\n"); ++ LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_HAS_EXIT); + } +diff -Nupr old/fs/jffs2/build.c new/fs/jffs2/build.c +--- old/fs/jffs2/build.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/build.c 2022-05-10 15:01:38.800000000 +0800 +@@ -10,15 +10,13 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- ++#include + #include + #include + #include +-#include +-#include +-#include /* kvfree() */ ++#include + #include "nodelist.h" ++#include "los_exc.h" + + static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, + struct jffs2_inode_cache *, struct jffs2_full_dirent **); +@@ -50,8 +48,7 @@ next_inode(int *i, struct jffs2_inode_ca + + + static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, +- struct jffs2_inode_cache *ic, +- int *dir_hardlinks) ++ struct jffs2_inode_cache *ic) + { + struct jffs2_full_dirent *fd; + +@@ -372,20 +369,24 @@ int jffs2_do_mount_fs(struct jffs2_sb_in + int ret; + int i; + int size; ++ struct super_block *sb; ++ struct MtdNorDev *device; + + c->free_size = c->flash_size; + c->nr_blocks = c->flash_size / c->sector_size; +- size = sizeof(struct jffs2_eraseblock) * c->nr_blocks; ++ sb = OFNI_BS_2SFFJ(c); ++ device = (struct MtdNorDev *)(sb->s_dev); ++ size = sizeof(struct jffs2_eraseblock) *(c->nr_blocks + device->blockStart); + #ifndef __ECOS + if (jffs2_blocks_use_vmalloc(c)) +- c->blocks = vzalloc(size); ++ c->blocks = malloc(size); + else + #endif + c->blocks = kzalloc(size, GFP_KERNEL); + if (!c->blocks) + return -ENOMEM; + +- for (i=0; inr_blocks; i++) { ++ for (i = device->blockStart; i < c->nr_blocks + device->blockStart; i++) { + INIT_LIST_HEAD(&c->blocks[i].list); + c->blocks[i].offset = i * c->sector_size; + c->blocks[i].free_size = c->sector_size; +diff -Nupr old/fs/jffs2/compr.c new/fs/jffs2/compr.c +--- old/fs/jffs2/compr.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/compr.c 2022-05-10 15:02:17.440000000 +0800 +@@ -12,14 +12,13 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include "compr.h" ++#include "jffs2.h" ++#include "user_copy.h" + +-static DEFINE_SPINLOCK(jffs2_compressor_list_lock); +- ++static spinlock_t jffs2_compressor_list_lock; + /* Available compressors are on this list */ +-static LIST_HEAD(jffs2_compressor_list); ++static LINUX_LIST_HEAD(jffs2_compressor_list); + + /* Actual compression mode */ + static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; +@@ -71,15 +70,15 @@ static int jffs2_is_best_compression(str + * could not be compressed; probably because we couldn't find the requested + * compression mode. + */ +-static int jffs2_selected_compress(u8 compr, unsigned char *data_in, +- unsigned char **cpage_out, u32 *datalen, u32 *cdatalen) ++static int jffs2_selected_compress(uint8_t compr, unsigned char *data_in, ++ unsigned char **cpage_out, uint32_t *datalen, uint32_t *cdatalen) + { + struct jffs2_compressor *this; + int err, ret = JFFS2_COMPR_NONE; + uint32_t orig_slen, orig_dlen; +- char *output_buf; ++ unsigned char *output_buf; + +- output_buf = kmalloc(*cdatalen, GFP_KERNEL); ++ output_buf = kmalloc(*cdatalen,GFP_KERNEL); + if (!output_buf) { + pr_warn("No memory for compressor allocation. Compression failed.\n"); + return ret; +@@ -265,11 +264,16 @@ int jffs2_decompress(struct jffs2_sb_inf + switch (comprtype & 0xff) { + case JFFS2_COMPR_NONE: + /* This should be special-cased elsewhere, but we might as well deal with it */ +- memcpy(data_out, cdata_in, datalen); ++ if (LOS_CopyFromKernel(data_out, datalen, cdata_in, datalen) != 0) { ++ return -EFAULT; ++ } + none_stat_decompr_blocks++; + break; + case JFFS2_COMPR_ZERO: +- memset(data_out, 0, datalen); ++ ret = LOS_UserMemClear(data_out, datalen); ++ if (ret != 0) { ++ return ret; ++ } + break; + default: + spin_lock(&jffs2_compressor_list_lock); +diff -Nupr old/fs/jffs2/compr.h new/fs/jffs2/compr.h +--- old/fs/jffs2/compr.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/compr.h 2022-05-10 15:02:50.040000000 +0800 +@@ -13,18 +13,20 @@ + #define __JFFS2_COMPR_H__ + + #include +-#include + #include + #include + #include + #include + #include +-#include +-#include +-#include "jffs2_fs_i.h" +-#include "jffs2_fs_sb.h" ++#include + #include "nodelist.h" + ++#ifdef __cplusplus ++#if __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ + #define JFFS2_RUBINMIPS_PRIORITY 10 + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 +@@ -102,4 +104,10 @@ int jffs2_lzo_init(void); + void jffs2_lzo_exit(void); + #endif + ++#ifdef __cplusplus ++#if __cplusplus ++} ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ + #endif /* __JFFS2_COMPR_H__ */ +diff -Nupr old/fs/jffs2/compr_lzo.c new/fs/jffs2/compr_lzo.c +--- old/fs/jffs2/compr_lzo.c 2022-05-09 17:15:24.350000000 +0800 ++++ new/fs/jffs2/compr_lzo.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,110 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2007 Nokia Corporation. All rights reserved. +- * Copyright © 2004-2010 David Woodhouse +- * +- * Created by Richard Purdie +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "compr.h" +- +-static void *lzo_mem; +-static void *lzo_compress_buf; +-static DEFINE_MUTEX(deflate_mutex); /* for lzo_mem and lzo_compress_buf */ +- +-static void free_workspace(void) +-{ +- vfree(lzo_mem); +- vfree(lzo_compress_buf); +-} +- +-static int __init alloc_workspace(void) +-{ +- lzo_mem = vmalloc(LZO1X_MEM_COMPRESS); +- lzo_compress_buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE)); +- +- if (!lzo_mem || !lzo_compress_buf) { +- free_workspace(); +- return -ENOMEM; +- } +- +- return 0; +-} +- +-static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, +- uint32_t *sourcelen, uint32_t *dstlen) +-{ +- size_t compress_size; +- int ret; +- +- mutex_lock(&deflate_mutex); +- ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); +- if (ret != LZO_E_OK) +- goto fail; +- +- if (compress_size > *dstlen) +- goto fail; +- +- memcpy(cpage_out, lzo_compress_buf, compress_size); +- mutex_unlock(&deflate_mutex); +- +- *dstlen = compress_size; +- return 0; +- +- fail: +- mutex_unlock(&deflate_mutex); +- return -1; +-} +- +-static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, +- uint32_t srclen, uint32_t destlen) +-{ +- size_t dl = destlen; +- int ret; +- +- ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl); +- +- if (ret != LZO_E_OK || dl != destlen) +- return -1; +- +- return 0; +-} +- +-static struct jffs2_compressor jffs2_lzo_comp = { +- .priority = JFFS2_LZO_PRIORITY, +- .name = "lzo", +- .compr = JFFS2_COMPR_LZO, +- .compress = &jffs2_lzo_compress, +- .decompress = &jffs2_lzo_decompress, +- .disabled = 0, +-}; +- +-int __init jffs2_lzo_init(void) +-{ +- int ret; +- +- ret = alloc_workspace(); +- if (ret < 0) +- return ret; +- +- ret = jffs2_register_compressor(&jffs2_lzo_comp); +- if (ret) +- free_workspace(); +- +- return ret; +-} +- +-void jffs2_lzo_exit(void) +-{ +- jffs2_unregister_compressor(&jffs2_lzo_comp); +- free_workspace(); +-} +diff -Nupr old/fs/jffs2/compr_rtime.c new/fs/jffs2/compr_rtime.c +--- old/fs/jffs2/compr_rtime.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/compr_rtime.c 2022-05-10 15:05:05.970000000 +0800 +@@ -25,7 +25,7 @@ + #include + #include + #include +-#include ++#include "jffs2.h" + #include "compr.h" + + /* _compress returns the compressed size, -1 if bigger */ +diff -Nupr old/fs/jffs2/compr_rubin.c new/fs/jffs2/compr_rubin.c +--- old/fs/jffs2/compr_rubin.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/compr_rubin.c 2022-05-10 15:05:51.830000000 +0800 +@@ -10,15 +10,12 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include +-#include + #include ++#include "jffs2.h" + #include "compr.h" + +- + #define RUBIN_REG_SIZE 16 + #define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) + #define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) +@@ -48,7 +45,7 @@ static inline void init_pushpull(struct + unsigned buflen, unsigned ofs, + unsigned reserve) + { +- pp->buf = buf; ++ pp->buf = (unsigned char *)buf; + pp->buflen = buflen; + pp->ofs = ofs; + pp->reserve = reserve; +@@ -267,7 +264,7 @@ static int rubin_do_compress(int bit_div + int pos=0; + struct rubin_state rs; + +- init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32); ++ init_pushpull(&rs.pp, (char *)cpage_out, *dstlen * 8, 0, 32); + + init_rubin(&rs, bit_divider, bits); + +@@ -366,14 +363,14 @@ static int jffs2_dynrubin_compress(unsig + } + + static void rubin_do_decompress(int bit_divider, int *bits, +- unsigned char *cdata_in, ++ unsigned char *cdata_in, + unsigned char *page_out, uint32_t srclen, + uint32_t destlen) + { + int outpos = 0; + struct rubin_state rs; + +- init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); ++ init_pushpull(&rs.pp, (char *)cdata_in, srclen, 0, 0); + init_decode(&rs, bit_divider, bits); + + while (outpos < destlen) +diff -Nupr old/fs/jffs2/compr_zlib.c new/fs/jffs2/compr_zlib.c +--- old/fs/jffs2/compr_zlib.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/compr_zlib.c 2022-05-10 15:06:46.640000000 +0800 +@@ -10,15 +10,10 @@ + * + */ + +-#if !defined(__KERNEL__) && !defined(__ECOS) +-#error "The userspace support got too messy and was removed. Update your mkfs.jffs2" +-#endif +- +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include +-#include ++#include + #include ++#include + #include "nodelist.h" + #include "compr.h" + +@@ -35,39 +30,8 @@ static DEFINE_MUTEX(deflate_mutex); + static DEFINE_MUTEX(inflate_mutex); + static z_stream inf_strm, def_strm; + +-#ifdef __KERNEL__ /* Linux-only */ +-#include +-#include +-#include +- +-static int __init alloc_workspaces(void) +-{ +- def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS, +- MAX_MEM_LEVEL)); +- if (!def_strm.workspace) +- return -ENOMEM; +- +- jffs2_dbg(1, "Allocated %d bytes for deflate workspace\n", +- zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); +- inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); +- if (!inf_strm.workspace) { +- vfree(def_strm.workspace); +- return -ENOMEM; +- } +- jffs2_dbg(1, "Allocated %d bytes for inflate workspace\n", +- zlib_inflate_workspacesize()); +- return 0; +-} +- +-static void free_workspaces(void) +-{ +- vfree(def_strm.workspace); +- vfree(inf_strm.workspace); +-} +-#else + #define alloc_workspaces() (0) + #define free_workspaces() do { } while(0) +-#endif /* __KERNEL__ */ + + static int jffs2_zlib_compress(unsigned char *data_in, + unsigned char *cpage_out, +@@ -80,7 +44,7 @@ static int jffs2_zlib_compress(unsigned + + mutex_lock(&deflate_mutex); + +- if (Z_OK != zlib_deflateInit(&def_strm, 3)) { ++ if (Z_OK != deflateInit(&def_strm, 3)) { + pr_warn("deflateInit failed\n"); + mutex_unlock(&deflate_mutex); + return -1; +@@ -98,21 +62,21 @@ static int jffs2_zlib_compress(unsigned + (*sourcelen-def_strm.total_in), def_strm.avail_out); + jffs2_dbg(1, "calling deflate with avail_in %ld, avail_out %ld\n", + def_strm.avail_in, def_strm.avail_out); +- ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); ++ ret = deflate(&def_strm, Z_PARTIAL_FLUSH); + jffs2_dbg(1, "deflate returned with avail_in %ld, avail_out %ld, total_in %ld, total_out %ld\n", + def_strm.avail_in, def_strm.avail_out, + def_strm.total_in, def_strm.total_out); + if (ret != Z_OK) { + jffs2_dbg(1, "deflate in loop returned %d\n", ret); +- zlib_deflateEnd(&def_strm); ++ deflateEnd(&def_strm); + mutex_unlock(&deflate_mutex); + return -1; + } + } + def_strm.avail_out += STREAM_END_SPACE; + def_strm.avail_in = 0; +- ret = zlib_deflate(&def_strm, Z_FINISH); +- zlib_deflateEnd(&def_strm); ++ ret = deflate(&def_strm, Z_FINISH); ++ deflateEnd(&def_strm); + + if (ret != Z_STREAM_END) { + jffs2_dbg(1, "final deflate returned %d\n", ret); +@@ -171,18 +135,18 @@ static int jffs2_zlib_decompress(unsigne + } + + +- if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) { ++ if (Z_OK != inflateInit2(&inf_strm, wbits)) { + pr_warn("inflateInit failed\n"); + mutex_unlock(&inflate_mutex); + return 1; + } + +- while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK) ++ while((ret = inflate(&inf_strm, Z_FINISH)) == Z_OK) + ; + if (ret != Z_STREAM_END) { + pr_notice("inflate returned %d\n", ret); + } +- zlib_inflateEnd(&inf_strm); ++ inflateEnd(&inf_strm); + mutex_unlock(&inflate_mutex); + return 0; + } +@@ -204,13 +168,30 @@ int __init jffs2_zlib_init(void) + { + int ret; + ++ ret = pthread_mutex_init(&inflate_mutex, NULL); ++ if (ret) { ++ return ret; ++ } ++ ++ ret = pthread_mutex_init(&deflate_mutex, NULL); ++ if (ret) { ++ pthread_mutex_destroy(&inflate_mutex); ++ return ret; ++ } ++ + ret = alloc_workspaces(); +- if (ret) +- return ret; ++ if (ret) { ++ pthread_mutex_destroy(&inflate_mutex); ++ pthread_mutex_destroy(&deflate_mutex); ++ return ret; ++ } + + ret = jffs2_register_compressor(&jffs2_zlib_comp); +- if (ret) +- free_workspaces(); ++ if (ret) { ++ pthread_mutex_destroy(&inflate_mutex); ++ pthread_mutex_destroy(&deflate_mutex); ++ free_workspaces(); ++ } + + return ret; + } +@@ -219,4 +200,6 @@ void jffs2_zlib_exit(void) + { + jffs2_unregister_compressor(&jffs2_zlib_comp); + free_workspaces(); ++ pthread_mutex_destroy(&inflate_mutex); ++ pthread_mutex_destroy(&deflate_mutex); + } +diff -Nupr old/fs/jffs2/debug.c new/fs/jffs2/debug.c +--- old/fs/jffs2/debug.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/debug.c 2022-05-10 15:11:46.200000000 +0800 +@@ -10,15 +10,12 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include + #include +-#include +-#include +-#include + #include ++#include ++#include "los_crc32.h" + #include "nodelist.h" + #include "debug.h" + +@@ -133,7 +130,7 @@ __jffs2_dbg_prewrite_paranoia_check(stru + if (!buf) + return; + +- ret = jffs2_flash_read(c, ofs, len, &retlen, buf); ++ ret = jffs2_flash_read(c, ofs, len, &retlen, (char *)buf); + if (ret || (retlen != len)) { + JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n", + len, ret, retlen); +diff -Nupr old/fs/jffs2/debug.h new/fs/jffs2/debug.h +--- old/fs/jffs2/debug.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/debug.h 2022-05-10 15:12:30.850000000 +0800 +@@ -14,7 +14,12 @@ + #define _JFFS2_DEBUG_H_ + + #include +- ++#include "los_process.h" ++#ifdef __cplusplus ++#if __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ + #ifndef CONFIG_JFFS2_FS_DEBUG + #define CONFIG_JFFS2_FS_DEBUG 0 + #endif +@@ -71,25 +76,26 @@ do { \ + + /* The prefixes of JFFS2 messages */ + #define JFFS2_DBG KERN_DEBUG ++#define JFFS2_DBG_LVL KERN_DEBUG + #define JFFS2_DBG_PREFIX "[JFFS2 DBG]" + #define JFFS2_DBG_MSG_PREFIX JFFS2_DBG JFFS2_DBG_PREFIX + + /* JFFS2 message macros */ + #define JFFS2_ERROR(fmt, ...) \ +- pr_err("error: (%d) %s: " fmt, \ +- task_pid_nr(current), __func__, ##__VA_ARGS__) ++ pr_err("error: (%u) %s: " fmt, \ ++ LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) + + #define JFFS2_WARNING(fmt, ...) \ +- pr_warn("warning: (%d) %s: " fmt, \ +- task_pid_nr(current), __func__, ##__VA_ARGS__) ++ pr_warn("warning: (%u) %s: " fmt, \ ++ LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) + + #define JFFS2_NOTICE(fmt, ...) \ +- pr_notice("notice: (%d) %s: " fmt, \ +- task_pid_nr(current), __func__, ##__VA_ARGS__) ++ pr_notice("notice: (%u) %s: " fmt, \ ++ LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) + + #define JFFS2_DEBUG(fmt, ...) \ +- printk(KERN_DEBUG "[JFFS2 DBG] (%d) %s: " fmt, \ +- task_pid_nr(current), __func__, ##__VA_ARGS__) ++ printk(KERN_DEBUG "[JFFS2 DBG] (%u) %s: " fmt, \ ++ LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) + + /* + * We split our debugging messages on several parts, depending on the JFFS2 +@@ -272,4 +278,10 @@ __jffs2_dbg_dump_node(struct jffs2_sb_in + #define jffs2_dbg_acct_sanity_check_nolock(c, jeb) + #endif /* !JFFS2_DBG_SANITY_CHECKS */ + ++#ifdef __cplusplus ++#if __cplusplus ++} ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ + #endif /* _JFFS2_DEBUG_H_ */ +diff -Nupr old/fs/jffs2/dir.c new/fs/jffs2/dir.c +--- old/fs/jffs2/dir.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/dir.c 2022-05-10 16:08:26.380000000 +0800 +@@ -10,95 +10,42 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- ++#include + #include + #include + #include +-#include +-#include +-#include "jffs2_fs_i.h" +-#include "jffs2_fs_sb.h" +-#include ++#include "los_crc32.h" + #include "nodelist.h" +- +-static int jffs2_readdir (struct file *, struct dir_context *); +- +-static int jffs2_create (struct inode *,struct dentry *,umode_t, +- bool); +-static struct dentry *jffs2_lookup (struct inode *,struct dentry *, +- unsigned int); +-static int jffs2_link (struct dentry *,struct inode *,struct dentry *); +-static int jffs2_unlink (struct inode *,struct dentry *); +-static int jffs2_symlink (struct inode *,struct dentry *,const char *); +-static int jffs2_mkdir (struct inode *,struct dentry *,umode_t); +-static int jffs2_rmdir (struct inode *,struct dentry *); +-static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); +-static int jffs2_rename (struct inode *, struct dentry *, +- struct inode *, struct dentry *, +- unsigned int); +- +-const struct file_operations jffs2_dir_operations = +-{ +- .read = generic_read_dir, +- .iterate_shared=jffs2_readdir, +- .unlocked_ioctl=jffs2_ioctl, +- .fsync = jffs2_fsync, +- .llseek = generic_file_llseek, +-}; +- +- +-const struct inode_operations jffs2_dir_inode_operations = +-{ +- .create = jffs2_create, +- .lookup = jffs2_lookup, +- .link = jffs2_link, +- .unlink = jffs2_unlink, +- .symlink = jffs2_symlink, +- .mkdir = jffs2_mkdir, +- .rmdir = jffs2_rmdir, +- .mknod = jffs2_mknod, +- .rename = jffs2_rename, +- .get_acl = jffs2_get_acl, +- .set_acl = jffs2_set_acl, +- .setattr = jffs2_setattr, +- .listxattr = jffs2_listxattr, +-}; +- +-/***********************************************************************/ +- ++#include "vfs_jffs2.h" ++#include "jffs2_hash.h" + + /* We keep the dirent list sorted in increasing order of name hash, + and we use the same hash function as the dentries. Makes this + nice and simple + */ +-static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, +- unsigned int flags) ++struct jffs2_inode *jffs2_lookup(struct jffs2_inode *dir_i, const unsigned char *d_name, int namelen) + { + struct jffs2_inode_info *dir_f; + struct jffs2_full_dirent *fd = NULL, *fd_list; + uint32_t ino = 0; +- struct inode *inode = NULL; +- unsigned int nhash; ++ uint32_t hash = full_name_hash(d_name, namelen); ++ struct jffs2_inode *inode = NULL; + + jffs2_dbg(1, "jffs2_lookup()\n"); + +- if (target->d_name.len > JFFS2_MAX_NAME_LEN) ++ if (namelen > JFFS2_MAX_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + dir_f = JFFS2_INODE_INFO(dir_i); + +- /* The 'nhash' on the fd_list is not the same as the dentry hash */ +- nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len); +- + mutex_lock(&dir_f->sem); + + /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ +- for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) { +- if (fd_list->nhash == nhash && +- (!fd || fd_list->version > fd->version) && +- strlen(fd_list->name) == target->d_name.len && +- !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { ++ for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= hash; fd_list = fd_list->next) { ++ if (fd_list->nhash == hash && ++ (!fd || fd_list->version > fd->version) && ++ strlen((char *)fd_list->name) == namelen && ++ !strncmp((char *)fd_list->name, (char *)d_name, namelen)) { + fd = fd_list; + } + } +@@ -111,176 +58,57 @@ static struct dentry *jffs2_lookup(struc + pr_warn("iget() failed for ino #%u\n", ino); + } + +- return d_splice_alias(inode, target); +-} +- +-/***********************************************************************/ +- +- +-static int jffs2_readdir(struct file *file, struct dir_context *ctx) +-{ +- struct inode *inode = file_inode(file); +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_full_dirent *fd; +- unsigned long curofs = 1; +- +- jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino); +- +- if (!dir_emit_dots(file, ctx)) +- return 0; +- +- mutex_lock(&f->sem); +- for (fd = f->dents; fd; fd = fd->next) { +- curofs++; +- /* First loop: curofs = 2; pos = 2 */ +- if (curofs < ctx->pos) { +- jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", +- fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos); +- continue; +- } +- if (!fd->ino) { +- jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n", +- fd->name); +- ctx->pos++; +- continue; +- } +- jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n", +- (unsigned long)ctx->pos, fd->name, fd->ino, fd->type); +- if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type)) +- break; +- ctx->pos++; +- } +- mutex_unlock(&f->sem); +- return 0; +-} +- +-/***********************************************************************/ +- +- +-static int jffs2_create(struct inode *dir_i, struct dentry *dentry, +- umode_t mode, bool excl) +-{ +- struct jffs2_raw_inode *ri; +- struct jffs2_inode_info *f, *dir_f; +- struct jffs2_sb_info *c; +- struct inode *inode; +- int ret; +- +- ri = jffs2_alloc_raw_inode(); +- if (!ri) +- return -ENOMEM; +- +- c = JFFS2_SB_INFO(dir_i->i_sb); +- +- jffs2_dbg(1, "%s()\n", __func__); +- +- inode = jffs2_new_inode(dir_i, mode, ri); +- +- if (IS_ERR(inode)) { +- jffs2_dbg(1, "jffs2_new_inode() failed\n"); +- jffs2_free_raw_inode(ri); +- return PTR_ERR(inode); +- } +- +- inode->i_op = &jffs2_file_inode_operations; +- inode->i_fop = &jffs2_file_operations; +- inode->i_mapping->a_ops = &jffs2_file_address_operations; +- inode->i_mapping->nrpages = 0; +- +- f = JFFS2_INODE_INFO(inode); +- dir_f = JFFS2_INODE_INFO(dir_i); +- +- /* jffs2_do_create() will want to lock it, _after_ reserving +- space and taking c-alloc_sem. If we keep it locked here, +- lockdep gets unhappy (although it's a false positive; +- nothing else will be looking at this inode yet so there's +- no chance of AB-BA deadlock involving its f->sem). */ +- mutex_unlock(&f->sem); +- +- ret = jffs2_do_create(c, dir_f, f, ri, &dentry->d_name); +- if (ret) +- goto fail; +- +- dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); +- +- jffs2_free_raw_inode(ri); +- +- jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", +- __func__, inode->i_ino, inode->i_mode, inode->i_nlink, +- f->inocache->pino_nlink, inode->i_mapping->nrpages); +- +- d_instantiate_new(dentry, inode); +- return 0; +- +- fail: +- iget_failed(inode); +- jffs2_free_raw_inode(ri); +- return ret; ++ return inode; + } + +-/***********************************************************************/ +- +- +-static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) ++int jffs2_unlink(struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name) + { + struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); +- struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode(dentry)); ++ struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode); + int ret; +- uint32_t now = JFFS2_NOW(); ++ uint32_t now = Jffs2CurSec(); + +- ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, +- dentry->d_name.len, dead_f, now); ++ ret = jffs2_do_unlink(c, dir_f, (const char *)d_name, ++ strlen((char *)d_name), dead_f, now); + if (dead_f->inocache) +- set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink); ++ d_inode->i_nlink = dead_f->inocache->pino_nlink; + if (!ret) +- dir_i->i_mtime = dir_i->i_ctime = ITIME(now); ++ dir_i->i_mtime = dir_i->i_ctime = now; + return ret; + } +-/***********************************************************************/ + +- +-static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) ++int jffs2_link(struct jffs2_inode *old_d_inode, struct jffs2_inode *dir_i, const unsigned char *d_name) + { +- struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb); +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); ++ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb); ++ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); + int ret; + uint8_t type; + uint32_t now; + +- /* Don't let people make hard links to bad inodes. */ +- if (!f->inocache) +- return -EIO; +- +- if (d_is_dir(old_dentry)) +- return -EPERM; +- + /* XXX: This is ugly */ +- type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; ++ type = (old_d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + +- now = JFFS2_NOW(); +- ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); ++ now = Jffs2CurSec(); ++ ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, (const char *)d_name, ++ strlen((char *)d_name), now); + + if (!ret) { + mutex_lock(&f->sem); +- set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink); ++ old_d_inode->i_nlink = ++f->inocache->pino_nlink; + mutex_unlock(&f->sem); +- d_instantiate(dentry, d_inode(old_dentry)); +- dir_i->i_mtime = dir_i->i_ctime = ITIME(now); +- ihold(d_inode(old_dentry)); ++ dir_i->i_mtime = dir_i->i_ctime = now; + } + return ret; + } + +-/***********************************************************************/ +- +-static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target) ++int jffs2_symlink(struct jffs2_inode *dir_i, struct jffs2_inode **d_inode, const unsigned char *d_name, const char *target) + { + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; +- struct inode *inode; ++ struct jffs2_inode *inode; + struct jffs2_raw_inode *ri; + struct jffs2_raw_dirent *rd; + struct jffs2_full_dnode *fn; +@@ -304,7 +132,7 @@ static int jffs2_symlink (struct inode * + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though + */ +- namelen = dentry->d_name.len; ++ namelen = strlen((char *)d_name); + ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + +@@ -321,8 +149,6 @@ static int jffs2_symlink (struct inode * + return PTR_ERR(inode); + } + +- inode->i_op = &jffs2_symlink_inode_operations; +- + f = JFFS2_INODE_INFO(inode); + + inode->i_size = targetlen; +@@ -334,7 +160,7 @@ static int jffs2_symlink (struct inode * + ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + +- fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL); ++ fn = jffs2_write_dnode(c, f, ri, (const unsigned char *)target, targetlen, ALLOC_NORMAL); + + jffs2_free_raw_inode(ri); + +@@ -347,7 +173,8 @@ static int jffs2_symlink (struct inode * + } + + /* We use f->target field to store the target path. */ +- f->target = kmemdup(target, targetlen + 1, GFP_KERNEL); ++ ++ f->target = (unsigned char *)malloc(targetlen + 1); + if (!f->target) { + pr_warn("Can't allocate %d bytes of memory\n", targetlen + 1); + mutex_unlock(&f->sem); +@@ -355,7 +182,15 @@ static int jffs2_symlink (struct inode * + ret = -ENOMEM; + goto fail; + } +- inode->i_link = f->target; ++ ++ ret = LOS_CopyToKernel((char *)f->target, targetlen + 1, target, targetlen + 1); ++ if (ret != EOK) { ++ (void)free(f->target); ++ f->target = NULL; ++ mutex_unlock(&f->sem); ++ jffs2_complete_reservation(c); ++ goto fail; ++ } + + jffs2_dbg(1, "%s(): symlink's target '%s' cached\n", + __func__, (char *)f->target); +@@ -368,14 +203,6 @@ static int jffs2_symlink (struct inode * + + jffs2_complete_reservation(c); + +- ret = jffs2_init_security(inode, dir_i, &dentry->d_name); +- if (ret) +- goto fail; +- +- ret = jffs2_init_acl_post(inode); +- if (ret) +- goto fail; +- + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); + if (ret) +@@ -400,13 +227,13 @@ static int jffs2_symlink (struct inode * + rd->pino = cpu_to_je32(dir_i->i_ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(inode->i_ino); +- rd->mctime = cpu_to_je32(JFFS2_NOW()); ++ rd->mctime = cpu_to_je32(Jffs2CurSec()); + rd->nsize = namelen; + rd->type = DT_LNK; + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); +- rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); ++ rd->name_crc = cpu_to_je32(crc32(0, (const char *)d_name, namelen)); + +- fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); ++ fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)d_name, namelen, ALLOC_NORMAL); + + if (IS_ERR(fd)) { + /* dirent failed to write. Delete the inode normally +@@ -418,7 +245,7 @@ static int jffs2_symlink (struct inode * + goto fail; + } + +- dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); ++ dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime); + + jffs2_free_raw_dirent(rd); + +@@ -429,20 +256,20 @@ static int jffs2_symlink (struct inode * + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); + +- d_instantiate_new(dentry, inode); ++ *d_inode = inode; + return 0; + + fail: +- iget_failed(inode); ++ inode->i_nlink = 0; ++ jffs2_iput(inode); + return ret; + } + +- +-static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode) ++int jffs2_mkdir(struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, struct jffs2_inode **new_i) + { + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; +- struct inode *inode; ++ struct jffs2_inode *inode; + struct jffs2_raw_inode *ri; + struct jffs2_raw_dirent *rd; + struct jffs2_full_dnode *fn; +@@ -450,7 +277,7 @@ static int jffs2_mkdir (struct inode *di + int namelen; + uint32_t alloclen; + int ret; +- ++ mode &= ~S_IFMT; + mode |= S_IFDIR; + + ri = jffs2_alloc_raw_inode(); +@@ -462,9 +289,8 @@ static int jffs2_mkdir (struct inode *di + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though + */ +- namelen = dentry->d_name.len; +- ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, +- JFFS2_SUMMARY_INODE_SIZE); ++ namelen = strlen((char *)d_name); ++ ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + + if (ret) { + jffs2_free_raw_inode(ri); +@@ -478,14 +304,8 @@ static int jffs2_mkdir (struct inode *di + jffs2_complete_reservation(c); + return PTR_ERR(inode); + } +- +- inode->i_op = &jffs2_dir_inode_operations; +- inode->i_fop = &jffs2_dir_operations; +- + f = JFFS2_INODE_INFO(inode); + +- /* Directories get nlink 2 at start */ +- set_nlink(inode, 2); + /* but ic->pino_nlink is the parent ino# */ + f->inocache->pino_nlink = dir_i->i_ino; + +@@ -500,6 +320,7 @@ static int jffs2_mkdir (struct inode *di + /* Eeek. Wave bye bye */ + mutex_unlock(&f->sem); + jffs2_complete_reservation(c); ++ + ret = PTR_ERR(fn); + goto fail; + } +@@ -511,14 +332,6 @@ static int jffs2_mkdir (struct inode *di + + jffs2_complete_reservation(c); + +- ret = jffs2_init_security(inode, dir_i, &dentry->d_name); +- if (ret) +- goto fail; +- +- ret = jffs2_init_acl_post(inode); +- if (ret) +- goto fail; +- + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); + if (ret) +@@ -543,13 +356,13 @@ static int jffs2_mkdir (struct inode *di + rd->pino = cpu_to_je32(dir_i->i_ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = cpu_to_je32(inode->i_ino); +- rd->mctime = cpu_to_je32(JFFS2_NOW()); ++ rd->mctime = cpu_to_je32(Jffs2CurSec()); + rd->nsize = namelen; + rd->type = DT_DIR; + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); +- rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); ++ rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen)); + +- fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); ++ fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, ALLOC_NORMAL); + + if (IS_ERR(fd)) { + /* dirent failed to write. Delete the inode normally +@@ -557,12 +370,12 @@ static int jffs2_mkdir (struct inode *di + jffs2_complete_reservation(c); + jffs2_free_raw_dirent(rd); + mutex_unlock(&dir_f->sem); ++ inode->i_nlink = 0; + ret = PTR_ERR(fd); + goto fail; + } + +- dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); +- inc_nlink(dir_i); ++ dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime); + + jffs2_free_raw_dirent(rd); + +@@ -572,300 +385,198 @@ static int jffs2_mkdir (struct inode *di + + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); ++ *new_i = inode; + +- d_instantiate_new(dentry, inode); + return 0; + + fail: +- iget_failed(inode); ++ inode->i_nlink = 0; ++ jffs2_iput(inode); + return ret; + } + +-static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) ++int jffs2_rmdir (struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name) + { + struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry)); ++ struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); + struct jffs2_full_dirent *fd; + int ret; +- uint32_t now = JFFS2_NOW(); ++ uint32_t now = Jffs2CurSec(); + +- mutex_lock(&f->sem); + for (fd = f->dents ; fd; fd = fd->next) { + if (fd->ino) { +- mutex_unlock(&f->sem); ++ PRINT_ERR("%s-%d: ret=%d\n", __FUNCTION__, __LINE__, ENOTEMPTY); + return -ENOTEMPTY; + } + } +- mutex_unlock(&f->sem); + +- ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, +- dentry->d_name.len, f, now); +- if (!ret) { +- dir_i->i_mtime = dir_i->i_ctime = ITIME(now); +- clear_nlink(d_inode(dentry)); +- drop_nlink(dir_i); +- } ++ ret = jffs2_do_unlink(c, dir_f, (const char *)d_name, ++ strlen((char *)d_name), f, now); ++ if (f->inocache) ++ d_inode->i_nlink = f->inocache->pino_nlink; ++ if (!ret) ++ dir_i->i_mtime = dir_i->i_ctime = now; ++ + return ret; + } + +-static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev) ++int jffs2_rename (struct jffs2_inode *old_dir_i, struct jffs2_inode *d_inode, const unsigned char *old_d_name, ++ struct jffs2_inode *new_dir_i, const unsigned char *new_d_name) + { +- struct jffs2_inode_info *f, *dir_f; +- struct jffs2_sb_info *c; +- struct inode *inode; +- struct jffs2_raw_inode *ri; +- struct jffs2_raw_dirent *rd; +- struct jffs2_full_dnode *fn; +- struct jffs2_full_dirent *fd; +- int namelen; +- union jffs2_device_node dev; +- int devlen = 0; +- uint32_t alloclen; + int ret; ++ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); ++ uint8_t type; ++ uint32_t now; + +- ri = jffs2_alloc_raw_inode(); +- if (!ri) +- return -ENOMEM; +- +- c = JFFS2_SB_INFO(dir_i->i_sb); +- +- if (S_ISBLK(mode) || S_ISCHR(mode)) +- devlen = jffs2_encode_dev(&dev, rdev); ++ /* XXX: This is ugly */ ++ type = (d_inode->i_mode & S_IFMT) >> 12; ++ if (!type) type = DT_REG; + +- /* Try to reserve enough space for both node and dirent. +- * Just the node will do for now, though +- */ +- namelen = dentry->d_name.len; +- ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen, +- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); ++ now = Jffs2CurSec(); ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), ++ d_inode->i_ino, type, ++ (const char *)new_d_name, strlen((char *)new_d_name), now); + +- if (ret) { +- jffs2_free_raw_inode(ri); ++ if (ret) + return ret; +- } + +- inode = jffs2_new_inode(dir_i, mode, ri); + +- if (IS_ERR(inode)) { +- jffs2_free_raw_inode(ri); +- jffs2_complete_reservation(c); +- return PTR_ERR(inode); ++ /* If it was a directory we moved, and there was no victim, ++ increase i_nlink on its new parent */ ++ if ((d_inode->i_mode & S_IFMT) == S_IFDIR) { ++ new_dir_i->i_nlink++; + } +- inode->i_op = &jffs2_file_inode_operations; +- init_special_inode(inode, inode->i_mode, rdev); + +- f = JFFS2_INODE_INFO(inode); +- +- ri->dsize = ri->csize = cpu_to_je32(devlen); +- ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); +- ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); +- +- ri->compr = JFFS2_COMPR_NONE; +- ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); +- ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); +- +- fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL); ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ (const char *)old_d_name, strlen((char *)old_d_name), NULL, now); + +- jffs2_free_raw_inode(ri); ++ /* We don't touch inode->i_nlink */ + +- if (IS_ERR(fn)) { +- /* Eeek. Wave bye bye */ ++ if (ret) { ++ /* Oh shit. We really ought to make a single node which can do both atomically */ ++ struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); ++ mutex_lock(&f->sem); ++ if (f->inocache) ++ d_inode->i_nlink = f->inocache->pino_nlink++; + mutex_unlock(&f->sem); +- jffs2_complete_reservation(c); +- ret = PTR_ERR(fn); +- goto fail; +- } +- /* No data here. Only a metadata node, which will be +- obsoleted by the first data write +- */ +- f->metadata = fn; +- mutex_unlock(&f->sem); +- +- jffs2_complete_reservation(c); +- +- ret = jffs2_init_security(inode, dir_i, &dentry->d_name); +- if (ret) +- goto fail; +- +- ret = jffs2_init_acl_post(inode); +- if (ret) +- goto fail; +- +- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, +- ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); +- if (ret) +- goto fail; + +- rd = jffs2_alloc_raw_dirent(); +- if (!rd) { +- /* Argh. Now we treat it like a normal delete */ +- jffs2_complete_reservation(c); +- ret = -ENOMEM; +- goto fail; ++ pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ++ __func__, ret); ++ /* Might as well let the VFS know */ ++ new_dir_i->i_mtime = new_dir_i->i_ctime = now; ++ return ret; + } + +- dir_f = JFFS2_INODE_INFO(dir_i); +- mutex_lock(&dir_f->sem); + +- rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +- rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); +- rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); +- rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); ++ new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = now; + +- rd->pino = cpu_to_je32(dir_i->i_ino); +- rd->version = cpu_to_je32(++dir_f->highest_version); +- rd->ino = cpu_to_je32(inode->i_ino); +- rd->mctime = cpu_to_je32(JFFS2_NOW()); +- rd->nsize = namelen; ++ return 0; ++} + +- /* XXX: This is ugly. */ +- rd->type = (mode & S_IFMT) >> 12; ++int jffs2_create(struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, ++ struct jffs2_inode **new_i) ++{ ++ struct jffs2_raw_inode *ri; ++ struct jffs2_inode_info *f, *dir_f; ++ struct jffs2_sb_info *c; ++ struct jffs2_inode *inode; ++ int ret; ++ mode &= ~S_IFMT; ++ mode |= S_IFREG; ++ ri = jffs2_alloc_raw_inode(); ++ if (!ri) ++ return -ENOMEM; + +- rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); +- rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); ++ c = JFFS2_SB_INFO(dir_i->i_sb); + +- fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); ++ D1(printk(KERN_DEBUG "jffs2_create()\n")); ++ inode = jffs2_new_inode(dir_i, mode, ri); + +- if (IS_ERR(fd)) { +- /* dirent failed to write. Delete the inode normally +- as if it were the final unlink() */ +- jffs2_complete_reservation(c); +- jffs2_free_raw_dirent(rd); +- mutex_unlock(&dir_f->sem); +- ret = PTR_ERR(fd); +- goto fail; ++ if (IS_ERR(inode)) { ++ D1(printk(KERN_DEBUG "jffs2_new_inode() failed, error:%ld\n", PTR_ERR(inode))); ++ jffs2_free_raw_inode(ri); ++ return PTR_ERR(inode); + } + +- dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); ++ f = JFFS2_INODE_INFO(inode); ++ dir_f = JFFS2_INODE_INFO(dir_i); + +- jffs2_free_raw_dirent(rd); ++ /* jffs2_do_create() will want to lock it, _after_ reserving ++ space and taking c-alloc_sem. If we keep it locked here, ++ lockdep gets unhappy (although it's a false positive; ++ nothing else will be looking at this inode yet so there's ++ no chance of AB-BA deadlock involving its f->sem). */ ++ mutex_unlock(&f->sem); ++ ret = jffs2_do_create(c, dir_f, f, ri, ++ (const char *)d_name, ++ strlen((char *)d_name)); + +- /* Link the fd into the inode's list, obsoleting an old +- one if necessary. */ +- jffs2_add_fd_to_list(c, fd, &dir_f->dents); ++ if (ret) { ++ inode->i_nlink = 0; ++ jffs2_iput(inode); ++ jffs2_free_raw_inode(ri); ++ return ret; ++ } + +- mutex_unlock(&dir_f->sem); +- jffs2_complete_reservation(c); ++ jffs2_free_raw_inode(ri); + +- d_instantiate_new(dentry, inode); ++ D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d)\n", ++ inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->pino_nlink)); ++ *new_i = inode; + return 0; ++} + +- fail: +- iget_failed(inode); +- return ret; ++static __inline void fill_name(char *dst_name, int nlen, const unsigned char *name, int namlen) ++{ ++ int len = nlen < namlen ? nlen : namlen; ++ (void)memcpy_s(dst_name, nlen, name, len); ++ dst_name[len] = '\0'; + } + +-static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, +- struct inode *new_dir_i, struct dentry *new_dentry, +- unsigned int flags) ++int jffs2_readdir(struct jffs2_inode *inode, off_t *offset, off_t *int_off, struct dirent *ent) + { +- int ret; +- struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); +- struct jffs2_inode_info *victim_f = NULL; +- uint8_t type; +- uint32_t now; ++ struct jffs2_inode_info *f; ++ struct jffs2_full_dirent *fd; ++ off_t curofs = 0; + +- if (flags & ~RENAME_NOREPLACE) +- return -EINVAL; ++ f = JFFS2_INODE_INFO(inode); + +- /* The VFS will check for us and prevent trying to rename a +- * file over a directory and vice versa, but if it's a directory, +- * the VFS can't check whether the victim is empty. The filesystem +- * needs to do that for itself. +- */ +- if (d_really_is_positive(new_dentry)) { +- victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); +- if (d_is_dir(new_dentry)) { +- struct jffs2_full_dirent *fd; +- +- mutex_lock(&victim_f->sem); +- for (fd = victim_f->dents; fd; fd = fd->next) { +- if (fd->ino) { +- mutex_unlock(&victim_f->sem); +- return -ENOTEMPTY; +- } +- } +- mutex_unlock(&victim_f->sem); ++ mutex_lock(&f->sem); ++ for (fd = f->dents; fd; fd = fd->next) { ++ if (curofs++ < *int_off) { ++ D2(printk ++ (KERN_DEBUG ++ "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", ++ fd->name, fd->ino, fd->type, curofs, offset)); ++ continue; + } +- } +- +- /* XXX: We probably ought to alloc enough space for +- both nodes at the same time. Writing the new link, +- then getting -ENOSPC, is quite bad :) +- */ +- +- /* Make a hard link */ +- +- /* XXX: This is ugly */ +- type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; +- if (!type) type = DT_REG; +- +- now = JFFS2_NOW(); +- ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), +- d_inode(old_dentry)->i_ino, type, +- new_dentry->d_name.name, new_dentry->d_name.len, now); +- +- if (ret) +- return ret; +- +- if (victim_f) { +- /* There was a victim. Kill it off nicely */ +- if (d_is_dir(new_dentry)) +- clear_nlink(d_inode(new_dentry)); +- else +- drop_nlink(d_inode(new_dentry)); +- /* Don't oops if the victim was a dirent pointing to an +- inode which didn't exist. */ +- if (victim_f->inocache) { +- mutex_lock(&victim_f->sem); +- if (d_is_dir(new_dentry)) +- victim_f->inocache->pino_nlink = 0; +- else +- victim_f->inocache->pino_nlink--; +- mutex_unlock(&victim_f->sem); ++ if (!fd->ino) { ++ D2(printk (KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name)); ++ (*int_off)++; ++ continue; + } +- } + +- /* If it was a directory we moved, and there was no victim, +- increase i_nlink on its new parent */ +- if (d_is_dir(old_dentry) && !victim_f) +- inc_nlink(new_dir_i); +- +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); +- +- /* We don't touch inode->i_nlink */ +- +- if (ret) { +- /* Oh shit. We really ought to make a single node which can do both atomically */ +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); +- mutex_lock(&f->sem); +- inc_nlink(d_inode(old_dentry)); +- if (f->inocache && !d_is_dir(old_dentry)) +- f->inocache->pino_nlink++; +- mutex_unlock(&f->sem); ++ D2(printk ++ (KERN_DEBUG "%s-%d: Dirent %ld: \"%s\", ino #%u, type %d\n", __FUNCTION__, __LINE__, offset, ++ fd->name, fd->ino, fd->type)); ++ fill_name(ent->d_name, sizeof(ent->d_name) - 1, fd->name, strlen((char *)fd->name)); ++ ent->d_type = fd->type; ++ ent->d_off = ++(*offset); ++ ent->d_reclen = (uint16_t)sizeof(struct dirent); + +- pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", +- __func__, ret); +- /* +- * We can't keep the target in dcache after that. +- * For one thing, we can't afford dentry aliases for directories. +- * For another, if there was a victim, we _can't_ set new inode +- * for that sucker and we have to trigger mount eviction - the +- * caller won't do it on its own since we are returning an error. +- */ +- d_invalidate(new_dentry); +- new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); +- return ret; ++ (*int_off)++; ++ break; + } + +- if (d_is_dir(old_dentry)) +- drop_nlink(old_dir_i); ++ mutex_unlock(&f->sem); + +- new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); ++ if (fd == NULL) { ++ D2(printk(KERN_DEBUG "reached the end of the directory\n")); ++ return ENOENT; ++ } + +- return 0; ++ return ENOERR; + } + +diff -Nupr old/fs/jffs2/erase.c new/fs/jffs2/erase.c +--- old/fs/jffs2/erase.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/erase.c 2022-05-10 16:09:47.150000000 +0800 +@@ -10,16 +10,19 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include +-#include + #include +-#include + #include + #include ++#include "mtd_dev.h" + #include "nodelist.h" ++#include "los_crc32.h" ++ ++struct erase_priv_struct { ++ struct jffs2_eraseblock *jeb; ++ struct jffs2_sb_info *c; ++}; + + static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset); + static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +@@ -29,50 +32,14 @@ static void jffs2_erase_block(struct jff + struct jffs2_eraseblock *jeb) + { + int ret; +- uint32_t bad_offset; +-#ifdef __ECOS +- ret = jffs2_flash_erase(c, jeb); +- if (!ret) { +- jffs2_erase_succeeded(c, jeb); +- return; +- } +- bad_offset = jeb->offset; +-#else /* Linux */ +- struct erase_info *instr; +- +- jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n", +- __func__, +- jeb->offset, jeb->offset, jeb->offset + c->sector_size); +- instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL); +- if (!instr) { +- pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); +- mutex_lock(&c->erase_free_sem); +- spin_lock(&c->erase_completion_lock); +- list_move(&jeb->list, &c->erase_pending_list); +- c->erasing_size -= c->sector_size; +- c->dirty_size += c->sector_size; +- jeb->dirty_size = c->sector_size; +- spin_unlock(&c->erase_completion_lock); +- mutex_unlock(&c->erase_free_sem); +- return; +- } ++ uint64_t bad_offset = 0; + +- memset(instr, 0, sizeof(*instr)); +- +- instr->addr = jeb->offset; +- instr->len = c->sector_size; +- +- ret = mtd_erase(c->mtd, instr); ++ ret = c->mtd->erase(c->mtd, jeb->offset, c->sector_size, &bad_offset); + if (!ret) { + jffs2_erase_succeeded(c, jeb); +- kfree(instr); + return; + } + +- bad_offset = instr->fail_addr; +- kfree(instr); +-#endif /* __ECOS */ +- + if (ret == -ENOMEM || ret == -EAGAIN) { + /* Erase failed immediately. Refile it on the list */ + jffs2_dbg(1, "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", +@@ -168,29 +135,10 @@ static void jffs2_erase_succeeded(struct + jffs2_garbage_collect_trigger(c); + spin_unlock(&c->erase_completion_lock); + mutex_unlock(&c->erase_free_sem); +- wake_up(&c->erase_wait); + } + + static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset) + { +- /* For NAND, if the failure did not occur at the device level for a +- specific physical page, don't bother updating the bad block table. */ +- if (jffs2_cleanmarker_oob(c) && (bad_offset != (uint32_t)MTD_FAIL_ADDR_UNKNOWN)) { +- /* We had a device-level failure to erase. Let's see if we've +- failed too many times. */ +- if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { +- /* We'd like to give this block another try. */ +- mutex_lock(&c->erase_free_sem); +- spin_lock(&c->erase_completion_lock); +- list_move(&jeb->list, &c->erase_pending_list); +- c->erasing_size -= c->sector_size; +- c->dirty_size += c->sector_size; +- jeb->dirty_size = c->sector_size; +- spin_unlock(&c->erase_completion_lock); +- mutex_unlock(&c->erase_free_sem); +- return; +- } +- } + + mutex_lock(&c->erase_free_sem); + spin_lock(&c->erase_completion_lock); +@@ -200,7 +148,6 @@ static void jffs2_erase_failed(struct jf + c->nr_erasing_blocks--; + spin_unlock(&c->erase_completion_lock); + mutex_unlock(&c->erase_free_sem); +- wake_up(&c->erase_wait); + } + + /* Hmmm. Maybe we should accept the extra space it takes and make +@@ -315,40 +262,8 @@ static int jffs2_block_check_erase(struc + void *ebuf; + uint32_t ofs; + size_t retlen; +- int ret; +- unsigned long *wordebuf; ++ int ret = -EIO; + +- ret = mtd_point(c->mtd, jeb->offset, c->sector_size, &retlen, +- &ebuf, NULL); +- if (ret != -EOPNOTSUPP) { +- if (ret) { +- jffs2_dbg(1, "MTD point failed %d\n", ret); +- goto do_flash_read; +- } +- if (retlen < c->sector_size) { +- /* Don't muck about if it won't let us point to the whole erase sector */ +- jffs2_dbg(1, "MTD point returned len too short: 0x%zx\n", +- retlen); +- mtd_unpoint(c->mtd, jeb->offset, retlen); +- goto do_flash_read; +- } +- wordebuf = ebuf-sizeof(*wordebuf); +- retlen /= sizeof(*wordebuf); +- do { +- if (*++wordebuf != ~0) +- break; +- } while(--retlen); +- mtd_unpoint(c->mtd, jeb->offset, c->sector_size); +- if (retlen) { +- pr_warn("Newly-erased block contained word 0x%lx at offset 0x%08tx\n", +- *wordebuf, +- jeb->offset + +- c->sector_size-retlen * sizeof(*wordebuf)); +- return -EIO; +- } +- return 0; +- } +- do_flash_read: + ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!ebuf) { + pr_warn("Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", +@@ -364,7 +279,7 @@ static int jffs2_block_check_erase(struc + + *bad_offset = ofs; + +- ret = mtd_read(c->mtd, ofs, readlen, &retlen, ebuf); ++ ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); + if (ret) { + pr_warn("Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", + ofs, ret); +@@ -379,7 +294,7 @@ static int jffs2_block_check_erase(struc + } + for (i=0; ierase_completion_lock); + mutex_unlock(&c->erase_free_sem); +- wake_up(&c->erase_wait); + return; + + filebad: +diff -Nupr old/fs/jffs2/file.c new/fs/jffs2/file.c +--- old/fs/jffs2/file.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/file.c 2022-05-10 09:43:14.250000000 +0800 +@@ -9,325 +9,34 @@ + * For licensing information, see the file 'LICENCE' in this directory. + * + */ ++#include "los_vm_common.h" + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include + #include "nodelist.h" ++#include "vfs_jffs2.h" + +-static int jffs2_write_end(struct file *filp, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned copied, +- struct page *pg, void *fsdata); +-static int jffs2_write_begin(struct file *filp, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned flags, +- struct page **pagep, void **fsdata); +-static int jffs2_readpage (struct file *filp, struct page *pg); +- +-int jffs2_fsync(struct file *filp, loff_t start, loff_t end, int datasync) +-{ +- struct inode *inode = filp->f_mapping->host; +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- int ret; +- +- ret = file_write_and_wait_range(filp, start, end); +- if (ret) +- return ret; + +- inode_lock(inode); +- /* Trigger GC to flush any pending writes for this inode */ +- jffs2_flush_wbuf_gc(c, inode->i_ino); +- inode_unlock(inode); ++static unsigned char gc_buffer[PAGE_SIZE]; //avoids malloc when user may be under memory pressure + +- return 0; +-} + +-const struct file_operations jffs2_file_operations = ++unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, ++ struct jffs2_inode_info *f, ++ unsigned long offset, ++ unsigned long *priv) + { +- .llseek = generic_file_llseek, +- .open = generic_file_open, +- .read_iter = generic_file_read_iter, +- .write_iter = generic_file_write_iter, +- .unlocked_ioctl=jffs2_ioctl, +- .mmap = generic_file_readonly_mmap, +- .fsync = jffs2_fsync, +- .splice_read = generic_file_splice_read, +- .splice_write = iter_file_splice_write, +-}; +- +-/* jffs2_file_inode_operations */ +- +-const struct inode_operations jffs2_file_inode_operations = +-{ +- .get_acl = jffs2_get_acl, +- .set_acl = jffs2_set_acl, +- .setattr = jffs2_setattr, +- .listxattr = jffs2_listxattr, +-}; +- +-const struct address_space_operations jffs2_file_address_operations = +-{ +- .readpage = jffs2_readpage, +- .write_begin = jffs2_write_begin, +- .write_end = jffs2_write_end, +-}; +- +-static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) +-{ +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- unsigned char *pg_buf; ++ /* FIXME: This works only with one file system mounted at a time */ + int ret; + +- jffs2_dbg(2, "%s(): ino #%lu, page at offset 0x%lx\n", +- __func__, inode->i_ino, pg->index << PAGE_SHIFT); +- +- BUG_ON(!PageLocked(pg)); +- +- pg_buf = kmap(pg); +- /* FIXME: Can kmap fail? */ +- +- ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_SHIFT, +- PAGE_SIZE); +- +- if (ret) { +- ClearPageUptodate(pg); +- SetPageError(pg); +- } else { +- SetPageUptodate(pg); +- ClearPageError(pg); +- } +- +- flush_dcache_page(pg); +- kunmap(pg); +- +- jffs2_dbg(2, "readpage finished\n"); +- return ret; +-} +- +-int jffs2_do_readpage_unlock(void *data, struct page *pg) +-{ +- int ret = jffs2_do_readpage_nolock(data, pg); +- unlock_page(pg); +- return ret; +-} +- +- +-static int jffs2_readpage (struct file *filp, struct page *pg) +-{ +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); +- int ret; ++ ret = jffs2_read_inode_range(c, f, gc_buffer, ++ offset & ~(PAGE_SIZE-1), PAGE_SIZE); ++ if (ret) ++ return ERR_PTR(ret); + +- mutex_lock(&f->sem); +- ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); +- mutex_unlock(&f->sem); +- return ret; ++ return gc_buffer; + } +- +-static int jffs2_write_begin(struct file *filp, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned flags, +- struct page **pagep, void **fsdata) ++void jffs2_gc_release_page(struct jffs2_sb_info *c, ++ unsigned char *ptr, ++ unsigned long *priv) + { +- struct page *pg; +- struct inode *inode = mapping->host; +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- pgoff_t index = pos >> PAGE_SHIFT; +- uint32_t pageofs = index << PAGE_SHIFT; +- int ret = 0; +- +- pg = grab_cache_page_write_begin(mapping, index, flags); +- if (!pg) +- return -ENOMEM; +- *pagep = pg; +- +- jffs2_dbg(1, "%s()\n", __func__); +- +- if (pageofs > inode->i_size) { +- /* Make new hole frag from old EOF to new page */ +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_raw_inode ri; +- struct jffs2_full_dnode *fn; +- uint32_t alloc_len; +- +- jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", +- (unsigned int)inode->i_size, pageofs); +- +- ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, +- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); +- if (ret) +- goto out_page; +- +- mutex_lock(&f->sem); +- memset(&ri, 0, sizeof(ri)); +- +- ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +- ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); +- ri.totlen = cpu_to_je32(sizeof(ri)); +- ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); +- +- ri.ino = cpu_to_je32(f->inocache->ino); +- ri.version = cpu_to_je32(++f->highest_version); +- ri.mode = cpu_to_jemode(inode->i_mode); +- ri.uid = cpu_to_je16(i_uid_read(inode)); +- ri.gid = cpu_to_je16(i_gid_read(inode)); +- ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); +- ri.atime = ri.ctime = ri.mtime = cpu_to_je32(JFFS2_NOW()); +- ri.offset = cpu_to_je32(inode->i_size); +- ri.dsize = cpu_to_je32(pageofs - inode->i_size); +- ri.csize = cpu_to_je32(0); +- ri.compr = JFFS2_COMPR_ZERO; +- ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); +- ri.data_crc = cpu_to_je32(0); +- +- fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL); +- +- if (IS_ERR(fn)) { +- ret = PTR_ERR(fn); +- jffs2_complete_reservation(c); +- mutex_unlock(&f->sem); +- goto out_page; +- } +- ret = jffs2_add_full_dnode_to_inode(c, f, fn); +- if (f->metadata) { +- jffs2_mark_node_obsolete(c, f->metadata->raw); +- jffs2_free_full_dnode(f->metadata); +- f->metadata = NULL; +- } +- if (ret) { +- jffs2_dbg(1, "Eep. add_full_dnode_to_inode() failed in write_begin, returned %d\n", +- ret); +- jffs2_mark_node_obsolete(c, fn->raw); +- jffs2_free_full_dnode(fn); +- jffs2_complete_reservation(c); +- mutex_unlock(&f->sem); +- goto out_page; +- } +- jffs2_complete_reservation(c); +- inode->i_size = pageofs; +- mutex_unlock(&f->sem); +- } +- +- /* +- * Read in the page if it wasn't already present. Cannot optimize away +- * the whole page write case until jffs2_write_end can handle the +- * case of a short-copy. +- */ +- if (!PageUptodate(pg)) { +- mutex_lock(&f->sem); +- ret = jffs2_do_readpage_nolock(inode, pg); +- mutex_unlock(&f->sem); +- if (ret) +- goto out_page; +- } +- jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); +- return ret; +- +-out_page: +- unlock_page(pg); +- put_page(pg); +- return ret; ++ /* Do nothing */ + } + +-static int jffs2_write_end(struct file *filp, struct address_space *mapping, +- loff_t pos, unsigned len, unsigned copied, +- struct page *pg, void *fsdata) +-{ +- /* Actually commit the write from the page cache page we're looking at. +- * For now, we write the full page out each time. It sucks, but it's simple +- */ +- struct inode *inode = mapping->host; +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_raw_inode *ri; +- unsigned start = pos & (PAGE_SIZE - 1); +- unsigned end = start + copied; +- unsigned aligned_start = start & ~3; +- int ret = 0; +- uint32_t writtenlen = 0; +- +- jffs2_dbg(1, "%s(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", +- __func__, inode->i_ino, pg->index << PAGE_SHIFT, +- start, end, pg->flags); +- +- /* We need to avoid deadlock with page_cache_read() in +- jffs2_garbage_collect_pass(). So the page must be +- up to date to prevent page_cache_read() from trying +- to re-lock it. */ +- BUG_ON(!PageUptodate(pg)); +- +- if (end == PAGE_SIZE) { +- /* When writing out the end of a page, write out the +- _whole_ page. This helps to reduce the number of +- nodes in files which have many short writes, like +- syslog files. */ +- aligned_start = 0; +- } +- +- ri = jffs2_alloc_raw_inode(); +- +- if (!ri) { +- jffs2_dbg(1, "%s(): Allocation of raw inode failed\n", +- __func__); +- unlock_page(pg); +- put_page(pg); +- return -ENOMEM; +- } +- +- /* Set the fields that the generic jffs2_write_inode_range() code can't find */ +- ri->ino = cpu_to_je32(inode->i_ino); +- ri->mode = cpu_to_jemode(inode->i_mode); +- ri->uid = cpu_to_je16(i_uid_read(inode)); +- ri->gid = cpu_to_je16(i_gid_read(inode)); +- ri->isize = cpu_to_je32((uint32_t)inode->i_size); +- ri->atime = ri->ctime = ri->mtime = cpu_to_je32(JFFS2_NOW()); +- +- /* In 2.4, it was already kmapped by generic_file_write(). Doesn't +- hurt to do it again. The alternative is ifdefs, which are ugly. */ +- kmap(pg); +- +- ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start, +- (pg->index << PAGE_SHIFT) + aligned_start, +- end - aligned_start, &writtenlen); +- +- kunmap(pg); +- +- if (ret) { +- /* There was an error writing. */ +- SetPageError(pg); +- } +- +- /* Adjust writtenlen for the padding we did, so we don't confuse our caller */ +- writtenlen -= min(writtenlen, (start - aligned_start)); +- +- if (writtenlen) { +- if (inode->i_size < pos + writtenlen) { +- inode->i_size = pos + writtenlen; +- inode->i_blocks = (inode->i_size + 511) >> 9; +- +- inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); +- } +- } +- +- jffs2_free_raw_inode(ri); +- +- if (start+writtenlen < end) { +- /* generic_file_write has written more to the page cache than we've +- actually written to the medium. Mark the page !Uptodate so that +- it gets reread */ +- jffs2_dbg(1, "%s(): Not all bytes written. Marking page !uptodate\n", +- __func__); +- SetPageError(pg); +- ClearPageUptodate(pg); +- } +- +- jffs2_dbg(1, "%s() returning %d\n", +- __func__, writtenlen > 0 ? writtenlen : ret); +- unlock_page(pg); +- put_page(pg); +- return writtenlen > 0 ? writtenlen : ret; +-} +diff -Nupr old/fs/jffs2/fs.c new/fs/jffs2/fs.c +--- old/fs/jffs2/fs.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/fs.c 2022-05-10 16:13:37.830000000 +0800 +@@ -10,136 +10,129 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include + #include "nodelist.h" ++#include "os-linux.h" ++#include "los_crc32.h" ++#include "jffs2_hash.h" ++#include "capability_type.h" ++#include "capability_api.h" + +-static int jffs2_flash_setup(struct jffs2_sb_info *c); +- +-int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) ++int jffs2_setattr (struct jffs2_inode *inode, struct IATTR *attr) + { + struct jffs2_full_dnode *old_metadata, *new_metadata; + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_raw_inode *ri; +- union jffs2_device_node dev; +- unsigned char *mdata = NULL; +- int mdatalen = 0; + unsigned int ivalid; ++ mode_t tmp_mode; ++ uint c_uid = OsCurrUserGet()->effUserID; ++ uint c_gid = OsCurrUserGet()->effGid; + uint32_t alloclen; + int ret; + int alloc_type = ALLOC_NORMAL; + + jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino); +- +- /* Special cases - we don't want more than one data node +- for these types on the medium at any time. So setattr +- must read the original data associated with the node +- (i.e. the device numbers or the target name) and write +- it out again with the appropriate data attached */ +- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { +- /* For these, we don't actually need to read the old node */ +- mdatalen = jffs2_encode_dev(&dev, inode->i_rdev); +- mdata = (char *)&dev; +- jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", +- __func__, mdatalen); +- } else if (S_ISLNK(inode->i_mode)) { +- mutex_lock(&f->sem); +- mdatalen = f->metadata->size; +- mdata = kmalloc(f->metadata->size, GFP_USER); +- if (!mdata) { +- mutex_unlock(&f->sem); +- return -ENOMEM; +- } +- ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); +- if (ret) { +- mutex_unlock(&f->sem); +- kfree(mdata); +- return ret; +- } +- mutex_unlock(&f->sem); +- jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n", +- __func__, mdatalen); +- } +- + ri = jffs2_alloc_raw_inode(); + if (!ri) { +- if (S_ISLNK(inode->i_mode)) +- kfree(mdata); + return -ENOMEM; + } + +- ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen, +- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); ++ ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); ++ + if (ret) { + jffs2_free_raw_inode(ri); +- if (S_ISLNK(inode->i_mode)) +- kfree(mdata); + return ret; + } + mutex_lock(&f->sem); +- ivalid = iattr->ia_valid; ++ ivalid = attr->attr_chg_valid; ++ tmp_mode = inode->i_mode; + + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); +- ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); +- ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ++ ri->totlen = cpu_to_je32(sizeof(*ri)); ++ ri->hdr_crc = cpu_to_je32(crc32(0, ri, (sizeof(struct jffs2_unknown_node)-4))); + + ri->ino = cpu_to_je32(inode->i_ino); + ri->version = cpu_to_je32(++f->highest_version); ++ ri->uid = cpu_to_je16(inode->i_uid); ++ ri->gid = cpu_to_je16(inode->i_gid); ++ ++ if (ivalid & CHG_UID) { ++ if (((c_uid != inode->i_uid) || (attr->attr_chg_uid != inode->i_uid)) && (!IsCapPermit(CAP_CHOWN))) { ++ jffs2_complete_reservation(c); ++ jffs2_free_raw_inode(ri); ++ mutex_unlock(&f->sem); ++ return -EPERM; ++ } else { ++ ri->uid = cpu_to_je16(attr->attr_chg_uid); ++ } ++ } ++ ++ if (ivalid & CHG_GID) { ++ if (((c_gid != inode->i_gid) || (attr->attr_chg_gid != inode->i_gid)) && (!IsCapPermit(CAP_CHOWN))) { ++ jffs2_complete_reservation(c); ++ jffs2_free_raw_inode(ri); ++ mutex_unlock(&f->sem); ++ return -EPERM; ++ } else { ++ ri->gid = cpu_to_je16(attr->attr_chg_gid); ++ } ++ } + +- ri->uid = cpu_to_je16((ivalid & ATTR_UID)? +- from_kuid(&init_user_ns, iattr->ia_uid):i_uid_read(inode)); +- ri->gid = cpu_to_je16((ivalid & ATTR_GID)? +- from_kgid(&init_user_ns, iattr->ia_gid):i_gid_read(inode)); +- +- if (ivalid & ATTR_MODE) +- ri->mode = cpu_to_jemode(iattr->ia_mode); +- else +- ri->mode = cpu_to_jemode(inode->i_mode); ++ if (ivalid & CHG_MODE) { ++ if (!IsCapPermit(CAP_FOWNER) && (c_uid != inode->i_uid)) { ++ jffs2_complete_reservation(c); ++ jffs2_free_raw_inode(ri); ++ mutex_unlock(&f->sem); ++ return -EPERM; ++ } else { ++ attr->attr_chg_mode &= ~S_IFMT; // delete file type ++ tmp_mode &= S_IFMT; ++ tmp_mode = attr->attr_chg_mode | tmp_mode; // add old file type ++ } ++ } + ++ if (ivalid & CHG_ATIME) { ++ if ((c_uid != inode->i_uid) || (attr->attr_chg_uid != inode->i_uid)) { ++ return -EPERM; ++ } else { ++ ri->atime = cpu_to_je32(attr->attr_chg_atime); ++ } ++ } else { ++ ri->atime = cpu_to_je32(inode->i_atime); ++ } ++ ++ if (ivalid & CHG_MTIME) { ++ if ((c_uid != inode->i_uid) || (attr->attr_chg_uid != inode->i_uid)) { ++ return -EPERM; ++ } else { ++ ri->mtime = cpu_to_je32(attr->attr_chg_mtime); ++ } ++ } else { ++ ri->mtime = cpu_to_je32(Jffs2CurSec()); ++ } ++ ri->mode = cpu_to_jemode(tmp_mode); + +- ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); +- ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); +- ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); +- ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); ++ ri->isize = cpu_to_je32((ivalid & CHG_SIZE) ? attr->attr_chg_size : inode->i_size); ++ ri->ctime = cpu_to_je32(Jffs2CurSec()); + + ri->offset = cpu_to_je32(0); +- ri->csize = ri->dsize = cpu_to_je32(mdatalen); ++ ri->csize = ri->dsize = cpu_to_je32(0); + ri->compr = JFFS2_COMPR_NONE; +- if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { ++ if (ivalid & CHG_SIZE && inode->i_size < attr->attr_chg_size) { + /* It's an extension. Make it a hole node */ + ri->compr = JFFS2_COMPR_ZERO; +- ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); ++ ri->dsize = cpu_to_je32(attr->attr_chg_size - inode->i_size); + ri->offset = cpu_to_je32(inode->i_size); +- } else if (ivalid & ATTR_SIZE && !iattr->ia_size) { ++ } else if (ivalid & CHG_SIZE && !attr->attr_chg_size) { + /* For truncate-to-zero, treat it as deletion because + it'll always be obsoleting all previous nodes */ + alloc_type = ALLOC_DELETION; + } +- ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); +- if (mdatalen) +- ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); +- else +- ri->data_crc = cpu_to_je32(0); +- +- new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); +- if (S_ISLNK(inode->i_mode)) +- kfree(mdata); +- ++ ri->node_crc = cpu_to_je32(crc32(0, ri, (sizeof(*ri)-8))); ++ ri->data_crc = cpu_to_je32(0); ++ new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, alloc_type); + if (IS_ERR(new_metadata)) { + jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); +@@ -147,23 +140,20 @@ int jffs2_do_setattr (struct inode *inod + return PTR_ERR(new_metadata); + } + /* It worked. Update the inode */ +- inode->i_atime = ITIME(je32_to_cpu(ri->atime)); +- inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); +- inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); ++ inode->i_atime = je32_to_cpu(ri->atime); ++ inode->i_ctime = je32_to_cpu(ri->ctime); ++ inode->i_mtime = je32_to_cpu(ri->mtime); + inode->i_mode = jemode_to_cpu(ri->mode); +- i_uid_write(inode, je16_to_cpu(ri->uid)); +- i_gid_write(inode, je16_to_cpu(ri->gid)); +- ++ inode->i_uid = je16_to_cpu(ri->uid); ++ inode->i_gid = je16_to_cpu(ri->gid); + + old_metadata = f->metadata; ++ if (ivalid & CHG_SIZE && inode->i_size > attr->attr_chg_size) ++ jffs2_truncate_fragtree (c, &f->fragtree, attr->attr_chg_size); + +- if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) +- jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); +- +- if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { ++ if (ivalid & CHG_SIZE && inode->i_size < attr->attr_chg_size) { + jffs2_add_full_dnode_to_inode(c, f, new_metadata); +- inode->i_size = iattr->ia_size; +- inode->i_blocks = (inode->i_size + 511) >> 9; ++ inode->i_size = attr->attr_chg_size; + f->metadata = NULL; + } else { + f->metadata = new_metadata; +@@ -182,315 +172,201 @@ int jffs2_do_setattr (struct inode *inod + We are protected from a simultaneous write() extending i_size + back past iattr->ia_size, because do_truncate() holds the + generic inode semaphore. */ +- if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { +- truncate_setsize(inode, iattr->ia_size); +- inode->i_blocks = (inode->i_size + 511) >> 9; ++ if (ivalid & CHG_SIZE && inode->i_size > attr->attr_chg_size) { ++ inode->i_size = attr->attr_chg_size; // truncate_setsize + } + + return 0; + } + +-int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) ++static void jffs2_clear_inode (struct jffs2_inode *inode) + { +- struct inode *inode = d_inode(dentry); +- int rc; +- +- rc = setattr_prepare(dentry, iattr); +- if (rc) +- return rc; +- +- rc = jffs2_do_setattr(inode, iattr); +- if (!rc && (iattr->ia_valid & ATTR_MODE)) +- rc = posix_acl_chmod(inode, inode->i_mode); ++ /* We can forget about this inode for now - drop all ++ * the nodelists associated with it, etc. ++ */ ++ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); ++ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + +- return rc; ++ jffs2_do_clear_inode(c, f); + } + +-int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) ++static struct jffs2_inode *ilookup(struct super_block *sb, uint32_t ino) + { +- struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb); +- unsigned long avail; ++ struct jffs2_inode *node = NULL; + +- buf->f_type = JFFS2_SUPER_MAGIC; +- buf->f_bsize = 1 << PAGE_SHIFT; +- buf->f_blocks = c->flash_size >> PAGE_SHIFT; +- buf->f_files = 0; +- buf->f_ffree = 0; +- buf->f_namelen = JFFS2_MAX_NAME_LEN; +- buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC; +- buf->f_fsid.val[1] = c->mtd->index; +- +- spin_lock(&c->erase_completion_lock); +- avail = c->dirty_size + c->free_size; +- if (avail > c->sector_size * c->resv_blocks_write) +- avail -= c->sector_size * c->resv_blocks_write; +- else +- avail = 0; +- spin_unlock(&c->erase_completion_lock); +- +- buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; ++ if (sb->s_root == NULL) { ++ return NULL; ++ } + +- return 0; ++ // Check for this inode in the cache ++ Jffs2NodeLock(); ++ (void)Jffs2HashGet(&sb->s_node_hash_lock, &sb->s_node_hash[0], sb, ino, &node); ++ Jffs2NodeUnlock(); ++ return node; + } + +- +-void jffs2_evict_inode (struct inode *inode) ++struct jffs2_inode *new_inode(struct super_block *sb) + { +- /* We can forget about this inode for now - drop all +- * the nodelists associated with it, etc. +- */ +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); ++ struct jffs2_inode *inode = NULL; + +- jffs2_dbg(1, "%s(): ino #%lu mode %o\n", +- __func__, inode->i_ino, inode->i_mode); +- truncate_inode_pages_final(&inode->i_data); +- clear_inode(inode); +- jffs2_do_clear_inode(c, f); ++ inode = zalloc(sizeof (struct jffs2_inode)); ++ if (inode == NULL) ++ return 0; ++ ++ D2(PRINTK("malloc new_inode %x ####################################\n", ++ inode)); ++ ++ inode->i_sb = sb; ++ inode->i_ino = 1; ++ inode->i_nlink = 1; // Let JFFS2 manage the link count ++ inode->i_size = 0; ++ LOS_ListInit((&(inode->i_hashlist))); ++ ++ return inode; + } + +-struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) ++struct jffs2_inode *jffs2_iget(struct super_block *sb, uint32_t ino) + { + struct jffs2_inode_info *f; + struct jffs2_sb_info *c; + struct jffs2_raw_inode latest_node; +- union jffs2_device_node jdev; +- struct inode *inode; +- dev_t rdev = 0; ++ struct jffs2_inode *inode; + int ret; + +- jffs2_dbg(1, "%s(): ino == %lu\n", __func__, ino); +- +- inode = iget_locked(sb, ino); +- if (!inode) +- return ERR_PTR(-ENOMEM); +- if (!(inode->i_state & I_NEW)) ++ Jffs2NodeLock(); ++ inode = ilookup(sb, ino); ++ if (inode) { ++ Jffs2NodeUnlock(); + return inode; ++ } ++ inode = new_inode(sb); ++ if (inode == NULL) { ++ Jffs2NodeUnlock(); ++ return (struct jffs2_inode *)-ENOMEM; ++ } + ++ inode->i_ino = ino; + f = JFFS2_INODE_INFO(inode); + c = JFFS2_SB_INFO(inode->i_sb); + +- jffs2_init_inode_info(f); +- mutex_lock(&f->sem); ++ (void)mutex_init(&f->sem); ++ (void)mutex_lock(&f->sem); + + ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); +- if (ret) +- goto error; ++ if (ret) { ++ (void)mutex_unlock(&f->sem); ++ inode->i_nlink = 0; ++ free(inode); ++ Jffs2NodeUnlock(); ++ return (struct jffs2_inode *)ret; ++ } + + inode->i_mode = jemode_to_cpu(latest_node.mode); +- i_uid_write(inode, je16_to_cpu(latest_node.uid)); +- i_gid_write(inode, je16_to_cpu(latest_node.gid)); ++ inode->i_uid = je16_to_cpu(latest_node.uid); ++ inode->i_gid = je16_to_cpu(latest_node.gid); + inode->i_size = je32_to_cpu(latest_node.isize); +- inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); +- inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); +- inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); +- +- set_nlink(inode, f->inocache->pino_nlink); ++ inode->i_atime = je32_to_cpu(latest_node.atime); ++ inode->i_mtime = je32_to_cpu(latest_node.mtime); ++ inode->i_ctime = je32_to_cpu(latest_node.ctime); ++ inode->i_nlink = f->inocache->pino_nlink; + +- inode->i_blocks = (inode->i_size + 511) >> 9; ++ (void)mutex_unlock(&f->sem); + +- switch (inode->i_mode & S_IFMT) { +- +- case S_IFLNK: +- inode->i_op = &jffs2_symlink_inode_operations; +- inode->i_link = f->target; +- break; +- +- case S_IFDIR: +- { +- struct jffs2_full_dirent *fd; +- set_nlink(inode, 2); /* parent and '.' */ +- +- for (fd=f->dents; fd; fd = fd->next) { +- if (fd->type == DT_DIR && fd->ino) +- inc_nlink(inode); +- } +- /* Root dir gets i_nlink 3 for some reason */ +- if (inode->i_ino == 1) +- inc_nlink(inode); +- +- inode->i_op = &jffs2_dir_inode_operations; +- inode->i_fop = &jffs2_dir_operations; +- break; +- } +- case S_IFREG: +- inode->i_op = &jffs2_file_inode_operations; +- inode->i_fop = &jffs2_file_operations; +- inode->i_mapping->a_ops = &jffs2_file_address_operations; +- inode->i_mapping->nrpages = 0; +- break; +- +- case S_IFBLK: +- case S_IFCHR: +- /* Read the device numbers from the media */ +- if (f->metadata->size != sizeof(jdev.old_id) && +- f->metadata->size != sizeof(jdev.new_id)) { +- pr_notice("Device node has strange size %d\n", +- f->metadata->size); +- goto error_io; +- } +- jffs2_dbg(1, "Reading device numbers from flash\n"); +- ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size); +- if (ret < 0) { +- /* Eep */ +- pr_notice("Read device numbers for inode %lu failed\n", +- (unsigned long)inode->i_ino); +- goto error; +- } +- if (f->metadata->size == sizeof(jdev.old_id)) +- rdev = old_decode_dev(je16_to_cpu(jdev.old_id)); +- else +- rdev = new_decode_dev(je32_to_cpu(jdev.new_id)); +- fallthrough; +- +- case S_IFSOCK: +- case S_IFIFO: +- inode->i_op = &jffs2_file_inode_operations; +- init_special_inode(inode, inode->i_mode, rdev); +- break; +- +- default: +- pr_warn("%s(): Bogus i_mode %o for ino %lu\n", +- __func__, inode->i_mode, (unsigned long)inode->i_ino); +- } +- +- mutex_unlock(&f->sem); ++ (void)Jffs2HashInsert(&sb->s_node_hash_lock, &sb->s_node_hash[0], inode, ino); + + jffs2_dbg(1, "jffs2_read_inode() returning\n"); +- unlock_new_inode(inode); +- return inode; +- +-error_io: +- ret = -EIO; +-error: +- mutex_unlock(&f->sem); +- iget_failed(inode); +- return ERR_PTR(ret); +-} ++ Jffs2NodeUnlock(); + +-void jffs2_dirty_inode(struct inode *inode, int flags) +-{ +- struct iattr iattr; +- +- if (!(inode->i_state & I_DIRTY_DATASYNC)) { +- jffs2_dbg(2, "%s(): not calling setattr() for ino #%lu\n", +- __func__, inode->i_ino); +- return; +- } +- +- jffs2_dbg(1, "%s(): calling setattr() for ino #%lu\n", +- __func__, inode->i_ino); +- +- iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME; +- iattr.ia_mode = inode->i_mode; +- iattr.ia_uid = inode->i_uid; +- iattr.ia_gid = inode->i_gid; +- iattr.ia_atime = inode->i_atime; +- iattr.ia_mtime = inode->i_mtime; +- iattr.ia_ctime = inode->i_ctime; +- +- jffs2_do_setattr(inode, &iattr); ++ return inode; + } + +-int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc) +-{ +- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); +- +- if (c->flags & JFFS2_SB_FLAG_RO && !sb_rdonly(sb)) +- return -EROFS; + +- /* We stop if it was running, then restart if it needs to. +- This also catches the case where it was stopped and this +- is just a remount to restart it. +- Flush the writebuffer, if neccecary, else we loose it */ +- if (!sb_rdonly(sb)) { +- jffs2_stop_garbage_collect_thread(c); +- mutex_lock(&c->alloc_sem); +- jffs2_flush_wbuf_pad(c); +- mutex_unlock(&c->alloc_sem); +- } ++// ------------------------------------------------------------------------- ++// Decrement the reference count on an inode. If this makes the ref count ++// zero, then this inode can be freed. ++ ++int jffs2_iput(struct jffs2_inode *i) ++{ ++ // Called in jffs2_find ++ // (and jffs2_open and jffs2_ops_mkdir?) ++ // super.c jffs2_fill_super, ++ // and gc.c jffs2_garbage_collect_pass ++ struct jffs2_inode_info *f = NULL; ++ ++ Jffs2NodeLock(); ++ if (!i || i->i_nlink) { ++ // and let it fault... ++ Jffs2NodeUnlock(); ++ return -EBUSY; ++ } ++ ++ jffs2_clear_inode(i); ++ f = JFFS2_INODE_INFO(i); ++ (void)mutex_destroy(&(f->sem)); ++ (void)Jffs2HashRemove(&i->i_sb->s_node_hash_lock, i); ++ (void)memset_s(i, sizeof(*i), 0x5a, sizeof(*i)); ++ free(i); ++ Jffs2NodeUnlock(); + +- if (!(fc->sb_flags & SB_RDONLY)) +- jffs2_start_garbage_collect_thread(c); +- +- fc->sb_flags |= SB_NOATIME; + return 0; + } + ++ + /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, + fill in the raw_inode while you're at it. */ +-struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_raw_inode *ri) ++struct jffs2_inode *jffs2_new_inode (struct jffs2_inode *dir_i, int mode, struct jffs2_raw_inode *ri) + { +- struct inode *inode; ++ struct jffs2_inode *inode; + struct super_block *sb = dir_i->i_sb; + struct jffs2_sb_info *c; + struct jffs2_inode_info *f; + int ret; + +- jffs2_dbg(1, "%s(): dir_i %ld, mode 0x%x\n", +- __func__, dir_i->i_ino, mode); +- + c = JFFS2_SB_INFO(sb); + ++ Jffs2NodeLock(); + inode = new_inode(sb); + + if (!inode) +- return ERR_PTR(-ENOMEM); ++ return (struct jffs2_inode *)-ENOMEM; + + f = JFFS2_INODE_INFO(inode); +- jffs2_init_inode_info(f); +- mutex_lock(&f->sem); ++ (void)mutex_init(&f->sem); ++ (void)mutex_lock(&f->sem);; + + memset(ri, 0, sizeof(*ri)); + /* Set OS-specific defaults for new inodes */ +- ri->uid = cpu_to_je16(from_kuid(&init_user_ns, current_fsuid())); ++ ri->uid = cpu_to_je16(OsCurrUserGet()->effUserID); ++ ri->gid = cpu_to_je16(OsCurrUserGet()->effGid); + +- if (dir_i->i_mode & S_ISGID) { +- ri->gid = cpu_to_je16(i_gid_read(dir_i)); +- if (S_ISDIR(mode)) +- mode |= S_ISGID; +- } else { +- ri->gid = cpu_to_je16(from_kgid(&init_user_ns, current_fsgid())); +- } +- +- /* POSIX ACLs have to be processed now, at least partly. +- The umask is only applied if there's no default ACL */ +- ret = jffs2_init_acl_pre(dir_i, inode, &mode); +- if (ret) { +- mutex_unlock(&f->sem); +- make_bad_inode(inode); +- iput(inode); +- return ERR_PTR(ret); +- } + ret = jffs2_do_new_inode (c, f, mode, ri); + if (ret) { +- mutex_unlock(&f->sem); +- make_bad_inode(inode); +- iput(inode); +- return ERR_PTR(ret); ++ mutex_unlock(&(f->sem)); ++ jffs2_clear_inode(inode); ++ (void)mutex_destroy(&(f->sem)); ++ (void)memset_s(inode, sizeof(*inode), 0x6a, sizeof(*inode)); ++ free(inode); ++ Jffs2NodeUnlock(); ++ return (struct jffs2_inode *)ret; ++ + } +- set_nlink(inode, 1); ++ inode->i_nlink = 1; + inode->i_ino = je32_to_cpu(ri->ino); + inode->i_mode = jemode_to_cpu(ri->mode); +- i_gid_write(inode, je16_to_cpu(ri->gid)); +- i_uid_write(inode, je16_to_cpu(ri->uid)); +- inode->i_atime = inode->i_ctime = inode->i_mtime = current_time(inode); +- ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); ++ inode->i_gid = je16_to_cpu(ri->gid); ++ inode->i_uid = je16_to_cpu(ri->uid); ++ inode->i_atime = inode->i_ctime = inode->i_mtime = Jffs2CurSec(); ++ ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime); + +- inode->i_blocks = 0; + inode->i_size = 0; + +- if (insert_inode_locked(inode) < 0) { +- mutex_unlock(&f->sem); +- make_bad_inode(inode); +- iput(inode); +- return ERR_PTR(-EINVAL); +- } ++ (void)Jffs2HashInsert(&sb->s_node_hash_lock, &sb->s_node_hash[0], inode, inode->i_ino); ++ Jffs2NodeUnlock(); + + return inode; + } + +-static int calculate_inocache_hashsize(uint32_t flash_size) ++int calculate_inocache_hashsize(uint32_t flash_size) + { + /* + * Pick a inocache hash size based on the size of the medium. +@@ -510,117 +386,17 @@ static int calculate_inocache_hashsize(u + return hashsize; + } + +-int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc) +-{ +- struct jffs2_sb_info *c; +- struct inode *root_i; +- int ret; +- size_t blocks; +- +- c = JFFS2_SB_INFO(sb); +- +- /* Do not support the MLC nand */ +- if (c->mtd->type == MTD_MLCNANDFLASH) +- return -EINVAL; +- +-#ifndef CONFIG_JFFS2_FS_WRITEBUFFER +- if (c->mtd->type == MTD_NANDFLASH) { +- errorf(fc, "Cannot operate on NAND flash unless jffs2 NAND support is compiled in"); +- return -EINVAL; +- } +- if (c->mtd->type == MTD_DATAFLASH) { +- errorf(fc, "Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in"); +- return -EINVAL; +- } +-#endif +- +- c->flash_size = c->mtd->size; +- c->sector_size = c->mtd->erasesize; +- blocks = c->flash_size / c->sector_size; +- +- /* +- * Size alignment check +- */ +- if ((c->sector_size * blocks) != c->flash_size) { +- c->flash_size = c->sector_size * blocks; +- infof(fc, "Flash size not aligned to erasesize, reducing to %dKiB", +- c->flash_size / 1024); +- } +- +- if (c->flash_size < 5*c->sector_size) { +- errorf(fc, "Too few erase blocks (%d)", +- c->flash_size / c->sector_size); +- return -EINVAL; +- } +- +- c->cleanmarker_size = sizeof(struct jffs2_unknown_node); +- +- /* NAND (or other bizarre) flash... do setup accordingly */ +- ret = jffs2_flash_setup(c); +- if (ret) +- return ret; +- +- c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); +- c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); +- if (!c->inocache_list) { +- ret = -ENOMEM; +- goto out_wbuf; +- } +- +- jffs2_init_xattr_subsystem(c); +- +- if ((ret = jffs2_do_mount_fs(c))) +- goto out_inohash; +- +- jffs2_dbg(1, "%s(): Getting root inode\n", __func__); +- root_i = jffs2_iget(sb, 1); +- if (IS_ERR(root_i)) { +- jffs2_dbg(1, "get root inode failed\n"); +- ret = PTR_ERR(root_i); +- goto out_root; +- } +- +- ret = -ENOMEM; +- +- jffs2_dbg(1, "%s(): d_make_root()\n", __func__); +- sb->s_root = d_make_root(root_i); +- if (!sb->s_root) +- goto out_root; +- +- sb->s_maxbytes = 0xFFFFFFFF; +- sb->s_blocksize = PAGE_SIZE; +- sb->s_blocksize_bits = PAGE_SHIFT; +- sb->s_magic = JFFS2_SUPER_MAGIC; +- sb->s_time_min = 0; +- sb->s_time_max = U32_MAX; +- +- if (!sb_rdonly(sb)) +- jffs2_start_garbage_collect_thread(c); +- return 0; +- +-out_root: +- jffs2_free_ino_caches(c); +- jffs2_free_raw_node_refs(c); +- kvfree(c->blocks); +- out_inohash: +- jffs2_clear_xattr_subsystem(c); +- kfree(c->inocache_list); +- out_wbuf: +- jffs2_flash_cleanup(c); +- +- return ret; +-} +- + void jffs2_gc_release_inode(struct jffs2_sb_info *c, +- struct jffs2_inode_info *f) ++ struct jffs2_inode_info *f) + { +- iput(OFNI_EDONI_2SFFJ(f)); ++ struct jffs2_inode *node = OFNI_EDONI_2SFFJ(f); ++ jffs2_iput(node); + } + + struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, + int inum, int unlinked) + { +- struct inode *inode; ++ struct jffs2_inode *inode; + struct jffs2_inode_cache *ic; + + if (unlinked) { +@@ -668,72 +444,9 @@ struct jffs2_inode_info *jffs2_gc_fetch_ + Just iget() it, and if read_inode() is necessary that's OK. + */ + inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum); +- if (IS_ERR(inode)) +- return ERR_CAST(inode); +- } +- if (is_bad_inode(inode)) { +- pr_notice("Eep. read_inode() failed for ino #%u. unlinked %d\n", +- inum, unlinked); +- /* NB. This will happen again. We need to do something appropriate here. */ +- iput(inode); +- return ERR_PTR(-EIO); ++ if (inode <= 0) ++ return (struct jffs2_inode_info *)inode; + } + + return JFFS2_INODE_INFO(inode); + } +- +-static int jffs2_flash_setup(struct jffs2_sb_info *c) { +- int ret = 0; +- +- if (jffs2_cleanmarker_oob(c)) { +- /* NAND flash... do setup accordingly */ +- ret = jffs2_nand_flash_setup(c); +- if (ret) +- return ret; +- } +- +- /* and Dataflash */ +- if (jffs2_dataflash(c)) { +- ret = jffs2_dataflash_setup(c); +- if (ret) +- return ret; +- } +- +- /* and Intel "Sibley" flash */ +- if (jffs2_nor_wbuf_flash(c)) { +- ret = jffs2_nor_wbuf_flash_setup(c); +- if (ret) +- return ret; +- } +- +- /* and an UBI volume */ +- if (jffs2_ubivol(c)) { +- ret = jffs2_ubivol_setup(c); +- if (ret) +- return ret; +- } +- +- return ret; +-} +- +-void jffs2_flash_cleanup(struct jffs2_sb_info *c) { +- +- if (jffs2_cleanmarker_oob(c)) { +- jffs2_nand_flash_cleanup(c); +- } +- +- /* and DataFlash */ +- if (jffs2_dataflash(c)) { +- jffs2_dataflash_cleanup(c); +- } +- +- /* and Intel "Sibley" flash */ +- if (jffs2_nor_wbuf_flash(c)) { +- jffs2_nor_wbuf_flash_cleanup(c); +- } +- +- /* and an UBI volume */ +- if (jffs2_ubivol(c)) { +- jffs2_ubivol_cleanup(c); +- } +-} +diff -Nupr old/fs/jffs2/gc.c new/fs/jffs2/gc.c +--- old/fs/jffs2/gc.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/gc.c 2022-05-10 16:11:42.090000000 +0800 +@@ -10,17 +10,17 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include +-#include + #include + #include +-#include ++#include ++#include + #include + #include ++#include "mtd_dev.h" + #include "nodelist.h" + #include "compr.h" ++#include "los_crc32.h" + + static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, +@@ -43,7 +43,7 @@ static int jffs2_garbage_collect_live(st + /* Called with erase_completion_lock held */ + static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) + { +- struct jffs2_eraseblock *ret; ++ struct jffs2_eraseblock *ret = NULL; + struct list_head *nextlist = NULL; + int n = jiffies % 128; + +@@ -131,62 +131,40 @@ int jffs2_garbage_collect_pass(struct jf + int ret = 0, inum, nlink; + int xattr = 0; + +- if (mutex_lock_interruptible(&c->alloc_sem)) ++ if (mutex_lock(&c->alloc_sem)) + return -EINTR; + +- + for (;;) { +- /* We can't start doing GC until we've finished checking +- the node CRCs etc. */ +- int bucket, want_ino; +- + spin_lock(&c->erase_completion_lock); + if (!c->unchecked_size) + break; ++ ++ /* We can't start doing GC yet. We haven't finished checking ++ the node CRCs etc. Do it now. */ ++ ++ /* checked_ino is protected by the alloc_sem */ ++ if (c->checked_ino > c->highest_ino && xattr) { ++ pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n", ++ c->unchecked_size); ++ jffs2_dbg_dump_block_lists_nolock(c); ++ spin_unlock(&c->erase_completion_lock); ++ mutex_unlock(&c->alloc_sem); ++ return -ENOSPC; ++ } ++ + spin_unlock(&c->erase_completion_lock); + + if (!xattr) + xattr = jffs2_verify_xattr(c); + + spin_lock(&c->inocache_lock); +- /* Instead of doing the inodes in numeric order, doing a lookup +- * in the hash for each possible number, just walk the hash +- * buckets of *existing* inodes. This means that we process +- * them out-of-order, but it can be a lot faster if there's +- * a sparse inode# space. Which there often is. */ +- want_ino = c->check_ino; +- for (bucket = c->check_ino % c->inocache_hashsize ; bucket < c->inocache_hashsize; bucket++) { +- for (ic = c->inocache_list[bucket]; ic; ic = ic->next) { +- if (ic->ino < want_ino) +- continue; +- +- if (ic->state != INO_STATE_CHECKEDABSENT && +- ic->state != INO_STATE_PRESENT) +- goto got_next; /* with inocache_lock held */ + +- jffs2_dbg(1, "Skipping ino #%u already checked\n", +- ic->ino); +- } +- want_ino = 0; +- } +- +- /* Point c->check_ino past the end of the last bucket. */ +- c->check_ino = ((c->highest_ino + c->inocache_hashsize + 1) & +- ~c->inocache_hashsize) - 1; +- +- spin_unlock(&c->inocache_lock); +- +- pr_crit("Checked all inodes but still 0x%x bytes of unchecked space?\n", +- c->unchecked_size); +- jffs2_dbg_dump_block_lists_nolock(c); +- mutex_unlock(&c->alloc_sem); +- return -ENOSPC; ++ ic = jffs2_get_ino_cache(c, c->checked_ino++); + +- got_next: +- /* For next time round the loop, we want c->checked_ino to indicate +- * the *next* one we want to check. And since we're walking the +- * buckets rather than doing it sequentially, it's: */ +- c->check_ino = ic->ino + c->inocache_hashsize; ++ if (!ic) { ++ spin_unlock(&c->inocache_lock); ++ continue; ++ } + + if (!ic->pino_nlink) { + jffs2_dbg(1, "Skipping check of ino #%d with nlink/pino zero\n", +@@ -198,6 +176,8 @@ int jffs2_garbage_collect_pass(struct jf + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + case INO_STATE_PRESENT: ++ jffs2_dbg(1, "Skipping ino #%u already checked\n", ++ ic->ino); + spin_unlock(&c->inocache_lock); + continue; + +@@ -207,6 +187,7 @@ int jffs2_garbage_collect_pass(struct jf + ic->ino, ic->state); + spin_unlock(&c->inocache_lock); + BUG(); ++ break; + + case INO_STATE_READING: + /* We need to wait for it to finish, lest we move on +@@ -216,7 +197,7 @@ int jffs2_garbage_collect_pass(struct jf + ic->ino); + /* We need to come back again for the _same_ inode. We've + made no progress in this case, but that should be OK */ +- c->check_ino = ic->ino; ++ c->checked_ino--; + + mutex_unlock(&c->alloc_sem); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); +@@ -224,6 +205,7 @@ int jffs2_garbage_collect_pass(struct jf + + default: + BUG(); ++ break; + + case INO_STATE_UNCHECKED: + ; +@@ -290,7 +272,7 @@ int jffs2_garbage_collect_pass(struct jf + raw = jeb->gc_node; + gcblock_dirty = jeb->dirty_size; + +- while(ref_obsolete(raw)) { ++ while(raw && ref_obsolete(raw)) { + jffs2_dbg(1, "Node at 0x%08x is obsolete... skipping\n", + ref_offset(raw)); + raw = ref_next(raw); +@@ -310,7 +292,7 @@ int jffs2_garbage_collect_pass(struct jf + jffs2_dbg(1, "Going to garbage collect node at 0x%08x\n", + ref_offset(raw)); + +- if (!raw->next_in_ino) { ++ if (raw &&!raw->next_in_ino) { + /* Inode-less node. Clean marker, snapshot or something like that */ + spin_unlock(&c->erase_completion_lock); + if (ref_flags(raw) == REF_PRISTINE) { +@@ -368,7 +350,7 @@ int jffs2_garbage_collect_pass(struct jf + We can just copy any pristine nodes, but have + to prevent anyone else from doing read_inode() while + we're at it, so we set the state accordingly */ +- if (ref_flags(raw) == REF_PRISTINE) ++ if (raw && ref_flags(raw) == REF_PRISTINE) + ic->state = INO_STATE_GC; + else { + jffs2_dbg(1, "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", +@@ -393,6 +375,7 @@ int jffs2_garbage_collect_pass(struct jf + mutex_unlock(&c->alloc_sem); + spin_unlock(&c->inocache_lock); + BUG(); ++ break; + + case INO_STATE_READING: + /* Someone's currently trying to read it. We must wait for +@@ -430,7 +413,6 @@ int jffs2_garbage_collect_pass(struct jf + + spin_lock(&c->inocache_lock); + ic->state = INO_STATE_CHECKEDABSENT; +- wake_up(&c->inocache_wq); + + if (ret != -EBADFD) { + spin_unlock(&c->inocache_lock); +@@ -460,9 +442,7 @@ int jffs2_garbage_collect_pass(struct jf + ret = 0; + goto release_sem; + } +- + ret = jffs2_garbage_collect_live(c, jeb, raw, f); +- + jffs2_gc_release_inode(c, f); + + test_gcnode: +@@ -541,7 +521,7 @@ static int jffs2_garbage_collect_live(st + break; /* We've found them all */ + } + } +- if (fn) { ++ if (fn != NULL && frag != NULL) { + if (ref_flags(raw) == REF_PRISTINE) { + ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); + if (!ret) { +@@ -552,7 +532,7 @@ static int jffs2_garbage_collect_live(st + goto upnout; + } + /* We found a datanode. Do the GC */ +- if((start >> PAGE_SHIFT) < ((end-1) >> PAGE_SHIFT)) { ++ if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) { + /* It crosses a page boundary. Therefore, it must be a hole. */ + ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end); + } else { +@@ -635,6 +615,7 @@ static int jffs2_garbage_collect_pristin + if (je32_to_cpu(node->u.hdr_crc) != crc) { + pr_warn("Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + +@@ -645,6 +626,7 @@ static int jffs2_garbage_collect_pristin + pr_warn("Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.node_crc), + crc); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + +@@ -654,6 +636,7 @@ static int jffs2_garbage_collect_pristin + pr_warn("Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), + je32_to_cpu(node->i.data_crc), crc); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + } +@@ -665,12 +648,14 @@ static int jffs2_garbage_collect_pristin + pr_warn("Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), + je32_to_cpu(node->d.node_crc), crc); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + +- if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { ++ if (strnlen((const char *)node->d.name, node->d.nsize) != node->d.nsize) { + pr_warn("Name in dirent node at 0x%08x contains zeroes\n", + ref_offset(raw)); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + +@@ -680,6 +665,7 @@ static int jffs2_garbage_collect_pristin + pr_warn("Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), + je32_to_cpu(node->d.name_crc), crc); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + } +@@ -689,6 +675,7 @@ static int jffs2_garbage_collect_pristin + if (ic) { + pr_warn("Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); ++ jffs2_dbg_dump_node(c, ref_offset(raw)); + goto bail; + } + } +@@ -697,7 +684,7 @@ static int jffs2_garbage_collect_pristin + retry: + phys_ofs = write_ofs(c); + +- ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); ++ ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (const u_char *)node); + + if (ret || (retlen != rawlen)) { + pr_notice("Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", +@@ -761,7 +748,7 @@ static int jffs2_garbage_collect_metadat + struct jffs2_full_dnode *new_fn; + struct jffs2_raw_inode ri; + struct jffs2_node_frag *last_frag; +- union jffs2_device_node dev; ++ jint16_t dev; + char *mdata = NULL; + int mdatalen = 0; + uint32_t alloclen, ilen; +@@ -770,8 +757,9 @@ static int jffs2_garbage_collect_metadat + if (S_ISBLK(JFFS2_F_I_MODE(f)) || + S_ISCHR(JFFS2_F_I_MODE(f)) ) { + /* For these, we don't actually need to read the old node */ +- mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f)); ++ dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | JFFS2_F_I_RDEV_MIN(f))); + mdata = (char *)&dev; ++ mdatalen = sizeof(dev); + jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", + __func__, mdatalen); + } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { +@@ -781,7 +769,7 @@ static int jffs2_garbage_collect_metadat + pr_warn("kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n"); + return -ENOMEM; + } +- ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen); ++ ret = jffs2_read_dnode(c, f, fn, (unsigned char *)mdata, 0, mdatalen); + if (ret) { + pr_warn("read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", + ret); +@@ -831,7 +819,7 @@ static int jffs2_garbage_collect_metadat + ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); + ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); + +- new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, ALLOC_GC); ++ new_fn = jffs2_write_dnode(c, f, &ri, (unsigned char *)mdata, mdatalen, ALLOC_GC); + + if (IS_ERR(new_fn)) { + pr_warn("Error writing new dnode: %ld\n", PTR_ERR(new_fn)); +@@ -857,7 +845,7 @@ static int jffs2_garbage_collect_dirent( + + rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); +- rd.nsize = strlen(fd->name); ++ rd.nsize = strlen((const char *)fd->name); + rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); + rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); + +@@ -908,7 +896,7 @@ static int jffs2_garbage_collect_deletio + struct jffs2_raw_node_ref *raw; + int ret; + size_t retlen; +- int name_len = strlen(fd->name); ++ int name_len = strlen((const char *)fd->name); + uint32_t name_crc = crc32(0, fd->name, name_len); + uint32_t rawlen = ref_totlen(c, jeb, fd->raw); + +@@ -1053,6 +1041,7 @@ static int jffs2_garbage_collect_hole(st + pr_warn("%s: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", + __func__, ref_offset(fn->raw), + je32_to_cpu(ri.node_crc), crc); ++ jffs2_dbg_dump_node(c, ref_offset(fn->raw)); + /* FIXME: We could possibly deal with this by writing new holes for each frag */ + pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", + start, end, f->inocache->ino); +@@ -1165,13 +1154,12 @@ static int jffs2_garbage_collect_dnode(s + struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, + uint32_t start, uint32_t end) + { +- struct inode *inode = OFNI_EDONI_2SFFJ(f); + struct jffs2_full_dnode *new_fn; + struct jffs2_raw_inode ri; + uint32_t alloclen, offset, orig_end, orig_start; + int ret = 0; + unsigned char *comprbuf = NULL, *writebuf; +- struct page *page; ++ unsigned long pg; + unsigned char *pg_ptr; + + memset(&ri, 0, sizeof(ri)); +@@ -1193,8 +1181,8 @@ static int jffs2_garbage_collect_dnode(s + struct jffs2_node_frag *frag; + uint32_t min, max; + +- min = start & ~(PAGE_SIZE-1); +- max = min + PAGE_SIZE; ++ min = start & ~(PAGE_CACHE_SIZE-1); ++ max = min + PAGE_CACHE_SIZE; + + frag = jffs2_lookup_node_frag(&f->fragtree, start); + +@@ -1203,7 +1191,7 @@ static int jffs2_garbage_collect_dnode(s + BUG_ON(frag->ofs != start); + + /* First grow down... */ +- while((frag = frag_prev(frag)) && frag->ofs >= min) { ++ while(frag && (frag = frag_prev(frag)) && frag->ofs >= min) { + + /* If the previous frag doesn't even reach the beginning, there's + excessive fragmentation. Just merge. */ +@@ -1259,7 +1247,7 @@ static int jffs2_garbage_collect_dnode(s + /* Find last frag which is actually part of the node we're to GC. */ + frag = jffs2_lookup_node_frag(&f->fragtree, end-1); + +- while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { ++ while(frag && (frag = frag_next(frag)) && frag->ofs+frag->size <= max) { + + /* If the previous frag doesn't even reach the beginning, there's lots + of fragmentation. Just merge. */ +@@ -1317,27 +1305,21 @@ static int jffs2_garbage_collect_dnode(s + BUG_ON(start > orig_start); + } + +- /* The rules state that we must obtain the page lock *before* f->sem, so +- * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's +- * actually going to *change* so we're safe; we only allow reading. +- * +- * It is important to note that jffs2_write_begin() will ensure that its +- * page is marked Uptodate before allocating space. That means that if we +- * end up here trying to GC the *same* page that jffs2_write_begin() is +- * trying to write out, read_cache_page() will not deadlock. */ +- mutex_unlock(&f->sem); +- page = read_cache_page(inode->i_mapping, start >> PAGE_SHIFT, +- jffs2_do_readpage_unlock, inode); +- if (IS_ERR(page)) { ++ /* First, use readpage() to read the appropriate page into the page cache */ ++ /* Q: What happens if we actually try to GC the _same_ page for which commit_write() ++ * triggered garbage collection in the first place? ++ * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the ++ * page OK. We'll actually write it out again in commit_write, which is a little ++ * suboptimal, but at least we're correct. ++ */ ++ pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); ++ ++ if (IS_ERR(pg_ptr)) { + pr_warn("read_cache_page() returned error: %ld\n", +- PTR_ERR(page)); +- mutex_lock(&f->sem); +- return PTR_ERR(page); ++ PTR_ERR(pg_ptr)); ++ return PTR_ERR(pg_ptr); + } + +- pg_ptr = kmap(page); +- mutex_lock(&f->sem); +- + offset = start; + while(offset < orig_end) { + uint32_t datalen; +@@ -1355,7 +1337,7 @@ static int jffs2_garbage_collect_dnode(s + cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); + datalen = end - offset; + +- writebuf = pg_ptr + (offset & (PAGE_SIZE -1)); ++ writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); + + comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen); + +@@ -1400,7 +1382,6 @@ static int jffs2_garbage_collect_dnode(s + } + } + +- kunmap(page); +- put_page(page); ++ jffs2_gc_release_page(c, pg_ptr, &pg); + return ret; + } +diff -Nupr old/fs/jffs2/ioctl.c new/fs/jffs2/ioctl.c +--- old/fs/jffs2/ioctl.c 2022-05-09 17:15:24.350000000 +0800 ++++ new/fs/jffs2/ioctl.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,22 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2001-2007 Red Hat, Inc. +- * Copyright © 2004-2010 David Woodhouse +- * +- * Created by David Woodhouse +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#include +-#include "nodelist.h" +- +-long jffs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +-{ +- /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which +- will include compression support etc. */ +- return -ENOTTY; +-} +- +diff -Nupr old/fs/jffs2/jffs2_fs_i.h new/fs/jffs2/jffs2_fs_i.h +--- old/fs/jffs2/jffs2_fs_i.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/jffs2_fs_i.h 2022-05-09 20:50:05.810000000 +0800 +@@ -14,8 +14,13 @@ + #define _JFFS2_FS_I + + #include +-#include +-#include ++#include ++ ++#ifdef __cplusplus ++#if __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ + + struct jffs2_inode_info { + /* We need an internal mutex similar to inode->i_mutex. +@@ -24,7 +29,7 @@ struct jffs2_inode_info { + before letting GC proceed. Or we'd have to put ugliness + into the GC code so it didn't attempt to obtain the i_mutex + for the inode(s) which are already locked */ +- struct mutex sem; ++ struct pthread_mutex sem; + + /* The highest (datanode) version number used for this ino */ + uint32_t highest_version; +@@ -50,7 +55,29 @@ struct jffs2_inode_info { + + uint16_t flags; + uint8_t usercompr; +- struct inode vfs_inode; + }; + ++struct super_block; ++ ++struct jffs2_inode { ++ uint32_t i_ino; ++ mode_t i_mode; ++ nlink_t i_nlink; ++ uid_t i_uid; ++ gid_t i_gid; ++ time_t i_atime; ++ time_t i_mtime; ++ time_t i_ctime; ++ off_t i_size; ++ struct super_block *i_sb; ++ LOS_DL_LIST i_hashlist; ++ struct jffs2_inode_info jffs2_i; ++}; ++ ++#ifdef __cplusplus ++#if __cplusplus ++} ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ + #endif /* _JFFS2_FS_I */ +diff -Nupr old/fs/jffs2/jffs2_fs_sb.h new/fs/jffs2/jffs2_fs_sb.h +--- old/fs/jffs2/jffs2_fs_sb.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/jffs2_fs_sb.h 2022-05-09 20:49:43.100000000 +0800 +@@ -17,11 +17,18 @@ + #include + #include + #include +-#include + #include + #include + #include + #include ++#include "vfs_jffs2.h" ++#include "mtd_dev.h" ++ ++#ifdef __cplusplus ++#if __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ + + #define JFFS2_SB_FLAG_RO 1 + #define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */ +@@ -47,10 +54,10 @@ struct jffs2_mount_opts { + Nee jffs_control + */ + struct jffs2_sb_info { +- struct mtd_info *mtd; ++ struct MtdDev *mtd; + + uint32_t highest_ino; +- uint32_t check_ino; /* *NEXT* inode to be checked */ ++ uint32_t checked_ino; + + unsigned int flags; + +@@ -58,7 +65,7 @@ struct jffs2_sb_info { + struct completion gc_thread_start; /* GC thread start completion */ + struct completion gc_thread_exit; /* GC thread exit completion port */ + +- struct mutex alloc_sem; /* Used to protect all the following ++ struct pthread_mutex alloc_sem; /* Used to protect all the following + fields, and also to protect against + out-of-order writing of nodes. And GC. */ + uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER +@@ -120,7 +127,7 @@ struct jffs2_sb_info { + /* Sem to allow jffs2_garbage_collect_deletion_dirent to + drop the erase_completion_lock while it's holding a pointer + to an obsoleted node. I don't like this. Alternatives welcomed. */ +- struct mutex erase_free_sem; ++ struct pthread_mutex erase_free_sem; + + uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ + +@@ -160,4 +167,27 @@ struct jffs2_sb_info { + void *os_priv; + }; + ++struct super_block { ++ struct jffs2_sb_info jffs2_sb; ++ LIST_HEAD s_node_hash[JFFS2_NODE_HASH_BUCKETS]; ++ LosMux s_node_hash_lock; ++ struct jffs2_inode *s_root; ++ void *s_dev; ++ ++ UINT32 s_lock; /* Lock the inode cache */ ++ EVENT_CB_S s_gc_thread_flags; /* Communication with the gcthread */ ++ unsigned int s_gc_thread; ++ unsigned long s_mount_flags; ++}; ++ ++#define JFFS2_SB_INFO(sb) (&(sb)->jffs2_sb) ++#define OFNI_BS_2SFFJ(c) \ ++ ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->jffs2_sb)) ) ) ++ ++#ifdef __cplusplus ++#if __cplusplus ++} ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ + #endif /* _JFFS2_FS_SB */ +diff -Nupr old/fs/jffs2/malloc.c new/fs/jffs2/malloc.c +--- old/fs/jffs2/malloc.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/malloc.c 2022-05-10 09:43:16.720000000 +0800 +@@ -9,111 +9,31 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include +-#include +-#include ++#include + #include "nodelist.h" + +-/* These are initialised to NULL in the kernel startup code. +- If you're porting to other operating systems, beware */ +-static struct kmem_cache *full_dnode_slab; +-static struct kmem_cache *raw_dirent_slab; +-static struct kmem_cache *raw_inode_slab; +-static struct kmem_cache *tmp_dnode_info_slab; +-static struct kmem_cache *raw_node_ref_slab; +-static struct kmem_cache *node_frag_slab; +-static struct kmem_cache *inode_cache_slab; +-#ifdef CONFIG_JFFS2_FS_XATTR +-static struct kmem_cache *xattr_datum_cache; +-static struct kmem_cache *xattr_ref_cache; ++#if !defined(JFFS2NUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE) ++# define JFFS2NUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE 0 + #endif + + int __init jffs2_create_slab_caches(void) + { +- full_dnode_slab = kmem_cache_create("jffs2_full_dnode", +- sizeof(struct jffs2_full_dnode), +- 0, 0, NULL); +- if (!full_dnode_slab) +- goto err; +- +- raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", +- sizeof(struct jffs2_raw_dirent), +- 0, SLAB_HWCACHE_ALIGN, NULL); +- if (!raw_dirent_slab) +- goto err; +- +- raw_inode_slab = kmem_cache_create("jffs2_raw_inode", +- sizeof(struct jffs2_raw_inode), +- 0, SLAB_HWCACHE_ALIGN, NULL); +- if (!raw_inode_slab) +- goto err; +- +- tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", +- sizeof(struct jffs2_tmp_dnode_info), +- 0, 0, NULL); +- if (!tmp_dnode_info_slab) +- goto err; +- +- raw_node_ref_slab = kmem_cache_create("jffs2_refblock", +- sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), +- 0, 0, NULL); +- if (!raw_node_ref_slab) +- goto err; +- +- node_frag_slab = kmem_cache_create("jffs2_node_frag", +- sizeof(struct jffs2_node_frag), +- 0, 0, NULL); +- if (!node_frag_slab) +- goto err; +- +- inode_cache_slab = kmem_cache_create("jffs2_inode_cache", +- sizeof(struct jffs2_inode_cache), +- 0, 0, NULL); +- if (!inode_cache_slab) +- goto err; +- +-#ifdef CONFIG_JFFS2_FS_XATTR +- xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", +- sizeof(struct jffs2_xattr_datum), +- 0, 0, NULL); +- if (!xattr_datum_cache) +- goto err; +- +- xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", +- sizeof(struct jffs2_xattr_ref), +- 0, 0, NULL); +- if (!xattr_ref_cache) +- goto err; +-#endif +- + return 0; +- err: +- jffs2_destroy_slab_caches(); +- return -ENOMEM; ++ + } + + void jffs2_destroy_slab_caches(void) + { +- kmem_cache_destroy(full_dnode_slab); +- kmem_cache_destroy(raw_dirent_slab); +- kmem_cache_destroy(raw_inode_slab); +- kmem_cache_destroy(tmp_dnode_info_slab); +- kmem_cache_destroy(raw_node_ref_slab); +- kmem_cache_destroy(node_frag_slab); +- kmem_cache_destroy(inode_cache_slab); +-#ifdef CONFIG_JFFS2_FS_XATTR +- kmem_cache_destroy(xattr_datum_cache); +- kmem_cache_destroy(xattr_ref_cache); +-#endif ++ return; + } + ++ + struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) + { + struct jffs2_full_dirent *ret; +- ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); ++ ret = zalloc(sizeof(struct jffs2_full_dirent) + namesize); + dbg_memalloc("%p\n", ret); + return ret; + } +@@ -127,7 +47,7 @@ void jffs2_free_full_dirent(struct jffs2 + struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) + { + struct jffs2_full_dnode *ret; +- ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); ++ ret = zalloc(sizeof(struct jffs2_full_dnode)); + dbg_memalloc("%p\n", ret); + return ret; + } +@@ -135,13 +55,13 @@ struct jffs2_full_dnode *jffs2_alloc_ful + void jffs2_free_full_dnode(struct jffs2_full_dnode *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(full_dnode_slab, x); ++ free(x); + } + + struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) + { + struct jffs2_raw_dirent *ret; +- ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); ++ ret = zalloc(sizeof(struct jffs2_raw_dirent)); + dbg_memalloc("%p\n", ret); + return ret; + } +@@ -149,13 +69,13 @@ struct jffs2_raw_dirent *jffs2_alloc_raw + void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(raw_dirent_slab, x); ++ free(x); + } + + struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) + { + struct jffs2_raw_inode *ret; +- ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); ++ ret = zalloc(sizeof(struct jffs2_raw_inode)); + dbg_memalloc("%p\n", ret); + return ret; + } +@@ -163,13 +83,13 @@ struct jffs2_raw_inode *jffs2_alloc_raw_ + void jffs2_free_raw_inode(struct jffs2_raw_inode *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(raw_inode_slab, x); ++ free(x); + } + + struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) + { + struct jffs2_tmp_dnode_info *ret; +- ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); ++ ret = zalloc(sizeof(struct jffs2_tmp_dnode_info)); + dbg_memalloc("%p\n", + ret); + return ret; +@@ -178,14 +98,14 @@ struct jffs2_tmp_dnode_info *jffs2_alloc + void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(tmp_dnode_info_slab, x); ++ free(x); + } + + static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) + { + struct jffs2_raw_node_ref *ret; + +- ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); ++ ret = malloc(sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK+1)); + if (ret) { + int i = 0; + for (i=0; i < REFS_PER_BLOCK; i++) { +@@ -242,13 +162,13 @@ int jffs2_prealloc_raw_node_refs(struct + void jffs2_free_refblock(struct jffs2_raw_node_ref *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(raw_node_ref_slab, x); ++ free(x); + } + + struct jffs2_node_frag *jffs2_alloc_node_frag(void) + { + struct jffs2_node_frag *ret; +- ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); ++ ret = malloc(sizeof(struct jffs2_node_frag)); + dbg_memalloc("%p\n", ret); + return ret; + } +@@ -256,13 +176,14 @@ struct jffs2_node_frag *jffs2_alloc_node + void jffs2_free_node_frag(struct jffs2_node_frag *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(node_frag_slab, x); ++ free(x); + } + ++ + struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) + { + struct jffs2_inode_cache *ret; +- ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); ++ ret = zalloc(sizeof(struct jffs2_inode_cache));; + dbg_memalloc("%p\n", ret); + return ret; + } +@@ -270,14 +191,14 @@ struct jffs2_inode_cache *jffs2_alloc_in + void jffs2_free_inode_cache(struct jffs2_inode_cache *x) + { + dbg_memalloc("%p\n", x); +- kmem_cache_free(inode_cache_slab, x); ++ kfree(x); + } + + #ifdef CONFIG_JFFS2_FS_XATTR + struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) + { + struct jffs2_xattr_datum *xd; +- xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL); ++ xd = malloc(sizeof(struct jffs2_xattr_datum)); + dbg_memalloc("%p\n", xd); + if (!xd) + return NULL; +@@ -291,13 +212,13 @@ struct jffs2_xattr_datum *jffs2_alloc_xa + void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) + { + dbg_memalloc("%p\n", xd); +- kmem_cache_free(xattr_datum_cache, xd); ++ kfree(xd); + } + + struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) + { + struct jffs2_xattr_ref *ref; +- ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL); ++ ref = malloc(sizeof(struct jffs2_xattr_ref)); + dbg_memalloc("%p\n", ref); + if (!ref) + return NULL; +@@ -310,6 +231,6 @@ struct jffs2_xattr_ref *jffs2_alloc_xatt + void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) + { + dbg_memalloc("%p\n", ref); +- kmem_cache_free(xattr_ref_cache, ref); ++ kfree(ref); + } + #endif +diff -Nupr old/fs/jffs2/nodelist.c new/fs/jffs2/nodelist.c +--- old/fs/jffs2/nodelist.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/nodelist.c 2022-05-09 20:37:35.680000000 +0800 +@@ -9,16 +9,15 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include + #include +-#include + #include +-#include + #include ++#include + #include "nodelist.h" ++#include "jffs2.h" ++#include "los_crc32.h" + + static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, + struct jffs2_node_frag *this); +@@ -30,7 +29,7 @@ void jffs2_add_fd_to_list(struct jffs2_s + dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino); + + while ((*prev) && (*prev)->nhash <= new->nhash) { +- if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { ++ if ((*prev)->nhash == new->nhash && !strcmp((const char *)((*prev)->name), (const char *)new->name)) { + /* Duplicate. Free one */ + if (new->version < (*prev)->version) { + dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n", +@@ -41,7 +40,7 @@ void jffs2_add_fd_to_list(struct jffs2_s + dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n", + (*prev)->name, (*prev)->ino); + new->next = (*prev)->next; +- /* It may have been a 'placeholder' deletion dirent, ++ /* It may have been a 'placeholder' deletion dirent, + if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */ + if ((*prev)->raw) + jffs2_mark_node_obsolete(c, ((*prev)->raw)); +@@ -65,13 +64,14 @@ uint32_t jffs2_truncate_fragtree(struct + /* We know frag->ofs <= size. That's what lookup does for us */ + if (frag && frag->ofs != size) { + if (frag->ofs+frag->size > size) { ++ dbg_fragtree("truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size); + frag->size = size - frag->ofs; + } + frag = frag_next(frag); + } + while (frag && frag->ofs >= size) { + struct jffs2_node_frag *next = frag_next(frag); +- ++ dbg_fragtree("removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size); + frag_erase(frag, list); + jffs2_obsolete_node_frag(c, frag); + frag = next; +@@ -90,7 +90,7 @@ uint32_t jffs2_truncate_fragtree(struct + + /* If the last fragment starts at the RAM page boundary, it is + * REF_PRISTINE irrespective of its size. */ +- if (frag->node && (frag->ofs & (PAGE_SIZE - 1)) == 0) { ++ if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { + dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", + frag->ofs, frag->ofs + frag->size); + frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; +@@ -237,7 +237,7 @@ static int jffs2_add_frag_to_fragtree(st + If so, both 'this' and the new node get marked REF_NORMAL so + the GC can take a look. + */ +- if (lastend && (lastend-1) >> PAGE_SHIFT == newfrag->ofs >> PAGE_SHIFT) { ++ if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { + if (this->node) + mark_ref_normal(this->node->raw); + mark_ref_normal(newfrag->node->raw); +@@ -382,7 +382,7 @@ int jffs2_add_full_dnode_to_inode(struct + + /* If we now share a page with other nodes, mark either previous + or next node REF_NORMAL, as appropriate. */ +- if (newfrag->ofs & (PAGE_SIZE-1)) { ++ if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *prev = frag_prev(newfrag); + + mark_ref_normal(fn->raw); +@@ -391,7 +391,7 @@ int jffs2_add_full_dnode_to_inode(struct + mark_ref_normal(prev->node->raw); + } + +- if ((newfrag->ofs+newfrag->size) & (PAGE_SIZE-1)) { ++ if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *next = frag_next(newfrag); + + if (next) { +@@ -401,7 +401,7 @@ int jffs2_add_full_dnode_to_inode(struct + } + } + jffs2_dbg_fragtree_paranoia_check_nolock(f); +- ++ jffs2_dbg_dump_fragtree_nolock(f); + return 0; + } + +@@ -409,7 +409,6 @@ void jffs2_set_inocache_state(struct jff + { + spin_lock(&c->inocache_lock); + ic->state = state; +- wake_up(&c->inocache_wq); + spin_unlock(&c->inocache_lock); + } + +@@ -505,8 +504,12 @@ void jffs2_free_raw_node_refs(struct jff + { + int i; + struct jffs2_raw_node_ref *this, *next; ++ struct super_block *sb = NULL; ++ struct MtdNorDev *device = NULL; ++ sb = OFNI_BS_2SFFJ(c); ++ device = (struct MtdNorDev*)(sb->s_dev); + +- for (i=0; inr_blocks; i++) { ++ for (i=device->blockStart; inr_blocks+device->blockStart; i++) { + this = c->blocks[i].first_node; + while (this) { + if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE) +@@ -536,14 +539,22 @@ struct jffs2_node_frag *jffs2_lookup_nod + while(next) { + frag = rb_entry(next, struct jffs2_node_frag, rb); + ++ dbg_fragtree2("considering frag %#04x-%#04x (%p). left %p, right %p\n", ++ frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right); + if (frag->ofs + frag->size <= offset) { ++ dbg_fragtree2("going right from frag %#04x-%#04x, before the region we care about\n", ++ frag->ofs, frag->ofs+frag->size); + /* Remember the closest smaller match on the way down */ + if (!prev || frag->ofs > prev->ofs) + prev = frag; + next = frag->rb.rb_right; + } else if (frag->ofs > offset) { ++ dbg_fragtree2("going left from frag %#04x-%#04x, after the region we care about\n", ++ frag->ofs, frag->ofs+frag->size); + next = frag->rb.rb_left; + } else { ++ dbg_fragtree2("returning frag %#04x-%#04x, matched\n", ++ frag->ofs, frag->ofs+frag->size); + return frag; + } + } +@@ -564,10 +575,12 @@ struct jffs2_node_frag *jffs2_lookup_nod + they're killed. */ + void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) + { +- struct jffs2_node_frag *frag, *next; ++ struct jffs2_node_frag *frag; ++ struct rb_node *tn,*next; + + dbg_fragtree("killing\n"); +- rbtree_postorder_for_each_entry_safe(frag, next, root, rb) { ++ RB_POSTORDER_FOREACH_SAFE(tn, linux_root, (struct linux_root *)root, next) { ++ frag = (struct jffs2_node_frag *)tn; + if (frag->node && !(--frag->node->frags)) { + /* Not a hole, and it's the final remaining frag + of this node. Free the node */ +@@ -604,7 +617,7 @@ struct jffs2_raw_node_ref *jffs2_link_no + ref++; + } + +- dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, ++ dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, + ref->flash_offset, ofs, ref->next_in_ino, len); + + ref->flash_offset = ofs; +@@ -617,7 +630,7 @@ struct jffs2_raw_node_ref *jffs2_link_no + + JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", + ref, ref_offset(ref), ref_offset(ref)+len, +- ref_offset(jeb->last_node), ++ ref_offset(jeb->last_node), + ref_offset(jeb->last_node)+last_len); + BUG(); + } +@@ -734,7 +747,7 @@ uint32_t __jffs2_ref_totlen(struct jffs2 + pr_crit("next %p (0x%08x-0x%08x)\n", + ref_next(ref), ref_offset(ref_next(ref)), + ref_offset(ref_next(ref)) + ref->__totlen); +- } else ++ } else + pr_crit("No next ref. jeb->last_node is %p\n", + jeb->last_node); + +diff -Nupr old/fs/jffs2/nodelist.h new/fs/jffs2/nodelist.h +--- old/fs/jffs2/nodelist.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/nodelist.h 2022-05-09 20:36:25.460000000 +0800 +@@ -12,20 +12,28 @@ + #ifndef __JFFS2_NODELIST_H__ + #define __JFFS2_NODELIST_H__ + +-#include ++#include + #include +-#include ++#include ++#include "jffs2.h" + #include "jffs2_fs_sb.h" + #include "jffs2_fs_i.h" + #include "xattr.h" + #include "acl.h" + #include "summary.h" +- +-#ifdef __ECOS +-#include "os-ecos.h" +-#else ++#include "vfs_jffs2.h" + #include "os-linux.h" +-#endif ++ ++#ifdef __cplusplus ++#if __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ ++struct kvec { ++ void *iov_base; ++ long iov_len; ++}; + + #define JFFS2_NATIVE_ENDIAN + +@@ -193,6 +201,8 @@ struct jffs2_inode_cache { + #define INO_STATE_READING 5 /* In read_inode() */ + #define INO_STATE_CLEARING 6 /* In clear_inode() */ + ++#define INOCACHE_HASHSIZE 128 ++ + #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ + #define INO_FLAGS_IS_DIR 0x02 /* is a directory */ + +@@ -250,10 +260,7 @@ struct jffs2_readinode_info + + struct jffs2_full_dirent + { +- union { +- struct jffs2_raw_node_ref *raw; +- struct jffs2_inode_cache *ic; /* Just during part of build */ +- }; ++ struct jffs2_raw_node_ref *raw; + struct jffs2_full_dirent *next; + uint32_t version; + uint32_t ino; /* == zero for unlink */ +@@ -313,34 +320,26 @@ static inline int jffs2_blocks_use_vmall + + #define PAD(x) (((x)+3)&~3) + +-static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev) +-{ +- if (old_valid_dev(rdev)) { +- jdev->old_id = cpu_to_je16(old_encode_dev(rdev)); +- return sizeof(jdev->old_id); +- } else { +- jdev->new_id = cpu_to_je32(new_encode_dev(rdev)); +- return sizeof(jdev->new_id); +- } +-} + + static inline struct jffs2_node_frag *frag_first(struct rb_root *root) + { +- struct rb_node *node = rb_first(root); ++ struct rb_node *node = root->rb_node; + + if (!node) + return NULL; +- ++ while(node->rb_left) ++ node = node->rb_left; + return rb_entry(node, struct jffs2_node_frag, rb); + } + + static inline struct jffs2_node_frag *frag_last(struct rb_root *root) + { +- struct rb_node *node = rb_last(root); ++ struct rb_node *node = root->rb_node; + + if (!node) + return NULL; +- ++ while(node->rb_right) ++ node = node->rb_right; + return rb_entry(node, struct jffs2_node_frag, rb); + } + +@@ -404,8 +403,9 @@ struct jffs2_full_dirent *jffs2_write_di + int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + struct jffs2_raw_inode *ri, unsigned char *buf, + uint32_t offset, uint32_t writelen, uint32_t *retlen); +-int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, +- struct jffs2_raw_inode *ri, const struct qstr *qstr); ++int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, ++ struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, ++ const char *name, int namelen); + int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, + int namelen, struct jffs2_inode_info *dead_f, uint32_t time); + int jffs2_do_link(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, +@@ -481,4 +481,10 @@ int jffs2_write_nand_cleanmarker(struct + + #include "debug.h" + ++#ifdef __cplusplus ++#if __cplusplus ++} ++#endif /* __cplusplus */ ++#endif /* __cplusplus */ ++ + #endif /* __JFFS2_NODELIST_H__ */ +diff -Nupr old/fs/jffs2/nodemgmt.c new/fs/jffs2/nodemgmt.c +--- old/fs/jffs2/nodemgmt.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/nodemgmt.c 2022-05-09 20:35:50.910000000 +0800 +@@ -9,46 +9,14 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include +-#include + #include +-#include ++#include /* For cond_resched() */ ++#include ++#include + #include "nodelist.h" + #include "debug.h" + +-/* +- * Check whether the user is allowed to write. +- */ +-static int jffs2_rp_can_write(struct jffs2_sb_info *c) +-{ +- uint32_t avail; +- struct jffs2_mount_opts *opts = &c->mount_opts; +- +- avail = c->dirty_size + c->free_size + c->unchecked_size + +- c->erasing_size - c->resv_blocks_write * c->sector_size +- - c->nospc_dirty_size; +- +- if (avail < 2 * opts->rp_size) +- jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, " +- "erasing_size %u, unchecked_size %u, " +- "nr_erasing_blocks %u, avail %u, resrv %u\n", +- opts->rp_size, c->dirty_size, c->free_size, +- c->erasing_size, c->unchecked_size, +- c->nr_erasing_blocks, avail, c->nospc_dirty_size); +- +- if (avail > opts->rp_size) +- return 1; +- +- /* Always allow root */ +- if (capable(CAP_SYS_RESOURCE)) +- return 1; +- +- jffs2_dbg(1, "forbid writing\n"); +- return 0; +-} +- + /** + * jffs2_reserve_space - request physical space to write nodes to flash + * @c: superblock info +@@ -57,8 +25,8 @@ static int jffs2_rp_can_write(struct jff + * @prio: Allocation type - ALLOC_{NORMAL,DELETION} + * + * Requests a block of physical space on the flash. Returns zero for success +- * and puts 'len' into the appropriate place, or returns -ENOSPC or other +- * error if appropriate. Doesn't return len since that's ++ * and puts 'len' into the appropriate place, or returns -ENOSPC or other ++ * error if appropriate. Doesn't return len since that's + * + * If it returns zero, jffs2_reserve_space() also downs the per-filesystem + * allocation semaphore, to prevent more than one allocation from being +@@ -86,15 +54,6 @@ int jffs2_reserve_space(struct jffs2_sb_ + + spin_lock(&c->erase_completion_lock); + +- /* +- * Check if the free space is greater then size of the reserved pool. +- * If not, only allow root to proceed with writing. +- */ +- if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) { +- ret = -ENOSPC; +- goto out; +- } +- + /* this needs a little more thought (true :)) */ + while(ret == -EAGAIN) { + while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { +@@ -165,24 +124,7 @@ int jffs2_reserve_space(struct jffs2_sb_ + spin_unlock(&c->erase_completion_lock); + + ret = jffs2_garbage_collect_pass(c); +- +- if (ret == -EAGAIN) { +- spin_lock(&c->erase_completion_lock); +- if (c->nr_erasing_blocks && +- list_empty(&c->erase_pending_list) && +- list_empty(&c->erase_complete_list)) { +- DECLARE_WAITQUEUE(wait, current); +- set_current_state(TASK_UNINTERRUPTIBLE); +- add_wait_queue(&c->erase_wait, &wait); +- jffs2_dbg(1, "%s waiting for erase to complete\n", +- __func__); +- spin_unlock(&c->erase_completion_lock); +- +- schedule(); +- remove_wait_queue(&c->erase_wait, &wait); +- } else +- spin_unlock(&c->erase_completion_lock); +- } else if (ret) ++ if (ret) + return ret; + + cond_resched(); +@@ -200,7 +142,6 @@ int jffs2_reserve_space(struct jffs2_sb_ + } + } + +-out: + spin_unlock(&c->erase_completion_lock); + if (!ret) + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); +@@ -509,7 +450,7 @@ struct jffs2_raw_node_ref *jffs2_add_phy + jffs2_dbg(1, "%s(): Node at 0x%x(%d), size 0x%x\n", + __func__, ofs & ~3, ofs & 3, len); + #if 1 +- /* Allow non-obsolete nodes only to be added at the end of c->nextblock, ++ /* Allow non-obsolete nodes only to be added at the end of c->nextblock, + if c->nextblock is set. Note that wbuf.c will file obsolete nodes + even after refiling c->nextblock */ + if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) +@@ -584,6 +525,8 @@ void jffs2_mark_node_obsolete(struct jff + int ret, addedsize; + size_t retlen; + uint32_t freed_len; ++ struct super_block *sb; ++ struct MtdNorDev *device; + + if(unlikely(!ref)) { + pr_notice("EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); +@@ -595,9 +538,10 @@ void jffs2_mark_node_obsolete(struct jff + return; + } + blocknr = ref->flash_offset / c->sector_size; +- if (blocknr >= c->nr_blocks) { +- pr_notice("raw node at 0x%08x is off the end of device!\n", +- ref->flash_offset); ++ sb = OFNI_BS_2SFFJ(c); ++ device = (struct MtdNorDev*)(sb->s_dev); ++ if (blocknr >= c->nr_blocks +device->blockStart) { ++ pr_notice("raw node at 0x%08x is off the end of device!\n",ref->flash_offset); + BUG(); + } + jeb = &c->blocks[blocknr]; +@@ -778,7 +722,7 @@ void jffs2_mark_node_obsolete(struct jff + } + /* XXX FIXME: This is ugly now */ + n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); +- ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); ++ ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (const u_char *)&n); + if (ret) { + pr_warn("Write error in obliterating obsoleted node at 0x%08x: %d\n", + ref_offset(ref), ret); +@@ -846,8 +790,8 @@ int jffs2_thread_should_wake(struct jffs + return 1; + + if (c->unchecked_size) { +- jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, check_ino #%d\n", +- c->unchecked_size, c->check_ino); ++ jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", ++ c->unchecked_size, c->checked_ino); + return 1; + } + +diff -Nupr old/fs/jffs2/os-linux.h new/fs/jffs2/os-linux.h +--- old/fs/jffs2/os-linux.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/os-linux.h 2022-05-09 20:33:21.200000000 +0800 +@@ -12,59 +12,57 @@ + #ifndef __JFFS2_OS_LINUX_H__ + #define __JFFS2_OS_LINUX_H__ + ++#include ++#include "fs/fs.h" ++#include "jffs2.h" ++#include "jffs2_fs_sb.h" ++ ++ ++/* jffs2 debug output opion */ ++#define CONFIG_JFFS2_FS_DEBUG 0 /* 1 or 2 */ ++ ++/* jffs2 gc thread section */ ++#define JFFS2_GC_THREAD_PRIORITY 10 /* GC thread's priority */ ++ ++/* zlib section*/ ++#define CONFIG_JFFS2_ZLIB ++#define CONFIG_JFFS2_RTIME ++#define CONFIG_JFFS2_RUBIN ++ + /* JFFS2 uses Linux mode bits natively -- no need for conversion */ + #define os_to_jffs2_mode(x) (x) + #define jffs2_to_os_mode(x) (x) + ++#ifndef BUG_ON ++#define BUG_ON(x) do {if (unlikely(x)) BUG();} while (0) ++#endif ++ + struct kstatfs; + struct kvec; + +-#define JFFS2_INODE_INFO(i) (container_of(i, struct jffs2_inode_info, vfs_inode)) +-#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) +-#define JFFS2_SB_INFO(sb) (sb->s_fs_info) +-#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv) + ++#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i) ++#define OFNI_EDONI_2SFFJ(f) \ ++ ((struct jffs2_inode *) (((char *)f) - ((char *)(&((struct jffs2_inode *)NULL)->jffs2_i)))) + + #define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) + #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) +-#define JFFS2_F_I_UID(f) (i_uid_read(OFNI_EDONI_2SFFJ(f))) +-#define JFFS2_F_I_GID(f) (i_gid_read(OFNI_EDONI_2SFFJ(f))) +-#define JFFS2_F_I_RDEV(f) (OFNI_EDONI_2SFFJ(f)->i_rdev) +- +-#define JFFS2_CLAMP_TIME(t) ((uint32_t)clamp_t(time64_t, (t), 0, U32_MAX)) +-#define ITIME(sec) ((struct timespec64){sec, 0}) +-#define JFFS2_NOW() JFFS2_CLAMP_TIME(ktime_get_real_seconds()) +-#define I_SEC(tv) JFFS2_CLAMP_TIME((tv).tv_sec) +-#define JFFS2_F_I_CTIME(f) I_SEC(OFNI_EDONI_2SFFJ(f)->i_ctime) +-#define JFFS2_F_I_MTIME(f) I_SEC(OFNI_EDONI_2SFFJ(f)->i_mtime) +-#define JFFS2_F_I_ATIME(f) I_SEC(OFNI_EDONI_2SFFJ(f)->i_atime) +-#define sleep_on_spinunlock(wq, s) \ +- do { \ +- DECLARE_WAITQUEUE(__wait, current); \ +- add_wait_queue((wq), &__wait); \ +- set_current_state(TASK_UNINTERRUPTIBLE); \ +- spin_unlock(s); \ +- schedule(); \ +- remove_wait_queue((wq), &__wait); \ +- } while(0) +- +-static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) +-{ +- f->highest_version = 0; +- f->fragtree = RB_ROOT; +- f->metadata = NULL; +- f->dents = NULL; +- f->target = NULL; +- f->flags = 0; +- f->usercompr = 0; +-} ++#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) ++#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) ++#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) ++#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) ++#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) ++ ++#define ITIME(sec) ((struct timespec){sec, 0}) ++#define I_SEC(tv) ((tv).tv_sec) + ++#define sleep_on_spinunlock(wq, sl) do {spin_unlock(sl); msleep(100);} while (0) + +-#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & SB_RDONLY) ++#define jffs2_is_readonly(c) (0) + + #define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) * c->sector_size) ) +-#ifndef CONFIG_JFFS2_FS_WRITEBUFFER + ++#ifndef CONFIG_JFFS2_FS_WRITEBUFFER + + #ifdef CONFIG_JFFS2_SUMMARY + #define jffs2_can_mark_obsolete(c) (0) +@@ -77,10 +75,10 @@ static inline void jffs2_init_inode_info + #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) + + #define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf) +-#define jffs2_flash_read(c, ofs, len, retlen, buf) (mtd_read((c)->mtd, ofs, len, retlen, buf)) +-#define jffs2_flush_wbuf_pad(c) ({ do{} while(0); (void)(c), 0; }) ++#define jffs2_flash_read(c, ofs, len, retlen, buf) jffs2_flash_direct_read(c, ofs, len, retlen, buf) ++#define jffs2_flush_wbuf_pad(c) (c=c) + #define jffs2_flush_wbuf_gc(c, i) ({ do{} while(0); (void)(c), (void) i, 0; }) +-#define jffs2_write_nand_badblock(c,jeb,bad_offset) (1) ++#define jffs2_write_nand_badblock(c,jeb,p) (0) + #define jffs2_nand_flash_setup(c) (0) + #define jffs2_nand_flash_cleanup(c) do {} while(0) + #define jffs2_wbuf_dirty(c) (0) +@@ -100,7 +98,8 @@ static inline void jffs2_init_inode_info + + #else /* NAND and/or ECC'd NOR support present */ + +-#define jffs2_is_writebuffered(c) (c->wbuf != NULL) ++/* current not support */ ++#define jffs2_is_writebuffered(c) (0) + + #ifdef CONFIG_JFFS2_SUMMARY + #define jffs2_can_mark_obsolete(c) (0) +@@ -142,38 +141,28 @@ void jffs2_dirty_trigger(struct jffs2_sb + #endif /* WRITEBUFFER */ + + /* background.c */ +-int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); ++void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); + void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); + void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); + + /* dir.c */ +-extern const struct file_operations jffs2_dir_operations; +-extern const struct inode_operations jffs2_dir_inode_operations; +- +-/* file.c */ +-extern const struct file_operations jffs2_file_operations; +-extern const struct inode_operations jffs2_file_inode_operations; +-extern const struct address_space_operations jffs2_file_address_operations; +-int jffs2_fsync(struct file *, loff_t, loff_t, int); +-int jffs2_do_readpage_unlock(void *data, struct page *pg); +- +-/* ioctl.c */ +-long jffs2_ioctl(struct file *, unsigned int, unsigned long); +- +-/* symlink.c */ +-extern const struct inode_operations jffs2_symlink_inode_operations; ++struct jffs2_inode *jffs2_lookup(struct jffs2_inode *dir_i, const unsigned char *name, int namelen); ++int jffs2_create(struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, struct jffs2_inode **new_i); ++int jffs2_mkdir (struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, struct jffs2_inode **new_i); ++int jffs2_link (struct jffs2_inode *old_d_inode, struct jffs2_inode *dir_i, const unsigned char *d_name); ++int jffs2_symlink(struct jffs2_inode *dir_i, struct jffs2_inode **d_inode, const unsigned char *d_name, const char *target); ++int jffs2_unlink(struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name); ++int jffs2_rmdir (struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name); ++int jffs2_rename (struct jffs2_inode *old_dir_i, struct jffs2_inode *d_inode, const unsigned char *old_d_name, ++ struct jffs2_inode *new_dir_i, const unsigned char *new_d_name); ++int jffs2_readdir(struct jffs2_inode *inode, off_t *offset, off_t *int_off, struct dirent *ent); + + /* fs.c */ +-int jffs2_setattr (struct dentry *, struct iattr *); +-int jffs2_do_setattr (struct inode *, struct iattr *); +-struct inode *jffs2_iget(struct super_block *, unsigned long); +-void jffs2_evict_inode (struct inode *); +-void jffs2_dirty_inode(struct inode *inode, int flags); +-struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, +- struct jffs2_raw_inode *ri); +-int jffs2_statfs (struct dentry *, struct kstatfs *); +-int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc); +-int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc); ++int jffs2_setattr (struct jffs2_inode *inode, struct IATTR *attr); ++struct jffs2_inode *jffs2_iget(struct super_block *sb, uint32_t ino); ++int jffs2_iput(struct jffs2_inode * i); ++struct jffs2_inode *jffs2_new_inode (struct jffs2_inode *dir_i, int mode, struct jffs2_raw_inode *ri); ++ + void jffs2_gc_release_inode(struct jffs2_sb_info *c, + struct jffs2_inode_info *f); + struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, +@@ -183,15 +172,25 @@ unsigned char *jffs2_gc_fetch_page(struc + struct jffs2_inode_info *f, + unsigned long offset, + unsigned long *priv); ++void jffs2_gc_release_page(struct jffs2_sb_info *c, ++ unsigned char *pg, ++ unsigned long *priv); + void jffs2_flash_cleanup(struct jffs2_sb_info *c); + ++int calculate_inocache_hashsize(uint32_t flash_size); + + /* writev.c */ + int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen); + int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf); ++int jffs2_flash_direct_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, ++ size_t *retlen, const char *buf); + +-#endif /* __JFFS2_OS_LINUX_H__ */ ++/* super.c */ ++int jffs2_fill_super(struct super_block *sb); ++int jffs2_mount(int part_no, struct jffs2_inode **root_node, unsigned long mountflags); ++int jffs2_umount(struct jffs2_inode *root_node); + ++#endif /* __JFFS2_OS_LINUX_H__ */ + +diff -Nupr old/fs/jffs2/read.c new/fs/jffs2/read.c +--- old/fs/jffs2/read.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/read.c 2022-05-09 20:27:15.580000000 +0800 +@@ -9,16 +9,15 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include +-#include + #include +-#include + #include ++#include + #include "nodelist.h" + #include "compr.h" ++#include "los_crc32.h" ++#include "user_copy.h" + + int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + struct jffs2_full_dnode *fd, unsigned char *buf, +@@ -57,6 +56,7 @@ int jffs2_read_dnode(struct jffs2_sb_inf + if (crc != je32_to_cpu(ri->node_crc)) { + pr_warn("Node CRC %08x != calculated CRC %08x for node at %08x\n", + je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); ++ jffs2_dbg_dump_node(c, ref_offset(fd->raw)); + ret = -EIO; + goto out_ri; + } +@@ -75,9 +75,8 @@ int jffs2_read_dnode(struct jffs2_sb_inf + goto out_ri; + }); + +- + if (ri->compr == JFFS2_COMPR_ZERO) { +- memset(buf, 0, len); ++ ret = LOS_UserMemClear(buf, len); + goto out_ri; + } + +@@ -88,7 +87,11 @@ int jffs2_read_dnode(struct jffs2_sb_inf + Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy + */ + if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { +- readbuf = buf; ++ readbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); ++ if (!readbuf) { ++ ret = -ENOMEM; ++ goto out_ri; ++ } + } else { + readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); + if (!readbuf) { +@@ -97,14 +100,10 @@ int jffs2_read_dnode(struct jffs2_sb_inf + } + } + if (ri->compr != JFFS2_COMPR_NONE) { +- if (len < je32_to_cpu(ri->dsize)) { +- decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); +- if (!decomprbuf) { +- ret = -ENOMEM; +- goto out_readbuf; +- } +- } else { +- decomprbuf = buf; ++ decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); ++ if (!decomprbuf) { ++ ret = -ENOMEM; ++ goto out_readbuf; + } + } else { + decomprbuf = readbuf; +@@ -113,7 +112,7 @@ int jffs2_read_dnode(struct jffs2_sb_inf + jffs2_dbg(2, "Read %d bytes to %p\n", je32_to_cpu(ri->csize), + readbuf); + ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), +- je32_to_cpu(ri->csize), &readlen, readbuf); ++ je32_to_cpu(ri->csize), &readlen, (char *)readbuf); + + if (!ret && readlen != je32_to_cpu(ri->csize)) + ret = -EIO; +@@ -124,6 +123,7 @@ int jffs2_read_dnode(struct jffs2_sb_inf + if (crc != je32_to_cpu(ri->data_crc)) { + pr_warn("Data CRC %08x != calculated CRC %08x for node at %08x\n", + je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); ++ jffs2_dbg_dump_node(c, ref_offset(fd->raw)); + ret = -EIO; + goto out_decomprbuf; + } +@@ -139,8 +139,8 @@ int jffs2_read_dnode(struct jffs2_sb_inf + } + } + +- if (len < je32_to_cpu(ri->dsize)) { +- memcpy(buf, decomprbuf+ofs, len); ++ if (LOS_CopyFromKernel(buf, len, decomprbuf + ofs, len) != 0) { ++ ret = -EFAULT; + } + out_decomprbuf: + if(decomprbuf != buf && decomprbuf != readbuf) +@@ -184,7 +184,10 @@ int jffs2_read_inode_range(struct jffs2_ + } + jffs2_dbg(1, "Filling non-frag hole from %d-%d\n", + offset, offset + holesize); +- memset(buf, 0, holesize); ++ ret = LOS_UserMemClear(buf, holesize); ++ if (ret != 0) { ++ return ret; ++ } + buf += holesize; + offset += holesize; + continue; +@@ -193,7 +196,10 @@ int jffs2_read_inode_range(struct jffs2_ + jffs2_dbg(1, "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", + offset, holeend, frag->ofs, + frag->ofs + frag->size); +- memset(buf, 0, holeend - offset); ++ ret = LOS_UserMemClear(buf, holeend - offset); ++ if (ret != 0) { ++ return ret; ++ } + buf += holeend - offset; + offset = holeend; + frag = frag_next(frag); +@@ -214,7 +220,7 @@ int jffs2_read_inode_range(struct jffs2_ + if (ret) { + jffs2_dbg(1, "%s(): error %d\n", + __func__, ret); +- memset(buf, 0, readlen); ++ (void)LOS_UserMemClear(buf, readlen); + return ret; + } + buf += readlen; +@@ -226,3 +232,15 @@ int jffs2_read_inode_range(struct jffs2_ + return 0; + } + ++int jffs2_flash_direct_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, ++ size_t *retlen, const char *buf) ++{ ++ int ret; ++ ret = c->mtd->read(c->mtd, ofs, len, (char *)buf); ++ if (ret >= 0) { ++ *retlen = ret; ++ return 0; ++ } ++ *retlen = 0; ++ return ret; ++} +\ No newline at end of file +diff -Nupr old/fs/jffs2/readinode.c new/fs/jffs2/readinode.c +--- old/fs/jffs2/readinode.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/readinode.c 2022-05-09 20:26:31.030000000 +0800 +@@ -9,17 +9,18 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include + #include + #include +-#include ++#include ++#include + #include +-#include + #include ++#include + #include "nodelist.h" ++#include "os-linux.h" ++#include "los_crc32.h" + + /* + * Check the data CRC of the node. +@@ -31,9 +32,9 @@ + static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) + { + struct jffs2_raw_node_ref *ref = tn->fn->raw; +- int err = 0, pointed = 0; ++ int err = 0; + struct jffs2_eraseblock *jeb; +- unsigned char *buffer; ++ unsigned char *buffer = NULL; + uint32_t crc, ofs, len; + size_t retlen; + +@@ -61,48 +62,28 @@ static int check_node_data(struct jffs2_ + dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", + ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); + +-#ifndef __ECOS +- /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), +- * adding and jffs2_flash_read_end() interface. */ +- err = mtd_point(c->mtd, ofs, len, &retlen, (void **)&buffer, NULL); +- if (!err && retlen < len) { +- JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); +- mtd_unpoint(c->mtd, ofs, retlen); +- } else if (err) { +- if (err != -EOPNOTSUPP) +- JFFS2_WARNING("MTD point failed: error code %d.\n", err); +- } else +- pointed = 1; /* succefully pointed to device */ +-#endif +- +- if (!pointed) { +- buffer = kmalloc(len, GFP_KERNEL); +- if (unlikely(!buffer)) +- return -ENOMEM; ++ buffer = kmalloc(len, GFP_KERNEL); ++ if (unlikely(!buffer)) ++ return -ENOMEM; + +- /* TODO: this is very frequent pattern, make it a separate +- * routine */ +- err = jffs2_flash_read(c, ofs, len, &retlen, buffer); +- if (err) { +- JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); +- goto free_out; +- } ++ /* TODO: this is very frequent pattern, make it a separate ++ * routine */ ++ err = jffs2_flash_read(c, ofs, len, &retlen, (char *)buffer); ++ if (err) { ++ JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); ++ goto free_out; ++ } + +- if (retlen != len) { +- JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); +- err = -EIO; +- goto free_out; +- } ++ if (retlen != len) { ++ JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); ++ err = -EIO; ++ goto free_out; + } + + /* Continue calculating CRC */ + crc = crc32(tn->partial_crc, buffer, len); +- if(!pointed) +- kfree(buffer); +-#ifndef __ECOS +- else +- mtd_unpoint(c->mtd, ofs, len); +-#endif ++ ++ kfree(buffer); + + if (crc != tn->data_crc) { + JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", +@@ -133,12 +114,7 @@ adj_acc: + return 0; + + free_out: +- if(!pointed) +- kfree(buffer); +-#ifndef __ECOS +- else +- mtd_unpoint(c->mtd, ofs, len); +-#endif ++ kfree(buffer); + return err; + } + +@@ -415,8 +391,12 @@ static void eat_last(struct rb_root *roo + link = &parent->rb_right; + + *link = node->rb_left; +- if (node->rb_left) +- node->rb_left->__rb_parent_color = node->__rb_parent_color; ++ if (node->rb_left) { ++ node->rb_left->rb_parent_color = node->rb_parent_color; ++ // set child parent only ++ rb_parent(node->rb_left) = parent; ++ node->rb_left = NULL; ++ } + } + + /* We put the version tree in reverse order, so we can use the same eat_last() +@@ -464,8 +444,8 @@ static int jffs2_build_inode_fragtree(st + #ifdef JFFS2_DBG_READINODE_MESSAGES + this = tn_last(&rii->tn_root); + while (this) { +- dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, +- this->fn->ofs+this->fn->size, this->overlapped); ++ dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d,left %p,right %p ,parent %p\n", this, this->version, this->fn->ofs, ++ this->fn->ofs+this->fn->size, this->overlapped,this->rb.rb_left,this->rb.rb_right,rb_parent(&(this->rb))); + this = tn_prev(this); + } + #endif +@@ -543,11 +523,13 @@ static int jffs2_build_inode_fragtree(st + + static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) + { +- struct jffs2_tmp_dnode_info *tn, *next; ++ struct jffs2_tmp_dnode_info *tn; ++ struct rb_node *rbn,*next; + +- rbtree_postorder_for_each_entry_safe(tn, next, list, rb) { +- jffs2_free_full_dnode(tn->fn); +- jffs2_free_tmp_dnode_info(tn); ++ RB_POSTORDER_FOREACH_SAFE(rbn, linux_root, (struct linux_root *)list, next) { ++ tn = (struct jffs2_tmp_dnode_info *)rbn; ++ jffs2_free_full_dnode(tn->fn); ++ jffs2_free_tmp_dnode_info(tn); + } + + *list = RB_ROOT; +@@ -659,7 +641,7 @@ static inline int read_direntry(struct j + int already = read - sizeof(*rd); + + err = jffs2_flash_read(c, (ref_offset(ref)) + read, +- rd->nsize - already, &read, &fd->name[already]); ++ rd->nsize - already, &read, (char *)&fd->name[already]); + if (unlikely(read != rd->nsize - already) && likely(!err)) { + jffs2_free_full_dirent(fd); + JFFS2_ERROR("short read: wanted %d bytes, got %zd\n", +@@ -690,7 +672,7 @@ static inline int read_direntry(struct j + #endif + } + +- fd->nhash = full_name_hash(NULL, fd->name, rd->nsize); ++ fd->nhash = full_name_hash(fd->name, rd->nsize); + fd->next = NULL; + fd->name[rd->nsize] = '\0'; + +@@ -956,7 +938,7 @@ static int read_more(struct jffs2_sb_inf + + dbg_readinode("read more %d bytes\n", to_read); + +- err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen); ++ err = jffs2_flash_read(c, offs, to_read, &retlen, (char *)(buf + *rdlen)); + if (err) { + JFFS2_ERROR("can not read %d bytes from 0x%08x, " + "error code: %d.\n", to_read, offs, err); +@@ -1042,7 +1024,7 @@ static int jffs2_get_inode_nodes(struct + dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); + + /* FIXME: point() */ +- err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf); ++ err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, (char *)buf); + if (err) { + JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ref_offset(ref), err); + goto free_out; +@@ -1079,6 +1061,7 @@ static int jffs2_get_inode_nodes(struct + + case JFFS2_NODETYPE_DIRENT: + ++ dbg_readinode("node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)); + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) && + len < sizeof(struct jffs2_raw_dirent)) { + err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf); +@@ -1094,6 +1077,7 @@ static int jffs2_get_inode_nodes(struct + + case JFFS2_NODETYPE_INODE: + ++ dbg_readinode("node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)); + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) && + len < sizeof(struct jffs2_raw_inode)) { + err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf); +@@ -1289,7 +1273,7 @@ static int jffs2_do_read_inode_internal( + dbg_readinode("symlink's target '%s' cached\n", f->target); + } + +- fallthrough; ++ /* fall through... */ + + case S_IFBLK: + case S_IFCHR: +@@ -1315,7 +1299,7 @@ static int jffs2_do_read_inode_internal( + /* OK. We're happy */ + f->metadata = frag_first(&f->fragtree)->node; + jffs2_free_node_frag(frag_first(&f->fragtree)); +- f->fragtree = RB_ROOT; ++ f->fragtree.rb_node = NULL; + break; + } + if (f->inocache->state == INO_STATE_READING) +@@ -1362,6 +1346,7 @@ int jffs2_do_read_inode(struct jffs2_sb_ + break; + + default: ++ JFFS2_ERROR("Unknow f->inocache->state %d!\n", f->inocache->state); + BUG(); + } + } +@@ -1375,14 +1360,13 @@ int jffs2_do_read_inode(struct jffs2_sb_ + return -ENOMEM; + } + dbg_readinode("creating inocache for root inode\n"); +- memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); + f->inocache->ino = f->inocache->pino_nlink = 1; + f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; + f->inocache->state = INO_STATE_READING; + jffs2_add_ino_cache(c, f->inocache); + } + if (!f->inocache) { +- JFFS2_ERROR("requested to read a nonexistent ino %u\n", ino); ++ JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino); + return -ENOENT; + } + +@@ -1430,6 +1414,11 @@ void jffs2_do_clear_inode(struct jffs2_s + + jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); + ++ if (f->target) { ++ kfree(f->target); ++ f->target = NULL; ++ } ++ + fds = f->dents; + while(fds) { + fd = fds; +diff -Nupr old/fs/jffs2/scan.c new/fs/jffs2/scan.c +--- old/fs/jffs2/scan.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/scan.c 2022-05-09 20:23:02.230000000 +0800 +@@ -9,18 +9,17 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- + #include + #include + #include +-#include + #include +-#include + #include + #include "nodelist.h" + #include "summary.h" + #include "debug.h" ++#include "mtd_dev.h" ++#include "los_typedef.h" ++#include "los_crc32.h" + + #define DEFAULT_EMPTY_SCAN_SIZE 256 + +@@ -74,7 +73,7 @@ static int file_dirty(struct jffs2_sb_in + return ret; + if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size))) + return ret; +- /* Turned wasted size into dirty, since we apparently ++ /* Turned wasted size into dirty, since we apparently + think it's recoverable now. */ + jeb->dirty_size += jeb->wasted_size; + c->dirty_size += jeb->wasted_size; +@@ -95,40 +94,26 @@ int jffs2_scan_medium(struct jffs2_sb_in + unsigned char *flashbuf = NULL; + uint32_t buf_size = 0; + struct jffs2_summary *s = NULL; /* summary info collected by the scan process */ +-#ifndef __ECOS +- size_t pointlen, try_size; ++ struct super_block *sb = NULL; ++ struct MtdNorDev *device = NULL; + +- ret = mtd_point(c->mtd, 0, c->mtd->size, &pointlen, +- (void **)&flashbuf, NULL); +- if (!ret && pointlen < c->mtd->size) { +- /* Don't muck about if it won't let us point to the whole flash */ +- jffs2_dbg(1, "MTD point returned len too short: 0x%zx\n", +- pointlen); +- mtd_unpoint(c->mtd, 0, pointlen); +- flashbuf = NULL; +- } +- if (ret && ret != -EOPNOTSUPP) +- jffs2_dbg(1, "MTD point failed %d\n", ret); +-#endif + if (!flashbuf) { + /* For NAND it's quicker to read a whole eraseblock at a time, + apparently */ + if (jffs2_cleanmarker_oob(c)) +- try_size = c->sector_size; ++ buf_size = c->sector_size; + else +- try_size = PAGE_SIZE; ++ buf_size = PAGE_SIZE; + + jffs2_dbg(1, "Trying to allocate readbuf of %zu " +- "bytes\n", try_size); ++ "bytes\n", buf_size); + +- flashbuf = mtd_kmalloc_up_to(c->mtd, &try_size); ++ flashbuf = kmalloc(buf_size, GFP_KERNEL); + if (!flashbuf) + return -ENOMEM; + + jffs2_dbg(1, "Allocated readbuf of %zu bytes\n", +- try_size); +- +- buf_size = (uint32_t)try_size; ++ buf_size); + } + + if (jffs2_sum_active()) { +@@ -140,7 +125,9 @@ int jffs2_scan_medium(struct jffs2_sb_in + } + } + +- for (i=0; inr_blocks; i++) { ++ sb = OFNI_BS_2SFFJ(c); ++ device = (struct MtdNorDev*)(sb->s_dev); ++ for (i=device->blockStart; inr_blocks + device->blockStart; i++) { + struct jffs2_eraseblock *jeb = &c->blocks[i]; + + cond_resched(); +@@ -269,19 +256,12 @@ int jffs2_scan_medium(struct jffs2_sb_in + ret = -EIO; + goto out; + } +- spin_lock(&c->erase_completion_lock); +- jffs2_garbage_collect_trigger(c); +- spin_unlock(&c->erase_completion_lock); + } + ret = 0; + out: +- if (buf_size) +- kfree(flashbuf); +-#ifndef __ECOS +- else +- mtd_unpoint(c->mtd, 0, c->mtd->size); +-#endif +- kfree(s); ++ ++ kfree(flashbuf); ++ + return ret; + } + +@@ -411,7 +391,7 @@ static int jffs2_scan_xref_node(struct j + if (!ref) + return -ENOMEM; + +- /* BEFORE jffs2_build_xattr_subsystem() called, ++ /* BEFORE jffs2_build_xattr_subsystem() called, + * and AFTER xattr_ref is marked as a dead xref, + * ref->xid is used to store 32bit xid, xd is not used + * ref->ino is used to store 32bit inode-number, ic is not used +@@ -484,10 +464,10 @@ static int jffs2_scan_eraseblock (struct + struct jffs2_sum_marker *sm; + void *sumptr = NULL; + uint32_t sumlen; +- ++ + if (!buf_size) { + /* XIP case. Just look, point at the summary if it's there */ +- sm = (void *)buf + c->sector_size - sizeof(*sm); ++ sm = (struct jffs2_sum_marker *)((uint8_t *)buf + c->sector_size - sizeof(*sm)); + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { + sumptr = buf + je32_to_cpu(sm->offset); + sumlen = c->sector_size - je32_to_cpu(sm->offset); +@@ -500,13 +480,13 @@ static int jffs2_scan_eraseblock (struct + buf_len = sizeof(*sm); + + /* Read as much as we want into the _end_ of the preallocated buffer */ +- err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, ++ err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, + jeb->offset + c->sector_size - buf_len, +- buf_len); ++ buf_len); + if (err) + return err; + +- sm = (void *)buf + buf_size - sizeof(*sm); ++ sm = (struct jffs2_sum_marker *)((uint8_t *)buf + buf_size - sizeof(*sm)); + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { + sumlen = c->sector_size - je32_to_cpu(sm->offset); + sumptr = buf + buf_size - sumlen; +@@ -521,18 +501,15 @@ static int jffs2_scan_eraseblock (struct + sumptr = kmalloc(sumlen, GFP_KERNEL); + if (!sumptr) + return -ENOMEM; +- memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len); ++ memcpy((uint8_t *)sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len); + } + if (buf_len < sumlen) { + /* Need to read more so that the entire summary node is present */ +- err = jffs2_fill_scan_buf(c, sumptr, ++ err = jffs2_fill_scan_buf(c, sumptr, + jeb->offset + c->sector_size - sumlen, +- sumlen - buf_len); +- if (err) { +- if (sumlen > buf_size) +- kfree(sumptr); ++ sumlen - buf_len); ++ if (err) + return err; +- } + } + } + +@@ -543,7 +520,7 @@ static int jffs2_scan_eraseblock (struct + + if (buf_size && sumlen > buf_size) + kfree(sumptr); +- /* If it returns with a real error, bail. ++ /* If it returns with a real error, bail. + If it returns positive, that's a block classification + (i.e. BLK_STATE_xxx) so return that too. + If it returns zero, fall through to full scan. */ +@@ -605,7 +582,7 @@ full_scan: + /* Now ofs is a complete physical flash offset as it always was... */ + ofs += jeb->offset; + +- noise = 10; ++ noise = 1; + + dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset); + +@@ -698,7 +675,7 @@ scan_more: + scan_end = buf_len; + goto more_empty; + } +- ++ + /* See how much more there is to read in this eraseblock... */ + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + if (!buf_len) { +@@ -948,7 +925,7 @@ scan_more: + jffs2_dbg(1, "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n", + jeb->offset, jeb->free_size, jeb->dirty_size, + jeb->unchecked_size, jeb->used_size, jeb->wasted_size); +- ++ + /* mark_node_obsolete can add to wasted !! */ + if (jeb->wasted_size) { + jeb->dirty_size += jeb->wasted_size; +@@ -976,7 +953,6 @@ struct jffs2_inode_cache *jffs2_scan_mak + pr_notice("%s(): allocation of inode cache failed\n", __func__); + return NULL; + } +- memset(ic, 0, sizeof(*ic)); + + ic->ino = ino; + ic->nodes = (void *)ic; +@@ -1067,7 +1043,7 @@ static int jffs2_scan_dirent_node(struct + pseudo_random += je32_to_cpu(rd->version); + + /* Should never happen. Did. (OLPC trac #4184)*/ +- checkedlen = strnlen(rd->name, rd->nsize); ++ checkedlen = strnlen((const char *)rd->name, rd->nsize); + if (checkedlen < rd->nsize) { + pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n", + ofs, checkedlen); +@@ -1079,7 +1055,7 @@ static int jffs2_scan_dirent_node(struct + memcpy(&fd->name, rd->name, checkedlen); + fd->name[checkedlen] = 0; + +- crc = crc32(0, fd->name, checkedlen); ++ crc = crc32(0, fd->name, rd->nsize); + if (crc != je32_to_cpu(rd->name_crc)) { + pr_notice("%s(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + __func__, ofs, je32_to_cpu(rd->name_crc), crc); +@@ -1104,7 +1080,7 @@ static int jffs2_scan_dirent_node(struct + fd->next = NULL; + fd->version = je32_to_cpu(rd->version); + fd->ino = je32_to_cpu(rd->ino); +- fd->nhash = full_name_hash(NULL, fd->name, checkedlen); ++ fd->nhash = full_name_hash(fd->name, checkedlen); + fd->type = rd->type; + jffs2_add_fd_to_list(c, fd, &ic->scan_dents); + +diff -Nupr old/fs/jffs2/security.c new/fs/jffs2/security.c +--- old/fs/jffs2/security.c 2022-05-09 17:15:24.350000000 +0800 ++++ new/fs/jffs2/security.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,72 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2006 NEC Corporation +- * +- * Created by KaiGai Kohei +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "nodelist.h" +- +-/* ---- Initial Security Label(s) Attachment callback --- */ +-static int jffs2_initxattrs(struct inode *inode, +- const struct xattr *xattr_array, void *fs_info) +-{ +- const struct xattr *xattr; +- int err = 0; +- +- for (xattr = xattr_array; xattr->name != NULL; xattr++) { +- err = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, +- xattr->name, xattr->value, +- xattr->value_len, 0); +- if (err < 0) +- break; +- } +- return err; +-} +- +-/* ---- Initial Security Label(s) Attachment ----------- */ +-int jffs2_init_security(struct inode *inode, struct inode *dir, +- const struct qstr *qstr) +-{ +- return security_inode_init_security(inode, dir, qstr, +- &jffs2_initxattrs, NULL); +-} +- +-/* ---- XATTR Handler for "security.*" ----------------- */ +-static int jffs2_security_getxattr(const struct xattr_handler *handler, +- struct dentry *unused, struct inode *inode, +- const char *name, void *buffer, size_t size) +-{ +- return do_jffs2_getxattr(inode, JFFS2_XPREFIX_SECURITY, +- name, buffer, size); +-} +- +-static int jffs2_security_setxattr(const struct xattr_handler *handler, +- struct dentry *unused, struct inode *inode, +- const char *name, const void *buffer, +- size_t size, int flags) +-{ +- return do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, +- name, buffer, size, flags); +-} +- +-const struct xattr_handler jffs2_security_xattr_handler = { +- .prefix = XATTR_SECURITY_PREFIX, +- .set = jffs2_security_setxattr, +- .get = jffs2_security_getxattr +-}; +diff -Nupr old/fs/jffs2/summary.c new/fs/jffs2/summary.c +--- old/fs/jffs2/summary.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/summary.c 2022-05-09 20:13:24.440000000 +0800 +@@ -10,16 +10,20 @@ + * For licensing information, see the file 'LICENCE' in this directory. + * + */ ++#include "summary.h" + ++#ifdef CONFIG_JFFS2_SUMMARY ++ ++#ifndef pr_fmt + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++#endif + + #include + #include +-#include ++#include + #include +-#include ++#include "los_crc32.h" + #include +-#include + #include "nodelist.h" + #include "debug.h" + +@@ -388,11 +392,25 @@ static int jffs2_sum_process_sum_data(st + { + struct jffs2_inode_cache *ic; + struct jffs2_full_dirent *fd; +- void *sp; ++ uintptr_t sp; + int i, ino; + int err; + +- sp = summary->sum; ++ sp = (uintptr_t)summary->sum; ++ ++#if 0 ++ PRINTK("summary: %x %x %d %d %x %x %d %x %x %p %p\n", ++ je16_to_cpu(summary->magic), ++ je16_to_cpu(summary->nodetype), ++ je32_to_cpu(summary->totlen), ++ je32_to_cpu(summary->hdr_crc), ++ je32_to_cpu(summary->sum_num), ++ je32_to_cpu(summary->cln_mkr), ++ je32_to_cpu(summary->padded), ++ je32_to_cpu(summary->sum_crc), ++ je32_to_cpu(summary->node_crc), ++ sp, summary->sum); ++#endif + + for (i=0; isum_num); i++) { + dbg_summary("processing summary index %d\n", i); +@@ -404,10 +422,12 @@ static int jffs2_sum_process_sum_data(st + if (err) + return err; + ++ //PRINTK("sum type %d \n", je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)); ++ + switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { + case JFFS2_NODETYPE_INODE: { + struct jffs2_sum_inode_flash *spi; +- spi = sp; ++ spi = (struct jffs2_sum_inode_flash *)sp; + + ino = je32_to_cpu(spi->inode); + +@@ -428,13 +448,29 @@ static int jffs2_sum_process_sum_data(st + + sp += JFFS2_SUMMARY_INODE_SIZE; + ++ //PRINTK("1 sp + %d %p\n", JFFS2_SUMMARY_INODE_SIZE, sp); ++ + break; + } + + case JFFS2_NODETYPE_DIRENT: { + struct jffs2_sum_dirent_flash *spd; + int checkedlen; +- spd = sp; ++ spd = (struct jffs2_sum_dirent_flash *)sp; ++ ++ ++#if 0 ++ PRINTK("dir: %x %d %d %d %d %d %d %d %d\n", ++ je16_to_cpu(spd->nodetype), ++ je32_to_cpu(spd->totlen), ++ je32_to_cpu(spd->offset), ++ je32_to_cpu(spd->pino), ++ je32_to_cpu(spd->version), ++ je32_to_cpu(spd->ino), ++ spd->nsize, ++ spd->type, ++ spd->name); ++#endif + + dbg_summary("Dirent at 0x%08x-0x%08x\n", + jeb->offset + je32_to_cpu(spd->offset), +@@ -442,7 +478,7 @@ static int jffs2_sum_process_sum_data(st + + + /* This should never happen, but https://dev.laptop.org/ticket/4184 */ +- checkedlen = strnlen(spd->name, spd->nsize); ++ checkedlen = strnlen((const char *)spd->name, spd->nsize); + if (!checkedlen) { + pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n", + jeb->offset + +@@ -463,6 +499,7 @@ static int jffs2_sum_process_sum_data(st + + memcpy(&fd->name, spd->name, checkedlen); + fd->name[checkedlen] = 0; ++ //PRINTK("add %s \n", fd->name); + + ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); + if (!ic) { +@@ -476,15 +513,19 @@ static int jffs2_sum_process_sum_data(st + fd->next = NULL; + fd->version = je32_to_cpu(spd->version); + fd->ino = je32_to_cpu(spd->ino); +- fd->nhash = full_name_hash(NULL, fd->name, checkedlen); ++ fd->nhash = full_name_hash((const unsigned char *)fd->name, checkedlen); + fd->type = spd->type; + + jffs2_add_fd_to_list(c, fd, &ic->scan_dents); + + *pseudo_random += je32_to_cpu(spd->version); + ++ //PRINTK("2 sp before add %p\n", sp); ++ + sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); + ++ //PRINTK("2 sp + %d %p\n", JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize), sp); ++ + break; + } + #ifdef CONFIG_JFFS2_FS_XATTR +@@ -493,7 +534,7 @@ static int jffs2_sum_process_sum_data(st + struct jffs2_sum_xattr_flash *spx; + + spx = (struct jffs2_sum_xattr_flash *)sp; +- dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", ++ dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", + jeb->offset + je32_to_cpu(spx->offset), + jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), + je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); +@@ -526,7 +567,7 @@ static int jffs2_sum_process_sum_data(st + spr = (struct jffs2_sum_xref_flash *)sp; + dbg_summary("xref at %#08x-%#08x\n", + jeb->offset + je32_to_cpu(spr->offset), +- jeb->offset + je32_to_cpu(spr->offset) + ++ jeb->offset + je32_to_cpu(spr->offset) + + (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); + + ref = jffs2_alloc_xattr_ref(); +@@ -679,7 +720,7 @@ static int jffs2_sum_write_data(struct j + struct jffs2_sum_marker *sm; + struct kvec vecs[2]; + uint32_t sum_ofs; +- void *wpage; ++ uintptr_t wpage; + int ret; + size_t retlen; + +@@ -713,14 +754,14 @@ static int jffs2_sum_write_data(struct j + isum.padded = cpu_to_je32(c->summary->sum_padded); + isum.cln_mkr = cpu_to_je32(c->cleanmarker_size); + isum.sum_num = cpu_to_je32(c->summary->sum_num); +- wpage = c->summary->sum_buf; ++ wpage = (uintptr_t)c->summary->sum_buf; + + while (c->summary->sum_num) { + temp = c->summary->sum_list_head; + + switch (je16_to_cpu(temp->u.nodetype)) { + case JFFS2_NODETYPE_INODE: { +- struct jffs2_sum_inode_flash *sino_ptr = wpage; ++ struct jffs2_sum_inode_flash *sino_ptr = (struct jffs2_sum_inode_flash *)wpage; + + sino_ptr->nodetype = temp->i.nodetype; + sino_ptr->inode = temp->i.inode; +@@ -734,7 +775,7 @@ static int jffs2_sum_write_data(struct j + } + + case JFFS2_NODETYPE_DIRENT: { +- struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; ++ struct jffs2_sum_dirent_flash *sdrnt_ptr = (struct jffs2_sum_dirent_flash *)wpage; + + sdrnt_ptr->nodetype = temp->d.nodetype; + sdrnt_ptr->totlen = temp->d.totlen; +@@ -802,7 +843,7 @@ static int jffs2_sum_write_data(struct j + + wpage += padsize; + +- sm = wpage; ++ sm = (struct jffs2_sum_marker *)wpage; + sm->offset = cpu_to_je32(c->sector_size - jeb->free_size); + sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC); + +@@ -847,7 +888,7 @@ static int jffs2_sum_write_data(struct j + /* Write out summary information - called from jffs2_do_reserve_space */ + + int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) +- __must_hold(&c->erase_completion_block) ++ //__must_hold(&c->erase_completion_block) + { + int datasize, infosize, padsize; + struct jffs2_eraseblock *jeb; +@@ -875,3 +916,5 @@ int jffs2_sum_write_sumnode(struct jffs2 + spin_lock(&c->erase_completion_lock); + return ret; + } ++ ++#endif +diff -Nupr old/fs/jffs2/summary.h new/fs/jffs2/summary.h +--- old/fs/jffs2/summary.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/summary.h 2022-05-09 20:35:43.430000000 +0800 +@@ -19,8 +19,9 @@ + anyway. */ + #define MAX_SUMMARY_SIZE 65536 + +-#include +-#include ++#include ++#include ++#include "jffs2.h" + + #define BLK_STATE_ALLFF 0 + #define BLK_STATE_CLEAN 1 +@@ -169,6 +170,10 @@ struct jffs2_sum_marker + + #define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) + ++#ifdef LOSCFG_FS_JFFS2_SUMMARY ++#define CONFIG_JFFS2_SUMMARY ++#endif ++ + #ifdef CONFIG_JFFS2_SUMMARY /* SUMMARY SUPPORT ENABLED */ + + #define jffs2_sum_active() (1) +diff -Nupr old/fs/jffs2/super.c new/fs/jffs2/super.c +--- old/fs/jffs2/super.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/super.c 2022-05-09 20:09:32.170000000 +0800 +@@ -9,433 +9,188 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "compr.h" ++#include "jffs2.h" + #include "nodelist.h" ++#include "jffs2_fs_sb.h" ++#include "mtd_dev.h" ++#include "mtd_partition.h" ++#include "compr.h" ++#include "jffs2_hash.h" + +-static void jffs2_put_super(struct super_block *); +- +-static struct kmem_cache *jffs2_inode_cachep; ++static unsigned char jffs2_mounted_number = 0; /* a counter to track the number of jffs2 instances mounted */ ++struct MtdNorDev jffs2_dev_list[CONFIG_MTD_PATTITION_NUM]; + +-static struct inode *jffs2_alloc_inode(struct super_block *sb) ++/* ++ * fill in the superblock ++ */ ++int jffs2_fill_super(struct super_block *sb) + { +- struct jffs2_inode_info *f; +- +- f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); +- if (!f) +- return NULL; +- return &f->vfs_inode; +-} ++ int ret; ++ struct jffs2_sb_info *c; ++ struct MtdNorDev *device; + +-static void jffs2_free_inode(struct inode *inode) +-{ +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); ++ c = JFFS2_SB_INFO(sb); ++ device = (struct MtdNorDev*)(sb->s_dev); + +- kfree(f->target); +- kmem_cache_free(jffs2_inode_cachep, f); +-} ++ (void)mutex_init(&c->alloc_sem); ++ (void)mutex_init(&c->erase_free_sem); ++ spin_lock_init(&c->erase_completion_lock); ++ spin_lock_init(&c->inocache_lock); + +-static void jffs2_i_init_once(void *foo) +-{ +- struct jffs2_inode_info *f = foo; ++ /* sector size is the erase block size */ ++ c->sector_size = device->blockSize; ++ c->flash_size = (device->blockEnd - device->blockStart + 1) * device->blockSize; ++ c->cleanmarker_size = sizeof(struct jffs2_unknown_node); + +- mutex_init(&f->sem); +- inode_init_once(&f->vfs_inode); +-} ++ ret = jffs2_do_mount_fs(c); ++ if (ret) { ++ (void)mutex_destroy(&c->alloc_sem); ++ (void)mutex_destroy(&c->erase_free_sem); ++ return ret; ++ } ++ D1(printk(KERN_DEBUG "jffs2_fill_super(): Getting root inode\n")); ++ ++ sb->s_root = jffs2_iget(sb, 1); ++ ++ if (IS_ERR(sb->s_root)) { ++ D1(printk(KERN_WARNING "get root inode failed\n")); ++ ret = PTR_ERR(sb->s_root); ++ sb->s_root = NULL; ++ jffs2_free_ino_caches(c); ++ jffs2_free_raw_node_refs(c); ++ free(c->blocks); ++ (void)mutex_destroy(&c->alloc_sem); ++ (void)mutex_destroy(&c->erase_free_sem); + +-static const char *jffs2_compr_name(unsigned int compr) +-{ +- switch (compr) { +- case JFFS2_COMPR_MODE_NONE: +- return "none"; +-#ifdef CONFIG_JFFS2_LZO +- case JFFS2_COMPR_MODE_FORCELZO: +- return "lzo"; +-#endif +-#ifdef CONFIG_JFFS2_ZLIB +- case JFFS2_COMPR_MODE_FORCEZLIB: +- return "zlib"; +-#endif +- default: +- /* should never happen; programmer error */ +- WARN_ON(1); +- return ""; ++ return ret; + } +-} +- +-static int jffs2_show_options(struct seq_file *s, struct dentry *root) +-{ +- struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb); +- struct jffs2_mount_opts *opts = &c->mount_opts; +- +- if (opts->override_compr) +- seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); +- if (opts->set_rp_size) +- seq_printf(s, ",rp_size=%u", opts->rp_size / 1024); +- +- return 0; +-} +- +-static int jffs2_sync_fs(struct super_block *sb, int wait) +-{ +- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); +- +-#ifdef CONFIG_JFFS2_FS_WRITEBUFFER +- if (jffs2_is_writebuffered(c)) +- cancel_delayed_work_sync(&c->wbuf_dwork); +-#endif +- +- mutex_lock(&c->alloc_sem); +- jffs2_flush_wbuf_pad(c); +- mutex_unlock(&c->alloc_sem); + return 0; + } + +-static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, +- uint32_t generation) ++int jffs2_mount(int part_no, struct jffs2_inode **root_node, unsigned long mountflags) + { +- /* We don't care about i_generation. We'll destroy the flash +- before we start re-using inode numbers anyway. And even +- if that wasn't true, we'd have other problems...*/ +- return jffs2_iget(sb, ino); +-} +- +-static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, +- int fh_len, int fh_type) +-{ +- return generic_fh_to_dentry(sb, fid, fh_len, fh_type, +- jffs2_nfs_get_inode); +-} +- +-static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid, +- int fh_len, int fh_type) +-{ +- return generic_fh_to_parent(sb, fid, fh_len, fh_type, +- jffs2_nfs_get_inode); +-} +- +-static struct dentry *jffs2_get_parent(struct dentry *child) +-{ +- struct jffs2_inode_info *f; +- uint32_t pino; +- +- BUG_ON(!d_is_dir(child)); +- +- f = JFFS2_INODE_INFO(d_inode(child)); +- +- pino = f->inocache->pino_nlink; +- +- JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", +- f->inocache->ino, pino); +- +- return d_obtain_alias(jffs2_iget(child->d_sb, pino)); +-} +- +-static const struct export_operations jffs2_export_ops = { +- .get_parent = jffs2_get_parent, +- .fh_to_dentry = jffs2_fh_to_dentry, +- .fh_to_parent = jffs2_fh_to_parent, +-}; +- +-/* +- * JFFS2 mount options. +- * +- * Opt_source: The source device +- * Opt_override_compr: override default compressor +- * Opt_rp_size: size of reserved pool in KiB +- */ +-enum { +- Opt_override_compr, +- Opt_rp_size, +-}; +- +-static const struct constant_table jffs2_param_compr[] = { +- {"none", JFFS2_COMPR_MODE_NONE }, +-#ifdef CONFIG_JFFS2_LZO +- {"lzo", JFFS2_COMPR_MODE_FORCELZO }, +-#endif +-#ifdef CONFIG_JFFS2_ZLIB +- {"zlib", JFFS2_COMPR_MODE_FORCEZLIB }, +-#endif +- {} +-}; ++ struct super_block *sb = NULL; ++ struct jffs2_sb_info *c = NULL; ++ LOS_DL_LIST *part_head = NULL; ++ struct MtdDev *spinor_mtd = NULL; ++ mtd_partition *mtd_part = GetSpinorPartitionHead(); ++ int ret; + +-static const struct fs_parameter_spec jffs2_fs_parameters[] = { +- fsparam_enum ("compr", Opt_override_compr, jffs2_param_compr), +- fsparam_u32 ("rp_size", Opt_rp_size), +- {} +-}; ++ jffs2_dbg(1, "begin los_jffs2_mount:%d\n", part_no); + +-static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param) +-{ +- struct fs_parse_result result; +- struct jffs2_sb_info *c = fc->s_fs_info; +- int opt; +- +- opt = fs_parse(fc, jffs2_fs_parameters, param, &result); +- if (opt < 0) +- return opt; +- +- switch (opt) { +- case Opt_override_compr: +- c->mount_opts.compr = result.uint_32; +- c->mount_opts.override_compr = true; +- break; +- case Opt_rp_size: +- if (result.uint_32 > UINT_MAX / 1024) +- return invalf(fc, "jffs2: rp_size unrepresentable"); +- c->mount_opts.rp_size = result.uint_32 * 1024; +- c->mount_opts.set_rp_size = true; +- break; +- default: +- return -EINVAL; ++ sb = zalloc(sizeof(struct super_block)); ++ if (sb == NULL) { ++ return -ENOMEM; + } + +- return 0; +-} +- +-static inline void jffs2_update_mount_opts(struct fs_context *fc) +-{ +- struct jffs2_sb_info *new_c = fc->s_fs_info; +- struct jffs2_sb_info *c = JFFS2_SB_INFO(fc->root->d_sb); +- +- mutex_lock(&c->alloc_sem); +- if (new_c->mount_opts.override_compr) { +- c->mount_opts.override_compr = new_c->mount_opts.override_compr; +- c->mount_opts.compr = new_c->mount_opts.compr; +- } +- if (new_c->mount_opts.set_rp_size) { +- c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size; +- c->mount_opts.rp_size = new_c->mount_opts.rp_size; ++ ret = Jffs2HashInit(&sb->s_node_hash_lock, &sb->s_node_hash[0]); ++ if (ret) { ++ free(sb); ++ return ret; ++ } ++ part_head = &(GetSpinorPartitionHead()->node_info); ++ LOS_DL_LIST_FOR_EACH_ENTRY(mtd_part,part_head, mtd_partition, node_info) { ++ if (mtd_part->patitionnum == part_no) ++ break; ++ } ++#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 ++ spinor_mtd = GetMtd("spinor"); ++#else ++ spinor_mtd = (struct MtdDev *)LOS_DL_LIST_ENTRY(part_head->pstNext, mtd_partition, node_info)->mtd_info; ++#endif ++ if (spinor_mtd == NULL) { ++ free(sb); ++ return -EPERM; ++ } ++ jffs2_dev_list[part_no].blockEnd = mtd_part->end_block; ++ jffs2_dev_list[part_no].blockSize = spinor_mtd->eraseSize; ++ jffs2_dev_list[part_no].blockStart = mtd_part->start_block; ++#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 ++ (void)FreeMtd(spinor_mtd); ++#endif ++ sb->jffs2_sb.mtd = mtd_part->mtd_info; ++ sb->s_dev = &jffs2_dev_list[part_no]; ++ ++ c = JFFS2_SB_INFO(sb); ++ c->flash_size = (mtd_part->end_block - mtd_part->start_block + 1) * spinor_mtd->eraseSize; ++ c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); ++ c->sector_size = spinor_mtd->eraseSize; ++ ++ jffs2_dbg(1, "C mtd_size:%d,mtd-erase:%d,blocks:%d,hashsize:%d\n", ++ c->flash_size, c->sector_size, c->flash_size / c->sector_size, c->inocache_hashsize); ++ ++ c->inocache_list = zalloc(sizeof(struct jffs2_inode_cache *) * c->inocache_hashsize); ++ if (c->inocache_list == NULL) { ++ free(sb); ++ return -ENOMEM; ++ } ++ if (jffs2_mounted_number++ == 0) { ++ (void)jffs2_create_slab_caches(); // No error check, cannot fail ++ (void)jffs2_compressors_init(); + } +- mutex_unlock(&c->alloc_sem); +-} +- +-static int jffs2_reconfigure(struct fs_context *fc) +-{ +- struct super_block *sb = fc->root->d_sb; +- +- sync_filesystem(sb); +- jffs2_update_mount_opts(fc); +- +- return jffs2_do_remount_fs(sb, fc); +-} +- +-static const struct super_operations jffs2_super_operations = +-{ +- .alloc_inode = jffs2_alloc_inode, +- .free_inode = jffs2_free_inode, +- .put_super = jffs2_put_super, +- .statfs = jffs2_statfs, +- .evict_inode = jffs2_evict_inode, +- .dirty_inode = jffs2_dirty_inode, +- .show_options = jffs2_show_options, +- .sync_fs = jffs2_sync_fs, +-}; +- +-/* +- * fill in the superblock +- */ +-static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc) +-{ +- struct jffs2_sb_info *c = sb->s_fs_info; +- +- jffs2_dbg(1, "jffs2_get_sb_mtd():" +- " New superblock for device %d (\"%s\")\n", +- sb->s_mtd->index, sb->s_mtd->name); +- +- c->mtd = sb->s_mtd; +- c->os_priv = sb; +- +- if (c->mount_opts.rp_size > c->mtd->size) +- return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB", +- c->mtd->size / 1024); +- +- /* Initialize JFFS2 superblock locks, the further initialization will +- * be done later */ +- mutex_init(&c->alloc_sem); +- mutex_init(&c->erase_free_sem); +- init_waitqueue_head(&c->erase_wait); +- init_waitqueue_head(&c->inocache_wq); +- spin_lock_init(&c->erase_completion_lock); +- spin_lock_init(&c->inocache_lock); +- +- sb->s_op = &jffs2_super_operations; +- sb->s_export_op = &jffs2_export_ops; +- sb->s_flags = sb->s_flags | SB_NOATIME; +- sb->s_xattr = jffs2_xattr_handlers; +-#ifdef CONFIG_JFFS2_FS_POSIX_ACL +- sb->s_flags |= SB_POSIXACL; +-#endif +- return jffs2_do_fill_super(sb, fc); +-} +- +-static int jffs2_get_tree(struct fs_context *fc) +-{ +- return get_tree_mtd(fc, jffs2_fill_super); +-} +- +-static void jffs2_free_fc(struct fs_context *fc) +-{ +- kfree(fc->s_fs_info); +-} + +-static const struct fs_context_operations jffs2_context_ops = { +- .free = jffs2_free_fc, +- .parse_param = jffs2_parse_param, +- .get_tree = jffs2_get_tree, +- .reconfigure = jffs2_reconfigure, +-}; ++ ret = jffs2_fill_super(sb); ++ if (ret) { ++ if (--jffs2_mounted_number == 0) { ++ jffs2_destroy_slab_caches(); ++ (void)jffs2_compressors_exit(); ++ } + +-static int jffs2_init_fs_context(struct fs_context *fc) +-{ +- struct jffs2_sb_info *ctx; ++ free(sb); ++ free(c->inocache_list); ++ c->inocache_list = NULL; ++ return ret; ++ } + +- ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL); +- if (!ctx) +- return -ENOMEM; ++ if (!(mountflags & MS_RDONLY)) { ++ jffs2_start_garbage_collect_thread(c); ++ } + +- fc->s_fs_info = ctx; +- fc->ops = &jffs2_context_ops; ++ sb->s_mount_flags = mountflags; ++ *root_node = sb->s_root; + return 0; + } + +-static void jffs2_put_super (struct super_block *sb) ++int jffs2_umount(struct jffs2_inode *root_node) + { ++ struct super_block *sb = root_node->i_sb; + struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); ++ struct jffs2_full_dirent *fd, *next; + +- jffs2_dbg(2, "%s()\n", __func__); ++ D2(PRINTK("Jffs2Umount\n")); + +- mutex_lock(&c->alloc_sem); +- jffs2_flush_wbuf_pad(c); +- mutex_unlock(&c->alloc_sem); +- +- jffs2_sum_exit(c); +- +- jffs2_free_ino_caches(c); +- jffs2_free_raw_node_refs(c); +- kvfree(c->blocks); +- jffs2_flash_cleanup(c); +- kfree(c->inocache_list); +- jffs2_clear_xattr_subsystem(c); +- mtd_sync(c->mtd); +- jffs2_dbg(1, "%s(): returning\n", __func__); +-} +- +-static void jffs2_kill_sb(struct super_block *sb) +-{ +- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); +- if (c && !sb_rdonly(sb)) ++ // Only really umount if this is the only mount ++ if (!(sb->s_mount_flags & MS_RDONLY)) { + jffs2_stop_garbage_collect_thread(c); +- kill_mtd_super(sb); +- kfree(c); +-} +- +-static struct file_system_type jffs2_fs_type = { +- .owner = THIS_MODULE, +- .name = "jffs2", +- .init_fs_context = jffs2_init_fs_context, +- .parameters = jffs2_fs_parameters, +- .kill_sb = jffs2_kill_sb, +-}; +-MODULE_ALIAS_FS("jffs2"); ++ } + +-static int __init init_jffs2_fs(void) +-{ +- int ret; ++ // free directory entries ++ for (fd = root_node->jffs2_i.dents; fd; fd = next) { ++ next = fd->next; ++ jffs2_free_full_dirent(fd); ++ } + +- /* Paranoia checks for on-medium structures. If we ask GCC +- to pack them with __attribute__((packed)) then it _also_ +- assumes that they're not aligned -- so it emits crappy +- code on some architectures. Ideally we want an attribute +- which means just 'no padding', without the alignment +- thing. But GCC doesn't have that -- we have to just +- hope the structs are the right sizes, instead. */ +- BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); +- BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); +- BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); +- BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); +- +- pr_info("version 2.2." +-#ifdef CONFIG_JFFS2_FS_WRITEBUFFER +- " (NAND)" +-#endif +-#ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " +-#endif +- " © 2001-2006 Red Hat, Inc.\n"); ++ free(root_node); + +- jffs2_inode_cachep = kmem_cache_create("jffs2_i", +- sizeof(struct jffs2_inode_info), +- 0, (SLAB_RECLAIM_ACCOUNT| +- SLAB_MEM_SPREAD|SLAB_ACCOUNT), +- jffs2_i_init_once); +- if (!jffs2_inode_cachep) { +- pr_err("error: Failed to initialise inode cache\n"); +- return -ENOMEM; +- } +- ret = jffs2_compressors_init(); +- if (ret) { +- pr_err("error: Failed to initialise compressors\n"); +- goto out; +- } +- ret = jffs2_create_slab_caches(); +- if (ret) { +- pr_err("error: Failed to initialise slab caches\n"); +- goto out_compressors; +- } +- ret = register_filesystem(&jffs2_fs_type); +- if (ret) { +- pr_err("error: Failed to register filesystem\n"); +- goto out_slab; ++ // Clean up the super block and root_node inode ++ jffs2_free_ino_caches(c); ++ jffs2_free_raw_node_refs(c); ++ free(c->blocks); ++ c->blocks = NULL; ++ free(c->inocache_list); ++ c->inocache_list = NULL; ++ (void)Jffs2HashDeinit(&sb->s_node_hash_lock); ++ ++ (void)mutex_destroy(&c->alloc_sem); ++ (void)mutex_destroy(&c->erase_free_sem); ++ free(sb); ++ // That's all folks. ++ D2(PRINTK("Jffs2Umount No current mounts\n")); ++ ++ if (--jffs2_mounted_number == 0) { ++ jffs2_destroy_slab_caches(); ++ (void)jffs2_compressors_exit(); + } + return 0; +- +- out_slab: +- jffs2_destroy_slab_caches(); +- out_compressors: +- jffs2_compressors_exit(); +- out: +- kmem_cache_destroy(jffs2_inode_cachep); +- return ret; + } +- +-static void __exit exit_jffs2_fs(void) +-{ +- unregister_filesystem(&jffs2_fs_type); +- jffs2_destroy_slab_caches(); +- jffs2_compressors_exit(); +- +- /* +- * Make sure all delayed rcu free inodes are flushed before we +- * destroy cache. +- */ +- rcu_barrier(); +- kmem_cache_destroy(jffs2_inode_cachep); +-} +- +-module_init(init_jffs2_fs); +-module_exit(exit_jffs2_fs); +- +-MODULE_DESCRIPTION("The Journalling Flash File System, v2"); +-MODULE_AUTHOR("Red Hat, Inc."); +-MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for +- // the sake of this tag. It's Free Software. +diff -Nupr old/fs/jffs2/symlink.c new/fs/jffs2/symlink.c +--- old/fs/jffs2/symlink.c 2022-05-09 17:15:24.350000000 +0800 ++++ new/fs/jffs2/symlink.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,19 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2001-2007 Red Hat, Inc. +- * +- * Created by David Woodhouse +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#include "nodelist.h" +- +-const struct inode_operations jffs2_symlink_inode_operations = +-{ +- .get_link = simple_get_link, +- .setattr = jffs2_setattr, +- .listxattr = jffs2_listxattr, +-}; +diff -Nupr old/fs/jffs2/wbuf.c new/fs/jffs2/wbuf.c +--- old/fs/jffs2/wbuf.c 2022-05-09 17:15:24.350000000 +0800 ++++ new/fs/jffs2/wbuf.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,1350 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2001-2007 Red Hat, Inc. +- * Copyright © 2004 Thomas Gleixner +- * +- * Created by David Woodhouse +- * Modified debugged and enhanced by Thomas Gleixner +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "nodelist.h" +- +-/* For testing write failures */ +-#undef BREAKME +-#undef BREAKMEHEADER +- +-#ifdef BREAKME +-static unsigned char *brokenbuf; +-#endif +- +-#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) +-#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) +- +-/* max. erase failures before we mark a block bad */ +-#define MAX_ERASE_FAILURES 2 +- +-struct jffs2_inodirty { +- uint32_t ino; +- struct jffs2_inodirty *next; +-}; +- +-static struct jffs2_inodirty inodirty_nomem; +- +-static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino) +-{ +- struct jffs2_inodirty *this = c->wbuf_inodes; +- +- /* If a malloc failed, consider _everything_ dirty */ +- if (this == &inodirty_nomem) +- return 1; +- +- /* If ino == 0, _any_ non-GC writes mean 'yes' */ +- if (this && !ino) +- return 1; +- +- /* Look to see if the inode in question is pending in the wbuf */ +- while (this) { +- if (this->ino == ino) +- return 1; +- this = this->next; +- } +- return 0; +-} +- +-static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c) +-{ +- struct jffs2_inodirty *this; +- +- this = c->wbuf_inodes; +- +- if (this != &inodirty_nomem) { +- while (this) { +- struct jffs2_inodirty *next = this->next; +- kfree(this); +- this = next; +- } +- } +- c->wbuf_inodes = NULL; +-} +- +-static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino) +-{ +- struct jffs2_inodirty *new; +- +- /* Schedule delayed write-buffer write-out */ +- jffs2_dirty_trigger(c); +- +- if (jffs2_wbuf_pending_for_ino(c, ino)) +- return; +- +- new = kmalloc(sizeof(*new), GFP_KERNEL); +- if (!new) { +- jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty\n"); +- jffs2_clear_wbuf_ino_list(c); +- c->wbuf_inodes = &inodirty_nomem; +- return; +- } +- new->ino = ino; +- new->next = c->wbuf_inodes; +- c->wbuf_inodes = new; +- return; +-} +- +-static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) +-{ +- struct list_head *this, *next; +- static int n; +- +- if (list_empty(&c->erasable_pending_wbuf_list)) +- return; +- +- list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) { +- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); +- +- jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", +- jeb->offset); +- list_del(this); +- if ((jiffies + (n++)) & 127) { +- /* Most of the time, we just erase it immediately. Otherwise we +- spend ages scanning it on mount, etc. */ +- jffs2_dbg(1, "...and adding to erase_pending_list\n"); +- list_add_tail(&jeb->list, &c->erase_pending_list); +- c->nr_erasing_blocks++; +- jffs2_garbage_collect_trigger(c); +- } else { +- /* Sometimes, however, we leave it elsewhere so it doesn't get +- immediately reused, and we spread the load a bit. */ +- jffs2_dbg(1, "...and adding to erasable_list\n"); +- list_add_tail(&jeb->list, &c->erasable_list); +- } +- } +-} +- +-#define REFILE_NOTEMPTY 0 +-#define REFILE_ANYWAY 1 +- +-static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) +-{ +- jffs2_dbg(1, "About to refile bad block at %08x\n", jeb->offset); +- +- /* File the existing block on the bad_used_list.... */ +- if (c->nextblock == jeb) +- c->nextblock = NULL; +- else /* Not sure this should ever happen... need more coffee */ +- list_del(&jeb->list); +- if (jeb->first_node) { +- jffs2_dbg(1, "Refiling block at %08x to bad_used_list\n", +- jeb->offset); +- list_add(&jeb->list, &c->bad_used_list); +- } else { +- BUG_ON(allow_empty == REFILE_NOTEMPTY); +- /* It has to have had some nodes or we couldn't be here */ +- jffs2_dbg(1, "Refiling block at %08x to erase_pending_list\n", +- jeb->offset); +- list_add(&jeb->list, &c->erase_pending_list); +- c->nr_erasing_blocks++; +- jffs2_garbage_collect_trigger(c); +- } +- +- if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) { +- uint32_t oldfree = jeb->free_size; +- +- jffs2_link_node_ref(c, jeb, +- (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE, +- oldfree, NULL); +- /* convert to wasted */ +- c->wasted_size += oldfree; +- jeb->wasted_size += oldfree; +- c->dirty_size -= oldfree; +- jeb->dirty_size -= oldfree; +- } +- +- jffs2_dbg_dump_block_lists_nolock(c); +- jffs2_dbg_acct_sanity_check_nolock(c,jeb); +- jffs2_dbg_acct_paranoia_check_nolock(c, jeb); +-} +- +-static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c, +- struct jffs2_inode_info *f, +- struct jffs2_raw_node_ref *raw, +- union jffs2_node_union *node) +-{ +- struct jffs2_node_frag *frag; +- struct jffs2_full_dirent *fd; +- +- dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n", +- node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype)); +- +- BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 && +- je16_to_cpu(node->u.magic) != 0); +- +- switch (je16_to_cpu(node->u.nodetype)) { +- case JFFS2_NODETYPE_INODE: +- if (f->metadata && f->metadata->raw == raw) { +- dbg_noderef("Will replace ->raw in f->metadata at %p\n", f->metadata); +- return &f->metadata->raw; +- } +- frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset)); +- BUG_ON(!frag); +- /* Find a frag which refers to the full_dnode we want to modify */ +- while (!frag->node || frag->node->raw != raw) { +- frag = frag_next(frag); +- BUG_ON(!frag); +- } +- dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node); +- return &frag->node->raw; +- +- case JFFS2_NODETYPE_DIRENT: +- for (fd = f->dents; fd; fd = fd->next) { +- if (fd->raw == raw) { +- dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd); +- return &fd->raw; +- } +- } +- BUG(); +- +- default: +- dbg_noderef("Don't care about replacing raw for nodetype %x\n", +- je16_to_cpu(node->u.nodetype)); +- break; +- } +- return NULL; +-} +- +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +-static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, +- uint32_t ofs) +-{ +- int ret; +- size_t retlen; +- char *eccstr; +- +- ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); +- if (ret && ret != -EUCLEAN && ret != -EBADMSG) { +- pr_warn("%s(): Read back of page at %08x failed: %d\n", +- __func__, c->wbuf_ofs, ret); +- return ret; +- } else if (retlen != c->wbuf_pagesize) { +- pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n", +- __func__, ofs, retlen, c->wbuf_pagesize); +- return -EIO; +- } +- if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) +- return 0; +- +- if (ret == -EUCLEAN) +- eccstr = "corrected"; +- else if (ret == -EBADMSG) +- eccstr = "correction failed"; +- else +- eccstr = "OK or unused"; +- +- pr_warn("Write verify error (ECC %s) at %08x. Wrote:\n", +- eccstr, c->wbuf_ofs); +- print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, +- c->wbuf, c->wbuf_pagesize, 0); +- +- pr_warn("Read back:\n"); +- print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, +- c->wbuf_verify, c->wbuf_pagesize, 0); +- +- return -EIO; +-} +-#else +-#define jffs2_verify_write(c,b,o) (0) +-#endif +- +-/* Recover from failure to write wbuf. Recover the nodes up to the +- * wbuf, not the one which we were starting to try to write. */ +- +-static void jffs2_wbuf_recover(struct jffs2_sb_info *c) +-{ +- struct jffs2_eraseblock *jeb, *new_jeb; +- struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL; +- size_t retlen; +- int ret; +- int nr_refile = 0; +- unsigned char *buf; +- uint32_t start, end, ofs, len; +- +- jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; +- +- spin_lock(&c->erase_completion_lock); +- if (c->wbuf_ofs % c->mtd->erasesize) +- jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); +- else +- jffs2_block_refile(c, jeb, REFILE_ANYWAY); +- spin_unlock(&c->erase_completion_lock); +- +- BUG_ON(!ref_obsolete(jeb->last_node)); +- +- /* Find the first node to be recovered, by skipping over every +- node which ends before the wbuf starts, or which is obsolete. */ +- for (next = raw = jeb->first_node; next; raw = next) { +- next = ref_next(raw); +- +- if (ref_obsolete(raw) || +- (next && ref_offset(next) <= c->wbuf_ofs)) { +- dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", +- ref_offset(raw), ref_flags(raw), +- (ref_offset(raw) + ref_totlen(c, jeb, raw)), +- c->wbuf_ofs); +- continue; +- } +- dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n", +- ref_offset(raw), ref_flags(raw), +- (ref_offset(raw) + ref_totlen(c, jeb, raw))); +- +- first_raw = raw; +- break; +- } +- +- if (!first_raw) { +- /* All nodes were obsolete. Nothing to recover. */ +- jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad\n"); +- c->wbuf_len = 0; +- return; +- } +- +- start = ref_offset(first_raw); +- end = ref_offset(jeb->last_node); +- nr_refile = 1; +- +- /* Count the number of refs which need to be copied */ +- while ((raw = ref_next(raw)) != jeb->last_node) +- nr_refile++; +- +- dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n", +- start, end, end - start, nr_refile); +- +- buf = NULL; +- if (start < c->wbuf_ofs) { +- /* First affected node was already partially written. +- * Attempt to reread the old data into our buffer. */ +- +- buf = kmalloc(end - start, GFP_KERNEL); +- if (!buf) { +- pr_crit("Malloc failure in wbuf recovery. Data loss ensues.\n"); +- +- goto read_failed; +- } +- +- /* Do the read... */ +- ret = mtd_read(c->mtd, start, c->wbuf_ofs - start, &retlen, +- buf); +- +- /* ECC recovered ? */ +- if ((ret == -EUCLEAN || ret == -EBADMSG) && +- (retlen == c->wbuf_ofs - start)) +- ret = 0; +- +- if (ret || retlen != c->wbuf_ofs - start) { +- pr_crit("Old data are already lost in wbuf recovery. Data loss ensues.\n"); +- +- kfree(buf); +- buf = NULL; +- read_failed: +- first_raw = ref_next(first_raw); +- nr_refile--; +- while (first_raw && ref_obsolete(first_raw)) { +- first_raw = ref_next(first_raw); +- nr_refile--; +- } +- +- /* If this was the only node to be recovered, give up */ +- if (!first_raw) { +- c->wbuf_len = 0; +- return; +- } +- +- /* It wasn't. Go on and try to recover nodes complete in the wbuf */ +- start = ref_offset(first_raw); +- dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n", +- start, end, end - start, nr_refile); +- +- } else { +- /* Read succeeded. Copy the remaining data from the wbuf */ +- memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); +- } +- } +- /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. +- Either 'buf' contains the data, or we find it in the wbuf */ +- +- /* ... and get an allocation of space from a shiny new block instead */ +- ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); +- if (ret) { +- pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues.\n"); +- kfree(buf); +- return; +- } +- +- /* The summary is not recovered, so it must be disabled for this erase block */ +- jffs2_sum_disable_collecting(c->summary); +- +- ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); +- if (ret) { +- pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); +- kfree(buf); +- return; +- } +- +- ofs = write_ofs(c); +- +- if (end-start >= c->wbuf_pagesize) { +- /* Need to do another write immediately, but it's possible +- that this is just because the wbuf itself is completely +- full, and there's nothing earlier read back from the +- flash. Hence 'buf' isn't necessarily what we're writing +- from. */ +- unsigned char *rewrite_buf = buf?:c->wbuf; +- uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); +- +- jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n", +- towrite, ofs); +- +-#ifdef BREAKMEHEADER +- static int breakme; +- if (breakme++ == 20) { +- pr_notice("Faking write error at 0x%08x\n", ofs); +- breakme = 0; +- mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf); +- ret = -EIO; +- } else +-#endif +- ret = mtd_write(c->mtd, ofs, towrite, &retlen, +- rewrite_buf); +- +- if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) { +- /* Argh. We tried. Really we did. */ +- pr_crit("Recovery of wbuf failed due to a second write error\n"); +- kfree(buf); +- +- if (retlen) +- jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL); +- +- return; +- } +- pr_notice("Recovery of wbuf succeeded to %08x\n", ofs); +- +- c->wbuf_len = (end - start) - towrite; +- c->wbuf_ofs = ofs + towrite; +- memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); +- /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ +- } else { +- /* OK, now we're left with the dregs in whichever buffer we're using */ +- if (buf) { +- memcpy(c->wbuf, buf, end-start); +- } else { +- memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); +- } +- c->wbuf_ofs = ofs; +- c->wbuf_len = end - start; +- } +- +- /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */ +- new_jeb = &c->blocks[ofs / c->sector_size]; +- +- spin_lock(&c->erase_completion_lock); +- for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) { +- uint32_t rawlen = ref_totlen(c, jeb, raw); +- struct jffs2_inode_cache *ic; +- struct jffs2_raw_node_ref *new_ref; +- struct jffs2_raw_node_ref **adjust_ref = NULL; +- struct jffs2_inode_info *f = NULL; +- +- jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x\n", +- rawlen, ref_offset(raw), ref_flags(raw), ofs); +- +- ic = jffs2_raw_ref_to_ic(raw); +- +- /* Ick. This XATTR mess should be fixed shortly... */ +- if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) { +- struct jffs2_xattr_datum *xd = (void *)ic; +- BUG_ON(xd->node != raw); +- adjust_ref = &xd->node; +- raw->next_in_ino = NULL; +- ic = NULL; +- } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) { +- struct jffs2_xattr_datum *xr = (void *)ic; +- BUG_ON(xr->node != raw); +- adjust_ref = &xr->node; +- raw->next_in_ino = NULL; +- ic = NULL; +- } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) { +- struct jffs2_raw_node_ref **p = &ic->nodes; +- +- /* Remove the old node from the per-inode list */ +- while (*p && *p != (void *)ic) { +- if (*p == raw) { +- (*p) = (raw->next_in_ino); +- raw->next_in_ino = NULL; +- break; +- } +- p = &((*p)->next_in_ino); +- } +- +- if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) { +- /* If it's an in-core inode, then we have to adjust any +- full_dirent or full_dnode structure to point to the +- new version instead of the old */ +- f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink); +- if (IS_ERR(f)) { +- /* Should never happen; it _must_ be present */ +- JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", +- ic->ino, PTR_ERR(f)); +- BUG(); +- } +- /* We don't lock f->sem. There's a number of ways we could +- end up in here with it already being locked, and nobody's +- going to modify it on us anyway because we hold the +- alloc_sem. We're only changing one ->raw pointer too, +- which we can get away with without upsetting readers. */ +- adjust_ref = jffs2_incore_replace_raw(c, f, raw, +- (void *)(buf?:c->wbuf) + (ref_offset(raw) - start)); +- } else if (unlikely(ic->state != INO_STATE_PRESENT && +- ic->state != INO_STATE_CHECKEDABSENT && +- ic->state != INO_STATE_GC)) { +- JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state); +- BUG(); +- } +- } +- +- new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic); +- +- if (adjust_ref) { +- BUG_ON(*adjust_ref != raw); +- *adjust_ref = new_ref; +- } +- if (f) +- jffs2_gc_release_inode(c, f); +- +- if (!ref_obsolete(raw)) { +- jeb->dirty_size += rawlen; +- jeb->used_size -= rawlen; +- c->dirty_size += rawlen; +- c->used_size -= rawlen; +- raw->flash_offset = ref_offset(raw) | REF_OBSOLETE; +- BUG_ON(raw->next_in_ino); +- } +- ofs += rawlen; +- } +- +- kfree(buf); +- +- /* Fix up the original jeb now it's on the bad_list */ +- if (first_raw == jeb->first_node) { +- jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list\n", +- jeb->offset); +- list_move(&jeb->list, &c->erase_pending_list); +- c->nr_erasing_blocks++; +- jffs2_garbage_collect_trigger(c); +- } +- +- jffs2_dbg_acct_sanity_check_nolock(c, jeb); +- jffs2_dbg_acct_paranoia_check_nolock(c, jeb); +- +- jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); +- jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); +- +- spin_unlock(&c->erase_completion_lock); +- +- jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", +- c->wbuf_ofs, c->wbuf_len); +- +-} +- +-/* Meaning of pad argument: +- 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway. +- 1: Pad, do not adjust nextblock free_size +- 2: Pad, adjust nextblock free_size +-*/ +-#define NOPAD 0 +-#define PAD_NOACCOUNT 1 +-#define PAD_ACCOUNTING 2 +- +-static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) +-{ +- struct jffs2_eraseblock *wbuf_jeb; +- int ret; +- size_t retlen; +- +- /* Nothing to do if not write-buffering the flash. In particular, we shouldn't +- del_timer() the timer we never initialised. */ +- if (!jffs2_is_writebuffered(c)) +- return 0; +- +- if (!mutex_is_locked(&c->alloc_sem)) { +- pr_crit("jffs2_flush_wbuf() called with alloc_sem not locked!\n"); +- BUG(); +- } +- +- if (!c->wbuf_len) /* already checked c->wbuf above */ +- return 0; +- +- wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; +- if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1)) +- return -ENOMEM; +- +- /* claim remaining space on the page +- this happens, if we have a change to a new block, +- or if fsync forces us to flush the writebuffer. +- if we have a switch to next page, we will not have +- enough remaining space for this. +- */ +- if (pad ) { +- c->wbuf_len = PAD(c->wbuf_len); +- +- /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR +- with 8 byte page size */ +- memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); +- +- if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { +- struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); +- padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +- padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING); +- padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len); +- padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4)); +- } +- } +- /* else jffs2_flash_writev has actually filled in the rest of the +- buffer for us, and will deal with the node refs etc. later. */ +- +-#ifdef BREAKME +- static int breakme; +- if (breakme++ == 20) { +- pr_notice("Faking write error at 0x%08x\n", c->wbuf_ofs); +- breakme = 0; +- mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, +- brokenbuf); +- ret = -EIO; +- } else +-#endif +- +- ret = mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, +- &retlen, c->wbuf); +- +- if (ret) { +- pr_warn("jffs2_flush_wbuf(): Write failed with %d\n", ret); +- goto wfail; +- } else if (retlen != c->wbuf_pagesize) { +- pr_warn("jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", +- retlen, c->wbuf_pagesize); +- ret = -EIO; +- goto wfail; +- } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { +- wfail: +- jffs2_wbuf_recover(c); +- +- return ret; +- } +- +- /* Adjust free size of the block if we padded. */ +- if (pad) { +- uint32_t waste = c->wbuf_pagesize - c->wbuf_len; +- +- jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", +- (wbuf_jeb == c->nextblock) ? "next" : "", +- wbuf_jeb->offset); +- +- /* wbuf_pagesize - wbuf_len is the amount of space that's to be +- padded. If there is less free space in the block than that, +- something screwed up */ +- if (wbuf_jeb->free_size < waste) { +- pr_crit("jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", +- c->wbuf_ofs, c->wbuf_len, waste); +- pr_crit("jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", +- wbuf_jeb->offset, wbuf_jeb->free_size); +- BUG(); +- } +- +- spin_lock(&c->erase_completion_lock); +- +- jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); +- /* FIXME: that made it count as dirty. Convert to wasted */ +- wbuf_jeb->dirty_size -= waste; +- c->dirty_size -= waste; +- wbuf_jeb->wasted_size += waste; +- c->wasted_size += waste; +- } else +- spin_lock(&c->erase_completion_lock); +- +- /* Stick any now-obsoleted blocks on the erase_pending_list */ +- jffs2_refile_wbuf_blocks(c); +- jffs2_clear_wbuf_ino_list(c); +- spin_unlock(&c->erase_completion_lock); +- +- memset(c->wbuf,0xff,c->wbuf_pagesize); +- /* adjust write buffer offset, else we get a non contiguous write bug */ +- c->wbuf_ofs += c->wbuf_pagesize; +- c->wbuf_len = 0; +- return 0; +-} +- +-/* Trigger garbage collection to flush the write-buffer. +- If ino arg is zero, do it if _any_ real (i.e. not GC) writes are +- outstanding. If ino arg non-zero, do it only if a write for the +- given inode is outstanding. */ +-int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) +-{ +- uint32_t old_wbuf_ofs; +- uint32_t old_wbuf_len; +- int ret = 0; +- +- jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino); +- +- if (!c->wbuf) +- return 0; +- +- mutex_lock(&c->alloc_sem); +- if (!jffs2_wbuf_pending_for_ino(c, ino)) { +- jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning\n", ino); +- mutex_unlock(&c->alloc_sem); +- return 0; +- } +- +- old_wbuf_ofs = c->wbuf_ofs; +- old_wbuf_len = c->wbuf_len; +- +- if (c->unchecked_size) { +- /* GC won't make any progress for a while */ +- jffs2_dbg(1, "%s(): padding. Not finished checking\n", +- __func__); +- down_write(&c->wbuf_sem); +- ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); +- /* retry flushing wbuf in case jffs2_wbuf_recover +- left some data in the wbuf */ +- if (ret) +- ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); +- up_write(&c->wbuf_sem); +- } else while (old_wbuf_len && +- old_wbuf_ofs == c->wbuf_ofs) { +- +- mutex_unlock(&c->alloc_sem); +- +- jffs2_dbg(1, "%s(): calls gc pass\n", __func__); +- +- ret = jffs2_garbage_collect_pass(c); +- if (ret) { +- /* GC failed. Flush it with padding instead */ +- mutex_lock(&c->alloc_sem); +- down_write(&c->wbuf_sem); +- ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); +- /* retry flushing wbuf in case jffs2_wbuf_recover +- left some data in the wbuf */ +- if (ret) +- ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); +- up_write(&c->wbuf_sem); +- break; +- } +- mutex_lock(&c->alloc_sem); +- } +- +- jffs2_dbg(1, "%s(): ends...\n", __func__); +- +- mutex_unlock(&c->alloc_sem); +- return ret; +-} +- +-/* Pad write-buffer to end and write it, wasting space. */ +-int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) +-{ +- int ret; +- +- if (!c->wbuf) +- return 0; +- +- down_write(&c->wbuf_sem); +- ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); +- /* retry - maybe wbuf recover left some data in wbuf. */ +- if (ret) +- ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); +- up_write(&c->wbuf_sem); +- +- return ret; +-} +- +-static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf, +- size_t len) +-{ +- if (len && !c->wbuf_len && (len >= c->wbuf_pagesize)) +- return 0; +- +- if (len > (c->wbuf_pagesize - c->wbuf_len)) +- len = c->wbuf_pagesize - c->wbuf_len; +- memcpy(c->wbuf + c->wbuf_len, buf, len); +- c->wbuf_len += (uint32_t) len; +- return len; +-} +- +-int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, +- unsigned long count, loff_t to, size_t *retlen, +- uint32_t ino) +-{ +- struct jffs2_eraseblock *jeb; +- size_t wbuf_retlen, donelen = 0; +- uint32_t outvec_to = to; +- int ret, invec; +- +- /* If not writebuffered flash, don't bother */ +- if (!jffs2_is_writebuffered(c)) +- return jffs2_flash_direct_writev(c, invecs, count, to, retlen); +- +- down_write(&c->wbuf_sem); +- +- /* If wbuf_ofs is not initialized, set it to target address */ +- if (c->wbuf_ofs == 0xFFFFFFFF) { +- c->wbuf_ofs = PAGE_DIV(to); +- c->wbuf_len = PAGE_MOD(to); +- memset(c->wbuf,0xff,c->wbuf_pagesize); +- } +- +- /* +- * Sanity checks on target address. It's permitted to write +- * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to +- * write at the beginning of a new erase block. Anything else, +- * and you die. New block starts at xxx000c (0-b = block +- * header) +- */ +- if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { +- /* It's a write to a new block */ +- if (c->wbuf_len) { +- jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x\n", +- __func__, (unsigned long)to, c->wbuf_ofs); +- ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); +- if (ret) +- goto outerr; +- } +- /* set pointer to new block */ +- c->wbuf_ofs = PAGE_DIV(to); +- c->wbuf_len = PAGE_MOD(to); +- } +- +- if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { +- /* We're not writing immediately after the writebuffer. Bad. */ +- pr_crit("%s(): Non-contiguous write to %08lx\n", +- __func__, (unsigned long)to); +- if (c->wbuf_len) +- pr_crit("wbuf was previously %08x-%08x\n", +- c->wbuf_ofs, c->wbuf_ofs + c->wbuf_len); +- BUG(); +- } +- +- /* adjust alignment offset */ +- if (c->wbuf_len != PAGE_MOD(to)) { +- c->wbuf_len = PAGE_MOD(to); +- /* take care of alignment to next page */ +- if (!c->wbuf_len) { +- c->wbuf_len = c->wbuf_pagesize; +- ret = __jffs2_flush_wbuf(c, NOPAD); +- if (ret) +- goto outerr; +- } +- } +- +- for (invec = 0; invec < count; invec++) { +- int vlen = invecs[invec].iov_len; +- uint8_t *v = invecs[invec].iov_base; +- +- wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); +- +- if (c->wbuf_len == c->wbuf_pagesize) { +- ret = __jffs2_flush_wbuf(c, NOPAD); +- if (ret) +- goto outerr; +- } +- vlen -= wbuf_retlen; +- outvec_to += wbuf_retlen; +- donelen += wbuf_retlen; +- v += wbuf_retlen; +- +- if (vlen >= c->wbuf_pagesize) { +- ret = mtd_write(c->mtd, outvec_to, PAGE_DIV(vlen), +- &wbuf_retlen, v); +- if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen)) +- goto outfile; +- +- vlen -= wbuf_retlen; +- outvec_to += wbuf_retlen; +- c->wbuf_ofs = outvec_to; +- donelen += wbuf_retlen; +- v += wbuf_retlen; +- } +- +- wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); +- if (c->wbuf_len == c->wbuf_pagesize) { +- ret = __jffs2_flush_wbuf(c, NOPAD); +- if (ret) +- goto outerr; +- } +- +- outvec_to += wbuf_retlen; +- donelen += wbuf_retlen; +- } +- +- /* +- * If there's a remainder in the wbuf and it's a non-GC write, +- * remember that the wbuf affects this ino +- */ +- *retlen = donelen; +- +- if (jffs2_sum_active()) { +- int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to); +- if (res) +- return res; +- } +- +- if (c->wbuf_len && ino) +- jffs2_wbuf_dirties_inode(c, ino); +- +- ret = 0; +- up_write(&c->wbuf_sem); +- return ret; +- +-outfile: +- /* +- * At this point we have no problem, c->wbuf is empty. However +- * refile nextblock to avoid writing again to same address. +- */ +- +- spin_lock(&c->erase_completion_lock); +- +- jeb = &c->blocks[outvec_to / c->sector_size]; +- jffs2_block_refile(c, jeb, REFILE_ANYWAY); +- +- spin_unlock(&c->erase_completion_lock); +- +-outerr: +- *retlen = 0; +- up_write(&c->wbuf_sem); +- return ret; +-} +- +-/* +- * This is the entry for flash write. +- * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev +-*/ +-int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, +- size_t *retlen, const u_char *buf) +-{ +- struct kvec vecs[1]; +- +- if (!jffs2_is_writebuffered(c)) +- return jffs2_flash_direct_write(c, ofs, len, retlen, buf); +- +- vecs[0].iov_base = (unsigned char *) buf; +- vecs[0].iov_len = len; +- return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0); +-} +- +-/* +- Handle readback from writebuffer and ECC failure return +-*/ +-int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf) +-{ +- loff_t orbf = 0, owbf = 0, lwbf = 0; +- int ret; +- +- if (!jffs2_is_writebuffered(c)) +- return mtd_read(c->mtd, ofs, len, retlen, buf); +- +- /* Read flash */ +- down_read(&c->wbuf_sem); +- ret = mtd_read(c->mtd, ofs, len, retlen, buf); +- +- if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) { +- if (ret == -EBADMSG) +- pr_warn("mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", +- len, ofs); +- /* +- * We have the raw data without ECC correction in the buffer, +- * maybe we are lucky and all data or parts are correct. We +- * check the node. If data are corrupted node check will sort +- * it out. We keep this block, it will fail on write or erase +- * and the we mark it bad. Or should we do that now? But we +- * should give him a chance. Maybe we had a system crash or +- * power loss before the ecc write or a erase was completed. +- * So we return success. :) +- */ +- ret = 0; +- } +- +- /* if no writebuffer available or write buffer empty, return */ +- if (!c->wbuf_pagesize || !c->wbuf_len) +- goto exit; +- +- /* if we read in a different block, return */ +- if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) +- goto exit; +- +- if (ofs >= c->wbuf_ofs) { +- owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ +- if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ +- goto exit; +- lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ +- if (lwbf > len) +- lwbf = len; +- } else { +- orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ +- if (orbf > len) /* is write beyond write buffer ? */ +- goto exit; +- lwbf = len - orbf; /* number of bytes to copy */ +- if (lwbf > c->wbuf_len) +- lwbf = c->wbuf_len; +- } +- if (lwbf > 0) +- memcpy(buf+orbf,c->wbuf+owbf,lwbf); +- +-exit: +- up_read(&c->wbuf_sem); +- return ret; +-} +- +-#define NR_OOB_SCAN_PAGES 4 +- +-/* For historical reasons we use only 8 bytes for OOB clean marker */ +-#define OOB_CM_SIZE 8 +- +-static const struct jffs2_unknown_node oob_cleanmarker = +-{ +- .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK), +- .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), +- .totlen = constant_cpu_to_je32(8) +-}; +- +-/* +- * Check, if the out of band area is empty. This function knows about the clean +- * marker and if it is present in OOB, treats the OOB as empty anyway. +- */ +-int jffs2_check_oob_empty(struct jffs2_sb_info *c, +- struct jffs2_eraseblock *jeb, int mode) +-{ +- int i, ret; +- int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); +- struct mtd_oob_ops ops; +- +- ops.mode = MTD_OPS_AUTO_OOB; +- ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; +- ops.oobbuf = c->oobbuf; +- ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; +- ops.datbuf = NULL; +- +- ret = mtd_read_oob(c->mtd, jeb->offset, &ops); +- if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { +- pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", +- jeb->offset, ops.ooblen, ops.oobretlen, ret); +- if (!ret || mtd_is_bitflip(ret)) +- ret = -EIO; +- return ret; +- } +- +- for(i = 0; i < ops.ooblen; i++) { +- if (mode && i < cmlen) +- /* Yeah, we know about the cleanmarker */ +- continue; +- +- if (ops.oobbuf[i] != 0xFF) { +- jffs2_dbg(2, "Found %02x at %x in OOB for " +- "%08x\n", ops.oobbuf[i], i, jeb->offset); +- return 1; +- } +- } +- +- return 0; +-} +- +-/* +- * Check for a valid cleanmarker. +- * Returns: 0 if a valid cleanmarker was found +- * 1 if no cleanmarker was found +- * negative error code if an error occurred +- */ +-int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, +- struct jffs2_eraseblock *jeb) +-{ +- struct mtd_oob_ops ops; +- int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); +- +- ops.mode = MTD_OPS_AUTO_OOB; +- ops.ooblen = cmlen; +- ops.oobbuf = c->oobbuf; +- ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; +- ops.datbuf = NULL; +- +- ret = mtd_read_oob(c->mtd, jeb->offset, &ops); +- if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { +- pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", +- jeb->offset, ops.ooblen, ops.oobretlen, ret); +- if (!ret || mtd_is_bitflip(ret)) +- ret = -EIO; +- return ret; +- } +- +- return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen); +-} +- +-int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, +- struct jffs2_eraseblock *jeb) +-{ +- int ret; +- struct mtd_oob_ops ops; +- int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); +- +- ops.mode = MTD_OPS_AUTO_OOB; +- ops.ooblen = cmlen; +- ops.oobbuf = (uint8_t *)&oob_cleanmarker; +- ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; +- ops.datbuf = NULL; +- +- ret = mtd_write_oob(c->mtd, jeb->offset, &ops); +- if (ret || ops.oobretlen != ops.ooblen) { +- pr_err("cannot write OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", +- jeb->offset, ops.ooblen, ops.oobretlen, ret); +- if (!ret) +- ret = -EIO; +- return ret; +- } +- +- return 0; +-} +- +-/* +- * On NAND we try to mark this block bad. If the block was erased more +- * than MAX_ERASE_FAILURES we mark it finally bad. +- * Don't care about failures. This block remains on the erase-pending +- * or badblock list as long as nobody manipulates the flash with +- * a bootloader or something like that. +- */ +- +-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset) +-{ +- int ret; +- +- /* if the count is < max, we try to write the counter to the 2nd page oob area */ +- if( ++jeb->bad_count < MAX_ERASE_FAILURES) +- return 0; +- +- pr_warn("marking eraseblock at %08x as bad\n", bad_offset); +- ret = mtd_block_markbad(c->mtd, bad_offset); +- +- if (ret) { +- jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d\n", +- __func__, jeb->offset, ret); +- return ret; +- } +- return 1; +-} +- +-static struct jffs2_sb_info *work_to_sb(struct work_struct *work) +-{ +- struct delayed_work *dwork; +- +- dwork = to_delayed_work(work); +- return container_of(dwork, struct jffs2_sb_info, wbuf_dwork); +-} +- +-static void delayed_wbuf_sync(struct work_struct *work) +-{ +- struct jffs2_sb_info *c = work_to_sb(work); +- struct super_block *sb = OFNI_BS_2SFFJ(c); +- +- if (!sb_rdonly(sb)) { +- jffs2_dbg(1, "%s()\n", __func__); +- jffs2_flush_wbuf_gc(c, 0); +- } +-} +- +-void jffs2_dirty_trigger(struct jffs2_sb_info *c) +-{ +- struct super_block *sb = OFNI_BS_2SFFJ(c); +- unsigned long delay; +- +- if (sb_rdonly(sb)) +- return; +- +- delay = msecs_to_jiffies(dirty_writeback_interval * 10); +- if (queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay)) +- jffs2_dbg(1, "%s()\n", __func__); +-} +- +-int jffs2_nand_flash_setup(struct jffs2_sb_info *c) +-{ +- if (!c->mtd->oobsize) +- return 0; +- +- /* Cleanmarker is out-of-band, so inline size zero */ +- c->cleanmarker_size = 0; +- +- if (c->mtd->oobavail == 0) { +- pr_err("inconsistent device description\n"); +- return -EINVAL; +- } +- +- jffs2_dbg(1, "using OOB on NAND\n"); +- +- c->oobavail = c->mtd->oobavail; +- +- /* Initialise write buffer */ +- init_rwsem(&c->wbuf_sem); +- INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); +- c->wbuf_pagesize = c->mtd->writesize; +- c->wbuf_ofs = 0xFFFFFFFF; +- +- c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf) +- return -ENOMEM; +- +- c->oobbuf = kmalloc_array(NR_OOB_SCAN_PAGES, c->oobavail, GFP_KERNEL); +- if (!c->oobbuf) { +- kfree(c->wbuf); +- return -ENOMEM; +- } +- +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +- c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf_verify) { +- kfree(c->oobbuf); +- kfree(c->wbuf); +- return -ENOMEM; +- } +-#endif +- return 0; +-} +- +-void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) +-{ +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +- kfree(c->wbuf_verify); +-#endif +- kfree(c->wbuf); +- kfree(c->oobbuf); +-} +- +-int jffs2_dataflash_setup(struct jffs2_sb_info *c) { +- c->cleanmarker_size = 0; /* No cleanmarkers needed */ +- +- /* Initialize write buffer */ +- init_rwsem(&c->wbuf_sem); +- INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); +- c->wbuf_pagesize = c->mtd->erasesize; +- +- /* Find a suitable c->sector_size +- * - Not too much sectors +- * - Sectors have to be at least 4 K + some bytes +- * - All known dataflashes have erase sizes of 528 or 1056 +- * - we take at least 8 eraseblocks and want to have at least 8K size +- * - The concatenation should be a power of 2 +- */ +- +- c->sector_size = 8 * c->mtd->erasesize; +- +- while (c->sector_size < 8192) { +- c->sector_size *= 2; +- } +- +- /* It may be necessary to adjust the flash size */ +- c->flash_size = c->mtd->size; +- +- if ((c->flash_size % c->sector_size) != 0) { +- c->flash_size = (c->flash_size / c->sector_size) * c->sector_size; +- pr_warn("flash size adjusted to %dKiB\n", c->flash_size); +- } +- +- c->wbuf_ofs = 0xFFFFFFFF; +- c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf) +- return -ENOMEM; +- +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +- c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf_verify) { +- kfree(c->wbuf); +- return -ENOMEM; +- } +-#endif +- +- pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n", +- c->wbuf_pagesize, c->sector_size); +- +- return 0; +-} +- +-void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +- kfree(c->wbuf_verify); +-#endif +- kfree(c->wbuf); +-} +- +-int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { +- /* Cleanmarker currently occupies whole programming regions, +- * either one or 2 for 8Byte STMicro flashes. */ +- c->cleanmarker_size = max(16u, c->mtd->writesize); +- +- /* Initialize write buffer */ +- init_rwsem(&c->wbuf_sem); +- INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); +- +- c->wbuf_pagesize = c->mtd->writesize; +- c->wbuf_ofs = 0xFFFFFFFF; +- +- c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf) +- return -ENOMEM; +- +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +- c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf_verify) { +- kfree(c->wbuf); +- return -ENOMEM; +- } +-#endif +- return 0; +-} +- +-void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { +-#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY +- kfree(c->wbuf_verify); +-#endif +- kfree(c->wbuf); +-} +- +-int jffs2_ubivol_setup(struct jffs2_sb_info *c) { +- c->cleanmarker_size = 0; +- +- if (c->mtd->writesize == 1) +- /* We do not need write-buffer */ +- return 0; +- +- init_rwsem(&c->wbuf_sem); +- INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); +- +- c->wbuf_pagesize = c->mtd->writesize; +- c->wbuf_ofs = 0xFFFFFFFF; +- c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); +- if (!c->wbuf) +- return -ENOMEM; +- +- pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n", +- c->wbuf_pagesize, c->sector_size); +- +- return 0; +-} +- +-void jffs2_ubivol_cleanup(struct jffs2_sb_info *c) { +- kfree(c->wbuf); +-} +diff -Nupr old/fs/jffs2/write.c new/fs/jffs2/write.c +--- old/fs/jffs2/write.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/write.c 2022-05-09 20:07:33.520000000 +0800 +@@ -9,16 +9,15 @@ + * + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- ++#include + #include + #include +-#include + #include +-#include ++#include ++#include "mtd_dev.h" + #include "nodelist.h" + #include "compr.h" +- ++#include "los_crc32.h" + + int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + uint32_t mode, struct jffs2_raw_inode *ri) +@@ -30,8 +29,6 @@ int jffs2_do_new_inode(struct jffs2_sb_i + return -ENOMEM; + } + +- memset(ic, 0, sizeof(*ic)); +- + f->inocache = ic; + f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */ + f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; +@@ -69,8 +66,10 @@ struct jffs2_full_dnode *jffs2_write_dno + int retried = 0; + unsigned long cnt = 2; + +- D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { +- pr_crit("Eep. CRC not correct in jffs2_write_dnode()\n"); ++ D1(if (je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { ++ printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode(), je32_to_cpu(ri->hdr_crc):%d, " ++ "crc32(0, ri, sizeof(struct jffs2_unknown_node) - 4):%d\n", je32_to_cpu(ri->hdr_crc), ++ crc32(0, ri, sizeof(struct jffs2_unknown_node) - 4)); + BUG(); + } + ); +@@ -172,8 +171,8 @@ struct jffs2_full_dnode *jffs2_write_dno + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + */ +- if ((je32_to_cpu(ri->dsize) >= PAGE_SIZE) || +- ( ((je32_to_cpu(ri->offset)&(PAGE_SIZE-1))==0) && ++ if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || ++ ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { + flash_ofs |= REF_PRISTINE; + } else { +@@ -219,11 +218,13 @@ struct jffs2_full_dirent *jffs2_write_di + je32_to_cpu(rd->name_crc)); + + D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { +- pr_crit("Eep. CRC not correct in jffs2_write_dirent()\n"); ++ printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent(), je32_to_cpu(rd->hdr_crc):%d, " ++ "crc32(0, rd, sizeof(struct jffs2_unknown_node) - 4):%d\n", je32_to_cpu(rd->hdr_crc), ++ crc32(0, rd, sizeof(struct jffs2_unknown_node) - 4)); + BUG(); + }); + +- if (strnlen(name, namelen) != namelen) { ++ if (strnlen((const char *)name, namelen) != namelen) { + /* This should never happen, but seems to have done on at least one + occasion: https://dev.laptop.org/ticket/4184 */ + pr_crit("Error in jffs2_write_dirent() -- name contains zero bytes!\n"); +@@ -245,7 +246,7 @@ struct jffs2_full_dirent *jffs2_write_di + + fd->version = je32_to_cpu(rd->version); + fd->ino = je32_to_cpu(rd->ino); +- fd->nhash = full_name_hash(NULL, name, namelen); ++ fd->nhash = full_name_hash(name, namelen); + fd->type = rd->type; + memcpy(fd->name, name, namelen); + fd->name[namelen]=0; +@@ -343,10 +344,24 @@ int jffs2_write_inode_range(struct jffs2 + { + int ret = 0; + uint32_t writtenlen = 0; ++ unsigned char *bufRet = NULL; ++ unsigned char *bufRetBak = NULL; + + jffs2_dbg(1, "%s(): Ino #%u, ofs 0x%x, len 0x%x\n", + __func__, f->inocache->ino, offset, writelen); + ++ if (writelen > 0) { ++ bufRet = kmalloc(writelen, GFP_KERNEL); ++ if (bufRet == NULL) { ++ return -ENOMEM; ++ } ++ bufRetBak = bufRet; ++ if (LOS_CopyToKernel(bufRet, writelen, buf, writelen) != 0) { ++ kfree(bufRet); ++ return -EFAULT; ++ } ++ } ++ + while(writelen) { + struct jffs2_full_dnode *fn; + unsigned char *comprbuf = NULL; +@@ -366,11 +381,10 @@ int jffs2_write_inode_range(struct jffs2 + break; + } + mutex_lock(&f->sem); +- datalen = min_t(uint32_t, writelen, +- PAGE_SIZE - (offset & (PAGE_SIZE-1))); ++ datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); + cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); + +- comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen); ++ comprtype = jffs2_compress(c, f, bufRet, &comprbuf, &datalen, &cdatalen); + + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); +@@ -390,7 +404,7 @@ int jffs2_write_inode_range(struct jffs2 + + fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, ALLOC_NORETRY); + +- jffs2_free_comprbuf(comprbuf, buf); ++ jffs2_free_comprbuf(comprbuf, bufRet); + + if (IS_ERR(fn)) { + ret = PTR_ERR(fn); +@@ -432,15 +446,18 @@ int jffs2_write_inode_range(struct jffs2 + writtenlen += datalen; + offset += datalen; + writelen -= datalen; +- buf += datalen; ++ bufRet += datalen; + } + *retlen = writtenlen; ++ if (bufRetBak != NULL) { ++ kfree(bufRetBak); ++ } + return ret; + } + + int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, + struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, +- const struct qstr *qstr) ++ const char *name, int namelen) + { + struct jffs2_raw_dirent *rd; + struct jffs2_full_dnode *fn; +@@ -468,7 +485,8 @@ int jffs2_do_create(struct jffs2_sb_info + jemode_to_cpu(ri->mode)); + + if (IS_ERR(fn)) { +- jffs2_dbg(1, "jffs2_write_dnode() failed\n"); ++ jffs2_dbg(1, "jffs2_write_dnode() failed,error:%ld\n", ++ PTR_ERR(fn)); + /* Eeek. Wave bye bye */ + mutex_unlock(&f->sem); + jffs2_complete_reservation(c); +@@ -482,19 +500,12 @@ int jffs2_do_create(struct jffs2_sb_info + mutex_unlock(&f->sem); + jffs2_complete_reservation(c); + +- ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode, qstr); +- if (ret) +- return ret; +- ret = jffs2_init_acl_post(&f->vfs_inode); +- if (ret) +- return ret; +- +- ret = jffs2_reserve_space(c, sizeof(*rd)+qstr->len, &alloclen, +- ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(qstr->len)); ++ ret = jffs2_reserve_space(c, sizeof(*rd)+ namelen, &alloclen, ++ ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); + + if (ret) { + /* Eep. */ +- jffs2_dbg(1, "jffs2_reserve_space() for dirent failed\n"); ++ jffs2_dbg(1, "jffs2_reserve_space() for dirent failed,ret:%d\n",ret); + return ret; + } + +@@ -509,19 +520,19 @@ int jffs2_do_create(struct jffs2_sb_info + + rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); +- rd->totlen = cpu_to_je32(sizeof(*rd) + qstr->len); ++ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); + rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + + rd->pino = cpu_to_je32(dir_f->inocache->ino); + rd->version = cpu_to_je32(++dir_f->highest_version); + rd->ino = ri->ino; + rd->mctime = ri->ctime; +- rd->nsize = qstr->len; ++ rd->nsize = namelen; + rd->type = DT_REG; + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); +- rd->name_crc = cpu_to_je32(crc32(0, qstr->name, qstr->len)); ++ rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); + +- fd = jffs2_write_dirent(c, dir_f, rd, qstr->name, qstr->len, ALLOC_NORMAL); ++ fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)name, namelen, ALLOC_NORMAL); + + jffs2_free_raw_dirent(rd); + +@@ -553,7 +564,7 @@ int jffs2_do_unlink(struct jffs2_sb_info + uint32_t alloclen; + int ret; + +- if (!jffs2_can_mark_obsolete(c)) { ++ if (jffs2_can_mark_obsolete(c)) { + /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ + + rd = jffs2_alloc_raw_dirent(); +@@ -584,7 +595,7 @@ int jffs2_do_unlink(struct jffs2_sb_info + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); + +- fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_DELETION); ++ fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)name, namelen, ALLOC_DELETION); + + jffs2_free_raw_dirent(rd); + +@@ -598,7 +609,7 @@ int jffs2_do_unlink(struct jffs2_sb_info + jffs2_add_fd_to_list(c, fd, &dir_f->dents); + mutex_unlock(&dir_f->sem); + } else { +- uint32_t nhash = full_name_hash(NULL, name, namelen); ++ uint32_t nhash = full_name_hash((const unsigned char *)name, namelen); + + fd = dir_f->dents; + /* We don't actually want to reserve any space, but we do +@@ -703,7 +714,7 @@ int jffs2_do_link (struct jffs2_sb_info + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); + +- fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_NORMAL); ++ fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)name, namelen, ALLOC_NORMAL); + + jffs2_free_raw_dirent(rd); + +diff -Nupr old/fs/jffs2/writev.c new/fs/jffs2/writev.c +--- old/fs/jffs2/writev.c 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/writev.c 2022-05-09 20:05:36.440000000 +0800 +@@ -10,42 +10,97 @@ + */ + + #include +-#include ++#include "mtd_dev.h" + #include "nodelist.h" + + int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) + { +- if (!jffs2_is_writebuffered(c)) { +- if (jffs2_sum_active()) { +- int res; +- res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to); +- if (res) { +- return res; ++ unsigned long i; ++ size_t totlen = 0, thislen; ++ int ret = 0; ++ ++ for (i = 0; i < count; i++) { ++ // writes need to be aligned but the data we're passed may not be ++ // Observation suggests most unaligned writes are small, so we ++ // optimize for that case. ++ ++ if (((vecs[i].iov_len & (sizeof(int) - 1))) || ++ (((unsigned long) vecs[i].iov_base & (sizeof(unsigned long) - 1)))) { ++ // are there iov's after this one? Or is it so much we'd need ++ // to do multiple writes anyway? ++ if ((i + 1) < count || vecs[i].iov_len > 256) { ++ // cop out and malloc ++ unsigned long j; ++ size_t sizetomalloc = 0, totvecsize = 0; ++ char *cbuf, *cbufptr; ++ ++ for (j = i; j < count; j++) ++ totvecsize += vecs[j].iov_len; ++ ++ // pad up in case unaligned ++ sizetomalloc = totvecsize + sizeof(int) - 1; ++ sizetomalloc &= ~(sizeof(int) - 1); ++ cbuf = (char *) malloc(sizetomalloc); ++ // malloc returns aligned memory ++ if (!cbuf) { ++ ret = -ENOMEM; ++ goto writev_out; ++ } ++ cbufptr = cbuf; ++ for (j = i; j < count; j++) { ++ (void)memcpy_s(cbufptr, vecs[j].iov_len, vecs[j].iov_base, vecs[j].iov_len); ++ cbufptr += vecs[j].iov_len; ++ } ++ ret = jffs2_flash_write(c, to, sizetomalloc, &thislen, ++ (unsigned char *) cbuf); ++ if (thislen > totvecsize) // in case it was aligned up ++ thislen = totvecsize; ++ totlen += thislen; ++ free(cbuf); ++ goto writev_out; ++ } else { ++ // otherwise optimize for the common case ++ int buf[256/sizeof(int)]; // int, so int aligned ++ size_t lentowrite; ++ ++ lentowrite = vecs[i].iov_len; ++ // pad up in case its unaligned ++ lentowrite += sizeof(int) - 1; ++ lentowrite &= ~(sizeof(int) - 1); ++ ret = memcpy_s(buf, sizeof(buf), vecs[i].iov_base, vecs[i].iov_len); ++ if (ret != EOK) ++ goto writev_out; ++ ++ ret = jffs2_flash_write(c, to, lentowrite, &thislen, ++ (unsigned char *) &buf[0]); ++ if (thislen > vecs[i].iov_len) ++ thislen = vecs[i].iov_len; + } ++ } else { ++ ret = jffs2_flash_write(c, to, vecs[i].iov_len, &thislen, ++ vecs[i].iov_base); + } ++ totlen += thislen; ++ if (ret || thislen != vecs[i].iov_len) break; ++ to += vecs[i].iov_len; + } + +- return mtd_writev(c->mtd, vecs, count, to, retlen); ++writev_out: ++ if (retlen) *retlen = totlen; ++ ++ return ret; + } + + int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf) + { + int ret; +- ret = mtd_write(c->mtd, ofs, len, retlen, buf); +- +- if (jffs2_sum_active()) { +- struct kvec vecs[1]; +- int res; +- +- vecs[0].iov_base = (unsigned char *) buf; +- vecs[0].iov_len = len; +- +- res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs); +- if (res) { +- return res; +- } ++ ret = c->mtd->write(c->mtd, ofs, len, (char *)buf); ++ if (ret >= 0) { ++ *retlen = ret; ++ return 0; + } ++ *retlen = 0; + return ret; + } +diff -Nupr old/fs/jffs2/xattr.c new/fs/jffs2/xattr.c +--- old/fs/jffs2/xattr.c 2022-05-09 17:15:24.360000000 +0800 ++++ new/fs/jffs2/xattr.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,1347 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2006 NEC Corporation +- * +- * Created by KaiGai Kohei +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#define JFFS2_XATTR_IS_CORRUPTED 1 +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "nodelist.h" +-/* -------- xdatum related functions ---------------- +- * xattr_datum_hashkey(xprefix, xname, xvalue, xsize) +- * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is +- * the index of the xattr name/value pair cache (c->xattrindex). +- * is_xattr_datum_unchecked(c, xd) +- * returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not +- * unchecked, it returns 0. +- * unload_xattr_datum(c, xd) +- * is used to release xattr name/value pair and detach from c->xattrindex. +- * reclaim_xattr_datum(c) +- * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when +- * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold +- * is hard coded as 32KiB. +- * do_verify_xattr_datum(c, xd) +- * is used to load the xdatum informations without name/value pair from the medium. +- * It's necessary once, because those informations are not collected during mounting +- * process when EBS is enabled. +- * 0 will be returned, if success. An negative return value means recoverable error, and +- * positive return value means unrecoverable error. Thus, caller must remove this xdatum +- * and xref when it returned positive value. +- * do_load_xattr_datum(c, xd) +- * is used to load name/value pair from the medium. +- * The meanings of return value is same as do_verify_xattr_datum(). +- * load_xattr_datum(c, xd) +- * is used to be as a wrapper of do_verify_xattr_datum() and do_load_xattr_datum(). +- * If xd need to call do_verify_xattr_datum() at first, it's called before calling +- * do_load_xattr_datum(). The meanings of return value is same as do_verify_xattr_datum(). +- * save_xattr_datum(c, xd) +- * is used to write xdatum to medium. xd->version will be incremented. +- * create_xattr_datum(c, xprefix, xname, xvalue, xsize) +- * is used to create new xdatum and write to medium. +- * unrefer_xattr_datum(c, xd) +- * is used to delete a xdatum. When nobody refers this xdatum, JFFS2_XFLAGS_DEAD +- * is set on xd->flags and chained xattr_dead_list or release it immediately. +- * In the first case, the garbage collector release it later. +- * -------------------------------------------------- */ +-static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize) +-{ +- int name_len = strlen(xname); +- +- return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize); +-} +- +-static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- struct jffs2_raw_node_ref *raw; +- int rc = 0; +- +- spin_lock(&c->erase_completion_lock); +- for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { +- if (ref_flags(raw) == REF_UNCHECKED) { +- rc = 1; +- break; +- } +- } +- spin_unlock(&c->erase_completion_lock); +- return rc; +-} +- +-static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem) */ +- D1(dbg_xattr("%s: xid=%u, version=%u\n", __func__, xd->xid, xd->version)); +- if (xd->xname) { +- c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len); +- kfree(xd->xname); +- } +- +- list_del_init(&xd->xindex); +- xd->hashkey = 0; +- xd->xname = NULL; +- xd->xvalue = NULL; +-} +- +-static void reclaim_xattr_datum(struct jffs2_sb_info *c) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_xattr_datum *xd, *_xd; +- uint32_t target, before; +- static int index = 0; +- int count; +- +- if (c->xdatum_mem_threshold > c->xdatum_mem_usage) +- return; +- +- before = c->xdatum_mem_usage; +- target = c->xdatum_mem_usage * 4 / 5; /* 20% reduction */ +- for (count = 0; count < XATTRINDEX_HASHSIZE; count++) { +- list_for_each_entry_safe(xd, _xd, &c->xattrindex[index], xindex) { +- if (xd->flags & JFFS2_XFLAGS_HOT) { +- xd->flags &= ~JFFS2_XFLAGS_HOT; +- } else if (!(xd->flags & JFFS2_XFLAGS_BIND)) { +- unload_xattr_datum(c, xd); +- } +- if (c->xdatum_mem_usage <= target) +- goto out; +- } +- index = (index+1) % XATTRINDEX_HASHSIZE; +- } +- out: +- JFFS2_NOTICE("xdatum_mem_usage from %u byte to %u byte (%u byte reclaimed)\n", +- before, c->xdatum_mem_usage, before - c->xdatum_mem_usage); +-} +- +-static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_eraseblock *jeb; +- struct jffs2_raw_node_ref *raw; +- struct jffs2_raw_xattr rx; +- size_t readlen; +- uint32_t crc, offset, totlen; +- int rc; +- +- spin_lock(&c->erase_completion_lock); +- offset = ref_offset(xd->node); +- if (ref_flags(xd->node) == REF_PRISTINE) +- goto complete; +- spin_unlock(&c->erase_completion_lock); +- +- rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx); +- if (rc || readlen != sizeof(rx)) { +- JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", +- rc, sizeof(rx), readlen, offset); +- return rc ? rc : -EIO; +- } +- crc = crc32(0, &rx, sizeof(rx) - 4); +- if (crc != je32_to_cpu(rx.node_crc)) { +- JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", +- offset, je32_to_cpu(rx.hdr_crc), crc); +- xd->flags |= JFFS2_XFLAGS_INVALID; +- return JFFS2_XATTR_IS_CORRUPTED; +- } +- totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); +- if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK +- || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR +- || je32_to_cpu(rx.totlen) != totlen +- || je32_to_cpu(rx.xid) != xd->xid +- || je32_to_cpu(rx.version) != xd->version) { +- JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, " +- "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n", +- offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK, +- je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR, +- je32_to_cpu(rx.totlen), totlen, +- je32_to_cpu(rx.xid), xd->xid, +- je32_to_cpu(rx.version), xd->version); +- xd->flags |= JFFS2_XFLAGS_INVALID; +- return JFFS2_XATTR_IS_CORRUPTED; +- } +- xd->xprefix = rx.xprefix; +- xd->name_len = rx.name_len; +- xd->value_len = je16_to_cpu(rx.value_len); +- xd->data_crc = je32_to_cpu(rx.data_crc); +- +- spin_lock(&c->erase_completion_lock); +- complete: +- for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { +- jeb = &c->blocks[ref_offset(raw) / c->sector_size]; +- totlen = PAD(ref_totlen(c, jeb, raw)); +- if (ref_flags(raw) == REF_UNCHECKED) { +- c->unchecked_size -= totlen; c->used_size += totlen; +- jeb->unchecked_size -= totlen; jeb->used_size += totlen; +- } +- raw->flash_offset = ref_offset(raw) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL); +- } +- spin_unlock(&c->erase_completion_lock); +- +- /* unchecked xdatum is chained with c->xattr_unchecked */ +- list_del_init(&xd->xindex); +- +- dbg_xattr("success on verifying xdatum (xid=%u, version=%u)\n", +- xd->xid, xd->version); +- +- return 0; +-} +- +-static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem) */ +- char *data; +- size_t readlen; +- uint32_t crc, length; +- int i, ret, retry = 0; +- +- BUG_ON(ref_flags(xd->node) != REF_PRISTINE); +- BUG_ON(!list_empty(&xd->xindex)); +- retry: +- length = xd->name_len + 1 + xd->value_len; +- data = kmalloc(length, GFP_KERNEL); +- if (!data) +- return -ENOMEM; +- +- ret = jffs2_flash_read(c, ref_offset(xd->node)+sizeof(struct jffs2_raw_xattr), +- length, &readlen, data); +- +- if (ret || length!=readlen) { +- JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%zu, at %#08x\n", +- ret, length, readlen, ref_offset(xd->node)); +- kfree(data); +- return ret ? ret : -EIO; +- } +- +- data[xd->name_len] = '\0'; +- crc = crc32(0, data, length); +- if (crc != xd->data_crc) { +- JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XATTR)" +- " at %#08x, read: 0x%08x calculated: 0x%08x\n", +- ref_offset(xd->node), xd->data_crc, crc); +- kfree(data); +- xd->flags |= JFFS2_XFLAGS_INVALID; +- return JFFS2_XATTR_IS_CORRUPTED; +- } +- +- xd->flags |= JFFS2_XFLAGS_HOT; +- xd->xname = data; +- xd->xvalue = data + xd->name_len+1; +- +- c->xdatum_mem_usage += length; +- +- xd->hashkey = xattr_datum_hashkey(xd->xprefix, xd->xname, xd->xvalue, xd->value_len); +- i = xd->hashkey % XATTRINDEX_HASHSIZE; +- list_add(&xd->xindex, &c->xattrindex[i]); +- if (!retry) { +- retry = 1; +- reclaim_xattr_datum(c); +- if (!xd->xname) +- goto retry; +- } +- +- dbg_xattr("success on loading xdatum (xid=%u, xprefix=%u, xname='%s')\n", +- xd->xid, xd->xprefix, xd->xname); +- +- return 0; +-} +- +-static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem); +- * rc < 0 : recoverable error, try again +- * rc = 0 : success +- * rc > 0 : Unrecoverable error, this node should be deleted. +- */ +- int rc = 0; +- +- BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD); +- if (xd->xname) +- return 0; +- if (xd->flags & JFFS2_XFLAGS_INVALID) +- return JFFS2_XATTR_IS_CORRUPTED; +- if (unlikely(is_xattr_datum_unchecked(c, xd))) +- rc = do_verify_xattr_datum(c, xd); +- if (!rc) +- rc = do_load_xattr_datum(c, xd); +- return rc; +-} +- +-static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_raw_xattr rx; +- struct kvec vecs[2]; +- size_t length; +- int rc, totlen; +- uint32_t phys_ofs = write_ofs(c); +- +- BUG_ON(!xd->xname); +- BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)); +- +- vecs[0].iov_base = ℞ +- vecs[0].iov_len = sizeof(rx); +- vecs[1].iov_base = xd->xname; +- vecs[1].iov_len = xd->name_len + 1 + xd->value_len; +- totlen = vecs[0].iov_len + vecs[1].iov_len; +- +- /* Setup raw-xattr */ +- memset(&rx, 0, sizeof(rx)); +- rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +- rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); +- rx.totlen = cpu_to_je32(PAD(totlen)); +- rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); +- +- rx.xid = cpu_to_je32(xd->xid); +- rx.version = cpu_to_je32(++xd->version); +- rx.xprefix = xd->xprefix; +- rx.name_len = xd->name_len; +- rx.value_len = cpu_to_je16(xd->value_len); +- rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); +- rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4)); +- +- rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0); +- if (rc || totlen != length) { +- JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n", +- rc, totlen, length, phys_ofs); +- rc = rc ? rc : -EIO; +- if (length) +- jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(totlen), NULL); +- +- return rc; +- } +- /* success */ +- jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd); +- +- dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n", +- xd->xid, xd->version, xd->xprefix, xd->xname); +- +- return 0; +-} +- +-static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, +- int xprefix, const char *xname, +- const char *xvalue, int xsize) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_xattr_datum *xd; +- uint32_t hashkey, name_len; +- char *data; +- int i, rc; +- +- /* Search xattr_datum has same xname/xvalue by index */ +- hashkey = xattr_datum_hashkey(xprefix, xname, xvalue, xsize); +- i = hashkey % XATTRINDEX_HASHSIZE; +- list_for_each_entry(xd, &c->xattrindex[i], xindex) { +- if (xd->hashkey==hashkey +- && xd->xprefix==xprefix +- && xd->value_len==xsize +- && !strcmp(xd->xname, xname) +- && !memcmp(xd->xvalue, xvalue, xsize)) { +- atomic_inc(&xd->refcnt); +- return xd; +- } +- } +- +- /* Not found, Create NEW XATTR-Cache */ +- name_len = strlen(xname); +- +- xd = jffs2_alloc_xattr_datum(); +- if (!xd) +- return ERR_PTR(-ENOMEM); +- +- data = kmalloc(name_len + 1 + xsize, GFP_KERNEL); +- if (!data) { +- jffs2_free_xattr_datum(xd); +- return ERR_PTR(-ENOMEM); +- } +- strcpy(data, xname); +- memcpy(data + name_len + 1, xvalue, xsize); +- +- atomic_set(&xd->refcnt, 1); +- xd->xid = ++c->highest_xid; +- xd->flags |= JFFS2_XFLAGS_HOT; +- xd->xprefix = xprefix; +- +- xd->hashkey = hashkey; +- xd->xname = data; +- xd->xvalue = data + name_len + 1; +- xd->name_len = name_len; +- xd->value_len = xsize; +- xd->data_crc = crc32(0, data, xd->name_len + 1 + xd->value_len); +- +- rc = save_xattr_datum(c, xd); +- if (rc) { +- kfree(xd->xname); +- jffs2_free_xattr_datum(xd); +- return ERR_PTR(rc); +- } +- +- /* Insert Hash Index */ +- i = hashkey % XATTRINDEX_HASHSIZE; +- list_add(&xd->xindex, &c->xattrindex[i]); +- +- c->xdatum_mem_usage += (xd->name_len + 1 + xd->value_len); +- reclaim_xattr_datum(c); +- +- return xd; +-} +- +-static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem) */ +- if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) { +- unload_xattr_datum(c, xd); +- xd->flags |= JFFS2_XFLAGS_DEAD; +- if (xd->node == (void *)xd) { +- BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID)); +- jffs2_free_xattr_datum(xd); +- } else { +- list_add(&xd->xindex, &c->xattr_dead_list); +- } +- spin_unlock(&c->erase_completion_lock); +- +- dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", +- xd->xid, xd->version); +- } +-} +- +-/* -------- xref related functions ------------------ +- * verify_xattr_ref(c, ref) +- * is used to load xref information from medium. Because summary data does not +- * contain xid/ino, it's necessary to verify once while mounting process. +- * save_xattr_ref(c, ref) +- * is used to write xref to medium. If delete marker is marked, it write +- * a delete marker of xref into medium. +- * create_xattr_ref(c, ic, xd) +- * is used to create a new xref and write to medium. +- * delete_xattr_ref(c, ref) +- * is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER, +- * and allows GC to reclaim those physical nodes. +- * jffs2_xattr_delete_inode(c, ic) +- * is called to remove xrefs related to obsolete inode when inode is unlinked. +- * jffs2_xattr_free_inode(c, ic) +- * is called to release xattr related objects when unmounting. +- * check_xattr_ref_inode(c, ic) +- * is used to confirm inode does not have duplicate xattr name/value pair. +- * jffs2_xattr_do_crccheck_inode(c, ic) +- * is used to force xattr data integrity check during the initial gc scan. +- * -------------------------------------------------- */ +-static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +-{ +- struct jffs2_eraseblock *jeb; +- struct jffs2_raw_node_ref *raw; +- struct jffs2_raw_xref rr; +- size_t readlen; +- uint32_t crc, offset, totlen; +- int rc; +- +- spin_lock(&c->erase_completion_lock); +- if (ref_flags(ref->node) != REF_UNCHECKED) +- goto complete; +- offset = ref_offset(ref->node); +- spin_unlock(&c->erase_completion_lock); +- +- rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr); +- if (rc || sizeof(rr) != readlen) { +- JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n", +- rc, sizeof(rr), readlen, offset); +- return rc ? rc : -EIO; +- } +- /* obsolete node */ +- crc = crc32(0, &rr, sizeof(rr) - 4); +- if (crc != je32_to_cpu(rr.node_crc)) { +- JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", +- offset, je32_to_cpu(rr.node_crc), crc); +- return JFFS2_XATTR_IS_CORRUPTED; +- } +- if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK +- || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF +- || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) { +- JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, " +- "nodetype=%#04x/%#04x, totlen=%u/%zu\n", +- offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, +- je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, +- je32_to_cpu(rr.totlen), PAD(sizeof(rr))); +- return JFFS2_XATTR_IS_CORRUPTED; +- } +- ref->ino = je32_to_cpu(rr.ino); +- ref->xid = je32_to_cpu(rr.xid); +- ref->xseqno = je32_to_cpu(rr.xseqno); +- if (ref->xseqno > c->highest_xseqno) +- c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER); +- +- spin_lock(&c->erase_completion_lock); +- complete: +- for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) { +- jeb = &c->blocks[ref_offset(raw) / c->sector_size]; +- totlen = PAD(ref_totlen(c, jeb, raw)); +- if (ref_flags(raw) == REF_UNCHECKED) { +- c->unchecked_size -= totlen; c->used_size += totlen; +- jeb->unchecked_size -= totlen; jeb->used_size += totlen; +- } +- raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL); +- } +- spin_unlock(&c->erase_completion_lock); +- +- dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n", +- ref->ino, ref->xid, ref_offset(ref->node)); +- return 0; +-} +- +-static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_raw_xref rr; +- size_t length; +- uint32_t xseqno, phys_ofs = write_ofs(c); +- int ret; +- +- rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +- rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); +- rr.totlen = cpu_to_je32(PAD(sizeof(rr))); +- rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4)); +- +- xseqno = (c->highest_xseqno += 2); +- if (is_xattr_ref_dead(ref)) { +- xseqno |= XREF_DELETE_MARKER; +- rr.ino = cpu_to_je32(ref->ino); +- rr.xid = cpu_to_je32(ref->xid); +- } else { +- rr.ino = cpu_to_je32(ref->ic->ino); +- rr.xid = cpu_to_je32(ref->xd->xid); +- } +- rr.xseqno = cpu_to_je32(xseqno); +- rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4)); +- +- ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr); +- if (ret || sizeof(rr) != length) { +- JFFS2_WARNING("jffs2_flash_write() returned %d, request=%zu, retlen=%zu, at %#08x\n", +- ret, sizeof(rr), length, phys_ofs); +- ret = ret ? ret : -EIO; +- if (length) +- jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(sizeof(rr)), NULL); +- +- return ret; +- } +- /* success */ +- ref->xseqno = xseqno; +- jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref); +- +- dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid); +- +- return 0; +-} +- +-static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, +- struct jffs2_xattr_datum *xd) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_xattr_ref *ref; +- int ret; +- +- ref = jffs2_alloc_xattr_ref(); +- if (!ref) +- return ERR_PTR(-ENOMEM); +- ref->ic = ic; +- ref->xd = xd; +- +- ret = save_xattr_ref(c, ref); +- if (ret) { +- jffs2_free_xattr_ref(ref); +- return ERR_PTR(ret); +- } +- +- /* Chain to inode */ +- ref->next = ic->xref; +- ic->xref = ref; +- +- return ref; /* success */ +-} +- +-static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +-{ +- /* must be called under down_write(xattr_sem) */ +- struct jffs2_xattr_datum *xd; +- +- xd = ref->xd; +- ref->xseqno |= XREF_DELETE_MARKER; +- ref->ino = ref->ic->ino; +- ref->xid = ref->xd->xid; +- spin_lock(&c->erase_completion_lock); +- ref->next = c->xref_dead_list; +- c->xref_dead_list = ref; +- spin_unlock(&c->erase_completion_lock); +- +- dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n", +- ref->ino, ref->xid, ref->xseqno); +- +- unrefer_xattr_datum(c, xd); +-} +- +-void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +-{ +- /* It's called from jffs2_evict_inode() on inode removing. +- When an inode with XATTR is removed, those XATTRs must be removed. */ +- struct jffs2_xattr_ref *ref, *_ref; +- +- if (!ic || ic->pino_nlink > 0) +- return; +- +- down_write(&c->xattr_sem); +- for (ref = ic->xref; ref; ref = _ref) { +- _ref = ref->next; +- delete_xattr_ref(c, ref); +- } +- ic->xref = NULL; +- up_write(&c->xattr_sem); +-} +- +-void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +-{ +- /* It's called from jffs2_free_ino_caches() until unmounting FS. */ +- struct jffs2_xattr_datum *xd; +- struct jffs2_xattr_ref *ref, *_ref; +- +- down_write(&c->xattr_sem); +- for (ref = ic->xref; ref; ref = _ref) { +- _ref = ref->next; +- xd = ref->xd; +- if (atomic_dec_and_test(&xd->refcnt)) { +- unload_xattr_datum(c, xd); +- jffs2_free_xattr_datum(xd); +- } +- jffs2_free_xattr_ref(ref); +- } +- ic->xref = NULL; +- up_write(&c->xattr_sem); +-} +- +-static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +-{ +- /* success of check_xattr_ref_inode() means that inode (ic) dose not have +- * duplicate name/value pairs. If duplicate name/value pair would be found, +- * one will be removed. +- */ +- struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp; +- int rc = 0; +- +- if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED)) +- return 0; +- down_write(&c->xattr_sem); +- retry: +- rc = 0; +- for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { +- if (!ref->xd->xname) { +- rc = load_xattr_datum(c, ref->xd); +- if (unlikely(rc > 0)) { +- *pref = ref->next; +- delete_xattr_ref(c, ref); +- goto retry; +- } else if (unlikely(rc < 0)) +- goto out; +- } +- for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) { +- if (!cmp->xd->xname) { +- ref->xd->flags |= JFFS2_XFLAGS_BIND; +- rc = load_xattr_datum(c, cmp->xd); +- ref->xd->flags &= ~JFFS2_XFLAGS_BIND; +- if (unlikely(rc > 0)) { +- *pcmp = cmp->next; +- delete_xattr_ref(c, cmp); +- goto retry; +- } else if (unlikely(rc < 0)) +- goto out; +- } +- if (ref->xd->xprefix == cmp->xd->xprefix +- && !strcmp(ref->xd->xname, cmp->xd->xname)) { +- if (ref->xseqno > cmp->xseqno) { +- *pcmp = cmp->next; +- delete_xattr_ref(c, cmp); +- } else { +- *pref = ref->next; +- delete_xattr_ref(c, ref); +- } +- goto retry; +- } +- } +- } +- ic->flags |= INO_FLAGS_XATTR_CHECKED; +- out: +- up_write(&c->xattr_sem); +- +- return rc; +-} +- +-void jffs2_xattr_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +-{ +- check_xattr_ref_inode(c, ic); +-} +- +-/* -------- xattr subsystem functions --------------- +- * jffs2_init_xattr_subsystem(c) +- * is used to initialize semaphore and list_head, and some variables. +- * jffs2_find_xattr_datum(c, xid) +- * is used to lookup xdatum while scanning process. +- * jffs2_clear_xattr_subsystem(c) +- * is used to release any xattr related objects. +- * jffs2_build_xattr_subsystem(c) +- * is used to associate xdatum and xref while super block building process. +- * jffs2_setup_xattr_datum(c, xid, version) +- * is used to insert xdatum while scanning process. +- * -------------------------------------------------- */ +-void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c) +-{ +- int i; +- +- for (i=0; i < XATTRINDEX_HASHSIZE; i++) +- INIT_LIST_HEAD(&c->xattrindex[i]); +- INIT_LIST_HEAD(&c->xattr_unchecked); +- INIT_LIST_HEAD(&c->xattr_dead_list); +- c->xref_dead_list = NULL; +- c->xref_temp = NULL; +- +- init_rwsem(&c->xattr_sem); +- c->highest_xid = 0; +- c->highest_xseqno = 0; +- c->xdatum_mem_usage = 0; +- c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */ +-} +- +-static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid) +-{ +- struct jffs2_xattr_datum *xd; +- int i = xid % XATTRINDEX_HASHSIZE; +- +- /* It's only used in scanning/building process. */ +- BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING))); +- +- list_for_each_entry(xd, &c->xattrindex[i], xindex) { +- if (xd->xid==xid) +- return xd; +- } +- return NULL; +-} +- +-void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) +-{ +- struct jffs2_xattr_datum *xd, *_xd; +- struct jffs2_xattr_ref *ref, *_ref; +- int i; +- +- for (ref=c->xref_temp; ref; ref = _ref) { +- _ref = ref->next; +- jffs2_free_xattr_ref(ref); +- } +- +- for (ref=c->xref_dead_list; ref; ref = _ref) { +- _ref = ref->next; +- jffs2_free_xattr_ref(ref); +- } +- +- for (i=0; i < XATTRINDEX_HASHSIZE; i++) { +- list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { +- list_del(&xd->xindex); +- kfree(xd->xname); +- jffs2_free_xattr_datum(xd); +- } +- } +- +- list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) { +- list_del(&xd->xindex); +- jffs2_free_xattr_datum(xd); +- } +- list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { +- list_del(&xd->xindex); +- jffs2_free_xattr_datum(xd); +- } +-} +- +-#define XREF_TMPHASH_SIZE (128) +-void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) +-{ +- struct jffs2_xattr_ref *ref, *_ref; +- struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE]; +- struct jffs2_xattr_datum *xd, *_xd; +- struct jffs2_inode_cache *ic; +- struct jffs2_raw_node_ref *raw; +- int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0; +- int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0; +- +- BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); +- +- /* Phase.1 : Merge same xref */ +- for (i=0; i < XREF_TMPHASH_SIZE; i++) +- xref_tmphash[i] = NULL; +- for (ref=c->xref_temp; ref; ref=_ref) { +- struct jffs2_xattr_ref *tmp; +- +- _ref = ref->next; +- if (ref_flags(ref->node) != REF_PRISTINE) { +- if (verify_xattr_ref(c, ref)) { +- BUG_ON(ref->node->next_in_ino != (void *)ref); +- ref->node->next_in_ino = NULL; +- jffs2_mark_node_obsolete(c, ref->node); +- jffs2_free_xattr_ref(ref); +- continue; +- } +- } +- +- i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE; +- for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) { +- if (tmp->ino == ref->ino && tmp->xid == ref->xid) +- break; +- } +- if (tmp) { +- raw = ref->node; +- if (ref->xseqno > tmp->xseqno) { +- tmp->xseqno = ref->xseqno; +- raw->next_in_ino = tmp->node; +- tmp->node = raw; +- } else { +- raw->next_in_ino = tmp->node->next_in_ino; +- tmp->node->next_in_ino = raw; +- } +- jffs2_free_xattr_ref(ref); +- continue; +- } else { +- ref->next = xref_tmphash[i]; +- xref_tmphash[i] = ref; +- } +- } +- c->xref_temp = NULL; +- +- /* Phase.2 : Bind xref with inode_cache and xattr_datum */ +- for (i=0; i < XREF_TMPHASH_SIZE; i++) { +- for (ref=xref_tmphash[i]; ref; ref=_ref) { +- xref_count++; +- _ref = ref->next; +- if (is_xattr_ref_dead(ref)) { +- ref->next = c->xref_dead_list; +- c->xref_dead_list = ref; +- xref_dead_count++; +- continue; +- } +- /* At this point, ref->xid and ref->ino contain XID and inode number. +- ref->xd and ref->ic are not valid yet. */ +- xd = jffs2_find_xattr_datum(c, ref->xid); +- ic = jffs2_get_ino_cache(c, ref->ino); +- if (!xd || !ic || !ic->pino_nlink) { +- dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", +- ref->ino, ref->xid, ref->xseqno); +- ref->xseqno |= XREF_DELETE_MARKER; +- ref->next = c->xref_dead_list; +- c->xref_dead_list = ref; +- xref_orphan_count++; +- continue; +- } +- ref->xd = xd; +- ref->ic = ic; +- atomic_inc(&xd->refcnt); +- ref->next = ic->xref; +- ic->xref = ref; +- } +- } +- +- /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */ +- for (i=0; i < XATTRINDEX_HASHSIZE; i++) { +- list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { +- xdatum_count++; +- list_del_init(&xd->xindex); +- if (!atomic_read(&xd->refcnt)) { +- dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n", +- xd->xid, xd->version); +- xd->flags |= JFFS2_XFLAGS_DEAD; +- list_add(&xd->xindex, &c->xattr_unchecked); +- xdatum_orphan_count++; +- continue; +- } +- if (is_xattr_datum_unchecked(c, xd)) { +- dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n", +- xd->xid, xd->version); +- list_add(&xd->xindex, &c->xattr_unchecked); +- xdatum_unchecked_count++; +- } +- } +- } +- /* build complete */ +- JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum" +- " (%u unchecked, %u orphan) and " +- "%u of xref (%u dead, %u orphan) found.\n", +- xdatum_count, xdatum_unchecked_count, xdatum_orphan_count, +- xref_count, xref_dead_count, xref_orphan_count); +-} +- +-struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, +- uint32_t xid, uint32_t version) +-{ +- struct jffs2_xattr_datum *xd; +- +- xd = jffs2_find_xattr_datum(c, xid); +- if (!xd) { +- xd = jffs2_alloc_xattr_datum(); +- if (!xd) +- return ERR_PTR(-ENOMEM); +- xd->xid = xid; +- xd->version = version; +- if (xd->xid > c->highest_xid) +- c->highest_xid = xd->xid; +- list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]); +- } +- return xd; +-} +- +-/* -------- xattr subsystem functions --------------- +- * xprefix_to_handler(xprefix) +- * is used to translate xprefix into xattr_handler. +- * jffs2_listxattr(dentry, buffer, size) +- * is an implementation of listxattr handler on jffs2. +- * do_jffs2_getxattr(inode, xprefix, xname, buffer, size) +- * is an implementation of getxattr handler on jffs2. +- * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags) +- * is an implementation of setxattr handler on jffs2. +- * -------------------------------------------------- */ +-const struct xattr_handler *jffs2_xattr_handlers[] = { +- &jffs2_user_xattr_handler, +-#ifdef CONFIG_JFFS2_FS_SECURITY +- &jffs2_security_xattr_handler, +-#endif +-#ifdef CONFIG_JFFS2_FS_POSIX_ACL +- &posix_acl_access_xattr_handler, +- &posix_acl_default_xattr_handler, +-#endif +- &jffs2_trusted_xattr_handler, +- NULL +-}; +- +-static const struct xattr_handler *xprefix_to_handler(int xprefix) { +- const struct xattr_handler *ret; +- +- switch (xprefix) { +- case JFFS2_XPREFIX_USER: +- ret = &jffs2_user_xattr_handler; +- break; +-#ifdef CONFIG_JFFS2_FS_SECURITY +- case JFFS2_XPREFIX_SECURITY: +- ret = &jffs2_security_xattr_handler; +- break; +-#endif +-#ifdef CONFIG_JFFS2_FS_POSIX_ACL +- case JFFS2_XPREFIX_ACL_ACCESS: +- ret = &posix_acl_access_xattr_handler; +- break; +- case JFFS2_XPREFIX_ACL_DEFAULT: +- ret = &posix_acl_default_xattr_handler; +- break; +-#endif +- case JFFS2_XPREFIX_TRUSTED: +- ret = &jffs2_trusted_xattr_handler; +- break; +- default: +- ret = NULL; +- break; +- } +- return ret; +-} +- +-ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) +-{ +- struct inode *inode = d_inode(dentry); +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_inode_cache *ic = f->inocache; +- struct jffs2_xattr_ref *ref, **pref; +- struct jffs2_xattr_datum *xd; +- const struct xattr_handler *xhandle; +- const char *prefix; +- ssize_t prefix_len, len, rc; +- int retry = 0; +- +- rc = check_xattr_ref_inode(c, ic); +- if (unlikely(rc)) +- return rc; +- +- down_read(&c->xattr_sem); +- retry: +- len = 0; +- for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { +- BUG_ON(ref->ic != ic); +- xd = ref->xd; +- if (!xd->xname) { +- /* xdatum is unchached */ +- if (!retry) { +- retry = 1; +- up_read(&c->xattr_sem); +- down_write(&c->xattr_sem); +- goto retry; +- } else { +- rc = load_xattr_datum(c, xd); +- if (unlikely(rc > 0)) { +- *pref = ref->next; +- delete_xattr_ref(c, ref); +- goto retry; +- } else if (unlikely(rc < 0)) +- goto out; +- } +- } +- xhandle = xprefix_to_handler(xd->xprefix); +- if (!xhandle || (xhandle->list && !xhandle->list(dentry))) +- continue; +- prefix = xhandle->prefix ?: xhandle->name; +- prefix_len = strlen(prefix); +- rc = prefix_len + xd->name_len + 1; +- +- if (buffer) { +- if (rc > size - len) { +- rc = -ERANGE; +- goto out; +- } +- memcpy(buffer, prefix, prefix_len); +- buffer += prefix_len; +- memcpy(buffer, xd->xname, xd->name_len); +- buffer += xd->name_len; +- *buffer++ = 0; +- } +- len += rc; +- } +- rc = len; +- out: +- if (!retry) { +- up_read(&c->xattr_sem); +- } else { +- up_write(&c->xattr_sem); +- } +- return rc; +-} +- +-int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, +- char *buffer, size_t size) +-{ +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_inode_cache *ic = f->inocache; +- struct jffs2_xattr_datum *xd; +- struct jffs2_xattr_ref *ref, **pref; +- int rc, retry = 0; +- +- rc = check_xattr_ref_inode(c, ic); +- if (unlikely(rc)) +- return rc; +- +- down_read(&c->xattr_sem); +- retry: +- for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { +- BUG_ON(ref->ic!=ic); +- +- xd = ref->xd; +- if (xd->xprefix != xprefix) +- continue; +- if (!xd->xname) { +- /* xdatum is unchached */ +- if (!retry) { +- retry = 1; +- up_read(&c->xattr_sem); +- down_write(&c->xattr_sem); +- goto retry; +- } else { +- rc = load_xattr_datum(c, xd); +- if (unlikely(rc > 0)) { +- *pref = ref->next; +- delete_xattr_ref(c, ref); +- goto retry; +- } else if (unlikely(rc < 0)) { +- goto out; +- } +- } +- } +- if (!strcmp(xname, xd->xname)) { +- rc = xd->value_len; +- if (buffer) { +- if (size < rc) { +- rc = -ERANGE; +- } else { +- memcpy(buffer, xd->xvalue, rc); +- } +- } +- goto out; +- } +- } +- rc = -ENODATA; +- out: +- if (!retry) { +- up_read(&c->xattr_sem); +- } else { +- up_write(&c->xattr_sem); +- } +- return rc; +-} +- +-int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, +- const char *buffer, size_t size, int flags) +-{ +- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_inode_cache *ic = f->inocache; +- struct jffs2_xattr_datum *xd; +- struct jffs2_xattr_ref *ref, *newref, **pref; +- uint32_t length, request; +- int rc; +- +- rc = check_xattr_ref_inode(c, ic); +- if (unlikely(rc)) +- return rc; +- +- request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size); +- rc = jffs2_reserve_space(c, request, &length, +- ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE); +- if (rc) { +- JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); +- return rc; +- } +- +- /* Find existing xattr */ +- down_write(&c->xattr_sem); +- retry: +- for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { +- xd = ref->xd; +- if (xd->xprefix != xprefix) +- continue; +- if (!xd->xname) { +- rc = load_xattr_datum(c, xd); +- if (unlikely(rc > 0)) { +- *pref = ref->next; +- delete_xattr_ref(c, ref); +- goto retry; +- } else if (unlikely(rc < 0)) +- goto out; +- } +- if (!strcmp(xd->xname, xname)) { +- if (flags & XATTR_CREATE) { +- rc = -EEXIST; +- goto out; +- } +- if (!buffer) { +- ref->ino = ic->ino; +- ref->xid = xd->xid; +- ref->xseqno |= XREF_DELETE_MARKER; +- rc = save_xattr_ref(c, ref); +- if (!rc) { +- *pref = ref->next; +- spin_lock(&c->erase_completion_lock); +- ref->next = c->xref_dead_list; +- c->xref_dead_list = ref; +- spin_unlock(&c->erase_completion_lock); +- unrefer_xattr_datum(c, xd); +- } else { +- ref->ic = ic; +- ref->xd = xd; +- ref->xseqno &= ~XREF_DELETE_MARKER; +- } +- goto out; +- } +- goto found; +- } +- } +- /* not found */ +- if (flags & XATTR_REPLACE) { +- rc = -ENODATA; +- goto out; +- } +- if (!buffer) { +- rc = -ENODATA; +- goto out; +- } +- found: +- xd = create_xattr_datum(c, xprefix, xname, buffer, size); +- if (IS_ERR(xd)) { +- rc = PTR_ERR(xd); +- goto out; +- } +- up_write(&c->xattr_sem); +- jffs2_complete_reservation(c); +- +- /* create xattr_ref */ +- request = PAD(sizeof(struct jffs2_raw_xref)); +- rc = jffs2_reserve_space(c, request, &length, +- ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE); +- down_write(&c->xattr_sem); +- if (rc) { +- JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); +- unrefer_xattr_datum(c, xd); +- up_write(&c->xattr_sem); +- return rc; +- } +- if (ref) +- *pref = ref->next; +- newref = create_xattr_ref(c, ic, xd); +- if (IS_ERR(newref)) { +- if (ref) { +- ref->next = ic->xref; +- ic->xref = ref; +- } +- rc = PTR_ERR(newref); +- unrefer_xattr_datum(c, xd); +- } else if (ref) { +- delete_xattr_ref(c, ref); +- } +- out: +- up_write(&c->xattr_sem); +- jffs2_complete_reservation(c); +- return rc; +-} +- +-/* -------- garbage collector functions ------------- +- * jffs2_garbage_collect_xattr_datum(c, xd, raw) +- * is used to move xdatum into new node. +- * jffs2_garbage_collect_xattr_ref(c, ref, raw) +- * is used to move xref into new node. +- * jffs2_verify_xattr(c) +- * is used to call do_verify_xattr_datum() before garbage collecting. +- * jffs2_release_xattr_datum(c, xd) +- * is used to release an in-memory object of xdatum. +- * jffs2_release_xattr_ref(c, ref) +- * is used to release an in-memory object of xref. +- * -------------------------------------------------- */ +-int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, +- struct jffs2_raw_node_ref *raw) +-{ +- uint32_t totlen, length, old_ofs; +- int rc = 0; +- +- down_write(&c->xattr_sem); +- if (xd->node != raw) +- goto out; +- if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)) +- goto out; +- +- rc = load_xattr_datum(c, xd); +- if (unlikely(rc)) { +- rc = (rc > 0) ? 0 : rc; +- goto out; +- } +- old_ofs = ref_offset(xd->node); +- totlen = PAD(sizeof(struct jffs2_raw_xattr) +- + xd->name_len + 1 + xd->value_len); +- rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE); +- if (rc) { +- JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen); +- goto out; +- } +- rc = save_xattr_datum(c, xd); +- if (!rc) +- dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n", +- xd->xid, xd->version, old_ofs, ref_offset(xd->node)); +- out: +- if (!rc) +- jffs2_mark_node_obsolete(c, raw); +- up_write(&c->xattr_sem); +- return rc; +-} +- +-int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, +- struct jffs2_raw_node_ref *raw) +-{ +- uint32_t totlen, length, old_ofs; +- int rc = 0; +- +- down_write(&c->xattr_sem); +- BUG_ON(!ref->node); +- +- if (ref->node != raw) +- goto out; +- if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref)) +- goto out; +- +- old_ofs = ref_offset(ref->node); +- totlen = ref_totlen(c, c->gcblock, ref->node); +- +- rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE); +- if (rc) { +- JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n", +- __func__, rc, totlen); +- goto out; +- } +- rc = save_xattr_ref(c, ref); +- if (!rc) +- dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n", +- ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node)); +- out: +- if (!rc) +- jffs2_mark_node_obsolete(c, raw); +- up_write(&c->xattr_sem); +- return rc; +-} +- +-int jffs2_verify_xattr(struct jffs2_sb_info *c) +-{ +- struct jffs2_xattr_datum *xd, *_xd; +- struct jffs2_eraseblock *jeb; +- struct jffs2_raw_node_ref *raw; +- uint32_t totlen; +- int rc; +- +- down_write(&c->xattr_sem); +- list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { +- rc = do_verify_xattr_datum(c, xd); +- if (rc < 0) +- continue; +- list_del_init(&xd->xindex); +- spin_lock(&c->erase_completion_lock); +- for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { +- if (ref_flags(raw) != REF_UNCHECKED) +- continue; +- jeb = &c->blocks[ref_offset(raw) / c->sector_size]; +- totlen = PAD(ref_totlen(c, jeb, raw)); +- c->unchecked_size -= totlen; c->used_size += totlen; +- jeb->unchecked_size -= totlen; jeb->used_size += totlen; +- raw->flash_offset = ref_offset(raw) +- | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL); +- } +- if (xd->flags & JFFS2_XFLAGS_DEAD) +- list_add(&xd->xindex, &c->xattr_dead_list); +- spin_unlock(&c->erase_completion_lock); +- } +- up_write(&c->xattr_sem); +- return list_empty(&c->xattr_unchecked) ? 1 : 0; +-} +- +-void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +-{ +- /* must be called under spin_lock(&c->erase_completion_lock) */ +- if (atomic_read(&xd->refcnt) || xd->node != (void *)xd) +- return; +- +- list_del(&xd->xindex); +- jffs2_free_xattr_datum(xd); +-} +- +-void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +-{ +- /* must be called under spin_lock(&c->erase_completion_lock) */ +- struct jffs2_xattr_ref *tmp, **ptmp; +- +- if (ref->node != (void *)ref) +- return; +- +- for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) { +- if (ref == tmp) { +- *ptmp = tmp->next; +- break; +- } +- } +- jffs2_free_xattr_ref(ref); +-} +diff -Nupr old/fs/jffs2/xattr.h new/fs/jffs2/xattr.h +--- old/fs/jffs2/xattr.h 2022-05-09 17:22:53.000000000 +0800 ++++ new/fs/jffs2/xattr.h 2022-05-09 20:04:55.580000000 +0800 +@@ -12,7 +12,6 @@ + #ifndef _JFFS2_FS_XATTR_H_ + #define _JFFS2_FS_XATTR_H_ + +-#include + #include + + #define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ +@@ -48,7 +47,7 @@ struct jffs2_xattr_ref + struct jffs2_raw_node_ref *node; + uint8_t class; + uint8_t flags; /* Currently unused */ +- u16 unused; ++ uint16_t unused; + + uint32_t xseqno; + union { +@@ -89,16 +88,14 @@ extern int jffs2_verify_xattr(struct jff + extern void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd); + extern void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref); + +-extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, +- char *buffer, size_t size); +-extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, +- const char *buffer, size_t size, int flags); +- + extern const struct xattr_handler *jffs2_xattr_handlers[]; + extern const struct xattr_handler jffs2_user_xattr_handler; + extern const struct xattr_handler jffs2_trusted_xattr_handler; + + extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); ++#define jffs2_getxattr generic_getxattr ++#define jffs2_setxattr generic_setxattr ++#define jffs2_removexattr generic_removexattr + + #else + +@@ -113,12 +110,13 @@ extern ssize_t jffs2_listxattr(struct de + + #define jffs2_xattr_handlers NULL + #define jffs2_listxattr NULL ++#define jffs2_getxattr NULL ++#define jffs2_setxattr NULL ++#define jffs2_removexattr NULL + + #endif /* CONFIG_JFFS2_FS_XATTR */ + + #ifdef CONFIG_JFFS2_FS_SECURITY +-extern int jffs2_init_security(struct inode *inode, struct inode *dir, +- const struct qstr *qstr); + extern const struct xattr_handler jffs2_security_xattr_handler; + #else + #define jffs2_init_security(inode,dir,qstr) (0) +diff -Nupr old/fs/jffs2/xattr_trusted.c new/fs/jffs2/xattr_trusted.c +--- old/fs/jffs2/xattr_trusted.c 2022-05-09 17:15:24.360000000 +0800 ++++ new/fs/jffs2/xattr_trusted.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,46 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2006 NEC Corporation +- * +- * Created by KaiGai Kohei +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "nodelist.h" +- +-static int jffs2_trusted_getxattr(const struct xattr_handler *handler, +- struct dentry *unused, struct inode *inode, +- const char *name, void *buffer, size_t size) +-{ +- return do_jffs2_getxattr(inode, JFFS2_XPREFIX_TRUSTED, +- name, buffer, size); +-} +- +-static int jffs2_trusted_setxattr(const struct xattr_handler *handler, +- struct dentry *unused, struct inode *inode, +- const char *name, const void *buffer, +- size_t size, int flags) +-{ +- return do_jffs2_setxattr(inode, JFFS2_XPREFIX_TRUSTED, +- name, buffer, size, flags); +-} +- +-static bool jffs2_trusted_listxattr(struct dentry *dentry) +-{ +- return capable(CAP_SYS_ADMIN); +-} +- +-const struct xattr_handler jffs2_trusted_xattr_handler = { +- .prefix = XATTR_TRUSTED_PREFIX, +- .list = jffs2_trusted_listxattr, +- .set = jffs2_trusted_setxattr, +- .get = jffs2_trusted_getxattr +-}; +diff -Nupr old/fs/jffs2/xattr_user.c new/fs/jffs2/xattr_user.c +--- old/fs/jffs2/xattr_user.c 2022-05-09 17:15:24.360000000 +0800 ++++ new/fs/jffs2/xattr_user.c 1970-01-01 08:00:00.000000000 +0800 +@@ -1,40 +0,0 @@ +-/* +- * JFFS2 -- Journalling Flash File System, Version 2. +- * +- * Copyright © 2006 NEC Corporation +- * +- * Created by KaiGai Kohei +- * +- * For licensing information, see the file 'LICENCE' in this directory. +- * +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "nodelist.h" +- +-static int jffs2_user_getxattr(const struct xattr_handler *handler, +- struct dentry *unused, struct inode *inode, +- const char *name, void *buffer, size_t size) +-{ +- return do_jffs2_getxattr(inode, JFFS2_XPREFIX_USER, +- name, buffer, size); +-} +- +-static int jffs2_user_setxattr(const struct xattr_handler *handler, +- struct dentry *unused, struct inode *inode, +- const char *name, const void *buffer, +- size_t size, int flags) +-{ +- return do_jffs2_setxattr(inode, JFFS2_XPREFIX_USER, +- name, buffer, size, flags); +-} +- +-const struct xattr_handler jffs2_user_xattr_handler = { +- .prefix = XATTR_USER_PREFIX, +- .set = jffs2_user_setxattr, +- .get = jffs2_user_getxattr +-}; diff --git a/zzz/git/push.sh b/zzz/git/push.sh index e55c20971f3965722f504590a14456970746d203..86a8ae2022397ca5dfc642c5b34f1fc9c9a0a6a8 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,5 +1,5 @@ git add -A -git commit -m ' 上传百篇博客离线文档 +git commit -m ' 同步官方代码,增加 jffs2 编译选项 鸿蒙研究站 | http://weharmonyos.com (国内) | https://weharmony.github.io (国外) 论坛 | http://bbs.weharmonyos.com