fs/inode: using rwsem lock as inode_lock to avoid deadlock

Example:
When executing "df -h" on Core A to view mount information, this
process will traverse inode nodes, thereby holding the inode_lock.
Since the inode type of the mount point may be rpmsgfs, it will fetch statfs
information from another Core B.

Meanwhile, rcS on Core B needs to obtain file information from Core A,
which will be achieved by fetching stat information through rpmsgfs.
When this message arrives at Core A, a deadlock can occur between Core A's
rptun ap and nsh task.

However, both of these places involve read operations only, thus a reader-writer lock
can be utilized to prevent such a deadlock.

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1
2024-09-29 22:00:04 +08:00
committed by Xiang Xiao
parent a367657d2d
commit 09a9611ae9
29 changed files with 121 additions and 224 deletions
+1 -6
View File
@@ -74,12 +74,7 @@ int register_blockdriver(FAR const char *path,
* valid data.
*/
ret = inode_lock();
if (ret < 0)
{
return ret;
}
inode_lock();
ret = inode_reserve(path, mode, &node);
if (ret >= 0)
{
+1 -6
View File
@@ -73,12 +73,7 @@ int register_driver(FAR const char *path,
* will have a momentarily bad structure.
*/
ret = inode_lock();
if (ret < 0)
{
return ret;
}
inode_lock();
ret = inode_reserve(path, mode, &node);
if (ret >= 0)
{
+1 -6
View File
@@ -74,12 +74,7 @@ int register_mtddriver(FAR const char *path, FAR struct mtd_dev_s *mtd,
* valid data.
*/
ret = inode_lock();
if (ret < 0)
{
return ret;
}
inode_lock();
ret = inode_reserve(path, mode, &node);
if (ret >= 0)
{
+1 -6
View File
@@ -72,12 +72,7 @@ int register_pipedriver(FAR const char *path,
* will have a momentarily bad structure.
*/
ret = inode_lock();
if (ret < 0)
{
return ret;
}
inode_lock();
ret = inode_reserve(path, mode, &node);
if (ret >= 0)
{
+5 -11
View File
@@ -45,17 +45,11 @@ int unregister_blockdriver(FAR const char *path)
{
int ret;
ret = inode_lock();
if (ret >= 0)
{
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return OK;
}
inode_lock();
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return ret;
}
+5 -11
View File
@@ -55,17 +55,11 @@ int unregister_driver(FAR const char *path)
/* If unlink failed, only remove inode. */
ret = inode_lock();
if (ret >= 0)
{
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return OK;
}
inode_lock();
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return ret;
}
+5 -11
View File
@@ -46,17 +46,11 @@ int unregister_mtddriver(FAR const char *path)
{
int ret;
ret = inode_lock();
if (ret >= 0)
{
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return OK;
}
inode_lock();
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return ret;
}
+5 -11
View File
@@ -47,18 +47,12 @@ int unregister_pipedriver(FAR const char *path)
{
int ret;
ret = inode_lock();
if (ret >= 0)
{
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return OK;
}
inode_lock();
ret = inode_remove(path);
inode_unlock();
#ifdef CONFIG_FS_NOTIFY
notify_unlink(path);
#endif
return ret;
}
+6 -12
View File
@@ -185,12 +185,9 @@ int foreach_inode(foreach_inode_t handler, FAR void *arg)
/* Start the recursion at the root inode */
ret = inode_lock();
if (ret >= 0)
{
ret = foreach_inodelevel(g_root_inode->i_child, info);
inode_unlock();
}
inode_rlock();
ret = foreach_inodelevel(g_root_inode->i_child, info);
inode_runlock();
/* Free the info structure and return the result */
@@ -209,12 +206,9 @@ int foreach_inode(foreach_inode_t handler, FAR void *arg)
/* Start the recursion at the root inode */
ret = inode_lock();
if (ret >= 0)
{
ret = foreach_inodelevel(g_root_inode->i_child, &info);
inode_unlock();
}
inode_rlock();
ret = foreach_inodelevel(g_root_inode->i_child, &info);
inode_runlock();
return ret;
+33 -13
View File
@@ -22,14 +22,8 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mutex.h>
#include <nuttx/rwsem.h>
#include "inode/inode.h"
@@ -45,7 +39,7 @@
* Private Data
****************************************************************************/
static rmutex_t g_inode_lock = NXRMUTEX_INITIALIZER;
static rw_semaphore_t g_inode_lock = RWSEM_INITIALIZER;
/****************************************************************************
* Public Functions
@@ -71,24 +65,50 @@ void inode_initialize(void)
* Name: inode_lock
*
* Description:
* Get exclusive access to the in-memory inode tree (g_inode_sem).
* Get writeable exclusive access to the in-memory inode tree.
*
****************************************************************************/
int inode_lock(void)
void inode_lock(void)
{
return nxrmutex_lock(&g_inode_lock);
down_write(&g_inode_lock);
}
/****************************************************************************
* Name: inode_rlock
*
* Description:
* Get readable exclusive access to the in-memory inode tree.
*
****************************************************************************/
void inode_rlock(void)
{
down_read(&g_inode_lock);
}
/****************************************************************************
* Name: inode_unlock
*
* Description:
* Relinquish exclusive access to the in-memory inode tree (g_inode_sem).
* Relinquish writeable exclusive access to the in-memory inode tree.
*
****************************************************************************/
void inode_unlock(void)
{
DEBUGVERIFY(nxrmutex_unlock(&g_inode_lock));
up_write(&g_inode_lock);
}
/****************************************************************************
* Name: inode_runlock
*
* Description:
* Relinquish read exclusive access to the in-memory inode tree.
*
****************************************************************************/
void inode_runlock(void)
{
up_read(&g_inode_lock);
}
+1 -3
View File
@@ -43,12 +43,10 @@
int inode_addref(FAR struct inode *inode)
{
int ret = OK;
if (inode)
{
atomic_fetch_add(&inode->i_crefs, 1);
}
return ret;
return OK;
}
+1 -6
View File
@@ -55,12 +55,7 @@ int inode_find(FAR struct inode_search_s *desc)
* references on the node.
*/
ret = inode_lock();
if (ret < 0)
{
return ret;
}
inode_lock();
ret = inode_search(desc);
if (ret >= 0)
{
+23 -3
View File
@@ -170,22 +170,42 @@ void inode_initialize(void);
* Name: inode_lock
*
* Description:
* Get exclusive access to the in-memory inode tree (tree_sem).
* Get writeable exclusive access to the in-memory inode tree.
*
****************************************************************************/
int inode_lock(void);
void inode_lock(void);
/****************************************************************************
* Name: inode_rlock
*
* Description:
* Get readable exclusive access to the in-memory inode tree.
*
****************************************************************************/
void inode_rlock(void);
/****************************************************************************
* Name: inode_unlock
*
* Description:
* Relinquish exclusive access to the in-memory inode tree (tree_sem).
* Relinquish writeable exclusive access to the in-memory inode tree.
*
****************************************************************************/
void inode_unlock(void);
/****************************************************************************
* Name: inode_runlock
*
* Description:
* Relinquish read exclusive access to the in-memory inode tree.
*
****************************************************************************/
void inode_runlock(void);
/****************************************************************************
* Name: inode_search
*
+2 -6
View File
@@ -402,11 +402,7 @@ static int automount_findinode(FAR const char *path)
/* Get exclusive access to the in-memory inode tree. */
ret = inode_lock();
if (ret < 0)
{
return ret;
}
inode_rlock();
/* Find the inode */
@@ -440,7 +436,7 @@ static int automount_findinode(FAR const char *path)
/* Relinquish our exclusive access to the inode try and return the result */
inode_unlock();
inode_runlock();
RELEASE_SEARCH(&desc);
return ret;
}
+2 -7
View File
@@ -367,12 +367,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
goto errout;
}
ret = inode_lock();
if (ret < 0)
{
goto errout_with_inode;
}
inode_lock();
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
/* Check if the inode already exists */
@@ -436,7 +431,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
#else
ret = mops->bind(NULL, data, &fshandle);
#endif
DEBUGVERIFY(inode_lock() >= 0);
inode_lock();
if (ret < 0)
{
/* The inode is unhappy with the driver for some reason. Back out
+1 -6
View File
@@ -110,12 +110,7 @@ int nx_umount2(FAR const char *target, unsigned int flags)
/* Hold the semaphore through the unbind logic */
ret = inode_lock();
if (ret < 0)
{
goto errout_with_mountpt;
}
inode_lock();
ret = mountpt_inode->u.i_mops->unbind(mountpt_inode->i_private,
&blkdrvr_inode, flags);
if (ret < 0)
+1 -6
View File
@@ -285,12 +285,7 @@ static int file_mq_vopen(FAR struct file *mq, FAR const char *mq_name,
/* Create an inode in the pseudo-filesystem at this path */
ret = inode_lock();
if (ret < 0)
{
goto errout_with_lock;
}
inode_lock();
ret = inode_reserve(fullpath, mode, &inode);
inode_unlock();
+1 -6
View File
@@ -137,12 +137,7 @@ int file_mq_unlink(FAR const char *mq_name)
* functioning as a directory and the directory is not empty.
*/
ret = inode_lock();
if (ret < 0)
{
goto errout_with_inode;
}
inode_lock();
if (inode->i_child != NULL)
{
ret = -ENOTEMPTY;
+1 -6
View File
@@ -178,12 +178,7 @@ int nxsem_open(FAR sem_t **sem, FAR const char *name, int oflags, ...)
* inode will be created with a reference count of zero.
*/
ret = inode_lock();
if (ret < 0)
{
goto errout_with_lock;
}
inode_lock();
ret = inode_reserve(fullpath, mode, &inode);
inode_unlock();
+1 -6
View File
@@ -102,12 +102,7 @@ int nxsem_unlink(FAR const char *name)
* functioning as a directory and the directory is not empty.
*/
ret = inode_lock();
if (ret < 0)
{
goto errout_with_inode;
}
inode_lock();
if (inode->i_child != NULL)
{
ret = -ENOTEMPTY;
+1 -7
View File
@@ -81,12 +81,7 @@ static int file_shm_open(FAR struct file *shm, FAR const char *name,
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_lock();
if (ret < 0)
{
goto errout_with_search;
}
inode_lock();
ret = inode_find(&desc);
if (ret >= 0)
{
@@ -148,7 +143,6 @@ static int file_shm_open(FAR struct file *shm, FAR const char *name,
errout_with_sem:
inode_unlock();
errout_with_search:
RELEASE_SEARCH(&desc);
#ifdef CONFIG_FS_NOTIFY
if (ret >= 0)
+1 -7
View File
@@ -77,12 +77,7 @@ static int file_shm_unlink(FAR const char *name)
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_lock();
if (ret < 0)
{
goto errout_with_search;
}
inode_lock();
ret = inode_find(&desc);
if (ret < 0)
{
@@ -139,7 +134,6 @@ errout_with_inode:
inode_release(inode);
errout_with_sem:
inode_unlock();
errout_with_search:
RELEASE_SEARCH(&desc);
#ifdef CONFIG_FS_NOTIFY
if (ret >= 0)
+16 -20
View File
@@ -215,40 +215,36 @@ static int shmfs_close(FAR struct file *filep)
static int shmfs_truncate(FAR struct file *filep, off_t length)
{
FAR struct shmfs_object_s *object;
int ret;
int ret = 0;
if (length == 0)
{
return -EINVAL;
}
ret = inode_lock();
if (ret >= 0)
inode_lock();
object = filep->f_inode->i_private;
if (!object)
{
object = filep->f_inode->i_private;
if (!object)
filep->f_inode->i_private = shmfs_alloc_object(length);
if (!filep->f_inode->i_private)
{
filep->f_inode->i_private = shmfs_alloc_object(length);
if (!filep->f_inode->i_private)
{
filep->f_inode->i_size = 0;
ret = -EFAULT;
}
else
{
filep->f_inode->i_size = length;
}
filep->f_inode->i_size = 0;
ret = -EFAULT;
}
else if (object->length != length)
else
{
/* This doesn't support resize */
ret = -EINVAL;
filep->f_inode->i_size = length;
}
}
else if (object->length != length)
{
/* This doesn't support resize */
inode_unlock();
ret = -EINVAL;
}
inode_unlock();
return ret;
}
+1 -7
View File
@@ -139,13 +139,7 @@ int mkdir(const char *pathname, mode_t mode)
* count of zero.
*/
ret = inode_lock();
if (ret < 0)
{
errcode = -ret;
goto errout_with_search;
}
inode_lock();
ret = inode_reserve(pathname, mode, &inode);
inode_unlock();
+1 -7
View File
@@ -484,12 +484,7 @@ int pseudofile_create(FAR struct inode **node, FAR const char *path,
nxmutex_init(&pf->lock);
ret = inode_lock();
if (ret < 0)
{
goto lock_err;
}
inode_lock();
ret = inode_reserve(path, mode, node);
if (ret < 0)
{
@@ -508,7 +503,6 @@ int pseudofile_create(FAR struct inode **node, FAR const char *path,
reserve_err:
inode_unlock();
lock_err:
nxmutex_destroy(&pf->lock);
fs_heap_free(pf);
return ret;
+1 -6
View File
@@ -178,12 +178,7 @@ next_subdir:
* of zero.
*/
ret = inode_lock();
if (ret < 0)
{
goto errout;
}
inode_lock();
ret = inode_reserve(newpath, 0777, &newinode);
if (ret < 0)
{
+1 -7
View File
@@ -134,13 +134,7 @@ int rmdir(FAR const char *pathname)
* -EBUSY to indicate that the inode was not deleted now.
*/
ret = inode_lock();
if (ret < 0)
{
errcode = -ret;
goto errout_with_inode;
}
inode_lock();
ret = inode_remove(pathname);
inode_unlock();
+1 -9
View File
@@ -141,17 +141,9 @@ int symlink(FAR const char *path1, FAR const char *path2)
* count of zero.
*/
ret = inode_lock();
if (ret < 0)
{
lib_free(newpath2);
errcode = -ret;
goto errout_with_search;
}
inode_lock();
ret = inode_reserve(path2, 0777, &inode);
inode_unlock();
if (ret < 0)
{
lib_free(newpath2);
+1 -6
View File
@@ -171,12 +171,7 @@ int nx_unlink(FAR const char *pathname)
* return -EBUSY to indicate that the inode was not deleted now.
*/
ret = inode_lock();
if (ret < 0)
{
goto errout_with_inode;
}
inode_lock();
ret = inode_remove(pathname);
inode_unlock();