git: 56a8aca83ab5 - main - Stop treating size 0 as unknown size in vnode_create_vobject().

From: Pawel Jakub Dawidek <pjd_at_FreeBSD.org>
Date: Thu, 23 May 2024 06:08:32 UTC
The branch main has been updated by pjd:

URL: https://cgit.FreeBSD.org/src/commit/?id=56a8aca83ab5a93af05f4c8c3a358b71a8392af8

commit 56a8aca83ab5a93af05f4c8c3a358b71a8392af8
Author:     Pawel Jakub Dawidek <pjd@FreeBSD.org>
AuthorDate: 2024-05-19 01:08:41 +0000
Commit:     Pawel Jakub Dawidek <pjd@FreeBSD.org>
CommitDate: 2024-05-23 06:08:14 +0000

    Stop treating size 0 as unknown size in vnode_create_vobject().
    
    Whenever file is created, the vnode_create_vobject() function will
    try to determine its size by calling vn_getsize_locked() as size 0
    is ambigious: it means either the file size is 0 or the file size
    is unknown.
    
    Introduce special value for the size argument: VNODE_NO_SIZE.
    Only when it is given, the vnode_create_vobject() will try to obtain
    file's size on its own.
    
    Introduce dedicated vnode_disk_create_vobject() for use by
    g_vfs_open(), so we don't have to call vn_isdisk() in the common case
    (for regular files).
    
    Handle the case of mediasize==0 in g_vfs_open().
    
    Reviewed by: alc, kib, markj, olce
    Approved by: oshogbo (mentor), allanjude (mentor)
    Differential Revision: https://reviews.freebsd.org/D45244
---
 sys/fs/ext2fs/ext2_vfsops.c |  2 +-
 sys/fs/fuse/fuse_node.c     |  2 +-
 sys/fs/fuse/fuse_vfsops.c   |  2 +-
 sys/geom/geom_vfs.c         | 11 ++++++++++-
 sys/sys/vnode.h             |  7 +++++++
 sys/vm/vnode_pager.c        | 45 +++++++++++++++++++++++++++++++--------------
 6 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c
index bffbf4546f37..9e7a03fffd71 100644
--- a/sys/fs/ext2fs/ext2_vfsops.c
+++ b/sys/fs/ext2fs/ext2_vfsops.c
@@ -1345,7 +1345,7 @@ ext2_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
 		return (ESTALE);
 	}
 	*vpp = nvp;
-	vnode_create_vobject(*vpp, 0, curthread);
+	vnode_create_vobject(*vpp, ip->i_size, curthread);
 	return (0);
 }
 
diff --git a/sys/fs/fuse/fuse_node.c b/sys/fs/fuse/fuse_node.c
index 777519450954..0a24d0da4fac 100644
--- a/sys/fs/fuse/fuse_node.c
+++ b/sys/fs/fuse/fuse_node.c
@@ -354,7 +354,7 @@ void
 fuse_vnode_open(struct vnode *vp, int32_t fuse_open_flags, struct thread *td)
 {
 	if (vnode_vtype(vp) == VREG)
-		vnode_create_vobject(vp, 0, td);
+		vnode_create_vobject(vp, VNODE_NO_SIZE, td);
 }
 
 int
diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c
index e088f92bf5bf..e60c9aa80cfa 100644
--- a/sys/fs/fuse/fuse_vfsops.c
+++ b/sys/fs/fuse/fuse_vfsops.c
@@ -286,7 +286,7 @@ fuse_vfsop_fhtovp(struct mount *mp, struct fid *fhp, int flags,
 		return (ESTALE);
 	}
 	*vpp = nvp;
-	vnode_create_vobject(*vpp, 0, curthread);
+	vnode_create_vobject(*vpp, VNODE_NO_SIZE, curthread);
 	return (0);
 }
 
diff --git a/sys/geom/geom_vfs.c b/sys/geom/geom_vfs.c
index 87b2fea21baa..d9e9a6c82da1 100644
--- a/sys/geom/geom_vfs.c
+++ b/sys/geom/geom_vfs.c
@@ -292,7 +292,16 @@ g_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr
 		g_wither_geom(gp, ENXIO);
 		return (error);
 	}
