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