diff options
Diffstat (limited to 'cpukit/libfs/src/jffs2/src/fs-rtems.c')
-rw-r--r-- | cpukit/libfs/src/jffs2/src/fs-rtems.c | 208 |
1 files changed, 203 insertions, 5 deletions
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c index b863c74547..029cba6618 100644 --- a/cpukit/libfs/src/jffs2/src/fs-rtems.c +++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c @@ -6,12 +6,12 @@ * Copyright © 2001-2003 Free Software Foundation, Inc. * Copyright © 2001-2007 Red Hat, Inc. * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> - * Copyright © 2013, 2016 embedded brains GmbH <rtems@embedded-brains.de> + * Copyright (C) 2013, 2016 embedded brains GmbH & Co. KG * * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com> * Contributors: David Woodhouse, Nick Garnett, Richard Panton. * - * Port to the RTEMS by embedded brains GmbH. + * Port to the RTEMS by embedded brains GmbH & Co. KG * * For licensing information, see the file 'LICENCE' in this directory. * @@ -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 */ @@ -577,6 +579,9 @@ static int rtems_jffs2_ioctl( break; case RTEMS_JFFS2_FORCE_GARBAGE_COLLECTION: eno = -jffs2_garbage_collect_pass(&inode->i_sb->jffs2_sb); + if (!eno) { + eno = -jffs2_flush_wbuf_pad(&inode->i_sb->jffs2_sb); + } break; default: eno = EINVAL; @@ -1049,10 +1054,26 @@ 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); + jffs2_flush_wbuf_pad(c); + } +#endif + + jffs2_sum_exit(c); icache_evict(root_i, NULL); assert(root_i->i_cache_next == NULL); @@ -1062,6 +1083,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 +1239,127 @@ 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; + +/* + * All delayed work structs are initialized and added to the chain during FS + * init. Must be called with no locks held + */ +static void add_delayed_work_to_chain(struct delayed_work *work) +{ + /* Initialize delayed work */ + mutex_init(&work->dw_mutex); + work->pending = false; + _Chain_Initialize_node(&work->work.node); \ + work->callback = NULL; + + mutex_lock(&delayed_work_mutex); + rtems_chain_append_unprotected(&delayed_work_chain, &work->work.node); + mutex_unlock(&delayed_work_mutex); +} + +void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms) +{ + mutex_lock(&work->dw_mutex); + if (!work->pending) { + work->execution_time = rtems_clock_get_uptime_nanoseconds(); + work->execution_time += delay_ms*1000000; + work->pending = true; + } + mutex_unlock(&work->dw_mutex); +} + +/* Clean up during FS unmount */ +static void jffs2_remove_delayed_work(struct delayed_work *dwork) +{ + mutex_lock(&delayed_work_mutex); + rtems_chain_extract_unprotected(&dwork->work.node); + mutex_unlock(&delayed_work_mutex); + /* Don't run pending delayed work, this will happen during unmount */ +} + +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; + node = rtems_chain_next(node); + + if (!work->pending) { + continue; + } + + if (rtems_clock_get_uptime_nanoseconds() < work->execution_time) { + continue; + } + + mutex_lock(&work->dw_mutex); + work->pending = false; + mutex_unlock(&work->dw_mutex); + + rtems_jffs2_do_lock(work->sb); + work->callback(&work->work); + rtems_jffs2_do_unlock(work->sb); + } + 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(); + usleep(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 @@ -1235,13 +1383,29 @@ int rtems_jffs2_initialize( err = -ENOMEM; } - sb = &fs_info->sb; - c = JFFS2_SB_INFO(sb); if (err == 0) { + sb = &fs_info->sb; + c = JFFS2_SB_INFO(sb); +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER + c->wbuf_dwork.sb = sb; + add_delayed_work_to_chain(&c->wbuf_dwork); +#endif + spin_lock_init(&c->erase_completion_lock); + spin_lock_init(&c->inocache_lock); + c->mtd = NULL; 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 +1427,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 +1479,11 @@ int rtems_jffs2_initialize( return 0; } else { if (fs_info != NULL) { +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER + jffs2_remove_delayed_work(&c->wbuf_dwork); +#endif + 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); @@ -1342,6 +1530,8 @@ static struct _inode *new_inode(struct super_block *sb) inode->i_cache_next = NULL; // Newest inode, about to be cached + mutex_init(&JFFS2_INODE_INFO(inode)->sem); + // Add to the icache for (cached_inode = sb->s_root; cached_inode != NULL; cached_inode = cached_inode->i_cache_next) { @@ -1458,7 +1648,14 @@ void jffs2_iput(struct _inode *i) static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { - memset(f, 0, sizeof(*f)); + /* These must be set manually to preserve other members */ + f->highest_version = 0; + f->fragtree = RB_ROOT; + f->metadata = NULL; + f->dents = NULL; + f->target = NULL; + f->flags = 0; + f->usercompr = 0; } static void jffs2_clear_inode (struct _inode *inode) @@ -1543,6 +1740,7 @@ static int jffs2_read_inode (struct _inode *inode) c = JFFS2_SB_INFO(inode->i_sb); jffs2_init_inode_info(f); + mutex_lock(&f->sem); ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); |