.. | .. |
---|
11 | 11 | #include "btree.h" |
---|
12 | 12 | #include "request.h" |
---|
13 | 13 | #include "writeback.h" |
---|
| 14 | +#include "features.h" |
---|
14 | 15 | |
---|
15 | 16 | #include <linux/blkdev.h> |
---|
16 | 17 | #include <linux/sort.h> |
---|
17 | 18 | #include <linux/sched/clock.h> |
---|
18 | 19 | |
---|
19 | | -/* Default is -1; we skip past it for struct cached_dev's cache mode */ |
---|
| 20 | +extern bool bcache_is_reboot; |
---|
| 21 | + |
---|
| 22 | +/* Default is 0 ("writethrough") */ |
---|
20 | 23 | static const char * const bch_cache_modes[] = { |
---|
21 | 24 | "writethrough", |
---|
22 | 25 | "writeback", |
---|
.. | .. |
---|
31 | 34 | NULL |
---|
32 | 35 | }; |
---|
33 | 36 | |
---|
34 | | -/* Default is -1; we skip past it for stop_when_cache_set_failed */ |
---|
| 37 | +/* Default is 0 ("auto") */ |
---|
35 | 38 | static const char * const bch_stop_on_failure_modes[] = { |
---|
36 | 39 | "auto", |
---|
37 | 40 | "always", |
---|
.. | .. |
---|
73 | 76 | read_attribute(btree_written); |
---|
74 | 77 | read_attribute(metadata_written); |
---|
75 | 78 | read_attribute(active_journal_entries); |
---|
| 79 | +read_attribute(backing_dev_name); |
---|
| 80 | +read_attribute(backing_dev_uuid); |
---|
76 | 81 | |
---|
77 | 82 | sysfs_time_stats_attribute(btree_gc, sec, ms); |
---|
78 | 83 | sysfs_time_stats_attribute(btree_split, sec, us); |
---|
.. | .. |
---|
84 | 89 | read_attribute(average_key_size); |
---|
85 | 90 | read_attribute(dirty_data); |
---|
86 | 91 | read_attribute(bset_tree_stats); |
---|
| 92 | +read_attribute(feature_compat); |
---|
| 93 | +read_attribute(feature_ro_compat); |
---|
| 94 | +read_attribute(feature_incompat); |
---|
87 | 95 | |
---|
88 | 96 | read_attribute(state); |
---|
89 | 97 | read_attribute(cache_read_races); |
---|
90 | 98 | read_attribute(reclaim); |
---|
| 99 | +read_attribute(reclaimed_journal_buckets); |
---|
91 | 100 | read_attribute(flush_write); |
---|
92 | | -read_attribute(retry_flush_write); |
---|
93 | 101 | read_attribute(writeback_keys_done); |
---|
94 | 102 | read_attribute(writeback_keys_failed); |
---|
95 | 103 | read_attribute(io_errors); |
---|
96 | 104 | read_attribute(congested); |
---|
| 105 | +read_attribute(cutoff_writeback); |
---|
| 106 | +read_attribute(cutoff_writeback_sync); |
---|
97 | 107 | rw_attribute(congested_read_threshold_us); |
---|
98 | 108 | rw_attribute(congested_write_threshold_us); |
---|
99 | 109 | |
---|
.. | .. |
---|
135 | 145 | rw_attribute(cache_replacement_policy); |
---|
136 | 146 | rw_attribute(btree_shrinker_disabled); |
---|
137 | 147 | rw_attribute(copy_gc_enabled); |
---|
| 148 | +rw_attribute(idle_max_writeback_rate); |
---|
| 149 | +rw_attribute(gc_after_writeback); |
---|
138 | 150 | rw_attribute(size); |
---|
139 | 151 | |
---|
140 | 152 | static ssize_t bch_snprint_string_list(char *buf, |
---|
.. | .. |
---|
146 | 158 | size_t i; |
---|
147 | 159 | |
---|
148 | 160 | for (i = 0; list[i]; i++) |
---|
149 | | - out += snprintf(out, buf + size - out, |
---|
| 161 | + out += scnprintf(out, buf + size - out, |
---|
150 | 162 | i == selected ? "[%s] " : "%s ", list[i]); |
---|
151 | 163 | |
---|
152 | 164 | out[-1] = '\n'; |
---|
.. | .. |
---|
252 | 264 | return strlen(buf); |
---|
253 | 265 | } |
---|
254 | 266 | |
---|
| 267 | + if (attr == &sysfs_backing_dev_name) { |
---|
| 268 | + snprintf(buf, BDEVNAME_SIZE + 1, "%s", dc->backing_dev_name); |
---|
| 269 | + strcat(buf, "\n"); |
---|
| 270 | + return strlen(buf); |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + if (attr == &sysfs_backing_dev_uuid) { |
---|
| 274 | + /* convert binary uuid into 36-byte string plus '\0' */ |
---|
| 275 | + snprintf(buf, 36+1, "%pU", dc->sb.uuid); |
---|
| 276 | + strcat(buf, "\n"); |
---|
| 277 | + return strlen(buf); |
---|
| 278 | + } |
---|
| 279 | + |
---|
255 | 280 | #undef var |
---|
256 | 281 | return 0; |
---|
257 | 282 | } |
---|
.. | .. |
---|
265 | 290 | struct cache_set *c; |
---|
266 | 291 | struct kobj_uevent_env *env; |
---|
267 | 292 | |
---|
| 293 | + /* no user space access if system is rebooting */ |
---|
| 294 | + if (bcache_is_reboot) |
---|
| 295 | + return -EBUSY; |
---|
| 296 | + |
---|
268 | 297 | #define d_strtoul(var) sysfs_strtoul(var, dc->var) |
---|
269 | 298 | #define d_strtoul_nonzero(var) sysfs_strtoul_clamp(var, dc->var, 1, INT_MAX) |
---|
270 | 299 | #define d_strtoi_h(var) sysfs_hatoi(var, dc->var) |
---|
271 | 300 | |
---|
272 | 301 | sysfs_strtoul(data_csum, dc->disk.data_csum); |
---|
273 | 302 | d_strtoul(verify); |
---|
274 | | - d_strtoul(bypass_torture_test); |
---|
275 | | - d_strtoul(writeback_metadata); |
---|
276 | | - d_strtoul(writeback_running); |
---|
277 | | - d_strtoul(writeback_delay); |
---|
| 303 | + sysfs_strtoul_bool(bypass_torture_test, dc->bypass_torture_test); |
---|
| 304 | + sysfs_strtoul_bool(writeback_metadata, dc->writeback_metadata); |
---|
| 305 | + sysfs_strtoul_bool(writeback_running, dc->writeback_running); |
---|
| 306 | + sysfs_strtoul_clamp(writeback_delay, dc->writeback_delay, 0, UINT_MAX); |
---|
278 | 307 | |
---|
279 | | - sysfs_strtoul_clamp(writeback_percent, dc->writeback_percent, 0, 40); |
---|
| 308 | + sysfs_strtoul_clamp(writeback_percent, dc->writeback_percent, |
---|
| 309 | + 0, bch_cutoff_writeback); |
---|
280 | 310 | |
---|
281 | 311 | if (attr == &sysfs_writeback_rate) { |
---|
282 | 312 | ssize_t ret; |
---|
.. | .. |
---|
322 | 352 | bch_cache_accounting_clear(&dc->accounting); |
---|
323 | 353 | |
---|
324 | 354 | if (attr == &sysfs_running && |
---|
325 | | - strtoul_or_return(buf)) |
---|
326 | | - bch_cached_dev_run(dc); |
---|
| 355 | + strtoul_or_return(buf)) { |
---|
| 356 | + v = bch_cached_dev_run(dc); |
---|
| 357 | + if (v) |
---|
| 358 | + return v; |
---|
| 359 | + } |
---|
327 | 360 | |
---|
328 | 361 | if (attr == &sysfs_cache_mode) { |
---|
329 | 362 | v = __sysfs_match_string(bch_cache_modes, -1, buf); |
---|
.. | .. |
---|
392 | 425 | return size; |
---|
393 | 426 | } |
---|
394 | 427 | if (v == -ENOENT) |
---|
395 | | - pr_err("Can't attach %s: cache set not found", buf); |
---|
| 428 | + pr_err("Can't attach %s: cache set not found\n", buf); |
---|
396 | 429 | return v; |
---|
397 | 430 | } |
---|
398 | 431 | |
---|
.. | .. |
---|
410 | 443 | struct cached_dev *dc = container_of(kobj, struct cached_dev, |
---|
411 | 444 | disk.kobj); |
---|
412 | 445 | |
---|
| 446 | + /* no user space access if system is rebooting */ |
---|
| 447 | + if (bcache_is_reboot) |
---|
| 448 | + return -EBUSY; |
---|
| 449 | + |
---|
413 | 450 | mutex_lock(&bch_register_lock); |
---|
414 | 451 | size = __cached_dev_store(kobj, attr, buf, size); |
---|
415 | 452 | |
---|
416 | | - if (attr == &sysfs_writeback_running) |
---|
417 | | - bch_writeback_queue(dc); |
---|
| 453 | + if (attr == &sysfs_writeback_running) { |
---|
| 454 | + /* dc->writeback_running changed in __cached_dev_store() */ |
---|
| 455 | + if (IS_ERR_OR_NULL(dc->writeback_thread)) { |
---|
| 456 | + /* |
---|
| 457 | + * reject setting it to 1 via sysfs if writeback |
---|
| 458 | + * kthread is not created yet. |
---|
| 459 | + */ |
---|
| 460 | + if (dc->writeback_running) { |
---|
| 461 | + dc->writeback_running = false; |
---|
| 462 | + pr_err("%s: failed to run non-existent writeback thread\n", |
---|
| 463 | + dc->disk.disk->disk_name); |
---|
| 464 | + } |
---|
| 465 | + } else |
---|
| 466 | + /* |
---|
| 467 | + * writeback kthread will check if dc->writeback_running |
---|
| 468 | + * is true or false. |
---|
| 469 | + */ |
---|
| 470 | + bch_writeback_queue(dc); |
---|
| 471 | + } |
---|
418 | 472 | |
---|
419 | 473 | /* |
---|
420 | 474 | * Only set BCACHE_DEV_WB_RUNNING when cached device attached to |
---|
.. | .. |
---|
466 | 520 | &sysfs_verify, |
---|
467 | 521 | &sysfs_bypass_torture_test, |
---|
468 | 522 | #endif |
---|
| 523 | + &sysfs_backing_dev_name, |
---|
| 524 | + &sysfs_backing_dev_uuid, |
---|
469 | 525 | NULL |
---|
470 | 526 | }; |
---|
471 | 527 | KTYPE(bch_cached_dev); |
---|
.. | .. |
---|
494 | 550 | struct bcache_device *d = container_of(kobj, struct bcache_device, |
---|
495 | 551 | kobj); |
---|
496 | 552 | struct uuid_entry *u = &d->c->uuids[d->id]; |
---|
| 553 | + |
---|
| 554 | + /* no user space access if system is rebooting */ |
---|
| 555 | + if (bcache_is_reboot) |
---|
| 556 | + return -EBUSY; |
---|
497 | 557 | |
---|
498 | 558 | sysfs_strtoul(data_csum, d->data_csum); |
---|
499 | 559 | |
---|
.. | .. |
---|
651 | 711 | { |
---|
652 | 712 | struct cache_set *c = container_of(kobj, struct cache_set, kobj); |
---|
653 | 713 | |
---|
654 | | - sysfs_print(synchronous, CACHE_SYNC(&c->sb)); |
---|
| 714 | + sysfs_print(synchronous, CACHE_SYNC(&c->cache->sb)); |
---|
655 | 715 | sysfs_print(journal_delay_ms, c->journal_delay_ms); |
---|
656 | | - sysfs_hprint(bucket_size, bucket_bytes(c)); |
---|
657 | | - sysfs_hprint(block_size, block_bytes(c)); |
---|
| 716 | + sysfs_hprint(bucket_size, bucket_bytes(c->cache)); |
---|
| 717 | + sysfs_hprint(block_size, block_bytes(c->cache)); |
---|
658 | 718 | sysfs_print(tree_depth, c->root->level); |
---|
659 | 719 | sysfs_print(root_usage_percent, bch_root_usage(c)); |
---|
660 | 720 | |
---|
.. | .. |
---|
677 | 737 | sysfs_print(reclaim, |
---|
678 | 738 | atomic_long_read(&c->reclaim)); |
---|
679 | 739 | |
---|
| 740 | + sysfs_print(reclaimed_journal_buckets, |
---|
| 741 | + atomic_long_read(&c->reclaimed_journal_buckets)); |
---|
| 742 | + |
---|
680 | 743 | sysfs_print(flush_write, |
---|
681 | 744 | atomic_long_read(&c->flush_write)); |
---|
682 | | - |
---|
683 | | - sysfs_print(retry_flush_write, |
---|
684 | | - atomic_long_read(&c->retry_flush_write)); |
---|
685 | 745 | |
---|
686 | 746 | sysfs_print(writeback_keys_done, |
---|
687 | 747 | atomic_long_read(&c->writeback_keys_done)); |
---|
.. | .. |
---|
703 | 763 | sysfs_print(congested_write_threshold_us, |
---|
704 | 764 | c->congested_write_threshold_us); |
---|
705 | 765 | |
---|
| 766 | + sysfs_print(cutoff_writeback, bch_cutoff_writeback); |
---|
| 767 | + sysfs_print(cutoff_writeback_sync, bch_cutoff_writeback_sync); |
---|
| 768 | + |
---|
706 | 769 | sysfs_print(active_journal_entries, fifo_used(&c->journal.pin)); |
---|
707 | 770 | sysfs_printf(verify, "%i", c->verify); |
---|
708 | 771 | sysfs_printf(key_merging_disabled, "%i", c->key_merging_disabled); |
---|
.. | .. |
---|
711 | 774 | sysfs_printf(gc_always_rewrite, "%i", c->gc_always_rewrite); |
---|
712 | 775 | sysfs_printf(btree_shrinker_disabled, "%i", c->shrinker_disabled); |
---|
713 | 776 | sysfs_printf(copy_gc_enabled, "%i", c->copy_gc_enabled); |
---|
| 777 | + sysfs_printf(idle_max_writeback_rate, "%i", |
---|
| 778 | + c->idle_max_writeback_rate_enabled); |
---|
| 779 | + sysfs_printf(gc_after_writeback, "%i", c->gc_after_writeback); |
---|
714 | 780 | sysfs_printf(io_disable, "%i", |
---|
715 | 781 | test_bit(CACHE_SET_IO_DISABLE, &c->flags)); |
---|
716 | 782 | |
---|
717 | 783 | if (attr == &sysfs_bset_tree_stats) |
---|
718 | 784 | return bch_bset_print_stats(c, buf); |
---|
| 785 | + |
---|
| 786 | + if (attr == &sysfs_feature_compat) |
---|
| 787 | + return bch_print_cache_set_feature_compat(c, buf, PAGE_SIZE); |
---|
| 788 | + if (attr == &sysfs_feature_ro_compat) |
---|
| 789 | + return bch_print_cache_set_feature_ro_compat(c, buf, PAGE_SIZE); |
---|
| 790 | + if (attr == &sysfs_feature_incompat) |
---|
| 791 | + return bch_print_cache_set_feature_incompat(c, buf, PAGE_SIZE); |
---|
719 | 792 | |
---|
720 | 793 | return 0; |
---|
721 | 794 | } |
---|
.. | .. |
---|
726 | 799 | struct cache_set *c = container_of(kobj, struct cache_set, kobj); |
---|
727 | 800 | ssize_t v; |
---|
728 | 801 | |
---|
| 802 | + /* no user space access if system is rebooting */ |
---|
| 803 | + if (bcache_is_reboot) |
---|
| 804 | + return -EBUSY; |
---|
| 805 | + |
---|
729 | 806 | if (attr == &sysfs_unregister) |
---|
730 | 807 | bch_cache_set_unregister(c); |
---|
731 | 808 | |
---|
.. | .. |
---|
735 | 812 | if (attr == &sysfs_synchronous) { |
---|
736 | 813 | bool sync = strtoul_or_return(buf); |
---|
737 | 814 | |
---|
738 | | - if (sync != CACHE_SYNC(&c->sb)) { |
---|
739 | | - SET_CACHE_SYNC(&c->sb, sync); |
---|
| 815 | + if (sync != CACHE_SYNC(&c->cache->sb)) { |
---|
| 816 | + SET_CACHE_SYNC(&c->cache->sb, sync); |
---|
740 | 817 | bcache_write_super(c); |
---|
741 | 818 | } |
---|
742 | 819 | } |
---|
.. | .. |
---|
760 | 837 | bch_cache_accounting_clear(&c->accounting); |
---|
761 | 838 | } |
---|
762 | 839 | |
---|
763 | | - if (attr == &sysfs_trigger_gc) { |
---|
764 | | - /* |
---|
765 | | - * Garbage collection thread only works when sectors_to_gc < 0, |
---|
766 | | - * when users write to sysfs entry trigger_gc, most of time |
---|
767 | | - * they want to forcibly triger gargage collection. Here -1 is |
---|
768 | | - * set to c->sectors_to_gc, to make gc_should_run() give a |
---|
769 | | - * chance to permit gc thread to run. "give a chance" means |
---|
770 | | - * before going into gc_should_run(), there is still chance |
---|
771 | | - * that c->sectors_to_gc being set to other positive value. So |
---|
772 | | - * writing sysfs entry trigger_gc won't always make sure gc |
---|
773 | | - * thread takes effect. |
---|
774 | | - */ |
---|
775 | | - atomic_set(&c->sectors_to_gc, -1); |
---|
776 | | - wake_up_gc(c); |
---|
777 | | - } |
---|
| 840 | + if (attr == &sysfs_trigger_gc) |
---|
| 841 | + force_wake_up_gc(c); |
---|
778 | 842 | |
---|
779 | 843 | if (attr == &sysfs_prune_cache) { |
---|
780 | 844 | struct shrink_control sc; |
---|
.. | .. |
---|
784 | 848 | c->shrink.scan_objects(&c->shrink, &sc); |
---|
785 | 849 | } |
---|
786 | 850 | |
---|
787 | | - sysfs_strtoul(congested_read_threshold_us, |
---|
788 | | - c->congested_read_threshold_us); |
---|
789 | | - sysfs_strtoul(congested_write_threshold_us, |
---|
790 | | - c->congested_write_threshold_us); |
---|
| 851 | + sysfs_strtoul_clamp(congested_read_threshold_us, |
---|
| 852 | + c->congested_read_threshold_us, |
---|
| 853 | + 0, UINT_MAX); |
---|
| 854 | + sysfs_strtoul_clamp(congested_write_threshold_us, |
---|
| 855 | + c->congested_write_threshold_us, |
---|
| 856 | + 0, UINT_MAX); |
---|
791 | 857 | |
---|
792 | 858 | if (attr == &sysfs_errors) { |
---|
793 | 859 | v = __sysfs_match_string(error_actions, -1, buf); |
---|
.. | .. |
---|
797 | 863 | c->on_error = v; |
---|
798 | 864 | } |
---|
799 | 865 | |
---|
800 | | - if (attr == &sysfs_io_error_limit) |
---|
801 | | - c->error_limit = strtoul_or_return(buf); |
---|
| 866 | + sysfs_strtoul_clamp(io_error_limit, c->error_limit, 0, UINT_MAX); |
---|
802 | 867 | |
---|
803 | 868 | /* See count_io_errors() for why 88 */ |
---|
804 | 869 | if (attr == &sysfs_io_error_halflife) { |
---|
.. | .. |
---|
818 | 883 | if (v) { |
---|
819 | 884 | if (test_and_set_bit(CACHE_SET_IO_DISABLE, |
---|
820 | 885 | &c->flags)) |
---|
821 | | - pr_warn("CACHE_SET_IO_DISABLE already set"); |
---|
| 886 | + pr_warn("CACHE_SET_IO_DISABLE already set\n"); |
---|
822 | 887 | } else { |
---|
823 | 888 | if (!test_and_clear_bit(CACHE_SET_IO_DISABLE, |
---|
824 | 889 | &c->flags)) |
---|
825 | | - pr_warn("CACHE_SET_IO_DISABLE already cleared"); |
---|
| 890 | + pr_warn("CACHE_SET_IO_DISABLE already cleared\n"); |
---|
826 | 891 | } |
---|
827 | 892 | } |
---|
828 | 893 | |
---|
829 | | - sysfs_strtoul(journal_delay_ms, c->journal_delay_ms); |
---|
830 | | - sysfs_strtoul(verify, c->verify); |
---|
831 | | - sysfs_strtoul(key_merging_disabled, c->key_merging_disabled); |
---|
| 894 | + sysfs_strtoul_clamp(journal_delay_ms, |
---|
| 895 | + c->journal_delay_ms, |
---|
| 896 | + 0, USHRT_MAX); |
---|
| 897 | + sysfs_strtoul_bool(verify, c->verify); |
---|
| 898 | + sysfs_strtoul_bool(key_merging_disabled, c->key_merging_disabled); |
---|
832 | 899 | sysfs_strtoul(expensive_debug_checks, c->expensive_debug_checks); |
---|
833 | | - sysfs_strtoul(gc_always_rewrite, c->gc_always_rewrite); |
---|
834 | | - sysfs_strtoul(btree_shrinker_disabled, c->shrinker_disabled); |
---|
835 | | - sysfs_strtoul(copy_gc_enabled, c->copy_gc_enabled); |
---|
| 900 | + sysfs_strtoul_bool(gc_always_rewrite, c->gc_always_rewrite); |
---|
| 901 | + sysfs_strtoul_bool(btree_shrinker_disabled, c->shrinker_disabled); |
---|
| 902 | + sysfs_strtoul_bool(copy_gc_enabled, c->copy_gc_enabled); |
---|
| 903 | + sysfs_strtoul_bool(idle_max_writeback_rate, |
---|
| 904 | + c->idle_max_writeback_rate_enabled); |
---|
| 905 | + |
---|
| 906 | + /* |
---|
| 907 | + * write gc_after_writeback here may overwrite an already set |
---|
| 908 | + * BCH_DO_AUTO_GC, it doesn't matter because this flag will be |
---|
| 909 | + * set in next chance. |
---|
| 910 | + */ |
---|
| 911 | + sysfs_strtoul_clamp(gc_after_writeback, c->gc_after_writeback, 0, 1); |
---|
836 | 912 | |
---|
837 | 913 | return size; |
---|
838 | 914 | } |
---|
.. | .. |
---|
848 | 924 | STORE(bch_cache_set_internal) |
---|
849 | 925 | { |
---|
850 | 926 | struct cache_set *c = container_of(kobj, struct cache_set, internal); |
---|
| 927 | + |
---|
| 928 | + /* no user space access if system is rebooting */ |
---|
| 929 | + if (bcache_is_reboot) |
---|
| 930 | + return -EBUSY; |
---|
851 | 931 | |
---|
852 | 932 | return bch_cache_set_store(&c->kobj, attr, buf, size); |
---|
853 | 933 | } |
---|
.. | .. |
---|
898 | 978 | &sysfs_bset_tree_stats, |
---|
899 | 979 | &sysfs_cache_read_races, |
---|
900 | 980 | &sysfs_reclaim, |
---|
| 981 | + &sysfs_reclaimed_journal_buckets, |
---|
901 | 982 | &sysfs_flush_write, |
---|
902 | | - &sysfs_retry_flush_write, |
---|
903 | 983 | &sysfs_writeback_keys_done, |
---|
904 | 984 | &sysfs_writeback_keys_failed, |
---|
905 | 985 | |
---|
.. | .. |
---|
913 | 993 | &sysfs_gc_always_rewrite, |
---|
914 | 994 | &sysfs_btree_shrinker_disabled, |
---|
915 | 995 | &sysfs_copy_gc_enabled, |
---|
| 996 | + &sysfs_idle_max_writeback_rate, |
---|
| 997 | + &sysfs_gc_after_writeback, |
---|
916 | 998 | &sysfs_io_disable, |
---|
| 999 | + &sysfs_cutoff_writeback, |
---|
| 1000 | + &sysfs_cutoff_writeback_sync, |
---|
| 1001 | + &sysfs_feature_compat, |
---|
| 1002 | + &sysfs_feature_ro_compat, |
---|
| 1003 | + &sysfs_feature_incompat, |
---|
917 | 1004 | NULL |
---|
918 | 1005 | }; |
---|
919 | 1006 | KTYPE(bch_cache_set_internal); |
---|
920 | 1007 | |
---|
921 | 1008 | static int __bch_cache_cmp(const void *l, const void *r) |
---|
922 | 1009 | { |
---|
| 1010 | + cond_resched(); |
---|
923 | 1011 | return *((uint16_t *)r) - *((uint16_t *)l); |
---|
924 | 1012 | } |
---|
925 | 1013 | |
---|
.. | .. |
---|
982 | 1070 | !cached[n - 1]) |
---|
983 | 1071 | --n; |
---|
984 | 1072 | |
---|
985 | | - unused = ca->sb.nbuckets - n; |
---|
986 | | - |
---|
987 | 1073 | while (cached < p + n && |
---|
988 | 1074 | *cached == BTREE_PRIO) |
---|
989 | 1075 | cached++, n--; |
---|
.. | .. |
---|
1033 | 1119 | struct cache *ca = container_of(kobj, struct cache, kobj); |
---|
1034 | 1120 | ssize_t v; |
---|
1035 | 1121 | |
---|
| 1122 | + /* no user space access if system is rebooting */ |
---|
| 1123 | + if (bcache_is_reboot) |
---|
| 1124 | + return -EBUSY; |
---|
| 1125 | + |
---|
1036 | 1126 | if (attr == &sysfs_discard) { |
---|
1037 | 1127 | bool v = strtoul_or_return(buf); |
---|
1038 | 1128 | |
---|