git: 89559b5d279c - stable/15 - vfs: add VOP_DELAYED_SETSIZE() and related infrastructure
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 17 Mar 2026 00:38:21 UTC
The branch stable/15 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=89559b5d279c6cccfe6ddd27f81408b1f0d44f15
commit 89559b5d279c6cccfe6ddd27f81408b1f0d44f15
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-02-28 16:11:58 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-03-15 06:58:56 +0000
vfs: add VOP_DELAYED_SETSIZE() and related infrastructure
(cherry picked from commit 45117ffcd533ddf995f654db60b10899ae8370ec)
---
sys/fs/deadfs/dead_vnops.c | 1 +
sys/kern/vfs_default.c | 1 +
sys/kern/vfs_vnops.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-
sys/kern/vnode_if.src | 8 +++++
sys/sys/vnode.h | 31 +++++++++++++++++++
5 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/sys/fs/deadfs/dead_vnops.c b/sys/fs/deadfs/dead_vnops.c
index 137c86b65058..b6d6fa55d221 100644
--- a/sys/fs/deadfs/dead_vnops.c
+++ b/sys/fs/deadfs/dead_vnops.c
@@ -80,6 +80,7 @@ struct vop_vector dead_vnodeops = {
.vop_write = dead_write,
.vop_fplookup_vexec = VOP_EOPNOTSUPP,
.vop_fplookup_symlink = VOP_EOPNOTSUPP,
+ .vop_delayed_setsize = VOP_NULL,
};
VFS_VOP_VECTOR_REGISTER(dead_vnodeops);
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index e04f328c0b37..76f63b187b65 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -147,6 +147,7 @@ struct vop_vector default_vnodeops = {
.vop_add_writecount = vop_stdadd_writecount,
.vop_copy_file_range = vop_stdcopy_file_range,
.vop_vput_pair = vop_stdvput_pair,
+ .vop_delayed_setsize = VOP_PANIC,
};
VFS_VOP_VECTOR_REGISTER(default_vnodeops);
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 68c0ea952e11..164a6b30d9ad 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -1963,9 +1963,74 @@ _vn_lock_fallback(struct vnode *vp, int flags, const char *file, int line,
return (0);
}
+static int
+vn_lock_delayed_setsize(struct vop_lock1_args *ap)
+{
+ struct vnode *vp;
+ int error, lktype;
+ bool onfault;
+
+ vp = ap->a_vp;
+ lktype = ap->a_flags & LK_TYPE_MASK;
+ if (vp->v_op == &dead_vnodeops)
+ return (0);
+ VI_LOCK(vp);
+ if ((vp->v_iflag & VI_DELAYEDSSZ) == 0 || (lktype != LK_SHARED &&
+ lktype != LK_EXCLUSIVE && lktype != LK_UPGRADE &&
+ lktype != LK_TRYUPGRADE)) {
+ VI_UNLOCK(vp);
+ return (0);
+ }
+ onfault = (ap->a_flags & LK_EATTR_MASK) == LK_NOWAIT &&
+ (ap->a_flags & LK_INIT_MASK) == LK_CANRECURSE &&
+ (lktype == LK_SHARED || lktype == LK_EXCLUSIVE);
+ if (onfault && vp->v_vnlock->lk_recurse == 0) {
+ /*
+ * Force retry in vm_fault(), to make the lock request
+ * sleepable, which allows us to piggy-back the
+ * sleepable call to vnode_pager_setsize().
+ */
+ VI_UNLOCK(vp);
+ VOP_UNLOCK(vp);
+ return (EBUSY);
+ }
+ if ((ap->a_flags & LK_NOWAIT) != 0 ||
+ (lktype == LK_SHARED && vp->v_vnlock->lk_recurse > 0)) {
+ VI_UNLOCK(vp);
+ return (0);
+ }
+ if (lktype == LK_SHARED) {
+ VOP_UNLOCK(vp);
+ ap->a_flags &= ~LK_TYPE_MASK;
+ ap->a_flags |= LK_EXCLUSIVE | LK_INTERLOCK;
+ error = VOP_LOCK1_APV(&default_vnodeops, ap);
+ if (error != 0 || vp->v_op == &dead_vnodeops)
+ return (error);
+ if (vp->v_data == NULL)
+ goto downgrade;
+ MPASS(vp->v_data != NULL);
+ VI_LOCK(vp);
+ if ((vp->v_iflag & VI_DELAYEDSSZ) == 0) {
+ VI_UNLOCK(vp);
+ goto downgrade;
+ }
+ }
+ vp->v_iflag &= ~VI_DELAYEDSSZ;
+ VI_UNLOCK(vp);
+ VOP_DELAYED_SETSIZE(vp);
+downgrade:
+ if (lktype == LK_SHARED) {
+ ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK);
+ ap->a_flags |= LK_DOWNGRADE;
+ (void)VOP_LOCK1_APV(&default_vnodeops, ap);
+ }
+ return (0);
+}
+
int
_vn_lock(struct vnode *vp, int flags, const char *file, int line)
{
+ struct vop_lock1_args ap;
int error;
VNASSERT((flags & LK_TYPE_MASK) != 0, vp,
@@ -1974,7 +2039,14 @@ _vn_lock(struct vnode *vp, int flags, const char *file, int line)
error = VOP_LOCK1(vp, flags, file, line);
if (__predict_false(error != 0 || VN_IS_DOOMED(vp)))
return (_vn_lock_fallback(vp, flags, file, line, error));
- return (0);
+ if (__predict_false((vp->v_iflag & VI_DELAYEDSSZ) == 0))
+ return (0);
+ ap.a_gen.a_desc = &vop_lock1_desc;
+ ap.a_vp = vp;
+ ap.a_flags = flags;
+ ap.a_file = file;
+ ap.a_line = line;
+ return (vn_lock_delayed_setsize(&ap));
}
/*
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index 6b7448d9f1df..78ba1aa7afda 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -847,6 +847,14 @@ vop_inotify_add_watch {
IN struct thread *td;
};
+
+%% delayed_setsize vp E E E
+
+vop_delayed_setsize {
+ IN struct vnode *vp;
+};
+
+
# The VOPs below are spares at the end of the table to allow new VOPs to be
# added in stable branches without breaking the KBI. New VOPs in HEAD should
# be added above these spares. When merging a new VOP to a stable branch,
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 8bcf2d43ff51..257e5e4f665c 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -268,6 +268,7 @@ _Static_assert(sizeof(struct vnode) <= 448, "vnode size crosses 448 bytes");
#define VI_DEFINACT 0x0010 /* deferred inactive */
#define VI_FOPENING 0x0020 /* In open, with opening process having the
first right to advlock file */
+#define VI_DELAYEDSSZ 0x0040 /* Delayed setsize */
#define VV_ROOT 0x0001 /* root of its filesystem */
#define VV_ISTTY 0x0002 /* vnode represents a tty */
@@ -1260,6 +1261,36 @@ vn_get_state(struct vnode *vp)
atomic_load_consume_ptr(&(_vp)->v_data);\
})
+static inline void
+vn_delay_setsize_locked(struct vnode *vp)
+{
+ ASSERT_VI_LOCKED(vp, "delayed_setsize");
+ vp->v_iflag |= VI_DELAYEDSSZ;
+}
+
+static inline void
+vn_delay_setsize(struct vnode *vp)
+{
+ VI_LOCK(vp);
+ vn_delay_setsize_locked(vp);
+ VI_UNLOCK(vp);
+}
+
+static inline void
+vn_clear_delayed_setsize_locked(struct vnode *vp)
+{
+ ASSERT_VI_LOCKED(vp, "delayed_setsize");
+ vp->v_iflag &= ~VI_DELAYEDSSZ;
+}
+
+static inline void
+vn_clear_delayed_setsize(struct vnode *vp)
+{
+ VI_LOCK(vp);
+ vn_clear_delayed_setsize_locked(vp);
+ VI_UNLOCK(vp);
+}
+
#endif /* _KERNEL */
#endif /* !_SYS_VNODE_H_ */