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