From 30f82ef48ed60def1ce9169d8b365b85384d2d83 Mon Sep 17 00:00:00 2001 From: fanglinxu Date: Wed, 21 Jun 2023 16:42:01 +0800 Subject: [PATCH] add powersafe Signed-off-by: fanglinxu --- yaffs_guts.c | 40 +++++++++++ yaffs_guts.h | 46 ++++++++++++ yaffs_powersafe.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++ yaffs_trace.h | 1 + yaffs_vfs_multi.c | 65 ++++++++++++++++- yaffs_yaffs2.c | 12 ++++ 6 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 yaffs_powersafe.c diff --git a/yaffs_guts.c b/yaffs_guts.c index b83fa63..be298b2 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -4579,6 +4579,34 @@ 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 + /* * If the dev is mounted r/w then the cleanup will happen during * yaffs_guts_initialise. However if the dev is mounted ro then @@ -4732,6 +4760,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) { @@ -4802,6 +4834,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; @@ -5033,3 +5072,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 74ded0b..8b55133 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 @@ -288,6 +295,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 */ @@ -548,6 +559,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. */ @@ -707,6 +721,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 */ @@ -895,6 +920,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); @@ -1081,6 +1118,15 @@ void yaffs_oh_ctime_load(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); void yaffs_oh_mtime_load(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); void yaffs_oh_atime_load(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); +#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 a08e071..4b670e9 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 @@ -3035,8 +3040,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; @@ -3226,6 +3235,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 6be3d6a..8ee7819 100644 --- a/yaffs_yaffs2.c +++ b/yaffs_yaffs2.c @@ -1584,6 +1584,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