xref: /linux/drivers/block/rnbd/rnbd-clt-sysfs.c (revision ec8a42e7343234802b9054874fe01810880289ce)
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, &sectors);
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