Page MenuHomeFreeBSD

D32931.id98379.diff
No OneTemporary

D32931.id98379.diff

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 busied prior
+ * to a VOP_GETPAGES operation, which acquires the teardown read 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
@@ -2429,6 +2429,10 @@
return (setfown(td, active_cred, vp, uid, gid));
}
+/*
+ * Remove pages in the range ["start", "end") from the vnode's VM object. If
+ * "end" is 0, then the range extends to the end of the object.
+ */
void
vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
{
@@ -2441,6 +2445,24 @@
VM_OBJECT_WUNLOCK(object);
}
+/*
+ * Like vn_pages_remove(), but skips invalid pages, which by definition are not
+ * mapped into any process' address space. Filesystems may use this in
+ * preference to vn_pages_remove() to avoid blocking on pages busied in
+ * preparation for a VOP_GETPAGES.
+ */
+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 &&

File Metadata

Mime Type
text/plain
Expires
Thu, Aug 27, 11:37 AM (15 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37380383
Default Alt Text
D32931.id98379.diff (4 KB)

Event Timeline