Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * bcache sysfs interfaces
4 *
5 * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
6 * Copyright 2012 Google, Inc.
7 */
8
9#ifndef NO_BCACHEFS_SYSFS
10
11#include "bcachefs.h"
12#include "alloc_background.h"
13#include "alloc_foreground.h"
14#include "sysfs.h"
15#include "btree_cache.h"
16#include "btree_io.h"
17#include "btree_iter.h"
18#include "btree_key_cache.h"
19#include "btree_update.h"
20#include "btree_gc.h"
21#include "buckets.h"
22#include "clock.h"
23#include "compress.h"
24#include "disk_groups.h"
25#include "ec.h"
26#include "inode.h"
27#include "journal.h"
28#include "journal_reclaim.h"
29#include "keylist.h"
30#include "move.h"
31#include "movinggc.h"
32#include "nocow_locking.h"
33#include "opts.h"
34#include "rebalance.h"
35#include "replicas.h"
36#include "super-io.h"
37#include "tests.h"
38
39#include <linux/blkdev.h>
40#include <linux/sort.h>
41#include <linux/sched/clock.h>
42
43#include "util.h"
44
45#define SYSFS_OPS(type) \
46const struct sysfs_ops type ## _sysfs_ops = { \
47 .show = type ## _show, \
48 .store = type ## _store \
49}
50
51#define SHOW(fn) \
52static ssize_t fn ## _to_text(struct printbuf *, \
53 struct kobject *, struct attribute *); \
54 \
55static ssize_t fn ## _show(struct kobject *kobj, struct attribute *attr,\
56 char *buf) \
57{ \
58 struct printbuf out = PRINTBUF; \
59 ssize_t ret = fn ## _to_text(&out, kobj, attr); \
60 \
61 if (out.pos && out.buf[out.pos - 1] != '\n') \
62 prt_newline(&out); \
63 \
64 if (!ret && out.allocation_failure) \
65 ret = -ENOMEM; \
66 \
67 if (!ret) { \
68 ret = min_t(size_t, out.pos, PAGE_SIZE - 1); \
69 memcpy(buf, out.buf, ret); \
70 } \
71 printbuf_exit(&out); \
72 return bch2_err_class(ret); \
73} \
74 \
75static ssize_t fn ## _to_text(struct printbuf *out, struct kobject *kobj,\
76 struct attribute *attr)
77
78#define STORE(fn) \
79static ssize_t fn ## _store_inner(struct kobject *, struct attribute *,\
80 const char *, size_t); \
81 \
82static ssize_t fn ## _store(struct kobject *kobj, struct attribute *attr,\
83 const char *buf, size_t size) \
84{ \
85 return bch2_err_class(fn##_store_inner(kobj, attr, buf, size)); \
86} \
87 \
88static ssize_t fn ## _store_inner(struct kobject *kobj, struct attribute *attr,\
89 const char *buf, size_t size)
90
91#define __sysfs_attribute(_name, _mode) \
92 static struct attribute sysfs_##_name = \
93 { .name = #_name, .mode = _mode }
94
95#define write_attribute(n) __sysfs_attribute(n, 0200)
96#define read_attribute(n) __sysfs_attribute(n, 0444)
97#define rw_attribute(n) __sysfs_attribute(n, 0644)
98
99#define sysfs_printf(file, fmt, ...) \
100do { \
101 if (attr == &sysfs_ ## file) \
102 prt_printf(out, fmt "\n", __VA_ARGS__); \
103} while (0)
104
105#define sysfs_print(file, var) \
106do { \
107 if (attr == &sysfs_ ## file) \
108 snprint(out, var); \
109} while (0)
110
111#define sysfs_hprint(file, val) \
112do { \
113 if (attr == &sysfs_ ## file) \
114 prt_human_readable_s64(out, val); \
115} while (0)
116
117#define sysfs_strtoul(file, var) \
118do { \
119 if (attr == &sysfs_ ## file) \
120 return strtoul_safe(buf, var) ?: (ssize_t) size; \
121} while (0)
122
123#define sysfs_strtoul_clamp(file, var, min, max) \
124do { \
125 if (attr == &sysfs_ ## file) \
126 return strtoul_safe_clamp(buf, var, min, max) \
127 ?: (ssize_t) size; \
128} while (0)
129
130#define strtoul_or_return(cp) \
131({ \
132 unsigned long _v; \
133 int _r = kstrtoul(cp, 10, &_v); \
134 if (_r) \
135 return _r; \
136 _v; \
137})
138
139write_attribute(trigger_gc);
140write_attribute(trigger_discards);
141write_attribute(trigger_invalidates);
142write_attribute(trigger_journal_flush);
143write_attribute(trigger_btree_cache_shrink);
144write_attribute(trigger_btree_key_cache_shrink);
145rw_attribute(gc_gens_pos);
146
147read_attribute(uuid);
148read_attribute(minor);
149read_attribute(flags);
150read_attribute(bucket_size);
151read_attribute(first_bucket);
152read_attribute(nbuckets);
153rw_attribute(durability);
154read_attribute(io_done);
155read_attribute(io_errors);
156write_attribute(io_errors_reset);
157
158read_attribute(io_latency_read);
159read_attribute(io_latency_write);
160read_attribute(io_latency_stats_read);
161read_attribute(io_latency_stats_write);
162read_attribute(congested);
163
164read_attribute(btree_write_stats);
165
166read_attribute(btree_cache_size);
167read_attribute(compression_stats);
168read_attribute(journal_debug);
169read_attribute(btree_cache);
170read_attribute(btree_key_cache);
171read_attribute(stripes_heap);
172read_attribute(open_buckets);
173read_attribute(open_buckets_partial);
174read_attribute(write_points);
175read_attribute(nocow_lock_table);
176
177#ifdef BCH_WRITE_REF_DEBUG
178read_attribute(write_refs);
179
180static const char * const bch2_write_refs[] = {
181#define x(n) #n,
182 BCH_WRITE_REFS()
183#undef x
184 NULL
185};
186
187static void bch2_write_refs_to_text(struct printbuf *out, struct bch_fs *c)
188{
189 bch2_printbuf_tabstop_push(out, 24);
190
191 for (unsigned i = 0; i < ARRAY_SIZE(c->writes); i++)
192 prt_printf(out, "%s\t%li\n", bch2_write_refs[i], atomic_long_read(&c->writes[i]));
193}
194#endif
195
196read_attribute(internal_uuid);
197read_attribute(disk_groups);
198
199read_attribute(has_data);
200read_attribute(alloc_debug);
201
202#define x(t, n, ...) read_attribute(t);
203BCH_PERSISTENT_COUNTERS()
204#undef x
205
206rw_attribute(discard);
207rw_attribute(label);
208
209rw_attribute(copy_gc_enabled);
210read_attribute(copy_gc_wait);
211
212rw_attribute(rebalance_enabled);
213sysfs_pd_controller_attribute(rebalance);
214read_attribute(rebalance_status);
215rw_attribute(promote_whole_extents);
216
217read_attribute(new_stripes);
218
219read_attribute(io_timers_read);
220read_attribute(io_timers_write);
221
222read_attribute(moving_ctxts);
223
224#ifdef CONFIG_BCACHEFS_TESTS
225write_attribute(perf_test);
226#endif /* CONFIG_BCACHEFS_TESTS */
227
228#define x(_name) \
229 static struct attribute sysfs_time_stat_##_name = \
230 { .name = #_name, .mode = 0444 };
231 BCH_TIME_STATS()
232#undef x
233
234static struct attribute sysfs_state_rw = {
235 .name = "state",
236 .mode = 0444,
237};
238
239static size_t bch2_btree_cache_size(struct bch_fs *c)
240{
241 size_t ret = 0;
242 struct btree *b;
243
244 mutex_lock(&c->btree_cache.lock);
245 list_for_each_entry(b, &c->btree_cache.live, list)
246 ret += btree_buf_bytes(b);
247
248 mutex_unlock(&c->btree_cache.lock);
249 return ret;
250}
251
252static int bch2_compression_stats_to_text(struct printbuf *out, struct bch_fs *c)
253{
254 struct btree_trans *trans;
255 enum btree_id id;
256 struct compression_type_stats {
257 u64 nr_extents;
258 u64 sectors_compressed;
259 u64 sectors_uncompressed;
260 } s[BCH_COMPRESSION_TYPE_NR];
261 u64 compressed_incompressible = 0;
262 int ret = 0;
263
264 memset(s, 0, sizeof(s));
265
266 if (!test_bit(BCH_FS_started, &c->flags))
267 return -EPERM;
268
269 trans = bch2_trans_get(c);
270
271 for (id = 0; id < BTREE_ID_NR; id++) {
272 if (!btree_type_has_ptrs(id))
273 continue;
274
275 ret = for_each_btree_key(trans, iter, id, POS_MIN,
276 BTREE_ITER_all_snapshots, k, ({
277 struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
278 struct bch_extent_crc_unpacked crc;
279 const union bch_extent_entry *entry;
280 bool compressed = false, incompressible = false;
281
282 bkey_for_each_crc(k.k, ptrs, crc, entry) {
283 incompressible |= crc.compression_type == BCH_COMPRESSION_TYPE_incompressible;
284 compressed |= crc_is_compressed(crc);
285
286 if (crc_is_compressed(crc)) {
287 s[crc.compression_type].nr_extents++;
288 s[crc.compression_type].sectors_compressed += crc.compressed_size;
289 s[crc.compression_type].sectors_uncompressed += crc.uncompressed_size;
290 }
291 }
292
293 compressed_incompressible += compressed && incompressible;
294
295 if (!compressed) {
296 unsigned t = incompressible ? BCH_COMPRESSION_TYPE_incompressible : 0;
297
298 s[t].nr_extents++;
299 s[t].sectors_compressed += k.k->size;
300 s[t].sectors_uncompressed += k.k->size;
301 }
302 0;
303 }));
304 }
305
306 bch2_trans_put(trans);
307
308 if (ret)
309 return ret;
310
311 printbuf_tabstop_push(out, 12);
312 printbuf_tabstop_push(out, 16);
313 printbuf_tabstop_push(out, 16);
314 printbuf_tabstop_push(out, 24);
315 prt_printf(out, "type\tcompressed\runcompressed\raverage extent size\r\n");
316
317 for (unsigned i = 0; i < ARRAY_SIZE(s); i++) {
318 bch2_prt_compression_type(out, i);
319 prt_tab(out);
320
321 prt_human_readable_u64(out, s[i].sectors_compressed << 9);
322 prt_tab_rjust(out);
323
324 prt_human_readable_u64(out, s[i].sectors_uncompressed << 9);
325 prt_tab_rjust(out);
326
327 prt_human_readable_u64(out, s[i].nr_extents
328 ? div_u64(s[i].sectors_uncompressed << 9, s[i].nr_extents)
329 : 0);
330 prt_tab_rjust(out);
331 prt_newline(out);
332 }
333
334 if (compressed_incompressible) {
335 prt_printf(out, "%llu compressed & incompressible extents", compressed_incompressible);
336 prt_newline(out);
337 }
338
339 return 0;
340}
341
342static void bch2_gc_gens_pos_to_text(struct printbuf *out, struct bch_fs *c)
343{
344 prt_printf(out, "%s: ", bch2_btree_id_str(c->gc_gens_btree));
345 bch2_bpos_to_text(out, c->gc_gens_pos);
346 prt_printf(out, "\n");
347}
348
349SHOW(bch2_fs)
350{
351 struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
352
353 sysfs_print(minor, c->minor);
354 sysfs_printf(internal_uuid, "%pU", c->sb.uuid.b);
355
356 if (attr == &sysfs_flags)
357 prt_bitflags(out, bch2_fs_flag_strs, c->flags);
358
359 sysfs_hprint(btree_cache_size, bch2_btree_cache_size(c));
360
361 if (attr == &sysfs_btree_write_stats)
362 bch2_btree_write_stats_to_text(out, c);
363
364 if (attr == &sysfs_gc_gens_pos)
365 bch2_gc_gens_pos_to_text(out, c);
366
367 sysfs_printf(copy_gc_enabled, "%i", c->copy_gc_enabled);
368
369 sysfs_printf(rebalance_enabled, "%i", c->rebalance.enabled);
370 sysfs_pd_controller_show(rebalance, &c->rebalance.pd); /* XXX */
371
372 if (attr == &sysfs_copy_gc_wait)
373 bch2_copygc_wait_to_text(out, c);
374
375 if (attr == &sysfs_rebalance_status)
376 bch2_rebalance_status_to_text(out, c);
377
378 sysfs_print(promote_whole_extents, c->promote_whole_extents);
379
380 /* Debugging: */
381
382 if (attr == &sysfs_journal_debug)
383 bch2_journal_debug_to_text(out, &c->journal);
384
385 if (attr == &sysfs_btree_cache)
386 bch2_btree_cache_to_text(out, &c->btree_cache);
387
388 if (attr == &sysfs_btree_key_cache)
389 bch2_btree_key_cache_to_text(out, &c->btree_key_cache);
390
391 if (attr == &sysfs_stripes_heap)
392 bch2_stripes_heap_to_text(out, c);
393
394 if (attr == &sysfs_open_buckets)
395 bch2_open_buckets_to_text(out, c);
396
397 if (attr == &sysfs_open_buckets_partial)
398 bch2_open_buckets_partial_to_text(out, c);
399
400 if (attr == &sysfs_write_points)
401 bch2_write_points_to_text(out, c);
402
403 if (attr == &sysfs_compression_stats)
404 bch2_compression_stats_to_text(out, c);
405
406 if (attr == &sysfs_new_stripes)
407 bch2_new_stripes_to_text(out, c);
408
409 if (attr == &sysfs_io_timers_read)
410 bch2_io_timers_to_text(out, &c->io_clock[READ]);
411
412 if (attr == &sysfs_io_timers_write)
413 bch2_io_timers_to_text(out, &c->io_clock[WRITE]);
414
415 if (attr == &sysfs_moving_ctxts)
416 bch2_fs_moving_ctxts_to_text(out, c);
417
418#ifdef BCH_WRITE_REF_DEBUG
419 if (attr == &sysfs_write_refs)
420 bch2_write_refs_to_text(out, c);
421#endif
422
423 if (attr == &sysfs_nocow_lock_table)
424 bch2_nocow_locks_to_text(out, &c->nocow_locks);
425
426 if (attr == &sysfs_disk_groups)
427 bch2_disk_groups_to_text(out, c);
428
429 if (attr == &sysfs_alloc_debug)
430 bch2_fs_alloc_debug_to_text(out, c);
431
432 return 0;
433}
434
435STORE(bch2_fs)
436{
437 struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
438
439 if (attr == &sysfs_copy_gc_enabled) {
440 ssize_t ret = strtoul_safe(buf, c->copy_gc_enabled)
441 ?: (ssize_t) size;
442
443 if (c->copygc_thread)
444 wake_up_process(c->copygc_thread);
445 return ret;
446 }
447
448 if (attr == &sysfs_rebalance_enabled) {
449 ssize_t ret = strtoul_safe(buf, c->rebalance.enabled)
450 ?: (ssize_t) size;
451
452 rebalance_wakeup(c);
453 return ret;
454 }
455
456 sysfs_pd_controller_store(rebalance, &c->rebalance.pd);
457
458 sysfs_strtoul(promote_whole_extents, c->promote_whole_extents);
459
460 /* Debugging: */
461
462 if (!test_bit(BCH_FS_started, &c->flags))
463 return -EPERM;
464
465 /* Debugging: */
466
467 if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_sysfs))
468 return -EROFS;
469
470 if (attr == &sysfs_trigger_btree_cache_shrink) {
471 struct shrink_control sc;
472
473 sc.gfp_mask = GFP_KERNEL;
474 sc.nr_to_scan = strtoul_or_return(buf);
475 c->btree_cache.shrink->scan_objects(c->btree_cache.shrink, &sc);
476 }
477
478 if (attr == &sysfs_trigger_btree_key_cache_shrink) {
479 struct shrink_control sc;
480
481 sc.gfp_mask = GFP_KERNEL;
482 sc.nr_to_scan = strtoul_or_return(buf);
483 c->btree_key_cache.shrink->scan_objects(c->btree_cache.shrink, &sc);
484 }
485
486 if (attr == &sysfs_trigger_gc)
487 bch2_gc_gens(c);
488
489 if (attr == &sysfs_trigger_discards)
490 bch2_do_discards(c);
491
492 if (attr == &sysfs_trigger_invalidates)
493 bch2_do_invalidates(c);
494
495 if (attr == &sysfs_trigger_journal_flush) {
496 bch2_journal_flush_all_pins(&c->journal);
497 bch2_journal_meta(&c->journal);
498 }
499
500#ifdef CONFIG_BCACHEFS_TESTS
501 if (attr == &sysfs_perf_test) {
502 char *tmp = kstrdup(buf, GFP_KERNEL), *p = tmp;
503 char *test = strsep(&p, " \t\n");
504 char *nr_str = strsep(&p, " \t\n");
505 char *threads_str = strsep(&p, " \t\n");
506 unsigned threads;
507 u64 nr;
508 int ret = -EINVAL;
509
510 if (threads_str &&
511 !(ret = kstrtouint(threads_str, 10, &threads)) &&
512 !(ret = bch2_strtoull_h(nr_str, &nr)))
513 ret = bch2_btree_perf_test(c, test, nr, threads);
514 kfree(tmp);
515
516 if (ret)
517 size = ret;
518 }
519#endif
520 bch2_write_ref_put(c, BCH_WRITE_REF_sysfs);
521 return size;
522}
523SYSFS_OPS(bch2_fs);
524
525struct attribute *bch2_fs_files[] = {
526 &sysfs_minor,
527 &sysfs_btree_cache_size,
528 &sysfs_btree_write_stats,
529
530 &sysfs_promote_whole_extents,
531
532 &sysfs_compression_stats,
533
534#ifdef CONFIG_BCACHEFS_TESTS
535 &sysfs_perf_test,
536#endif
537 NULL
538};
539
540/* counters dir */
541
542SHOW(bch2_fs_counters)
543{
544 struct bch_fs *c = container_of(kobj, struct bch_fs, counters_kobj);
545 u64 counter = 0;
546 u64 counter_since_mount = 0;
547
548 printbuf_tabstop_push(out, 32);
549
550 #define x(t, ...) \
551 if (attr == &sysfs_##t) { \
552 counter = percpu_u64_get(&c->counters[BCH_COUNTER_##t]);\
553 counter_since_mount = counter - c->counters_on_mount[BCH_COUNTER_##t];\
554 prt_printf(out, "since mount:\t"); \
555 prt_human_readable_u64(out, counter_since_mount); \
556 prt_newline(out); \
557 \
558 prt_printf(out, "since filesystem creation:\t"); \
559 prt_human_readable_u64(out, counter); \
560 prt_newline(out); \
561 }
562 BCH_PERSISTENT_COUNTERS()
563 #undef x
564 return 0;
565}
566
567STORE(bch2_fs_counters) {
568 return 0;
569}
570
571SYSFS_OPS(bch2_fs_counters);
572
573struct attribute *bch2_fs_counters_files[] = {
574#define x(t, ...) \
575 &sysfs_##t,
576 BCH_PERSISTENT_COUNTERS()
577#undef x
578 NULL
579};
580/* internal dir - just a wrapper */
581
582SHOW(bch2_fs_internal)
583{
584 struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
585
586 return bch2_fs_to_text(out, &c->kobj, attr);
587}
588
589STORE(bch2_fs_internal)
590{
591 struct bch_fs *c = container_of(kobj, struct bch_fs, internal);
592
593 return bch2_fs_store(&c->kobj, attr, buf, size);
594}
595SYSFS_OPS(bch2_fs_internal);
596
597struct attribute *bch2_fs_internal_files[] = {
598 &sysfs_flags,
599 &sysfs_journal_debug,
600 &sysfs_btree_cache,
601 &sysfs_btree_key_cache,
602 &sysfs_new_stripes,
603 &sysfs_stripes_heap,
604 &sysfs_open_buckets,
605 &sysfs_open_buckets_partial,
606 &sysfs_write_points,
607#ifdef BCH_WRITE_REF_DEBUG
608 &sysfs_write_refs,
609#endif
610 &sysfs_nocow_lock_table,
611 &sysfs_io_timers_read,
612 &sysfs_io_timers_write,
613
614 &sysfs_trigger_gc,
615 &sysfs_trigger_discards,
616 &sysfs_trigger_invalidates,
617 &sysfs_trigger_journal_flush,
618 &sysfs_trigger_btree_cache_shrink,
619 &sysfs_trigger_btree_key_cache_shrink,
620
621 &sysfs_gc_gens_pos,
622
623 &sysfs_copy_gc_enabled,
624 &sysfs_copy_gc_wait,
625
626 &sysfs_rebalance_enabled,
627 &sysfs_rebalance_status,
628 sysfs_pd_controller_files(rebalance),
629
630 &sysfs_moving_ctxts,
631
632 &sysfs_internal_uuid,
633
634 &sysfs_disk_groups,
635 &sysfs_alloc_debug,
636 NULL
637};
638
639/* options */
640
641SHOW(bch2_fs_opts_dir)
642{
643 struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
644 const struct bch_option *opt = container_of(attr, struct bch_option, attr);
645 int id = opt - bch2_opt_table;
646 u64 v = bch2_opt_get_by_id(&c->opts, id);
647
648 bch2_opt_to_text(out, c, c->disk_sb.sb, opt, v, OPT_SHOW_FULL_LIST);
649 prt_char(out, '\n');
650
651 return 0;
652}
653
654STORE(bch2_fs_opts_dir)
655{
656 struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
657 const struct bch_option *opt = container_of(attr, struct bch_option, attr);
658 int ret, id = opt - bch2_opt_table;
659 char *tmp;
660 u64 v;
661
662 /*
663 * We don't need to take c->writes for correctness, but it eliminates an
664 * unsightly error message in the dmesg log when we're RO:
665 */
666 if (unlikely(!bch2_write_ref_tryget(c, BCH_WRITE_REF_sysfs)))
667 return -EROFS;
668
669 tmp = kstrdup(buf, GFP_KERNEL);
670 if (!tmp) {
671 ret = -ENOMEM;
672 goto err;
673 }
674
675 ret = bch2_opt_parse(c, opt, strim(tmp), &v, NULL);
676 kfree(tmp);
677
678 if (ret < 0)
679 goto err;
680
681 ret = bch2_opt_check_may_set(c, id, v);
682 if (ret < 0)
683 goto err;
684
685 bch2_opt_set_sb(c, opt, v);
686 bch2_opt_set_by_id(&c->opts, id, v);
687
688 if (v &&
689 (id == Opt_background_target ||
690 id == Opt_background_compression ||
691 (id == Opt_compression && !c->opts.background_compression)))
692 bch2_set_rebalance_needs_scan(c, 0);
693
694 ret = size;
695err:
696 bch2_write_ref_put(c, BCH_WRITE_REF_sysfs);
697 return ret;
698}
699SYSFS_OPS(bch2_fs_opts_dir);
700
701struct attribute *bch2_fs_opts_dir_files[] = { NULL };
702
703int bch2_opts_create_sysfs_files(struct kobject *kobj)
704{
705 const struct bch_option *i;
706 int ret;
707
708 for (i = bch2_opt_table;
709 i < bch2_opt_table + bch2_opts_nr;
710 i++) {
711 if (!(i->flags & OPT_FS))
712 continue;
713
714 ret = sysfs_create_file(kobj, &i->attr);
715 if (ret)
716 return ret;
717 }
718
719 return 0;
720}
721
722/* time stats */
723
724SHOW(bch2_fs_time_stats)
725{
726 struct bch_fs *c = container_of(kobj, struct bch_fs, time_stats);
727
728#define x(name) \
729 if (attr == &sysfs_time_stat_##name) \
730 bch2_time_stats_to_text(out, &c->times[BCH_TIME_##name]);
731 BCH_TIME_STATS()
732#undef x
733
734 return 0;
735}
736
737STORE(bch2_fs_time_stats)
738{
739 return size;
740}
741SYSFS_OPS(bch2_fs_time_stats);
742
743struct attribute *bch2_fs_time_stats_files[] = {
744#define x(name) \
745 &sysfs_time_stat_##name,
746 BCH_TIME_STATS()
747#undef x
748 NULL
749};
750
751static const char * const bch2_rw[] = {
752 "read",
753 "write",
754 NULL
755};
756
757static void dev_io_done_to_text(struct printbuf *out, struct bch_dev *ca)
758{
759 int rw, i;
760
761 for (rw = 0; rw < 2; rw++) {
762 prt_printf(out, "%s:\n", bch2_rw[rw]);
763
764 for (i = 1; i < BCH_DATA_NR; i++)
765 prt_printf(out, "%-12s:%12llu\n",
766 bch2_data_type_str(i),
767 percpu_u64_get(&ca->io_done->sectors[rw][i]) << 9);
768 }
769}
770
771SHOW(bch2_dev)
772{
773 struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
774 struct bch_fs *c = ca->fs;
775
776 sysfs_printf(uuid, "%pU\n", ca->uuid.b);
777
778 sysfs_print(bucket_size, bucket_bytes(ca));
779 sysfs_print(first_bucket, ca->mi.first_bucket);
780 sysfs_print(nbuckets, ca->mi.nbuckets);
781 sysfs_print(durability, ca->mi.durability);
782 sysfs_print(discard, ca->mi.discard);
783
784 if (attr == &sysfs_label) {
785 if (ca->mi.group)
786 bch2_disk_path_to_text(out, c, ca->mi.group - 1);
787 prt_char(out, '\n');
788 }
789
790 if (attr == &sysfs_has_data) {
791 prt_bitflags(out, __bch2_data_types, bch2_dev_has_data(c, ca));
792 prt_char(out, '\n');
793 }
794
795 if (attr == &sysfs_state_rw) {
796 prt_string_option(out, bch2_member_states, ca->mi.state);
797 prt_char(out, '\n');
798 }
799
800 if (attr == &sysfs_io_done)
801 dev_io_done_to_text(out, ca);
802
803 if (attr == &sysfs_io_errors)
804 bch2_dev_io_errors_to_text(out, ca);
805
806 sysfs_print(io_latency_read, atomic64_read(&ca->cur_latency[READ]));
807 sysfs_print(io_latency_write, atomic64_read(&ca->cur_latency[WRITE]));
808
809 if (attr == &sysfs_io_latency_stats_read)
810 bch2_time_stats_to_text(out, &ca->io_latency[READ].stats);
811
812 if (attr == &sysfs_io_latency_stats_write)
813 bch2_time_stats_to_text(out, &ca->io_latency[WRITE].stats);
814
815 sysfs_printf(congested, "%u%%",
816 clamp(atomic_read(&ca->congested), 0, CONGESTED_MAX)
817 * 100 / CONGESTED_MAX);
818
819 if (attr == &sysfs_alloc_debug)
820 bch2_dev_alloc_debug_to_text(out, ca);
821
822 return 0;
823}
824
825STORE(bch2_dev)
826{
827 struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj);
828 struct bch_fs *c = ca->fs;
829 struct bch_member *mi;
830
831 if (attr == &sysfs_discard) {
832 bool v = strtoul_or_return(buf);
833
834 mutex_lock(&c->sb_lock);
835 mi = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
836
837 if (v != BCH_MEMBER_DISCARD(mi)) {
838 SET_BCH_MEMBER_DISCARD(mi, v);
839 bch2_write_super(c);
840 }
841 mutex_unlock(&c->sb_lock);
842 }
843
844 if (attr == &sysfs_durability) {
845 u64 v = strtoul_or_return(buf);
846
847 mutex_lock(&c->sb_lock);
848 mi = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
849
850 if (v + 1 != BCH_MEMBER_DURABILITY(mi)) {
851 SET_BCH_MEMBER_DURABILITY(mi, v + 1);
852 bch2_write_super(c);
853 }
854 mutex_unlock(&c->sb_lock);
855 }
856
857 if (attr == &sysfs_label) {
858 char *tmp;
859 int ret;
860
861 tmp = kstrdup(buf, GFP_KERNEL);
862 if (!tmp)
863 return -ENOMEM;
864
865 ret = bch2_dev_group_set(c, ca, strim(tmp));
866 kfree(tmp);
867 if (ret)
868 return ret;
869 }
870
871 if (attr == &sysfs_io_errors_reset)
872 bch2_dev_errors_reset(ca);
873
874 return size;
875}
876SYSFS_OPS(bch2_dev);
877
878struct attribute *bch2_dev_files[] = {
879 &sysfs_uuid,
880 &sysfs_bucket_size,
881 &sysfs_first_bucket,
882 &sysfs_nbuckets,
883 &sysfs_durability,
884
885 /* settings: */
886 &sysfs_discard,
887 &sysfs_state_rw,
888 &sysfs_label,
889
890 &sysfs_has_data,
891 &sysfs_io_done,
892 &sysfs_io_errors,
893 &sysfs_io_errors_reset,
894
895 &sysfs_io_latency_read,
896 &sysfs_io_latency_write,
897 &sysfs_io_latency_stats_read,
898 &sysfs_io_latency_stats_write,
899 &sysfs_congested,
900
901 /* debug: */
902 &sysfs_alloc_debug,
903 NULL
904};
905
906#endif /* _BCACHEFS_SYSFS_H_ */