From c0f091a0f8bd8ba9038197032408eab50fe26d91 Mon Sep 17 00:00:00 2001 From: Tim Chase Date: Tue, 5 Jan 2016 13:25:23 -0600 Subject: [PATCH] Update arc_c under a mutex The arc_c value can be updated concurrently by multiple threads including the arc reclaim thread, kswapd, kthreadd and user processes. This patch updates it under a mutex to close the race between the checking of its value and subsequent updates. Reverts: 935434ef Fixes: #3904 Fixes: #4161 --- module/zfs/arc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 0741633696b2..9726fcfbafd4 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -649,6 +649,7 @@ static kmutex_t arc_prune_mtx; static taskq_t *arc_prune_taskq; static arc_buf_t *arc_eviction_list; static arc_buf_hdr_t arc_eviction_hdr; +static kmutex_t arc_c_mtx; #define GHOST_STATE(state) \ ((state) == arc_mru_ghost || (state) == arc_mfu_ghost || \ @@ -3179,6 +3180,7 @@ arc_flush(spa_t *spa, boolean_t retry) void arc_shrink(int64_t to_free) { + mutex_enter(&arc_c_mtx); if (arc_c > arc_c_min) { if (arc_c > arc_c_min + to_free) @@ -3195,8 +3197,11 @@ arc_shrink(int64_t to_free) ASSERT((int64_t)arc_p >= 0); } - if (arc_size > arc_c) + if (arc_size > arc_c) { + mutex_exit(&arc_c_mtx); (void) arc_adjust(); + } else + mutex_exit(&arc_c_mtx); } typedef enum free_memory_reason_t { @@ -3762,8 +3767,8 @@ arc_adapt(int bytes, arc_state_t *state) * If we're within (2 * maxblocksize) bytes of the target * cache size, increment the target cache size */ - ASSERT3U(arc_c, >=, 2ULL << SPA_MAXBLOCKSHIFT); - arc_c = MAX(arc_c, 2ULL << SPA_MAXBLOCKSHIFT); + VERIFY3U(arc_c, >=, 2ULL << SPA_MAXBLOCKSHIFT); + mutex_enter(&arc_c_mtx); if (arc_size >= arc_c - (2ULL << SPA_MAXBLOCKSHIFT)) { atomic_add_64(&arc_c, (int64_t)bytes); if (arc_c > arc_c_max) @@ -3773,6 +3778,7 @@ arc_adapt(int bytes, arc_state_t *state) if (arc_p > arc_c) arc_p = arc_c; } + mutex_exit(&arc_c_mtx); ASSERT((int64_t)arc_p >= 0); } @@ -5442,6 +5448,7 @@ arc_init(void) arc_eviction_list = NULL; mutex_init(&arc_prune_mtx, NULL, MUTEX_DEFAULT, NULL); bzero(&arc_eviction_hdr, sizeof (arc_buf_hdr_t)); + mutex_init(&arc_c_mtx, NULL, MUTEX_DEFAULT, NULL); arc_prune_taskq = taskq_create("arc_prune", max_ncpus, defclsyspri, max_ncpus, INT_MAX, TASKQ_PREPOPULATE | TASKQ_DYNAMIC); @@ -5542,6 +5549,7 @@ arc_fini(void) list_destroy(&arc_prune_list); mutex_destroy(&arc_prune_mtx); mutex_destroy(&arc_reclaim_lock); + mutex_destroy(&arc_c_mtx); cv_destroy(&arc_reclaim_thread_cv); cv_destroy(&arc_reclaim_waiters_cv);