Date: Mon, 15 Dec 2014 04:51:37 +0000 (UTC) From: Xin LI <delphij@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r275780 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs Message-ID: <201412150451.sBF4pbvC031833@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: delphij Date: Mon Dec 15 04:51:36 2014 New Revision: 275780 URL: https://svnweb.freebsd.org/changeset/base/275780 Log: MFV r275549: Add a loader tunable, vfs.zfs.arc_meta_min, which controls how much metadata ZFS should keep in ARC at minimum. In arc_evict(), when doing recycle, take more factors into account by applying the following policy: 1. If no evictable data, evict metadata; 2. If no evictable metadata, evict data; 3. If we hit arc_meta_limit, evict metadata; 4. If we haven't hit arc_meta_min, evict data; 5* (Illumos only, not present in new FreeBSD code, yet) evict the oldest cached element from data and metadata. (FreeBSD) evict the data type specified by caller, which is the existing behavior. Note that because of our splitted locks (implemented in r205231 to improve scalability by reducing lock contention), implementing the fifth Illumos behavior will not be cheap, so for now just implement the 1-4 and fall back to current behavior for 5. Illumos issue: 5368 ARC should cache more metadata MFC after: 2 months (assuming we didn't found better solution) Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c Directory Properties: head/sys/cddl/contrib/opensolaris/ (props changed) Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c Sun Dec 14 22:41:08 2014 (r275779) +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c Mon Dec 15 04:51:36 2014 (r275780) @@ -197,6 +197,7 @@ static boolean_t arc_warm; uint64_t zfs_arc_max; uint64_t zfs_arc_min; uint64_t zfs_arc_meta_limit = 0; +uint64_t zfs_arc_meta_min = 0; int zfs_arc_grow_retry = 0; int zfs_arc_shrink_shift = 0; int zfs_arc_p_min_shift = 0; @@ -218,6 +219,7 @@ SYSINIT(arc_free_target_init, SI_SUB_KTH arc_free_target_init, NULL); TUNABLE_QUAD("vfs.zfs.arc_meta_limit", &zfs_arc_meta_limit); +TUNABLE_QUAD("vfs.zfs.arc_meta_min", &zfs_arc_meta_min); TUNABLE_INT("vfs.zfs.arc_shrink_shift", &zfs_arc_shrink_shift); SYSCTL_DECL(_vfs_zfs); SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, arc_max, CTLFLAG_RDTUN, &zfs_arc_max, 0, @@ -426,6 +428,7 @@ typedef struct arc_stats { kstat_named_t arcstat_meta_used; kstat_named_t arcstat_meta_limit; kstat_named_t arcstat_meta_max; + kstat_named_t arcstat_meta_min; } arc_stats_t; static arc_stats_t arc_stats = { @@ -506,7 +509,8 @@ static arc_stats_t arc_stats = { { "duplicate_reads", KSTAT_DATA_UINT64 }, { "arc_meta_used", KSTAT_DATA_UINT64 }, { "arc_meta_limit", KSTAT_DATA_UINT64 }, - { "arc_meta_max", KSTAT_DATA_UINT64 } + { "arc_meta_max", KSTAT_DATA_UINT64 }, + { "arc_meta_min", KSTAT_DATA_UINT64 } }; #define ARCSTAT(stat) (arc_stats.stat.value.ui64) @@ -569,6 +573,7 @@ static arc_state_t *arc_l2c_only; #define arc_c_min ARCSTAT(arcstat_c_min) /* min target cache size */ #define arc_c_max ARCSTAT(arcstat_c_max) /* max target cache size */ #define arc_meta_limit ARCSTAT(arcstat_meta_limit) /* max size for metadata */ +#define arc_meta_min ARCSTAT(arcstat_meta_min) /* min size for metadata */ #define arc_meta_used ARCSTAT(arcstat_meta_used) /* size of metadata */ #define arc_meta_max ARCSTAT(arcstat_meta_max) /* max size of metadata */ @@ -2057,6 +2062,49 @@ arc_evict(arc_state_t *state, uint64_t s evicted_state = (state == arc_mru) ? arc_mru_ghost : arc_mfu_ghost; + /* + * Decide which "type" (data vs metadata) to recycle from. + * + * If we are over the metadata limit, recycle from metadata. + * If we are under the metadata minimum, recycle from data. + * Otherwise, recycle from whichever type has the oldest (least + * recently accessed) header. This is not yet implemented. + */ + if (recycle) { + arc_buf_contents_t realtype; + if (state->arcs_lsize[ARC_BUFC_DATA] == 0) { + realtype = ARC_BUFC_METADATA; + } else if (state->arcs_lsize[ARC_BUFC_METADATA] == 0) { + realtype = ARC_BUFC_DATA; + } else if (arc_meta_used >= arc_meta_limit) { + realtype = ARC_BUFC_METADATA; + } else if (arc_meta_used <= arc_meta_min) { + realtype = ARC_BUFC_DATA; + } else { +#ifdef illumos + if (data_hdr->b_arc_access < + metadata_hdr->b_arc_access) { + realtype = ARC_BUFC_DATA; + } else { + realtype = ARC_BUFC_METADATA; + } +#else + /* TODO */ + realtype = type; +#endif + } + if (realtype != type) { + /* + * If we want to evict from a different list, + * we can not recycle, because DATA vs METADATA + * buffers are segregated into different kmem + * caches (and vmem arenas). + */ + type = realtype; + recycle = B_FALSE; + } + } + if (type == ARC_BUFC_METADATA) { offset = 0; list_count = ARC_BUFC_NUMMETADATALISTS; @@ -4198,6 +4246,12 @@ arc_init(void) if (arc_c_min < arc_meta_limit / 2 && zfs_arc_min == 0) arc_c_min = arc_meta_limit / 2; + if (zfs_arc_meta_min > 0) { + arc_meta_min = zfs_arc_meta_min; + } else { + arc_meta_min = arc_c_min / 2; + } + if (zfs_arc_grow_retry > 0) arc_grow_retry = zfs_arc_grow_retry;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201412150451.sBF4pbvC031833>