aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/arc.c
diff options
context:
space:
mode:
authorTim Chase <[email protected]>2016-01-22 07:37:37 -0600
committerBrian Behlendorf <[email protected]>2016-01-25 10:25:04 -0800
commit1b8951b319b7bcddfe0cc2408b7717f9ce3d758b (patch)
tree6ca6e7b31b96a8632cd9493237c65ad619cc21e4 /module/zfs/arc.c
parent957dc93242bfa5c94b3ffecfb02c5f758cf82f37 (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/zfs/arc.c')
-rw-r--r--module/zfs/arc.c16
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);
/*