kern/178997: Heavy disk I/O may hang system
Klaus Weber
fbsd-bugs-2013-1 at unix-admin.de
Wed Jul 31 16:30:02 UTC 2013
The following reply was made to PR kern/178997; it has been noted by GNATS.
From: Klaus Weber <fbsd-bugs-2013-1 at unix-admin.de>
To: Bruce Evans <brde at optusnet.com.au>, freebsd-gnats-submit at FreeBSD.org
Cc: Klaus Weber <fbsd-bugs-2013-1 at unix-admin.de>
Subject: Re: kern/178997: Heavy disk I/O may hang system
Date: Wed, 31 Jul 2013 18:18:59 +0200
--OgqxwSJOaUobr8KG
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
After studying style(9), I have now made a revised version of the
patch, relative to 9/STABLE of about 3 weeks ago:
Index: sys/kern/vfs_bio.c
===================================================================
--- sys/kern/vfs_bio.c (revision 253339)
+++ sys/kern/vfs_bio.c (working copy)
@@ -1146,7 +1146,7 @@
if (bo->bo_dirty.bv_cnt > dirtybufthresh + 10) {
(void) VOP_FSYNC(bp->b_vp, MNT_NOWAIT, curthread);
altbufferflushes++;
- } else if (bo->bo_dirty.bv_cnt > dirtybufthresh) {
+ } else if (bdflush_required(bo)) {
BO_LOCK(bo);
/*
* Try to find a buffer to flush.
@@ -1438,6 +1438,24 @@
}
/*
+ * Flushing is deemed necessary if at least one of the following is true:
+ * - bo is hogging more than dirtybufthresh buffers (previous behavior)
+ * - numdirtybuffers exceeds dirtybufthresh
+ * - we are or act as bufdaemon (TDP_NORUNNINGBUF)
+ */
+int
+bdflush_required(struct bufobj *bo)
+{
+ struct thread *td = curthread;
+
+ KASSERT(bo != NULL, ("bdflush_required: NULL bo"));
+
+ return ((bo->bo_dirty.bv_cnt > dirtybufthresh) ||
+ (numdirtybuffers > dirtybufthresh) ||
+ (td && (td->td_pflags & TDP_NORUNNINGBUF)));
+}
+
+/*
* brelse:
*
* Release a busy buffer and, if requested, free its resources. The
Index: sys/sys/buf.h
===================================================================
--- sys/sys/buf.h (revision 253339)
+++ sys/sys/buf.h (working copy)
@@ -486,6 +486,7 @@
void bdata2bio(struct buf *bp, struct bio *bip);
void bwillwrite(void);
int buf_dirty_count_severe(void);
+int bdflush_required(struct bufobj *bo);
void bremfree(struct buf *);
void bremfreef(struct buf *); /* XXX Force bremfree, only for nfs. */
int bread(struct vnode *, daddr_t, int, struct ucred *, struct buf **);
Index: sys/ufs/ffs/ffs_snapshot.c
===================================================================
--- sys/ufs/ffs/ffs_snapshot.c (revision 253339)
+++ sys/ufs/ffs/ffs_snapshot.c (working copy)
@@ -2161,7 +2161,7 @@
struct buf *nbp;
int bp_bdskip;
- if (bo->bo_dirty.bv_cnt <= dirtybufthresh)
+ if (!bdflush_required(bo))
return;
td = curthread;
[End of patch]
Besides being more concise, I hope this patch no longer has
style-issues, although I was not sure regarding the indention of the
second and third line of the return statement. I chose to left-align
the condtions.
I have also tested limiting numdirtybuffers to hidirtybuffers (instead
of dirtybufthresh), but that does not prevent the system from hanging.
I would appreciate if someone could review and eventually commit this
patch (or a variant thereof), and then close this bug.
Thanks, Klaus
--OgqxwSJOaUobr8KG
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="bo_dirty.bv_cnt_FIX_FINAL.patch"
Index: sys/kern/vfs_bio.c
===================================================================
--- sys/kern/vfs_bio.c (revision 253339)
+++ sys/kern/vfs_bio.c (working copy)
@@ -1146,7 +1146,7 @@
if (bo->bo_dirty.bv_cnt > dirtybufthresh + 10) {
(void) VOP_FSYNC(bp->b_vp, MNT_NOWAIT, curthread);
altbufferflushes++;
- } else if (bo->bo_dirty.bv_cnt > dirtybufthresh) {
+ } else if (bdflush_required(bo)) {
BO_LOCK(bo);
/*
* Try to find a buffer to flush.
@@ -1438,6 +1438,24 @@
}
/*
+ * Flushing is deemed necessary if at least one of the following is true:
+ * - bo is hogging more than dirtybufthresh buffers (previous behavior)
+ * - numdirtybuffers exceeds dirtybufthresh
+ * - we are or act as bufdaemon (TDP_NORUNNINGBUF)
+ */
+int
+bdflush_required(struct bufobj *bo)
+{
+ struct thread *td = curthread;
+
+ KASSERT(bo != NULL, ("bdflush_required: NULL bo"));
+
+ return ((bo->bo_dirty.bv_cnt > dirtybufthresh) ||
+ (numdirtybuffers > dirtybufthresh) ||
+ (td && (td->td_pflags & TDP_NORUNNINGBUF)));
+}
+
+/*
* brelse:
*
* Release a busy buffer and, if requested, free its resources. The
Index: sys/sys/buf.h
===================================================================
--- sys/sys/buf.h (revision 253339)
+++ sys/sys/buf.h (working copy)
@@ -486,6 +486,7 @@
void bdata2bio(struct buf *bp, struct bio *bip);
void bwillwrite(void);
int buf_dirty_count_severe(void);
+int bdflush_required(struct bufobj *bo);
void bremfree(struct buf *);
void bremfreef(struct buf *); /* XXX Force bremfree, only for nfs. */
int bread(struct vnode *, daddr_t, int, struct ucred *, struct buf **);
Index: sys/ufs/ffs/ffs_snapshot.c
===================================================================
--- sys/ufs/ffs/ffs_snapshot.c (revision 253339)
+++ sys/ufs/ffs/ffs_snapshot.c (working copy)
@@ -2161,7 +2161,7 @@
struct buf *nbp;
int bp_bdskip;
- if (bo->bo_dirty.bv_cnt <= dirtybufthresh)
+ if (!bdflush_required(bo))
return;
td = curthread;
--OgqxwSJOaUobr8KG--
More information about the freebsd-bugs
mailing list