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 10 #undef pr_fmt 11 #define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt 12 13 #include <linux/types.h> 14 #include <linux/ctype.h> 15 #include <linux/parser.h> 16 #include <linux/module.h> 17 #include <linux/in6.h> 18 #include <linux/fs.h> 19 #include <linux/uaccess.h> 20 #include <linux/device.h> 21 #include <rdma/ib.h> 22 #include <rdma/rdma_cm.h> 23 24 #include "rnbd-clt.h" 25 26 static struct device *rnbd_dev; 27 static struct class *rnbd_dev_class; 28 static struct kobject *rnbd_devs_kobj; 29 30 enum { 31 RNBD_OPT_ERR = 0, 32 RNBD_OPT_DEST_PORT = 1 << 0, 33 RNBD_OPT_PATH = 1 << 1, 34 RNBD_OPT_DEV_PATH = 1 << 2, 35 RNBD_OPT_ACCESS_MODE = 1 << 3, 36 RNBD_OPT_SESSNAME = 1 << 6, 37 }; 38 39 static const unsigned int rnbd_opt_mandatory[] = { 40 RNBD_OPT_DEV_PATH, 41 RNBD_OPT_SESSNAME, 42 }; 43 44 static const match_table_t rnbd_opt_tokens = { 45 {RNBD_OPT_PATH, "path=%s" }, 46 {RNBD_OPT_DEV_PATH, "device_path=%s"}, 47 {RNBD_OPT_DEST_PORT, "dest_port=%d" }, 48 {RNBD_OPT_ACCESS_MODE, "access_mode=%s"}, 49 {RNBD_OPT_SESSNAME, "sessname=%s" }, 50 {RNBD_OPT_ERR, NULL }, 51 }; 52 53 struct rnbd_map_options { 54 char *sessname; 55 struct rtrs_addr *paths; 56 size_t *path_cnt; 57 char *pathname; 58 u16 *dest_port; 59 enum rnbd_access_mode *access_mode; 60 }; 61 62 static int rnbd_clt_parse_map_options(const char *buf, size_t max_path_cnt, 63 struct rnbd_map_options *opt) 64 { 65 char *options, *sep_opt; 66 char *p; 67 substring_t args[MAX_OPT_ARGS]; 68 int opt_mask = 0; 69 int token; 70 int ret = -EINVAL; 71 int i, dest_port; 72 int p_cnt = 0; 73 74 options = kstrdup(buf, GFP_KERNEL); 75 if (!options) 76 return -ENOMEM; 77 78 sep_opt = strstrip(options); 79 while ((p = strsep(&sep_opt, " ")) != NULL) { 80 if (!*p) 81 continue; 82 83 token = match_token(p, rnbd_opt_tokens, args); 84 opt_mask |= token; 85 86 switch (token) { 87 case RNBD_OPT_SESSNAME: 88 p = match_strdup(args); 89 if (!p) { 90 ret = -ENOMEM; 91 goto out; 92 } 93 if (strlen(p) > NAME_MAX) { 94 pr_err("map_device: sessname too long\n"); 95 ret = -EINVAL; 96 kfree(p); 97 goto out; 98 } 99 strlcpy(opt->sessname, p, NAME_MAX); 100 kfree(p); 101 break; 102 103 case RNBD_OPT_PATH: 104 if (p_cnt >= max_path_cnt) { 105 pr_err("map_device: too many (> %zu) paths provided\n", 106 max_path_cnt); 107 ret = -ENOMEM; 108 goto out; 109 } 110 p = match_strdup(args); 111 if (!p) { 112 ret = -ENOMEM; 113 goto out; 114 } 115 116 ret = rtrs_addr_to_sockaddr(p, strlen(p), 117 *opt->dest_port, 118 &opt->paths[p_cnt]); 119 if (ret) { 120 pr_err("Can't parse path %s: %d\n", p, ret); 121 kfree(p); 122 goto out; 123 } 124 125 p_cnt++; 126 127 kfree(p); 128 break; 129 130 case RNBD_OPT_DEV_PATH: 131 p = match_strdup(args); 132 if (!p) { 133 ret = -ENOMEM; 134 goto out; 135 } 136 if (strlen(p) > NAME_MAX) { 137 pr_err("map_device: Device path too long\n"); 138 ret = -EINVAL; 139 kfree(p); 140 goto out; 141 } 142 strlcpy(opt->pathname, p, NAME_MAX); 143 kfree(p); 144 break; 145 146 case RNBD_OPT_DEST_PORT: 147 if (match_int(args, &dest_port) || dest_port < 0 || 148 dest_port > 65535) { 149 pr_err("bad destination port number parameter '%d'\n", 150 dest_port); 151 ret = -EINVAL; 152 goto out; 153 } 154 *opt->dest_port = dest_port; 155 break; 156 157 case RNBD_OPT_ACCESS_MODE: 158 p = match_strdup(args); 159 if (!p) { 160 ret = -ENOMEM; 161 goto out; 162 } 163 164 if (!strcmp(p, "ro")) { 165 *opt->access_mode = RNBD_ACCESS_RO; 166 } else if (!strcmp(p, "rw")) { 167 *opt->access_mode = RNBD_ACCESS_RW; 168 } else if (!strcmp(p, "migration")) { 169 *opt->access_mode = RNBD_ACCESS_MIGRATION; 170 } else { 171 pr_err("map_device: Invalid access_mode: '%s'\n", 172 p); 173 ret = -EINVAL; 174 kfree(p); 175 goto out; 176 } 177 178 kfree(p); 179 break; 180 181 default: 182 pr_err("map_device: Unknown parameter or missing value '%s'\n", 183 p); 184 ret = -EINVAL; 185 goto out; 186 } 187 } 188 189 for (i = 0; i < ARRAY_SIZE(rnbd_opt_mandatory); i++) { 190 if ((opt_mask & rnbd_opt_mandatory[i])) { 191 ret = 0; 192 } else { 193 pr_err("map_device: Parameters missing\n"); 194 ret = -EINVAL; 195 break; 196 } 197 } 198 199 out: 200 *opt->path_cnt = p_cnt; 201 kfree(options); 202 return ret; 203 } 204 205 static ssize_t state_show(struct kobject *kobj, 206 struct kobj_attribute *attr, char *page) 207 { 208 struct rnbd_clt_dev *dev; 209 210 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 211 212 switch (dev->dev_state) { 213 case DEV_STATE_INIT: 214 return snprintf(page, PAGE_SIZE, "init\n"); 215 case DEV_STATE_MAPPED: 216 /* TODO fix cli tool before changing to proper state */ 217 return snprintf(page, PAGE_SIZE, "open\n"); 218 case DEV_STATE_MAPPED_DISCONNECTED: 219 /* TODO fix cli tool before changing to proper state */ 220 return snprintf(page, PAGE_SIZE, "closed\n"); 221 case DEV_STATE_UNMAPPED: 222 return snprintf(page, PAGE_SIZE, "unmapped\n"); 223 default: 224 return snprintf(page, PAGE_SIZE, "unknown\n"); 225 } 226 } 227 228 static struct kobj_attribute rnbd_clt_state_attr = __ATTR_RO(state); 229 230 static ssize_t mapping_path_show(struct kobject *kobj, 231 struct kobj_attribute *attr, char *page) 232 { 233 struct rnbd_clt_dev *dev; 234 235 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 236 237 return scnprintf(page, PAGE_SIZE, "%s\n", dev->pathname); 238 } 239 240 static struct kobj_attribute rnbd_clt_mapping_path_attr = 241 __ATTR_RO(mapping_path); 242 243 static ssize_t access_mode_show(struct kobject *kobj, 244 struct kobj_attribute *attr, char *page) 245 { 246 struct rnbd_clt_dev *dev; 247 248 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 249 250 return snprintf(page, PAGE_SIZE, "%s\n", 251 rnbd_access_mode_str(dev->access_mode)); 252 } 253 254 static struct kobj_attribute rnbd_clt_access_mode = 255 __ATTR_RO(access_mode); 256 257 static ssize_t rnbd_clt_unmap_dev_show(struct kobject *kobj, 258 struct kobj_attribute *attr, char *page) 259 { 260 return scnprintf(page, PAGE_SIZE, "Usage: echo <normal|force> > %s\n", 261 attr->attr.name); 262 } 263 264 static ssize_t rnbd_clt_unmap_dev_store(struct kobject *kobj, 265 struct kobj_attribute *attr, 266 const char *buf, size_t count) 267 { 268 struct rnbd_clt_dev *dev; 269 char *opt, *options; 270 bool force; 271 int err; 272 273 opt = kstrdup(buf, GFP_KERNEL); 274 if (!opt) 275 return -ENOMEM; 276 277 options = strstrip(opt); 278 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 279 if (sysfs_streq(options, "normal")) { 280 force = false; 281 } else if (sysfs_streq(options, "force")) { 282 force = true; 283 } else { 284 rnbd_clt_err(dev, 285 "unmap_device: Invalid value: %s\n", 286 options); 287 err = -EINVAL; 288 goto out; 289 } 290 291 rnbd_clt_info(dev, "Unmapping device, option: %s.\n", 292 force ? "force" : "normal"); 293 294 /* 295 * We take explicit module reference only for one reason: do not 296 * race with lockless rnbd_destroy_sessions(). 297 */ 298 if (!try_module_get(THIS_MODULE)) { 299 err = -ENODEV; 300 goto out; 301 } 302 err = rnbd_clt_unmap_device(dev, force, &attr->attr); 303 if (err) { 304 if (err != -EALREADY) 305 rnbd_clt_err(dev, "unmap_device: %d\n", err); 306 goto module_put; 307 } 308 309 /* 310 * Here device can be vanished! 311 */ 312 313 err = count; 314 315 module_put: 316 module_put(THIS_MODULE); 317 out: 318 kfree(opt); 319 320 return err; 321 } 322 323 static struct kobj_attribute rnbd_clt_unmap_device_attr = 324 __ATTR(unmap_device, 0644, rnbd_clt_unmap_dev_show, 325 rnbd_clt_unmap_dev_store); 326 327 static ssize_t rnbd_clt_resize_dev_show(struct kobject *kobj, 328 struct kobj_attribute *attr, 329 char *page) 330 { 331 return scnprintf(page, PAGE_SIZE, 332 "Usage: echo <new size in sectors> > %s\n", 333 attr->attr.name); 334 } 335 336 static ssize_t rnbd_clt_resize_dev_store(struct kobject *kobj, 337 struct kobj_attribute *attr, 338 const char *buf, size_t count) 339 { 340 int ret; 341 unsigned long sectors; 342 struct rnbd_clt_dev *dev; 343 344 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 345 346 ret = kstrtoul(buf, 0, §ors); 347 if (ret) 348 return ret; 349 350 ret = rnbd_clt_resize_disk(dev, (size_t)sectors); 351 if (ret) 352 return ret; 353 354 return count; 355 } 356 357 static struct kobj_attribute rnbd_clt_resize_dev_attr = 358 __ATTR(resize, 0644, rnbd_clt_resize_dev_show, 359 rnbd_clt_resize_dev_store); 360 361 static ssize_t rnbd_clt_remap_dev_show(struct kobject *kobj, 362 struct kobj_attribute *attr, char *page) 363 { 364 return scnprintf(page, PAGE_SIZE, "Usage: echo <1> > %s\n", 365 attr->attr.name); 366 } 367 368 static ssize_t rnbd_clt_remap_dev_store(struct kobject *kobj, 369 struct kobj_attribute *attr, 370 const char *buf, size_t count) 371 { 372 struct rnbd_clt_dev *dev; 373 char *opt, *options; 374 int err; 375 376 opt = kstrdup(buf, GFP_KERNEL); 377 if (!opt) 378 return -ENOMEM; 379 380 options = strstrip(opt); 381 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 382 if (!sysfs_streq(options, "1")) { 383 rnbd_clt_err(dev, 384 "remap_device: Invalid value: %s\n", 385 options); 386 err = -EINVAL; 387 goto out; 388 } 389 err = rnbd_clt_remap_device(dev); 390 if (likely(!err)) 391 err = count; 392 393 out: 394 kfree(opt); 395 396 return err; 397 } 398 399 static struct kobj_attribute rnbd_clt_remap_device_attr = 400 __ATTR(remap_device, 0644, rnbd_clt_remap_dev_show, 401 rnbd_clt_remap_dev_store); 402 403 static ssize_t session_show(struct kobject *kobj, struct kobj_attribute *attr, 404 char *page) 405 { 406 struct rnbd_clt_dev *dev; 407 408 dev = container_of(kobj, struct rnbd_clt_dev, kobj); 409 410 return scnprintf(page, PAGE_SIZE, "%s\n", dev->sess->sessname); 411 } 412 413 static struct kobj_attribute rnbd_clt_session_attr = 414 __ATTR_RO(session); 415 416 static struct attribute *rnbd_dev_attrs[] = { 417 &rnbd_clt_unmap_device_attr.attr, 418 &rnbd_clt_resize_dev_attr.attr, 419 &rnbd_clt_remap_device_attr.attr, 420 &rnbd_clt_mapping_path_attr.attr, 421 &rnbd_clt_state_attr.attr, 422 &rnbd_clt_session_attr.attr, 423 &rnbd_clt_access_mode.attr, 424 NULL, 425 }; 426 427 void rnbd_clt_remove_dev_symlink(struct rnbd_clt_dev *dev) 428 { 429 /* 430 * The module unload rnbd_client_exit path is racing with unmapping of 431 * the last single device from the sysfs manually 432 * i.e. rnbd_clt_unmap_dev_store() leading to a sysfs warning because 433 * of sysfs link already was removed already. 434 */ 435 if (dev->blk_symlink_name && try_module_get(THIS_MODULE)) { 436 sysfs_remove_link(rnbd_devs_kobj, dev->blk_symlink_name); 437 kfree(dev->blk_symlink_name); 438 module_put(THIS_MODULE); 439 } 440 } 441 442 static struct kobj_type rnbd_dev_ktype = { 443 .sysfs_ops = &kobj_sysfs_ops, 444 .default_attrs = rnbd_dev_attrs, 445 }; 446 447 static int rnbd_clt_add_dev_kobj(struct rnbd_clt_dev *dev) 448 { 449 int ret; 450 struct kobject *gd_kobj = &disk_to_dev(dev->gd)->kobj; 451 452 ret = kobject_init_and_add(&dev->kobj, &rnbd_dev_ktype, gd_kobj, "%s", 453 "rnbd"); 454 if (ret) { 455 rnbd_clt_err(dev, "Failed to create device sysfs dir, err: %d\n", 456 ret); 457 kobject_put(&dev->kobj); 458 } 459 460 return ret; 461 } 462 463 static ssize_t rnbd_clt_map_device_show(struct kobject *kobj, 464 struct kobj_attribute *attr, 465 char *page) 466 { 467 return scnprintf(page, PAGE_SIZE, 468 "Usage: echo \"[dest_port=server port number] sessname=<name of the rtrs session> path=<[srcaddr@]dstaddr> [path=<[srcaddr@]dstaddr>] device_path=<full path on remote side> [access_mode=<ro|rw|migration>]\" > %s\n\naddr ::= [ ip:<ipv4> | ip:<ipv6> | gid:<gid> ]\n", 469 attr->attr.name); 470 } 471 472 static int rnbd_clt_get_path_name(struct rnbd_clt_dev *dev, char *buf, 473 size_t len) 474 { 475 int ret; 476 char pathname[NAME_MAX], *s; 477 478 strlcpy(pathname, dev->pathname, sizeof(pathname)); 479 while ((s = strchr(pathname, '/'))) 480 s[0] = '!'; 481 482 ret = snprintf(buf, len, "%s", pathname); 483 if (ret >= len) 484 return -ENAMETOOLONG; 485 486 ret = snprintf(buf, len, "%s@%s", buf, dev->sess->sessname); 487 if (ret >= len) 488 return -ENAMETOOLONG; 489 490 return 0; 491 } 492 493 static int rnbd_clt_add_dev_symlink(struct rnbd_clt_dev *dev) 494 { 495 struct kobject *gd_kobj = &disk_to_dev(dev->gd)->kobj; 496 int ret, len; 497 498 len = strlen(dev->pathname) + strlen(dev->sess->sessname) + 2; 499 dev->blk_symlink_name = kzalloc(len, GFP_KERNEL); 500 if (!dev->blk_symlink_name) { 501 rnbd_clt_err(dev, "Failed to allocate memory for blk_symlink_name\n"); 502 return -ENOMEM; 503 } 504 505 ret = rnbd_clt_get_path_name(dev, dev->blk_symlink_name, 506 len); 507 if (ret) { 508 rnbd_clt_err(dev, "Failed to get /sys/block symlink path, err: %d\n", 509 ret); 510 goto out_err; 511 } 512 513 ret = sysfs_create_link(rnbd_devs_kobj, gd_kobj, 514 dev->blk_symlink_name); 515 if (ret) { 516 rnbd_clt_err(dev, "Creating /sys/block symlink failed, err: %d\n", 517 ret); 518 goto out_err; 519 } 520 521 return 0; 522 523 out_err: 524 kfree(dev->blk_symlink_name); 525 dev->blk_symlink_name = NULL ; 526 return ret; 527 } 528 529 static ssize_t rnbd_clt_map_device_store(struct kobject *kobj, 530 struct kobj_attribute *attr, 531 const char *buf, size_t count) 532 { 533 struct rnbd_clt_dev *dev; 534 struct rnbd_map_options opt; 535 int ret; 536 char pathname[NAME_MAX]; 537 char sessname[NAME_MAX]; 538 enum rnbd_access_mode access_mode = RNBD_ACCESS_RW; 539 u16 port_nr = RTRS_PORT; 540 541 struct sockaddr_storage *addrs; 542 struct rtrs_addr paths[6]; 543 size_t path_cnt; 544 545 opt.sessname = sessname; 546 opt.paths = paths; 547 opt.path_cnt = &path_cnt; 548 opt.pathname = pathname; 549 opt.dest_port = &port_nr; 550 opt.access_mode = &access_mode; 551 addrs = kcalloc(ARRAY_SIZE(paths) * 2, sizeof(*addrs), GFP_KERNEL); 552 if (!addrs) 553 return -ENOMEM; 554 555 for (path_cnt = 0; path_cnt < ARRAY_SIZE(paths); path_cnt++) { 556 paths[path_cnt].src = &addrs[path_cnt * 2]; 557 paths[path_cnt].dst = &addrs[path_cnt * 2 + 1]; 558 } 559 560 ret = rnbd_clt_parse_map_options(buf, ARRAY_SIZE(paths), &opt); 561 if (ret) 562 goto out; 563 564 pr_info("Mapping device %s on session %s, (access_mode: %s)\n", 565 pathname, sessname, 566 rnbd_access_mode_str(access_mode)); 567 568 dev = rnbd_clt_map_device(sessname, paths, path_cnt, port_nr, pathname, 569 access_mode); 570 if (IS_ERR(dev)) { 571 ret = PTR_ERR(dev); 572 goto out; 573 } 574 575 ret = rnbd_clt_add_dev_kobj(dev); 576 if (ret) 577 goto unmap_dev; 578 579 ret = rnbd_clt_add_dev_symlink(dev); 580 if (ret) 581 goto unmap_dev; 582 583 kfree(addrs); 584 return count; 585 586 unmap_dev: 587 rnbd_clt_unmap_device(dev, true, NULL); 588 out: 589 kfree(addrs); 590 return ret; 591 } 592 593 static struct kobj_attribute rnbd_clt_map_device_attr = 594 __ATTR(map_device, 0644, 595 rnbd_clt_map_device_show, rnbd_clt_map_device_store); 596 597 static struct attribute *default_attrs[] = { 598 &rnbd_clt_map_device_attr.attr, 599 NULL, 600 }; 601 602 static struct attribute_group default_attr_group = { 603 .attrs = default_attrs, 604 }; 605 606 static const struct attribute_group *default_attr_groups[] = { 607 &default_attr_group, 608 NULL, 609 }; 610 611 int rnbd_clt_create_sysfs_files(void) 612 { 613 int err; 614 615 rnbd_dev_class = class_create(THIS_MODULE, "rnbd-client"); 616 if (IS_ERR(rnbd_dev_class)) 617 return PTR_ERR(rnbd_dev_class); 618 619 rnbd_dev = device_create_with_groups(rnbd_dev_class, NULL, 620 MKDEV(0, 0), NULL, 621 default_attr_groups, "ctl"); 622 if (IS_ERR(rnbd_dev)) { 623 err = PTR_ERR(rnbd_dev); 624 goto cls_destroy; 625 } 626 rnbd_devs_kobj = kobject_create_and_add("devices", &rnbd_dev->kobj); 627 if (!rnbd_devs_kobj) { 628 err = -ENOMEM; 629 goto dev_destroy; 630 } 631 632 return 0; 633 634 dev_destroy: 635 device_destroy(rnbd_dev_class, MKDEV(0, 0)); 636 cls_destroy: 637 class_destroy(rnbd_dev_class); 638 639 return err; 640 } 641 642 void rnbd_clt_destroy_default_group(void) 643 { 644 sysfs_remove_group(&rnbd_dev->kobj, &default_attr_group); 645 } 646 647 void rnbd_clt_destroy_sysfs_files(void) 648 { 649 kobject_del(rnbd_devs_kobj); 650 kobject_put(rnbd_devs_kobj); 651 device_destroy(rnbd_dev_class, MKDEV(0, 0)); 652 class_destroy(rnbd_dev_class); 653 } 654