Index: cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c =================================================================== --- cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c (revision 305005) +++ cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c (working copy) @@ -237,7 +237,16 @@ int zfs_arc_p_min_shift = 0; int zfs_disable_dup_eviction = 0; uint64_t zfs_arc_average_blocksize = 8 * 1024; /* 8KB */ u_int zfs_arc_free_target = 0; +u_int zfs_arc_wakeup_pager = 0; +u_int zfs_arc_wakeup_delay = 500; +#define WAKE_PAGER +#ifdef WAKE_PAGER +#define WAKE_PAGER_CONSTANT 10 / 9 /* Pager wakeup threshold */ +static int arc_init_done = 0; /* After arc_warm is valid */ +extern void pagedaemon_wakeup(void); +#endif + /* Absolute min for arc min / max is 16MB. */ static uint64_t arc_abs_min = 16 << 20; @@ -252,6 +261,7 @@ arc_free_target_init(void *unused __unused) { zfs_arc_free_target = vm_pageout_wakeup_thresh; + zfs_arc_wakeup_pager = zfs_arc_free_target * WAKE_PAGER_CONSTANT; } SYSINIT(arc_free_target_init, SI_SUB_KTHREAD_PAGE, SI_ORDER_ANY, arc_free_target_init, NULL); @@ -3476,6 +3486,11 @@ int64_t arc_pages_pp_reserve = 64; int64_t arc_swapfs_reserve = 64; /* + * Declare file-local static for event processor bypass + */ +static unsigned int arc_no_wake_event = 0; + +/* * Return the amount of memory that can be consumed before reclaim will be * needed. Positive if there is sufficient free memory, negative indicates * the amount of memory that needs to be freed up. @@ -3488,6 +3503,12 @@ arc_available_memory(void) free_memory_reason_t r = FMR_UNKNOWN; #ifdef _KERNEL +#ifdef WAKE_PAGER + sbintime_t now; + static sbintime_t last_pagedaemon_wake = 0; + void call_arc_kmem_reap(void); +#endif /* WAKE_PAGER */ + if (needfree > 0) { n = PAGESIZE * (-needfree); if (n < lowest) { @@ -3495,6 +3516,25 @@ arc_available_memory(void) r = FMR_NEEDFREE; } } +#ifdef WAKE_PAGER +/* + * If memory is less than the ARC wakeup threshold and time has expired since + * the last time we woke the pager... Do not execute until the ARC warms up. + */ + if ((arc_init_done) && + (((int64_t) freemem - zfs_arc_wakeup_pager) < 0) && + (arc_warm == B_TRUE) + ) { + now = getsbinuptime(); + if ((now - last_pagedaemon_wake) / SBT_1MS > zfs_arc_wakeup_delay) { + last_pagedaemon_wake = now; + arc_no_wake_event++; /* Set bypass flag for ARC */ + call_arc_kmem_reap(); /* Reap caches if we're close */ + DTRACE_PROBE(arc__wake_pagedaemon); + (void) pagedaemon_wakeup(); /* Wake the pager */ + } + } +#endif /* WAKE_PAGER */ /* * Cooperate with pagedaemon when it's time for it to scan @@ -3684,6 +3724,11 @@ arc_kmem_reap_now(void) DTRACE_PROBE(arc__kmem_reap_end); } +void call_arc_kmem_reap() +{ + arc_kmem_reap_now(); +} + /* * Threads can block in arc_get_data_buf() waiting for this thread to evict * enough data and signal them to proceed. When this happens, the threads in @@ -5431,6 +5476,10 @@ static eventhandler_tag arc_event_lowmem = NULL; static void arc_lowmem(void *arg __unused, int howto __unused) { + if (arc_no_wake_event) { /* Don't do it if we woke the pager */ + arc_no_wake_event = 0; /* Just clear the flag */ + return; + } mutex_enter(&arc_reclaim_lock); /* XXX: Memory deficit should be passed as argument. */ @@ -5696,6 +5745,9 @@ arc_init(void) printf(" in /boot/loader.conf.\n"); } #endif +#ifdef WAKE_PAGER + arc_init_done++; +#endif /* WAKE_PAGER */ } void