From c8955d227cc6bc3699ce462174d191782cc775b6 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 13 Dec 2024 16:50:59 +0800 Subject: [PATCH] use atomic to protect f_refs fix regresion from https://github.com/apache/nuttx/pull/14801 Signed-off-by: hujun5 --- fs/inode/fs_files.c | 48 ++++++++++++++++++++----------------------- include/nuttx/fs/fs.h | 3 ++- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c index 8374ad06d3041..ff5b5c30f2600 100644 --- a/fs/inode/fs_files.c +++ b/fs/inode/fs_files.c @@ -76,33 +76,40 @@ static FAR struct file *files_fget_by_index(FAR struct filelist *list, filep = &list->fl_files[l1][l2]; #ifdef CONFIG_FS_REFCOUNT + int32_t refs = 0; + if (filep->f_inode != NULL) { /* When the reference count is zero but the inode has not yet been * released, At this point we should return a null pointer */ - if (filep->f_refs == 0) - { - filep = NULL; - } - else + do { - filep->f_refs++; + refs = atomic_read(&filep->f_refs); + if (refs == 0) + { + filep = NULL; + break; + } } + while (!atomic_try_cmpxchg(&filep->f_refs, &refs, refs + 1)); } else if (new == NULL) { filep = NULL; } - else if (filep->f_refs) - { - filep->f_refs++; - } else { - filep->f_refs = 2; - *new = true; + do + { + if (atomic_try_cmpxchg(&filep->f_refs, &refs, 2)) + { + *new = true; + break; + } + } + while (!atomic_try_cmpxchg(&filep->f_refs, &refs, refs + 1)); } #else if (filep->f_inode == NULL && new == NULL) @@ -628,7 +635,7 @@ int file_allocate_from_tcb(FAR struct tcb_s *tcb, FAR struct inode *inode, filep->f_inode = inode; filep->f_priv = priv; #ifdef CONFIG_FS_REFCOUNT - filep->f_refs = 1; + atomic_set(&filep->f_refs, 1); #endif #ifdef CONFIG_FDSAN filep->f_tag_fdsan = 0; @@ -858,12 +865,8 @@ void fs_reffilep(FAR struct file *filep) { /* This interface is used to increase the reference count of filep */ - irqstate_t flags; - DEBUGASSERT(filep); - flags = spin_lock_irqsave(NULL); - filep->f_refs++; - spin_unlock_irqrestore(NULL, flags); + atomic_fetch_add(&filep->f_refs, 1); } /**************************************************************************** @@ -880,20 +883,13 @@ void fs_reffilep(FAR struct file *filep) int fs_putfilep(FAR struct file *filep) { - irqstate_t flags; int ret = 0; - int refs; DEBUGASSERT(filep); - flags = spin_lock_irqsave(NULL); - - refs = --filep->f_refs; - - spin_unlock_irqrestore(NULL, flags); /* If refs is zero, the close() had called, closing it now. */ - if (refs == 0) + if (atomic_fetch_sub(&filep->f_refs, 1) == 0) { ret = file_close(filep); if (ret < 0) diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index e82df41bffea5..81502ea8aed1a 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -50,6 +50,7 @@ #include #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -461,7 +462,7 @@ struct file { int f_oflags; /* Open mode flags */ #ifdef CONFIG_FS_REFCOUNT - int f_refs; /* Reference count */ + atomic_t f_refs; /* Reference count */ #endif off_t f_pos; /* File position */ FAR struct inode *f_inode; /* Driver or file system interface */