]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/sysfs.c
Update bcachefs sources to e99d29e402 bcachefs: zstd support, compression refactoring
[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
172 rw_attribute(copy_gc_enabled);
173 sysfs_pd_controller_attribute(copy_gc);
174
175 rw_attribute(tier);
176 rw_attribute(tiering_enabled);
177 rw_attribute(tiering_percent);
178 sysfs_pd_controller_attribute(tiering);
179
180
181 rw_attribute(pd_controllers_update_seconds);
182
183 read_attribute(meta_replicas_have);
184 read_attribute(data_replicas_have);
185
186 #define BCH_DEBUG_PARAM(name, description)                              \
187         rw_attribute(name);
188
189         BCH_DEBUG_PARAMS()
190 #undef BCH_DEBUG_PARAM
191
192 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
193         sysfs_time_stats_attribute(name, frequency_units, duration_units);
194         BCH_TIME_STATS()
195 #undef BCH_TIME_STAT
196
197 static struct attribute sysfs_state_rw = {
198         .name = "state",
199         .mode = S_IRUGO
200 };
201
202 static size_t bch2_btree_cache_size(struct bch_fs *c)
203 {
204         size_t ret = 0;
205         struct btree *b;
206
207         mutex_lock(&c->btree_cache.lock);
208         list_for_each_entry(b, &c->btree_cache.live, list)
209                 ret += btree_bytes(c);
210
211         mutex_unlock(&c->btree_cache.lock);
212         return ret;
213 }
214
215 static ssize_t show_fs_alloc_debug(struct bch_fs *c, char *buf)
216 {
217         struct bch_fs_usage stats = bch2_fs_usage_read(c);
218
219         return scnprintf(buf, PAGE_SIZE,
220                          "capacity:\t\t%llu\n"
221                          "1 replicas:\n"
222                          "\tmeta:\t\t%llu\n"
223                          "\tdirty:\t\t%llu\n"
224                          "\treserved:\t%llu\n"
225                          "2 replicas:\n"
226                          "\tmeta:\t\t%llu\n"
227                          "\tdirty:\t\t%llu\n"
228                          "\treserved:\t%llu\n"
229                          "3 replicas:\n"
230                          "\tmeta:\t\t%llu\n"
231                          "\tdirty:\t\t%llu\n"
232                          "\treserved:\t%llu\n"
233                          "4 replicas:\n"
234                          "\tmeta:\t\t%llu\n"
235                          "\tdirty:\t\t%llu\n"
236                          "\treserved:\t%llu\n"
237                          "online reserved:\t%llu\n",
238                          c->capacity,
239                          stats.s[0].data[S_META],
240                          stats.s[0].data[S_DIRTY],
241                          stats.s[0].persistent_reserved,
242                          stats.s[1].data[S_META],
243                          stats.s[1].data[S_DIRTY],
244                          stats.s[1].persistent_reserved,
245                          stats.s[2].data[S_META],
246                          stats.s[2].data[S_DIRTY],
247                          stats.s[2].persistent_reserved,
248                          stats.s[3].data[S_META],
249                          stats.s[3].data[S_DIRTY],
250                          stats.s[3].persistent_reserved,
251                          stats.online_reserved);
252 }
253
254 static ssize_t bch2_compression_stats(struct bch_fs *c, char *buf)
255 {
256         struct btree_iter iter;
257         struct bkey_s_c k;
258         u64 nr_uncompressed_extents = 0, uncompressed_sectors = 0,
259             nr_compressed_extents = 0,
260             compressed_sectors_compressed = 0,
261             compressed_sectors_uncompressed = 0;
262
263         if (!bch2_fs_running(c))
264                 return -EPERM;
265
266         for_each_btree_key(&iter, c, BTREE_ID_EXTENTS, POS_MIN, 0, k)
267                 if (k.k->type == BCH_EXTENT) {
268                         struct bkey_s_c_extent e = bkey_s_c_to_extent(k);
269                         const struct bch_extent_ptr *ptr;
270                         struct bch_extent_crc_unpacked crc;
271
272                         extent_for_each_ptr_crc(e, ptr, crc) {
273                                 if (crc.compression_type == BCH_COMPRESSION_NONE) {
274                                         nr_uncompressed_extents++;
275                                         uncompressed_sectors += e.k->size;
276                                 } else {
277                                         nr_compressed_extents++;
278                                         compressed_sectors_compressed +=
279                                                 crc.compressed_size;
280                                         compressed_sectors_uncompressed +=
281                                                 crc.uncompressed_size;
282                                 }
283
284                                 /* only looking at the first ptr */
285                                 break;
286                         }
287                 }
288         bch2_btree_iter_unlock(&iter);
289
290         return scnprintf(buf, PAGE_SIZE,
291                         "uncompressed data:\n"
292                         "       nr extents:                     %llu\n"
293                         "       size (bytes):                   %llu\n"
294                         "compressed data:\n"
295                         "       nr extents:                     %llu\n"
296                         "       compressed size (bytes):        %llu\n"
297                         "       uncompressed size (bytes):      %llu\n",
298                         nr_uncompressed_extents,
299                         uncompressed_sectors << 9,
300                         nr_compressed_extents,
301                         compressed_sectors_compressed << 9,
302                         compressed_sectors_uncompressed << 9);
303 }
304
305 SHOW(bch2_fs)
306 {
307         struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
308
309         sysfs_print(minor,                      c->minor);
310         sysfs_printf(internal_uuid, "%pU",      c->sb.uuid.b);
311
312         sysfs_print(journal_write_delay_ms,     c->journal.write_delay_ms);
313         sysfs_print(journal_reclaim_delay_ms,   c->journal.reclaim_delay_ms);
314
315         sysfs_print(writeback_pages_max,        c->writeback_pages_max);
316
317         sysfs_print(block_size,                 block_bytes(c));
318         sysfs_print(btree_node_size,            btree_bytes(c));
319         sysfs_hprint(btree_cache_size,          bch2_btree_cache_size(c));
320
321         sysfs_print(read_realloc_races,
322                     atomic_long_read(&c->read_realloc_races));
323         sysfs_print(extent_migrate_done,
324                     atomic_long_read(&c->extent_migrate_done));
325         sysfs_print(extent_migrate_raced,
326                     atomic_long_read(&c->extent_migrate_raced));
327
328         sysfs_printf(btree_gc_periodic, "%u",   (int) c->btree_gc_periodic);
329
330         sysfs_printf(copy_gc_enabled, "%i", c->copy_gc_enabled);
331
332         sysfs_print(pd_controllers_update_seconds,
333                     c->pd_controllers_update_seconds);
334
335         sysfs_printf(tiering_enabled,           "%i", c->tiering_enabled);
336         sysfs_print(tiering_percent,            c->tiering_percent);
337
338         sysfs_pd_controller_show(tiering,       &c->tiers[1].pd); /* XXX */
339
340         sysfs_printf(meta_replicas_have, "%u",  bch2_replicas_online(c, true));
341         sysfs_printf(data_replicas_have, "%u",  bch2_replicas_online(c, false));
342
343         /* Debugging: */
344
345         if (attr == &sysfs_alloc_debug)
346                 return show_fs_alloc_debug(c, buf);
347
348         if (attr == &sysfs_journal_debug)
349                 return bch2_journal_print_debug(&c->journal, buf);
350
351         if (attr == &sysfs_journal_pins)
352                 return bch2_journal_print_pins(&c->journal, buf);
353
354         if (attr == &sysfs_btree_updates)
355                 return bch2_btree_updates_print(c, buf);
356
357         if (attr == &sysfs_dirty_btree_nodes)
358                 return bch2_dirty_btree_nodes_print(c, buf);
359
360         if (attr == &sysfs_compression_stats)
361                 return bch2_compression_stats(c, buf);
362
363 #define BCH_DEBUG_PARAM(name, description) sysfs_print(name, c->name);
364         BCH_DEBUG_PARAMS()
365 #undef BCH_DEBUG_PARAM
366
367         return 0;
368 }
369
370 STORE(__bch2_fs)
371 {
372         struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
373
374         sysfs_strtoul(journal_write_delay_ms, c->journal.write_delay_ms);
375         sysfs_strtoul(journal_reclaim_delay_ms, c->journal.reclaim_delay_ms);
376
377         if (attr == &sysfs_writeback_pages_max)
378                 c->writeback_pages_max = strtoul_restrict_or_return(buf, 1, UINT_MAX);
379
380         if (attr == &sysfs_btree_gc_periodic) {
381                 ssize_t ret = strtoul_safe(buf, c->btree_gc_periodic)
382                         ?: (ssize_t) size;
383
384                 wake_up_process(c->gc_thread);
385                 return ret;
386         }
387
388         if (attr == &sysfs_copy_gc_enabled) {
389                 struct bch_dev *ca;
390                 unsigned i;
391                 ssize_t ret = strtoul_safe(buf, c->copy_gc_enabled)
392                         ?: (ssize_t) size;
393
394                 for_each_member_device(ca, c, i)
395                         if (ca->copygc_thread)
396                                 wake_up_process(ca->copygc_thread);
397                 return ret;
398         }
399
400         if (attr == &sysfs_tiering_enabled) {
401                 ssize_t ret = strtoul_safe(buf, c->tiering_enabled)
402                         ?: (ssize_t) size;
403
404                 bch2_tiering_start(c); /* issue wakeups */
405                 return ret;
406         }
407
408         sysfs_strtoul(pd_controllers_update_seconds,
409                       c->pd_controllers_update_seconds);
410
411         sysfs_strtoul(tiering_percent,          c->tiering_percent);
412         sysfs_pd_controller_store(tiering,      &c->tiers[1].pd); /* XXX */
413
414         /* Debugging: */
415
416 #define BCH_DEBUG_PARAM(name, description) sysfs_strtoul(name, c->name);
417         BCH_DEBUG_PARAMS()
418 #undef BCH_DEBUG_PARAM
419
420         if (!bch2_fs_running(c))
421                 return -EPERM;
422
423         /* Debugging: */
424
425         if (attr == &sysfs_trigger_journal_flush)
426                 bch2_journal_meta_async(&c->journal, NULL);
427
428         if (attr == &sysfs_trigger_btree_coalesce)
429                 bch2_coalesce(c);
430
431         if (attr == &sysfs_trigger_gc)
432                 bch2_gc(c);
433
434         if (attr == &sysfs_prune_cache) {
435                 struct shrink_control sc;
436
437                 sc.gfp_mask = GFP_KERNEL;
438                 sc.nr_to_scan = strtoul_or_return(buf);
439                 c->btree_cache.shrink.scan_objects(&c->btree_cache.shrink, &sc);
440         }
441
442         return size;
443 }
444
445 STORE(bch2_fs)
446 {
447         struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
448
449         mutex_lock(&c->state_lock);
450         size = __bch2_fs_store(kobj, attr, buf, size);
451         mutex_unlock(&c->state_lock);
452
453         return size;
454 }
455 SYSFS_OPS(bch2_fs);
456
457 struct attribute *bch2_fs_files[] = {
458         &sysfs_minor,
459         &sysfs_block_size,
460         &sysfs_btree_node_size,
461         &sysfs_btree_cache_size,
462
463         &sysfs_meta_replicas_have,
464         &sysfs_data_replicas_have,
465
466         &sysfs_journal_write_delay_ms,
467         &sysfs_journal_reclaim_delay_ms,
468
469         &sysfs_writeback_pages_max,
470
471         &sysfs_tiering_percent,
472
473         &sysfs_compression_stats,
474         NULL
475 };
476
477 /* internal dir - just a wrapper */
478
479 SHOW(bch2_fs_internal)
480 {
481         struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
482         return bch2_fs_show(&c->kobj, attr, buf);
483 }
484
485 STORE(bch2_fs_internal)
486 {
487         struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
488         return bch2_fs_store(&c->kobj, attr, buf, size);
489 }
490 SYSFS_OPS(bch2_fs_internal);
491
492 struct attribute *bch2_fs_internal_files[] = {
493         &sysfs_alloc_debug,
494         &sysfs_journal_debug,
495         &sysfs_journal_pins,
496         &sysfs_btree_updates,
497         &sysfs_dirty_btree_nodes,
498
499         &sysfs_read_realloc_races,
500         &sysfs_extent_migrate_done,
501         &sysfs_extent_migrate_raced,
502
503         &sysfs_trigger_journal_flush,
504         &sysfs_trigger_btree_coalesce,
505         &sysfs_trigger_gc,
506         &sysfs_prune_cache,
507
508         &sysfs_copy_gc_enabled,
509         &sysfs_tiering_enabled,
510         sysfs_pd_controller_files(tiering),
511         &sysfs_internal_uuid,
512
513 #define BCH_DEBUG_PARAM(name, description) &sysfs_##name,
514         BCH_DEBUG_PARAMS()
515 #undef BCH_DEBUG_PARAM
516
517         NULL
518 };
519
520 /* options */
521
522 SHOW(bch2_fs_opts_dir)
523 {
524         char *out = buf, *end = buf + PAGE_SIZE;
525         struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
526         const struct bch_option *opt = container_of(attr, struct bch_option, attr);
527         int id = opt - bch2_opt_table;
528         u64 v = bch2_opt_get_by_id(&c->opts, id);
529
530         out += opt->type == BCH_OPT_STR
531                 ? bch2_scnprint_string_list(out, end - out, opt->choices, v)
532                 : scnprintf(out, end - out, "%lli", v);
533         out += scnprintf(out, end - out, "\n");
534
535         return out - buf;
536 }
537
538 STORE(bch2_fs_opts_dir)
539 {
540         struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
541         const struct bch_option *opt = container_of(attr, struct bch_option, attr);
542         int ret, id = opt - bch2_opt_table;
543         u64 v;
544
545         ret = bch2_opt_parse(opt, buf, &v);
546         if (ret < 0)
547                 return ret;
548
549         mutex_lock(&c->sb_lock);
550
551         if (id == Opt_compression) {
552                 int ret = bch2_check_set_has_compressed_data(c, v);
553                 if (ret) {
554                         mutex_unlock(&c->sb_lock);
555                         return ret;
556                 }
557         }
558
559         if (opt->set_sb != SET_NO_SB_OPT) {
560                 opt->set_sb(c->disk_sb, v);
561                 bch2_write_super(c);
562         }
563
564         bch2_opt_set_by_id(&c->opts, id, v);
565
566         mutex_unlock(&c->sb_lock);
567
568         return size;
569 }
570 SYSFS_OPS(bch2_fs_opts_dir);
571
572 struct attribute *bch2_fs_opts_dir_files[] = { NULL };
573
574 int bch2_opts_create_sysfs_files(struct kobject *kobj)
575 {
576         const struct bch_option *i;
577         int ret;
578
579         for (i = bch2_opt_table;
580              i < bch2_opt_table + bch2_opts_nr;
581              i++) {
582                 if (i->mode == OPT_INTERNAL)
583                         continue;
584
585                 ret = sysfs_create_file(kobj, &i->attr);
586                 if (ret)
587                         return ret;
588         }
589
590         return 0;
591 }
592
593 /* time stats */
594
595 SHOW(bch2_fs_time_stats)
596 {
597         struct bch_fs *c = container_of(kobj, struct bch_fs, time_stats);
598
599 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
600         sysfs_print_time_stats(&c->name##_time, name,                   \
601                                frequency_units, duration_units);
602         BCH_TIME_STATS()
603 #undef BCH_TIME_STAT
604
605         return 0;
606 }
607
608 STORE(bch2_fs_time_stats)
609 {
610         struct bch_fs *c = container_of(kobj, struct bch_fs, time_stats);
611
612 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
613         sysfs_clear_time_stats(&c->name##_time, name);
614         BCH_TIME_STATS()
615 #undef BCH_TIME_STAT
616
617         return size;
618 }
619 SYSFS_OPS(bch2_fs_time_stats);
620
621 struct attribute *bch2_fs_time_stats_files[] = {
622 #define BCH_TIME_STAT(name, frequency_units, duration_units)            \
623         sysfs_time_stats_attribute_list(name, frequency_units, duration_units)
624         BCH_TIME_STATS()
625 #undef BCH_TIME_STAT
626
627         NULL
628 };
629
630 typedef unsigned (bucket_map_fn)(struct bch_dev *, size_t, void *);
631
632 static unsigned bucket_priority_fn(struct bch_dev *ca, size_t b,
633                                    void *private)
634 {
635         struct bucket *g = bucket(ca, b);
636         int rw = (private ? 1 : 0);
637
638         return ca->fs->prio_clock[rw].hand - g->prio[rw];
639 }
640
641 static unsigned bucket_sectors_used_fn(struct bch_dev *ca, size_t b,
642                                        void *private)
643 {
644         struct bucket *g = bucket(ca, b);
645         return bucket_sectors_used(g->mark);
646 }
647
648 static unsigned bucket_oldest_gen_fn(struct bch_dev *ca, size_t b,
649                                      void *private)
650 {
651         return bucket_gc_gen(ca, b);
652 }
653
654 static ssize_t show_quantiles(struct bch_dev *ca, char *buf,
655                               bucket_map_fn *fn, void *private)
656 {
657         int cmp(const void *l, const void *r)
658         {       return *((unsigned *) r) - *((unsigned *) l); }
659
660         size_t i, n;
661         /* Compute 31 quantiles */
662         unsigned q[31], *p;
663         ssize_t ret = 0;
664
665         down_read(&ca->bucket_lock);
666         n = ca->mi.nbuckets;
667
668         p = vzalloc(n * sizeof(unsigned));
669         if (!p) {
670                 up_read(&ca->bucket_lock);
671                 return -ENOMEM;
672         }
673
674         for (i = ca->mi.first_bucket; i < n; i++)
675                 p[i] = fn(ca, i, private);
676
677         sort(p, n, sizeof(unsigned), cmp, NULL);
678         up_read(&ca->bucket_lock);
679
680         while (n &&
681                !p[n - 1])
682                 --n;
683
684         for (i = 0; i < ARRAY_SIZE(q); i++)
685                 q[i] = p[n * (i + 1) / (ARRAY_SIZE(q) + 1)];
686
687         vfree(p);
688
689         for (i = 0; i < ARRAY_SIZE(q); i++)
690                 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
691                                  "%u ", q[i]);
692         buf[ret - 1] = '\n';
693
694         return ret;
695 }
696
697 static ssize_t show_reserve_stats(struct bch_dev *ca, char *buf)
698 {
699         enum alloc_reserve i;
700         ssize_t ret;
701
702         spin_lock(&ca->freelist_lock);
703
704         ret = scnprintf(buf, PAGE_SIZE,
705                         "free_inc:\t%zu\t%zu\n",
706                         fifo_used(&ca->free_inc),
707                         ca->free_inc.size);
708
709         for (i = 0; i < RESERVE_NR; i++)
710                 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
711                                  "free[%u]:\t%zu\t%zu\n", i,
712                                  fifo_used(&ca->free[i]),
713                                  ca->free[i].size);
714
715         spin_unlock(&ca->freelist_lock);
716
717         return ret;
718 }
719
720 static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf)
721 {
722         struct bch_fs *c = ca->fs;
723         struct bch_dev_usage stats = bch2_dev_usage_read(c, ca);
724
725         return scnprintf(buf, PAGE_SIZE,
726                 "free_inc:               %zu/%zu\n"
727                 "free[RESERVE_BTREE]:    %zu/%zu\n"
728                 "free[RESERVE_MOVINGGC]: %zu/%zu\n"
729                 "free[RESERVE_NONE]:     %zu/%zu\n"
730                 "buckets:\n"
731                 "    capacity:           %llu\n"
732                 "    alloc:              %llu\n"
733                 "    sb:                 %llu\n"
734                 "    journal:            %llu\n"
735                 "    meta:               %llu\n"
736                 "    user:               %llu\n"
737                 "    cached:             %llu\n"
738                 "    available:          %llu\n"
739                 "sectors:\n"
740                 "    sb:                 %llu\n"
741                 "    journal:            %llu\n"
742                 "    meta:               %llu\n"
743                 "    user:               %llu\n"
744                 "    cached:             %llu\n"
745                 "freelist_wait:          %s\n"
746                 "open buckets:           %u/%u (reserved %u)\n"
747                 "open_buckets_wait:      %s\n",
748                 fifo_used(&ca->free_inc),               ca->free_inc.size,
749                 fifo_used(&ca->free[RESERVE_BTREE]),    ca->free[RESERVE_BTREE].size,
750                 fifo_used(&ca->free[RESERVE_MOVINGGC]), ca->free[RESERVE_MOVINGGC].size,
751                 fifo_used(&ca->free[RESERVE_NONE]),     ca->free[RESERVE_NONE].size,
752                 ca->mi.nbuckets - ca->mi.first_bucket,
753                 stats.buckets_alloc,
754                 stats.buckets[BCH_DATA_SB],
755                 stats.buckets[BCH_DATA_JOURNAL],
756                 stats.buckets[BCH_DATA_BTREE],
757                 stats.buckets[BCH_DATA_USER],
758                 stats.buckets[BCH_DATA_CACHED],
759                 __dev_buckets_available(ca, stats),
760                 stats.sectors[BCH_DATA_SB],
761                 stats.sectors[BCH_DATA_JOURNAL],
762                 stats.sectors[BCH_DATA_BTREE],
763                 stats.sectors[BCH_DATA_USER],
764                 stats.sectors[BCH_DATA_CACHED],
765                 c->freelist_wait.list.first             ? "waiting" : "empty",
766                 c->open_buckets_nr_free, OPEN_BUCKETS_COUNT, BTREE_NODE_RESERVE,
767                 c->open_buckets_wait.list.first         ? "waiting" : "empty");
768 }
769
770 static const char * const bch2_rw[] = {
771         "read",
772         "write",
773         NULL
774 };
775
776 static ssize_t show_dev_iostats(struct bch_dev *ca, char *buf)
777 {
778         char *out = buf, *end = buf + PAGE_SIZE;
779         int rw, i, cpu;
780
781         for (rw = 0; rw < 2; rw++) {
782                 out += scnprintf(out, end - out, "%s:\n", bch2_rw[rw]);
783
784                 for (i = 1; i < BCH_DATA_NR; i++) {
785                         u64 n = 0;
786
787                         for_each_possible_cpu(cpu)
788                                 n += per_cpu_ptr(ca->io_done, cpu)->sectors[rw][i];
789
790                         out += scnprintf(out, end - out, "%-12s:%12llu\n",
791                                          bch2_data_types[i], n << 9);
792                 }
793         }
794
795         return out - buf;
796 }
797
798 SHOW(bch2_dev)
799 {
800         struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
801         struct bch_fs *c = ca->fs;
802         char *out = buf, *end = buf + PAGE_SIZE;
803
804         sysfs_printf(uuid,              "%pU\n", ca->uuid.b);
805
806         sysfs_print(bucket_size,        bucket_bytes(ca));
807         sysfs_print(block_size,         block_bytes(c));
808         sysfs_print(first_bucket,       ca->mi.first_bucket);
809         sysfs_print(nbuckets,           ca->mi.nbuckets);
810         sysfs_print(discard,            ca->mi.discard);
811
812         if (attr == &sysfs_has_data) {
813                 out += bch2_scnprint_flag_list(out, end - out,
814                                                bch2_data_types,
815                                                bch2_dev_has_data(c, ca));
816                 out += scnprintf(out, end - out, "\n");
817                 return out - buf;
818         }
819
820         sysfs_pd_controller_show(copy_gc, &ca->copygc_pd);
821
822         if (attr == &sysfs_cache_replacement_policy) {
823                 out += bch2_scnprint_string_list(out, end - out,
824                                                  bch2_cache_replacement_policies,
825                                                  ca->mi.replacement);
826                 out += scnprintf(out, end - out, "\n");
827                 return out - buf;
828         }
829
830         sysfs_print(tier,               ca->mi.tier);
831
832         if (attr == &sysfs_state_rw) {
833                 out += bch2_scnprint_string_list(out, end - out,
834                                                  bch2_dev_state,
835                                                  ca->mi.state);
836                 out += scnprintf(out, end - out, "\n");
837                 return out - buf;
838         }
839
840         if (attr == &sysfs_iostats)
841                 return show_dev_iostats(ca, buf);
842         if (attr == &sysfs_read_priority_stats)
843                 return show_quantiles(ca, buf, bucket_priority_fn, (void *) 0);
844         if (attr == &sysfs_write_priority_stats)
845                 return show_quantiles(ca, buf, bucket_priority_fn, (void *) 1);
846         if (attr == &sysfs_fragmentation_stats)
847                 return show_quantiles(ca, buf, bucket_sectors_used_fn, NULL);
848         if (attr == &sysfs_oldest_gen_stats)
849                 return show_quantiles(ca, buf, bucket_oldest_gen_fn, NULL);
850         if (attr == &sysfs_reserve_stats)
851                 return show_reserve_stats(ca, buf);
852         if (attr == &sysfs_alloc_debug)
853                 return show_dev_alloc_debug(ca, buf);
854
855         return 0;
856 }
857
858 STORE(bch2_dev)
859 {
860         struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
861         struct bch_fs *c = ca->fs;
862         struct bch_member *mi;
863
864         sysfs_pd_controller_store(copy_gc, &ca->copygc_pd);
865
866         if (attr == &sysfs_discard) {
867                 bool v = strtoul_or_return(buf);
868
869                 mutex_lock(&c->sb_lock);
870                 mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
871
872                 if (v != BCH_MEMBER_DISCARD(mi)) {
873                         SET_BCH_MEMBER_DISCARD(mi, v);
874                         bch2_write_super(c);
875                 }
876                 mutex_unlock(&c->sb_lock);
877         }
878
879         if (attr == &sysfs_cache_replacement_policy) {
880                 ssize_t v = bch2_read_string_list(buf, bch2_cache_replacement_policies);
881
882                 if (v < 0)
883                         return v;
884
885                 mutex_lock(&c->sb_lock);
886                 mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
887
888                 if ((unsigned) v != BCH_MEMBER_REPLACEMENT(mi)) {
889                         SET_BCH_MEMBER_REPLACEMENT(mi, v);
890                         bch2_write_super(c);
891                 }
892                 mutex_unlock(&c->sb_lock);
893         }
894
895         if (attr == &sysfs_tier) {
896                 unsigned prev_tier;
897                 unsigned v = strtoul_restrict_or_return(buf,
898                                         0, BCH_TIER_MAX - 1);
899
900                 mutex_lock(&c->sb_lock);
901                 prev_tier = ca->mi.tier;
902
903                 if (v == ca->mi.tier) {
904                         mutex_unlock(&c->sb_lock);
905                         return size;
906                 }
907
908                 mi = &bch2_sb_get_members(c->disk_sb)->members[ca->dev_idx];
909                 SET_BCH_MEMBER_TIER(mi, v);
910                 bch2_write_super(c);
911
912                 clear_bit(ca->dev_idx, c->tiers[prev_tier].devs.d);
913                 set_bit(ca->dev_idx, c->tiers[ca->mi.tier].devs.d);
914                 mutex_unlock(&c->sb_lock);
915
916                 bch2_recalc_capacity(c);
917                 bch2_tiering_start(c);
918         }
919
920         if (attr == &sysfs_wake_allocator)
921                 bch2_wake_allocator(ca);
922
923         return size;
924 }
925 SYSFS_OPS(bch2_dev);
926
927 struct attribute *bch2_dev_files[] = {
928         &sysfs_uuid,
929         &sysfs_bucket_size,
930         &sysfs_block_size,
931         &sysfs_first_bucket,
932         &sysfs_nbuckets,
933
934         /* settings: */
935         &sysfs_discard,
936         &sysfs_cache_replacement_policy,
937         &sysfs_tier,
938         &sysfs_state_rw,
939
940         &sysfs_has_data,
941         &sysfs_iostats,
942
943         /* alloc info - other stats: */
944         &sysfs_read_priority_stats,
945         &sysfs_write_priority_stats,
946         &sysfs_fragmentation_stats,
947         &sysfs_oldest_gen_stats,
948         &sysfs_reserve_stats,
949
950         /* debug: */
951         &sysfs_alloc_debug,
952         &sysfs_wake_allocator,
953
954         sysfs_pd_controller_files(copy_gc),
955         NULL
956 };
957
958 #endif  /* _BCACHEFS_SYSFS_H_ */