summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2013-07-25 10:39:31 -0700
committerBrian Behlendorf <[email protected]>2013-08-09 10:06:12 -0700
commitfadd0c4da1e2ccd6014800d8b1a0fd117dd323e8 (patch)
tree4127fe9f936a7631fef0a04e385d7b537f40f3c2 /module
parent68121a03daf58a7d5b9351f110196b8ce806e1fa (diff)
Evict meta data from ghost lists + l2arc headers
When the meta limit is exceeded the ARC evicts some meta data buffers from the mfu+mru lists. Unfortunately, for meta data heavy workloads it's possible for these buffers to accumulate on the ghost lists if arc_c doesn't exceed arc_size. To handle this case arc_adjust_meta() has been entended to explicitly evict meta data buffers from the ghost lists in proportion to what was evicted from the mfu+mru lists. If this is insufficient we request that the VFS release some inodes and dentries. This will result in the release of some dnodes which are counted as 'other' metadata. Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module')
-rw-r--r--module/zfs/arc.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c
index ce4a0239c..32ad80bcb 100644
--- a/module/zfs/arc.c
+++ b/module/zfs/arc.c
@@ -2104,8 +2104,9 @@ arc_do_user_evicts(void)
void
arc_adjust_meta(int64_t adjustment, boolean_t may_prune)
{
- int64_t delta;
+ int64_t delta, tmp = adjustment;
+ /* Evict MRU+MFU meta data to ghost lists */
if (adjustment > 0 && arc_mru->arcs_lsize[ARC_BUFC_METADATA] > 0) {
delta = MIN(arc_mru->arcs_lsize[ARC_BUFC_METADATA], adjustment);
arc_evict(arc_mru, 0, delta, FALSE, ARC_BUFC_METADATA);
@@ -2115,9 +2116,24 @@ arc_adjust_meta(int64_t adjustment, boolean_t may_prune)
if (adjustment > 0 && arc_mfu->arcs_lsize[ARC_BUFC_METADATA] > 0) {
delta = MIN(arc_mfu->arcs_lsize[ARC_BUFC_METADATA], adjustment);
arc_evict(arc_mfu, 0, delta, FALSE, ARC_BUFC_METADATA);
+ }
+
+ /* Evict ghost MRU+MFU meta data */
+ adjustment = tmp;
+
+ if (adjustment > 0 && arc_mru_ghost->arcs_size > 0) {
+ delta = MIN(arc_mru_ghost->arcs_size, adjustment);
+ arc_evict_ghost(arc_mru_ghost, 0, delta, ARC_BUFC_METADATA);
+ adjustment -= delta;
+ }
+
+ if (adjustment > 0 && arc_mfu_ghost->arcs_size > 0) {
+ delta = MIN(arc_mfu_ghost->arcs_size, adjustment);
+ arc_evict_ghost(arc_mfu_ghost, 0, delta, ARC_BUFC_METADATA);
adjustment -= delta;
}
+ /* Request the VFS release some meta data */
if (may_prune && (adjustment > 0) && (arc_meta_used > arc_meta_limit))
arc_do_user_prune(zfs_arc_meta_prune);
}