This may or may not be related.  In tracking down the sched_sync() 
    panic I found two bugs.  

    First, a couple of places where the worklist was not being protected
    at splbio().  I'm not 100% sure that this is a problem but the code
    is complex enough that it's just too dangerous not to do it.

    Second, a double LIST_REMOVE() was being performed in the case where
    VOP_FSYNC() would fail to sync all the dirty pages.  This can occur
    legally for both NFS and filesystems with SOFTUPDATES set.

    I'd appreciate it if someone could verify the double LIST_REMOVE()
    bug.  vn_syncer_add_to_worklist() already removes the vn from
    the list ( assuming the VONWORKLIST v_flag is set, which it should be
    in this case ).

                                        -Matt
                                        Matthew Dillon 
                                        <dil...@backplane.com>

Index: kern/vfs_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.186
diff -u -r1.186 vfs_subr.c
--- vfs_subr.c  1999/02/04 18:25:39     1.186
+++ vfs_subr.c  1999/02/19 10:40:17
@@ -881,10 +881,8 @@
 /*
  * Add an item to the syncer work queue.
  */
-void
-vn_syncer_add_to_worklist(vp, delay)
-       struct vnode *vp;
-       int delay;
+static void
+vn_syncer_add_to_worklist(struct vnode *vp, int delay)
 {
        int s, slot;
 
@@ -928,7 +926,8 @@
                starttime = time_second;
 
                /*
-                * Push files whose dirty time has expired.
+                * Push files whose dirty time has expired.  Be careful
+                * of interrupt race on slp queue.
                 */
                s = splbio();
                slp = &syncer_workitem_pending[syncer_delayno];
@@ -941,16 +940,20 @@
                        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
                        (void) VOP_FSYNC(vp, p->p_ucred, MNT_LAZY, p);
                        VOP_UNLOCK(vp, 0, p);
+                       s = splbio();
                        if (LIST_FIRST(slp) == vp) {
                                if (TAILQ_EMPTY(&vp->v_dirtyblkhd) &&
                                    vp->v_type != VBLK)
-                                       panic("sched_sync: fsync failed");
+                                       panic("sched_sync: fsync failed vp %p 
type %d tag %d", vp, vp->v_type, vp->v_tag);
                                /*
                                 * Move ourselves to the back of the sync list.
+                                * vn_syncer_*worklist() will remove and re-add
+                                * the node.
                                 */
-                               LIST_REMOVE(vp, v_synclist);
+                               /*LIST_REMOVE(vp, v_synclist);*/
                                vn_syncer_add_to_worklist(vp, syncdelay);
                        }
+                       splx(s);
                }
 
                /*
@@ -2841,6 +2844,8 @@
 
 /*
  * The syncer vnode is no longer needed and is being decommissioned.
+ *
+ * Modifications to the worklist must be protected at splbio().
  */
 static int
 sync_reclaim(ap)
@@ -2849,12 +2854,15 @@
        } */ *ap;
 {
        struct vnode *vp = ap->a_vp;
+       int s;
 
+       s = splbio();
        vp->v_mount->mnt_syncer = NULL;
        if (vp->v_flag & VONWORKLST) {
                LIST_REMOVE(vp, v_synclist);
                vp->v_flag &= ~VONWORKLST;
        }
+       splx(s);
 
        return (0);
 }


To Unsubscribe: send mail to majord...@freebsd.org
with "unsubscribe freebsd-current" in the body of the message

Reply via email to