diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c --- a/sys/fs/ext2fs/ext2_vfsops.c +++ b/sys/fs/ext2fs/ext2_vfsops.c @@ -1345,7 +1345,7 @@ 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 --- a/sys/fs/fuse/fuse_node.c +++ b/sys/fs/fuse/fuse_node.c @@ -354,7 +354,7 @@ 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 --- a/sys/fs/fuse/fuse_vfsops.c +++ b/sys/fs/fuse/fuse_vfsops.c @@ -286,7 +286,7 @@ 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 --- a/sys/geom/geom_vfs.c +++ b/sys/geom/geom_vfs.c @@ -292,7 +292,16 @@ 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 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1081,7 +1081,14 @@ 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 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -146,27 +146,22 @@ 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 @@ 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) {