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