Author: mjg
Date: Sun Feb 16 03:33:34 2020
New Revision: 357991
URL: https://svnweb.freebsd.org/changeset/base/357991

Log:
  vfs: fix vlrureclaim ->v_object access
  
  The routine was checking for ->v_type == VBAD. Since vgone drops the interlock
  early sets this type at the end of the process of dooming a vnode, this opens
  a time window where it can clear the pointer while the inerlock-holders is
  accessing it.
  
  Another note is that the code was:
           (vp->v_object != NULL &&
           vp->v_object->resident_page_count > trigger)
  
  With the compiler being fully allowed to emit another read to get the pointer,
  and in fact it did on the kernel used by pho.
  
  Use atomic_load_ptr and remember the result.
  
  Note that this depends on type-safety of vm_object.
  
  Reported by:  pho

Modified:
  head/sys/kern/vfs_subr.c

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c    Sun Feb 16 03:16:28 2020        (r357990)
+++ head/sys/kern/vfs_subr.c    Sun Feb 16 03:33:34 2020        (r357991)
@@ -1100,6 +1100,7 @@ vlrureclaim(bool reclaim_nc_src, int trigger, u_long t
 {
        struct vnode *vp, *mvp;
        struct mount *mp;
+       struct vm_object *object;
        u_long done;
        bool retried;
 
@@ -1137,12 +1138,17 @@ restart:
 
                if (vp->v_usecount > 0 || vp->v_holdcnt == 0 ||
                    (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) ||
-                   vp->v_type == VBAD || vp->v_type == VNON ||
-                   (vp->v_object != NULL &&
-                   vp->v_object->resident_page_count > trigger)) {
+                   VN_IS_DOOMED(vp) || vp->v_type == VNON) {
                        VI_UNLOCK(vp);
                        goto next_iter;
                }
+
+               object = atomic_load_ptr(&vp->v_object);
+               if (object == NULL || object->resident_page_count > trigger) {
+                       VI_UNLOCK(vp);
+                       goto next_iter;
+               }
+
                vholdl(vp);
                VI_UNLOCK(vp);
                TAILQ_REMOVE(&vnode_list, mvp, v_vnodelist);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to