summaryrefslogtreecommitdiff
path: root/cpukit
diff options
context:
space:
mode:
authorKinsey Moore <kinsey.moore@oarcorp.com>2023-09-20 13:16:14 -0500
committerJoel Sherrill <joel@rtems.org>2023-09-26 09:02:48 -0500
commit99c637fbd973a3d2f6e5adf38aac8f3f588cbb7e (patch)
treeae1009674691d128dc92bfb3e0c7821fdf2d7d09 /cpukit
parent41d43cef6c6d1f41e626c7a45b088f608656ee6a (diff)
cpukit/jffs2: Avoid use of off-chain semantics
This reworks the JFFS2 delayed work queue to avoid use of on-chain/off-chain semantics since they vary in behavior under RTEMS_DEBUG and are not guaranteed to be safe to use in SMP systems. This adds all delayed work structs to the chain on FS init and does not remove them until umount. Updates #4956
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/workqueue.h6
-rw-r--r--cpukit/libfs/src/jffs2/src/fs-rtems.c86
2 files changed, 50 insertions, 42 deletions
diff --git a/cpukit/libfs/src/jffs2/include/linux/workqueue.h b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
index 45a2942bfc..dceb328417 100644
--- a/cpukit/libfs/src/jffs2/include/linux/workqueue.h
+++ b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
@@ -2,6 +2,7 @@
#define __LINUX_WORKQUEUE_H__
#include <rtems/chain.h>
+#include <linux/mutex.h>
struct work_struct { rtems_chain_node node; };
@@ -11,7 +12,6 @@ struct work_struct { rtems_chain_node node; };
})
#define INIT_DELAYED_WORK(delayed_work, delayed_workqueue_callback) ({ \
- _Chain_Initialize_node(&(delayed_work)->work.node); \
(delayed_work)->callback = delayed_workqueue_callback; \
})
@@ -20,7 +20,9 @@ struct work_struct { rtems_chain_node node; };
typedef void (*work_callback_t)(struct work_struct *work);
struct delayed_work {
struct work_struct work;
- uint64_t execution_time;
+ struct mutex dw_mutex;
+ volatile bool pending;
+ volatile uint64_t execution_time;
work_callback_t callback;
};
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c
index 1a677c9772..e47f2e7fd2 100644
--- a/cpukit/libfs/src/jffs2/src/fs-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c
@@ -1241,39 +1241,41 @@ 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)
+/*
+ * 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);
- 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);
- }
+ rtems_chain_append_unprotected(&delayed_work_chain, &work->work.node);
mutex_unlock(&delayed_work_mutex);
}
-static void jffs2_remove_delayed_work(struct delayed_work *dwork)
+void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms)
{
- 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;
+ 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);
+}
- 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;
- }
+/* 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)
@@ -1282,8 +1284,6 @@ static void process_delayed_work(void)
rtems_chain_node* node;
mutex_lock(&delayed_work_mutex);
- rtems_chain_control process_work_chain;
- rtems_chain_initialize_empty(&process_work_chain);
if (rtems_chain_is_empty(&delayed_work_chain)) {
mutex_unlock(&delayed_work_mutex);
@@ -1293,23 +1293,23 @@ static void process_delayed_work(void)
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);
- rtems_chain_append(&process_work_chain, node);
+ node = rtems_chain_next(node);
+
+ if (!work->pending) {
+ continue;
}
- node = next_node;
- }
- mutex_unlock(&delayed_work_mutex);
- node = rtems_chain_first(&process_work_chain);
- while (!rtems_chain_is_tail(&process_work_chain, node)) {
- work = (struct delayed_work*) node;
- rtems_chain_node* next_node = rtems_chain_next(node);
- rtems_chain_extract(node);
+ if (rtems_clock_get_uptime_nanoseconds() < work->execution_time) {
+ continue;
+ }
+
+ mutex_lock(&work->dw_mutex);
+ work->pending = false;
+ mutex_unlock(&work->dw_mutex);
+
work->callback(&work->work);
- node = next_node;
}
+ mutex_unlock(&delayed_work_mutex);
}
/* Task for processing delayed work */
@@ -1320,7 +1320,7 @@ static rtems_task delayed_work_task(
(void)unused;
while (1) {
process_delayed_work();
- sleep(1);
+ usleep(1);
}
}
@@ -1381,6 +1381,9 @@ int rtems_jffs2_initialize(
if (err == 0) {
sb = &fs_info->sb;
c = JFFS2_SB_INFO(sb);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ add_delayed_work_to_chain(&c->wbuf_dwork);
+#endif
c->mtd = NULL;
rtems_recursive_mutex_init(&sb->s_mutex, RTEMS_FILESYSTEM_TYPE_JFFS2);
}
@@ -1467,6 +1470,9 @@ 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);