Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Aug 2002 21:19:47 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Pierre Beyssac <beyssac@enst.fr>
Cc:        freebsd-current@FreeBSD.ORG
Subject:   Re: deadlock in fs/msdosfs/msdosfs_vnops.c:msdosfs_fsync()
Message-ID:  <20020805203323.M17317-100000@gamplex.bde.org>
In-Reply-To: <20020805104153.A37733@bofh.enst.fr>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 5 Aug 2002, Pierre Beyssac wrote:

> I'm having a problem with the fsync() call on the MSDOS filesystem.
>
> I have a reproductible way (using a specific application under Wine)
> to get it to deadlock in the msleep() call. If I disable msdos_fsync()
> entirely by adding a return 0 at the top, everything runs smoothly,
> no deadlock.

msdosfs_fsync() doesn't honor the MNT_NOWAIT flag.  This might explain
your problem.  msdosfs (and other filesystems, and even ffs in RELENG_4?)
is missing fixes for endless looping on write errors.  This is
unlikely to be the problem here.

> Since AFAIK the problem doesn't occur with ufs fsync(), should I
> suppose this may have to do (and should I start looking) with the
> way msdosfs handles vp->v_numoutput, can it be a deadlock with some
> other vnode locking in the msdosfs code, or can it be an unexpected
> side-effet of recent SMP/KSE changes (not likely considering my
> machine is UP) ?

The following patch makes msdosfs_fsync() as identical as possible with
an old version of ffs_fsync().  Summary of the changes:
- in the main loop, optimize bwrite() to vfs_bio_awrite() in the MNT_NOWAIT
  case.  A more up to date merge from ffs would do this in the !MNT_WAIT
  case (ffs once had more complications involving the MNT_LAZY case
  and some of these complications made it into this patch and into
  some other filesystems).  A less agressive optimization would use
  bawrite() for the !MNT_WAIT case and bwrite() for the MNT_WAIT case.
- in the main loop, exit early if bwrite() fails.  This is from rev.1.57
  of ffs_vnops.c.  IIRC, in ffs this fixes endless looping on write
  errors in some but not all cases.  However, it seems to be moot here
  because the other change in the main loop makes the bwrite() unreachable
  (the Debugger() call is to detect it being reached).
- don't wait for v_numoutput in the !MNT_WAIT case.
- don't use a too-long or poorly abbreviated string for the sleep message.

%%%
Index: msdosfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_vnops.c,v
retrieving revision 1.121
diff -u -2 -r1.121 msdosfs_vnops.c
--- msdosfs_vnops.c	16 May 2002 21:25:37 -0000	1.121
+++ msdosfs_vnops.c	21 May 2002 21:07:15 -0000
@@ -808,12 +821,12 @@
 {
 	struct vnode *vp = ap->a_vp;
-	int s;
 	struct buf *bp, *nbp;
+	int error, s;

 	/*
 	 * Flush all dirty buffers associated with a vnode.
 	 */
-loop:
 	s = splbio();
+loop:
 	for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
 		nbp = TAILQ_NEXT(bp, b_vnbufs);
@@ -822,19 +835,35 @@
 		if ((bp->b_flags & B_DELWRI) == 0)
 			panic("msdosfs_fsync: not dirty");
-		bremfree(bp);
-		splx(s);
-		(void) bwrite(bp);
+		if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) {
+			BUF_UNLOCK(bp);
+			vfs_bio_awrite(bp);
+		} else {
+			/*
+			 * Wait for I/O associated with metadata blocks to
+			 * complete, since there is no way to quickly wait
+			 * for them below.
+			 */
+			Debugger("msdosfs_fsync: metadata");
+			bremfree(bp);
+			splx(s);
+			error = bwrite(bp);
+			if (error != 0)
+				return (error);
+			s = splbio();
+		}
 		goto loop;
 	}
-	while (vp->v_numoutput) {
-		vp->v_flag |= VBWAIT;
-		(void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "msdosfsn", 0);
-	}
+	if (ap->a_waitfor == MNT_WAIT) {
+		while (vp->v_numoutput) {
+			vp->v_flag |= VBWAIT;
+			tsleep(&vp->v_numoutput, PRIBIO + 1, "msfsyn", 0);
+		}
 #ifdef DIAGNOSTIC
-	if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
-		vprint("msdosfs_fsync: dirty", vp);
-		goto loop;
-	}
+		if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
+			vprint("msdosfs_fsync: dirty", vp);
+			goto loop;
+		}
 #endif
+	}
 	splx(s);
 	return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
%%%

Bruce


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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020805203323.M17317-100000>