From patchwork Mon Feb 10 15:09:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: SeongJae Park X-Patchwork-Id: 11373537 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2D2B2921 for ; Mon, 10 Feb 2020 15:10:31 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id E03E620838 for ; Mon, 10 Feb 2020 15:10:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=amazon.com header.i=@amazon.com header.b="D3x5Iqdj" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E03E620838 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 1CD986B0120; Mon, 10 Feb 2020 10:10:30 -0500 (EST) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 17E5B6B0121; Mon, 10 Feb 2020 10:10:30 -0500 (EST) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 092DE6B0122; Mon, 10 Feb 2020 10:10:30 -0500 (EST) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0141.hostedemail.com [216.40.44.141]) by kanga.kvack.org (Postfix) with ESMTP id E263C6B0120 for ; Mon, 10 Feb 2020 10:10:29 -0500 (EST) Received: from smtpin24.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay03.hostedemail.com (Postfix) with ESMTP id 94CC4824805A for ; Mon, 10 Feb 2020 15:10:29 +0000 (UTC) X-FDA: 76474553778.24.sort76_3e6ded4f4341d X-Spam-Summary: 1,0,0,,d41d8cd98f00b204,prvs=302a421da=sjpark@amazon.com,:akpm@linux-foundation.org:sjpark@amazon.de:acme@kernel.org:alexander.shishkin@linux.intel.com:amit@kernel.org:brendan.d.gregg@gmail.com:brendanhiggins@google.com:cai@lca.pw:colin.king@canonical.com:corbet@lwn.net:dwmw@amazon.com:jolsa@redhat.com:kirill@shutemov.name:mark.rutland@arm.com:mgorman@suse.de:minchan@kernel.org:mingo@redhat.com:namhyung@kernel.org:peterz@infradead.org:rdunlap@infradead.org:rostedt@goodmis.org:sj38.park@gmail.com:vdavydov.dev@gmail.com::linux-doc@vger.kernel.org:linux-kernel@vger.kernel.org,RULES_HIT:30051:30054:30064:30070,0,RBL:72.21.196.25:@amazon.com:.lbl8.mailshell.net-62.18.0.100 66.10.201.10,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:25,LUA_SUMMARY:none X-HE-Tag: sort76_3e6ded4f4341d X-Filterd-Recvd-Size: 8741 Received: from smtp-fw-2101.amazon.com (smtp-fw-2101.amazon.com [72.21.196.25]) by imf29.hostedemail.com (Postfix) with ESMTP for ; Mon, 10 Feb 2020 15:10:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazon201209; t=1581347429; x=1612883429; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=hNmJvif+++9bpJXH4ocwEtBZOpr7pyJLf5AMSJbMCdE=; b=D3x5IqdjGAt9Brz77sHFDY6my8u7ZvhVyDVRbBohNth0gHW8i2gsU6Ub m7OjHpXokW1O+Iv2lsHufiQ41HNNql1H+P0DrNtz/SOF8P5a42K1FU5bP cCrGGPNgzirs5ZHB73XqCZs+HRGsQ28uh53Ra8j35756Playsl8HQ+YG/ M=; IronPort-SDR: qTd2qINutpDE+kMds/NxaKsqI4nJ7UiYNe6hAjUULg5OUjUeS8uDqzZ+uxjF29ZEvhhhomImD6 nNPXqRC2rB7Q== X-IronPort-AV: E=Sophos;i="5.70,425,1574121600"; d="scan'208";a="16476134" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-2a-90c42d1d.us-west-2.amazon.com) ([10.43.8.2]) by smtp-border-fw-out-2101.iad2.amazon.com with ESMTP; 10 Feb 2020 15:10:26 +0000 Received: from EX13MTAUEA002.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan3.pdx.amazon.com [10.170.41.166]) by email-inbound-relay-2a-90c42d1d.us-west-2.amazon.com (Postfix) with ESMTPS id 60AEDA0666; Mon, 10 Feb 2020 15:10:24 +0000 (UTC) Received: from EX13D31EUA001.ant.amazon.com (10.43.165.15) by EX13MTAUEA002.ant.amazon.com (10.43.61.77) with Microsoft SMTP Server (TLS) id 15.0.1236.3; Mon, 10 Feb 2020 15:10:23 +0000 Received: from u886c93fd17d25d.ant.amazon.com (10.43.162.69) by EX13D31EUA001.ant.amazon.com (10.43.165.15) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Mon, 10 Feb 2020 15:10:12 +0000 From: To: CC: SeongJae Park , , , , , , , , , , , , , , , , , , , , , , , , Subject: [RFC PATCH 3/3] mm/damon/rules: Implement a debugfs interface Date: Mon, 10 Feb 2020 16:09:21 +0100 Message-ID: <20200210150921.32482-4-sjpark@amazon.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200210150921.32482-1-sjpark@amazon.com> References: <20200210150921.32482-1-sjpark@amazon.com> MIME-Version: 1.0 X-Originating-IP: [10.43.162.69] X-ClientProxiedBy: EX13D17UWB002.ant.amazon.com (10.43.161.141) To EX13D31EUA001.ant.amazon.com (10.43.165.15) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: SeongJae Park This commit implements a debugfs interface for the DAMON's access pattern based memory management rules. It is supposed to be used by administrators and privileged user space programs. Users read and update the rules using ``/damon/rules`` file. The format is:: Signed-off-by: SeongJae Park --- mm/damon.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/mm/damon.c b/mm/damon.c index 5d33b5d6504b..efb85bdf9400 100644 --- a/mm/damon.c +++ b/mm/damon.c @@ -195,6 +195,29 @@ static void damon_destroy_task(struct damon_task *t) damon_free_task(t); } +static struct damon_rule *damon_new_rule( + unsigned int min_sz_region, unsigned int max_sz_region, + unsigned int min_nr_accesses, unsigned int max_nr_accesses, + unsigned int min_age_region, unsigned int max_age_region, + enum damon_action action) +{ + struct damon_rule *ret; + + ret = kmalloc(sizeof(struct damon_rule), GFP_KERNEL); + if (!ret) + return NULL; + ret->min_sz_region = min_sz_region; + ret->max_sz_region = max_sz_region; + ret->min_nr_accesses = min_nr_accesses; + ret->max_nr_accesses = max_nr_accesses; + ret->min_age_region = min_age_region; + ret->max_age_region = max_age_region; + ret->action = action; + INIT_LIST_HEAD(&ret->list); + + return ret; +} + static void damon_add_rule(struct damon_ctx *ctx, struct damon_rule *r) { list_add_tail(&r->list, &ctx->rules_list); @@ -1266,6 +1289,130 @@ static ssize_t debugfs_monitor_on_write(struct file *file, return ret; } +static ssize_t damon_sprint_rules(struct damon_ctx *c, char *buf, ssize_t len) +{ + char *cursor = buf; + struct damon_rule *r; + int ret; + + damon_for_each_rule(c, r) { + ret = snprintf(cursor, len, "%u %u %u %u %u %u %d\n", + r->min_sz_region, r->max_sz_region, + r->min_nr_accesses, r->max_nr_accesses, + r->min_age_region, r->max_age_region, + r->action); + cursor += ret; + } + return cursor - buf; +} + +static ssize_t debugfs_rules_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = &damon_user_ctx; + ssize_t len; + char *rules_buf; + + rules_buf = kmalloc(sizeof(char) * 1024, GFP_KERNEL); + + len = damon_sprint_rules(ctx, rules_buf, 1024); + len = simple_read_from_buffer(buf, count, ppos, rules_buf, len); + + kfree(rules_buf); + return len; +} + +static void damon_free_rules(struct damon_rule **rules, ssize_t nr_rules) +{ + ssize_t i; + + for (i = 0; i < nr_rules; i++) + kfree(rules[i]); + kfree(rules); +} + +/* + * Converts a string into an array of struct damon_rule pointers + * + * Returns an array of struct damon_rule pointers that converted, or NULL + * otherwise. + */ +static struct damon_rule **str_to_rules(const char *str, ssize_t len, + ssize_t *nr_rules) +{ + struct damon_rule *rule, **rules; + int pos = 0, parsed, ret; + unsigned int min_sz, max_sz, min_nr_a, max_nr_a, min_age, max_age; + int action; + + rules = kmalloc_array(256, sizeof(struct damon_rule *), GFP_KERNEL); + if (!rules) + return NULL; + + *nr_rules = 0; + while (pos < len && *nr_rules < 256) { + ret = sscanf(&str[pos], "%u %u %u %u %u %u %d%n", + &min_sz, &max_sz, &min_nr_a, &max_nr_a, + &min_age, &max_age, &action, &parsed); + pos += parsed; + if (ret != 7) + break; + if (action >= DAMON_ACTION_LEN) { + pr_err("wrong action %d\n", action); + goto error; + } + + rule = damon_new_rule(min_sz, max_sz, min_nr_a, max_nr_a, + min_age, max_age, action); + if (!rule) + goto error; + + rules[*nr_rules] = rule; + *nr_rules += 1; + } + return rules; +error: + damon_free_rules(rules, *nr_rules); + return NULL; +} + +static ssize_t debugfs_rules_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct damon_ctx *ctx = &damon_user_ctx; + char *rules_buf; + struct damon_rule **rules; + ssize_t nr_rules, ret; + + rules_buf = kmalloc(sizeof(char) * 1024, GFP_KERNEL); + ret = simple_write_to_buffer(rules_buf, 1024, ppos, buf, count); + if (ret < 0) { + kfree(rules_buf); + return ret; + } + + rules = str_to_rules(rules_buf, ret, &nr_rules); + if (!rules) + return -EINVAL; + + spin_lock(&ctx->kdamond_lock); + if (ctx->kdamond) + goto monitor_running; + + damon_set_rules(ctx, rules, nr_rules); + spin_unlock(&ctx->kdamond_lock); + kfree(rules_buf); + return ret; + +monitor_running: + spin_unlock(&ctx->kdamond_lock); + pr_err("%s: kdamond is running. Turn it off first.\n", __func__); + ret = -EINVAL; + damon_free_rules(rules, nr_rules); + kfree(rules_buf); + return ret; +} + static ssize_t damon_sprint_pids(struct damon_ctx *ctx, char *buf, ssize_t len) { char *cursor = buf; @@ -1468,6 +1615,12 @@ static const struct file_operations pids_fops = { .write = debugfs_pids_write, }; +static const struct file_operations rules_fops = { + .owner = THIS_MODULE, + .read = debugfs_rules_read, + .write = debugfs_rules_write, +}; + static const struct file_operations record_fops = { .owner = THIS_MODULE, .read = debugfs_record_read, @@ -1484,10 +1637,10 @@ static struct dentry *debugfs_root; static int __init debugfs_init(void) { - const char * const file_names[] = {"attrs", "record", + const char * const file_names[] = {"attrs", "record", "rules", "pids", "monitor_on"}; const struct file_operations *fops[] = {&attrs_fops, &record_fops, - &pids_fops, &monitor_on_fops}; + &rules_fops, &pids_fops, &monitor_on_fops}; int i; debugfs_root = debugfs_create_dir("damon", NULL);