diff options
Diffstat (limited to 'mm/vmscan.c')
| -rw-r--r-- | mm/vmscan.c | 42 | 
1 files changed, 25 insertions, 17 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index d75cdf360730..6aa5b01d3e75 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -291,6 +291,7 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,  	int nid = shrinkctl->nid;  	long batch_size = shrinker->batch ? shrinker->batch  					  : SHRINK_BATCH; +	long scanned = 0, next_deferred;  	freeable = shrinker->count_objects(shrinker, shrinkctl);  	if (freeable == 0) @@ -312,7 +313,9 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,  		pr_err("shrink_slab: %pF negative objects to delete nr=%ld\n",  		       shrinker->scan_objects, total_scan);  		total_scan = freeable; -	} +		next_deferred = nr; +	} else +		next_deferred = total_scan;  	/*  	 * We need to avoid excessive windup on filesystem shrinkers @@ -369,17 +372,22 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,  		count_vm_events(SLABS_SCANNED, nr_to_scan);  		total_scan -= nr_to_scan; +		scanned += nr_to_scan;  		cond_resched();  	} +	if (next_deferred >= scanned) +		next_deferred -= scanned; +	else +		next_deferred = 0;  	/*  	 * move the unused scan count back into the shrinker in a  	 * manner that handles concurrent updates. If we exhausted the  	 * scan, there is no need to do an update.  	 */ -	if (total_scan > 0) -		new_nr = atomic_long_add_return(total_scan, +	if (next_deferred > 0) +		new_nr = atomic_long_add_return(next_deferred,  						&shrinker->nr_deferred[nid]);  	else  		new_nr = atomic_long_read(&shrinker->nr_deferred[nid]); @@ -3558,24 +3566,21 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)     not required for correctness.  So if the last cpu in a node goes     away, we get changed to run anywhere: as the first one comes back,     restore their cpu bindings. */ -static int cpu_callback(struct notifier_block *nfb, unsigned long action, -			void *hcpu) +static int kswapd_cpu_online(unsigned int cpu)  {  	int nid; -	if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) { -		for_each_node_state(nid, N_MEMORY) { -			pg_data_t *pgdat = NODE_DATA(nid); -			const struct cpumask *mask; +	for_each_node_state(nid, N_MEMORY) { +		pg_data_t *pgdat = NODE_DATA(nid); +		const struct cpumask *mask; -			mask = cpumask_of_node(pgdat->node_id); +		mask = cpumask_of_node(pgdat->node_id); -			if (cpumask_any_and(cpu_online_mask, mask) < nr_cpu_ids) -				/* One of our CPUs online: restore mask */ -				set_cpus_allowed_ptr(pgdat->kswapd, mask); -		} +		if (cpumask_any_and(cpu_online_mask, mask) < nr_cpu_ids) +			/* One of our CPUs online: restore mask */ +			set_cpus_allowed_ptr(pgdat->kswapd, mask);  	} -	return NOTIFY_OK; +	return 0;  }  /* @@ -3617,12 +3622,15 @@ void kswapd_stop(int nid)  static int __init kswapd_init(void)  { -	int nid; +	int nid, ret;  	swap_setup();  	for_each_node_state(nid, N_MEMORY)   		kswapd_run(nid); -	hotcpu_notifier(cpu_callback, 0); +	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, +					"mm/vmscan:online", kswapd_cpu_online, +					NULL); +	WARN_ON(ret < 0);  	return 0;  }  |