2 #include "bcachefs_ioctl.h"
6 #include <linux/module.h>
8 #include <linux/major.h>
9 #include <linux/cdev.h>
10 #include <linux/device.h>
11 #include <linux/ioctl.h>
12 #include <linux/uaccess.h>
13 #include <linux/slab.h>
15 /* returns with ref on ca->ref */
16 static struct bch_dev *bch2_device_lookup(struct bch_fs *c, u64 dev,
21 if (flags & BCH_BY_INDEX) {
22 if (dev >= c->sb.nr_devices)
23 return ERR_PTR(-EINVAL);
28 percpu_ref_get(&ca->ref);
32 return ERR_PTR(-EINVAL);
34 struct block_device *bdev;
38 path = strndup_user((const char __user *)
39 (unsigned long) dev, PATH_MAX);
41 return ERR_CAST(path);
43 bdev = lookup_bdev(path);
46 return ERR_CAST(bdev);
48 for_each_member_device(ca, c, i)
49 if (ca->disk_sb.bdev == bdev)
52 ca = ERR_PTR(-ENOENT);
60 static long bch2_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
62 struct bch_ioctl_assemble arg;
64 u64 *user_devs = NULL;
69 if (copy_from_user(&arg, user_arg, sizeof(arg)))
72 if (arg.flags || arg.pad)
75 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
79 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
81 if (copy_from_user(user_devs, arg.devs,
82 sizeof(u64) * arg.nr_devs))
85 for (i = 0; i < arg.nr_devs; i++) {
86 devs[i] = strndup_user((const char __user *)(unsigned long)
95 err = bch2_fs_open(devs, arg.nr_devs, bch2_opts_empty(), NULL);
97 pr_err("Could not open filesystem: %s", err);
105 for (i = 0; i < arg.nr_devs; i++)
111 static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
113 struct bch_ioctl_incremental arg;
117 if (copy_from_user(&arg, user_arg, sizeof(arg)))
120 if (arg.flags || arg.pad)
123 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
127 err = bch2_fs_open_incremental(path);
131 pr_err("Could not register bcachefs devices: %s", err);
138 static long bch2_global_ioctl(unsigned cmd, void __user *arg)
141 case BCH_IOCTL_ASSEMBLE:
142 return bch2_ioctl_assemble(arg);
143 case BCH_IOCTL_INCREMENTAL:
144 return bch2_ioctl_incremental(arg);
150 static long bch2_ioctl_query_uuid(struct bch_fs *c,
151 struct bch_ioctl_query_uuid __user *user_arg)
153 return copy_to_user(&user_arg->uuid,
155 sizeof(c->sb.user_uuid));
158 static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start arg)
160 if (arg.flags || arg.pad)
163 return bch2_fs_start(c) ? -EIO : 0;
166 static long bch2_ioctl_stop(struct bch_fs *c)
172 static long bch2_ioctl_disk_add(struct bch_fs *c, struct bch_ioctl_disk arg)
177 if (arg.flags || arg.pad)
180 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
184 ret = bch2_dev_add(c, path);
190 static long bch2_ioctl_disk_remove(struct bch_fs *c, struct bch_ioctl_disk arg)
194 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
195 BCH_FORCE_IF_METADATA_LOST|
196 BCH_FORCE_IF_DEGRADED|
201 ca = bch2_device_lookup(c, arg.dev, arg.flags);
205 return bch2_dev_remove(c, ca, arg.flags);
208 static long bch2_ioctl_disk_online(struct bch_fs *c, struct bch_ioctl_disk arg)
213 if (arg.flags || arg.pad)
216 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
220 ret = bch2_dev_online(c, path);
225 static long bch2_ioctl_disk_offline(struct bch_fs *c, struct bch_ioctl_disk arg)
230 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
231 BCH_FORCE_IF_METADATA_LOST|
232 BCH_FORCE_IF_DEGRADED|
237 ca = bch2_device_lookup(c, arg.dev, arg.flags);
241 ret = bch2_dev_offline(c, ca, arg.flags);
242 percpu_ref_put(&ca->ref);
246 static long bch2_ioctl_disk_set_state(struct bch_fs *c,
247 struct bch_ioctl_disk_set_state arg)
252 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
253 BCH_FORCE_IF_METADATA_LOST|
254 BCH_FORCE_IF_DEGRADED|
256 arg.pad[0] || arg.pad[1] || arg.pad[2])
259 ca = bch2_device_lookup(c, arg.dev, arg.flags);
263 ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags);
265 percpu_ref_put(&ca->ref);
269 static long bch2_ioctl_disk_evacuate(struct bch_fs *c,
270 struct bch_ioctl_disk arg)
275 if ((arg.flags & ~BCH_BY_INDEX) ||
279 ca = bch2_device_lookup(c, arg.dev, arg.flags);
283 ret = bch2_dev_evacuate(c, ca);
285 percpu_ref_put(&ca->ref);
289 #define BCH_IOCTL(_name, _argtype) \
293 if (copy_from_user(&i, arg, sizeof(i))) \
295 return bch2_ioctl_##_name(c, i); \
298 long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
300 /* ioctls that don't require admin cap: */
302 case BCH_IOCTL_QUERY_UUID:
303 return bch2_ioctl_query_uuid(c, arg);
306 if (!capable(CAP_SYS_ADMIN))
309 /* ioctls that do require admin cap: */
311 case BCH_IOCTL_START:
312 BCH_IOCTL(start, struct bch_ioctl_start);
314 return bch2_ioctl_stop(c);
316 case BCH_IOCTL_DISK_ADD:
317 BCH_IOCTL(disk_add, struct bch_ioctl_disk);
318 case BCH_IOCTL_DISK_REMOVE:
319 BCH_IOCTL(disk_remove, struct bch_ioctl_disk);
320 case BCH_IOCTL_DISK_ONLINE:
321 BCH_IOCTL(disk_online, struct bch_ioctl_disk);
322 case BCH_IOCTL_DISK_OFFLINE:
323 BCH_IOCTL(disk_offline, struct bch_ioctl_disk);
324 case BCH_IOCTL_DISK_SET_STATE:
325 BCH_IOCTL(disk_set_state, struct bch_ioctl_disk_set_state);
326 case BCH_IOCTL_DISK_EVACUATE:
327 BCH_IOCTL(disk_evacuate, struct bch_ioctl_disk);
334 static long bch2_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
336 struct bch_fs *c = filp->private_data;
337 void __user *arg = (void __user *) v;
340 ? bch2_fs_ioctl(c, cmd, arg)
341 : bch2_global_ioctl(cmd, arg);
344 static const struct file_operations bch_chardev_fops = {
345 .owner = THIS_MODULE,
346 .unlocked_ioctl = bch2_chardev_ioctl,
347 .open = nonseekable_open,
350 static int bch_chardev_major;
351 static struct class *bch_chardev_class;
352 static struct device *bch_chardev;
353 static DEFINE_IDR(bch_chardev_minor);
355 void bch2_fs_chardev_exit(struct bch_fs *c)
357 if (!IS_ERR_OR_NULL(c->chardev))
358 device_unregister(c->chardev);
360 idr_remove(&bch_chardev_minor, c->minor);
363 int bch2_fs_chardev_init(struct bch_fs *c)
365 c->minor = idr_alloc(&bch_chardev_minor, c, 0, 0, GFP_KERNEL);
369 c->chardev = device_create(bch_chardev_class, NULL,
370 MKDEV(bch_chardev_major, c->minor), NULL,
371 "bcachefs%u-ctl", c->minor);
372 if (IS_ERR(c->chardev))
373 return PTR_ERR(c->chardev);
378 void bch2_chardev_exit(void)
380 if (!IS_ERR_OR_NULL(bch_chardev_class))
381 device_destroy(bch_chardev_class,
382 MKDEV(bch_chardev_major, 255));
383 if (!IS_ERR_OR_NULL(bch_chardev_class))
384 class_destroy(bch_chardev_class);
385 if (bch_chardev_major > 0)
386 unregister_chrdev(bch_chardev_major, "bcachefs");
389 int __init bch2_chardev_init(void)
391 bch_chardev_major = register_chrdev(0, "bcachefs-ctl", &bch_chardev_fops);
392 if (bch_chardev_major < 0)
393 return bch_chardev_major;
395 bch_chardev_class = class_create(THIS_MODULE, "bcachefs");
396 if (IS_ERR(bch_chardev_class))
397 return PTR_ERR(bch_chardev_class);
399 bch_chardev = device_create(bch_chardev_class, NULL,
400 MKDEV(bch_chardev_major, 255),
401 NULL, "bcachefs-ctl");
402 if (IS_ERR(bch_chardev))
403 return PTR_ERR(bch_chardev);