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