]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/chardev.c
Merge remote-tracking branch 'amoz/devel'
[bcachefs-tools-debian] / libbcachefs / chardev.c
1 // SPDX-License-Identifier: GPL-2.0
2 #ifndef NO_BCACHEFS_CHARDEV
3
4 #include "bcachefs.h"
5 #include "bcachefs_ioctl.h"
6 #include "buckets.h"
7 #include "chardev.h"
8 #include "journal.h"
9 #include "move.h"
10 #include "replicas.h"
11 #include "super.h"
12 #include "super-io.h"
13
14 #include <linux/anon_inodes.h>
15 #include <linux/cdev.h>
16 #include <linux/device.h>
17 #include <linux/file.h>
18 #include <linux/fs.h>
19 #include <linux/ioctl.h>
20 #include <linux/kthread.h>
21 #include <linux/major.h>
22 #include <linux/sched/task.h>
23 #include <linux/slab.h>
24 #include <linux/uaccess.h>
25
26 __must_check
27 static int copy_to_user_errcode(void __user *to, const void *from, unsigned long n)
28 {
29         return copy_to_user(to, from, n) ? -EFAULT : 0;
30 }
31
32 struct thread_with_file {
33         struct task_struct      *task;
34         int                     ret;
35 };
36
37 static void thread_with_file_exit(struct thread_with_file *thr)
38 {
39         if (thr->task) {
40                 kthread_stop(thr->task);
41                 put_task_struct(thr->task);
42         }
43 }
44
45 static int run_thread_with_file(struct thread_with_file *thr,
46                                 const struct file_operations *fops,
47                                 int (*fn)(void *), const char *fmt, ...)
48 {
49         va_list args;
50         struct file *file = NULL;
51         int ret, fd = -1;
52         struct printbuf name = PRINTBUF;
53         unsigned fd_flags = O_RDONLY|O_CLOEXEC|O_NONBLOCK;
54
55         va_start(args, fmt);
56         prt_vprintf(&name, fmt, args);
57         va_end(args);
58
59         thr->ret = 0;
60         thr->task = kthread_create(fn, thr, name.buf);
61         ret = PTR_ERR_OR_ZERO(thr->task);
62         if (ret)
63                 goto err;
64
65         ret = get_unused_fd_flags(fd_flags);
66         if (ret < 0)
67                 goto err_stop_task;
68         fd = ret;
69
70         file = anon_inode_getfile(name.buf, fops, thr, fd_flags);
71         ret = PTR_ERR_OR_ZERO(file);
72         if (ret)
73                 goto err_put_fd;
74
75         fd_install(fd, file);
76         get_task_struct(thr->task);
77         wake_up_process(thr->task);
78         printbuf_exit(&name);
79         return fd;
80 err_put_fd:
81         put_unused_fd(fd);
82 err_stop_task:
83         kthread_stop(thr->task);
84 err:
85         printbuf_exit(&name);
86         return ret;
87 }
88
89 /* returns with ref on ca->ref */
90 static struct bch_dev *bch2_device_lookup(struct bch_fs *c, u64 dev,
91                                           unsigned flags)
92 {
93         struct bch_dev *ca;
94
95         if (flags & BCH_BY_INDEX) {
96                 if (dev >= c->sb.nr_devices)
97                         return ERR_PTR(-EINVAL);
98
99                 rcu_read_lock();
100                 ca = rcu_dereference(c->devs[dev]);
101                 if (ca)
102                         percpu_ref_get(&ca->ref);
103                 rcu_read_unlock();
104
105                 if (!ca)
106                         return ERR_PTR(-EINVAL);
107         } else {
108                 char *path;
109
110                 path = strndup_user((const char __user *)
111                                     (unsigned long) dev, PATH_MAX);
112                 if (IS_ERR(path))
113                         return ERR_CAST(path);
114
115                 ca = bch2_dev_lookup(c, path);
116                 kfree(path);
117         }
118
119         return ca;
120 }
121
122 #if 0
123 static long bch2_ioctl_assemble(struct bch_ioctl_assemble __user *user_arg)
124 {
125         struct bch_ioctl_assemble arg;
126         struct bch_fs *c;
127         u64 *user_devs = NULL;
128         char **devs = NULL;
129         unsigned i;
130         int ret = -EFAULT;
131
132         if (copy_from_user(&arg, user_arg, sizeof(arg)))
133                 return -EFAULT;
134
135         if (arg.flags || arg.pad)
136                 return -EINVAL;
137
138         user_devs = kmalloc_array(arg.nr_devs, sizeof(u64), GFP_KERNEL);
139         if (!user_devs)
140                 return -ENOMEM;
141
142         devs = kcalloc(arg.nr_devs, sizeof(char *), GFP_KERNEL);
143
144         if (copy_from_user(user_devs, user_arg->devs,
145                            sizeof(u64) * arg.nr_devs))
146                 goto err;
147
148         for (i = 0; i < arg.nr_devs; i++) {
149                 devs[i] = strndup_user((const char __user *)(unsigned long)
150                                        user_devs[i],
151                                        PATH_MAX);
152                 ret= PTR_ERR_OR_ZERO(devs[i]);
153                 if (ret)
154                         goto err;
155         }
156
157         c = bch2_fs_open(devs, arg.nr_devs, bch2_opts_empty());
158         ret = PTR_ERR_OR_ZERO(c);
159         if (!ret)
160                 closure_put(&c->cl);
161 err:
162         if (devs)
163                 for (i = 0; i < arg.nr_devs; i++)
164                         kfree(devs[i]);
165         kfree(devs);
166         return ret;
167 }
168
169 static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg)
170 {
171         struct bch_ioctl_incremental arg;
172         const char *err;
173         char *path;
174
175         if (copy_from_user(&arg, user_arg, sizeof(arg)))
176                 return -EFAULT;
177
178         if (arg.flags || arg.pad)
179                 return -EINVAL;
180
181         path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
182         ret = PTR_ERR_OR_ZERO(path);
183         if (ret)
184                 return ret;
185
186         err = bch2_fs_open_incremental(path);
187         kfree(path);
188
189         if (err) {
190                 pr_err("Could not register bcachefs devices: %s", err);
191                 return -EINVAL;
192         }
193
194         return 0;
195 }
196 #endif
197
198 struct fsck_thread {
199         struct thread_with_file thr;
200         struct printbuf         buf;
201         struct bch_fs           *c;
202         char                    **devs;
203         size_t                  nr_devs;
204         struct bch_opts         opts;
205
206         struct log_output       output;
207         DARRAY(char)            output2;
208 };
209
210 static void bch2_fsck_thread_free(struct fsck_thread *thr)
211 {
212         thread_with_file_exit(&thr->thr);
213         if (thr->devs)
214                 for (size_t i = 0; i < thr->nr_devs; i++)
215                         kfree(thr->devs[i]);
216         darray_exit(&thr->output2);
217         printbuf_exit(&thr->output.buf);
218         kfree(thr->devs);
219         kfree(thr);
220 }
221
222 static int bch2_fsck_thread_release(struct inode *inode, struct file *file)
223 {
224         struct fsck_thread *thr = container_of(file->private_data, struct fsck_thread, thr);
225
226         bch2_fsck_thread_free(thr);
227         return 0;
228 }
229
230 static ssize_t bch2_fsck_thread_read(struct file *file, char __user *buf,
231                                      size_t len, loff_t *ppos)
232 {
233         struct fsck_thread *thr = container_of(file->private_data, struct fsck_thread, thr);
234         size_t copied = 0, b;
235         int ret = 0;
236
237         ret = wait_event_interruptible(thr->output.wait,
238                         thr->output.buf.pos || thr->output2.nr);
239         if (ret)
240                 return ret;
241
242         while (len) {
243                 ret = darray_make_room(&thr->output2, thr->output.buf.pos);
244                 if (ret)
245                         break;
246
247                 spin_lock_irq(&thr->output.lock);
248                 b = min_t(size_t, darray_room(thr->output2), thr->output.buf.pos);
249
250                 memcpy(&darray_top(thr->output2), thr->output.buf.buf, b);
251                 memmove(thr->output.buf.buf,
252                         thr->output.buf.buf + b,
253                         thr->output.buf.pos - b);
254
255                 thr->output2.nr += b;
256                 thr->output.buf.pos -= b;
257                 spin_unlock_irq(&thr->output.lock);
258
259                 b = min(len, thr->output2.nr);
260                 if (!b)
261                         break;
262
263                 b -= copy_to_user(buf, thr->output2.data, b);
264                 if (!b) {
265                         ret = -EFAULT;
266                         break;
267                 }
268
269                 copied  += b;
270                 buf     += b;
271                 len     -= b;
272
273                 memmove(thr->output2.data,
274                         thr->output2.data + b,
275                         thr->output2.nr - b);
276                 thr->output2.nr -= b;
277         }
278
279         return copied ?: ret;
280 }
281
282 static const struct file_operations fsck_thread_ops = {
283         .release        = bch2_fsck_thread_release,
284         .read           = bch2_fsck_thread_read,
285         .llseek         = no_llseek,
286 };
287
288 static int bch2_fsck_offline_thread_fn(void *arg)
289 {
290         struct fsck_thread *thr = container_of(arg, struct fsck_thread, thr);
291         struct bch_fs *c = bch2_fs_open(thr->devs, thr->nr_devs, thr->opts);
292
293         thr->thr.ret = PTR_ERR_OR_ZERO(c);
294         if (!thr->thr.ret)
295                 bch2_fs_stop(c);
296         return 0;
297 }
298
299 static long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *user_arg)
300 {
301         struct bch_ioctl_fsck_offline arg;
302         struct fsck_thread *thr = NULL;
303         u64 *devs = NULL;
304         long ret = 0;
305
306         if (copy_from_user(&arg, user_arg, sizeof(arg)))
307                 return -EFAULT;
308
309         if (arg.flags)
310                 return -EINVAL;
311
312         if (!(devs = kcalloc(arg.nr_devs, sizeof(*devs), GFP_KERNEL)) ||
313             !(thr = kzalloc(sizeof(*thr), GFP_KERNEL)) ||
314             !(thr->devs = kcalloc(arg.nr_devs, sizeof(*thr->devs), GFP_KERNEL))) {
315                 ret = -ENOMEM;
316                 goto err;
317         }
318
319         thr->nr_devs = arg.nr_devs;
320         thr->output.buf = PRINTBUF;
321         thr->output.buf.atomic++;
322         spin_lock_init(&thr->output.lock);
323         init_waitqueue_head(&thr->output.wait);
324         darray_init(&thr->output2);
325
326         if (copy_from_user(devs, &user_arg->devs[0], sizeof(user_arg->devs[0]) * arg.nr_devs)) {
327                 ret = -EINVAL;
328                 goto err;
329         }
330
331         for (size_t i = 0; i < arg.nr_devs; i++) {
332                 thr->devs[i] = strndup_user((char __user *)(unsigned long) devs[i], PATH_MAX);
333                 ret = PTR_ERR_OR_ZERO(thr->devs[i]);
334                 if (ret)
335                         goto err;
336         }
337
338         if (arg.opts) {
339                 char *optstr = strndup_user((char __user *)(unsigned long) arg.opts, 1 << 16);
340
341                 ret =   PTR_ERR_OR_ZERO(optstr) ?:
342                         bch2_parse_mount_opts(NULL, &thr->opts, optstr);
343                 kfree(optstr);
344
345                 if (ret)
346                         goto err;
347         }
348
349         opt_set(thr->opts, log_output, (u64)(unsigned long)&thr->output);
350
351         ret = run_thread_with_file(&thr->thr,
352                                    &fsck_thread_ops,
353                                    bch2_fsck_offline_thread_fn,
354                                    "bch-fsck");
355 err:
356         if (ret < 0) {
357                 if (thr)
358                         bch2_fsck_thread_free(thr);
359                 pr_err("ret %s", bch2_err_str(ret));
360         }
361         kfree(devs);
362         return ret;
363 }
364
365 static long bch2_global_ioctl(unsigned cmd, void __user *arg)
366 {
367         long ret;
368
369         switch (cmd) {
370 #if 0
371         case BCH_IOCTL_ASSEMBLE:
372                 return bch2_ioctl_assemble(arg);
373         case BCH_IOCTL_INCREMENTAL:
374                 return bch2_ioctl_incremental(arg);
375 #endif
376         case BCH_IOCTL_FSCK_OFFLINE: {
377                 ret = bch2_ioctl_fsck_offline(arg);
378                 break;
379         }
380         default:
381                 ret = -ENOTTY;
382                 break;
383         }
384
385         if (ret < 0)
386                 ret = bch2_err_class(ret);
387         return ret;
388 }
389
390 static long bch2_ioctl_query_uuid(struct bch_fs *c,
391                         struct bch_ioctl_query_uuid __user *user_arg)
392 {
393         return copy_to_user_errcode(&user_arg->uuid, &c->sb.user_uuid,
394                                     sizeof(c->sb.user_uuid));
395 }
396
397 #if 0
398 static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start arg)
399 {
400         if (!capable(CAP_SYS_ADMIN))
401                 return -EPERM;
402
403         if (arg.flags || arg.pad)
404                 return -EINVAL;
405
406         return bch2_fs_start(c);
407 }
408
409 static long bch2_ioctl_stop(struct bch_fs *c)
410 {
411         if (!capable(CAP_SYS_ADMIN))
412                 return -EPERM;
413
414         bch2_fs_stop(c);
415         return 0;
416 }
417 #endif
418
419 static long bch2_ioctl_disk_add(struct bch_fs *c, struct bch_ioctl_disk arg)
420 {
421         char *path;
422         int ret;
423
424         if (!capable(CAP_SYS_ADMIN))
425                 return -EPERM;
426
427         if (arg.flags || arg.pad)
428                 return -EINVAL;
429
430         path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
431         ret = PTR_ERR_OR_ZERO(path);
432         if (ret)
433                 return ret;
434
435         ret = bch2_dev_add(c, path);
436         kfree(path);
437
438         return ret;
439 }
440
441 static long bch2_ioctl_disk_remove(struct bch_fs *c, struct bch_ioctl_disk arg)
442 {
443         struct bch_dev *ca;
444
445         if (!capable(CAP_SYS_ADMIN))
446                 return -EPERM;
447
448         if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
449                            BCH_FORCE_IF_METADATA_LOST|
450                            BCH_FORCE_IF_DEGRADED|
451                            BCH_BY_INDEX)) ||
452             arg.pad)
453                 return -EINVAL;
454
455         ca = bch2_device_lookup(c, arg.dev, arg.flags);
456         if (IS_ERR(ca))
457                 return PTR_ERR(ca);
458
459         return bch2_dev_remove(c, ca, arg.flags);
460 }
461
462 static long bch2_ioctl_disk_online(struct bch_fs *c, struct bch_ioctl_disk arg)
463 {
464         char *path;
465         int ret;
466
467         if (!capable(CAP_SYS_ADMIN))
468                 return -EPERM;
469
470         if (arg.flags || arg.pad)
471                 return -EINVAL;
472
473         path = strndup_user((const char __user *)(unsigned long) arg.dev, PATH_MAX);
474         ret = PTR_ERR_OR_ZERO(path);
475         if (ret)
476                 return ret;
477
478         ret = bch2_dev_online(c, path);
479         kfree(path);
480         return ret;
481 }
482
483 static long bch2_ioctl_disk_offline(struct bch_fs *c, struct bch_ioctl_disk arg)
484 {
485         struct bch_dev *ca;
486         int ret;
487
488         if (!capable(CAP_SYS_ADMIN))
489                 return -EPERM;
490
491         if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
492                            BCH_FORCE_IF_METADATA_LOST|
493                            BCH_FORCE_IF_DEGRADED|
494                            BCH_BY_INDEX)) ||
495             arg.pad)
496                 return -EINVAL;
497
498         ca = bch2_device_lookup(c, arg.dev, arg.flags);
499         if (IS_ERR(ca))
500                 return PTR_ERR(ca);
501
502         ret = bch2_dev_offline(c, ca, arg.flags);
503         percpu_ref_put(&ca->ref);
504         return ret;
505 }
506
507 static long bch2_ioctl_disk_set_state(struct bch_fs *c,
508                         struct bch_ioctl_disk_set_state arg)
509 {
510         struct bch_dev *ca;
511         int ret;
512
513         if (!capable(CAP_SYS_ADMIN))
514                 return -EPERM;
515
516         if ((arg.flags & ~(BCH_FORCE_IF_DATA_LOST|
517                            BCH_FORCE_IF_METADATA_LOST|
518                            BCH_FORCE_IF_DEGRADED|
519                            BCH_BY_INDEX)) ||
520             arg.pad[0] || arg.pad[1] || arg.pad[2] ||
521             arg.new_state >= BCH_MEMBER_STATE_NR)
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_set_state(c, ca, arg.new_state, arg.flags);
529         if (ret)
530                 bch_err(c, "Error setting device state: %s", bch2_err_str(ret));
531
532         percpu_ref_put(&ca->ref);
533         return ret;
534 }
535
536 struct bch_data_ctx {
537         struct thread_with_file         thr;
538
539         struct bch_fs                   *c;
540         struct bch_ioctl_data           arg;
541         struct bch_move_stats           stats;
542 };
543
544 static int bch2_data_thread(void *arg)
545 {
546         struct bch_data_ctx *ctx = container_of(arg, struct bch_data_ctx, thr);
547
548         ctx->thr.ret = bch2_data_job(ctx->c, &ctx->stats, ctx->arg);
549         ctx->stats.data_type = U8_MAX;
550         return 0;
551 }
552
553 static int bch2_data_job_release(struct inode *inode, struct file *file)
554 {
555         struct bch_data_ctx *ctx = container_of(file->private_data, struct bch_data_ctx, thr);
556
557         thread_with_file_exit(&ctx->thr);
558         kfree(ctx);
559         return 0;
560 }
561
562 static ssize_t bch2_data_job_read(struct file *file, char __user *buf,
563                                   size_t len, loff_t *ppos)
564 {
565         struct bch_data_ctx *ctx = container_of(file->private_data, struct bch_data_ctx, thr);
566         struct bch_fs *c = ctx->c;
567         struct bch_ioctl_data_event e = {
568                 .type                   = BCH_DATA_EVENT_PROGRESS,
569                 .p.data_type            = ctx->stats.data_type,
570                 .p.btree_id             = ctx->stats.pos.btree,
571                 .p.pos                  = ctx->stats.pos.pos,
572                 .p.sectors_done         = atomic64_read(&ctx->stats.sectors_seen),
573                 .p.sectors_total        = bch2_fs_usage_read_short(c).used,
574         };
575
576         if (len < sizeof(e))
577                 return -EINVAL;
578
579         return copy_to_user_errcode(buf, &e, sizeof(e)) ?: sizeof(e);
580 }
581
582 static const struct file_operations bcachefs_data_ops = {
583         .release        = bch2_data_job_release,
584         .read           = bch2_data_job_read,
585         .llseek         = no_llseek,
586 };
587
588 static long bch2_ioctl_data(struct bch_fs *c,
589                             struct bch_ioctl_data arg)
590 {
591         struct bch_data_ctx *ctx;
592         int ret;
593
594         if (!capable(CAP_SYS_ADMIN))
595                 return -EPERM;
596
597         if (arg.op >= BCH_DATA_OP_NR || arg.flags)
598                 return -EINVAL;
599
600         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
601         if (!ctx)
602                 return -ENOMEM;
603
604         ctx->c = c;
605         ctx->arg = arg;
606
607         ret = run_thread_with_file(&ctx->thr,
608                                    &bcachefs_data_ops,
609                                    bch2_data_thread,
610                                    "bch-data/%s", c->name);
611         if (ret < 0)
612                 kfree(ctx);
613         return ret;
614 }
615
616 static long bch2_ioctl_fs_usage(struct bch_fs *c,
617                                 struct bch_ioctl_fs_usage __user *user_arg)
618 {
619         struct bch_ioctl_fs_usage *arg = NULL;
620         struct bch_replicas_usage *dst_e, *dst_end;
621         struct bch_fs_usage_online *src;
622         u32 replica_entries_bytes;
623         unsigned i;
624         int ret = 0;
625
626         if (!test_bit(BCH_FS_started, &c->flags))
627                 return -EINVAL;
628
629         if (get_user(replica_entries_bytes, &user_arg->replica_entries_bytes))
630                 return -EFAULT;
631
632         arg = kzalloc(size_add(sizeof(*arg), replica_entries_bytes), GFP_KERNEL);
633         if (!arg)
634                 return -ENOMEM;
635
636         src = bch2_fs_usage_read(c);
637         if (!src) {
638                 ret = -ENOMEM;
639                 goto err;
640         }
641
642         arg->capacity           = c->capacity;
643         arg->used               = bch2_fs_sectors_used(c, src);
644         arg->online_reserved    = src->online_reserved;
645
646         for (i = 0; i < BCH_REPLICAS_MAX; i++)
647                 arg->persistent_reserved[i] = src->u.persistent_reserved[i];
648
649         dst_e   = arg->replicas;
650         dst_end = (void *) arg->replicas + replica_entries_bytes;
651
652         for (i = 0; i < c->replicas.nr; i++) {
653                 struct bch_replicas_entry_v1 *src_e =
654                         cpu_replicas_entry(&c->replicas, i);
655
656                 /* check that we have enough space for one replicas entry */
657                 if (dst_e + 1 > dst_end) {
658                         ret = -ERANGE;
659                         break;
660                 }
661
662                 dst_e->sectors          = src->u.replicas[i];
663                 dst_e->r                = *src_e;
664
665                 /* recheck after setting nr_devs: */
666                 if (replicas_usage_next(dst_e) > dst_end) {
667                         ret = -ERANGE;
668                         break;
669                 }
670
671                 memcpy(dst_e->r.devs, src_e->devs, src_e->nr_devs);
672
673                 dst_e = replicas_usage_next(dst_e);
674         }
675
676         arg->replica_entries_bytes = (void *) dst_e - (void *) arg->replicas;
677
678         percpu_up_read(&c->mark_lock);
679         kfree(src);
680
681         if (ret)
682                 goto err;
683
684         ret = copy_to_user_errcode(user_arg, arg,
685                         sizeof(*arg) + arg->replica_entries_bytes);
686 err:
687         kfree(arg);
688         return ret;
689 }
690
691 /* obsolete, didn't allow for new data types: */
692 static long bch2_ioctl_dev_usage(struct bch_fs *c,
693                                  struct bch_ioctl_dev_usage __user *user_arg)
694 {
695         struct bch_ioctl_dev_usage arg;
696         struct bch_dev_usage src;
697         struct bch_dev *ca;
698         unsigned i;
699
700         if (!test_bit(BCH_FS_started, &c->flags))
701                 return -EINVAL;
702
703         if (copy_from_user(&arg, user_arg, sizeof(arg)))
704                 return -EFAULT;
705
706         if ((arg.flags & ~BCH_BY_INDEX) ||
707             arg.pad[0] ||
708             arg.pad[1] ||
709             arg.pad[2])
710                 return -EINVAL;
711
712         ca = bch2_device_lookup(c, arg.dev, arg.flags);
713         if (IS_ERR(ca))
714                 return PTR_ERR(ca);
715
716         src = bch2_dev_usage_read(ca);
717
718         arg.state               = ca->mi.state;
719         arg.bucket_size         = ca->mi.bucket_size;
720         arg.nr_buckets          = ca->mi.nbuckets - ca->mi.first_bucket;
721
722         for (i = 0; i < BCH_DATA_NR; i++) {
723                 arg.d[i].buckets        = src.d[i].buckets;
724                 arg.d[i].sectors        = src.d[i].sectors;
725                 arg.d[i].fragmented     = src.d[i].fragmented;
726         }
727
728         percpu_ref_put(&ca->ref);
729
730         return copy_to_user_errcode(user_arg, &arg, sizeof(arg));
731 }
732
733 static long bch2_ioctl_dev_usage_v2(struct bch_fs *c,
734                                  struct bch_ioctl_dev_usage_v2 __user *user_arg)
735 {
736         struct bch_ioctl_dev_usage_v2 arg;
737         struct bch_dev_usage src;
738         struct bch_dev *ca;
739         int ret = 0;
740
741         if (!test_bit(BCH_FS_started, &c->flags))
742                 return -EINVAL;
743
744         if (copy_from_user(&arg, user_arg, sizeof(arg)))
745                 return -EFAULT;
746
747         if ((arg.flags & ~BCH_BY_INDEX) ||
748             arg.pad[0] ||
749             arg.pad[1] ||
750             arg.pad[2])
751                 return -EINVAL;
752
753         ca = bch2_device_lookup(c, arg.dev, arg.flags);
754         if (IS_ERR(ca))
755                 return PTR_ERR(ca);
756
757         src = bch2_dev_usage_read(ca);
758
759         arg.state               = ca->mi.state;
760         arg.bucket_size         = ca->mi.bucket_size;
761         arg.nr_data_types       = min(arg.nr_data_types, BCH_DATA_NR);
762         arg.nr_buckets          = ca->mi.nbuckets - ca->mi.first_bucket;
763
764         ret = copy_to_user_errcode(user_arg, &arg, sizeof(arg));
765         if (ret)
766                 goto err;
767
768         for (unsigned i = 0; i < arg.nr_data_types; i++) {
769                 struct bch_ioctl_dev_usage_type t = {
770                         .buckets        = src.d[i].buckets,
771                         .sectors        = src.d[i].sectors,
772                         .fragmented     = src.d[i].fragmented,
773                 };
774
775                 ret = copy_to_user_errcode(&user_arg->d[i], &t, sizeof(t));
776                 if (ret)
777                         goto err;
778         }
779 err:
780         percpu_ref_put(&ca->ref);
781         return ret;
782 }
783
784 static long bch2_ioctl_read_super(struct bch_fs *c,
785                                   struct bch_ioctl_read_super arg)
786 {
787         struct bch_dev *ca = NULL;
788         struct bch_sb *sb;
789         int ret = 0;
790
791         if (!capable(CAP_SYS_ADMIN))
792                 return -EPERM;
793
794         if ((arg.flags & ~(BCH_BY_INDEX|BCH_READ_DEV)) ||
795             arg.pad)
796                 return -EINVAL;
797
798         mutex_lock(&c->sb_lock);
799
800         if (arg.flags & BCH_READ_DEV) {
801                 ca = bch2_device_lookup(c, arg.dev, arg.flags);
802
803                 if (IS_ERR(ca)) {
804                         ret = PTR_ERR(ca);
805                         goto err;
806                 }
807
808                 sb = ca->disk_sb.sb;
809         } else {
810                 sb = c->disk_sb.sb;
811         }
812
813         if (vstruct_bytes(sb) > arg.size) {
814                 ret = -ERANGE;
815                 goto err;
816         }
817
818         ret = copy_to_user_errcode((void __user *)(unsigned long)arg.sb, sb,
819                                    vstruct_bytes(sb));
820 err:
821         if (!IS_ERR_OR_NULL(ca))
822                 percpu_ref_put(&ca->ref);
823         mutex_unlock(&c->sb_lock);
824         return ret;
825 }
826
827 static long bch2_ioctl_disk_get_idx(struct bch_fs *c,
828                                     struct bch_ioctl_disk_get_idx arg)
829 {
830         dev_t dev = huge_decode_dev(arg.dev);
831         struct bch_dev *ca;
832         unsigned i;
833
834         if (!capable(CAP_SYS_ADMIN))
835                 return -EPERM;
836
837         if (!dev)
838                 return -EINVAL;
839
840         for_each_online_member(ca, c, i)
841                 if (ca->dev == dev) {
842                         percpu_ref_put(&ca->io_ref);
843                         return i;
844                 }
845
846         return -BCH_ERR_ENOENT_dev_idx_not_found;
847 }
848
849 static long bch2_ioctl_disk_resize(struct bch_fs *c,
850                                    struct bch_ioctl_disk_resize arg)
851 {
852         struct bch_dev *ca;
853         int ret;
854
855         if (!capable(CAP_SYS_ADMIN))
856                 return -EPERM;
857
858         if ((arg.flags & ~BCH_BY_INDEX) ||
859             arg.pad)
860                 return -EINVAL;
861
862         ca = bch2_device_lookup(c, arg.dev, arg.flags);
863         if (IS_ERR(ca))
864                 return PTR_ERR(ca);
865
866         ret = bch2_dev_resize(c, ca, arg.nbuckets);
867
868         percpu_ref_put(&ca->ref);
869         return ret;
870 }
871
872 static long bch2_ioctl_disk_resize_journal(struct bch_fs *c,
873                                    struct bch_ioctl_disk_resize_journal arg)
874 {
875         struct bch_dev *ca;
876         int ret;
877
878         if (!capable(CAP_SYS_ADMIN))
879                 return -EPERM;
880
881         if ((arg.flags & ~BCH_BY_INDEX) ||
882             arg.pad)
883                 return -EINVAL;
884
885         if (arg.nbuckets > U32_MAX)
886                 return -EINVAL;
887
888         ca = bch2_device_lookup(c, arg.dev, arg.flags);
889         if (IS_ERR(ca))
890                 return PTR_ERR(ca);
891
892         ret = bch2_set_nr_journal_buckets(c, ca, arg.nbuckets);
893
894         percpu_ref_put(&ca->ref);
895         return ret;
896 }
897
898 static int bch2_fsck_online_thread_fn(void *arg)
899 {
900         struct fsck_thread *thr = container_of(arg, struct fsck_thread, thr);
901         struct bch_fs *c = thr->c;
902 #if 0
903         struct bch_fs *c = bch2_fs_open(thr->devs, thr->nr_devs, thr->opts);
904
905         thr->thr.ret = PTR_ERR_OR_ZERO(c);
906         if (!thr->thr.ret)
907                 bch2_fs_stop(c);
908 #endif
909         return 0;
910 }
911
912 static long bch2_ioctl_fsck_online(struct bch_fs *c,
913                                    struct bch_ioctl_fsck_online arg)
914 {
915         struct fsck_thread *thr = NULL;
916         long ret = 0;
917
918         if (arg.flags)
919                 return -EINVAL;
920
921         thr = kzalloc(sizeof(*thr), GFP_KERNEL);
922         if (!thr)
923                 return -ENOMEM;
924
925         thr->c = c;
926         thr->output.buf = PRINTBUF;
927         thr->output.buf.atomic++;
928         spin_lock_init(&thr->output.lock);
929         init_waitqueue_head(&thr->output.wait);
930         darray_init(&thr->output2);
931
932         ret = run_thread_with_file(&thr->thr,
933                                    &fsck_thread_ops,
934                                    bch2_fsck_online_thread_fn,
935                                    "bch-fsck");
936         bch_err_fn(c, ret);
937         if (ret < 0)
938                 bch2_fsck_thread_free(thr);
939         return ret;
940 }
941
942 #define BCH_IOCTL(_name, _argtype)                                      \
943 do {                                                                    \
944         _argtype i;                                                     \
945                                                                         \
946         if (copy_from_user(&i, arg, sizeof(i)))                         \
947                 return -EFAULT;                                         \
948         ret = bch2_ioctl_##_name(c, i);                                 \
949         goto out;                                                       \
950 } while (0)
951
952 long bch2_fs_ioctl(struct bch_fs *c, unsigned cmd, void __user *arg)
953 {
954         long ret;
955
956         switch (cmd) {
957         case BCH_IOCTL_QUERY_UUID:
958                 return bch2_ioctl_query_uuid(c, arg);
959         case BCH_IOCTL_FS_USAGE:
960                 return bch2_ioctl_fs_usage(c, arg);
961         case BCH_IOCTL_DEV_USAGE:
962                 return bch2_ioctl_dev_usage(c, arg);
963         case BCH_IOCTL_DEV_USAGE_V2:
964                 return bch2_ioctl_dev_usage_v2(c, arg);
965 #if 0
966         case BCH_IOCTL_START:
967                 BCH_IOCTL(start, struct bch_ioctl_start);
968         case BCH_IOCTL_STOP:
969                 return bch2_ioctl_stop(c);
970 #endif
971         case BCH_IOCTL_READ_SUPER:
972                 BCH_IOCTL(read_super, struct bch_ioctl_read_super);
973         case BCH_IOCTL_DISK_GET_IDX:
974                 BCH_IOCTL(disk_get_idx, struct bch_ioctl_disk_get_idx);
975         }
976
977         if (!test_bit(BCH_FS_started, &c->flags))
978                 return -EINVAL;
979
980         switch (cmd) {
981         case BCH_IOCTL_DISK_ADD:
982                 BCH_IOCTL(disk_add, struct bch_ioctl_disk);
983         case BCH_IOCTL_DISK_REMOVE:
984                 BCH_IOCTL(disk_remove, struct bch_ioctl_disk);
985         case BCH_IOCTL_DISK_ONLINE:
986                 BCH_IOCTL(disk_online, struct bch_ioctl_disk);
987         case BCH_IOCTL_DISK_OFFLINE:
988                 BCH_IOCTL(disk_offline, struct bch_ioctl_disk);
989         case BCH_IOCTL_DISK_SET_STATE:
990                 BCH_IOCTL(disk_set_state, struct bch_ioctl_disk_set_state);
991         case BCH_IOCTL_DATA:
992                 BCH_IOCTL(data, struct bch_ioctl_data);
993         case BCH_IOCTL_DISK_RESIZE:
994                 BCH_IOCTL(disk_resize, struct bch_ioctl_disk_resize);
995         case BCH_IOCTL_DISK_RESIZE_JOURNAL:
996                 BCH_IOCTL(disk_resize_journal, struct bch_ioctl_disk_resize_journal);
997         case BCH_IOCTL_FSCK_ONLINE:
998                 BCH_IOCTL(fsck_online, struct bch_ioctl_fsck_online);
999         default:
1000                 return -ENOTTY;
1001         }
1002 out:
1003         if (ret < 0)
1004                 ret = bch2_err_class(ret);
1005         return ret;
1006 }
1007
1008 static DEFINE_IDR(bch_chardev_minor);
1009
1010 static long bch2_chardev_ioctl(struct file *filp, unsigned cmd, unsigned long v)
1011 {
1012         unsigned minor = iminor(file_inode(filp));
1013         struct bch_fs *c = minor < U8_MAX ? idr_find(&bch_chardev_minor, minor) : NULL;
1014         void __user *arg = (void __user *) v;
1015
1016         return c
1017                 ? bch2_fs_ioctl(c, cmd, arg)
1018                 : bch2_global_ioctl(cmd, arg);
1019 }
1020
1021 static const struct file_operations bch_chardev_fops = {
1022         .owner          = THIS_MODULE,
1023         .unlocked_ioctl = bch2_chardev_ioctl,
1024         .open           = nonseekable_open,
1025 };
1026
1027 static int bch_chardev_major;
1028 static struct class *bch_chardev_class;
1029 static struct device *bch_chardev;
1030
1031 void bch2_fs_chardev_exit(struct bch_fs *c)
1032 {
1033         if (!IS_ERR_OR_NULL(c->chardev))
1034                 device_unregister(c->chardev);
1035         if (c->minor >= 0)
1036                 idr_remove(&bch_chardev_minor, c->minor);
1037 }
1038
1039 int bch2_fs_chardev_init(struct bch_fs *c)
1040 {
1041         c->minor = idr_alloc(&bch_chardev_minor, c, 0, 0, GFP_KERNEL);
1042         if (c->minor < 0)
1043                 return c->minor;
1044
1045         c->chardev = device_create(bch_chardev_class, NULL,
1046                                    MKDEV(bch_chardev_major, c->minor), c,
1047                                    "bcachefs%u-ctl", c->minor);
1048         if (IS_ERR(c->chardev))
1049                 return PTR_ERR(c->chardev);
1050
1051         return 0;
1052 }
1053
1054 void bch2_chardev_exit(void)
1055 {
1056         if (!IS_ERR_OR_NULL(bch_chardev_class))
1057                 device_destroy(bch_chardev_class,
1058                                MKDEV(bch_chardev_major, U8_MAX));
1059         if (!IS_ERR_OR_NULL(bch_chardev_class))
1060                 class_destroy(bch_chardev_class);
1061         if (bch_chardev_major > 0)
1062                 unregister_chrdev(bch_chardev_major, "bcachefs");
1063 }
1064
1065 int __init bch2_chardev_init(void)
1066 {
1067         bch_chardev_major = register_chrdev(0, "bcachefs-ctl", &bch_chardev_fops);
1068         if (bch_chardev_major < 0)
1069                 return bch_chardev_major;
1070
1071         bch_chardev_class = class_create("bcachefs");
1072         if (IS_ERR(bch_chardev_class))
1073                 return PTR_ERR(bch_chardev_class);
1074
1075         bch_chardev = device_create(bch_chardev_class, NULL,
1076                                     MKDEV(bch_chardev_major, U8_MAX),
1077                                     NULL, "bcachefs-ctl");
1078         if (IS_ERR(bch_chardev))
1079                 return PTR_ERR(bch_chardev);
1080
1081         return 0;
1082 }
1083
1084 #endif /* NO_BCACHEFS_CHARDEV */