diff options
4 files changed, 521 insertions, 0 deletions
diff --git a/sys-fs/bcache-tools/Manifest b/sys-fs/bcache-tools/Manifest index 7e092b1fd8f1..030990051d52 100644 --- a/sys-fs/bcache-tools/Manifest +++ b/sys-fs/bcache-tools/Manifest @@ -1,2 +1,3 @@ DIST bcache-status-20140220.tar.gz 3779 BLAKE2B a3fa5e9d87b2c51f1f5178693db6d9f8b4bde31c77783d1ebd9de6e81995d89a4b07df43178cba384757b212087c474a0508640d1d3ddcd97d3d928643971e4a SHA512 0c8db02dc865b469f3a5964f679a3bfdf5cdbf5a2f6ccd5d81544f3bb3c06df2f5d06b9f09aaec527ec90229740dcd31fbb33e2628721b6da139cfcee6b48d7c DIST bcache-tools-1.0.8_p20140220.tgz 22153 BLAKE2B d40a64b02e0d66ef8868151870715f6e6ab54633e4875c32d0e03dfe1871e5aa98d7e133b9eed583ac4898b1598f38b71e47109210009ca51c4dfe9dbd31768c SHA512 21eaed457e5de623089c0d4e1c11394a3950f29c749c502bfd5dd94d3dcdc7379c4a910825e33bf9fc8080df656949b94a1a28d19048a8eb6422976cb391b7dc +DIST bcache-tools-1.1.tar.gz 34548 BLAKE2B e6ebc0f609debe0cc123deba0e21076441c37cdbc6edd02bf2c16c0e36fe806f1fc160b9e9baed577f86f6358884182a4e3903f34bccee81943191c0ba6a2d11 SHA512 4ccbef47255bf3644a50242a79951b1f3720e71a55eb1e07dc6b8486df0245da99a77bba751b50197d489b4c5d738e5284aabc014c2f7f44816ddf6a1bb807ca diff --git a/sys-fs/bcache-tools/bcache-tools-1.1.ebuild b/sys-fs/bcache-tools/bcache-tools-1.1.ebuild new file mode 100644 index 000000000000..38d4ef379bff --- /dev/null +++ b/sys-fs/bcache-tools/bcache-tools-1.1.ebuild @@ -0,0 +1,70 @@ +# Copyright 1999-2020 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +PYTHON_COMPAT=( python3_{6,7,8,9} ) + +inherit flag-o-matic python-r1 toolchain-funcs udev + +DESCRIPTION="Tools for bcache" +HOMEPAGE="https://bcache.evilpiepirate.org/" +SRC_URI="https://git.kernel.org/pub/scm/linux/kernel/git/colyli/${PN}.git/snapshot/${P}.tar.gz" + +SLOT="0" +LICENSE="GPL-2" +KEYWORDS="~amd64 ~x86 ~amd64-linux ~x86-linux" +IUSE="" + +REQUIRED_USE="${PYTHON_REQUIRED_USE}" + +RDEPEND="${PYTHON_DEPS} + sys-apps/util-linux" +DEPEND="${RDEPEND}" + +PATCHES=( + "${FILESDIR}"/1.0.8_p20140220/bcache-tools-1.0.8-noprobe.patch + "${FILESDIR}"/${PV}/bcache-tools-add-bcache-status.patch + "${FILESDIR}"/${PV}/bcache-tools-add-man-page-bcache-status.8.patch +) + +src_prepare() { + eapply_user + + tc-export CC + sed \ + -e '/^CFLAGS/s:-O2::' \ + -e '/^CFLAGS/s:-g::' \ + -i Makefile || die + + append-lfs-flags + + eapply "${PATCHES[@]}" +} + +src_install() { + into / + dosbin bcache make-bcache bcache-super-show + + exeinto $(get_udevdir) + doexe bcache-register probe-bcache + + python_foreach_impl python_doscript bcache-status + + udev_dorules 69-bcache.rules + + insinto /etc/initramfs-tools/hooks/bcache + doins initramfs/hook + + # that is what dracut does + insinto /usr/lib/dracut/modules.d/90bcache + doins dracut/module-setup.sh + + doman *.8 + + dodoc README +} + +pkg_postinst() { + udev_reload +} diff --git a/sys-fs/bcache-tools/files/1.1/bcache-tools-add-bcache-status.patch b/sys-fs/bcache-tools/files/1.1/bcache-tools-add-bcache-status.patch new file mode 100644 index 000000000000..bd58d0a309d5 --- /dev/null +++ b/sys-fs/bcache-tools/files/1.1/bcache-tools-add-bcache-status.patch @@ -0,0 +1,381 @@ +From 10824170800268e91508e2edc6ed745f40370f0a Mon Sep 17 00:00:00 2001 +From: Coly Li <colyli@suse.de> +Date: Wed, 2 Sep 2020 19:27:08 +0800 +Subject: [PATCH 1/2] bcache-tools: add bcache-status + +People request to include bcache-status into bcache-tools package. This +patch picks bcache-status script from github page of the orginal author +Darrick J. Wong, + https://github.com/djwong/bcache-tools/blob/master/bcache-status + +Thanks to Darrick for writing the great bcache-status, and I will keep +this script being updated from Darrick's repo time to time. + +Signed-off-by: Coly Li <colyli@suse.de> +Cc: Darrick J. Wong <darrick.wong@oracle.com> +--- + bcache-status | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 352 insertions(+) + create mode 100755 bcache-status + +diff --git a/bcache-status b/bcache-status +new file mode 100755 +index 0000000..ac5a22f +--- /dev/null ++++ b/bcache-status +@@ -0,0 +1,352 @@ ++#!/usr/bin/env python ++# ++# Dumb script to dump (some) of bcache status ++# Copyright 2014 Darrick J. Wong. All rights reserved. ++# ++# This file is part of Bcache. Bcache is free software: you can ++# redistribute it and/or modify it under the terms of the GNU General Public ++# License as published by the Free Software Foundation, version 2. ++# ++# This program is distributed in the hope that it will be useful, but WITHOUT ++# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ++# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ++# details. ++# ++# You should have received a copy of the GNU General Public License along with ++# this program; if not, write to the Free Software Foundation, Inc., 51 ++# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++# ++ ++import os ++import sys ++import argparse ++ ++MAX_KEY_LENGTH = 28 ++DEV_BLOCK_PATH = '/dev/block/' ++SYSFS_BCACHE_PATH = '/sys/fs/bcache/' ++SYSFS_BLOCK_PATH = '/sys/block/' ++ ++def file_to_lines(fname): ++ try: ++ with open(fname, "r") as fd: ++ return fd.readlines() ++ except: ++ return [] ++ ++def file_to_line(fname): ++ ret = file_to_lines(fname) ++ if ret: ++ return ret[0].strip() ++ return '' ++ ++def str_to_bool(x): ++ return x == '1' ++ ++def format_sectors(x): ++ '''Pretty print a sector count.''' ++ sectors = float(x) ++ asectors = abs(sectors) ++ ++ if asectors < 2: ++ return '%d B' % (sectors * 512) ++ elif asectors < 2048: ++ return '%.2f KiB' % (sectors / 2) ++ elif asectors < 2097152: ++ return '%.1f MiB' % (sectors / 2048) ++ elif asectors < 2147483648: ++ return '%.0f GiB' % (sectors / 2097152) ++ else: ++ return '%.0f TiB' % (sectors / 2147483648) ++ ++def interpret_sectors(x): ++ '''Interpret a pretty-printed disk size.''' ++ factors = { ++ 'k': 1 << 10, ++ 'M': 1 << 20, ++ 'G': 1 << 30, ++ 'T': 1 << 40, ++ 'P': 1 << 50, ++ 'E': 1 << 60, ++ 'Z': 1 << 70, ++ 'Y': 1 << 80, ++ } ++ ++ factor = 1 ++ if x[-1] in factors: ++ factor = factors[x[-1]] ++ x = x[:-1] ++ return int(float(x) * factor / 512) ++ ++def pretty_size(x): ++ return format_sectors(interpret_sectors(x)) ++ ++def device_path(x): ++ if not os.path.isdir(DEV_BLOCK_PATH): ++ return '?' ++ x = '%s/%s' % (DEV_BLOCK_PATH, x) ++ return os.path.abspath(os.path.join(os.path.dirname(x), os.readlink(x))) ++ ++def str_device_path(x): ++ return '%s (%s)' % (device_path(x), x) ++ ++def dump_bdev(bdev_path): ++ '''Dump a backing device stats.''' ++ global MAX_KEY_LENGTH ++ attrs = [ ++ ('../dev', 'Device File', str_device_path), ++ ('dev/dev', 'bcache Device File', str_device_path), ++ ('../size', 'Size', format_sectors), ++ ('cache_mode', 'Cache Mode', None), ++ ('readahead', 'Readahead', None), ++ ('sequential_cutoff', 'Sequential Cutoff', pretty_size), ++ ('sequential_merge', 'Merge sequential?', str_to_bool), ++ ('state', 'State', None), ++ ('writeback_running', 'Writeback?', str_to_bool), ++ ('dirty_data', 'Dirty Data', pretty_size), ++ ('writeback_rate', 'Writeback Rate', lambda x: '%s/s' % x), ++ ('writeback_percent', 'Dirty Target', lambda x: '%s%%' % x), ++ ] ++ ++ print('--- Backing Device ---') ++ for (sysfs_name, display_name, conversion_func) in attrs: ++ val = file_to_line('%s/%s' % (bdev_path, sysfs_name)) ++ if conversion_func is not None: ++ val = conversion_func(val) ++ if display_name is None: ++ display_name = sysfs_name ++ print(' %-*s%s' % (MAX_KEY_LENGTH - 2, display_name, val)) ++ ++def dump_cachedev(cachedev_path): ++ '''Dump a cachding device stats.''' ++ def fmt_cachesize(val): ++ return '%s\t(%.0f%%)' % (format_sectors(val), float(val) / cache_size * 100) ++ ++ global MAX_KEY_LENGTH ++ attrs = [ ++ ('../dev', 'Device File', str_device_path), ++ ('../size', 'Size', format_sectors), ++ ('block_size', 'Block Size', pretty_size), ++ ('bucket_size', 'Bucket Size', pretty_size), ++ ('cache_replacement_policy', 'Replacement Policy', None), ++ ('discard', 'Discard?', str_to_bool), ++ ('io_errors', 'I/O Errors', None), ++ ('metadata_written', 'Metadata Written', pretty_size), ++ ('written', 'Data Written', pretty_size), ++ ('nbuckets', 'Buckets', None), ++ (None, 'Cache Used', lambda x: fmt_cachesize(used_sectors)), ++ (None, 'Cache Unused', lambda x: fmt_cachesize(unused_sectors)), ++ ] ++ ++ stats = get_cache_priority_stats(cachedev_path) ++ cache_size = int(file_to_line('%s/../size' % cachedev_path)) ++ unused_sectors = float(stats['Unused'][:-1]) * cache_size / 100 ++ used_sectors = cache_size - unused_sectors ++ ++ print('--- Cache Device ---') ++ for (sysfs_name, display_name, conversion_func) in attrs: ++ if sysfs_name is not None: ++ val = file_to_line('%s/%s' % (cachedev_path, sysfs_name)) ++ if conversion_func is not None: ++ val = conversion_func(val) ++ if display_name is None: ++ display_name = sysfs_name ++ print(' %-*s%s' % (MAX_KEY_LENGTH - 2, display_name, val)) ++ ++def hits_to_str(hits_str, misses_str): ++ '''Render a hits/misses ratio as a string.''' ++ hits = int(hits_str) ++ misses = int(misses_str) ++ ++ ret = '%d' % hits ++ if hits + misses != 0: ++ ret = '%s\t(%.d%%)' % (ret, 100 * hits / (hits + misses)) ++ return ret ++ ++def dump_stats(sysfs_path, indent_str, stats): ++ '''Dump stats on a bcache device.''' ++ stat_types = [ ++ ('five_minute', 'Last 5min'), ++ ('hour', 'Last Hour'), ++ ('day', 'Last Day'), ++ ('total', 'Total'), ++ ] ++ attrs = ['bypassed', 'cache_bypass_hits', 'cache_bypass_misses', 'cache_hits', 'cache_misses'] ++ display = [ ++ ('Hits', lambda: hits_to_str(stat_data['cache_hits'], stat_data['cache_misses'])), ++ ('Misses', lambda: stat_data['cache_misses']), ++ ('Bypass Hits', lambda: hits_to_str(stat_data['cache_bypass_hits'], stat_data['cache_bypass_misses'])), ++ ('Bypass Misses', lambda: stat_data['cache_bypass_misses']), ++ ('Bypassed', lambda: pretty_size(stat_data['bypassed'])), ++ ] ++ ++ for (sysfs_name, stat_display_name) in stat_types: ++ if len(stats) > 0 and sysfs_name not in stats: ++ continue ++ stat_data = {} ++ for attr in attrs: ++ val = file_to_line('%s/stats_%s/%s' % (sysfs_path, sysfs_name, attr)) ++ stat_data[attr] = val ++ for (display_name, str_func) in display: ++ d = '%s%s %s' % (indent_str, stat_display_name, display_name) ++ print('%-*s%s' % (MAX_KEY_LENGTH, d, str_func())) ++ ++def get_cache_priority_stats(cache): ++ '''Retrieve priority stats from a cache.''' ++ attrs = {} ++ ++ for line in file_to_lines('%s/priority_stats' % cache): ++ x = line.split() ++ key = x[0] ++ value = x[1] ++ attrs[key[:-1]] = value ++ return attrs ++ ++def dump_bcache(bcache_sysfs_path, stats, print_subdevices, device): ++ '''Dump bcache stats''' ++ def fmt_cachesize(val): ++ return '%s\t(%.0f%%)' % (format_sectors(val), 100.0 * val / cache_sectors) ++ ++ attrs = [ ++ (None, 'UUID', lambda x: os.path.basename(bcache_sysfs_path)), ++ ('block_size', 'Block Size', pretty_size), ++ ('bucket_size', 'Bucket Size', pretty_size), ++ ('congested', 'Congested?', str_to_bool), ++ ('congested_read_threshold_us', 'Read Congestion', lambda x: '%.1fms' % (int(x) / 1000)), ++ ('congested_write_threshold_us', 'Write Congestion', lambda x: '%.1fms' % (int(x) / 1000)), ++ (None, 'Total Cache Size', lambda x: format_sectors(cache_sectors)), ++ (None, 'Total Cache Used', lambda x: fmt_cachesize(cache_used_sectors)), ++ (None, 'Total Cache Unused', lambda x: fmt_cachesize(cache_unused_sectors)), ++ #('dirty_data', 'Dirty Data', lambda x: fmt_cachesize(interpret_sectors(x))), # disappeared in 3.13? ++ ('cache_available_percent', 'Evictable Cache', lambda x: '%s\t(%s%%)' % (format_sectors(float(x) * cache_sectors / 100), x)), ++ (None, 'Replacement Policy', lambda x: replacement_policies.pop() if len(replacement_policies) == 1 else '(Various)'), ++ (None, 'Cache Mode', lambda x: cache_modes.pop() if len(cache_modes) == 1 else '(Various)'), ++ ] ++ ++ # Calculate aggregate data ++ cache_sectors = 0 ++ cache_unused_sectors = 0 ++ cache_modes = set() ++ replacement_policies = set() ++ for obj in os.listdir(bcache_sysfs_path): ++ if not os.path.isdir('%s/%s' % (bcache_sysfs_path, obj)): ++ continue ++ if obj.startswith('cache'): ++ cache_size = int(file_to_line('%s/%s/../size' % (bcache_sysfs_path, obj))) ++ cache_sectors += cache_size ++ cstats = get_cache_priority_stats('%s/%s' % (bcache_sysfs_path, obj)) ++ unused_size = float(cstats['Unused'][:-1]) * cache_size / 100 ++ cache_unused_sectors += unused_size ++ replacement_policies.add(file_to_line('%s/%s/cache_replacement_policy' % (bcache_sysfs_path, obj))) ++ elif obj.startswith('bdev'): ++ cache_modes.add(file_to_line('%s/%s/cache_mode' % (bcache_sysfs_path, obj))) ++ cache_used_sectors = cache_sectors - cache_unused_sectors ++ ++ # Dump basic stats ++ print("--- bcache ---") ++ for (sysfs_name, display_name, conversion_func) in attrs: ++ if sysfs_name is not None: ++ val = file_to_line('%s/%s' % (bcache_sysfs_path, sysfs_name)) ++ else: ++ val = None ++ if conversion_func is not None: ++ val = conversion_func(val) ++ if display_name is None: ++ display_name = sysfs_name ++ print('%-*s%s' % (MAX_KEY_LENGTH, display_name, val)) ++ dump_stats(bcache_sysfs_path, '', stats) ++ ++ # Dump sub-device stats ++ if not print_subdevices: ++ return ++ for obj in os.listdir(bcache_sysfs_path): ++ if not os.path.isdir('%s/%s' % (bcache_sysfs_path, obj)): ++ continue ++ if obj.startswith('bdev'): ++ dump_bdev('%s/%s' % (bcache_sysfs_path, obj)) ++ dump_stats('%s/%s' % (bcache_sysfs_path, obj), ' ', stats) ++ elif obj.startswith('cache'): ++ dump_cachedev('%s/%s' % (bcache_sysfs_path, obj)) ++ ++def map_uuid_to_device(): ++ '''Map bcache UUIDs to device files.''' ++ global SYSFS_BLOCK_PATH ++ ret = {} ++ ++ if not os.path.isdir(SYSFS_BLOCK_PATH): ++ return ret ++ for bdev in os.listdir(SYSFS_BLOCK_PATH): ++ link = '%s%s/bcache/cache' % (SYSFS_BLOCK_PATH, bdev) ++ if not os.path.islink(link): ++ continue ++ basename = os.path.basename(os.readlink(link)) ++ ret[basename] = file_to_line('%s%s/dev' % (SYSFS_BLOCK_PATH, bdev)) ++ return ret ++ ++def main(): ++ '''Main function''' ++ global SYSFS_BCACHE_PATH ++ global uuid_map ++ stats = set() ++ reset_stats = False ++ print_subdevices = False ++ run_gc = False ++ ++ parser = argparse.ArgumentParser(add_help=False) ++ parser.add_argument('--help', help='Show this help message and exit', action='store_true') ++ parser.add_argument('-f', '--five-minute', help='Print the last five minutes of stats.', action='store_true') ++ parser.add_argument('-h', '--hour', help='Print the last hour of stats.', action='store_true') ++ parser.add_argument('-d', '--day', help='Print the last day of stats.', action='store_true') ++ parser.add_argument('-t', '--total', help='Print total stats.', action='store_true') ++ parser.add_argument('-a', '--all', help='Print all stats.', action='store_true') ++ parser.add_argument('-r', '--reset-stats', help='Reset stats after printing them.', action='store_true') ++ parser.add_argument('-s', '--sub-status', help='Print subdevice status.', action='store_true') ++ parser.add_argument('-g', '--gc', help='Invoke GC before printing status.', action='store_true') ++ args = parser.parse_args() ++ ++ if args.help: ++ parser.print_help() ++ return 0 ++ ++ if args.five_minute: ++ stats.add('five_minute') ++ if args.hour: ++ stats.add('hour') ++ if args.day: ++ stats.add('day') ++ if args.total: ++ stats.add('total') ++ if args.all: ++ stats.add('five_minute') ++ stats.add('hour') ++ stats.add('day') ++ stats.add('total') ++ if args.reset_stats: ++ reset_stats = True ++ if args.sub_status: ++ print_subdevices = True ++ if args.gc: ++ run_gc = True ++ ++ if not stats: ++ stats.add('total') ++ ++ uuid_map = map_uuid_to_device() ++ if not os.path.isdir(SYSFS_BCACHE_PATH): ++ print('bcache is not loaded.') ++ return ++ for cache in os.listdir(SYSFS_BCACHE_PATH): ++ if not os.path.isdir('%s%s' % (SYSFS_BCACHE_PATH, cache)): ++ continue ++ ++ if run_gc: ++ with open('%s%s/internal/trigger_gc' % (SYSFS_BCACHE_PATH, cache), 'w') as fd: ++ fd.write('1\n') ++ ++ dump_bcache('%s%s' % (SYSFS_BCACHE_PATH, cache), stats, print_subdevices, uuid_map.get(cache, '?')) ++ ++ if reset_stats: ++ with open('%s%s/clear_stats' % (SYSFS_BCACHE_PATH, cache), 'w') as fd: ++ fd.write('1\n') ++ ++if __name__ == '__main__': ++ main() +-- +2.28.0 + diff --git a/sys-fs/bcache-tools/files/1.1/bcache-tools-add-man-page-bcache-status.8.patch b/sys-fs/bcache-tools/files/1.1/bcache-tools-add-man-page-bcache-status.8.patch new file mode 100644 index 000000000000..cd999a994a16 --- /dev/null +++ b/sys-fs/bcache-tools/files/1.1/bcache-tools-add-man-page-bcache-status.8.patch @@ -0,0 +1,69 @@ +From 91fd5fb518ae535e36cff1ae188d1bcef874cf40 Mon Sep 17 00:00:00 2001 +From: Coly Li <colyli@suse.de> +Date: Wed, 2 Sep 2020 20:09:06 +0800 +Subject: [PATCH 2/2] bcache-tools: add man page bcache-status.8 + +Add the initial man page for bcache-status. + +Signed-off-by: Coly Li <colyli@suse.de> +--- + bcache-status.8 | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + create mode 100644 bcache-status.8 + +diff --git a/bcache-status.8 b/bcache-status.8 +new file mode 100644 +index 0000000..f56cfb6 +--- /dev/null ++++ b/bcache-status.8 +@@ -0,0 +1,47 @@ ++.TH bcache-status 8 ++.SH NAME ++bcache-status \- Display useful bcache statistics ++ ++.SH SYNOPSIS ++.B bcache-status [ --help ] [ -f ] [ -h ] [ -d ] [ -t ] [ -a ] [ -r ] [ -s ] [ -g ] ++ ++.SH DESCRIPTION ++This command displays useful bcache statistics in a convenient way. ++ ++.SH OPTIONS ++ ++.TP ++.BR \-\-help ++Print help message and exit. ++ ++.TP ++.BR \-f ", " \-\-five\-minute ++Print the last five minutes of stats. ++ ++.TP ++.BR \-h ", " \-\-hour ++Print the last hour of stats. ++ ++.TP ++.BR \-d ", " \-\-day ++Print the last day of stats. ++ ++.TP ++.BR \-t ", " \-\-total ++Print total stats. ++ ++.TP ++.BR \-a ", " \-\-all ++Print all stats. ++ ++.TP ++.BR \-r ", " \-\-reset\-stats ++Reset stats after printing them. ++ ++.TP ++.BR \-s ", " \-\-sub\-status ++Print subdevice status. ++ ++.TP ++.BR \-g ", " \-\-gc ++Invoke GC before printing status (root only). +-- +2.28.0 + |