linux/drivers/block/rnbd/rnbd-srv-sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * RDMA Network Block Driver
   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 <uapi/linux/limits.h>
  13#include <linux/kobject.h>
  14#include <linux/sysfs.h>
  15#include <linux/stat.h>
  16#include <linux/genhd.h>
  17#include <linux/list.h>
  18#include <linux/moduleparam.h>
  19#include <linux/device.h>
  20
  21#include "rnbd-srv.h"
  22
  23static struct device *rnbd_dev;
  24static struct class *rnbd_dev_class;
  25static struct kobject *rnbd_devs_kobj;
  26
  27static void rnbd_srv_dev_release(struct kobject *kobj)
  28{
  29        struct rnbd_srv_dev *dev;
  30
  31        dev = container_of(kobj, struct rnbd_srv_dev, dev_kobj);
  32
  33        kfree(dev);
  34}
  35
  36static struct kobj_type dev_ktype = {
  37        .sysfs_ops = &kobj_sysfs_ops,
  38        .release = rnbd_srv_dev_release
  39};
  40
  41int rnbd_srv_create_dev_sysfs(struct rnbd_srv_dev *dev,
  42                               struct block_device *bdev,
  43                               const char *dev_name)
  44{
  45        struct kobject *bdev_kobj;
  46        int ret;
  47
  48        ret = kobject_init_and_add(&dev->dev_kobj, &dev_ktype,
  49                                   rnbd_devs_kobj, dev_name);
  50        if (ret) {
  51                kobject_put(&dev->dev_kobj);
  52                return ret;
  53        }
  54
  55        dev->dev_sessions_kobj = kobject_create_and_add("sessions",
  56                                                        &dev->dev_kobj);
  57        if (!dev->dev_sessions_kobj) {
  58                ret = -ENOMEM;
  59                goto free_dev_kobj;
  60        }
  61
  62        bdev_kobj = &disk_to_dev(bdev->bd_disk)->kobj;
  63        ret = sysfs_create_link(&dev->dev_kobj, bdev_kobj, "block_dev");
  64        if (ret)
  65                goto put_sess_kobj;
  66
  67        return 0;
  68
  69put_sess_kobj:
  70        kobject_put(dev->dev_sessions_kobj);
  71free_dev_kobj:
  72        kobject_del(&dev->dev_kobj);
  73        kobject_put(&dev->dev_kobj);
  74        return ret;
  75}
  76
  77void rnbd_srv_destroy_dev_sysfs(struct rnbd_srv_dev *dev)
  78{
  79        sysfs_remove_link(&dev->dev_kobj, "block_dev");
  80        kobject_del(dev->dev_sessions_kobj);
  81        kobject_put(dev->dev_sessions_kobj);
  82        kobject_del(&dev->dev_kobj);
  83        kobject_put(&dev->dev_kobj);
  84}
  85
  86static ssize_t read_only_show(struct kobject *kobj, struct kobj_attribute *attr,
  87                              char *page)
  88{
  89        struct rnbd_srv_sess_dev *sess_dev;
  90
  91        sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
  92
  93        return sysfs_emit(page, "%d\n",
  94                          !(sess_dev->open_flags & FMODE_WRITE));
  95}
  96
  97static struct kobj_attribute rnbd_srv_dev_session_ro_attr =
  98        __ATTR_RO(read_only);
  99
 100static ssize_t access_mode_show(struct kobject *kobj,
 101                                struct kobj_attribute *attr,
 102                                char *page)
 103{
 104        struct rnbd_srv_sess_dev *sess_dev;
 105
 106        sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
 107
 108        return sysfs_emit(page, "%s\n",
 109                          rnbd_access_mode_str(sess_dev->access_mode));
 110}
 111
 112static struct kobj_attribute rnbd_srv_dev_session_access_mode_attr =
 113        __ATTR_RO(access_mode);
 114
 115static ssize_t mapping_path_show(struct kobject *kobj,
 116                                 struct kobj_attribute *attr, char *page)
 117{
 118        struct rnbd_srv_sess_dev *sess_dev;
 119
 120        sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
 121
 122        return sysfs_emit(page, "%s\n", sess_dev->pathname);
 123}
 124
 125static struct kobj_attribute rnbd_srv_dev_session_mapping_path_attr =
 126        __ATTR_RO(mapping_path);
 127
 128static ssize_t rnbd_srv_dev_session_force_close_show(struct kobject *kobj,
 129                                        struct kobj_attribute *attr, char *page)
 130{
 131        return sysfs_emit(page, "Usage: echo 1 > %s\n",
 132                          attr->attr.name);
 133}
 134
 135static ssize_t rnbd_srv_dev_session_force_close_store(struct kobject *kobj,
 136                                        struct kobj_attribute *attr,
 137                                        const char *buf, size_t count)
 138{
 139        struct rnbd_srv_sess_dev *sess_dev;
 140
 141        sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
 142
 143        if (!sysfs_streq(buf, "1")) {
 144                rnbd_srv_err(sess_dev, "%s: invalid value: '%s'\n",
 145                              attr->attr.name, buf);
 146                return -EINVAL;
 147        }
 148
 149        rnbd_srv_info(sess_dev, "force close requested\n");
 150        rnbd_srv_sess_dev_force_close(sess_dev, attr);
 151
 152        return count;
 153}
 154
 155static struct kobj_attribute rnbd_srv_dev_session_force_close_attr =
 156        __ATTR(force_close, 0644,
 157               rnbd_srv_dev_session_force_close_show,
 158               rnbd_srv_dev_session_force_close_store);
 159
 160static struct attribute *rnbd_srv_default_dev_sessions_attrs[] = {
 161        &rnbd_srv_dev_session_access_mode_attr.attr,
 162        &rnbd_srv_dev_session_ro_attr.attr,
 163        &rnbd_srv_dev_session_mapping_path_attr.attr,
 164        &rnbd_srv_dev_session_force_close_attr.attr,
 165        NULL,
 166};
 167
 168static struct attribute_group rnbd_srv_default_dev_session_attr_group = {
 169        .attrs = rnbd_srv_default_dev_sessions_attrs,
 170};
 171
 172void rnbd_srv_destroy_dev_session_sysfs(struct rnbd_srv_sess_dev *sess_dev)
 173{
 174        sysfs_remove_group(&sess_dev->kobj,
 175                           &rnbd_srv_default_dev_session_attr_group);
 176
 177        kobject_del(&sess_dev->kobj);
 178        kobject_put(&sess_dev->kobj);
 179}
 180
 181static void rnbd_srv_sess_dev_release(struct kobject *kobj)
 182{
 183        struct rnbd_srv_sess_dev *sess_dev;
 184
 185        sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
 186        rnbd_destroy_sess_dev(sess_dev, sess_dev->keep_id);
 187}
 188
 189static struct kobj_type rnbd_srv_sess_dev_ktype = {
 190        .sysfs_ops      = &kobj_sysfs_ops,
 191        .release        = rnbd_srv_sess_dev_release,
 192};
 193
 194int rnbd_srv_create_dev_session_sysfs(struct rnbd_srv_sess_dev *sess_dev)
 195{
 196        int ret;
 197
 198        ret = kobject_init_and_add(&sess_dev->kobj, &rnbd_srv_sess_dev_ktype,
 199                                   sess_dev->dev->dev_sessions_kobj, "%s",
 200                                   sess_dev->sess->sessname);
 201        if (ret) {
 202                kobject_put(&sess_dev->kobj);
 203                return ret;
 204        }
 205
 206        ret = sysfs_create_group(&sess_dev->kobj,
 207                                 &rnbd_srv_default_dev_session_attr_group);
 208        if (ret) {
 209                kobject_del(&sess_dev->kobj);
 210                kobject_put(&sess_dev->kobj);
 211        }
 212
 213        return ret;
 214}
 215
 216int rnbd_srv_create_sysfs_files(void)
 217{
 218        int err;
 219
 220        rnbd_dev_class = class_create(THIS_MODULE, "rnbd-server");
 221        if (IS_ERR(rnbd_dev_class))
 222                return PTR_ERR(rnbd_dev_class);
 223
 224        rnbd_dev = device_create(rnbd_dev_class, NULL,
 225                                  MKDEV(0, 0), NULL, "ctl");
 226        if (IS_ERR(rnbd_dev)) {
 227                err = PTR_ERR(rnbd_dev);
 228                goto cls_destroy;
 229        }
 230        rnbd_devs_kobj = kobject_create_and_add("devices", &rnbd_dev->kobj);
 231        if (!rnbd_devs_kobj) {
 232                err = -ENOMEM;
 233                goto dev_destroy;
 234        }
 235
 236        return 0;
 237
 238dev_destroy:
 239        device_destroy(rnbd_dev_class, MKDEV(0, 0));
 240cls_destroy:
 241        class_destroy(rnbd_dev_class);
 242
 243        return err;
 244}
 245
 246void rnbd_srv_destroy_sysfs_files(void)
 247{
 248        kobject_del(rnbd_devs_kobj);
 249        kobject_put(rnbd_devs_kobj);
 250        device_destroy(rnbd_dev_class, MKDEV(0, 0));
 251        class_destroy(rnbd_dev_class);
 252}
 253