The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4c3a868d13c053ef173268cdfe1365978a282178

commit 4c3a868d13c053ef173268cdfe1365978a282178
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2025-09-11 10:05:04 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2025-09-20 19:24:10 +0000

    fcntl(F_SETFL): only allow one thread to perform F_SETFL
    
    Use f_vflags file locking for this.
    Allowing more than one thread handling F_SETFL might cause de-sync
    between real driver state and flags.
    
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 weeks
    Differential revision:  https://reviews.freebsd.org/D52487
---
 sys/kern/kern_descrip.c |  3 +++
 sys/kern/vfs_vnops.c    | 36 ++++++++++++++++++++++++++++++++++++
 sys/sys/file.h          |  4 ++++
 3 files changed, 43 insertions(+)

diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 2a833d2eafbe..19118eb7f275 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -658,6 +658,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
                        error = EBADF;
                        break;
                }
+               fsetfl_lock(fp);
                do {
                        tmp = flg = fp->f_flag;
                        tmp &= ~FCNTLFLAGS;
@@ -677,6 +678,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
                        if (error != 0)
                                goto revert_nonblock;
                }
+               fsetfl_unlock(fp);
                fdrop(fp, td);
                break;
 revert_nonblock:
@@ -691,6 +693,7 @@ revert_flags:
                        tmp |= got_cleared;
                        tmp &= ~got_set;
                } while (atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0);
+               fsetfl_unlock(fp);
                fdrop(fp, td);
                break;
 
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index f81c2033d95e..3d4567b6ab1e 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -896,6 +896,18 @@ foffset_read(struct file *fp)
        return (atomic_load_long(&fp->f_offset));
 }
 
+void
+fsetfl_lock(struct file *fp)
+{
+       file_v_lock(fp, FILE_V_SETFL_LOCKED, FILE_V_SETFL_LOCK_WAITING);
+}
+
+void
+fsetfl_unlock(struct file *fp)
+{
+       file_v_unlock(fp, FILE_V_SETFL_LOCKED, FILE_V_SETFL_LOCK_WAITING);
+}
+
 #else  /* OFF_MAX <= LONG_MAX */
 
 static void
@@ -971,6 +983,30 @@ foffset_read(struct file *fp)
 
        return (foffset_lock(fp, FOF_NOLOCK));
 }
+
+void
+fsetfl_lock(struct file *fp)
+{
+       struct mtx *mtxp;
+
+       mtxp = mtx_pool_find(mtxpool_sleep, fp);
+       mtx_lock(mtxp);
+       file_v_lock_mtxp(fp, mtxp, FILE_V_SETFL_LOCKED,
+           FILE_V_SETFL_LOCK_WAITING);
+       mtx_unlock(mtxp);
+}
+
+void
+fsetfl_unlock(struct file *fp)
+{
+       struct mtx *mtxp;
+
+       mtxp = mtx_pool_find(mtxpool_sleep, fp);
+       mtx_lock(mtxp);
+       file_v_unlock_mtxp(fp, mtxp, FILE_V_SETFL_LOCKED,
+           FILE_V_SETFL_LOCK_WAITING);
+       mtx_unlock(mtxp);
+}
 #endif
 
 void
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 9a072121e25f..c44fd0f28929 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -93,6 +93,8 @@ void foffset_lock_pair(struct file *fp1, off_t *off1p, struct 
file *fp2,
 void foffset_lock_uio(struct file *fp, struct uio *uio, int flags);
 void foffset_unlock(struct file *fp, off_t val, int flags);
 void foffset_unlock_uio(struct file *fp, struct uio *uio, int flags);
+void fsetfl_lock(struct file *fp);
+void fsetfl_unlock(struct file *fp);
 
 static inline off_t
 foffset_get(struct file *fp)
@@ -222,6 +224,8 @@ struct file {
 
 #define        FILE_V_FOFFSET_LOCKED           0x0001
 #define        FILE_V_FOFFSET_LOCK_WAITING     0x0002
+#define        FILE_V_SETFL_LOCKED             0x0004
+#define        FILE_V_SETFL_LOCK_WAITING       0x0008
 #endif /* __BSD_VISIBLE */
 
 #endif /* _KERNEL || _WANT_FILE */

Reply via email to