1 // SPDX-License-Identifier: GPL-2.0 2 #ifndef NO_BCACHEFS_CHARDEV 3 4 #include "bcachefs.h" 5 #include "bcachefs_ioctl.h" 6 #include "buckets.h" 7 #include "chardev.h" 8 #include "journal.h" 9 #include "move.h" 10 #include "replicas.h" 11 #include "super.h" 12 #include "super-io.h" 13 14 #include <linux/anon_inodes.h> 15 #include <linux/cdev.h> 16 #include <linux/device.h> 17 #include <linux/file.h> 18 #include <linux/fs.h> 19 #include <linux/ioctl.h> 20 #include <linux/kthread.h> 21 #include <linux/major.h> 22 #include <linux/sched/task.h> 23 #include <linux/slab.h> 24 #include <linux/uaccess.h> 25 26 /* returns with ref on ca->ref */ 27 static struct bch_dev *bch2_device_lookup(struct bch_fs *c, u64 dev, 28 unsigned flags) 29 { 30 struct bch_dev *ca; 31 32 if (flags & BCH_BY_INDEX) { 33 if (dev >= c->sb.nr_devices) 34 return ERR_PTR(-EINVAL); 35 36 rcu_read_lock(); 37 ca = rcu_dereference(c->devs[dev]); 38 if (ca) 39 percpu_ref_get(&ca->ref); 40 rcu_read_unlock(); 41 42 if (!ca) 43 return ERR_PTR(-EINVAL); 44 } else { 45 char *path; 46 47 path = strndup_user((const char __user *) 48 (unsigned long) dev, PATH_MAX); 49 if (IS_ERR(path)) 50 return ERR_CAST(path); 51 52 ca = bch2_dev_lookup(c, path); 53 kfree(path); 54 } 55 56 return ca; 57 } 58 59 #if 0 60 static long bch2_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg) 61 { 62 struct bch_ioctl_assemble arg; 63 struct bch_fs *c; 64 u64 *user_devs = NULL; 65 char **devs = NULL; 66 unsigned i; 67 int ret = -EFAULT; 68 69 if (copy_from_user(&arg, user_arg, sizeof(arg))) 70 return -EFAULT; 71 72 if (arg.flags || arg.pad) 73 return -EINVAL; 74 75 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL); 76 if (!user_devs) 77 return -ENOMEM; 78 79 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL); 80 81 if (copy_from_user(user_devs, user_arg->devs, 82 sizeof(u64) * arg.nr_devs)) 83 goto err; 84 85 for (i = 0; i < arg.nr_devs; i++) { 86 devs[i] = strndup_user((const char __user *)(unsigned long) 87 user_devs[i], 88 PATH_MAX); 89 ret= PTR_ERR_OR_ZERO(devs[i]); 90 if (ret) 91 goto err; 92 } 93 94 c = bch2_fs_open(devs, arg.nr_devs, bch2_opts_empty()); 95 ret = PTR_ERR_OR_ZERO(c); 96 if (!ret) 97 closure_put(&c->cl); 98 err: 99 if (devs) 100 for (i = 0; i < arg.nr_devs; i++) 101 kfree(devs[i]); 102 kfree(devs); 103 return ret; 104 } 105 106 static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg) 107 { 108 struct bch_ioctl_incremental arg; 109 const char *err; 110 char *path; 111 112 if (copy_from_user(&arg, user_arg, sizeof(arg))) 113 return -EFAULT; 114 115 if (arg.flags || arg.pad) 116 return -EINVAL; 117 118 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX); 119 ret = PTR_ERR_OR_ZERO(path); 120 if (ret) 121 return ret; 122 123 err = bch2_fs_open_incremental(path); 124 kfree(path); 125 126 if (err) { 127 pr_err("Could not register bcachefs devices: %s", err); 128 return -EINVAL; 129 } 130 131 return 0; 132 } 133 #endif 134 135 static long bch2_global_ioctl(unsigned cmd, void __user *arg) 136 { 137 switch (cmd) { 138 #if 0 139 case BCH_IOCTL_ASSEMBLE: 140 return bch2_ioctl_assemble(arg); 141 case BCH_IOCTL_INCREMENTAL: 142 return bch2_ioctl_incremental(arg); 143 #endif 144 default: 145 return -ENOTTY; 146 } 147 } 148 149 static long bch2_ioctl_query_uuid(struct bch_fs *c, 150 struct bch_ioctl_query_uuid __user *user_arg) 151 { 152 if (copy_to_user(&user_arg->uuid, &c->sb.user_uuid, 153 sizeof(c->sb.user_uuid))) 154 return -EFAULT; 155 return 0; 156 } 157 158 #if 0 159 static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start arg) 160 { 161 if (!capable(CAP_SYS_ADMIN)) 162 return -EPERM; 163 164 if (arg.flags || arg.pad) 165 return -EINVAL; 166 167 return bch2_fs_start(c); 168 } 169 170 static long bch2_ioctl_stop(struct bch_fs *c) 171 { 172 if (!capable(CAP_SYS_ADMIN)) 173 return -EPERM; 174 175 bch2_fs_stop(c); 176 return 0; 177 } 178 #endif 179 180 static long bch2_ioctl_disk_add(struct bch_fs *c, struct bch_ioctl_disk arg) 181 { 182 char *path; 183 int ret; 184 185 if (!capable(CAP_SYS_ADMIN)) 186 return -EPERM; 187 188 if (arg.flags || arg.pad) 189 return -EINVAL; 190 191 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX); 192 ret = PTR_ERR_OR_ZERO(path); 193 if (ret) 194 return ret; 195 196 ret = bch2_dev_add(c, path); 197 kfree(path); 198 199 return ret; 200 } 201 202 static long bch2_ioctl_disk_remove(struct bch_fs *c, struct bch_ioctl_disk arg) 203 { 204 struct bch_dev *ca; 205 206 if (!capable(CAP_SYS_ADMIN)) 207 return -EPERM; 208 209 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST| 210 BCH_FORCE_IF_METADATA_LOST| 211 BCH_FORCE_IF_DEGRADED| 212 BCH_BY_INDEX)) || 213 arg.pad) 214 return -EINVAL; 215 216 ca = bch2_device_lookup(c, arg.dev, arg.flags); 217 if (IS_ERR(ca)) 218 return PTR_ERR(ca); 219 220 return bch2_dev_remove(c, ca, arg.flags); 221 } 222 223 static long bch2_ioctl_disk_online(struct bch_fs *c, struct bch_ioctl_disk arg) 224 { 225 char *path; 226 int ret; 227 228 if (!capable(CAP_SYS_ADMIN)) 229 return -EPERM; 230 231 if (arg.flags || arg.pad) 232 return -EINVAL; 233 234 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX); 235 ret = PTR_ERR_OR_ZERO(path); 236 if (ret) 237 return ret; 238 239 ret = bch2_dev_online(c, path); 240 kfree(path); 241 return ret; 242 } 243 244 static long bch2_ioctl_disk_offline(struct bch_fs *c, struct bch_ioctl_disk arg) 245 { 246 struct bch_dev *ca; 247 int ret; 248 249 if (!capable(CAP_SYS_ADMIN)) 250 return -EPERM; 251 252 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST| 253 BCH_FORCE_IF_METADATA_LOST| 254 BCH_FORCE_IF_DEGRADED| 255 BCH_BY_INDEX)) || 256 arg.pad) 257 return -EINVAL; 258 259 ca = bch2_device_lookup(c, arg.dev, arg.flags); 260 if (IS_ERR(ca)) 261 return PTR_ERR(ca); 262 263 ret = bch2_dev_offline(c, ca, arg.flags); 264 percpu_ref_put(&ca->ref); 265 return ret; 266 } 267 268 static long bch2_ioctl_disk_set_state(struct bch_fs *c, 269 struct bch_ioctl_disk_set_state arg) 270 { 271 struct bch_dev *ca; 272 int ret; 273 274 if (!capable(CAP_SYS_ADMIN)) 275 return -EPERM; 276 277 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST| 278 BCH_FORCE_IF_METADATA_LOST| 279 BCH_FORCE_IF_DEGRADED| 280 BCH_BY_INDEX)) || 281 arg.pad[0] || arg.pad[1] || arg.pad[2] || 282 arg.new_state >= BCH_MEMBER_STATE_NR) 283 return -EINVAL; 284 285 ca = bch2_device_lookup(c, arg.dev, arg.flags); 286 if (IS_ERR(ca)) 287 return PTR_ERR(ca); 288 289 ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags); 290 if (ret) 291 bch_err(c, "Error setting device state: %s", bch2_err_str(ret)); 292 293 percpu_ref_put(&ca->ref); 294 return ret; 295 } 296 297 struct bch_data_ctx { 298 struct bch_fs *c; 299 struct bch_ioctl_data arg; 300 struct bch_move_stats stats; 301 302 int ret; 303 304 struct task_struct *thread; 305 }; 306 307 static int bch2_data_thread(void *arg) 308 { 309 struct bch_data_ctx *ctx = arg; 310 311 ctx->ret = bch2_data_job(ctx->c, &ctx->stats, ctx->arg); 312 313 ctx->stats.data_type = U8_MAX; 314 return 0; 315 } 316 317 static int bch2_data_job_release(struct inode *inode, struct file *file) 318 { 319 struct bch_data_ctx *ctx = file->private_data; 320 321 kthread_stop(ctx->thread); 322 put_task_struct(ctx->thread); 323 kfree(ctx); 324 return 0; 325 } 326 327 static ssize_t bch2_data_job_read(struct file *file, char __user *buf, 328 size_t len, loff_t *ppos) 329 { 330 struct bch_data_ctx *ctx = file->private_data; 331 struct bch_fs *c = ctx->c; 332 struct bch_ioctl_data_event e = { 333 .type = BCH_DATA_EVENT_PROGRESS, 334 .p.data_type = ctx->stats.data_type, 335 .p.btree_id = ctx->stats.pos.btree, 336 .p.pos = ctx->stats.pos.pos, 337 .p.sectors_done = atomic64_read(&ctx->stats.sectors_seen), 338 .p.sectors_total = bch2_fs_usage_read_short(c).used, 339 }; 340 341 if (len < sizeof(e)) 342 return -EINVAL; 343 344 if (copy_to_user(buf, &e, sizeof(e))) 345 return -EFAULT; 346 347 return sizeof(e); 348 } 349 350 static const struct file_operations bcachefs_data_ops = { 351 .release = bch2_data_job_release, 352 .read = bch2_data_job_read, 353 .llseek = no_llseek, 354 }; 355 356 static long bch2_ioctl_data(struct bch_fs *c, 357 struct bch_ioctl_data arg) 358 { 359 struct bch_data_ctx *ctx = NULL; 360 struct file *file = NULL; 361 unsigned flags = O_RDONLY|O_CLOEXEC|O_NONBLOCK; 362 int ret, fd = -1; 363 364 if (!capable(CAP_SYS_ADMIN)) 365 return -EPERM; 366 367 if (arg.op >= BCH_DATA_OP_NR || arg.flags) 368 return -EINVAL; 369 370 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 371 if (!ctx) 372 return -ENOMEM; 373 374 ctx->c = c; 375 ctx->arg = arg; 376 377 ctx->thread = kthread_create(bch2_data_thread, ctx, 378 "bch-data/%s", c->name); 379 if (IS_ERR(ctx->thread)) { 380 ret = PTR_ERR(ctx->thread); 381 goto err; 382 } 383 384 ret = get_unused_fd_flags(flags); 385 if (ret < 0) 386 goto err; 387 fd = ret; 388 389 file = anon_inode_getfile("[bcachefs]", &bcachefs_data_ops, ctx, flags); 390 if (IS_ERR(file)) { 391 ret = PTR_ERR(file); 392 goto err; 393 } 394 395 fd_install(fd, file); 396 397 get_task_struct(ctx->thread); 398 wake_up_process(ctx->thread); 399 400 return fd; 401 err: 402 if (fd >= 0) 403 put_unused_fd(fd); 404 if (!IS_ERR_OR_NULL(ctx->thread)) 405 kthread_stop(ctx->thread); 406 kfree(ctx); 407 return ret; 408 } 409 410 static long bch2_ioctl_fs_usage(struct bch_fs *c, 411 struct bch_ioctl_fs_usage __user *user_arg) 412 { 413 struct bch_ioctl_fs_usage *arg = NULL; 414 struct bch_replicas_usage *dst_e, *dst_end; 415 struct bch_fs_usage_online *src; 416 u32 replica_entries_bytes; 417 unsigned i; 418 int ret = 0; 419 420 if (!test_bit(BCH_FS_STARTED, &c->flags)) 421 return -EINVAL; 422 423 if (get_user(replica_entries_bytes, &user_arg->replica_entries_bytes)) 424 return -EFAULT; 425 426 arg = kzalloc(size_add(sizeof(*arg), replica_entries_bytes), GFP_KERNEL); 427 if (!arg) 428 return -ENOMEM; 429 430 src = bch2_fs_usage_read(c); 431 if (!src) { 432 ret = -ENOMEM; 433 goto err; 434 } 435 436 arg->capacity = c->capacity; 437 arg->used = bch2_fs_sectors_used(c, src); 438 arg->online_reserved = src->online_reserved; 439 440 for (i = 0; i < BCH_REPLICAS_MAX; i++) 441 arg->persistent_reserved[i] = src->u.persistent_reserved[i]; 442 443 dst_e = arg->replicas; 444 dst_end = (void *) arg->replicas + replica_entries_bytes; 445 446 for (i = 0; i < c->replicas.nr; i++) { 447 struct bch_replicas_entry *src_e = 448 cpu_replicas_entry(&c->replicas, i); 449 450 /* check that we have enough space for one replicas entry */ 451 if (dst_e + 1 > dst_end) { 452 ret = -ERANGE; 453 break; 454 } 455 456 dst_e->sectors = src->u.replicas[i]; 457 dst_e->r = *src_e; 458 459 /* recheck after setting nr_devs: */ 460 if (replicas_usage_next(dst_e) > dst_end) { 461 ret = -ERANGE; 462 break; 463 } 464 465 memcpy(dst_e->r.devs, src_e->devs, src_e->nr_devs); 466 467 dst_e = replicas_usage_next(dst_e); 468 } 469 470 arg->replica_entries_bytes = (void *) dst_e - (void *) arg->replicas; 471 472 percpu_up_read(&c->mark_lock); 473 kfree(src); 474 475 if (ret) 476 goto err; 477 if (copy_to_user(user_arg, arg, 478 sizeof(*arg) + arg->replica_entries_bytes)) 479 ret = -EFAULT; 480 err: 481 kfree(arg); 482 return ret; 483 } 484 485 static long bch2_ioctl_dev_usage(struct bch_fs *c, 486 struct bch_ioctl_dev_usage __user *user_arg) 487 { 488 struct bch_ioctl_dev_usage arg; 489 struct bch_dev_usage src; 490 struct bch_dev *ca; 491 unsigned i; 492 493 if (!test_bit(BCH_FS_STARTED, &c->flags)) 494 return -EINVAL; 495 496 if (copy_from_user(&arg, user_arg, sizeof(arg))) 497 return -EFAULT; 498 499 if ((arg.flags & ~BCH_BY_INDEX) || 500 arg.pad[0] || 501 arg.pad[1] || 502 arg.pad[2]) 503 return -EINVAL; 504 505 ca = bch2_device_lookup(c, arg.dev, arg.flags); 506 if (IS_ERR(ca)) 507 return PTR_ERR(ca); 508 509 src = bch2_dev_usage_read(ca); 510 511 arg.state = ca->mi.state; 512 arg.bucket_size = ca->mi.bucket_size; 513 arg.nr_buckets = ca->mi.nbuckets - ca->mi.first_bucket; 514 arg.buckets_ec = src.buckets_ec; 515 516 for (i = 0; i < BCH_DATA_NR; i++) { 517 arg.d[i].buckets = src.d[i].buckets; 518 arg.d[i].sectors = src.d[i].sectors; 519 arg.d[i].fragmented = src.d[i].fragmented; 520 } 521 522 percpu_ref_put(&ca->ref); 523 524 if (copy_to_user(user_arg, &arg, sizeof(arg))) 525 return -EFAULT; 526 527 return 0; 528 } 529 530 static long bch2_ioctl_read_super(struct bch_fs *c, 531 struct bch_ioctl_read_super arg) 532 { 533 struct bch_dev *ca = NULL; 534 struct bch_sb *sb; 535 int ret = 0; 536 537 if (!capable(CAP_SYS_ADMIN)) 538 return -EPERM; 539 540 if ((arg.flags & ~(BCH_BY_INDEX|BCH_READ_DEV)) || 541 arg.pad) 542 return -EINVAL; 543 544 mutex_lock(&c->sb_lock); 545 546 if (arg.flags & BCH_READ_DEV) { 547 ca = bch2_device_lookup(c, arg.dev, arg.flags); 548 549 if (IS_ERR(ca)) { 550 ret = PTR_ERR(ca); 551 goto err; 552 } 553 554 sb = ca->disk_sb.sb; 555 } else { 556 sb = c->disk_sb.sb; 557 } 558 559 if (vstruct_bytes(sb) > arg.size) { 560 ret = -ERANGE; 561 goto err; 562 } 563 564 if (copy_to_user((void __user *)(unsigned long)arg.sb, sb, 565 vstruct_bytes(sb))) 566 ret = -EFAULT; 567 err: 568 if (!IS_ERR_OR_NULL(ca)) 569 percpu_ref_put(&ca->ref); 570 mutex_unlock(&c->sb_lock); 571 return ret; 572 } 573 574 static long bch2_ioctl_disk_get_idx(struct bch_fs *c, 575 struct bch_ioctl_disk_get_idx arg) 576 { 577 dev_t dev = huge_decode_dev(arg.dev); 578 struct bch_dev *ca; 579 unsigned i; 580 581 if (!capable(CAP_SYS_ADMIN)) 582 return -EPERM; 583 584 if (!dev) 585 return -EINVAL; 586 587 for_each_online_member(ca, c, i) 588 if (ca->dev == dev) { 589 percpu_ref_put(&ca->io_ref); 590 return i; 591 } 592 593 return -BCH_ERR_ENOENT_dev_idx_not_found; 594 } 595 596 static long bch2_ioctl_disk_resize(struct bch_fs *c, 597 struct bch_ioctl_disk_resize arg) 598 { 599 struct bch_dev *ca; 600 int ret; 601 602 if (!capable(CAP_SYS_ADMIN)) 603 return -EPERM; 604 605 if ((arg.flags & ~BCH_BY_INDEX) || 606 arg.pad) 607 return -EINVAL; 608 609 ca = bch2_device_lookup(c, arg.dev, arg.flags); 610 if (IS_ERR(ca)) 611 return PTR_ERR(ca); 612 613 ret = bch2_dev_resize(c, ca, arg.nbuckets); 614 615 percpu_ref_put(&ca->ref); 616 return ret; 617 } 618 619 static long bch2_ioctl_disk_resize_journal(struct bch_fs *c, 620 struct bch_ioctl_disk_resize_journal arg) 621 { 622 struct bch_dev *ca; 623 int ret; 624 625 if (!capable(CAP_SYS_ADMIN)) 626 return -EPERM; 627 628 if ((arg.flags & ~BCH_BY_INDEX) || 629 arg.pad) 630 return -EINVAL; 631 632 if (arg.nbuckets > U32_MAX) 633 return -EINVAL; 634 635 ca = bch2_device_lookup(c, arg.dev, arg.flags); 636 if (IS_ERR(ca)) 637 return PTR_ERR(ca); 638 639 ret = bch2_set_nr_journal_buckets(c, ca, arg.nbuckets); 640 641 percpu_ref_put(&ca->ref); 642 return ret; 643 } 644 645 #define BCH_IOCTL(_name, _argtype) \ 646 do { \ 647 _argtype i; \ 648 \ 649 if (copy_from_user(&i, arg, sizeof(i))) \ 650 return -EFAULT; \ 651 ret = bch2_ioctl_##_name(c, i); \ 652 goto out; \ 653 } while (0) 654 655 long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg) 656 { 657 long ret; 658 659 switch (cmd) { 660 case BCH_IOCTL_QUERY_UUID: 661 return bch2_ioctl_query_uuid(c, arg); 662 case BCH_IOCTL_FS_USAGE: 663 return bch2_ioctl_fs_usage(c, arg); 664 case BCH_IOCTL_DEV_USAGE: 665 return bch2_ioctl_dev_usage(c, arg); 666 #if 0 667 case BCH_IOCTL_START: 668 BCH_IOCTL(start, struct bch_ioctl_start); 669 case BCH_IOCTL_STOP: 670 return bch2_ioctl_stop(c); 671 #endif 672 case BCH_IOCTL_READ_SUPER: 673 BCH_IOCTL(read_super, struct bch_ioctl_read_super); 674 case BCH_IOCTL_DISK_GET_IDX: 675 BCH_IOCTL(disk_get_idx, struct bch_ioctl_disk_get_idx); 676 } 677 678 if (!test_bit(BCH_FS_STARTED, &c->flags)) 679 return -EINVAL; 680 681 switch (cmd) { 682 case BCH_IOCTL_DISK_ADD: 683 BCH_IOCTL(disk_add, struct bch_ioctl_disk); 684 case BCH_IOCTL_DISK_REMOVE: 685 BCH_IOCTL(disk_remove, struct bch_ioctl_disk); 686 case BCH_IOCTL_DISK_ONLINE: 687 BCH_IOCTL(disk_online, struct bch_ioctl_disk); 688 case BCH_IOCTL_DISK_OFFLINE: 689 BCH_IOCTL(disk_offline, struct bch_ioctl_disk); 690 case BCH_IOCTL_DISK_SET_STATE: 691 BCH_IOCTL(disk_set_state, struct bch_ioctl_disk_set_state); 692 case BCH_IOCTL_DATA: 693 BCH_IOCTL(data, struct bch_ioctl_data); 694 case BCH_IOCTL_DISK_RESIZE: 695 BCH_IOCTL(disk_resize, struct bch_ioctl_disk_resize); 696 case BCH_IOCTL_DISK_RESIZE_JOURNAL: 697 BCH_IOCTL(disk_resize_journal, struct bch_ioctl_disk_resize_journal); 698 699 default: 700 return -ENOTTY; 701 } 702 out: 703 if (ret < 0) 704 ret = bch2_err_class(ret); 705 return ret; 706 } 707 708 static DEFINE_IDR(bch_chardev_minor); 709 710 static long bch2_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v) 711 { 712 unsigned minor = iminor(file_inode(filp)); 713 struct bch_fs *c = minor < U8_MAX ? idr_find(&bch_chardev_minor, minor) : NULL; 714 void __user *arg = (void __user *) v; 715 716 return c 717 ? bch2_fs_ioctl(c, cmd, arg) 718 : bch2_global_ioctl(cmd, arg); 719 } 720 721 static const struct file_operations bch_chardev_fops = { 722 .owner = THIS_MODULE, 723 .unlocked_ioctl = bch2_chardev_ioctl, 724 .open = nonseekable_open, 725 }; 726 727 static int bch_chardev_major; 728 static struct class *bch_chardev_class; 729 static struct device *bch_chardev; 730 731 void bch2_fs_chardev_exit(struct bch_fs *c) 732 { 733 if (!IS_ERR_OR_NULL(c->chardev)) 734 device_unregister(c->chardev); 735 if (c->minor >= 0) 736 idr_remove(&bch_chardev_minor, c->minor); 737 } 738 739 int bch2_fs_chardev_init(struct bch_fs *c) 740 { 741 c->minor = idr_alloc(&bch_chardev_minor, c, 0, 0, GFP_KERNEL); 742 if (c->minor < 0) 743 return c->minor; 744 745 c->chardev = device_create(bch_chardev_class, NULL, 746 MKDEV(bch_chardev_major, c->minor), c, 747 "bcachefs%u-ctl", c->minor); 748 if (IS_ERR(c->chardev)) 749 return PTR_ERR(c->chardev); 750 751 return 0; 752 } 753 754 void bch2_chardev_exit(void) 755 { 756 if (!IS_ERR_OR_NULL(bch_chardev_class)) 757 device_destroy(bch_chardev_class, 758 MKDEV(bch_chardev_major, U8_MAX)); 759 if (!IS_ERR_OR_NULL(bch_chardev_class)) 760 class_destroy(bch_chardev_class); 761 if (bch_chardev_major > 0) 762 unregister_chrdev(bch_chardev_major, "bcachefs"); 763 } 764 765 int __init bch2_chardev_init(void) 766 { 767 bch_chardev_major = register_chrdev(0, "bcachefs-ctl", &bch_chardev_fops); 768 if (bch_chardev_major < 0) 769 return bch_chardev_major; 770 771 bch_chardev_class = class_create("bcachefs"); 772 if (IS_ERR(bch_chardev_class)) 773 return PTR_ERR(bch_chardev_class); 774 775 bch_chardev = device_create(bch_chardev_class, NULL, 776 MKDEV(bch_chardev_major, U8_MAX), 777 NULL, "bcachefs-ctl"); 778 if (IS_ERR(bch_chardev)) 779 return PTR_ERR(bch_chardev); 780 781 return 0; 782 } 783 784 #endif /* NO_BCACHEFS_CHARDEV */ 785