-	vnode_create_vobject(vp, pp->mediasize, curthread);
+	/*
+	 * Mediasize might not be set until first access (see g_disk_access()),
+	 * That's why we check it here and not earlier.
+	 */
+	if (pp->mediasize == 0) {
+		(void)g_access(cp, -1, -wr, -wr);
+		g_wither_geom(gp, ENXIO);
+		return (ENXIO);
+	}
+	vnode_create_disk_vobject(vp, pp->mediasize, curthread);
 	*cpp = cp;
 	cp->private = vp;
 	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 987cf995f606..dc926d7a9c9e 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -1081,7 +1081,14 @@ vrefcnt(struct vnode *vp)
 	vref(vp);							\
 } while (0)
 
+/*
+ * The caller doesn't know the file size and vnode_create_vobject() should
+ * determine the size on its own.
+ */
+#define	VNODE_NO_SIZE	((off_t)-1)
+
 int vnode_create_vobject(struct vnode *vp, off_t size, struct thread *td);
+int vnode_create_disk_vobject(struct vnode *vp, off_t size, struct thread *td);
 void vnode_destroy_vobject(struct vnode *vp);
 
 extern struct vop_vector fifo_specops;
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index d32fec845043..98b905f27c4a 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -146,27 +146,22 @@ vnode_pager_init(void *dummy)
 SYSINIT(vnode_pager, SI_SUB_CPU, SI_ORDER_ANY, vnode_pager_init, NULL);
 
 /* Create the VM system backing object for this vnode */
-int
-vnode_create_vobject(struct vnode *vp, off_t isize, struct thread *td)
+static int
+vnode_create_vobject_any(struct vnode *vp, off_t isize, struct thread *td)
 {
 	vm_object_t object;
-	vm_ooffset_t size = isize;
+	vm_ooffset_t size;
 	bool last;
 
-	if (!vn_isdisk(vp) && vn_canvmio(vp) == FALSE)
-		return (0);
-
 	object = vp->v_object;
 	if (object != NULL)
 		return (0);
 
-	if (size == 0) {
-		if (vn_isdisk(vp)) {
-			size = IDX_TO_OFF(INT_MAX);
-		} else {
-			if (vn_getsize_locked(vp, &size, td->td_ucred) != 0)
-				return (0);
-		}
+	if (isize == VNODE_NO_SIZE) {
+		if (vn_getsize_locked(vp, &size, td->td_ucred) != 0)
+			return (0);
+	} else {
+		size = isize;
 	}
 
 	object = vnode_pager_alloc(vp, size, 0, 0, td->td_ucred);
@@ -182,11 +177,33 @@ vnode_create_vobject(struct vnode *vp, off_t isize, struct thread *td)
 	if (last)
 		vrele(vp);
 
-	KASSERT(vp->v_object != NULL, ("vnode_create_vobject: NULL object"));
+	VNASSERT(vp->v_object != NULL, vp, ("%s: NULL object", __func__));
 
 	return (0);
 }
 
+int
+vnode_create_vobject(struct vnode *vp, off_t isize, struct thread *td)
+{
+	VNASSERT(!vn_isdisk(vp), vp, ("%s: disk vnode", __func__));
+	VNASSERT(isize == VNODE_NO_SIZE || isize >= 0, vp,
+	    ("%s: invalid size (%jd)", __func__, (intmax_t)isize));
+
+	if (!vn_canvmio(vp))
+		return (0);
+
+	return (vnode_create_vobject_any(vp, isize, td));
+}
+
+int
+vnode_create_disk_vobject(struct vnode *vp, off_t isize, struct thread *td)
+{
+	VNASSERT(isize > 0, vp, ("%s: invalid size (%jd)", __func__,
+	    (intmax_t)isize));
+
+	return (vnode_create_vobject_any(vp, isize, td));
+}
+
 void
 vnode_destroy_vobject(struct vnode *vp)
 {