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>