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