[PATCH 2/9] cpukit/jffs2: Protect the inode cache

Kinsey Moore kinsey.moore at oarcorp.com
Sat Dec 9 02:31:19 UTC 2023


The inode cache can be altered and queried by multiple threads of
execution, even before the introduction of delayed write support for
NAND. This provides a new lock to prevent simultaneous modification of
the cache.
---
 cpukit/libfs/src/jffs2/src/fs-rtems.c | 24 +++++++++++++++++++++++-
 cpukit/libfs/src/jffs2/src/os-rtems.h |  2 ++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c
index 8e8dfe8b0c..6a14bfa9b3 100644
--- a/cpukit/libfs/src/jffs2/src/fs-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c
@@ -369,6 +369,7 @@ static void rtems_jffs2_free_fs_info(rtems_jffs2_fs_info *fs_info, bool do_mount
 	rtems_jffs2_flash_control_destroy(fs_info->sb.s_flash_control);
 	rtems_jffs2_compressor_control_destroy(fs_info->sb.s_compressor_control);
 	rtems_recursive_mutex_destroy(&sb->s_mutex);
+	rtems_recursive_mutex_destroy(&sb->s_cache_mutex);
 	free(fs_info);
 }
 
@@ -1071,7 +1072,9 @@ static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry
 
 	jffs2_sum_exit(c);
 
+	rtems_recursive_mutex_lock(&fs_info->sb.s_cache_mutex);
 	icache_evict(root_i, NULL);
+	rtems_recursive_mutex_unlock(&fs_info->sb.s_cache_mutex);
 	assert(root_i->i_cache_next == NULL);
 	assert(root_i->i_count == 1);
 	jffs2_iput(root_i);
@@ -1388,6 +1391,7 @@ int rtems_jffs2_initialize(
 		spin_lock_init(&c->inocache_lock);
 		c->mtd = NULL;
 		rtems_recursive_mutex_init(&sb->s_mutex, RTEMS_FILESYSTEM_TYPE_JFFS2);
+		rtems_recursive_mutex_init(&sb->s_cache_mutex, RTEMS_FILESYSTEM_TYPE_JFFS2);
 	}
 
 	/* Start task for delayed work if it hasn't already been started */
@@ -1497,6 +1501,7 @@ int rtems_jffs2_initialize(
 //
 //==========================================================================
 
+// The s_cache_mutex must be held while calling this function
 static struct _inode *new_inode(struct super_block *sb)
 {
 
@@ -1537,6 +1542,7 @@ static struct _inode *new_inode(struct super_block *sb)
 	return inode;
 }
 
+// The s_cache_mutex must be held while calling this function
 static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino)
 {
 	struct _inode *inode = NULL;
@@ -1565,12 +1571,20 @@ struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino)
 
 	D2(printf("jffs2_iget\n"));
 
+	/*
+	 * ilookup and new_inode need to be locked together since they're
+	 * related manipulations of the inode cache
+	 */
+	rtems_recursive_mutex_lock(&sb->s_cache_mutex);
 	inode = ilookup(sb, ino);
-	if (inode)
+	if (inode) {
+		rtems_recursive_mutex_unlock(&sb->s_cache_mutex);
 		return inode;
+	}
 
 	// Not cached, so malloc it
 	inode = new_inode(sb);
+	rtems_recursive_mutex_unlock(&sb->s_cache_mutex);
 	if (inode == NULL)
 		return ERR_PTR(-ENOMEM);
 
@@ -1612,6 +1626,7 @@ void jffs2_iput(struct _inode *i)
 		struct _inode *parent;
 
 		// Remove from the icache linked list and free immediately
+		rtems_recursive_mutex_lock(&i->i_sb->s_cache_mutex);
 		if (i->i_cache_prev)
 			i->i_cache_prev->i_cache_next = i->i_cache_next;
 		if (i->i_cache_next)
@@ -1619,6 +1634,7 @@ void jffs2_iput(struct _inode *i)
 
 		parent = i->i_parent;
 		jffs2_clear_inode(i);
+		rtems_recursive_mutex_unlock(&i->i_sb->s_cache_mutex);
 		memset(i, 0x5a, sizeof(*i));
 		free(i);
 
@@ -1630,7 +1646,9 @@ void jffs2_iput(struct _inode *i)
 	} else {
 		// Evict some _other_ inode with i_count zero, leaving
 		// this latest one in the cache for a while 
+		rtems_recursive_mutex_lock(&i->i_sb->s_cache_mutex);
 		icache_evict(i->i_sb->s_root, i);
+		rtems_recursive_mutex_unlock(&i->i_sb->s_cache_mutex);
 	}
 }
 
@@ -1679,7 +1697,9 @@ struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw
 
 	c = JFFS2_SB_INFO(sb);
 	
+	rtems_recursive_mutex_lock(&sb->s_cache_mutex);
 	inode = new_inode(sb);
+	rtems_recursive_mutex_unlock(&sb->s_cache_mutex);
 	
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
@@ -1784,7 +1804,9 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
 		   holding the alloc_sem, and jffs2_do_unlink() would also
 		   need that while decrementing nlink on any inode.
 		*/
+		rtems_recursive_mutex_lock(&(OFNI_BS_2SFFJ(c))->s_cache_mutex);
 		inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+		rtems_recursive_mutex_unlock(&(OFNI_BS_2SFFJ(c))->s_cache_mutex);
 		if (!inode) {
 			jffs2_dbg(1, "ilookup() failed for ino #%u; inode is probably deleted.\n",
 				  inum);
diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h
index 63841a5e50..a53d909b4c 100644
--- a/cpukit/libfs/src/jffs2/src/os-rtems.h
+++ b/cpukit/libfs/src/jffs2/src/os-rtems.h
@@ -100,6 +100,8 @@ struct _inode {
 
 struct super_block {
 	struct jffs2_sb_info	jffs2_sb;
+	/* Protects the s_root inode cache */
+	rtems_recursive_mutex	s_cache_mutex;
 	struct _inode *		s_root;
 	rtems_jffs2_flash_control	*s_flash_control;
 	rtems_jffs2_compressor_control	*s_compressor_control;
-- 
2.39.2



More information about the devel mailing list