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