1 #ifndef NO_BCACHEFS_CHARDEV
4 #include "bcachefs_ioctl.h"
8 #include <linux/module.h>
10 #include <linux/major.h>
11 #include <linux/cdev.h>
12 #include <linux/device.h>
13 #include <linux/ioctl.h>
14 #include <linux/uaccess.h>
15 #include <linux/slab.h>
17 /* returns with ref on ca->ref */
18 static struct bch_dev *bch2_device_lookup(struct bch_fs *c, u64 dev,
23 if (flags & BCH_BY_INDEX) {
24 if (dev >= c->sb.nr_devices)
25 return ERR_PTR(-EINVAL);
30 percpu_ref_get(&ca->ref);
34 return ERR_PTR(-EINVAL);
36 struct block_device *bdev;
40 path = strndup_user((const char __user *)
41 (unsigned long) dev, PATH_MAX);
43 return ERR_CAST(path);
45 bdev = lookup_bdev(path);
48 return ERR_CAST(bdev);
50 for_each_member_device(ca, c, i)
51 if (ca->disk_sb.bdev == bdev)
54 ca = ERR_PTR(-ENOENT);
62 static long bch2_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
64 struct bch_ioctl_assemble arg;
66 u64 *user_devs = NULL;
71 if (copy_from_user(&arg, user_arg, sizeof(arg)))
74 if (arg.flags || arg.pad)
77 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
81 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
83 if (copy_from_user(user_devs, arg.devs,
84 sizeof(u64) * arg.nr_devs))
87 for (i = 0; i < arg.nr_devs; i++) {
88 devs[i] = strndup_user((const char __user *)(unsigned long)
97 err = bch2_fs_open(devs, arg.nr_devs, bch2_opts_empty(), NULL);
99 pr_err("Could not open filesystem: %s", err);
107 for (i = 0; i < arg.nr_devs; i++)
113 static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
115 struct bch_ioctl_incremental arg;
119 if (copy_from_user(&arg, user_arg, sizeof(arg)))
122 if (arg.flags || arg.pad)
125 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
129 err = bch2_fs_open_incremental(path);
133 pr_err("Could not register bcachefs devices: %s", err);
140 static long bch2_global_ioctl(unsigned cmd, void __user *arg)
143 case BCH_IOCTL_ASSEMBLE:
144 return bch2_ioctl_assemble(arg);
145 case BCH_IOCTL_INCREMENTAL:
146 return bch2_ioctl_incremental(arg);
152 static long bch2_ioctl_query_uuid(struct bch_fs *c,
153 struct bch_ioctl_query_uuid __user *user_arg)
155 return copy_to_user(&user_arg->uuid,
157 sizeof(c->sb.user_uuid));
160 static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start arg)
162 if (arg.flags || arg.pad)
165 return bch2_fs_start(c) ? -EIO : 0;
168 static long bch2_ioctl_stop(struct bch_fs *c)
174 static long bch2_ioctl_disk_add(struct bch_fs *c, struct bch_ioctl_disk arg)
179 if (arg.flags || arg.pad)
182 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
186 ret = bch2_dev_add(c, path);
192 static long bch2_ioctl_disk_remove(struct bch_fs *c, struct bch_ioctl_disk arg)
196 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
197 BCH_FORCE_IF_METADATA_LOST|
198 BCH_FORCE_IF_DEGRADED|
203 ca = bch2_device_lookup(c, arg.dev, arg.flags);
207 return bch2_dev_remove(c, ca, arg.flags);
210 static long bch2_ioctl_disk_online(struct bch_fs *c, struct bch_ioctl_disk arg)
215 if (arg.flags || arg.pad)
218 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
222 ret = bch2_dev_online(c, path);
227 static long bch2_ioctl_disk_offline(struct bch_fs *c, struct bch_ioctl_disk arg)
232 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
233 BCH_FORCE_IF_METADATA_LOST|
234 BCH_FORCE_IF_DEGRADED|
239 ca = bch2_device_lookup(c, arg.dev, arg.flags);
243 ret = bch2_dev_offline(c, ca, arg.flags);
244 percpu_ref_put(&ca->ref);
248 static long bch2_ioctl_disk_set_state(struct bch_fs *c,
249 struct bch_ioctl_disk_set_state arg)
254 if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
255 BCH_FORCE_IF_METADATA_LOST|
256 BCH_FORCE_IF_DEGRADED|
258 arg.pad[0] || arg.pad[1] || arg.pad[2])
261 ca = bch2_device_lookup(c, arg.dev, arg.flags);
265 ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags);
267 percpu_ref_put(&ca->ref);
271 static long bch2_ioctl_disk_evacuate(struct bch_fs *c,
272 struct bch_ioctl_disk arg)
277 if ((arg.flags & ~BCH_BY_INDEX) ||
281 ca = bch2_device_lookup(c, arg.dev, arg.flags);
285 ret = bch2_dev_evacuate(c, ca);
287 percpu_ref_put(&ca->ref);
291 #define BCH_IOCTL(_name, _argtype) \
295 if (copy_from_user(&i, arg, sizeof(i))) \
297 return bch2_ioctl_##_name(c, i); \
300 long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
302 /* ioctls that don't require admin cap: */
304 case BCH_IOCTL_QUERY_UUID:
305 return bch2_ioctl_query_uuid(c, arg);
308 if (!capable(CAP_SYS_ADMIN))
311 /* ioctls that do require admin cap: */
313 case BCH_IOCTL_START:
314 BCH_IOCTL(start, struct bch_ioctl_start);
316 return bch2_ioctl_stop(c);
318 case BCH_IOCTL_DISK_ADD:
319 BCH_IOCTL(disk_add, struct bch_ioctl_disk);
320 case BCH_IOCTL_DISK_REMOVE:
321 BCH_IOCTL(disk_remove, struct bch_ioctl_disk);
322 case BCH_IOCTL_DISK_ONLINE:
323 BCH_IOCTL(disk_online, struct bch_ioctl_disk);
324 case BCH_IOCTL_DISK_OFFLINE:
325 BCH_IOCTL(disk_offline, struct bch_ioctl_disk);
326 case BCH_IOCTL_DISK_SET_STATE:
327 BCH_IOCTL(disk_set_state, struct bch_ioctl_disk_set_state);
328 case BCH_IOCTL_DISK_EVACUATE:
329 BCH_IOCTL(disk_evacuate, struct bch_ioctl_disk);
336 static long bch2_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
338 struct bch_fs *c = filp->private_data;
339 void __user *arg = (void __user *) v;
342 ? bch2_fs_ioctl(c, cmd, arg)
343 : bch2_global_ioctl(cmd, arg);
346 static const struct file_operations bch_chardev_fops = {
347 .owner = THIS_MODULE,
348 .unlocked_ioctl = bch2_chardev_ioctl,
349 .open = nonseekable_open,
352 static int bch_chardev_major;
353 static struct class *bch_chardev_class;
354 static struct device *bch_chardev;
355 static DEFINE_IDR(bch_chardev_minor);
357 void bch2_fs_chardev_exit(struct bch_fs *c)
359 if (!IS_ERR_OR_NULL(c->chardev))
360 device_unregister(c->chardev);
362 idr_remove(&bch_chardev_minor, c->minor);
365 int bch2_fs_chardev_init(struct bch_fs *c)
367 c->minor = idr_alloc(&bch_chardev_minor, c, 0, 0, GFP_KERNEL);
371 c->chardev = device_create(bch_chardev_class, NULL,
372 MKDEV(bch_chardev_major, c->minor), NULL,
373 "bcachefs%u-ctl", c->minor);
374 if (IS_ERR(c->chardev))
375 return PTR_ERR(c->chardev);
380 void bch2_chardev_exit(void)
382 if (!IS_ERR_OR_NULL(bch_chardev_class))
383 device_destroy(bch_chardev_class,
384 MKDEV(bch_chardev_major, 255));
385 if (!IS_ERR_OR_NULL(bch_chardev_class))
386 class_destroy(bch_chardev_class);
387 if (bch_chardev_major > 0)
388 unregister_chrdev(bch_chardev_major, "bcachefs");
391 int __init bch2_chardev_init(void)
393 bch_chardev_major = register_chrdev(0, "bcachefs-ctl", &bch_chardev_fops);
394 if (bch_chardev_major < 0)
395 return bch_chardev_major;
397 bch_chardev_class = class_create(THIS_MODULE, "bcachefs");
398 if (IS_ERR(bch_chardev_class))
399 return PTR_ERR(bch_chardev_class);
401 bch_chardev = device_create(bch_chardev_class, NULL,
402 MKDEV(bch_chardev_major, 255),
403 NULL, "bcachefs-ctl");
404 if (IS_ERR(bch_chardev))
405 return PTR_ERR(bch_chardev);
410 #endif /* NO_BCACHEFS_CHARDEV */