diff options
author | Tim Chase <[email protected]> | 2016-01-22 07:37:37 -0600 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2016-01-25 10:25:04 -0800 |
commit | 1b8951b319b7bcddfe0cc2408b7717f9ce3d758b (patch) | |
tree | 6ca6e7b31b96a8632cd9493237c65ad619cc21e4 /module | |
parent | 957dc93242bfa5c94b3ffecfb02c5f758cf82f37 (diff) |
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 <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Reverts: 935434ef
Closes: #3904
Closes: #4161
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/arc.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c index b8707474d..88939d0d3 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -3183,13 +3183,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); @@ -3197,6 +3194,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) @@ -3767,7 +3766,6 @@ arc_adapt(int bytes, arc_state_t *state) * cache size, increment the target cache size */ ASSERT3U(arc_c, >=, 2ULL << SPA_MAXBLOCKSHIFT); - arc_c = MAX(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) @@ -5160,7 +5158,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); /* |