• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
rtrs_srv_release(struct kobject * kobj)16 static 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 
24 static struct kobj_type ktype = {
25 	.sysfs_ops	= &kobj_sysfs_ops,
26 	.release	= rtrs_srv_release,
27 };
28 
rtrs_srv_disconnect_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)29 static 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 
rtrs_srv_disconnect_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)37 static 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 
63 static struct kobj_attribute rtrs_srv_disconnect_attr =
64 	__ATTR(disconnect, 0644,
65 	       rtrs_srv_disconnect_show, rtrs_srv_disconnect_store);
66 
rtrs_srv_hca_port_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)67 static 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 
81 static struct kobj_attribute rtrs_srv_hca_port_attr =
82 	__ATTR(hca_port, 0444, rtrs_srv_hca_port_show, NULL);
83 
rtrs_srv_hca_name_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)84 static 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 
96 static struct kobj_attribute rtrs_srv_hca_name_attr =
97 	__ATTR(hca_name, 0444, rtrs_srv_hca_name_show, NULL);
98 
rtrs_srv_src_addr_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)99 static 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 
112 static struct kobj_attribute rtrs_srv_src_addr_attr =
113 	__ATTR(src_addr, 0444, rtrs_srv_src_addr_show, NULL);
114 
rtrs_srv_dst_addr_show(struct kobject * kobj,struct kobj_attribute * attr,char * page)115 static 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 
128 static struct kobj_attribute rtrs_srv_dst_addr_attr =
129 	__ATTR(dst_addr, 0444, rtrs_srv_dst_addr_show, NULL);
130 
131 static 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 
140 static const struct attribute_group rtrs_srv_sess_attr_group = {
141 	.attrs = rtrs_srv_sess_attrs,
142 };
143 
144 STAT_ATTR(struct rtrs_srv_stats, rdma,
145 	  rtrs_srv_stats_rdma_to_str,
146 	  rtrs_srv_reset_rdma_stats);
147 
148 static struct attribute *rtrs_srv_stats_attrs[] = {
149 	&rdma_attr.attr,
150 	NULL,
151 };
152 
153 static const struct attribute_group rtrs_srv_stats_attr_group = {
154 	.attrs = rtrs_srv_stats_attrs,
155 };
156 
rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_sess * sess)157 static 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 
196 put:
197 	put_device(&srv->dev);
198 unlock:
199 	mutex_unlock(&srv->paths_mutex);
200 
201 	return err;
202 }
203 
204 static void
rtrs_srv_destroy_once_sysfs_root_folders(struct rtrs_srv_sess * sess)205 rtrs_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 
rtrs_srv_sess_stats_release(struct kobject * kobj)222 static 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 
231 static struct kobj_type ktype_stats = {
232 	.sysfs_ops = &kobj_sysfs_ops,
233 	.release = rtrs_srv_sess_stats_release,
234 };
235 
rtrs_srv_create_stats_files(struct rtrs_srv_sess * sess)236 static 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 
257 err:
258 	kobject_del(&sess->stats->kobj_stats);
259 	kobject_put(&sess->stats->kobj_stats);
260 
261 	return err;
262 }
263 
rtrs_srv_create_sess_files(struct rtrs_srv_sess * sess)264 int 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 
298 remove_group:
299 	sysfs_remove_group(&sess->kobj, &rtrs_srv_sess_attr_group);
300 put_kobj:
301 	kobject_del(&sess->kobj);
302 destroy_root:
303 	kobject_put(&sess->kobj);
304 	rtrs_srv_destroy_once_sysfs_root_folders(sess);
305 
306 	return err;
307 }
308 
rtrs_srv_destroy_sess_files(struct rtrs_srv_sess * sess)309 void 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