1 #ifndef NO_BCACHEFS_CHARDEV
4 #include "bcachefs_ioctl.h"
10 #include <linux/module.h>
12 #include <linux/major.h>
13 #include <linux/cdev.h>
14 #include <linux/device.h>
15 #include <linux/ioctl.h>
16 #include <linux/uaccess.h>
17 #include <linux/slab.h>
19 /* returns with ref on ca->ref */
20 static struct bch_dev *bch2_device_lookup(struct bch_fs *c, u64 dev,
25 if (flags & BCH_BY_INDEX) {
26 if (dev >= c->sb.nr_devices)
27 return ERR_PTR(-EINVAL);
30 ca = rcu_dereference(c->devs[dev]);
32 percpu_ref_get(&ca->ref);
36 return ERR_PTR(-EINVAL);
38 struct block_device *bdev;
42 path = strndup_user((const char __user *)
43 (unsigned long) dev, PATH_MAX);
45 return ERR_CAST(path);
47 bdev = lookup_bdev(path);
50 return ERR_CAST(bdev);
52 for_each_member_device(ca, c, i)
53 if (ca->disk_sb.bdev == bdev)
56 ca = ERR_PTR(-ENOENT);
64 static long bch2_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
66 struct bch_ioctl_assemble arg;
68 u64 *user_devs = NULL;
73 if (copy_from_user(&arg, user_arg, sizeof(arg)))
76 if (arg.flags || arg.pad)
79 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
83 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
85 if (copy_from_user(user_devs, user_arg->devs,
86 sizeof(u64) * arg.nr_devs))
89 for (i = 0; i < arg.nr_devs; i++) {
90 devs[i] = strndup_user((const char __user *)(unsigned long)
99 err = bch2_fs_open(devs, arg.nr_devs, bch2_opts_empty(), NULL);
101 pr_err("Could not open filesystem: %s", err);
109 for (i = 0; i < arg.nr_devs; i++)
115 static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
117 struct bch_ioctl_incremental arg;
121 if (copy_from_user(&arg, user_arg, sizeof(arg)))
124 if (arg.flags || arg.pad)
127 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
131 err = bch2_fs_open_incremental(path);
135 pr_err("Could not register bcachefs devices: %s", err);
142 static long bch2_global_ioctl(unsigned cmd, void __user *arg)
145 case BCH_IOCTL_ASSEMBLE:
146 return bch2_ioctl_assemble(arg);
147 case BCH_IOCTL_INCREMENTAL:
148 return bch2_ioctl_incremental(arg);
154 static long bch2_ioctl_query_uuid(struct bch_fs *c,
155 struct bch_ioctl_query_uuid __user *user_arg)
157 return copy_to_user(&user_arg->uuid,
159 sizeof(c->sb.user_uuid));
162 static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start arg)
164 if (arg.flags || arg.pad)
167 return bch2_fs_start(c) ? -EIO : 0;
170 static long bch2_ioctl_stop(struct bch_fs *c)
176 static long bch2_ioctl_disk_add(struct bch_fs *c, struct bch_ioctl_disk arg)
181 if (arg.flags || arg.pad)
184 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
188 ret = bch2_dev_add(c, path);
194 static long bch2_ioctl_disk_remove(struct bch_fs *c, struct bch_ioctl_disk arg)
198 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
199 BCH_FORCE_IF_METADATA_LOST|
200 BCH_FORCE_IF_DEGRADED|
205 ca = bch2_device_lookup(c, arg.dev, arg.flags);
209 return bch2_dev_remove(c, ca, arg.flags);
212 static long bch2_ioctl_disk_online(struct bch_fs *c, struct bch_ioctl_disk arg)
217 if (arg.flags || arg.pad)
220 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
224 ret = bch2_dev_online(c, path);
229 static long bch2_ioctl_disk_offline(struct bch_fs *c, struct bch_ioctl_disk arg)
234 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
235 BCH_FORCE_IF_METADATA_LOST|
236 BCH_FORCE_IF_DEGRADED|
241 ca = bch2_device_lookup(c, arg.dev, arg.flags);
245 ret = bch2_dev_offline(c, ca, arg.flags);
246 percpu_ref_put(&ca->ref);
250 static long bch2_ioctl_disk_set_state(struct bch_fs *c,
251 struct bch_ioctl_disk_set_state arg)
256 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
257 BCH_FORCE_IF_METADATA_LOST|
258 BCH_FORCE_IF_DEGRADED|
260 arg.pad[0] || arg.pad[1] || arg.pad[2])
263 ca = bch2_device_lookup(c, arg.dev, arg.flags);
267 ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags);
269 percpu_ref_put(&ca->ref);
273 static long bch2_ioctl_disk_evacuate(struct bch_fs *c,
274 struct bch_ioctl_disk arg)
279 if ((arg.flags & ~BCH_BY_INDEX) ||
283 ca = bch2_device_lookup(c, arg.dev, arg.flags);
287 ret = bch2_dev_evacuate(c, ca);
289 percpu_ref_put(&ca->ref);
293 static long bch2_ioctl_usage(struct bch_fs *c,
294 struct bch_ioctl_usage __user *user_arg)
296 struct bch_ioctl_usage arg;
301 if (copy_from_user(&arg, user_arg, sizeof(arg)))
304 for (i = 0; i < arg.nr_devices; i++) {
305 struct bch_ioctl_dev_usage dst = { .alive = 0 };
307 ret = copy_to_user(&user_arg->devs[i], &dst, sizeof(dst));
313 struct bch_fs_usage src = bch2_fs_usage_read(c);
314 struct bch_ioctl_fs_usage dst = {
315 .capacity = c->capacity,
316 .used = bch2_fs_sectors_used(c, src),
317 .online_reserved = src.online_reserved,
320 for (i = 0; i < BCH_REPLICAS_MAX; i++) {
321 dst.persistent_reserved[i] =
322 src.s[i].persistent_reserved;
324 for (j = 0; j < S_ALLOC_NR; j++)
325 dst.sectors[s_alloc_to_data_type(j)][i] =
329 ret = copy_to_user(&user_arg->fs, &dst, sizeof(dst));
334 for_each_member_device(ca, c, i) {
335 struct bch_dev_usage src = bch2_dev_usage_read(c, ca);
336 struct bch_ioctl_dev_usage dst = {
338 .state = ca->mi.state,
339 .bucket_size = ca->mi.bucket_size,
340 .nr_buckets = ca->mi.nbuckets - ca->mi.first_bucket,
343 if (ca->dev_idx >= arg.nr_devices) {
344 percpu_ref_put(&ca->ref);
348 if (percpu_ref_tryget(&ca->io_ref)) {
349 dst.dev = huge_encode_dev(ca->disk_sb.bdev->bd_dev);
350 percpu_ref_put(&ca->io_ref);
353 for (j = 0; j < BCH_DATA_NR; j++) {
354 dst.buckets[j] = src.buckets[j];
355 dst.sectors[j] = src.sectors[j];
358 ret = copy_to_user(&user_arg->devs[i], &dst, sizeof(dst));
366 #define BCH_IOCTL(_name, _argtype) \
370 if (copy_from_user(&i, arg, sizeof(i))) \
372 return bch2_ioctl_##_name(c, i); \
375 long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
377 /* ioctls that don't require admin cap: */
379 case BCH_IOCTL_QUERY_UUID:
380 return bch2_ioctl_query_uuid(c, arg);
381 case BCH_IOCTL_USAGE:
382 return bch2_ioctl_usage(c, arg);
385 if (!capable(CAP_SYS_ADMIN))
388 /* ioctls that do require admin cap: */
390 case BCH_IOCTL_START:
391 BCH_IOCTL(start, struct bch_ioctl_start);
393 return bch2_ioctl_stop(c);
395 case BCH_IOCTL_DISK_ADD:
396 BCH_IOCTL(disk_add, struct bch_ioctl_disk);
397 case BCH_IOCTL_DISK_REMOVE:
398 BCH_IOCTL(disk_remove, struct bch_ioctl_disk);
399 case BCH_IOCTL_DISK_ONLINE:
400 BCH_IOCTL(disk_online, struct bch_ioctl_disk);
401 case BCH_IOCTL_DISK_OFFLINE:
402 BCH_IOCTL(disk_offline, struct bch_ioctl_disk);
403 case BCH_IOCTL_DISK_SET_STATE:
404 BCH_IOCTL(disk_set_state, struct bch_ioctl_disk_set_state);
405 case BCH_IOCTL_DISK_EVACUATE:
406 BCH_IOCTL(disk_evacuate, struct bch_ioctl_disk);
413 static long bch2_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
415 struct bch_fs *c = filp->private_data;
416 void __user *arg = (void __user *) v;
419 ? bch2_fs_ioctl(c, cmd, arg)
420 : bch2_global_ioctl(cmd, arg);
423 static const struct file_operations bch_chardev_fops = {
424 .owner = THIS_MODULE,
425 .unlocked_ioctl = bch2_chardev_ioctl,
426 .open = nonseekable_open,
429 static int bch_chardev_major;
430 static struct class *bch_chardev_class;
431 static struct device *bch_chardev;
432 static DEFINE_IDR(bch_chardev_minor);
434 void bch2_fs_chardev_exit(struct bch_fs *c)
436 if (!IS_ERR_OR_NULL(c->chardev))
437 device_unregister(c->chardev);
439 idr_remove(&bch_chardev_minor, c->minor);
442 int bch2_fs_chardev_init(struct bch_fs *c)
444 c->minor = idr_alloc(&bch_chardev_minor, c, 0, 0, GFP_KERNEL);
448 c->chardev = device_create(bch_chardev_class, NULL,
449 MKDEV(bch_chardev_major, c->minor), NULL,
450 "bcachefs%u-ctl", c->minor);
451 if (IS_ERR(c->chardev))
452 return PTR_ERR(c->chardev);
457 void bch2_chardev_exit(void)
459 if (!IS_ERR_OR_NULL(bch_chardev_class))
460 device_destroy(bch_chardev_class,
461 MKDEV(bch_chardev_major, 255));
462 if (!IS_ERR_OR_NULL(bch_chardev_class))
463 class_destroy(bch_chardev_class);
464 if (bch_chardev_major > 0)
465 unregister_chrdev(bch_chardev_major, "bcachefs");
468 int __init bch2_chardev_init(void)
470 bch_chardev_major = register_chrdev(0, "bcachefs-ctl", &bch_chardev_fops);
471 if (bch_chardev_major < 0)
472 return bch_chardev_major;
474 bch_chardev_class = class_create(THIS_MODULE, "bcachefs");
475 if (IS_ERR(bch_chardev_class))
476 return PTR_ERR(bch_chardev_class);
478 bch_chardev = device_create(bch_chardev_class, NULL,
479 MKDEV(bch_chardev_major, 255),
480 NULL, "bcachefs-ctl");
481 if (IS_ERR(bch_chardev))
482 return PTR_ERR(bch_chardev);
487 #endif /* NO_BCACHEFS_CHARDEV */