summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src
diff options
context:
space:
mode:
authorKinsey Moore <kinsey.moore@oarcorp.com>2019-10-04 16:11:30 -0500
committerJoel Sherrill <joel@rtems.org>2023-03-15 13:29:12 -0500
commit5db68a5859e2ec04b6e49ed2a04243a1b78358eb (patch)
tree35c3799d588865447b4b18e0cab0c76a8f2e7249 /cpukit/libfs/src
parentcpukit/jffs2: Import wbuf.c from upstream (diff)
downloadrtems-5db68a5859e2ec04b6e49ed2a04243a1b78358eb.tar.bz2
cpukit/jffs2: Add support for NAND under JFFS2
This adds write buffer and bad block support required for JFFS2 operation on NAND devices. This also adds the minor modifications necessary for RTEMS support in the Linux header stubs and in wbuf.c. Memory and NOR backed applications should experience no difference in operation since they do not expose the callbacks required for write buffer support.
Diffstat (limited to 'cpukit/libfs/src')
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/fs.h3
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/jiffies.h1
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/list.h8
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h37
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h26
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/mutex.h33
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/rwsem.h16
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/slab.h1
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/workqueue.h28
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/writeback.h1
-rw-r--r--cpukit/libfs/src/jffs2/src/flashio.c75
-rw-r--r--cpukit/libfs/src/jffs2/src/fs-rtems.c161
-rw-r--r--cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h2
-rw-r--r--cpukit/libfs/src/jffs2/src/os-rtems.h69
-rw-r--r--cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h1
-rw-r--r--cpukit/libfs/src/jffs2/src/wbuf.c2
16 files changed, 424 insertions, 40 deletions
diff --git a/cpukit/libfs/src/jffs2/include/linux/fs.h b/cpukit/libfs/src/jffs2/include/linux/fs.h
index a638e7b6bf..9e40d105dc 100644
--- a/cpukit/libfs/src/jffs2/include/linux/fs.h
+++ b/cpukit/libfs/src/jffs2/include/linux/fs.h
@@ -34,4 +34,7 @@ struct iattr {
time_t ia_ctime;
};
+#define SB_RDONLY 1
+#define sb_rdonly(sb) ((sb)->s_flags & SB_RDONLY)
+
#endif /* __LINUX_FS_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/jiffies.h b/cpukit/libfs/src/jffs2/include/linux/jiffies.h
new file mode 100644
index 0000000000..77debb5d27
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/jiffies.h
@@ -0,0 +1 @@
+#include <linux/workqueue.h>
diff --git a/cpukit/libfs/src/jffs2/include/linux/list.h b/cpukit/libfs/src/jffs2/include/linux/list.h
index 4dc8a5a6b7..efb7fb8019 100644
--- a/cpukit/libfs/src/jffs2/include/linux/list.h
+++ b/cpukit/libfs/src/jffs2/include/linux/list.h
@@ -139,6 +139,14 @@ list_empty( struct list_head *list )
(_ent_) != (_list_); \
(_ent_) = (_ent_)->next )
+/* list_for_each_safe - using _ent_, iterate through list _list_
+ while protecting against removal of list elements */
+
+#define list_for_each_safe( _ent_, _tmp_, _list_ ) \
+ for ( (_ent_) = (_list_)->next, (_tmp_) = (_ent_)->next; \
+ (_ent_) != (_list_); \
+ (_ent_) = (_tmp_), (_tmp_) = (_ent_)->next )
+
/*
* list_for_each_entry - this function can be use to iterate over all
* items in a list* _list_ with it's head at _head_ and link _item_
diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
index bcf0a9aa70..548201483f 100644
--- a/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
+++ b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
@@ -6,6 +6,14 @@
#define MTD_FAIL_ADDR_UNKNOWN -1LL
+struct mtd_info {
+ uint32_t oobavail;
+ uint32_t oobsize;
+ uint32_t size;
+ uint32_t erasesize;
+ uint32_t writesize;
+};
+
static inline int do_mtd_point(size_t *retlen, void **ebuf)
{
*retlen = 0;
@@ -20,4 +28,33 @@ static inline int do_mtd_point(size_t *retlen, void **ebuf)
#define mtd_kmalloc_up_to(a, b) kmalloc(*(b), GFP_KERNEL)
+struct mtd_oob_ops {
+ uint32_t mode;
+ size_t len;
+ size_t retlen;
+ size_t ooblen;
+ size_t oobretlen;
+ uint32_t ooboffs;
+ uint8_t *datbuf;
+ uint8_t *oobbuf;
+};
+
+#define EUCLEAN EAGAIN
+static inline int mtd_is_bitflip(int err) { return (err == -EUCLEAN); }
+
+#define mtd_block_isbad(mtd_sp, offset) ({ \
+ bool bad; \
+ int sc = jffs2_flash_block_is_bad(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), offset, &bad); \
+ if (sc) { \
+ return sc; \
+ } \
+ bad; \
+})
+#define mtd_block_markbad(mtd_sp, offset) \
+ jffs2_flash_block_mark_bad(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), offset)
+#define mtd_write(mtd_sp, ofs, len, retlen, buf) \
+ jffs2_flash_direct_write(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), ofs, len, retlen, buf)
+#define mtd_read(mtd_sp, ofs, len, retlen, buf) \
+ jffs2_flash_direct_read(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), ofs, len, retlen, buf)
+
#endif /* __LINUX_MTD_MTD_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h b/cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h
new file mode 100644
index 0000000000..fe47ba6fbf
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_MTD_RAWNAND_H__
+#define __LINUX_MTD_RAWNAND_H__
+
+#define mtd_read_oob(mtd_sp, offset, ops) ({ \
+ struct jffs2_sb_info *sb_info = RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd); \
+ int sc = jffs2_flash_oob_read(sb_info, offset, (ops)->oobbuf, (ops)->ooblen); \
+ if (sc) { \
+ sc = -EIO; \
+ } else { \
+ (ops)->oobretlen = (ops)->ooblen; \
+ } \
+ sc; \
+})
+#define mtd_write_oob(mtd_sp, offset, ops) ({ \
+ struct jffs2_sb_info *sb_info = RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd); \
+ int sc = jffs2_flash_oob_write(sb_info, offset, (ops)->oobbuf, (ops)->ooblen); \
+ if (sc != RTEMS_SUCCESSFUL) { \
+ sc = -EIO; \
+ } else { \
+ (ops)->oobretlen = (ops)->ooblen; \
+ } \
+ sc; \
+})
+#define MTD_OPS_AUTO_OOB 1
+
+#endif /* __LINUX_MTD_RAWNAND_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/mutex.h b/cpukit/libfs/src/jffs2/include/linux/mutex.h
index f5e1efb1af..be8709f125 100644
--- a/cpukit/libfs/src/jffs2/include/linux/mutex.h
+++ b/cpukit/libfs/src/jffs2/include/linux/mutex.h
@@ -1,29 +1,20 @@
#ifndef __LINUX_MUTEX_H
#define __LINUX_MUTEX_H
-struct mutex { };
+#include <rtems/thread.h>
+
+struct mutex { rtems_mutex r_m; };
#define DEFINE_MUTEX(m) struct mutex m
-static inline void mutex_init(struct mutex *m)
-{
- (void) m;
-}
-
-static inline void mutex_lock(struct mutex *m)
-{
- (void) m;
-}
-
-static inline int mutex_lock_interruptible(struct mutex *m)
-{
- (void) m;
- return 0;
-}
-
-static inline void mutex_unlock(struct mutex *m)
-{
- (void) m;
-}
+#define mutex_init(m) rtems_mutex_init(&(m)->r_m, "JFFS2 Mutex");
+
+#define mutex_lock(m) rtems_mutex_lock(&(m)->r_m);
+
+#define mutex_lock_interruptible(m) ({ mutex_lock(m); 0; })
+
+#define mutex_unlock(m) rtems_mutex_unlock(&(m)->r_m);
+
+#define mutex_is_locked(m) 1
#endif
diff --git a/cpukit/libfs/src/jffs2/include/linux/rwsem.h b/cpukit/libfs/src/jffs2/include/linux/rwsem.h
index 57bfdf13b7..9db6d45ad2 100644
--- a/cpukit/libfs/src/jffs2/include/linux/rwsem.h
+++ b/cpukit/libfs/src/jffs2/include/linux/rwsem.h
@@ -1,6 +1,20 @@
#ifndef __LINUX_RWSEM_H__
#define __LINUX_RWSEM_H__
-struct rw_semaphore;
+#include <pthread.h>
+
+struct rw_semaphore {
+ pthread_rwlock_t lock;
+};
+
+#define init_rwsem(rwsem) pthread_rwlock_init(&(rwsem)->lock, NULL)
+
+#define down_read(rwsem) pthread_rwlock_rdlock(&(rwsem)->lock)
+
+#define down_write(rwsem) pthread_rwlock_wrlock(&(rwsem)->lock)
+
+#define up_read(rwsem) pthread_rwlock_unlock(&(rwsem)->lock)
+
+#define up_write(rwsem) pthread_rwlock_unlock(&(rwsem)->lock)
#endif /* __LINUX_RWSEM_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/slab.h b/cpukit/libfs/src/jffs2/include/linux/slab.h
index 532586e210..d664f50dfb 100644
--- a/cpukit/libfs/src/jffs2/include/linux/slab.h
+++ b/cpukit/libfs/src/jffs2/include/linux/slab.h
@@ -7,6 +7,7 @@
#define kzalloc(x, y) calloc(1, x)
#define kmalloc(x, y) malloc(x)
+#define kmalloc_array(x, y, z) kmalloc((x * y), z)
#define kfree(x) free(x)
#define kvfree(x) free(x)
#define vmalloc(x) malloc(x)
diff --git a/cpukit/libfs/src/jffs2/include/linux/workqueue.h b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
index 90d98288af..45a2942bfc 100644
--- a/cpukit/libfs/src/jffs2/include/linux/workqueue.h
+++ b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
@@ -1,10 +1,30 @@
#ifndef __LINUX_WORKQUEUE_H__
#define __LINUX_WORKQUEUE_H__
-struct work_struct { } ;
+#include <rtems/chain.h>
-#define INIT_WORK(x,y,z) /* */
-#define schedule_work(x) do { } while(0)
-#define flush_scheduled_work() do { } while(0)
+struct work_struct { rtems_chain_node node; };
+
+#define queue_delayed_work(workqueue, delayed_work, delay_ms) ({ \
+ jffs2_queue_delayed_work(delayed_work, delay_ms); \
+ 0; \
+})
+
+#define INIT_DELAYED_WORK(delayed_work, delayed_workqueue_callback) ({ \
+ _Chain_Initialize_node(&(delayed_work)->work.node); \
+ (delayed_work)->callback = delayed_workqueue_callback; \
+})
+
+#define msecs_to_jiffies(a) (a)
+
+typedef void (*work_callback_t)(struct work_struct *work);
+struct delayed_work {
+ struct work_struct work;
+ uint64_t execution_time;
+ work_callback_t callback;
+};
+
+#define to_delayed_work(work) RTEMS_CONTAINER_OF(work, struct delayed_work, work)
+void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms);
#endif /* __LINUX_WORKQUEUE_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/writeback.h b/cpukit/libfs/src/jffs2/include/linux/writeback.h
new file mode 100644
index 0000000000..9899205383
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/writeback.h
@@ -0,0 +1 @@
+/* This file intentionally left empty as a stub for wbuf.c */
diff --git a/cpukit/libfs/src/jffs2/src/flashio.c b/cpukit/libfs/src/jffs2/src/flashio.c
index 7b689a5a7c..6b0a9433fa 100644
--- a/cpukit/libfs/src/jffs2/src/flashio.c
+++ b/cpukit/libfs/src/jffs2/src/flashio.c
@@ -17,8 +17,23 @@
#include <linux/kernel.h>
#include "nodelist.h"
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
int jffs2_flash_read(struct jffs2_sb_info * c,
- cyg_uint32 read_buffer_offset, const size_t size,
+ loff_t read_buffer_offset, const size_t size,
+ size_t * return_size, unsigned char *write_buffer)
+{
+ return jffs2_flash_direct_read(c, read_buffer_offset, size, return_size, write_buffer);
+}
+
+int jffs2_flash_write(struct jffs2_sb_info * c,
+ loff_t write_buffer_offset, size_t size,
+ size_t * return_size, const unsigned char *read_buffer)
+{
+ return jffs2_flash_direct_write(c, write_buffer_offset, size, return_size, read_buffer);
+}
+#endif
+int jffs2_flash_direct_read(struct jffs2_sb_info * c,
+ loff_t read_buffer_offset, const size_t size,
size_t * return_size, unsigned char *write_buffer)
{
const struct super_block *sb = OFNI_BS_2SFFJ(c);
@@ -29,9 +44,9 @@ int jffs2_flash_read(struct jffs2_sb_info * c,
return (*fc->read)(fc, read_buffer_offset, write_buffer, size);
}
-int jffs2_flash_write(struct jffs2_sb_info * c,
- cyg_uint32 write_buffer_offset, const size_t size,
- size_t * return_size, unsigned char *read_buffer)
+int jffs2_flash_direct_write(struct jffs2_sb_info * c,
+ loff_t write_buffer_offset, const size_t size,
+ size_t * return_size, const unsigned char *read_buffer)
{
const struct super_block *sb = OFNI_BS_2SFFJ(c);
rtems_jffs2_flash_control *fc = sb->s_flash_control;
@@ -133,3 +148,55 @@ int jffs2_flash_erase(struct jffs2_sb_info * c,
return (*fc->erase)(fc, jeb->offset);
}
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+int jffs2_flash_block_is_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset, bool *bad)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->block_is_bad)(fc, block_offset, bad);
+}
+
+int jffs2_flash_block_mark_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->block_mark_bad)(fc, block_offset);
+}
+
+int jffs2_flash_oob_write(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->oob_write)(fc, block_offset, oobbuf, ooblen);
+}
+
+int jffs2_flash_oob_read(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->oob_read)(fc, block_offset, oobbuf, ooblen);
+}
+
+int jffs2_flash_get_oob_size(struct jffs2_sb_info * c)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ if (fc->get_oob_size == NULL) {
+ return 0;
+ }
+ return (*fc->get_oob_size)(fc);
+}
+#endif
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c
index 3be142a75f..bff7d59ba1 100644
--- a/cpukit/libfs/src/jffs2/src/fs-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c
@@ -23,12 +23,14 @@
#include "nodelist.h"
#include <linux/pagemap.h>
#include <linux/crc32.h>
+#include <linux/mtd/mtd.h>
#include "compr.h"
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <rtems/libio.h>
#include <rtems/libio_.h>
+#include <rtems/sysinit.h>
/* Ensure that the JFFS2 values are identical to the POSIX defines */
@@ -1049,10 +1051,25 @@ static void rtems_jffs2_freenode(const rtems_filesystem_location_info_t *loc)
jffs2_iput(inode);
}
+static void jffs2_remove_delayed_work(struct delayed_work *dwork);
+
static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
{
rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
struct _inode *root_i = mt_entry->mt_fs_root->location.node_access;
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(&fs_info->sb);
+
+ /* Remove wbuf delayed work */
+ jffs2_remove_delayed_work(&c->wbuf_dwork);
+
+ /* Flush any pending writes */
+ if (!sb_rdonly(&fs_info->sb)) {
+ jffs2_flush_wbuf_gc(c, 0);
+ }
+#endif
+
+ jffs2_sum_exit(c);
icache_evict(root_i, NULL);
assert(root_i->i_cache_next == NULL);
@@ -1062,6 +1079,12 @@ static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry
rtems_jffs2_free_directory_entries(root_i);
free(root_i);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ jffs2_nand_flash_cleanup(c);
+ free(c->mtd);
+ c->mtd = NULL;
+#endif
+
rtems_jffs2_free_fs_info(fs_info, true);
}
@@ -1212,6 +1235,113 @@ static int calculate_inocache_hashsize(uint32_t flash_size)
return hashsize;
}
+/* Chain for holding delayed work */
+rtems_chain_control delayed_work_chain;
+
+/* Lock for protecting the delayed work chain */
+struct mutex delayed_work_mutex;
+
+void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms)
+{
+ mutex_lock(&delayed_work_mutex);
+ if (rtems_chain_is_node_off_chain(&work->work.node)) {
+ work->execution_time = rtems_clock_get_uptime_nanoseconds() + delay_ms*1000000;
+ rtems_chain_append(&delayed_work_chain, &work->work.node);
+ }
+ mutex_unlock(&delayed_work_mutex);
+}
+
+static void jffs2_remove_delayed_work(struct delayed_work *dwork)
+{
+ struct delayed_work* work;
+ rtems_chain_node* node;
+
+ mutex_lock(&delayed_work_mutex);
+ if (rtems_chain_is_node_off_chain(&dwork->work.node)) {
+ mutex_unlock(&delayed_work_mutex);
+ return;
+ }
+
+ node = rtems_chain_first(&delayed_work_chain);
+ while (!rtems_chain_is_tail(&delayed_work_chain, node)) {
+ work = (struct delayed_work*) node;
+ rtems_chain_node* next_node = rtems_chain_next(node);
+ if (work == dwork) {
+ rtems_chain_extract(node);
+ mutex_unlock(&delayed_work_mutex);
+ return;
+ }
+ node = next_node;
+ }
+ mutex_unlock(&delayed_work_mutex);
+}
+
+static void process_delayed_work(void)
+{
+ struct delayed_work* work;
+ rtems_chain_node* node;
+
+ mutex_lock(&delayed_work_mutex);
+
+ if (rtems_chain_is_empty(&delayed_work_chain)) {
+ mutex_unlock(&delayed_work_mutex);
+ return;
+ }
+
+ node = rtems_chain_first(&delayed_work_chain);
+ while (!rtems_chain_is_tail(&delayed_work_chain, node)) {
+ work = (struct delayed_work*) node;
+ rtems_chain_node* next_node = rtems_chain_next(node);
+ if (rtems_clock_get_uptime_nanoseconds() >= work->execution_time) {
+ rtems_chain_extract(node);
+ work->callback(&work->work);
+ }
+ node = next_node;
+ }
+ mutex_unlock(&delayed_work_mutex);
+}
+/* Task for processing delayed work */
+static rtems_task delayed_work_task(
+ rtems_task_argument unused
+)
+{
+ (void)unused;
+ while (1) {
+ process_delayed_work();
+ sleep(1);
+ }
+}
+
+rtems_id delayed_work_task_id;
+
+static void jffs2_init_delayed_work_task(void)
+{
+ /* Initialize chain for delayed work */
+ rtems_chain_initialize_empty(&delayed_work_chain);
+
+ /* Initialize lock for delayed work */
+ mutex_init(&delayed_work_mutex);
+
+ /* Create task for delayed work */
+ rtems_status_code err = rtems_task_create(
+ rtems_build_name( 'J', 'F', 'F', 'S' ),
+ jffs2_config.delayed_write_priority,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &delayed_work_task_id
+ );
+ if (err != RTEMS_SUCCESSFUL) {
+ printk("JFFS2 delayed work task processor creation failed\n");
+ }
+}
+
+RTEMS_SYSINIT_ITEM(
+ jffs2_init_delayed_work_task,
+ RTEMS_SYSINIT_LIBIO,
+ RTEMS_SYSINIT_ORDER_MIDDLE
+);
+
int rtems_jffs2_initialize(
rtems_filesystem_mount_table_entry_t *mt_entry,
const void *data
@@ -1237,11 +1367,21 @@ int rtems_jffs2_initialize(
sb = &fs_info->sb;
c = JFFS2_SB_INFO(sb);
+ c->mtd = NULL;
if (err == 0) {
rtems_recursive_mutex_init(&sb->s_mutex, RTEMS_FILESYSTEM_TYPE_JFFS2);
}
+ /* Start task for delayed work if it hasn't already been started */
+ if (err == 0) {
+ err = rtems_task_start( delayed_work_task_id, delayed_work_task, 0 );
+ /* Task already running from previous mount */
+ if (err == RTEMS_INCORRECT_STATE) {
+ err = 0;
+ }
+ }
+
if (err == 0) {
uint32_t blocks = fc->flash_size / fc->block_size;
@@ -1263,12 +1403,31 @@ int rtems_jffs2_initialize(
sb->s_flash_control = fc;
sb->s_compressor_control = jffs2_mount_data->compressor_control;
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ c->mtd = malloc(sizeof(struct mtd_info));
+ if (!c->mtd) {
+ err = -ENOMEM;
+ }
+ }
+
+ if (err == 0) {
+ c->mtd->oobavail = jffs2_flash_get_oob_size(c);
+ c->mtd->oobsize = c->mtd->oobavail;
+ c->mtd->size = fc->flash_size;
+ c->mtd->erasesize = fc->block_size;
+ c->mtd->writesize = fc->write_size;
+#endif
c->inocache_hashsize = inocache_hashsize;
c->inocache_list = &fs_info->inode_cache[0];
c->sector_size = fc->block_size;
c->flash_size = fc->flash_size;
c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ err = jffs2_nand_flash_setup(c);
+ }
+ if (err == 0) {
+#endif
err = jffs2_do_mount_fs(c);
}
@@ -1296,6 +1455,8 @@ int rtems_jffs2_initialize(
return 0;
} else {
if (fs_info != NULL) {
+ free(c->mtd);
+ c->mtd = NULL;
rtems_jffs2_free_fs_info(fs_info, do_mount_fs_was_successful);
} else {
rtems_jffs2_flash_control_destroy(fc);
diff --git a/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h b/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h
index 5a7091746f..4ee43a6f30 100644
--- a/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h
+++ b/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h
@@ -1,3 +1,5 @@
+#include "rtems-jffs2-config.h"
+
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h
index d9e4330371..bda4fc9d46 100644
--- a/cpukit/libfs/src/jffs2/src/os-rtems.h
+++ b/cpukit/libfs/src/jffs2/src/os-rtems.h
@@ -52,8 +52,7 @@ static inline unsigned int full_name_hash(const void *salt, const unsigned char
return hash;
}
-/* NAND flash not currently supported on RTEMS */
-#define jffs2_can_mark_obsolete(c) (1)
+#define container_of(a, b, c) RTEMS_CONTAINER_OF(a, b, c)
#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i)
#define OFNI_EDONI_2SFFJ(f) RTEMS_CONTAINER_OF(f, struct _inode, jffs2_i)
@@ -108,6 +107,7 @@ struct super_block {
unsigned char s_gc_buffer[PAGE_CACHE_SIZE]; // Avoids malloc when user may be under memory pressure
rtems_recursive_mutex s_mutex;
char s_name_buf[JFFS2_MAX_NAME_LEN];
+ uint32_t s_flags;
};
#define sleep_on_spinunlock(wq, sl) spin_unlock(sl)
@@ -151,13 +151,15 @@ static inline uint32_t jffs2_to_os_mode (uint32_t jmode)
/* flashio.c */
-int jffs2_flash_read(struct jffs2_sb_info *c, cyg_uint32 read_buffer_offset,
- const size_t size, size_t * return_size, unsigned char * write_buffer);
-int jffs2_flash_write(struct jffs2_sb_info *c, cyg_uint32 write_buffer_offset,
- const size_t size, size_t * return_size, unsigned char * read_buffer);
+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t read_buffer_offset,
+ size_t size, size_t * return_size, unsigned char * write_buffer);
+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t write_buffer_offset,
+ size_t size, size_t * return_size, const unsigned char * read_buffer);
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
unsigned long count, loff_t to, size_t *retlen);
int jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+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, u_char *buf);
// dir-rtems.c
struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, size_t namelen);
@@ -173,8 +175,9 @@ int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsign
static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
{ }
-#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+
#define jffs2_can_mark_obsolete(c) (1)
#define jffs2_is_writebuffered(c) (0)
#define jffs2_cleanmarker_oob(c) (0)
@@ -191,9 +194,55 @@ static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
#define jffs2_wbuf_timeout NULL
#define jffs2_wbuf_process NULL
#define jffs2_nor_ecc(c) (0)
-#else
-#error no nand yet
-#endif
+#else /* CONFIG_JFFS2_FS_WRITEBUFFER */
+/* dirty_writeback_interval is in centiseconds, 500cs == 5s */
+#define dirty_writeback_interval 500
+#define MTD_BIT_WRITEABLE 0x800
+#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
+
+#define jffs2_can_mark_obsolete(c) (OFNI_BS_2SFFJ(c)->s_flash_control->block_is_bad == NULL)
+
+#define jffs2_cleanmarker_oob(c) (OFNI_BS_2SFFJ(c)->s_flash_control->block_is_bad != NULL)
+
+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
+
+/* wbuf.c */
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
+int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
+void jffs2_wbuf_timeout(unsigned long data);
+void jffs2_wbuf_process(void *data);
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
+int jffs2_flash_block_is_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ bool *bad);
+int jffs2_flash_block_mark_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset);
+int jffs2_flash_oob_write(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen);
+int jffs2_flash_oob_read(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen);
+int jffs2_flash_get_oob_size(struct jffs2_sb_info * c);
+
+int jffs2_dataflash_setup(struct jffs2_sb_info *c);
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
+int jffs2_ubivol_setup(struct jffs2_sb_info *c);
+void jffs2_ubivol_cleanup(struct jffs2_sb_info *c);
+
+int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c);
+void jffs2_dirty_trigger(struct jffs2_sb_info *c);
+
+#endif /* CONFIG_JFFS2_FS_WRITEBUFFER */
#ifndef BUG_ON
#define BUG_ON(x) do { if (unlikely(x)) BUG(); } while(0)
diff --git a/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h b/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h
index 56395e1528..c56cbfeb8a 100644
--- a/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h
+++ b/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h
@@ -34,3 +34,4 @@
#define __ECOS 1
#define KBUILD_MODNAME "JFFS2"
#define fallthrough __attribute__((__fallthrough__))
+#define CONFIG_JFFS2_FS_WRITEBUFFER
diff --git a/cpukit/libfs/src/jffs2/src/wbuf.c b/cpukit/libfs/src/jffs2/src/wbuf.c
index 2e939c5ef0..04e2b03efc 100644
--- a/cpukit/libfs/src/jffs2/src/wbuf.c
+++ b/cpukit/libfs/src/jffs2/src/wbuf.c
@@ -1,3 +1,5 @@
+#include "rtems-jffs2-config.h"
+
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*