Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168119610
D32931.id98379.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D32931.id98379.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D32931: zfs: Fix a deadlock between page busy and the teardown lock
Attached
Detach File
Event Timeline
Log In to Comment