From 6f7acfc9c97f7329f84a71d2914c708f11ed0fd3 Mon Sep 17 00:00:00 2001 From: Tim Chase Date: Fri, 22 Jan 2016 07:37:37 -0600 Subject: [PATCH] Prevent arc_c collapse Adjusting arc_c directly is racy because it can happen in the context of multiple threads. It should always be >= 2 * maxblocksize. Set it to a known valid value rather than adjusting it directly. In addition refactor arc_shrink() to a simpler structure, protect against underflow in the calculation of the new arc_c value. Signed-off-by: Tim Chase Signed-off-by: Brian Behlendorf Reverts: 935434ef Closes: #3904 Closes: #4161 --- module/zfs/arc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 729f8936e3..c53c01ea4b 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -3179,13 +3179,10 @@ arc_flush(spa_t *spa, boolean_t retry) void arc_shrink(int64_t to_free) { - if (arc_c > arc_c_min) { - - if (arc_c > arc_c_min + to_free) - atomic_add_64(&arc_c, -to_free); - else - arc_c = arc_c_min; + uint64_t c = arc_c; + if (c > to_free && c - to_free > arc_c_min) { + arc_c = c - to_free; atomic_add_64(&arc_p, -(arc_p >> arc_shrink_shift)); if (arc_c > arc_size) arc_c = MAX(arc_size, arc_c_min); @@ -3193,6 +3190,8 @@ arc_shrink(int64_t to_free) arc_p = (arc_c >> 1); ASSERT(arc_c >= arc_c_min); ASSERT((int64_t)arc_p >= 0); + } else { + arc_c = arc_c_min; } if (arc_size > arc_c) @@ -3762,7 +3761,7 @@ 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 */ - VERIFY3U(arc_c, >=, 2ULL << SPA_MAXBLOCKSHIFT); + ASSERT3U(arc_c, >=, 2ULL << SPA_MAXBLOCKSHIFT); if (arc_size >= arc_c - (2ULL << SPA_MAXBLOCKSHIFT)) { atomic_add_64(&arc_c, (int64_t)bytes); if (arc_c > arc_c_max) @@ -5105,7 +5104,9 @@ arc_tempreserve_space(uint64_t reserve, uint64_t txg) int error; uint64_t anon_size; - if (reserve > arc_c/4 && !arc_no_grow) + if (!arc_no_grow && + reserve > arc_c/4 && + reserve * 4 > (2ULL << SPA_MAXBLOCKSHIFT)) arc_c = MIN(arc_c_max, reserve * 4); /*