summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/include/rtems/confdefs/libio.h10
-rw-r--r--cpukit/include/rtems/jffs2.h147
-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
-rw-r--r--spec/build/cpukit/libjffs2.yml1
-rw-r--r--testsuites/fstests/jffs2_support/fs_support.c2
20 files changed, 583 insertions, 41 deletions
diff --git a/cpukit/include/rtems/confdefs/libio.h b/cpukit/include/rtems/confdefs/libio.h
index 1b84f8c20f..0027a86f50 100644
--- a/cpukit/include/rtems/confdefs/libio.h
+++ b/cpukit/include/rtems/confdefs/libio.h
@@ -145,6 +145,16 @@
#ifdef CONFIGURE_FILESYSTEM_JFFS2
#include <rtems/jffs2.h>
+
+#ifndef CONFIGURE_JFFS2_DELAYED_WRITE_TASK_PRIORITY
+ #define CONFIGURE_JFFS2_DELAYED_WRITE_TASK_PRIORITY \
+ RTEMS_JFFS2_DELAYED_WRITE_TASK_PRIORITY_DEFAULT
+#endif
+
+const rtems_jffs2_config jffs2_config = {
+ CONFIGURE_JFFS2_DELAYED_WRITE_TASK_PRIORITY,
+};
+
#endif
#ifdef CONFIGURE_FILESYSTEM_NFS
diff --git a/cpukit/include/rtems/jffs2.h b/cpukit/include/rtems/jffs2.h
index 1cf9a01c6e..e1dee9b582 100644
--- a/cpukit/include/rtems/jffs2.h
+++ b/cpukit/include/rtems/jffs2.h
@@ -230,6 +230,99 @@ typedef int (*rtems_jffs2_flash_erase)(
);
/**
+ * @brief Flash bad block check operation.
+ *
+ * This operation checks whether a block is bad.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset in bytes of the block to check.
+ * @param[out] The result of the bad block check.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred. Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_block_is_bad)(
+ rtems_jffs2_flash_control *self,
+ uint32_t offset,
+ bool *bad
+);
+
+/**
+ * @brief Flash bad block mark operation.
+ *
+ * This operation marks a block bad.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset in bytes of the block to mark bad.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred. Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_block_mark_bad)(
+ rtems_jffs2_flash_control *self,
+ uint32_t offset
+);
+
+/**
+ * @brief Flash oob write.
+ *
+ * This operation writes the out-of-band/spare bytes for the block matching
+ * the given offset in bytes.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset to erase from the flash begin in bytes.
+ * @param[in] pointer to the buffer which will be written to the oob/spare bytes.
+ * @param[in] length of the buffer which will be written to the oob/spare bytes.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred. Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_oob_write)(
+ rtems_jffs2_flash_control *self,
+ uint32_t offset,
+ uint8_t *oobbuf,
+ uint32_t obblen
+);
+
+/**
+ * @brief Flash oob read.
+ *
+ * This operation reads the out-of-band/spare bytes for the block matching
+ * the given offset in bytes.
+ *
+ * @param[in, out] self The flash control.
+ * @param[in] offset The offset to erase from the flash begin in bytes.
+ * @param[out] pointer to the buffer which will have the oob/spare bytes data written to it.
+ * @param[in] length of the buffer which will hold the oob/spare bytes.
+ *
+ * @retval 0 Successful operation.
+ * @retval -EIO An error occurred. Please note that the value is negative.
+ * @retval other All other values are reserved and must not be used.
+ */
+typedef int (*rtems_jffs2_flash_oob_read)(
+ rtems_jffs2_flash_control *self,
+ uint32_t offset,
+ uint8_t *oobbuf,
+ uint32_t obblen
+);
+
+/**
+ * @brief Flash get oob size.
+ *
+ * This operation gets the size of the out-of-band/spare bytes for each page.
+ *
+ * @param[in, out] self The flash control.
+ *
+ * @retval The size of the OOB/spare area available to each page
+ */
+typedef uint32_t (*rtems_jffs2_flash_get_oob_size)(
+ rtems_jffs2_flash_control *self
+);
+
+/**
* @brief Flash destroy operation.
*
* The flash destroy operation is called during unmount of the file system
@@ -274,6 +367,14 @@ struct rtems_jffs2_flash_control {
uint32_t flash_size;
/**
+ * @brief The size in bytes of the minimum write size for the flash device.
+ *
+ * It must be an integral divisor into the block size. This is only applicable
+ * for NAND devices.
+ */
+ uint32_t write_size;
+
+ /**
* @brief Read from flash operation.
*/
rtems_jffs2_flash_read read;
@@ -289,6 +390,31 @@ struct rtems_jffs2_flash_control {
rtems_jffs2_flash_erase erase;
/**
+ * @brief Flash bad block check operation.
+ */
+ rtems_jffs2_flash_block_is_bad block_is_bad;
+
+ /**
+ * @brief Flash bad block mark operation.
+ */
+ rtems_jffs2_flash_block_mark_bad block_mark_bad;
+
+ /**
+ * @brief Flash oob bytes write operation.
+ */
+ rtems_jffs2_flash_oob_write oob_write;
+
+ /**
+ * @brief Flash oob bytes read operation.
+ */
+ rtems_jffs2_flash_oob_read oob_read;
+
+ /**
+ * @brief Flash get oob bytes per page operation.
+ */
+ rtems_jffs2_flash_get_oob_size get_oob_size;
+
+ /**
* @brief Flash destroy operation.
*
* This operation is optional and the pointer may be @c NULL.
@@ -608,6 +734,27 @@ typedef struct {
*/
#define RTEMS_JFFS2_FORCE_GARBAGE_COLLECTION _IO('F', 3)
+/**
+ * Default delayed-write servicing task priority.
+ */
+#define RTEMS_JFFS2_DELAYED_WRITE_TASK_PRIORITY_DEFAULT 15
+
+/**
+ * JFFS2 configuration definition. See confdefs.h for support on using this
+ * structure.
+ */
+typedef struct rtems_jffs2_config {
+ rtems_task_priority delayed_write_priority; /**< Priority of the delayed write
+ * task. */
+} rtems_jffs2_config;
+
+/**
+ * External reference to the configuration.
+ *
+ * The configuration is provided by the application.
+ */
+extern const rtems_jffs2_config jffs2_config;
+
/** @} */
#ifdef __cplusplus
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.
*
diff --git a/spec/build/cpukit/libjffs2.yml b/spec/build/cpukit/libjffs2.yml
index bc57baa68b..d41db4a2c9 100644
--- a/spec/build/cpukit/libjffs2.yml
+++ b/spec/build/cpukit/libjffs2.yml
@@ -33,6 +33,7 @@ source:
- cpukit/libfs/src/jffs2/src/read.c
- cpukit/libfs/src/jffs2/src/readinode.c
- cpukit/libfs/src/jffs2/src/scan.c
+- cpukit/libfs/src/jffs2/src/wbuf.c
- cpukit/libfs/src/jffs2/src/write.c
target: jffs2
type: build
diff --git a/testsuites/fstests/jffs2_support/fs_support.c b/testsuites/fstests/jffs2_support/fs_support.c
index 2aa04a27c6..c2f2dcaf8e 100644
--- a/testsuites/fstests/jffs2_support/fs_support.c
+++ b/testsuites/fstests/jffs2_support/fs_support.c
@@ -163,7 +163,7 @@ void test_shutdown_filesystem(void)
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 40
-#define CONFIGURE_MAXIMUM_TASKS 1
+#define CONFIGURE_MAXIMUM_TASKS 2
#define CONFIGURE_INIT_TASK_STACK_SIZE (32 * 1024)
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT