[Devel,v2,1/3] sunrpc: add "kill-tasks" proc entry

Submitted by Stanislav Kinsburskiy on June 26, 2017, 2:59 p.m.

Details

Message ID 20170626145927.31092.71296.stgit@localhost.localdomain
State New
Series "Kill SUNRPC tasks on container fast stop"
Headers show

Commit Message

Stanislav Kinsburskiy June 26, 2017, 2:59 p.m.
Boolean per-net SUNPRC proc entry. Will be used to abort SUNRPC traffic when
necessary.

Signed-off-by: Stanislav Kinsburskiy <skinsbursky@virtuozzo.com>
---
 include/linux/sunrpc/clnt.h |    4 ++
 net/sunrpc/clnt.c           |   71 +++++++++++++++++++++++++++++++++++++++++++
 net/sunrpc/netns.h          |    3 ++
 net/sunrpc/stats.c          |    8 +++++
 4 files changed, 86 insertions(+)

Patch hide | download patch | download mbox

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 131032f..597e5ae 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -182,5 +182,9 @@  const char	*rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
 int		rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
 
 const char *rpc_proc_name(const struct rpc_task *task);
+
+int rpc_task_kill_proc_init(struct net *net);
+void rpc_task_kill_proc_fini(struct net *net);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 23608eb..e64f751 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -2536,3 +2536,74 @@  retry:
 }
 EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
 #endif /* CONFIG_SUNRPC_SWAP */
+
+static ssize_t write_kill_tasks(struct file *file, const char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	char tbuf[20];
+	unsigned long kill_tasks;
+	int res;
+
+	if (*ppos || count > sizeof(tbuf)-1)
+		return -EINVAL;
+	if (copy_from_user(tbuf, buf, count))
+		return -EFAULT;
+
+	tbuf[count] = 0;
+	res = kstrtoul(tbuf, 0, &kill_tasks);
+	if (res)
+		return res;
+
+	sn->kill_tasks = !!kill_tasks;
+	return count;
+}
+
+static ssize_t read_kill_tasks(struct file *file, char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+	unsigned long p = *ppos;
+	char tbuf[10];
+	size_t len;
+
+	snprintf(tbuf, sizeof(tbuf), "%d\n", sn->kill_tasks);
+	len = strlen(tbuf);
+	if (p >= len)
+		return 0;
+	len -= p;
+	if (len > count)
+		len = count;
+	if (copy_to_user(buf, (void *)(tbuf+p), len))
+		return -EFAULT;
+	*ppos += len;
+	return len;
+}
+
+static const struct file_operations kill_tasks_ops = {
+	.open = nonseekable_open,
+	.write = write_kill_tasks,
+	.read = read_kill_tasks,
+};
+
+int rpc_task_kill_proc_init(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	sn->kill_tasks = 0;
+	sn->kill_tasks_proc = proc_create_data("kill-tasks",
+					      S_IFREG|S_IRUSR|S_IWUSR,
+					      sn->proc_net_rpc,
+					      &kill_tasks_ops, net);
+	return sn->kill_tasks_proc ? 0 : -ENOMEM;
+}
+
+void rpc_task_kill_proc_fini(struct net *net)
+{
+	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+	if (sn->kill_tasks_proc)
+		remove_proc_entry("kill-tasks", sn->proc_net_rpc);
+}
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h
index df58268..b0150ae 100644
--- a/net/sunrpc/netns.h
+++ b/net/sunrpc/netns.h
@@ -32,6 +32,9 @@  struct sunrpc_net {
 	int pipe_version;
 	atomic_t pipe_users;
 	struct proc_dir_entry *use_gssp_proc;
+
+	bool kill_tasks;
+	struct proc_dir_entry *kill_tasks_proc;
 };
 
 extern int sunrpc_net_id;
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 80d3401..f621756 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -287,6 +287,7 @@  EXPORT_SYMBOL_GPL(svc_proc_unregister);
 int rpc_proc_init(struct net *net)
 {
 	struct sunrpc_net *sn;
+	int err;
 
 	dprintk("RPC:       registering /proc/net/rpc\n");
 	sn = net_generic(net, sunrpc_net_id);
@@ -294,12 +295,19 @@  int rpc_proc_init(struct net *net)
 	if (sn->proc_net_rpc == NULL)
 		return -ENOMEM;
 
+	err = rpc_task_kill_proc_init(net);
+	if (err) {
+		remove_proc_entry("rpc", net->proc_net);
+		return err;
+	}
+
 	return 0;
 }
 
 void rpc_proc_exit(struct net *net)
 {
 	dprintk("RPC:       unregistering /proc/net/rpc\n");
+	rpc_task_kill_proc_fini(net);
 	remove_proc_entry("rpc", net->proc_net);
 }