Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 9 Apr 2019 19:55:03 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r346064 - head/sys/fs/msdosfs
Message-ID:  <201904091955.x39Jt35P068854@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Apr  9 19:55:02 2019
New Revision: 346064
URL: https://svnweb.freebsd.org/changeset/base/346064

Log:
  Fix dirty buf exhaustion easily triggered with msdosfs.
  
  If truncate(2) is performed on msdosfs file, which extends the file by
  system-depended large amount, fs creates corresponding amount of dirty
  delayed-write buffers, which can consume all buffers.  Such buffers
  cannot be flushed by the bufdaemon because the ftruncate() thread owns
  the vnode lock.  So the system runs out of free buffers, and even
  truncate() thread starves, which means deadlock because it owns the
  vnode lock.
  
  Fix this by doing vnode fsync in extendfile() when low memory or low
  buffers condition detected, which flushes all dirty buffers belonging
  to the file being extended.
  
  Note that the more usual fallback to bawrite() does not work
  acceptable in this situation, because it would only allow one buffer
  to be recycled.  Other filesystems, most important UFS, do not allow
  userspace to create arbitrary amount of dirty delayed-write buffers
  without feedback, so bawrite() is good enough for them.
  
  Reported and tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

Modified:
  head/sys/fs/msdosfs/msdosfs_fat.c

Modified: head/sys/fs/msdosfs/msdosfs_fat.c
==============================================================================
--- head/sys/fs/msdosfs/msdosfs_fat.c	Tue Apr  9 19:22:08 2019	(r346063)
+++ head/sys/fs/msdosfs/msdosfs_fat.c	Tue Apr  9 19:55:02 2019	(r346064)
@@ -54,6 +54,7 @@
 #include <sys/systm.h>
 #include <sys/buf.h>
 #include <sys/mount.h>
+#include <sys/vmmeter.h>
 #include <sys/vnode.h>
 
 #include <fs/msdosfs/bpb.h>
@@ -979,6 +980,7 @@ extendfile(struct denode *dep, u_long count, struct bu
 	u_long cn, got;
 	struct msdosfsmount *pmp = dep->de_pmp;
 	struct buf *bp;
+	struct vop_fsync_args fsync_ap;
 	daddr_t blkno;
 
 	/*
@@ -1086,8 +1088,16 @@ extendfile(struct denode *dep, u_long count, struct bu
 				if (bpp) {
 					*bpp = bp;
 					bpp = NULL;
-				} else
+				} else {
 					bdwrite(bp);
+				}
+				if (vm_page_count_severe() ||
+				    buf_dirty_count_severe()) {
+					fsync_ap.a_vp = DETOV(dep);
+					fsync_ap.a_waitfor = MNT_WAIT;
+					fsync_ap.a_td = curthread;
+					vop_stdfsync(&fsync_ap);
+				}
 			}
 		}
 	}



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