svn commit: r329139 - user/jeff/numa/sys/kern
Jeff Roberson
jeff at FreeBSD.org
Sun Feb 11 20:47:39 UTC 2018
Author: jeff
Date: Sun Feb 11 20:47:38 2018
New Revision: 329139
URL: https://svnweb.freebsd.org/changeset/base/329139
Log:
Fix a wakeup race in the bufspace daemon. Rename bufdomain->bd_request to
bd_running to better reflect what it means and remove ambiguity with the
dirty bd_request.
Modified:
user/jeff/numa/sys/kern/vfs_bio.c
Modified: user/jeff/numa/sys/kern/vfs_bio.c
==============================================================================
--- user/jeff/numa/sys/kern/vfs_bio.c Sun Feb 11 20:35:14 2018 (r329138)
+++ user/jeff/numa/sys/kern/vfs_bio.c Sun Feb 11 20:47:38 2018 (r329139)
@@ -313,6 +313,7 @@ struct bufqueue __exclusive_cache_line bqdirty;
struct bufdomain {
struct bufqueue bd_cpuq[MAXCPU];
struct bufqueue bd_cleanq;
+ struct mtx_padalign bd_run_lock;
/* Constants */
long bd_maxbufspace;
long bd_hibufspace;
@@ -323,7 +324,7 @@ struct bufdomain {
int bd_lim;
/* atomics */
int bd_wanted;
- int __aligned(CACHE_LINE_SIZE) bd_request;
+ int __aligned(CACHE_LINE_SIZE) bd_running;
long __aligned(CACHE_LINE_SIZE) bd_bufspace;
int __aligned(CACHE_LINE_SIZE) bd_freebuffers;
} __aligned(CACHE_LINE_SIZE);
@@ -332,6 +333,9 @@ struct bufdomain {
#define BD_LOCK(bd) mtx_lock(BD_LOCKPTR((bd)))
#define BD_UNLOCK(bd) mtx_unlock(BD_LOCKPTR((bd)))
#define BD_ASSERT_LOCKED(bd) mtx_assert(BD_LOCKPTR((bd)), MA_OWNED)
+#define BD_RUN_LOCKPTR(bd) (&(bd)->bd_run_lock)
+#define BD_RUN_LOCK(bd) mtx_lock(BD_RUN_LOCKPTR((bd)))
+#define BD_RUN_UNLOCK(bd) mtx_unlock(BD_RUN_LOCKPTR((bd)))
#define BD_DOMAIN(bd) (bd - bdclean)
/* Maximum number of clean buffer domains. */
@@ -474,23 +478,53 @@ bdirtyadd(void)
}
/*
- * bufspace_daemonwakeup:
+ * bufspace_daemon_wakeup:
*
* Wakeup the daemons responsible for freeing clean bufs.
*/
static void
-bufspace_daemonwakeup(struct bufdomain *bd)
+bufspace_daemon_wakeup(struct bufdomain *bd)
{
- if (atomic_fetchadd_int(&bd->bd_request, 1) == 0) {
- BD_LOCK(bd);
- bd->bd_request = 1;
- wakeup(&bd->bd_request);
- BD_UNLOCK(bd);
+ /*
+ * avoid the lock if the daemon is running.
+ */
+ if (atomic_fetchadd_int(&bd->bd_running, 1) == 0) {
+ BD_RUN_LOCK(bd);
+ bd->bd_running = 1;
+ wakeup(&bd->bd_running);
+ BD_RUN_UNLOCK(bd);
}
}
/*
+ * bufspace_daemon_wait:
+ *
+ * Sleep until the domain falls below a limit or one second passes.
+ */
+static void
+bufspace_daemon_wait(struct bufdomain *bd)
+{
+ /*
+ * Re-check our limits and sleep. bd_running must be
+ * cleared prior to checking the limits to avoid missed
+ * wakeups. The waker will adjust one of bufspace or
+ * freebuffers prior to checking bd_running.
+ */
+ BD_RUN_LOCK(bd);
+ atomic_store_int(&bd->bd_running, 0);
+ if (bd->bd_bufspace < bd->bd_bufspacethresh &&
+ bd->bd_freebuffers > bd->bd_lofreebuffers) {
+ msleep(&bd->bd_running, BD_RUN_LOCKPTR(bd), PRIBIO|PDROP,
+ "-", hz);
+ } else {
+ /* Avoid spurious wakeups while running. */
+ atomic_store_int(&bd->bd_running, 1);
+ BD_RUN_UNLOCK(bd);
+ }
+}
+
+/*
* bufspace_adjust:
*
* Adjust the reported bufspace for a KVA managed buffer, possibly
@@ -514,7 +548,7 @@ bufspace_adjust(struct buf *bp, int bufsize)
/* Wake up the daemon on the transition. */
if (space < bd->bd_bufspacethresh &&
space + diff >= bd->bd_bufspacethresh)
- bufspace_daemonwakeup(bd);
+ bufspace_daemon_wakeup(bd);
}
bp->b_bufsize = bufsize;
}
@@ -544,7 +578,7 @@ bufspace_reserve(struct bufdomain *bd, int size, bool
/* Wake up the daemon on the transition. */
if (space < bd->bd_bufspacethresh && new >= bd->bd_bufspacethresh)
- bufspace_daemonwakeup(bd);
+ bufspace_daemon_wakeup(bd);
return (0);
}
@@ -677,17 +711,7 @@ bufspace_daemon(void *arg)
} while (bd->bd_bufspace > bd->bd_lobufspace ||
bd->bd_freebuffers < bd->bd_hifreebuffers);
- /*
- * Re-check our limits and sleep.
- */
- BD_LOCK(bd);
- if (bd->bd_bufspace < bd->bd_bufspacethresh &&
- bd->bd_freebuffers > bd->bd_lofreebuffers) {
- bd->bd_request = 0;
- msleep(&bd->bd_request, BD_LOCKPTR(bd), PRIBIO|PDROP,
- "-", hz);
- } else
- BD_UNLOCK(bd);
+ bufspace_daemon_wait(bd);
}
}
@@ -804,7 +828,7 @@ vfs_buf_test_cache(struct buf *bp, vm_ooffset_t foff,
}
/* Wake up the buffer daemon if necessary */
-static __inline void
+static void
bd_wakeup(void)
{
@@ -1504,7 +1528,7 @@ buf_alloc(struct bufdomain *bd)
bp = uma_zalloc(buf_zone, M_NOWAIT);
if (bp == NULL) {
atomic_fetchadd_int(&bd->bd_freebuffers, 1);
- bufspace_daemonwakeup(bd);
+ bufspace_daemon_wakeup(bd);
counter_u64_add(numbufallocfails, 1);
return (NULL);
}
@@ -1512,7 +1536,7 @@ buf_alloc(struct bufdomain *bd)
* Wake-up the bufspace daemon on transition below threshold.
*/
if (freebufs == bd->bd_lofreebuffers)
- bufspace_daemonwakeup(bd);
+ bufspace_daemon_wakeup(bd);
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0)
panic("getnewbuf_empty: Locked buf %p on free queue.", bp);
@@ -1706,6 +1730,7 @@ bd_init(struct bufdomain *bd)
for (i = 0; i <= mp_maxid; i++)
bq_init(&bd->bd_cpuq[i], QUEUE_CLEAN, i,
"bufq clean cpu lock");
+ mtx_init(&bd->bd_run_lock, "bufspace daemon run lock", NULL, MTX_DEF);
}
/*
More information about the svn-src-user
mailing list