Allow proactive reclaimers to submit an additional swappiness= argument to memory.reclaim. This overrides the global or per-memcg swappiness setting for that reclaim attempt.
Dan Schatzberg (2): mm: add defines for min/max swappiness mm: add swappiness= arg to memory.reclaim
Documentation/admin-guide/cgroup-v2.rst | 18 +++++++++--- include/linux/swap.h | 5 +++- mm/memcontrol.c | 38 ++++++++++++++++-------- mm/vmscan.c | 39 ++++++++++++++++++------- 4 files changed, 73 insertions(+), 27 deletions(-)
From: Dan Schatzberg schatzberg.dan@gmail.com
maillist inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8Z5Z0 CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?...
-------------------------------------------
Patch series "Add swappiness argument to memory.reclaim", v6.
This patch proposes augmenting the memory.reclaim interface with a swappiness=<val> argument that overrides the swappiness value for that instance of proactive reclaim.
Userspace proactive reclaimers use the memory.reclaim interface to trigger reclaim. The memory.reclaim interface does not allow for any way to effect the balance of file vs anon during proactive reclaim. The only approach is to adjust the vm.swappiness setting. However, there are a few reasons we look to control the balance of file vs anon during proactive reclaim, separately from reactive reclaim:
* Swapout should be limited to manage SSD write endurance. In near-OOM situations we are fine with lots of swap-out to avoid OOMs. As these are typically rare events, they have relatively little impact on write endurance. However, proactive reclaim runs continuously and so its impact on SSD write endurance is more significant. Therefore it is desireable to control swap-out for proactive reclaim separately from reactive reclaim
* Some userspace OOM killers like systemd-oomd[1] support OOM killing on swap exhaustion. This makes sense if the swap exhaustion is triggered due to reactive reclaim but less so if it is triggered due to proactive reclaim (e.g. one could see OOMs when free memory is ample but anon is just particularly cold). Therefore, it's desireable to have proactive reclaim reduce or stop swap-out before the threshold at which OOM killing occurs.
In the case of Meta's Senpai proactive reclaimer, we adjust vm.swappiness before writes to memory.reclaim[2]. This has been in production for nearly two years and has addressed our needs to control proactive vs reactive reclaim behavior but is still not ideal for a number of reasons:
* vm.swappiness is a global setting, adjusting it can race/interfere with other system administration that wishes to control vm.swappiness. In our case, we need to disable Senpai before adjusting vm.swappiness.
* vm.swappiness is stateful - so a crash or restart of Senpai can leave a misconfigured setting. This requires some additional management to record the "desired" setting and ensure Senpai always adjusts to it.
With this patch, we avoid these downsides of adjusting vm.swappiness globally.
Previously, this exact interface addition was proposed by Yosry[3]. In response, Roman proposed instead an interface to specify precise file/anon/slab reclaim amounts[4]. More recently Huan also proposed this as well[5] and others similarly questioned if this was the proper interface.
Previous proposals sought to use this to allow proactive reclaimers to effectively perform a custom reclaim algorithm by issuing proactive reclaim with different settings to control file vs anon reclaim (e.g. to only reclaim anon from some applications). Responses argued that adjusting swappiness is a poor interface for custom reclaim.
In contrast, I argue in favor of a swappiness setting not as a way to implement custom reclaim algorithms but rather to bias the balance of anon vs file due to differences of proactive vs reactive reclaim. In this context, swappiness is the existing interface for controlling this balance and this patch simply allows for it to be configured differently for proactive vs reactive reclaim.
Specifying explicit amounts of anon vs file pages to reclaim feels inappropriate for this prupose. Proactive reclaimers are un-aware of the relative age of file vs anon for a cgroup which makes it difficult to manage proactive reclaim of different memory pools. A proactive reclaimer would need some amount of anon reclaim attempts separate from the amount of file reclaim attempts which seems brittle given that it's difficult to observe the impact.
[1]https://www.freedesktop.org/software/systemd/man/latest/systemd-oomd.service... [2]https://github.com/facebookincubator/oomd/blob/main/src/oomd/plugins/Senpai.... [3]https://lore.kernel.org/linux-mm/CAJD7tkbDpyoODveCsnaqBBMZEkDvshXJmNdbk51yKS... [4]https://lore.kernel.org/linux-mm/YoPHtHXzpK51F%2F1Z@carbon/ [5]https://lore.kernel.org/lkml/20231108065818.19932-1-link@vivo.com/
This patch (of 2):
We use the constants 0 and 200 in a few places in the mm code when referring to the min and max swappiness. This patch adds MIN_SWAPPINESS and MAX_SWAPPINESS #defines to improve clarity. There are no functional changes.
Link: https://lkml.kernel.org/r/20240103164841.2800183-1-schatzberg.dan@gmail.com Link: https://lkml.kernel.org/r/20240103164841.2800183-2-schatzberg.dan@gmail.com Signed-off-by: Dan Schatzberg schatzberg.dan@gmail.com Acked-by: David Rientjes rientjes@google.com Acked-by: Chris Li chrisl@kernel.org Reviewed-by: Nhat Pham nphamcs@gmail.com Cc: David Hildenbrand david@redhat.com Cc: Hugh Dickins hughd@google.com Cc: Johannes Weiner hannes@cmpxchg.org Cc: Jonathan Corbet corbet@lwn.net Cc: Kefeng Wang wangkefeng.wang@huawei.com Cc: Matthew Wilcox (Oracle) willy@infradead.org Cc: Michal Hocko mhocko@suse.com Cc: Muchun Song muchun.song@linux.dev Cc: Roman Gushchin roman.gushchin@linux.dev Cc: Shakeel Butt shakeelb@google.com Cc: Tejun Heo tj@kernel.org Cc: Yosry Ahmed yosryahmed@google.com Cc: Yue Zhao findns94@gmail.com Cc: Zefan Li lizefan.x@bytedance.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Jinjiang Tu tujinjiang@huawei.com --- include/linux/swap.h | 2 ++ mm/memcontrol.c | 2 +- mm/vmscan.c | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h index 5ac12a963469..010f6be26a15 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -421,6 +421,8 @@ extern unsigned long reclaim_pages(struct list_head *folio_list); #define MEMCG_RECLAIM_MAY_SWAP (1 << 1) #define MEMCG_RECLAIM_PROACTIVE (1 << 2) #define MEMCG_RECLAIM_NOT_FILE (1 << 3) +#define MIN_SWAPPINESS 0 +#define MAX_SWAPPINESS 200 extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, unsigned long nr_pages, gfp_t gfp_mask, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 8327cef9d53a..a39b901169dd 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4822,7 +4822,7 @@ static int mem_cgroup_swappiness_write(struct cgroup_subsys_state *css, { struct mem_cgroup *memcg = mem_cgroup_from_css(css);
- if (val > 200) + if (val > MAX_SWAPPINESS) return -EINVAL;
if (!mem_cgroup_is_root(memcg)) diff --git a/mm/vmscan.c b/mm/vmscan.c index b36d839e972a..3f0ad58b5a06 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -188,7 +188,7 @@ struct scan_control { #endif
/* - * From 0 .. 200. Higher means more swappy. + * From 0 .. MAX_SWAPPINESS. Higher means more swappy. */ int vm_swappiness = 60;
@@ -3118,7 +3118,7 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc, ap = swappiness * (total_cost + 1); ap /= anon_cost + 1;
- fp = (200 - swappiness) * (total_cost + 1); + fp = (MAX_SWAPPINESS - swappiness) * (total_cost + 1); fp /= file_cost + 1;
fraction[0] = ap; @@ -5114,7 +5114,7 @@ static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx { int type, tier; struct ctrl_pos sp, pv; - int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; + int gain[ANON_AND_FILE] = { swappiness, MAX_SWAPPINESS - swappiness };
/* * Compare the first tier of anon with that of file to determine which @@ -5150,7 +5150,7 @@ static int isolate_folios(struct lruvec *lruvec, struct scan_control *sc, int sw /* * Try to make the obvious choice first. When anon and file are both * available from the same generation, interpret swappiness 1 as file - * first and 200 as anon first. + * first and MAX_SWAPPINESS as anon first. */ if (!swappiness) type = LRU_GEN_FILE; @@ -5158,7 +5158,7 @@ static int isolate_folios(struct lruvec *lruvec, struct scan_control *sc, int sw type = LRU_GEN_ANON; else if (swappiness == 1) type = LRU_GEN_FILE; - else if (swappiness == 200) + else if (swappiness == MAX_SWAPPINESS) type = LRU_GEN_ANON; else type = get_type_to_scan(lruvec, swappiness, &tier); @@ -6079,9 +6079,9 @@ static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq,
lruvec = get_lruvec(memcg, nid);
- if (swappiness < 0) + if (swappiness < MIN_SWAPPINESS) swappiness = get_swappiness(lruvec, sc); - else if (swappiness > 200) + else if (swappiness > MAX_SWAPPINESS) goto done;
switch (cmd) {
From: Dan Schatzberg schatzberg.dan@gmail.com
maillist inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8Z5Z0 CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?...
-------------------------------------------
Allow proactive reclaimers to submit an additional swappiness=<val> argument to memory.reclaim. This overrides the global or per-memcg swappiness setting for that reclaim attempt.
For example:
echo "2M swappiness=0" > /sys/fs/cgroup/memory.reclaim
will perform reclaim on the rootcg with a swappiness setting of 0 (no swap) regardless of the vm.swappiness sysctl setting.
Userspace proactive reclaimers use the memory.reclaim interface to trigger reclaim. The memory.reclaim interface does not allow for any way to effect the balance of file vs anon during proactive reclaim. The only approach is to adjust the vm.swappiness setting. However, there are a few reasons we look to control the balance of file vs anon during proactive reclaim, separately from reactive reclaim:
* Swapout should be limited to manage SSD write endurance. In near-OOM situations we are fine with lots of swap-out to avoid OOMs. As these are typically rare events, they have relatively little impact on write endurance. However, proactive reclaim runs continuously and so its impact on SSD write endurance is more significant. Therefore it is desireable to control swap-out for proactive reclaim separately from reactive reclaim
* Some userspace OOM killers like systemd-oomd[1] support OOM killing on swap exhaustion. This makes sense if the swap exhaustion is triggered due to reactive reclaim but less so if it is triggered due to proactive reclaim (e.g. one could see OOMs when free memory is ample but anon is just particularly cold). Therefore, it's desireable to have proactive reclaim reduce or stop swap-out before the threshold at which OOM killing occurs.
In the case of Meta's Senpai proactive reclaimer, we adjust vm.swappiness before writes to memory.reclaim[2]. This has been in production for nearly two years and has addressed our needs to control proactive vs reactive reclaim behavior but is still not ideal for a number of reasons:
* vm.swappiness is a global setting, adjusting it can race/interfere with other system administration that wishes to control vm.swappiness. In our case, we need to disable Senpai before adjusting vm.swappiness.
* vm.swappiness is stateful - so a crash or restart of Senpai can leave a misconfigured setting. This requires some additional management to record the "desired" setting and ensure Senpai always adjusts to it.
With this patch, we avoid these downsides of adjusting vm.swappiness globally.
[1]https://www.freedesktop.org/software/systemd/man/latest/systemd-oomd.service... [2]https://github.com/facebookincubator/oomd/blob/main/src/oomd/plugins/Senpai....
Link: https://lkml.kernel.org/r/20240103164841.2800183-3-schatzberg.dan@gmail.com Signed-off-by: Dan Schatzberg schatzberg.dan@gmail.com Suggested-by: Yosry Ahmed yosryahmed@google.com Acked-by: Michal Hocko mhocko@suse.com Acked-by: David Rientjes rientjes@google.com Acked-by: Chris Li chrisl@kernel.org Cc: David Hildenbrand david@redhat.com Cc: Hugh Dickins hughd@google.com Cc: Johannes Weiner hannes@cmpxchg.org Cc: Jonathan Corbet corbet@lwn.net Cc: Kefeng Wang wangkefeng.wang@huawei.com Cc: Matthew Wilcox (Oracle) willy@infradead.org Cc: Muchun Song muchun.song@linux.dev Cc: Roman Gushchin roman.gushchin@linux.dev Cc: Shakeel Butt shakeelb@google.com Cc: Tejun Heo tj@kernel.org Cc: Yue Zhao findns94@gmail.com Cc: Zefan Li lizefan.x@bytedance.com Cc: Nhat Pham nphamcs@gmail.com Signed-off-by: Andrew Morton akpm@linux-foundation.org
Conflicts: mm/memcontrol.c mm/vmscan.c Documentation/admin-guide/cgroup-v2.rst
Signed-off-by: Jinjiang Tu tujinjiang@huawei.com --- Documentation/admin-guide/cgroup-v2.rst | 18 ++++++++++--- include/linux/swap.h | 3 ++- mm/memcontrol.c | 36 +++++++++++++++++-------- mm/vmscan.c | 25 ++++++++++++++--- 4 files changed, 63 insertions(+), 19 deletions(-)
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 84cbbeaf0d78..027111212a30 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -1246,14 +1246,24 @@ PAGE_SIZE multiple when read back. This is a simple interface to trigger memory reclaim in the target cgroup.
- This file accepts a single key, the number of bytes to reclaim. - Example::
echo "1G" > memory.reclaim
- This file also accepts nested keys, the number of bytes to reclaim - with the type of memory to reclaim. + The following nested keys are defined. + + ========== ================================ + swappiness Swappiness value to reclaim with + type The type of memory to reclaim + ========== ================================ + + Specifying a swappiness value instructs the kernel to perform + the reclaim with that swappiness value. Note that this has the + same semantics as vm.swappiness applied to memcg reclaim with + all the existing limitations and potential future extensions. + + Specifying a type value instructs the kernel to reclaim with + the type of memory.
Example:: echo "1G type=file" > memory.reclaim diff --git a/include/linux/swap.h b/include/linux/swap.h index 010f6be26a15..e704fa684417 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -426,7 +426,8 @@ extern unsigned long reclaim_pages(struct list_head *folio_list); extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, unsigned long nr_pages, gfp_t gfp_mask, - unsigned int reclaim_options); + unsigned int reclaim_options, + int *swappiness); extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem, gfp_t gfp_mask, bool noswap, pg_data_t *pgdat, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index a39b901169dd..ceebc270b226 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -52,6 +52,7 @@ #include <linux/sort.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/parser.h> #include <linux/vmpressure.h> #include <linux/memremap.h> #include <linux/mm_inline.h> @@ -2450,7 +2451,8 @@ static unsigned long reclaim_high(struct mem_cgroup *memcg, psi_memstall_enter(&pflags); nr_reclaimed += try_to_free_mem_cgroup_pages(memcg, nr_pages, gfp_mask, - MEMCG_RECLAIM_MAY_SWAP); + MEMCG_RECLAIM_MAY_SWAP, + NULL); psi_memstall_leave(&pflags); } while ((memcg = parent_mem_cgroup(memcg)) && !mem_cgroup_is_root(memcg)); @@ -2488,7 +2490,8 @@ static void async_reclaim_high(struct mem_cgroup *memcg) psi_memstall_enter(&pflags); nr_pages = memcg_usage > safe_pages ? memcg_usage - safe_pages : MEMCG_CHARGE_BATCH; - try_to_free_mem_cgroup_pages(memcg, nr_pages, GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP); + try_to_free_mem_cgroup_pages(memcg, nr_pages, GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP, + NULL); psi_memstall_leave(&pflags); WRITE_ONCE(memcg->high_async_reclaim, false); } @@ -2784,7 +2787,7 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask, pflags = PSI_MEMCG_RECLAIM; psi_memstall_enter(&pflags); nr_reclaimed = try_to_free_mem_cgroup_pages(mem_over_limit, nr_pages, - gfp_mask, reclaim_options); + gfp_mask, reclaim_options, NULL); psi_memstall_leave(&pflags);
if (mem_cgroup_margin(mem_over_limit) >= nr_pages) @@ -3630,7 +3633,7 @@ static int mem_cgroup_resize_max(struct mem_cgroup *memcg, }
if (!try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL, - memsw ? 0 : MEMCG_RECLAIM_MAY_SWAP)) { + memsw ? 0 : MEMCG_RECLAIM_MAY_SWAP, NULL)) { ret = -EBUSY; break; } @@ -3744,7 +3747,7 @@ int mem_cgroup_force_empty(struct mem_cgroup *memcg) return -EINTR;
if (!try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL, - MEMCG_RECLAIM_MAY_SWAP)) + MEMCG_RECLAIM_MAY_SWAP, NULL)) nr_retries--; }
@@ -7598,7 +7601,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of, }
reclaimed = try_to_free_mem_cgroup_pages(memcg, nr_pages - high, - GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP); + GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP, NULL);
if (!reclaimed && !nr_retries--) break; @@ -7647,7 +7650,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
if (nr_reclaims) { if (!try_to_free_mem_cgroup_pages(memcg, nr_pages - max, - GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP)) + GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP, NULL)) nr_reclaims--; continue; } @@ -7773,11 +7776,13 @@ static ssize_t memory_oom_group_write(struct kernfs_open_file *of, }
enum { - MEMORY_RECLAIM_TYPE = 0, + MEMORY_RECLAIM_SWAPPINESS = 0, + MEMORY_RECLAIM_TYPE = 1, MEMORY_RECLAIM_NULL, };
static const match_table_t tokens = { + { MEMORY_RECLAIM_SWAPPINESS, "swappiness=%d"}, { MEMORY_RECLAIM_TYPE, "type=%s"}, { MEMORY_RECLAIM_NULL, NULL }, }; @@ -7785,7 +7790,7 @@ static const match_table_t tokens = { #define RECLAIM_TYPE_SIZE 8
static int reclaim_param_parse(char *buf, unsigned long *nr_pages, - unsigned int *reclaim_options) + unsigned int *reclaim_options, int *swappiness) { char *old_buf, *start; char type[RECLAIM_TYPE_SIZE]; @@ -7811,6 +7816,12 @@ static int reclaim_param_parse(char *buf, unsigned long *nr_pages, continue;
switch (match_token(start, tokens, args)) { + case MEMORY_RECLAIM_SWAPPINESS: + if (match_int(&args[0], swappiness)) + return -EINVAL; + if (*swappiness < MIN_SWAPPINESS || *swappiness > MAX_SWAPPINESS) + return -EINVAL; + break; case MEMORY_RECLAIM_TYPE: match_strlcpy(type, &args[0], RECLAIM_TYPE_SIZE); if (!strcmp(type, "anon")) @@ -7834,11 +7845,13 @@ static ssize_t memory_reclaim(struct kernfs_open_file *of, char *buf, struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); unsigned int nr_retries = MAX_RECLAIM_RETRIES; unsigned long nr_to_reclaim, nr_reclaimed = 0; + int swappiness = -1; unsigned int reclaim_options; int err;
reclaim_options = MEMCG_RECLAIM_MAY_SWAP | MEMCG_RECLAIM_PROACTIVE; - err = reclaim_param_parse(buf, &nr_to_reclaim, &reclaim_options); + err = reclaim_param_parse(buf, &nr_to_reclaim, &reclaim_options, + &swappiness); if (err) return err;
@@ -7863,7 +7876,8 @@ static ssize_t memory_reclaim(struct kernfs_open_file *of, char *buf,
reclaimed = try_to_free_mem_cgroup_pages(memcg, min(nr_to_reclaim - nr_reclaimed, SWAP_CLUSTER_MAX), - GFP_KERNEL, reclaim_options); + GFP_KERNEL, reclaim_options, + swappiness == -1 ? NULL : &swappiness);
if (!reclaimed && !nr_retries--) return -EAGAIN; diff --git a/mm/vmscan.c b/mm/vmscan.c index 3f0ad58b5a06..f212339b592e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -94,6 +94,11 @@ struct scan_control { unsigned long anon_cost; unsigned long file_cost;
+#ifdef CONFIG_MEMCG + /* Swappiness value for proactive reclaim. Always use sc_swappiness()! */ + int *proactive_swappiness; +#endif + /* Can active folios be deactivated as part of reclaim? */ #define DEACTIVATE_ANON 1 #define DEACTIVATE_FILE 2 @@ -471,6 +476,13 @@ static bool writeback_throttling_sane(struct scan_control *sc) #endif return false; } + +static int sc_swappiness(struct scan_control *sc, struct mem_cgroup *memcg) +{ + if (sc->proactive && sc->proactive_swappiness) + return *sc->proactive_swappiness; + return mem_cgroup_swappiness(memcg); +} #else static int prealloc_memcg_shrinker(struct shrinker *shrinker) { @@ -507,6 +519,11 @@ static bool writeback_throttling_sane(struct scan_control *sc) { return true; } + +static int sc_swappiness(struct scan_control *sc, struct mem_cgroup *memcg) +{ + return READ_ONCE(vm_swappiness); +} #endif
static void set_task_reclaim_state(struct task_struct *task, @@ -3034,7 +3051,7 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc, struct pglist_data *pgdat = lruvec_pgdat(lruvec); struct mem_cgroup *memcg = lruvec_memcg(lruvec); unsigned long anon_cost, file_cost, total_cost; - int swappiness = mem_cgroup_swappiness(memcg); + int swappiness = sc_swappiness(sc, memcg); u64 fraction[ANON_AND_FILE]; u64 denominator = 0; /* gcc */ enum scan_balance scan_balance; @@ -3326,7 +3343,7 @@ static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) return 0;
- return mem_cgroup_swappiness(memcg); + return sc_swappiness(sc, memcg); }
static int get_nr_gens(struct lruvec *lruvec, int type) @@ -7144,12 +7161,14 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg, unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, unsigned long nr_pages, gfp_t gfp_mask, - unsigned int reclaim_options) + unsigned int reclaim_options, + int *swappiness) { unsigned long nr_reclaimed; unsigned int noreclaim_flag; struct scan_control sc = { .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX), + .proactive_swappiness = swappiness, .gfp_mask = (current_gfp_context(gfp_mask) & GFP_RECLAIM_MASK) | (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK), .reclaim_idx = MAX_NR_ZONES - 1,