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