The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2b256f00aaee4713b8e6f0e3c0f3493065f710c4

commit 2b256f00aaee4713b8e6f0e3c0f3493065f710c4
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-03-05 12:35:43 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-03-10 12:44:34 +0000

    p9fs: locking improvements for p9fs_stat_vnode_dotl()
    
    If the vnode is share-locked:
    - Use vn_delayed_setsize() to avoid calling vnode_pager_setsize() with
      the vnode only shared locked.
    - Interlock the vnode to get exclusive mode for updating the node
      fields.
    
    Reciprocally, interlock the vnode in p9fs_getattr_dotl() to observe the
    consistent values on read.
    
    PR:     293492
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D55665
---
 sys/fs/p9fs/p9fs_vnops.c | 42 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c
index e64d7840f7f9..c6d35548e9ed 100644
--- a/sys/fs/p9fs/p9fs_vnops.c
+++ b/sys/fs/p9fs/p9fs_vnops.c
@@ -896,6 +896,7 @@ p9fs_getattr_dotl(struct vop_getattr_args *ap)
        /* Basic info */
        VATTR_NULL(vap);
 
+       VI_LOCK(vp);
        vap->va_atime.tv_sec = inode->i_atime;
        vap->va_mtime.tv_sec = inode->i_mtime;
        vap->va_ctime.tv_sec = inode->i_ctime;
@@ -916,6 +917,7 @@ p9fs_getattr_dotl(struct vop_getattr_args *ap)
        vap->va_filerev = inode->data_version;
        vap->va_vaflags = 0;
        vap->va_bytes = inode->blocks * P9PROTO_TGETATTR_BLK;
+       VI_UNLOCK(vp);
 
        return (0);
 }
@@ -951,16 +953,36 @@ p9fs_stat_vnode_dotl(struct p9_stat_dotl *stat, struct 
vnode *vp)
 {
        struct p9fs_node *np;
        struct p9fs_inode *inode;
+       bool excl_locked;
 
        np = P9FS_VTON(vp);
        inode = &np->inode;
 
+       /*
+        * This function might be called with the vnode only shared
+        * locked.  Then, interlock the vnode to ensure the exclusive
+        * access to the inode fields: the thread either owns
+        * exclusive vnode lock, or shared vnode lock plus interlock.
+        *
+        * If the vnode is locked exclusive, do not take the
+        * interlock.  We directly call vnode_pager_setsize(), which
+        * needs the vm_object lock, and that lock is before vnode
+        * interlock in the lock order.
+        */
        ASSERT_VOP_LOCKED(vp, __func__);
+       excl_locked = VOP_ISLOCKED(vp) == LK_EXCLUSIVE;
+       if (!excl_locked)
+               VI_LOCK(vp);
+
        /* Update the pager size if file size changes on host */
        if (inode->i_size != stat->st_size) {
                inode->i_size = stat->st_size;
-               if (vp->v_type == VREG)
-                       vnode_pager_setsize(vp, inode->i_size);
+               if (vp->v_type == VREG) {
+                       if (excl_locked)
+                               vnode_pager_setsize(vp, inode->i_size);
+                       else
+                               vn_delayed_setsize_locked(vp);
+               }
        }
 
        inode->i_mtime = stat->st_mtime_sec;
@@ -979,11 +1001,12 @@ p9fs_stat_vnode_dotl(struct p9_stat_dotl *stat, struct 
vnode *vp)
        inode->gen = stat->st_gen;
        inode->data_version = stat->st_data_version;
 
-       ASSERT_VOP_LOCKED(vp, __func__);
        /* Setting a flag if file changes based on qid version */
        if (np->vqid.qid_version != stat->qid.version)
                np->flags |= P9FS_NODE_MODIFIED;
        memcpy(&np->vqid, &stat->qid, sizeof(stat->qid));
+       if (!excl_locked)
+               VI_UNLOCK(vp);
 
        return (0);
 }
@@ -2213,12 +2236,25 @@ p9fs_putpages(struct vop_putpages_args *ap)
        return (rtvals[0]);
 }
 
+static int
+p9fs_delayed_setsize(struct vop_delayed_setsize_args *ap)
+{
+       struct vnode *vp;
+       struct p9fs_node *np;
+
+       vp = ap->a_vp;
+       np = P9FS_VTON(vp);
+       vnode_pager_setsize(vp, np->inode.i_size);
+       return (0);
+}
+
 struct vop_vector p9fs_vnops = {
        .vop_default =          &default_vnodeops,
        .vop_lookup =           p9fs_lookup,
        .vop_open =             p9fs_open,
        .vop_close =            p9fs_close,
        .vop_access =           p9fs_access,
+       .vop_delayed_setsize =  p9fs_delayed_setsize,
        .vop_getattr =          p9fs_getattr_dotl,
        .vop_setattr =          p9fs_setattr_dotl,
        .vop_reclaim =          p9fs_reclaim,

Reply via email to