1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * RDMA Transport Layer
4 *
5 * Copyright (c) 2014 - 2018 ProfitBricks GmbH. All rights reserved.
6 * Copyright (c) 2018 - 2019 1&1 IONOS Cloud GmbH. All rights reserved.
7 * Copyright (c) 2019 - 2020 1&1 IONOS SE. All rights reserved.
8 */
9#undef pr_fmt
10#define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt
11
12#include "rtrs-pri.h"
13#include "rtrs-srv.h"
14#include "rtrs-log.h"
15
16static void rtrs_srv_release(struct kobject *kobj)
17{
18	struct rtrs_srv_sess *sess;
19
20	sess = container_of(kobj, struct rtrs_srv_sess, kobj);
21	kfree(sess);
22}
23
24static struct kobj_type ktype = {
25	.sysfs_ops	= &kobj_sysfs_ops,
26	.release	= rtrs_srv_release,
27};
28
29static ssize_t rtrs_srv_disconnect_show(struct kobject *kobj,
30					 struct kobj_attribute *attr,
31					 char *page)
32{
33	return scnprintf(page, PAGE_SIZE, "Usage: echo 1 > %s\n",
34			 attr->attr.name);
35}
36
37static ssize_t rtrs_srv_disconnect_store(struct kobject *kobj,
38					  struct kobj_attribute *attr,
39					  const char *buf, size_t count)
40{
41	struct rtrs_srv_sess *sess;
42	struct rtrs_sess *s;
43	char str[MAXHOSTNAMELEN];
44
45	sess = container_of(kobj, struct rtrs_srv_sess, kobj);
46	s = &sess->s;
47	if (!sysfs_streq(buf, "1")) {
48		rtrs_err(s, "%s: invalid value: '%s'\n",
49			  attr->attr.name, buf);
50		return -EINVAL;
51	}
52
53	sockaddr_to_str((struct sockaddr *)&sess->s.dst_addr, str, sizeof(str));
54
55	rtrs_info(s, "disconnect for path %s requested\n", str);
56	/* first remove sysfs itself to avoid deadlock */
57	sysfs_remove_file_self(&sess->kobj, &attr->attr);
58	close_sess(sess);
59
60	return count;
61}
62
63static struct kobj_attribute rtrs_srv_disconnect_attr =
64	__ATTR(disconnect, 0644,
65	       rtrs_srv_disconnect_show, rtrs_srv_disconnect_store);
66
67static ssize_t rtrs_srv_hca_port_show(struct kobject *kobj,
68				       struct kobj_attribute *attr,
69				       char *page)
70{
71	struct rtrs_srv_sess *sess;
72	struct rtrs_con *usr_con;
73
74	sess = container_of(kobj, typeof(*sess), kobj);
75	usr_con = sess->s.con[0];
76
77	return scnprintf(page, PAGE_SIZE, "%u\n",
78			 usr_con->cm_id->port_num);
79}
80
81static struct kobj_attribute rtrs_srv_hca_port_attr =
82	__ATTR(hca_port, 0444, rtrs_srv_hca_port_show, NULL);
83
84static ssize_t rtrs_srv_hca_name_show(struct kobject *kobj,
85				       struct kobj_attribute *attr,
86				       char *page)
87{
88	struct rtrs_srv_sess *sess;
89
90	sess = container_of(kobj, struct rtrs_srv_sess, kobj);
91
92	return scnprintf(page, PAGE_SIZE, "%s\n",
93			 sess->s.dev->ib_dev->name);
94}
95
96static struct kobj_attribute rtrs_srv_hca_name_attr =
97	__ATTR(hca_name, 0444, rtrs_srv_hca_name_show, NULL);
98
99static ssize_t rtrs_srv_src_addr_show(struct kobject *kobj,
100				       struct kobj_attribute *attr,
101				       char *page)
102{
103	struct rtrs_srv_sess *sess;
104	int cnt;
105
106	sess = container_of(kobj, struct rtrs_srv_sess, kobj);
107	cnt = sockaddr_to_str((struct sockaddr *)&sess->s.dst_addr,
108			      page, PAGE_SIZE);
109	return cnt + scnprintf(page + cnt, PAGE_SIZE - cnt, "\n");
110}
111
112static struct kobj_attribute rtrs_srv_src_addr_attr =
113	__ATTR(src_addr, 0444, rtrs_srv_src_addr_show, NULL);
114
115static ssize_t rtrs_srv_dst_addr_show(struct kobject *kobj,
116				       struct kobj_attribute *attr,
117				       char *page)
118{
119	struct rtrs_srv_sess *sess;
120	int cnt;
121
122	sess = container_of(kobj, struct rtrs_srv_sess, kobj);
123	cnt = sockaddr_to_str((struct sockaddr *)&sess->s.src_addr,
124			      page, PAGE_SIZE);
125	return cnt + scnprintf(page + cnt, PAGE_SIZE - cnt, "\n");
126}
127
128static struct kobj_attribute rtrs_srv_dst_addr_attr =
129	__ATTR(dst_addr, 0444, rtrs_srv_dst_addr_show, NULL);
130
131static struct attribute *rtrs_srv_sess_attrs[] = {
132	&rtrs_srv_hca_name_attr.attr,
133	&rtrs_srv_hca_port_attr.attr,
134	&rtrs_srv_src_addr_attr.attr,
135	&rtrs_srv_dst_addr_attr.attr,
136	&rtrs_srv_disconnect_attr.attr,
137	NULL,
138};
139
140static const struct attribute_group rtrs_srv_sess_attr_group = {
141	.attrs = rtrs_srv_sess_attrs,
142};
143
144STAT_ATTR(struct rtrs_srv_stats, rdma,
145	  rtrs_srv_stats_rdma_to_str,
146	  rtrs_srv_reset_rdma_stats);
147
148static struct attribute *rtrs_srv_stats_attrs[] = {
149	&rdma_attr.attr,
150	NULL,
151};
152
153static const struct attribute_group rtrs_srv_stats_attr_group = {
154	.attrs = rtrs_srv_stats_attrs,
155};
156
157static int rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
158{
159	struct rtrs_srv *srv = sess->srv;
160	int err = 0;
161
162	mutex_lock(&srv->paths_mutex);
163	if (srv->dev_ref++) {
164		/*
165		 * Device needs to be registered only on the first session
166		 */
167		goto unlock;
168	}
169	srv->dev.class = rtrs_dev_class;
170	err = dev_set_name(&srv->dev, "%s", sess->s.sessname);
171	if (err)
172		goto unlock;
173
174	/*
175	 * Suppress user space notification until
176	 * sysfs files are created
177	 */
178	dev_set_uevent_suppress(&srv->dev, true);
179	err = device_add(&srv->dev);
180	if (err) {
181		pr_err("device_add(): %d\n", err);
182		goto put;
183	}
184	srv->kobj_paths = kobject_create_and_add("paths", &srv->dev.kobj);
185	if (!srv->kobj_paths) {
186		err = -ENOMEM;
187		pr_err("kobject_create_and_add(): %d\n", err);
188		device_del(&srv->dev);
189		put_device(&srv->dev);
190		goto unlock;
191	}
192	dev_set_uevent_suppress(&srv->dev, false);
193	kobject_uevent(&srv->dev.kobj, KOBJ_ADD);
194	goto unlock;
195
196put:
197	put_device(&srv->dev);
198unlock:
199	mutex_unlock(&srv->paths_mutex);
200
201	return err;
202}
203
204static void
205rtrs_srv_destroy_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
206{
207	struct rtrs_srv *srv = sess->srv;
208
209	mutex_lock(&srv->paths_mutex);
210	if (!--srv->dev_ref) {
211		kobject_del(srv->kobj_paths);
212		kobject_put(srv->kobj_paths);
213		mutex_unlock(&srv->paths_mutex);
214		device_del(&srv->dev);
215		put_device(&srv->dev);
216	} else {
217		put_device(&srv->dev);
218		mutex_unlock(&srv->paths_mutex);
219	}
220}
221
222static void rtrs_srv_sess_stats_release(struct kobject *kobj)
223{
224	struct rtrs_srv_stats *stats;
225
226	stats = container_of(kobj, struct rtrs_srv_stats, kobj_stats);
227
228	kfree(stats);
229}
230
231static struct kobj_type ktype_stats = {
232	.sysfs_ops = &kobj_sysfs_ops,
233	.release = rtrs_srv_sess_stats_release,
234};
235
236static int rtrs_srv_create_stats_files(struct rtrs_srv_sess *sess)
237{
238	int err;
239	struct rtrs_sess *s = &sess->s;
240
241	err = kobject_init_and_add(&sess->stats->kobj_stats, &ktype_stats,
242				   &sess->kobj, "stats");
243	if (err) {
244		rtrs_err(s, "kobject_init_and_add(): %d\n", err);
245		kobject_put(&sess->stats->kobj_stats);
246		return err;
247	}
248	err = sysfs_create_group(&sess->stats->kobj_stats,
249				 &rtrs_srv_stats_attr_group);
250	if (err) {
251		rtrs_err(s, "sysfs_create_group(): %d\n", err);
252		goto err;
253	}
254
255	return 0;
256
257err:
258	kobject_del(&sess->stats->kobj_stats);
259	kobject_put(&sess->stats->kobj_stats);
260
261	return err;
262}
263
264int rtrs_srv_create_sess_files(struct rtrs_srv_sess *sess)
265{
266	struct rtrs_srv *srv = sess->srv;
267	struct rtrs_sess *s = &sess->s;
268	char str[NAME_MAX];
269	int err, cnt;
270
271	cnt = sockaddr_to_str((struct sockaddr *)&sess->s.dst_addr,
272			      str, sizeof(str));
273	cnt += scnprintf(str + cnt, sizeof(str) - cnt, "@");
274	sockaddr_to_str((struct sockaddr *)&sess->s.src_addr,
275			str + cnt, sizeof(str) - cnt);
276
277	err = rtrs_srv_create_once_sysfs_root_folders(sess);
278	if (err)
279		return err;
280
281	err = kobject_init_and_add(&sess->kobj, &ktype, srv->kobj_paths,
282				   "%s", str);
283	if (err) {
284		rtrs_err(s, "kobject_init_and_add(): %d\n", err);
285		goto destroy_root;
286	}
287	err = sysfs_create_group(&sess->kobj, &rtrs_srv_sess_attr_group);
288	if (err) {
289		rtrs_err(s, "sysfs_create_group(): %d\n", err);
290		goto put_kobj;
291	}
292	err = rtrs_srv_create_stats_files(sess);
293	if (err)
294		goto remove_group;
295
296	return 0;
297
298remove_group:
299	sysfs_remove_group(&sess->kobj, &rtrs_srv_sess_attr_group);
300put_kobj:
301	kobject_del(&sess->kobj);
302destroy_root:
303	kobject_put(&sess->kobj);
304	rtrs_srv_destroy_once_sysfs_root_folders(sess);
305
306	return err;
307}
308
309void rtrs_srv_destroy_sess_files(struct rtrs_srv_sess *sess)
310{
311	if (sess->kobj.state_in_sysfs) {
312		kobject_del(&sess->stats->kobj_stats);
313		kobject_put(&sess->stats->kobj_stats);
314		sysfs_remove_group(&sess->kobj, &rtrs_srv_sess_attr_group);
315		kobject_put(&sess->kobj);
316
317		rtrs_srv_destroy_once_sysfs_root_folders(sess);
318	}
319}
320