2023-06-21 17:19:43 +08:00
|
|
|
From 30f82ef48ed60def1ce9169d8b365b85384d2d83 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: fanglinxu <fanglinxu@huawei.com>
|
|
|
|
|
Date: Wed, 21 Jun 2023 16:42:01 +0800
|
2022-12-16 09:40:14 +08:00
|
|
|
Subject: [PATCH] add powersafe
|
|
|
|
|
|
2023-06-21 17:19:43 +08:00
|
|
|
Signed-off-by: fanglinxu <fanglinxu@huawei.com>
|
2022-12-16 09:40:14 +08:00
|
|
|
---
|
2023-06-21 17:19:43 +08:00
|
|
|
yaffs_guts.c | 40 +++++++++++
|
2022-12-16 09:40:14 +08:00
|
|
|
yaffs_guts.h | 46 ++++++++++++
|
|
|
|
|
yaffs_powersafe.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
yaffs_trace.h | 1 +
|
|
|
|
|
yaffs_vfs_multi.c | 65 ++++++++++++++++-
|
|
|
|
|
yaffs_yaffs2.c | 12 ++++
|
2023-06-21 17:19:43 +08:00
|
|
|
6 files changed, 343 insertions(+), 1 deletion(-)
|
2022-12-16 09:40:14 +08:00
|
|
|
create mode 100644 yaffs_powersafe.c
|
|
|
|
|
|
|
|
|
|
diff --git a/yaffs_guts.c b/yaffs_guts.c
|
2023-06-21 17:19:43 +08:00
|
|
|
index b83fa63..be298b2 100644
|
2022-12-16 09:40:14 +08:00
|
|
|
--- a/yaffs_guts.c
|
|
|
|
|
+++ b/yaffs_guts.c
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -4579,6 +4579,34 @@ int yaffs_guts_format_dev(struct yaffs_dev *dev)
|
2022-12-16 09:40:14 +08:00
|
|
|
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);
|
|
|
|
|
+}
|
2023-06-21 17:19:43 +08:00
|
|
|
+
|
2022-12-16 09:40:14 +08:00
|
|
|
+#endif
|
2023-06-21 17:19:43 +08:00
|
|
|
+
|
|
|
|
|
/*
|
|
|
|
|
* 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)
|
2022-12-16 09:40:14 +08:00
|
|
|
!yaffs_summary_init(dev))
|
|
|
|
|
init_failed = 1;
|
|
|
|
|
|
|
|
|
|
+#ifdef CONFIG_POWERSAFE
|
2023-06-21 17:19:43 +08:00
|
|
|
+ init_power_safe(dev);
|
2022-12-16 09:40:14 +08:00
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
if (!init_failed) {
|
|
|
|
|
/* Now scan the flash. */
|
|
|
|
|
if (dev->param.is_yaffs2) {
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -4802,6 +4834,13 @@ int yaffs_guts_initialise(struct yaffs_dev *dev)
|
2022-12-16 09:40:14 +08:00
|
|
|
if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
|
|
|
|
|
yaffs2_checkpt_invalidate(dev);
|
|
|
|
|
|
|
|
|
|
+#ifdef CONFIG_POWERSAFE
|
2023-06-21 17:19:43 +08:00
|
|
|
+ yaffs_sort_powersafe_block(dev);
|
|
|
|
|
+ yaffs_powersafe_read_buffer(dev);
|
|
|
|
|
+ yaffs_powersafe_invalied(dev);
|
2022-12-16 09:40:14 +08:00
|
|
|
+
|
2023-06-21 17:19:43 +08:00
|
|
|
+ yaffs_trace(YAFFS_TRACE_POWER, "yaffs: dev->blocks_in_powersafe %d", dev->blocks_in_powersafe);
|
2022-12-16 09:40:14 +08:00
|
|
|
+#endif
|
|
|
|
|
yaffs_trace(YAFFS_TRACE_TRACING,
|
|
|
|
|
"yaffs: yaffs_guts_initialise() done.");
|
|
|
|
|
return YAFFS_OK;
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -5033,3 +5072,4 @@ void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
|
2022-12-16 09:40:14 +08:00
|
|
|
bs[s]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
+
|
|
|
|
|
diff --git a/yaffs_guts.h b/yaffs_guts.h
|
2023-06-21 17:19:43 +08:00
|
|
|
index 74ded0b..8b55133 100644
|
2022-12-16 09:40:14 +08:00
|
|
|
--- 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
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -288,6 +295,10 @@ enum yaffs_block_state {
|
2022-12-16 09:40:14 +08:00
|
|
|
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 */
|
|
|
|
|
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -548,6 +559,9 @@ struct yaffs_param {
|
2022-12-16 09:40:14 +08:00
|
|
|
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.
|
|
|
|
|
*/
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -707,6 +721,17 @@ struct yaffs_dev {
|
2022-12-16 09:40:14 +08:00
|
|
|
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 */
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -895,6 +920,18 @@ struct yaffs_xattr_mod {
|
2022-12-16 09:40:14 +08:00
|
|
|
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);
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -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);
|
2022-12-16 09:40:14 +08:00
|
|
|
|
|
|
|
|
+#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
|
2023-06-21 17:19:43 +08:00
|
|
|
index a08e071..4b670e9 100644
|
2022-12-16 09:40:14 +08:00
|
|
|
--- 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
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -3035,8 +3040,12 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
|
2022-12-16 09:40:14 +08:00
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -3226,6 +3235,60 @@ static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
|
2022-12-16 09:40:14 +08:00
|
|
|
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
|
2023-06-21 17:19:43 +08:00
|
|
|
index 6be3d6a..8ee7819 100644
|
2022-12-16 09:40:14 +08:00
|
|
|
--- a/yaffs_yaffs2.c
|
|
|
|
|
+++ b/yaffs_yaffs2.c
|
2023-06-21 17:19:43 +08:00
|
|
|
@@ -1584,6 +1584,18 @@ int yaffs2_scan_backwards(struct yaffs_dev *dev)
|
2022-12-16 09:40:14 +08:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|