diff options
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 |