]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/sysfs.c
e42bc1dae336c8571e67917eccbd4b723ddafa44
[bcachefs-tools-debian] / libbcachefs / sysfs.c
1 /*
2  * bcache sysfs interfaces
3  *
4  * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
5  * Copyright 2012 Google, Inc.
6  */
7
8 #ifndef NO_BCACHEFS_SYSFS
9
10 #include "bcachefs.h"
11 #include "alloc.h"
12 #include "compress.h"
13 #include "sysfs.h"
14 #include "btree_cache.h"
15 #include "btree_io.h"
16 #include "btree_iter.h"
17 #include "btree_update.h"
18 #include "btree_update_interior.h"
19 #include "btree_gc.h"
20 #include "buckets.h"
21 #include "inode.h"
22 #include "journal.h"
23 #include "keylist.h"
24 #include "move.h"
25 #include "opts.h"
26 #include "super-io.h"
27 #include "tier.h"
28
29 #include <linux/blkdev.h>
30 #include <linux/sort.h>
31 #include <linux/sched/clock.h>
32
33 #include "util.h"
34
35 #define SYSFS_OPS(type)                                                 \
36 struct sysfs_ops type ## _sysfs_ops = {                                 \
37         .show   = type ## _show,                                        \
38         .store  = type ## _store                                        \
39 }
40
41 #define SHOW(fn)                                                        \
42 static ssize_t fn ## _show(struct kobject *kobj, struct attribute *attr,\
43                            char *buf)                                   \
44
45 #define STORE(fn)                                                       \
46 static ssize_t fn ## _store(struct kobject *kobj, struct attribute *attr,\
47                             const char *buf, size_t size)               \
48
49 #define __sysfs_attribute(_name, _mode)                                 \
50         static struct attribute sysfs_##_name =                         \
51                 { .name = #_name, .mode = _mode }
52
53 #define write_attribute(n)      __sysfs_attribute(n, S_IWUSR)
54 #define read_attribute(n)       __sysfs_attribute(n, S_IRUGO)
55 #define rw_attribute(n)         __sysfs_attribute(n, S_IRUGO|S_IWUSR)
56
57 #define sysfs_printf(file, fmt, ...)                                    \
58 do {                                                                    \
59         if (attr == &sysfs_ ## file)                                    \
60                 return scnprintf(buf, PAGE_SIZE, fmt "\n", __VA_ARGS__);\
61 } while (0)
62
63 #define sysfs_print(file, var)                                          \
64 do {                                                                    \
65         if (attr == &sysfs_ ## file)                                    \
66                 return snprint(buf, PAGE_SIZE, var);                    \
67 } while (0)
68
69 #define sysfs_hprint(file, val)                                         \
70 do {                                                                    \
71         if (attr == &sysfs_ ## file) {                                  \
72                 ssize_t ret = bch2_hprint(buf, val);                    \
73                 strcat(buf, "\n");                                      \
74                 return ret + 1;                                         \
75         }                                                               \
76 } while (0)
77
78 #define var_printf(_var, fmt)   sysfs_printf(_var, fmt, var(_var))
79 #define var_print(_var)         sysfs_print(_var, var(_var))
80 #define var_hprint(_var)        sysfs_hprint(_var, var(_var))
81
82 #define sysfs_strtoul(file, var)                                        \
83 do {                                                                    \
84         if (attr == &sysfs_ ## file)                                    \
85                 return strtoul_safe(buf, var) ?: (ssize_t) size;        \
86 } while (0)
87
88 #define sysfs_strtoul_clamp(file, var, min, max)                        \
89 do {                                                                    \
90         if (attr == &sysfs_ ## file)                                    \
91                 return strtoul_safe_clamp(buf, var, min, max)           \
92                         ?: (ssize_t) size;                              \
93 } while (0)
94
95 #define strtoul_or_return(cp)                                           \
96 ({                                                                      \
97         unsigned long _v;                                               \
98         int _r = kstrtoul(cp, 10, &_v);                                 \
99         if (_r)                                                         \
100                 return _r;                                              \
101         _v;                                                             \
102 })
103
104 #define strtoul_restrict_or_return(cp, min, max)                        \
105 ({                                                                      \
106         unsigned long __v = 0;                                          \
107         int _r = strtoul_safe_restrict(cp, __v, min, max);              \
108         if (_r)                                                         \
109                 return _r;                                              \
110         __v;                                                            \
111 })
112
113 #define strtoi_h_or_return(cp)                                          \
114 ({                                                                      \
115         u64 _v;                                                         \
116         int _r = strtoi_h(cp, &_v);                                     \
117         if (_r)                                                         \
118                 return _r;                                              \
119         _v;                                                             \
120 })
121
122 #define sysfs_hatoi(file, var)                                          \
123 do {                                                                    \
124         if (attr == &sysfs_ ## file)                                    \
125                 return strtoi_h(buf, &var) ?: (ssize_t) size;           \
126 } while (0)
127
128 write_attribute(trigger_journal_flush);
129 write_attribute(trigger_btree_coalesce);
130 write_attribute(trigger_gc);
131 write_attribute(prune_cache);
132 rw_attribute(btree_gc_periodic);
133
134 read_attribute(uuid);
135 read_attribute(minor);
136 read_attribute(bucket_size);
137 read_attribute(block_size);
138 read_attribute(btree_node_size);
139 read_attribute(first_bucket);
140 read_attribute(nbuckets);
141 read_attribute(iostats);
142 read_attribute(read_priority_stats);
143 read_attribute(write_priority_stats);
144 read_attribute(fragmentation_stats);
145 read_attribute(oldest_gen_stats);
146 read_attribute(reserve_stats);
147 read_attribute(btree_cache_size);
148 read_attribute(compression_stats);
149 read_attribute(journal_debug);
150 read_attribute(journal_pins);
151 read_attribute(btree_updates);
152 read_attribute(dirty_btree_nodes);
153
154 read_attribute(internal_uuid);
155
156 read_attribute(has_data);
157 read_attribute(alloc_debug);
158 write_attribute(wake_allocator);
159
160 read_attribute(read_realloc_races);
161 read_attribute(extent_migrate_done);
162 read_attribute(extent_migrate_raced);
163
164 rw_attribute(journal_write_delay_ms);
165 rw_attribute(journal_reclaim_delay_ms);
166
167 rw_attribute(writeback_pages_max);
168
169 rw_attribute(discard);
170 rw_attribute(cache_replacement_policy);
171 rw_attribute(group);
172
173 rw_attribute(copy_gc_enabled);
174 sysfs_pd_controller_attribute(copy_gc);
175
176 rw_attribute(rebalance_enabled);
177 rw_attribute(rebalance_percent);
178 sysfs_pd_controller_attribute(rebalance);
179
180 rw_attribute(pd_controllers_update_seconds);
181
182 read_attribute(meta_replicas_have);
183 read_attribute(data_replicas_have);
184
185 #define BCH_DEBUG_PARAM(name, description)                              \
186         rw_attribute(name);
187
188         BCH_DEBUG_PARAMS()
189 #undef BCH_DEBUG_PARAM
190
191 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
192         sysfs_time_stats_attribute(name, frequency_units, duration_units);
193         BCH_TIME_STATS()
194 #undef BCH_TIME_STAT
195
196 static struct attribute sysfs_state_rw = {
197         .name = "state",
198         .mode = S_IRUGO
199 };
200
201 static size_t bch2_btree_cache_size(struct bch_fs *c)
202 {
203         size_t ret = 0;
204         struct btree *b;
205
206         mutex_lock(&c->btree_cache.lock);
207         list_for_each_entry(b, &c->btree_cache.live, list)
208                 ret += btree_bytes(c);
209
210         mutex_unlock(&c->btree_cache.lock);
211         return ret;
212 }
213
214 static ssize_t show_fs_alloc_debug(struct bch_fs *c, char *buf)
215 {
216         struct bch_fs_usage stats = bch2_fs_usage_read(c);
217
218         return scnprintf(buf, PAGE_SIZE,
219                          "capacity:\t\t%llu\n"
220                          "1 replicas:\n"
221                          "\tmeta:\t\t%llu\n"
222                          "\tdirty:\t\t%llu\n"
223                          "\treserved:\t%llu\n"
224                          "2 replicas:\n"
225                          "\tmeta:\t\t%llu\n"
226                          "\tdirty:\t\t%llu\n"
227                          "\treserved:\t%llu\n"
228                          "3 replicas:\n"
229                          "\tmeta:\t\t%llu\n"
230                          "\tdirty:\t\t%llu\n"
231                          "\treserved:\t%llu\n"
232                          "4 replicas:\n"
233                          "\tmeta:\t\t%llu\n"
234                          "\tdirty:\t\t%llu\n"
235                          "\treserved:\t%llu\n"
236                          "online reserved:\t%llu\n",
237                          c->capacity,
238                          stats.s[0].data[S_META],
239                          stats.s[0].data[S_DIRTY],
240                          stats.s[0].persistent_reserved,
241                          stats.s[1].data[S_META],
242                          stats.s[1].data[S_DIRTY],
243                          stats.s[1].persistent_reserved,
244                          stats.s[2].data[S_META],
245                          stats.s[2].data[S_DIRTY],
246                          stats.s[2].persistent_reserved,
247                          stats.s[3].data[S_META],
248                          stats.s[3].data[S_DIRTY],
249                          stats.s[3].persistent_reserved,
250                          stats.online_reserved);
251 }
252
253 static ssize_t bch2_compression_stats(struct bch_fs *c, char *buf)
254 {
255         struct btree_iter iter;
256         struct bkey_s_c k;
257         u64 nr_uncompressed_extents = 0, uncompressed_sectors = 0,
258             nr_compressed_extents = 0,
259             compressed_sectors_compressed = 0,
260             compressed_sectors_uncompressed = 0;
261
262         if (!bch2_fs_running(c))
263                 return -EPERM;
264
265         for_each_btree_key(&iter, c, BTREE_ID_EXTENTS, POS_MIN, 0, k)
266                 if (k.k->type == BCH_EXTENT) {
267                         struct bkey_s_c_extent e = bkey_s_c_to_extent(k);
268                         const struct bch_extent_ptr *ptr;
269                         struct bch_extent_crc_unpacked crc;
270
271                         extent_for_each_ptr_crc(e, ptr, crc) {
272                                 if (crc.compression_type == BCH_COMPRESSION_NONE) {
273                                         nr_uncompressed_extents++;
274                                         uncompressed_sectors += e.k->size;
275                                 } else {
276                                         nr_compressed_extents++;
277                                         compressed_sectors_compressed +=
278                                                 crc.compressed_size;
279                                         compressed_sectors_uncompressed +=
280                                                 crc.uncompressed_size;
281                                 }
282
283                                 /* only looking at the first ptr */
284                                 break;
285                         }
286                 }
287         bch2_btree_iter_unlock(&iter);
288
289         return scnprintf(buf, PAGE_SIZE,
290                         "uncompressed data:\n"
291                         "       nr extents:                     %llu\n"
292                         "       size (bytes):                   %llu\n"
293                         "compressed data:\n"
294                         "       nr extents:                     %llu\n"
295                         "       compressed size (bytes):        %llu\n"
296                         "       uncompressed size (bytes):      %llu\n",
297                         nr_uncompressed_extents,
298                         uncompressed_sectors << 9,
299                         nr_compressed_extents,
300                         compressed_sectors_compressed << 9,
301                         compressed_sectors_uncompressed << 9);
302 }
303
304 SHOW(bch2_fs)
305 {
306         struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
307
308         sysfs_print(minor,                      c->minor);
309         sysfs_printf(internal_uuid, "%pU",      c->sb.uuid.b);
310
311         sysfs_print(journal_write_delay_ms,     c->journal.write_delay_ms);
312         sysfs_print(journal_reclaim_delay_ms,   c->journal.reclaim_delay_ms);
313
314         sysfs_print(writeback_pages_max,        c->writeback_pages_max);
315
316         sysfs_print(block_size,                 block_bytes(c));
317         sysfs_print(btree_node_size,            btree_bytes(c));
318         sysfs_hprint(btree_cache_size,          bch2_btree_cache_size(c));
319
320         sysfs_print(read_realloc_races,
321                     atomic_long_read(&c->read_realloc_races));
322         sysfs_print(extent_migrate_done,
323                     atomic_long_read(&c->extent_migrate_done));
324         sysfs_print(extent_migrate_raced,
325                     atomic_long_read(&c->extent_migrate_raced));
326
327         sysfs_printf(btree_gc_periodic, "%u",   (int) c->btree_gc_periodic);
328
329         sysfs_printf(copy_gc_enabled, "%i", c->copy_gc_enabled);
330
331         sysfs_print(pd_controllers_update_seconds,
332                     c->pd_controllers_update_seconds);
333
334         sysfs_printf(rebalance_enabled,         "%i", c->rebalance_enabled);
335         sysfs_print(rebalance_percent,          c->rebalance_percent);
336
337         sysfs_pd_controller_show(rebalance,     &c->rebalance_pd); /* XXX */
338
339         sysfs_printf(meta_replicas_have, "%u",  bch2_replicas_online(c, true));
340         sysfs_printf(data_replicas_have, "%u",  bch2_replicas_online(c, false));
341
342         /* Debugging: */
343
344         if (attr == &sysfs_alloc_debug)
345                 return show_fs_alloc_debug(c, buf);
346
347         if (attr == &sysfs_journal_debug)
348                 return bch2_journal_print_debug(&c->journal, buf);
349
350         if (attr == &sysfs_journal_pins)
351                 return bch2_journal_print_pins(&c->journal, buf);
352
353         if (attr == &sysfs_btree_updates)
354                 return bch2_btree_updates_print(c, buf);
355
356         if (attr == &sysfs_dirty_btree_nodes)
357                 return bch2_dirty_btree_nodes_print(c, buf);
358
359         if (attr == &sysfs_compression_stats)
360                 return bch2_compression_stats(c, buf);
361
362 #define BCH_DEBUG_PARAM(name, description) sysfs_print(name, c->name);
363         BCH_DEBUG_PARAMS()
364 #undef BCH_DEBUG_PARAM
365
366         return 0;
367 }
368
369 STORE(__bch2_fs)
370 {
371         struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
372
373         sysfs_strtoul(journal_write_delay_ms, c->journal.write_delay_ms);
374         sysfs_strtoul(journal_reclaim_delay_ms, c->journal.reclaim_delay_ms);
375
376         if (attr == &sysfs_writeback_pages_max)
377                 c->writeback_pages_max = strtoul_restrict_or_return(buf, 1, UINT_MAX);
378
379         if (attr == &sysfs_btree_gc_periodic) {
380                 ssize_t ret = strtoul_safe(buf, c->btree_gc_periodic)
381                         ?: (ssize_t) size;
382
383                 wake_up_process(c->gc_thread);
384                 return ret;
385         }
386
387         if (attr == &sysfs_copy_gc_enabled) {
388                 struct bch_dev *ca;
389                 unsigned i;
390                 ssize_t ret = strtoul_safe(buf, c->copy_gc_enabled)
391                         ?: (ssize_t) size;
392
393                 for_each_member_device(ca, c, i)
394                         if (ca->copygc_thread)
395                                 wake_up_process(ca->copygc_thread);
396                 return ret;
397         }
398
399         if (attr == &sysfs_rebalance_enabled) {
400                 ssize_t ret = strtoul_safe(buf, c->rebalance_enabled)
401                         ?: (ssize_t) size;
402
403                 rebalance_wakeup(c);
404                 return ret;
405         }
406
407         sysfs_strtoul(pd_controllers_update_seconds,
408                       c->pd_controllers_update_seconds);
409
410         sysfs_strtoul(rebalance_percent,        c->rebalance_percent);
411         sysfs_pd_controller_store(rebalance,    &c->rebalance_pd);
412
413         /* Debugging: */
414
415 #define BCH_DEBUG_PARAM(name, description) sysfs_strtoul(name, c->name);
416         BCH_DEBUG_PARAMS()
417 #undef BCH_DEBUG_PARAM
418
419         if (!bch2_fs_running(c))
420                 return -EPERM;
421
422         /* Debugging: */
423
424         if (attr == &sysfs_trigger_journal_flush)
425                 bch2_journal_meta_async(&c->journal, NULL);
426
427         if (attr == &sysfs_trigger_btree_coalesce)
428                 bch2_coalesce(c);
429
430         if (attr == &sysfs_trigger_gc)
431                 bch2_gc(c);
432
433         if (attr == &sysfs_prune_cache) {
434                 struct shrink_control sc;
435
436                 sc.gfp_mask = GFP_KERNEL;
437                 sc.nr_to_scan = strtoul_or_return(buf);
438                 c->btree_cache.shrink.scan_objects(&c->btree_cache.shrink, &sc);
439         }
440
441         return size;
442 }
443
444 STORE(bch2_fs)
445 {
446         struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
447
448         mutex_lock(&c->state_lock);
449         size = __bch2_fs_store(kobj, attr, buf, size);
450         mutex_unlock(&c->state_lock);
451
452         return size;
453 }
454 SYSFS_OPS(bch2_fs);
455
456 struct attribute *bch2_fs_files[] = {
457         &sysfs_minor,
458         &sysfs_block_size,
459         &sysfs_btree_node_size,
460         &sysfs_btree_cache_size,
461
462         &sysfs_meta_replicas_have,
463         &sysfs_data_replicas_have,
464
465         &sysfs_journal_write_delay_ms,
466         &sysfs_journal_reclaim_delay_ms,
467
468         &sysfs_writeback_pages_max,
469
470         &sysfs_rebalance_percent,
471
472         &sysfs_compression_stats,
473         NULL
474 };
475
476 /* internal dir - just a wrapper */
477
478 SHOW(bch2_fs_internal)
479 {
480         struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
481         return bch2_fs_show(&c->kobj, attr, buf);
482 }
483
484 STORE(bch2_fs_internal)
485 {
486         struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
487         return bch2_fs_store(&c->kobj, attr, buf, size);
488 }
489 SYSFS_OPS(bch2_fs_internal);
490
491 struct attribute *bch2_fs_internal_files[] = {
492         &sysfs_alloc_debug,
493         &sysfs_journal_debug,
494         &sysfs_journal_pins,
495         &sysfs_btree_updates,
496         &sysfs_dirty_btree_nodes,
497
498         &sysfs_read_realloc_races,
499         &sysfs_extent_migrate_done,
500         &sysfs_extent_migrate_raced,
501
502         &sysfs_trigger_journal_flush,
503         &sysfs_trigger_btree_coalesce,
504         &sysfs_trigger_gc,
505         &sysfs_prune_cache,
506
507         &sysfs_copy_gc_enabled,
508         &sysfs_rebalance_enabled,
509         sysfs_pd_controller_files(rebalance),
510         &sysfs_internal_uuid,
511
512 #define BCH_DEBUG_PARAM(name, description) &sysfs_##name,
513         BCH_DEBUG_PARAMS()
514 #undef BCH_DEBUG_PARAM
515
516         NULL
517 };
518
519 /* options */
520
521 SHOW(bch2_fs_opts_dir)
522 {
523         char *out = buf, *end = buf + PAGE_SIZE;
524         struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
525         const struct bch_option *opt = container_of(attr, struct bch_option, attr);
526         int id = opt - bch2_opt_table;
527         u64 v = bch2_opt_get_by_id(&c->opts, id);
528
529         out += bch2_opt_to_text(c, out, end - out, opt, v, OPT_SHOW_FULL_LIST);
530         out += scnprintf(out, end - out, "\n");
531
532         return out - buf;
533 }
534
535 STORE(bch2_fs_opts_dir)
536 {
537         struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
538         const struct bch_option *opt = container_of(attr, struct bch_option, attr);
539         int ret, id = opt - bch2_opt_table;
540         u64 v;
541
542         ret = bch2_opt_parse(c, opt, buf, &v);
543         if (ret < 0)
544                 return ret;
545
546         if (id == Opt_compression ||
547             id == Opt_background_compression) {
548                 int ret = bch2_check_set_has_compressed_data(c, v);
549                 if (ret) {
550                         mutex_unlock(&c->sb_lock);
551                         return ret;
552                 }
553         }
554
555         if (opt->set_sb != SET_NO_SB_OPT) {
556                 mutex_lock(&c->sb_lock);
557                 opt->set_sb(c->disk_sb, v);
558                 bch2_write_super(c);
559                 mutex_unlock(&c->sb_lock);
560         }
561
562         bch2_opt_set_by_id(&c->opts, id, v);
563
564         if ((id == Opt_background_target ||
565              id == Opt_background_compression) && v) {
566                 bch2_rebalance_add_work(c, S64_MAX);
567                 rebalance_wakeup(c);
568         }
569
570         return size;
571 }
572 SYSFS_OPS(bch2_fs_opts_dir);
573
574 struct attribute *bch2_fs_opts_dir_files[] = { NULL };
575
576 int bch2_opts_create_sysfs_files(struct kobject *kobj)
577 {
578         const struct bch_option *i;
579         int ret;
580
581         for (i = bch2_opt_table;
582              i < bch2_opt_table + bch2_opts_nr;
583              i++) {
584                 if (i->mode == OPT_INTERNAL)
585                         continue;
586
587                 ret = sysfs_create_file(kobj, &i->attr);
588                 if (ret)
589                         return ret;
590         }
591
592         return 0;
593 }
594
595 /* time stats */
596
597 SHOW(bch2_fs_time_stats)
598 {
599         struct bch_fs *c = container_of(kobj, struct bch_fs, time_stats);
600
601 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
602         sysfs_print_time_stats(&c->name##_time, name,                   \
603                                frequency_units, duration_units);
604         BCH_TIME_STATS()
605 #undef BCH_TIME_STAT
606
607         return 0;
608 }
609
610 STORE(bch2_fs_time_stats)
611 {
612         struct bch_fs *c = container_of(kobj, struct bch_fs, time_stats);
613
614 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
615         sysfs_clear_time_stats(&c->name##_time, name);
616         BCH_TIME_STATS()
617 #undef BCH_TIME_STAT
618
619         return size;
620 }
621 SYSFS_OPS(bch2_fs_time_stats);
622
623 struct attribute *bch2_fs_time_stats_files[] = {
624 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
625         sysfs_time_stats_attribute_list(name, frequency_units, duration_units)
626         BCH_TIME_STATS()
627 #undef BCH_TIME_STAT
628
629         NULL
630 };
631
632 typedef unsigned (bucket_map_fn)(struct bch_dev *, size_t, void *);
633
634 static unsigned bucket_priority_fn(struct bch_dev *ca, size_t b,
635                                    void *private)
636 {
637         struct bucket *g = bucket(ca, b);
638         int rw = (private ? 1 : 0);
639
640         return ca->fs->prio_clock[rw].hand - g->prio[rw];
641 }
642
643 static unsigned bucket_sectors_used_fn(struct bch_dev *ca, size_t b,
644                                        void *private)
645 {
646         struct bucket *g = bucket(ca, b);
647         return bucket_sectors_used(g->mark);
648 }
649
650 static unsigned bucket_oldest_gen_fn(struct bch_dev *ca, size_t b,
651                                      void *private)
652 {
653         return bucket_gc_gen(ca, b);
654 }
655
656 static ssize_t show_quantiles(struct bch_dev *ca, char *buf,
657                               bucket_map_fn *fn, void *private)
658 {
659         int cmp(const void *l, const void *r)
660         {       return *((unsigned *) r) - *((unsigned *) l); }
661
662         size_t i, n;
663         /* Compute 31 quantiles */
664         unsigned q[31], *p;
665         ssize_t ret = 0;
666
667         down_read(&ca->bucket_lock);
668         n = ca->mi.nbuckets;
669
670         p = vzalloc(n * sizeof(unsigned));
671         if (!p) {
672                 up_read(&ca->bucket_lock);
673                 return -ENOMEM;
674         }
675
676         for (i = ca->mi.first_bucket; i < n; i++)
677                 p[i] = fn(ca, i, private);
678
679         sort(p, n, sizeof(unsigned), cmp, NULL);
680         up_read(&ca->bucket_lock);
681
682         while (n &&
683                !p[n - 1])
684                 --n;
685
686         for (i = 0; i < ARRAY_SIZE(q); i++)
687                 q[i] = p[n * (i + 1) / (ARRAY_SIZE(q) + 1)];
688
689         vfree(p);
690
691         for (i = 0; i < ARRAY_SIZE(q); i++)
692                 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
693                                  "%u ", q[i]);
694         buf[ret - 1] = '\n';
695
696         return ret;
697 }
698
699 static ssize_t show_reserve_stats(struct bch_dev *ca, char *buf)
700 {
701         enum alloc_reserve i;
702         ssize_t ret;
703
704         spin_lock(&ca->freelist_lock);
705
706         ret = scnprintf(buf, PAGE_SIZE,
707                         "free_inc:\t%zu\t%zu\n",
708                         fifo_used(&ca->free_inc),
709                         ca->free_inc.size);
710
711         for (i = 0; i < RESERVE_NR; i++)
712                 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
713                                  "free[%u]:\t%zu\t%zu\n", i,
714                                  fifo_used(&ca->free[i]),
715                                  ca->free[i].size);
716
717         spin_unlock(&ca->freelist_lock);
718
719         return ret;
720 }
721
722 static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf)
723 {
724         struct bch_fs *c = ca->fs;
725         struct bch_dev_usage stats = bch2_dev_usage_read(c, ca);
726
727         return scnprintf(buf, PAGE_SIZE,
728                 "free_inc:               %zu/%zu\n"
729                 "free[RESERVE_BTREE]:    %zu/%zu\n"
730                 "free[RESERVE_MOVINGGC]: %zu/%zu\n"
731                 "free[RESERVE_NONE]:     %zu/%zu\n"
732                 "buckets:\n"
733                 "    capacity:           %llu\n"
734                 "    alloc:              %llu\n"
735                 "    sb:                 %llu\n"
736                 "    journal:            %llu\n"
737                 "    meta:               %llu\n"
738                 "    user:               %llu\n"
739                 "    cached:             %llu\n"
740                 "    available:          %llu\n"
741                 "sectors:\n"
742                 "    sb:                 %llu\n"
743                 "    journal:            %llu\n"
744                 "    meta:               %llu\n"
745                 "    user:               %llu\n"
746                 "    cached:             %llu\n"
747                 "freelist_wait:          %s\n"
748                 "open buckets:           %u/%u (reserved %u)\n"
749                 "open_buckets_wait:      %s\n",
750                 fifo_used(&ca->free_inc),               ca->free_inc.size,
751                 fifo_used(&ca->free[RESERVE_BTREE]),    ca->free[RESERVE_BTREE].size,
752                 fifo_used(&ca->free[RESERVE_MOVINGGC]), ca->free[RESERVE_MOVINGGC].size,
753                 fifo_used(&ca->free[RESERVE_NONE]),     ca->free[RESERVE_NONE].size,
754                 ca->mi.nbuckets - ca->mi.first_bucket,
755                 stats.buckets_alloc,
756                 stats.buckets[BCH_DATA_SB],
757                 stats.buckets[BCH_DATA_JOURNAL],
758                 stats.buckets[BCH_DATA_BTREE],
759                 stats.buckets[BCH_DATA_USER],
760                 stats.buckets[BCH_DATA_CACHED],
761                 __dev_buckets_available(ca, stats),
762                 stats.sectors[BCH_DATA_SB],
763                 stats.sectors[BCH_DATA_JOURNAL],
764                 stats.sectors[BCH_DATA_BTREE],
765                 stats.sectors[BCH_DATA_USER],
766                 stats.sectors[BCH_DATA_CACHED],
767                 c->freelist_wait.list.first             ? "waiting" : "empty",
768                 c->open_buckets_nr_free, OPEN_BUCKETS_COUNT, BTREE_NODE_RESERVE,
769                 c->open_buckets_wait.list.first         ? "waiting" : "empty");
770 }
771
772 static const char * const bch2_rw[] = {
773         "read",
774         "write",
775         NULL
776 };
777
778 static ssize_t show_dev_iostats(struct bch_dev *ca, char *buf)
779 {
780         char *out = buf, *end = buf + PAGE_SIZE;
781         int rw, i, cpu;
782
783         for (rw = 0; rw < 2; rw++) {
784                 out += scnprintf(out, end - out, "%s:\n", bch2_rw[rw]);
785
786                 for (i = 1; i < BCH_DATA_NR; i++) {
787                         u64 n = 0;
788
789                         for_each_possible_cpu(cpu)
790                                 n += per_cpu_ptr(ca->io_done, cpu)->sectors[rw][i];
791
792                         out += scnprintf(out, end - out, "%-12s:%12llu\n",
793                                          bch2_data_types[i], n << 9);
794                 }
795         }
796
797         return out - buf;
798 }
799
800 SHOW(bch2_dev)
801 {
802         struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
803         struct bch_fs *c = ca->fs;
804         char *out = buf, *end = buf + PAGE_SIZE;
805
806         sysfs_printf(uuid,              "%pU\n", ca->uuid.b);
807
808         sysfs_print(bucket_size,        bucket_bytes(ca));
809         sysfs_print(block_size,         block_bytes(c));
810         sysfs_print(first_bucket,       ca->mi.first_bucket);
811         sysfs_print(nbuckets,           ca->mi.nbuckets);
812         sysfs_print(discard,            ca->mi.discard);
813
814         if (attr == &sysfs_group) {
815                 struct bch_sb_field_disk_groups *groups;
816                 struct bch_disk_group *g;
817                 unsigned len;
818
819                 if (!ca->mi.group)
820                         return scnprintf(out, end - out, "none\n");
821
822                 mutex_lock(&c->sb_lock);
823                 groups = bch2_sb_get_disk_groups(c->disk_sb);
824
825                 g = &groups->entries[ca->mi.group - 1];
826                 len = strnlen(g->label, sizeof(g->label));
827                 memcpy(buf, g->label, len);
828                 mutex_unlock(&c->sb_lock);
829
830                 buf[len++] = '\n';
831                 return len;
832         }
833
834         if (attr == &sysfs_has_data) {
835                 out += bch2_scnprint_flag_list(out, end - out,
836                                                bch2_data_types,
837                                                bch2_dev_has_data(c, ca));
838                 out += scnprintf(out, end - out, "\n");
839                 return out - buf;
840         }
841
842         sysfs_pd_controller_show(copy_gc, &ca->copygc_pd);
843
844         if (attr == &sysfs_cache_replacement_policy) {
845                 out += bch2_scnprint_string_list(out, end - out,
846                                                  bch2_cache_replacement_policies,
847                                                  ca->mi.replacement);
848                 out += scnprintf(out, end - out, "\n");
849                 return out - buf;
850         }
851
852         if (attr == &sysfs_state_rw) {
853                 out += bch2_scnprint_string_list(out, end - out,
854                                                  bch2_dev_state,
855                                                  ca->mi.state);
856                 out += scnprintf(out, end - out, "\n");
857                 return out - buf;
858         }
859
860         if (attr == &sysfs_iostats)
861                 return show_dev_iostats(ca, buf);
862         if (attr == &sysfs_read_priority_stats)
863                 return show_quantiles(ca, buf, bucket_priority_fn, (void *) 0);
864         if (attr == &sysfs_write_priority_stats)
865                 return show_quantiles(ca, buf, bucket_priority_fn, (void *) 1);
866         if (attr == &sysfs_fragmentation_stats)
867                 return show_quantiles(ca, buf, bucket_sectors_used_fn, NULL);
868         if (attr == &sysfs_oldest_gen_stats)
869                 return show_quantiles(ca, buf, bucket_oldest_gen_fn, NULL);
870         if (attr == &sysfs_reserve_stats)
871                 return show_reserve_stats(ca, buf);
872         if (attr == &sysfs_alloc_debug)
873                 return show_dev_alloc_debug(ca, buf);
874
875         return 0;
876 }
877
878 STORE(bch2_dev)
879 {
880         struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
881         struct bch_fs *c = ca->fs;
882         struct bch_member *mi;
883
884         sysfs_pd_controller_store(copy_gc, &ca->copygc_pd);
885
886         if (attr == &sysfs_discard) {
887                 bool v = strtoul_or_return(buf);
888
889                 mutex_lock(&c->sb_lock);
890                 mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
891
892                 if (v != BCH_MEMBER_DISCARD(mi)) {
893                         SET_BCH_MEMBER_DISCARD(mi, v);
894                         bch2_write_super(c);
895                 }
896                 mutex_unlock(&c->sb_lock);
897         }
898
899         if (attr == &sysfs_cache_replacement_policy) {
900                 ssize_t v = bch2_read_string_list(buf, bch2_cache_replacement_policies);
901
902                 if (v < 0)
903                         return v;
904
905                 mutex_lock(&c->sb_lock);
906                 mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
907
908                 if ((unsigned) v != BCH_MEMBER_REPLACEMENT(mi)) {
909                         SET_BCH_MEMBER_REPLACEMENT(mi, v);
910                         bch2_write_super(c);
911                 }
912                 mutex_unlock(&c->sb_lock);
913         }
914
915         if (attr == &sysfs_group) {
916                 int ret = bch2_dev_group_set(c, ca, buf);
917                 if (ret)
918                         return ret;
919         }
920
921         if (attr == &sysfs_wake_allocator)
922                 bch2_wake_allocator(ca);
923
924         return size;
925 }
926 SYSFS_OPS(bch2_dev);
927
928 struct attribute *bch2_dev_files[] = {
929         &sysfs_uuid,
930         &sysfs_bucket_size,
931         &sysfs_block_size,
932         &sysfs_first_bucket,
933         &sysfs_nbuckets,
934
935         /* settings: */
936         &sysfs_discard,
937         &sysfs_cache_replacement_policy,
938         &sysfs_state_rw,
939         &sysfs_group,
940
941         &sysfs_has_data,
942         &sysfs_iostats,
943
944         /* alloc info - other stats: */
945         &sysfs_read_priority_stats,
946         &sysfs_write_priority_stats,
947         &sysfs_fragmentation_stats,
948         &sysfs_oldest_gen_stats,
949         &sysfs_reserve_stats,
950
951         /* debug: */
952         &sysfs_alloc_debug,
953         &sysfs_wake_allocator,
954
955         sysfs_pd_controller_files(copy_gc),
956         NULL
957 };
958
959 #endif  /* _BCACHEFS_SYSFS_H_ */