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 static long bch2_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
17 struct bch_ioctl_assemble arg;
19 u64 *user_devs = NULL;
24 if (copy_from_user(&arg, user_arg, sizeof(arg)))
27 if (arg.flags || arg.pad)
30 user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
34 devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
36 if (copy_from_user(user_devs, user_arg->devs,
37 sizeof(u64) * arg.nr_devs))
40 for (i = 0; i < arg.nr_devs; i++) {
41 devs[i] = strndup_user((const char __user *)(unsigned long)
50 err = bch2_fs_open(devs, arg.nr_devs, bch2_opts_empty(), NULL);
52 pr_err("Could not open filesystem: %s", err);
60 for (i = 0; i < arg.nr_devs; i++)
66 static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
68 struct bch_ioctl_incremental arg;
72 if (copy_from_user(&arg, user_arg, sizeof(arg)))
75 if (arg.flags || arg.pad)
78 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
82 err = bch2_fs_open_incremental(path);
86 pr_err("Could not register bcachefs devices: %s", err);
93 static long bch2_global_ioctl(unsigned cmd, void __user *arg)
96 case BCH_IOCTL_ASSEMBLE:
97 return bch2_ioctl_assemble(arg);
98 case BCH_IOCTL_INCREMENTAL:
99 return bch2_ioctl_incremental(arg);
105 static long bch2_ioctl_query_uuid(struct bch_fs *c,
106 struct bch_ioctl_query_uuid __user *user_arg)
108 return copy_to_user(&user_arg->uuid,
110 sizeof(c->sb.user_uuid));
113 static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start __user *user_arg)
115 struct bch_ioctl_start arg;
117 if (copy_from_user(&arg, user_arg, sizeof(arg)))
120 if (arg.flags || arg.pad)
123 return bch2_fs_start(c) ? -EIO : 0;
126 static long bch2_ioctl_stop(struct bch_fs *c)
132 /* returns with ref on ca->ref */
133 static struct bch_dev *bch2_device_lookup(struct bch_fs *c,
134 const char __user *dev)
136 struct block_device *bdev;
141 path = strndup_user(dev, PATH_MAX);
143 return ERR_PTR(-ENOMEM);
145 bdev = lookup_bdev(strim(path));
148 return ERR_CAST(bdev);
150 for_each_member_device(ca, c, i)
151 if (ca->disk_sb.bdev == bdev)
161 static struct bch_member *bch2_uuid_lookup(struct bch_fs *c, uuid_le uuid)
163 struct bch_sb_field_members *mi = bch2_sb_get_members(c->disk_sb);
166 lockdep_assert_held(&c->sb_lock);
168 for (i = 0; i < c->disk_sb->nr_devices; i++)
169 if (!memcmp(&mi->members[i].uuid, &uuid, sizeof(uuid)))
170 return &mi->members[i];
176 static long bch2_ioctl_disk_add(struct bch_fs *c,
177 struct bch_ioctl_disk __user *user_arg)
179 struct bch_ioctl_disk arg;
183 if (copy_from_user(&arg, user_arg, sizeof(arg)))
186 if (arg.flags || arg.pad)
189 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
193 ret = bch2_dev_add(c, path);
199 static long bch2_ioctl_disk_remove(struct bch_fs *c,
200 struct bch_ioctl_disk __user *user_arg)
202 struct bch_ioctl_disk arg;
205 if (copy_from_user(&arg, user_arg, sizeof(arg)))
208 ca = bch2_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
212 return bch2_dev_remove(c, ca, arg.flags);
215 static long bch2_ioctl_disk_online(struct bch_fs *c,
216 struct bch_ioctl_disk __user *user_arg)
218 struct bch_ioctl_disk arg;
222 if (copy_from_user(&arg, user_arg, sizeof(arg)))
225 if (arg.flags || arg.pad)
228 path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
232 ret = bch2_dev_online(c, path);
237 static long bch2_ioctl_disk_offline(struct bch_fs *c,
238 struct bch_ioctl_disk __user *user_arg)
240 struct bch_ioctl_disk arg;
244 if (copy_from_user(&arg, user_arg, sizeof(arg)))
250 ca = bch2_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
254 ret = bch2_dev_offline(c, ca, arg.flags);
255 percpu_ref_put(&ca->ref);
259 static long bch2_ioctl_disk_set_state(struct bch_fs *c,
260 struct bch_ioctl_disk_set_state __user *user_arg)
262 struct bch_ioctl_disk_set_state arg;
266 if (copy_from_user(&arg, user_arg, sizeof(arg)))
269 ca = bch2_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
273 ret = bch2_dev_set_state(c, ca, arg.new_state, arg.flags);
275 percpu_ref_put(&ca->ref);
279 static long bch2_ioctl_disk_evacuate(struct bch_fs *c,
280 struct bch_ioctl_disk __user *user_arg)
282 struct bch_ioctl_disk arg;
286 if (copy_from_user(&arg, user_arg, sizeof(arg)))
289 ca = bch2_device_lookup(c, (const char __user *)(unsigned long) arg.dev);
293 ret = bch2_dev_evacuate(c, ca);
295 percpu_ref_put(&ca->ref);
299 long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
301 /* ioctls that don't require admin cap: */
303 case BCH_IOCTL_QUERY_UUID:
304 return bch2_ioctl_query_uuid(c, arg);
307 if (!capable(CAP_SYS_ADMIN))
310 /* ioctls that do require admin cap: */
312 case BCH_IOCTL_START:
313 return bch2_ioctl_start(c, arg);
315 return bch2_ioctl_stop(c);
317 case BCH_IOCTL_DISK_ADD:
318 return bch2_ioctl_disk_add(c, arg);
319 case BCH_IOCTL_DISK_REMOVE:
320 return bch2_ioctl_disk_remove(c, arg);
321 case BCH_IOCTL_DISK_ONLINE:
322 return bch2_ioctl_disk_online(c, arg);
323 case BCH_IOCTL_DISK_OFFLINE:
324 return bch2_ioctl_disk_offline(c, arg);
325 case BCH_IOCTL_DISK_SET_STATE:
326 return bch2_ioctl_disk_set_state(c, arg);
327 case BCH_IOCTL_DISK_EVACUATE:
328 return bch2_ioctl_disk_evacuate(c, arg);
335 static long bch2_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
337 struct bch_fs *c = filp->private_data;
338 void __user *arg = (void __user *) v;
341 ? bch2_fs_ioctl(c, cmd, arg)
342 : bch2_global_ioctl(cmd, arg);
345 static const struct file_operations bch_chardev_fops = {
346 .owner = THIS_MODULE,
347 .unlocked_ioctl = bch2_chardev_ioctl,
348 .open = nonseekable_open,
351 static int bch_chardev_major;
352 static struct class *bch_chardev_class;
353 static struct device *bch_chardev;
354 static DEFINE_IDR(bch_chardev_minor);
356 void bch2_fs_chardev_exit(struct bch_fs *c)
358 if (!IS_ERR_OR_NULL(c->chardev))
359 device_unregister(c->chardev);
361 idr_remove(&bch_chardev_minor, c->minor);
364 int bch2_fs_chardev_init(struct bch_fs *c)
366 c->minor = idr_alloc(&bch_chardev_minor, c, 0, 0, GFP_KERNEL);
370 c->chardev = device_create(bch_chardev_class, NULL,
371 MKDEV(bch_chardev_major, c->minor), NULL,
372 "bcachefs%u-ctl", c->minor);
373 if (IS_ERR(c->chardev))
374 return PTR_ERR(c->chardev);
379 void bch2_chardev_exit(void)
381 if (!IS_ERR_OR_NULL(bch_chardev_class))
382 device_destroy(bch_chardev_class,
383 MKDEV(bch_chardev_major, 255));
384 if (!IS_ERR_OR_NULL(bch_chardev_class))
385 class_destroy(bch_chardev_class);
386 if (bch_chardev_major > 0)
387 unregister_chrdev(bch_chardev_major, "bcachefs");
390 int __init bch2_chardev_init(void)
392 bch_chardev_major = register_chrdev(0, "bcachefs-ctl", &bch_chardev_fops);
393 if (bch_chardev_major < 0)
394 return bch_chardev_major;
396 bch_chardev_class = class_create(THIS_MODULE, "bcachefs");
397 if (IS_ERR(bch_chardev_class))
398 return PTR_ERR(bch_chardev_class);
400 bch_chardev = device_create(bch_chardev_class, NULL,
401 MKDEV(bch_chardev_major, 255),
402 NULL, "bcachefs-ctl");
403 if (IS_ERR(bch_chardev))
404 return PTR_ERR(bch_chardev);