Index: sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c =================================================================== --- sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c +++ sys/contrib/openzfs/module/os/freebsd/zfs/zfs_znode.c @@ -1079,9 +1079,18 @@ * the vnode in case of error, but currently we cannot do that * because of the LOR between the vnode lock and z_teardown_lock. * So, instead, we have to "doom" the znode in the illumos style. + * + * Ignore invalid pages during the scan. This is to avoid deadlocks + * between page busying and the teardown lock, as pages are typically + * busied prior to a VOP_GETPAGES operation, which acquires the teardown + * lock. Such pages will be invalid and can safely be skipped here. */ vp = ZTOV(zp); +#if __FreeBSD_version >= 1400042 + vn_pages_remove_valid(vp, 0, 0); +#else vn_pages_remove(vp, 0, 0); +#endif ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num); Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -2441,6 +2441,18 @@ VM_OBJECT_WUNLOCK(object); } +void +vn_pages_remove_valid(struct vnode *vp, vm_pindex_t start, vm_pindex_t end) +{ + vm_object_t object; + + if ((object = vp->v_object) == NULL) + return; + VM_OBJECT_WLOCK(object); + vm_object_page_remove(object, start, end, OBJPR_VALIDONLY); + VM_OBJECT_WUNLOCK(object); +} + int vn_bmap_seekhole_locked(struct vnode *vp, u_long cmd, off_t *off, struct ucred *cred) Index: sys/sys/param.h =================================================================== --- sys/sys/param.h +++ sys/sys/param.h @@ -76,7 +76,7 @@ * cannot include sys/param.h and should only be updated here. */ #undef __FreeBSD_version -#define __FreeBSD_version 1400041 +#define __FreeBSD_version 1400042 /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -770,6 +770,8 @@ int vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred, struct thread *td, struct file *fp); void vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end); +void vn_pages_remove_valid(struct vnode *vp, vm_pindex_t start, + vm_pindex_t end); int vn_pollrecord(struct vnode *vp, struct thread *p, int events); int vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base, int len, off_t offset, enum uio_seg segflg, int ioflg, Index: sys/vm/vm_object.h =================================================================== --- sys/vm/vm_object.h +++ sys/vm/vm_object.h @@ -232,6 +232,7 @@ */ #define OBJPR_CLEANONLY 0x1 /* Don't remove dirty pages. */ #define OBJPR_NOTMAPPED 0x2 /* Don't unmap pages. */ +#define OBJPR_VALIDONLY 0x4 /* Ignore invalid pages. */ TAILQ_HEAD(object_q, vm_object); Index: sys/vm/vm_object.c =================================================================== --- sys/vm/vm_object.c +++ sys/vm/vm_object.c @@ -2094,6 +2094,21 @@ for (; p != NULL && (p->pindex < end || end == 0); p = next) { next = TAILQ_NEXT(p, listq); + /* + * Skip invalid pages if asked to do so. Try to avoid acquiring + * the busy lock, as some consumers rely on this to avoid + * deadlocks. + * + * A thread may concurrently transition the page from invalid to + * valid using only the busy lock, so the result of this check + * is immediately stale. It is up to consumers to handle this, + * for instance by ensuring that all invalid->valid transitions + * happen with a mutex held, as may be possible for a + * filesystem. + */ + if ((options & OBJPR_VALIDONLY) != 0 && vm_page_none_valid(p)) + continue; + /* * If the page is wired for any reason besides the existence * of managed, wired mappings, then it cannot be freed. For @@ -2106,6 +2121,10 @@ vm_page_sleep_if_busy(p, "vmopar"); goto again; } + if ((options & OBJPR_VALIDONLY) != 0 && vm_page_none_valid(p)) { + vm_page_xunbusy(p); + continue; + } if (vm_page_wired(p)) { wired: if ((options & OBJPR_NOTMAPPED) == 0 &&