From 012daf7beda61b25c66e233cbe27ed7732200b48 Mon Sep 17 00:00:00 2001 From: luojects Date: Fri, 16 Dec 2022 09:40:14 +0800 Subject: [PATCH] YAFFS: support powersafe powersafe: provide interface to safe powersafe data Signed-off-by: luojects --- 0001-add-powersafe.patch | 497 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 497 insertions(+) create mode 100644 0001-add-powersafe.patch diff --git a/0001-add-powersafe.patch b/0001-add-powersafe.patch new file mode 100644 index 0000000..fdb68d3 --- /dev/null +++ b/0001-add-powersafe.patch @@ -0,0 +1,497 @@ +From 9a1e3b523b552f52c90a2b451d311cefc378d29d Mon Sep 17 00:00:00 2001 +From: luojects +Date: Thu, 15 Dec 2022 20:32:08 +0800 +Subject: [PATCH] add powersafe + +--- + yaffs_guts.c | 39 ++++++++++ + yaffs_guts.h | 46 ++++++++++++ + yaffs_powersafe.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++ + yaffs_trace.h | 1 + + yaffs_vfs_multi.c | 65 ++++++++++++++++- + yaffs_yaffs2.c | 12 ++++ + 6 files changed, 342 insertions(+), 1 deletion(-) + create mode 100644 yaffs_powersafe.c + +diff --git a/yaffs_guts.c b/yaffs_guts.c +index 40a5b46..46b6c16 100644 +--- a/yaffs_guts.c ++++ b/yaffs_guts.c +@@ -4799,6 +4799,33 @@ int yaffs_guts_format_dev(struct yaffs_dev *dev) + return YAFFS_OK; + } + ++#ifdef CONFIG_POWERSAFE ++static int sort_fun(const void *a, const void *b) ++{ ++ int sort_a = *(int *)a; ++ int sort_b = *(int *)b; ++ ++ if (sort_a > sort_b) ++ return 1; ++ ++ return 0; ++} ++ ++static void yaffs_sort_powersafe_block(struct yaffs_dev *dev) ++{ ++ if (dev->blocks_in_powersafe) ++ return; ++ ++ sort(dev->powersafe_block_list, dev->blocks_in_powersafe, sizeof(int), ++ sort_fun, NULL); ++} ++ ++void yaffs2_powersafe_find_erased_block(struct yaffs_dev *dev) ++{ ++ dev->powersafe_block = yaffs_find_alloc_block(dev); ++} ++ ++#endif + + int yaffs_guts_initialise(struct yaffs_dev *dev) + { +@@ -4970,6 +4997,10 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) + !yaffs_summary_init(dev)) + init_failed = 1; + ++#ifdef CONFIG_POWERSAFE ++ init_power_safe(dev); ++#endif ++ + if (!init_failed) { + /* Now scan the flash. */ + if (dev->param.is_yaffs2) { +@@ -5043,6 +5074,13 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) + if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) + yaffs2_checkpt_invalidate(dev); + ++#ifdef CONFIG_POWERSAFE ++ yaffs_sort_powersafe_block(dev); ++ yaffs_powersafe_read_buffer(dev); ++ yaffs_powersafe_invalied(dev); ++ ++ yaffs_trace(YAFFS_TRACE_POWER, "yaffs: dev->blocks_in_powersafe %d", dev->blocks_in_powersafe); ++#endif + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: yaffs_guts_initialise() done."); + return YAFFS_OK; +@@ -5210,3 +5248,4 @@ void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]) + bs[s]++; + } + } ++ +diff --git a/yaffs_guts.h b/yaffs_guts.h +index 5ebc378..f5d47af 100644 +--- a/yaffs_guts.h ++++ b/yaffs_guts.h +@@ -28,6 +28,8 @@ + */ + #define YAFFS_MAGIC 0x5941ff53 + ++//#define CONFIG_POWERSAFE ++ + /* + * Tnodes form a tree with the tnodes in "levels" + * Levels greater than 0 hold 8 slots which point to other tnodes. +@@ -102,6 +104,11 @@ + #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 + #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 + ++#ifdef CONFIG_POWERSAFE ++#define YAFFS_OBJECTID_POWERSAFE_DATA 0x40 ++#define YAFFS_SEQUENCE_POWERSAFE_DATA 0x41 ++#endif ++ + #define YAFFS_MAX_SHORT_OP_CACHES 20 + + #define YAFFS_N_TEMP_BUFFERS 6 +@@ -281,6 +288,10 @@ enum yaffs_block_state { + YAFFS_BLOCK_STATE_CHECKPOINT, + /* This block is assigned to holding checkpoint data. */ + ++#ifdef CONFIG_POWERSAFE ++ YAFFS_BLOCK_STATE_POWERSAFE, ++#endif ++ + YAFFS_BLOCK_STATE_COLLECTING, + /* This block is being garbage collected */ + +@@ -533,6 +544,9 @@ struct yaffs_param { + u32 n_reserved_blocks; /* Tuneable so that we can reduce + * reserved blocks on NOR and RAM. */ + ++#ifdef CONFIG_POWERSAFE ++ u32 n_reserved_powersafe_blocks; ++#endif + u32 n_caches; /* If == 0, then short op caching is disabled, + * else the number of short op caches. + */ +@@ -692,6 +706,17 @@ struct yaffs_dev { + int checkpoint_blocks_required; /* Number of blocks needed to store + * current checkpoint set */ + ++#ifdef CONFIG_POWERSAFE ++ int *powersafe_block_list; ++ u8 *powersafe_buffer; ++ int powersafe_block; ++ int powersafe_cur_chunk; ++ int powersafe_byte_count; ++ int powersafe_page_seq; ++ u32 blocks_in_powersafe; ++ int powersafe_cmd_lenth; ++#endif ++ + /* Block Info */ + struct yaffs_block_info *block_info; + u8 *chunk_bits; /* bitmap of chunks in use */ +@@ -881,6 +906,18 @@ struct yaffs_xattr_mod { + int result; + }; + ++#ifdef CONFIG_POWERSAFE ++struct powersafe_data { ++ int lenth; ++ char buffer[4096]; ++} ++ ++#define CMD_POWERSAFE_DATA_WRITE _IOW('P', 1, struct powersafe_data) ++#define CMD_POWERSAFE_DATA_READ _IOR('P', 2, struct powersafe_data) ++#define CMD_POWERSAFE_DATA_GET_LENTH _IOR('P', 3, struct powersafe_data) ++#define CMD_POWERSAFE_DATA_SET_LENTH _IOR('P', 4, struct powersafe_data) ++#endif ++ + /*----------------------- YAFFS Functions -----------------------*/ + + int yaffs_guts_initialise(struct yaffs_dev *dev); +@@ -1049,6 +1086,15 @@ void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]); + int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + struct yaffs_ext_tags *tags); + ++#ifdef CONFIG_POWERSAFE ++/*modify by powersafe*/ ++int yaffs_powersafe_read_buffer(struct yaffs_dev *dev); ++void yaffs_powersafe_invalied(struct yaffs_dev *dev); ++void yaffs2_powersafe_find_erased_block(struct yaffs_dev *dev); ++long yaffs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); ++int yaffs2_powersafe_write(struct yaffs_dev *dev, int lenth); ++void init_power_safe(struct yaffs_dev *dev); ++#endif + /* + * Define LOFF_T_32_BIT if a 32-bit LOFF_T is being used. + * Not serious if you get this wrong - you might just get some warnings. +diff --git a/yaffs_powersafe.c b/yaffs_powersafe.c +new file mode 100644 +index 0000000..fec7566 +--- /dev/null ++++ b/yaffs_powersafe.c +@@ -0,0 +1,180 @@ ++#include "yportenv.h" ++#include "yaffs_trace.h" ++ ++#include "yaffs_guts.h" ++#include "yaffs_endian.h" ++#include "yaffs_getblockinfo.h" ++#include "yaffs_tagscompat.h" ++#include "yaffs_tagsmarshall.h" ++#include "yaffs_nand.h" ++#include "yaffs_yaffs2.h" ++#include "yaffs_bitmap.h" ++#include "yaffs_verify.h" ++#include "yaffs_nand.h" ++#include "yaffs_packedtags2.h" ++#include "yaffs_nameval.h" ++#include "yaffs_allocator.h" ++#include "yaffs_attribs.h" ++#include "yaffs_summary.h" ++ ++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) ++{ ++ return chunk - dev->chunk_offset; ++} ++ ++void init_power_safe(struct yaffs_dev *dev) ++{ ++ int i; ++ ++ if (dev->param.n_reserved_powersafe_blocks == 0) ++ return; ++ ++ dev->powersafe_block = -1; ++ dev->powersafe_cur_chunk = 0; ++ dev->powersafe_byte_count = 0; ++ dev->powersafe_page_seq = 0; ++ dev->blocks_in_powersafe = 0; ++ dev->powersafe_cmd_lenth = 0; ++ ++ dev->powersafe_block_list = kmalloc(sizeof(int) * dev->param.n_reserved_powersafe_blocks, GFP_NOFS); ++ if (!dev->powersafe_block_list) ++ return; ++ ++ for (i = 0; i < dev->param.n_reserved_powersafe_blocks; i++) { ++ dev->powersafe_block_list[i] = -1; ++ } ++ ++ if (!dev->powersafe_buffer) { ++ dev->powersafe_buffer = kzalloc(dev->param.n_reserved_powersafe_blocks * dev->data_bytes_per_chunk * dev->param.chunks_per_block, GFP_NOFS); ++ if (!dev->powersafe_buffer) ++ return; ++ } ++} ++ ++static int yaffs2_powersafe_write_buffer(struct yaffs_dev *dev, int n_bytes) ++{ ++ int chunk; ++ int offset_chunk; ++ struct yaffs_ext_tags tags; ++ int ret; ++ ++ u8 * buffer = kzalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); ++ ++ enum yaffs_block_state state; ++ u32 seq_number; ++ ++ yaffs_trace(YAFFS_TRACE_POWER, "write buffer %d", n_bytes); ++ ++ if (dev->powersafe_block < 0) { ++ yaffs2_powersafe_find_erased_block(dev); ++ dev->powersafe_cur_chunk = 0; ++ } ++ ++ if (dev->powersafe_block < 0) ++ return 0; ++ ++ tags.is_deleted = 0; ++ ++ tags.obj_id = dev->blocks_in_powersafe + YAFFS_OBJECTID_POWERSAFE_DATA; ++ tags.chunk_id = dev->powersafe_page_seq + 1; ++ tags.seq_number = YAFFS_SEQUENCE_POWERSAFE_DATA; ++ tags.n_bytes = n_bytes; ++ ++ if (dev->powersafe_cur_chunk == 0) { ++ struct yaffs_block_info *bi = yaffs_get_block_info(dev, dev->powersafe_block); ++ ++ bi->block_state = YAFFS_BLOCK_STATE_POWERSAFE; ++ dev->blocks_in_powersafe++; ++ } ++ ++ chunk = dev->powersafe_block * dev->param.chunks_per_block + dev->powersafe_cur_chunk; ++ offset_chunk = apply_chunk_offset(dev, chunk); ++ dev->n_page_writes++; ++ ++ yaffs_trace(YAFFS_TRACE_POWER, "power write n_bytes %d block %d cur_chunk %d offset_chunk %d", ++ n_bytes, dev->powersafe_block, dev->powersafe_cur_chunk, offset_chunk); ++ ++ ret = dev->tagger.write_chunk_tags_fn(dev, offset_chunk, dev->powersafe_buffer + dev->powersafe_byte_count, &tags); ++ dev->powersafe_byte_count += n_bytes; ++ dev->powersafe_page_seq++; ++ dev->powersafe_cur_chunk++; ++ if (dev->powersafe_cur_chunk >= (int)dev->param.chunks_per_block) { ++ dev->powersafe_cur_chunk = 0; ++ dev->powersafe_block = -1; ++ } ++ ++ dev->tagger.read_chunk_tags_fn(dev, offset_chunk, buffer, &tags); ++ yaffs_trace(YAFFS_TRACE_POWER, "power block %d oid %d seq %d eccr %d", ++ dev->powersafe_block, tags.obj_id, tags.seq_number, tags.ecc_result); ++ ++ yaffs_query_init_block_state(dev, dev->powerafe_block, &state, &seq_number); ++ yaffs_trace(YAFFS_TRACE_POWER, "block yaffs_query block %d, state %d seq %d", ++ dev->powersafe_block, state, seq_number); ++ ++ return 0; ++} ++ ++int yaffs2_powersafe_write(struct yaffs_dev *dev, int lenth) ++{ ++ int writed_lenth = 0; ++ int ret; ++ ++ while (writed_lenth < lenth){ ++ if (lenth >= dev->data_bytes_per_chunk) { ++ ret = yaffs2_powersafe_write_buffer(dev, dev->data_bytes_per_chunk); ++ writed_lenth -= dev->data_bytes_per_chunk; ++ if (writed_lenth == 0) ++ writed_lenth = lenth; ++ } else { ++ ret = yaffs2_powersafe_write_buffer(dev, lenth); ++ writed_lenth = lenth; ++ ++ } ++ } ++ ++ return 0; ++} ++ ++int yaffs_powersafe_read_buffer(struct yaffs_dev *dev) ++{ ++ int i; ++ int cur_chunk; ++ int offset_chunk; ++ struct yaffs_ext_tags tags; ++ ++ if (!dev->powersafe_block_list && dev->blocks_in_powersafe > 0) ++ return 0; ++ ++ for (i = 0; i < dev->blocks_in_powersafe && dev->powersafe_block_list[i] >= 0; i++) { ++ for (cur_chunk = 0; cur_chunk < dev->param.chunks_per_block; cur_chunk++) { ++ chunk = dev->powersafe_block_list[i] * dev->param.chunks_per_block + cur_chunk; ++ offset_chunk = apply_chunk_offset(dev, chunk); ++ ++ dev->tagger.read_chunk_tags_fn(dev, offset_chunk, dev->powersafe_buffer + dev->powersafe_byte_count, &tags); ++ ++ yaffs_trace(YAFFS_TRACE_POWER, "power read block %d, cur_chunk %d offset_chunk %d seq %d tags.n_bytes %d", ++ dev->powersafe_block_list[i], cur_chunk, offset_chunk, tags.seq_number, tags.n_bytes); ++ ++ if (tags.n_bytes < dev->data_bytes_per_chunk) ++ break; ++ } ++ ++ } ++ ++ return 0; ++} ++ ++void yaffs_powersafe_invalied(struct yaffs_dev *dev) ++{ ++ struct yaffs_block_info *bi; ++ int i; ++ ++ if (!dev->powersafe_block_list && dev->blocks_in_powersafe > 0) ++ return; ++ ++ for (i = 0; i < dev->blocks_in_powersafe && dev->powersafe_block_list[i] >= 0; i++) { ++ bi = yaffs_get_block_info(dev, dev->powersafe_block_list[i]); ++ bi->block_state = YAFFS_BLOCK_STATE_FULL; ++ yaffs_block_became_dirty(dev, dev->powersafe_block_list[i]); ++ } ++} +diff --git a/yaffs_trace.h b/yaffs_trace.h +index 5a6aeed..4ee0357 100644 +--- a/yaffs_trace.h ++++ b/yaffs_trace.h +@@ -42,6 +42,7 @@ extern unsigned int yaffs_wr_attempts; + #define YAFFS_TRACE_VERIFY 0x00010000 + #define YAFFS_TRACE_VERIFY_NAND 0x00020000 + #define YAFFS_TRACE_VERIFY_FULL 0x00040000 ++#define YAFFS_TRACE_POWER 0x00080000 + #define YAFFS_TRACE_VERIFY_ALL 0x000f0000 + + #define YAFFS_TRACE_SYNC 0x00100000 +diff --git a/yaffs_vfs_multi.c b/yaffs_vfs_multi.c +index a36d9bf..35d3e71 100644 +--- a/yaffs_vfs_multi.c ++++ b/yaffs_vfs_multi.c +@@ -828,6 +828,11 @@ static const struct file_operations yaffs_file_operations = { + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, + .splice_read = generic_file_splice_read, ++ ++#ifdef CONFIG_POWERSAFE ++ .unlocked_ioctl = yaffs2_ioctl, ++#endif ++ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) + .splice_write = iter_file_splice_write, + #else +@@ -3026,8 +3031,12 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version, + + /* Set up the memory size parameters.... */ + +- ++#ifdef CONFIG_POWERSAFE ++ param->n_reserved_powersafe_blocks = 5; ++ param->n_reserved_blocks += param->n_reserved_powersafe_blocks + 5; ++#else + param->n_reserved_blocks = 5; ++#endif + param->n_caches = (options.no_cache) ? 0 : 10; + param->inband_tags = inband_tags; + +@@ -3217,6 +3226,60 @@ static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, + FS_REQUIRES_DEV); + #endif + ++#ifdef CONFIG_POWERSAFE ++long yaffs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ long ret = 0; ++ struct yaffs_obj *obj; ++ int n_written, ipos; ++ struct inode *inode; ++ struct yaffs_dev *dev; ++ int lenth; ++ struct powersafe_data data; ++ unsigned long addr; ++ ++ obj = yaffs_dentry_to_obj(Y_GET_DENTRY(filp)); ++ if (!obj) { ++ return -EINVAL; ++ } ++ ++ dev = obj->my_dev; ++ yaffs_gross_lock(dev); ++ ++ switch(cmd) { ++ case CMD_POWERSAFE_DATA_WRITE: ++ if (copy_from_user(&data, arg, sizeof(struct powersafe_data))) { ++ yaffs_gross_unlock(dev); ++ return -EFAULT; ++ } ++ ++ dev->powersafe_cmd_lenth = data.lenth; ++ memcpy(dev->powersafe_buffer, data.buffer, data.lenth); ++ yaffs2_powersafe_write(dev, dev->powersafe_cmd_lenth); ++ break; ++ case CMD_POWERSAFE_DATA_READ: ++ memset(data.buffer, 0 , 4096); ++ data.lenth = dev->powersafe_byte_count; ++ if (data.lenth == 0){ ++ yaffs_gross_unlock(dev); ++ return -ENOENT; ++ } ++ memcpy(data.buffer, dev->powersafe_buffer, data.lenth); ++ if (copy_to_user(arg, &data, data.lenth)) { ++ yaffs_gross_unlock(dev); ++ return -EFAULT; ++ } ++ break; ++ default: ++ yaffs_gross_unlock(dev); ++ return -EINVAL; ++ ++ } ++ ++ yaffs_gross_unlock(dev); ++ return ret; ++} ++#endif + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) + static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, +diff --git a/yaffs_yaffs2.c b/yaffs_yaffs2.c +index 9eb42f7..6d66e70 100644 +--- a/yaffs_yaffs2.c ++++ b/yaffs_yaffs2.c +@@ -1582,6 +1582,18 @@ int yaffs2_scan_backwards(struct yaffs_dev *dev) + + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; ++#ifdef CONFIG_POWERSAFE ++ if (bi->seq_number == YAFFS_SEQUENCE_POWERSAFE_DATA) { ++ bi->block_state = YAFFS_BLOCK_STATE_POWERSAFE; ++ if (dev->powersafe_block_list) { ++ dev->powersafe_block_list[dev->blocks_in_powersafe] = blk; ++ } ++ ++ dev->blocks_in_powersafe++; ++ yaffs_trace(YAFFS_TRACE_POWER, "block power block %d state %d seq %d", ++ blk, bi->block_state, seq_number); ++ } ++#endif + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + +-- +2.34.1 +