watermark_scale_factor_sysctl_handler()是/proc/sys/vm/watermark_scale_factor的 sysctl 处理函数,负责响应用户对该参数的读写请求,并在写入后重新计算所有 zone 的水位线。
核心实现
static int watermark_scale_factor_sysctl_handler(const struct ctl_table *table, int write, void *buffer, size_t *length, loff_t *ppos) { int rc; rc = proc_dointvec_minmax(table, write, buffer, length, ppos); if (rc) return rc; if (write) setup_per_zone_wmarks(); return 0; }逐步解析
1. 委托标准整数读写与范围检查
rc = proc_dointvec_minmax(table, write, buffer, length, ppos); if (rc) return rc;
proc_dointvec_minmax():标准 sysctl 整数处理,把用户输入的字符串解析为整数写入table->data(即watermark_scale_factor),或把当前值读出。带
_minmax后缀表示写入时检查值是否在table->extra1(最小值)和table->extra2(最大值)范围内。范围定义在 sysctl 表中,通常是
[1, 3000]——即水位间距最小 0.01%、最大 30% 的managed_pages。
2. 写操作后重新计算水位
if (write) setup_per_zone_wmarks();
watermark_scale_factor直接决定WMARK_LOW和WMARK_HIGH相对于WMARK_MIN的间距。参数一变,所有 zone 的水位线都必须重新计算。setup_per_zone_wmarks()(前面讲过的)会获取pcp_batch_high_lock,调用__setup_per_zone_wmarks()遍历所有 zone 重新计算_watermark[]。
3. 读操作
如果write == 0,只执行proc_dointvec_minmax()把当前值复制给用户,不做额外处理。
与min_free_kbyteshandler 的对比
| 方面 | min_free_kbytes_sysctl_handler | watermark_scale_factor_sysctl_handler |
|---|---|---|
| 控制的参数 | WMARK_MIN的基准 | WMARK_LOW/HIGH与MIN的间距 |
| 写后操作 | 记录user_min_free_kbytes+setup_per_zone_wmarks() | 仅setup_per_zone_wmarks() |
| 是否需要记录用户值 | 是(防止被自动计算覆盖) | 否(无自动计算逻辑) |
watermark_scale_factor没有自动计算逻辑,所以不需要user_*记录——用户设多少就是多少。
sysctl 表定义
{ .procname = "watermark_scale_factor", .data = &watermark_scale_factor, .maxlen = sizeof(watermark_scale_factor), .mode = 0644, .proc_handler = watermark_scale_factor_sysctl_handler, .extra1 = SYSCTL_ONE, .extra2 = &one_thousand, },最小值 1(0.01%),最大值 1000(10%)或更高(现代内核允许到 3000)。
总结
watermark_scale_factor_sysctl_handler()是vm.watermark_scale_factor的sysctl 读写入口:它通过proc_dointvec_minmax()完成标准的整数读写和范围检查,写操作后调用setup_per_zone_wmarks()重新计算所有 zone 的水位线。与min_free_kbytes不同,它不需要记录用户设置值,因为watermark_scale_factor没有自动计算逻辑。