linux/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c
Md Haris Iqbal 39c2d639ca RDMA/rtrs-srv: Set .release function for rtrs srv device during device init
The device .release function was not being set during the device
initialization. This was leading to the below warning, in error cases when
put_srv was called before device_add was called.

Warning:

Device '(null)' does not have a release() function, it is broken and must
be fixed. See Documentation/kobject.txt.

So, set the device .release function during device initialization in the
__alloc_srv() function.

Fixes: baa5b28b7a47 ("RDMA/rtrs-srv: Replace device_register with device_initialize and device_add")
Link: https://lore.kernel.org/r/20200907102216.104041-1-haris.iqbal@cloud.ionos.com
Signed-off-by: Md Haris Iqbal <haris.iqbal@cloud.ionos.com>
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
2020-09-09 13:28:14 -03:00

314 lines
7.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* RDMA Transport Layer
*
* Copyright (c) 2014 - 2018 ProfitBricks GmbH. All rights reserved.
* Copyright (c) 2018 - 2019 1&1 IONOS Cloud GmbH. All rights reserved.
* Copyright (c) 2019 - 2020 1&1 IONOS SE. All rights reserved.
*/
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt
#include "rtrs-pri.h"
#include "rtrs-srv.h"
#include "rtrs-log.h"
static void rtrs_srv_release(struct kobject *kobj)
{
struct rtrs_srv_sess *sess;
sess = container_of(kobj, struct rtrs_srv_sess, kobj);
kfree(sess);
}
static struct kobj_type ktype = {
.sysfs_ops = &kobj_sysfs_ops,
.release = rtrs_srv_release,
};
static ssize_t rtrs_srv_disconnect_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *page)
{
return scnprintf(page, PAGE_SIZE, "Usage: echo 1 > %s\n",
attr->attr.name);
}
static ssize_t rtrs_srv_disconnect_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct rtrs_srv_sess *sess;
struct rtrs_sess *s;
char str[MAXHOSTNAMELEN];
sess = container_of(kobj, struct rtrs_srv_sess, kobj);
s = &sess->s;
if (!sysfs_streq(buf, "1")) {
rtrs_err(s, "%s: invalid value: '%s'\n",
attr->attr.name, buf);
return -EINVAL;
}
sockaddr_to_str((struct sockaddr *)&sess->s.dst_addr, str, sizeof(str));
rtrs_info(s, "disconnect for path %s requested\n", str);
close_sess(sess);
return count;
}
static struct kobj_attribute rtrs_srv_disconnect_attr =
__ATTR(disconnect, 0644,
rtrs_srv_disconnect_show, rtrs_srv_disconnect_store);
static ssize_t rtrs_srv_hca_port_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *page)
{
struct rtrs_srv_sess *sess;
struct rtrs_con *usr_con;
sess = container_of(kobj, typeof(*sess), kobj);
usr_con = sess->s.con[0];
return scnprintf(page, PAGE_SIZE, "%u\n",
usr_con->cm_id->port_num);
}
static struct kobj_attribute rtrs_srv_hca_port_attr =
__ATTR(hca_port, 0444, rtrs_srv_hca_port_show, NULL);
static ssize_t rtrs_srv_hca_name_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *page)
{
struct rtrs_srv_sess *sess;
sess = container_of(kobj, struct rtrs_srv_sess, kobj);
return scnprintf(page, PAGE_SIZE, "%s\n",
sess->s.dev->ib_dev->name);
}
static struct kobj_attribute rtrs_srv_hca_name_attr =
__ATTR(hca_name, 0444, rtrs_srv_hca_name_show, NULL);
static ssize_t rtrs_srv_src_addr_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *page)
{
struct rtrs_srv_sess *sess;
int cnt;
sess = container_of(kobj, struct rtrs_srv_sess, kobj);
cnt = sockaddr_to_str((struct sockaddr *)&sess->s.dst_addr,
page, PAGE_SIZE);
return cnt + scnprintf(page + cnt, PAGE_SIZE - cnt, "\n");
}
static struct kobj_attribute rtrs_srv_src_addr_attr =
__ATTR(src_addr, 0444, rtrs_srv_src_addr_show, NULL);
static ssize_t rtrs_srv_dst_addr_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *page)
{
struct rtrs_srv_sess *sess;
int cnt;
sess = container_of(kobj, struct rtrs_srv_sess, kobj);
cnt = sockaddr_to_str((struct sockaddr *)&sess->s.src_addr,
page, PAGE_SIZE);
return cnt + scnprintf(page + cnt, PAGE_SIZE - cnt, "\n");
}
static struct kobj_attribute rtrs_srv_dst_addr_attr =
__ATTR(dst_addr, 0444, rtrs_srv_dst_addr_show, NULL);
static struct attribute *rtrs_srv_sess_attrs[] = {
&rtrs_srv_hca_name_attr.attr,
&rtrs_srv_hca_port_attr.attr,
&rtrs_srv_src_addr_attr.attr,
&rtrs_srv_dst_addr_attr.attr,
&rtrs_srv_disconnect_attr.attr,
NULL,
};
static struct attribute_group rtrs_srv_sess_attr_group = {
.attrs = rtrs_srv_sess_attrs,
};
STAT_ATTR(struct rtrs_srv_stats, rdma,
rtrs_srv_stats_rdma_to_str,
rtrs_srv_reset_rdma_stats);
static struct attribute *rtrs_srv_stats_attrs[] = {
&rdma_attr.attr,
NULL,
};
static struct attribute_group rtrs_srv_stats_attr_group = {
.attrs = rtrs_srv_stats_attrs,
};
static int rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
{
struct rtrs_srv *srv = sess->srv;
int err = 0;
mutex_lock(&srv->paths_mutex);
if (srv->dev_ref++) {
/*
* Device needs to be registered only on the first session
*/
goto unlock;
}
srv->dev.class = rtrs_dev_class;
err = dev_set_name(&srv->dev, "%s", sess->s.sessname);
if (err)
goto unlock;
/*
* Suppress user space notification until
* sysfs files are created
*/
dev_set_uevent_suppress(&srv->dev, true);
err = device_add(&srv->dev);
if (err) {
pr_err("device_add(): %d\n", err);
goto put;
}
srv->kobj_paths = kobject_create_and_add("paths", &srv->dev.kobj);
if (!srv->kobj_paths) {
err = -ENOMEM;
pr_err("kobject_create_and_add(): %d\n", err);
device_del(&srv->dev);
goto unlock;
}
dev_set_uevent_suppress(&srv->dev, false);
kobject_uevent(&srv->dev.kobj, KOBJ_ADD);
goto unlock;
put:
put_device(&srv->dev);
unlock:
mutex_unlock(&srv->paths_mutex);
return err;
}
static void
rtrs_srv_destroy_once_sysfs_root_folders(struct rtrs_srv_sess *sess)
{
struct rtrs_srv *srv = sess->srv;
mutex_lock(&srv->paths_mutex);
if (!--srv->dev_ref) {
kobject_del(srv->kobj_paths);
kobject_put(srv->kobj_paths);
mutex_unlock(&srv->paths_mutex);
device_del(&srv->dev);
} else {
mutex_unlock(&srv->paths_mutex);
}
}
static void rtrs_srv_sess_stats_release(struct kobject *kobj)
{
struct rtrs_srv_stats *stats;
stats = container_of(kobj, struct rtrs_srv_stats, kobj_stats);
kfree(stats);
}
static struct kobj_type ktype_stats = {
.sysfs_ops = &kobj_sysfs_ops,
.release = rtrs_srv_sess_stats_release,
};
static int rtrs_srv_create_stats_files(struct rtrs_srv_sess *sess)
{
int err;
struct rtrs_sess *s = &sess->s;
err = kobject_init_and_add(&sess->stats->kobj_stats, &ktype_stats,
&sess->kobj, "stats");
if (err) {
rtrs_err(s, "kobject_init_and_add(): %d\n", err);
return err;
}
err = sysfs_create_group(&sess->stats->kobj_stats,
&rtrs_srv_stats_attr_group);
if (err) {
rtrs_err(s, "sysfs_create_group(): %d\n", err);
goto err;
}
return 0;
err:
kobject_del(&sess->stats->kobj_stats);
kobject_put(&sess->stats->kobj_stats);
return err;
}
int rtrs_srv_create_sess_files(struct rtrs_srv_sess *sess)
{
struct rtrs_srv *srv = sess->srv;
struct rtrs_sess *s = &sess->s;
char str[NAME_MAX];
int err, cnt;
cnt = sockaddr_to_str((struct sockaddr *)&sess->s.dst_addr,
str, sizeof(str));
cnt += scnprintf(str + cnt, sizeof(str) - cnt, "@");
sockaddr_to_str((struct sockaddr *)&sess->s.src_addr,
str + cnt, sizeof(str) - cnt);
err = rtrs_srv_create_once_sysfs_root_folders(sess);
if (err)
return err;
err = kobject_init_and_add(&sess->kobj, &ktype, srv->kobj_paths,
"%s", str);
if (err) {
rtrs_err(s, "kobject_init_and_add(): %d\n", err);
goto destroy_root;
}
err = sysfs_create_group(&sess->kobj, &rtrs_srv_sess_attr_group);
if (err) {
rtrs_err(s, "sysfs_create_group(): %d\n", err);
goto put_kobj;
}
err = rtrs_srv_create_stats_files(sess);
if (err)
goto remove_group;
return 0;
remove_group:
sysfs_remove_group(&sess->kobj, &rtrs_srv_sess_attr_group);
put_kobj:
kobject_del(&sess->kobj);
kobject_put(&sess->kobj);
destroy_root:
rtrs_srv_destroy_once_sysfs_root_folders(sess);
return err;
}
void rtrs_srv_destroy_sess_files(struct rtrs_srv_sess *sess)
{
if (sess->kobj.state_in_sysfs) {
kobject_del(&sess->stats->kobj_stats);
kobject_put(&sess->stats->kobj_stats);
kobject_del(&sess->kobj);
kobject_put(&sess->kobj);
rtrs_srv_destroy_once_sysfs_root_folders(sess);
}
}