diff --git a/cmd/Makefile.am b/cmd/Makefile.am index e79bfae2b10f..c1c4e2fe1c4c 100644 --- a/cmd/Makefile.am +++ b/cmd/Makefile.am @@ -1,118 +1,113 @@ bin_SCRIPTS = bin_PROGRAMS = sbin_SCRIPTS = sbin_PROGRAMS = dist_bin_SCRIPTS = zfsexec_PROGRAMS = mounthelper_PROGRAMS = sbin_SCRIPTS += fsck.zfs SHELLCHECKSCRIPTS += fsck.zfs CLEANFILES += fsck.zfs dist_noinst_DATA += %D%/fsck.zfs.in $(call SUBST,fsck.zfs,%D%/) sbin_PROGRAMS += zfs_ids_to_path CPPCHECKTARGETS += zfs_ids_to_path zfs_ids_to_path_SOURCES = \ %D%/zfs_ids_to_path.c zfs_ids_to_path_LDADD = \ libzfs.la zhack_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS) sbin_PROGRAMS += zhack CPPCHECKTARGETS += zhack zhack_SOURCES = \ %D%/zhack.c zhack_LDADD = \ libzpool.la \ libzfs_core.la \ libnvpair.la ztest_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) ztest_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS) sbin_PROGRAMS += ztest CPPCHECKTARGETS += ztest ztest_SOURCES = \ %D%/ztest.c ztest_LDADD = \ libzpool.la \ libzfs_core.la \ libnvpair.la ztest_LDADD += -lm ztest_LDFLAGS = -pthread include $(srcdir)/%D%/raidz_test/Makefile.am include $(srcdir)/%D%/zdb/Makefile.am include $(srcdir)/%D%/zfs/Makefile.am include $(srcdir)/%D%/zinject/Makefile.am include $(srcdir)/%D%/zpool/Makefile.am include $(srcdir)/%D%/zpool_influxdb/Makefile.am include $(srcdir)/%D%/zstream/Makefile.am if BUILD_LINUX mounthelper_PROGRAMS += mount.zfs CPPCHECKTARGETS += mount.zfs mount_zfs_SOURCES = \ %D%/mount_zfs.c mount_zfs_LDADD = \ libzfs.la \ libzfs_core.la \ libnvpair.la mount_zfs_LDADD += $(LTLIBINTL) CPPCHECKTARGETS += raidz_test sbin_PROGRAMS += zgenhostid CPPCHECKTARGETS += zgenhostid zgenhostid_SOURCES = \ %D%/zgenhostid.c dist_bin_SCRIPTS += %D%/zvol_wait SHELLCHECKSCRIPTS += %D%/zvol_wait include $(srcdir)/%D%/zed/Makefile.am endif if USING_PYTHON bin_SCRIPTS += arc_summary arcstat dbufstat zilstat CLEANFILES += arc_summary arcstat dbufstat zilstat dist_noinst_DATA += %D%/arc_summary %D%/arcstat.in %D%/dbufstat.in %D%/zilstat.in $(call SUBST,arcstat,%D%/) $(call SUBST,dbufstat,%D%/) $(call SUBST,zilstat,%D%/) arc_summary: %D%/arc_summary $(AM_V_at)cp $< $@ - -cmd-rename-install-exec-hook: - $(LN_S) -f arcstat $(DESTDIR)$(bindir)/zarcstat - $(LN_S) -f arc_summary $(DESTDIR)$(bindir)/zarcsummary -INSTALL_EXEC_HOOKS += cmd-rename-install-exec-hook endif PHONY += cmd cmd: $(bin_SCRIPTS) $(bin_PROGRAMS) $(sbin_SCRIPTS) $(sbin_PROGRAMS) $(dist_bin_SCRIPTS) $(zfsexec_PROGRAMS) $(mounthelper_PROGRAMS) diff --git a/cmd/arc_summary b/cmd/arc_summary index 9538dd599cb7..e60c6b64e8a1 100755 --- a/cmd/arc_summary +++ b/cmd/arc_summary @@ -1,1080 +1,1073 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2008 Ben Rockwood , # Copyright (c) 2010 Martin Matuska , # Copyright (c) 2010-2011 Jason J. Hellenthal , # Copyright (c) 2017 Scot W. Stevenson # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. """Print statistics on the ZFS ARC Cache and other information Provides basic information on the ARC, its efficiency, the L2ARC (if present), the Data Management Unit (DMU), Virtual Devices (VDEVs), and tunables. See the in-source documentation and code at https://github.com/openzfs/zfs/blob/master/module/zfs/arc.c for details. The original introduction to arc_summary can be found at http://cuddletech.com/?p=454 """ import argparse import os import subprocess import sys import time import errno # We can't use env -S portably, and we need python3 -u to handle pipes in # the shell abruptly closing the way we want to, so... import io if isinstance(sys.__stderr__.buffer, io.BufferedWriter): os.execv(sys.executable, [sys.executable, "-u"] + sys.argv) DESCRIPTION = 'Print ARC and other statistics for OpenZFS' INDENT = ' '*8 LINE_LENGTH = 72 DATE_FORMAT = '%a %b %d %H:%M:%S %Y' TITLE = 'ZFS Subsystem Report' SECTIONS = 'arc archits dmu l2arc spl tunables vdev zil'.split() SECTION_HELP = 'print info from one section ('+' '.join(SECTIONS)+')' # Tunables and SPL are handled separately because they come from # different sources SECTION_PATHS = {'arc': 'arcstats', 'dmu': 'dmu_tx', 'l2arc': 'arcstats', # L2ARC stuff lives in arcstats 'zfetch': 'zfetchstats', 'zil': 'zil'} parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('-a', '--alternate', action='store_true', default=False, help='use alternate formatting for tunables and SPL', dest='alt') parser.add_argument('-d', '--description', action='store_true', default=False, help='print descriptions with tunables and SPL', dest='desc') parser.add_argument('-g', '--graph', action='store_true', default=False, help='print graph on ARC use and exit', dest='graph') parser.add_argument('-p', '--page', type=int, dest='page', help='print page by number (DEPRECATED, use "-s")') parser.add_argument('-r', '--raw', action='store_true', default=False, help='dump all available data with minimal formatting', dest='raw') parser.add_argument('-s', '--section', dest='section', help=SECTION_HELP) ARGS = parser.parse_args() if sys.platform.startswith('freebsd'): # Requires py36-sysctl on FreeBSD import sysctl def is_value(ctl): return ctl.type != sysctl.CTLTYPE_NODE def namefmt(ctl, base='vfs.zfs.'): # base is removed from the name cut = len(base) return ctl.name[cut:] def load_kstats(section): base = 'kstat.zfs.misc.{section}.'.format(section=section) fmt = lambda kstat: '{name} : {value}'.format(name=namefmt(kstat, base), value=kstat.value) kstats = sysctl.filter(base) return [fmt(kstat) for kstat in kstats if is_value(kstat)] def get_params(base): ctls = sysctl.filter(base) return {namefmt(ctl): str(ctl.value) for ctl in ctls if is_value(ctl)} def get_tunable_params(): return get_params('vfs.zfs') def get_vdev_params(): return get_params('vfs.zfs.vdev') def get_version_impl(request): # FreeBSD reports versions for zpl and spa instead of zfs and spl. name = {'zfs': 'zpl', 'spl': 'spa'}[request] mib = 'vfs.zfs.version.{}'.format(name) version = sysctl.filter(mib)[0].value return '{} version {}'.format(name, version) def get_descriptions(_request): ctls = sysctl.filter('vfs.zfs') return {namefmt(ctl): ctl.description for ctl in ctls if is_value(ctl)} elif sys.platform.startswith('linux'): KSTAT_PATH = '/proc/spl/kstat/zfs' SPL_PATH = '/sys/module/spl/parameters' TUNABLES_PATH = '/sys/module/zfs/parameters' def load_kstats(section): path = os.path.join(KSTAT_PATH, section) with open(path) as f: return list(f)[2:] # Get rid of header def get_params(basepath): """Collect information on the Solaris Porting Layer (SPL) or the tunables, depending on the PATH given. Does not check if PATH is legal. """ result = {} for name in os.listdir(basepath): path = os.path.join(basepath, name) with open(path) as f: value = f.read() result[name] = value.strip() return result def get_spl_params(): return get_params(SPL_PATH) def get_tunable_params(): return get_params(TUNABLES_PATH) def get_vdev_params(): return get_params(TUNABLES_PATH) def get_version_impl(request): # The original arc_summary called /sbin/modinfo/{spl,zfs} to get # the version information. We switch to /sys/module/{spl,zfs}/version # to make sure we get what is really loaded in the kernel try: with open("/sys/module/{}/version".format(request)) as f: return f.read().strip() except: return "(unknown)" def get_descriptions(request): """Get the descriptions of the Solaris Porting Layer (SPL) or the tunables, return with minimal formatting. """ if request not in ('spl', 'zfs'): print('ERROR: description of "{0}" requested)'.format(request)) sys.exit(1) descs = {} target_prefix = 'parm:' # We would prefer to do this with /sys/modules -- see the discussion at # get_version() -- but there isn't a way to get the descriptions from # there, so we fall back on modinfo command = ["/sbin/modinfo", request, "-0"] info = '' try: info = subprocess.run(command, stdout=subprocess.PIPE, check=True, universal_newlines=True) raw_output = info.stdout.split('\0') except subprocess.CalledProcessError: print("Error: Descriptions not available", "(can't access kernel module)") sys.exit(1) for line in raw_output: if not line.startswith(target_prefix): continue line = line[len(target_prefix):].strip() name, raw_desc = line.split(':', 1) desc = raw_desc.rsplit('(', 1)[0] if desc == '': desc = '(No description found)' descs[name.strip()] = desc.strip() return descs def handle_unraisableException(exc_type, exc_value=None, exc_traceback=None, err_msg=None, object=None): handle_Exception(exc_type, object, exc_traceback) def handle_Exception(ex_cls, ex, tb): if ex_cls is KeyboardInterrupt: sys.exit() if ex_cls is BrokenPipeError: # It turns out that while sys.exit() triggers an exception # not handled message on Python 3.8+, os._exit() does not. os._exit(0) if ex_cls is OSError: if ex.errno == errno.ENOTCONN: sys.exit() raise ex if hasattr(sys,'unraisablehook'): # Python 3.8+ sys.unraisablehook = handle_unraisableException sys.excepthook = handle_Exception def cleanup_line(single_line): """Format a raw line of data from /proc and isolate the name value part, returning a tuple with each. Currently, this gets rid of the middle '4'. For example "arc_no_grow 4 0" returns the tuple ("arc_no_grow", "0"). """ name, _, value = single_line.split() return name, value def draw_graph(kstats_dict): """Draw a primitive graph representing the basic information on the ARC -- its size and the proportion used by MFU and MRU -- and quit. We use max size of the ARC to calculate how full it is. This is a very rough representation. """ arc_stats = isolate_section('arcstats', kstats_dict) GRAPH_INDENT = ' '*4 GRAPH_WIDTH = 70 arc_max = int(arc_stats['c_max']) arc_size = f_bytes(arc_stats['size']) arc_perc = f_perc(arc_stats['size'], arc_max) data_size = f_bytes(arc_stats['data_size']) meta_size = f_bytes(arc_stats['metadata_size']) dnode_size = f_bytes(arc_stats['dnode_size']) info_form = ('ARC: {0} ({1}) Data: {2} Meta: {3} Dnode: {4}') info_line = info_form.format(arc_size, arc_perc, data_size, meta_size, dnode_size) info_spc = ' '*int((GRAPH_WIDTH-len(info_line))/2) info_line = GRAPH_INDENT+info_spc+info_line graph_line = GRAPH_INDENT+'+'+('-'*(GRAPH_WIDTH-2))+'+' arc_perc = float(int(arc_stats['size'])/arc_max) data_perc = float(int(arc_stats['data_size'])/arc_max) meta_perc = float(int(arc_stats['metadata_size'])/arc_max) dnode_perc = float(int(arc_stats['dnode_size'])/arc_max) total_ticks = float(arc_perc)*GRAPH_WIDTH data_ticks = data_perc*GRAPH_WIDTH meta_ticks = meta_perc*GRAPH_WIDTH dnode_ticks = dnode_perc*GRAPH_WIDTH other_ticks = total_ticks-(data_ticks+meta_ticks+dnode_ticks) core_form = 'D'*int(data_ticks)+'M'*int(meta_ticks)+'N'*int(dnode_ticks)+\ 'O'*int(other_ticks) core_spc = ' '*(GRAPH_WIDTH-(2+len(core_form))) core_line = GRAPH_INDENT+'|'+core_form+core_spc+'|' for line in ('', info_line, graph_line, core_line, graph_line, ''): print(line) def f_bytes(byte_string): """Return human-readable representation of a byte value in powers of 2 (eg "KiB" for "kibibytes", etc) to two decimal points. Values smaller than one KiB are returned without decimal points. Note "bytes" is a reserved keyword. """ prefixes = ([2**80, "YiB"], # yobibytes (yotta) [2**70, "ZiB"], # zebibytes (zetta) [2**60, "EiB"], # exbibytes (exa) [2**50, "PiB"], # pebibytes (peta) [2**40, "TiB"], # tebibytes (tera) [2**30, "GiB"], # gibibytes (giga) [2**20, "MiB"], # mebibytes (mega) [2**10, "KiB"]) # kibibytes (kilo) bites = int(byte_string) if bites >= 2**10: for limit, unit in prefixes: if bites >= limit: value = bites / limit break result = '{0:.1f} {1}'.format(value, unit) else: result = '{0} Bytes'.format(bites) return result def f_hits(hits_string): """Create a human-readable representation of the number of hits. The single-letter symbols used are SI to avoid the confusion caused by the different "short scale" and "long scale" representations in English, which use the same words for different values. See https://en.wikipedia.org/wiki/Names_of_large_numbers and: https://physics.nist.gov/cuu/Units/prefixes.html """ numbers = ([10**24, 'Y'], # yotta (septillion) [10**21, 'Z'], # zetta (sextillion) [10**18, 'E'], # exa (quintrillion) [10**15, 'P'], # peta (quadrillion) [10**12, 'T'], # tera (trillion) [10**9, 'G'], # giga (billion) [10**6, 'M'], # mega (million) [10**3, 'k']) # kilo (thousand) hits = int(hits_string) if hits >= 1000: for limit, symbol in numbers: if hits >= limit: value = hits/limit break result = "%0.1f%s" % (value, symbol) else: result = "%d" % hits return result def f_perc(value1, value2): """Calculate percentage and return in human-readable form. If rounding produces the result '0.0' though the first number is not zero, include a 'less-than' symbol to avoid confusion. Division by zero is handled by returning 'n/a'; no error is called. """ v1 = float(value1) v2 = float(value2) try: perc = 100 * v1/v2 except ZeroDivisionError: result = 'n/a' else: result = '{0:0.1f} %'.format(perc) if result == '0.0 %' and v1 > 0: result = '< 0.1 %' return result def format_raw_line(name, value): """For the --raw option for the tunable and SPL outputs, decide on the correct formatting based on the --alternate flag. """ if ARGS.alt: result = '{0}{1}={2}'.format(INDENT, name, value) else: # Right-align the value within the line length if it fits, # otherwise just separate it from the name by a single space. fit = LINE_LENGTH - len(INDENT) - len(name) overflow = len(value) + 1 w = max(fit, overflow) result = '{0}{1}{2:>{w}}'.format(INDENT, name, value, w=w) return result def get_kstats(): """Collect information on the ZFS subsystem. The step does not perform any further processing, giving us the option to only work on what is actually needed. The name "kstat" is a holdover from the Solaris utility of the same name. """ result = {} for section in SECTION_PATHS.values(): if section not in result: result[section] = load_kstats(section) return result def get_version(request): """Get the version number of ZFS or SPL on this machine for header. Returns an error string, but does not raise an error, if we can't get the ZFS/SPL version. """ if request not in ('spl', 'zfs'): error_msg = '(ERROR: "{0}" requested)'.format(request) return error_msg return get_version_impl(request) def print_header(): """Print the initial heading with date and time as well as info on the kernel and ZFS versions. This is not called for the graph. """ # datetime is now recommended over time but we keep the exact formatting # from the older version of arc_summary in case there are scripts # that expect it in this way daydate = time.strftime(DATE_FORMAT) spc_date = LINE_LENGTH-len(daydate) sys_version = os.uname() sys_msg = sys_version.sysname+' '+sys_version.release zfs = get_version('zfs') spc_zfs = LINE_LENGTH-len(zfs) machine_msg = 'Machine: '+sys_version.nodename+' ('+sys_version.machine+')' spl = get_version('spl') spc_spl = LINE_LENGTH-len(spl) print('\n'+('-'*LINE_LENGTH)) print('{0:<{spc}}{1}'.format(TITLE, daydate, spc=spc_date)) print('{0:<{spc}}{1}'.format(sys_msg, zfs, spc=spc_zfs)) print('{0:<{spc}}{1}\n'.format(machine_msg, spl, spc=spc_spl)) def print_raw(kstats_dict): """Print all available data from the system in a minimally sorted format. This can be used as a source to be piped through 'grep'. """ sections = sorted(kstats_dict.keys()) for section in sections: print('\n{0}:'.format(section.upper())) lines = sorted(kstats_dict[section]) for line in lines: name, value = cleanup_line(line) print(format_raw_line(name, value)) # Tunables and SPL must be handled separately because they come from a # different source and have descriptions the user might request print() section_spl() section_tunables() def isolate_section(section_name, kstats_dict): """From the complete information on all sections, retrieve only those for one section. """ try: section_data = kstats_dict[section_name] except KeyError: print('ERROR: Data on {0} not available'.format(section_data)) sys.exit(1) section_dict = dict(cleanup_line(l) for l in section_data) return section_dict # Formatted output helper functions def prt_1(text, value): """Print text and one value, no indent""" spc = ' '*(LINE_LENGTH-(len(text)+len(value))) print('{0}{spc}{1}'.format(text, value, spc=spc)) def prt_i1(text, value): """Print text and one value, with indent""" spc = ' '*(LINE_LENGTH-(len(INDENT)+len(text)+len(value))) print(INDENT+'{0}{spc}{1}'.format(text, value, spc=spc)) def prt_2(text, value1, value2): """Print text and two values, no indent""" values = '{0:>9} {1:>9}'.format(value1, value2) spc = ' '*(LINE_LENGTH-(len(text)+len(values)+2)) print('{0}{spc} {1}'.format(text, values, spc=spc)) def prt_i2(text, value1, value2): """Print text and two values, with indent""" values = '{0:>9} {1:>9}'.format(value1, value2) spc = ' '*(LINE_LENGTH-(len(INDENT)+len(text)+len(values)+2)) print(INDENT+'{0}{spc} {1}'.format(text, values, spc=spc)) # The section output concentrates on important parameters instead of # being exhaustive (that is what the --raw parameter is for) def section_arc(kstats_dict): """Give basic information on the ARC, MRU and MFU. This is the first and most used section. """ arc_stats = isolate_section('arcstats', kstats_dict) memory_all = arc_stats['memory_all_bytes'] memory_free = arc_stats['memory_free_bytes'] memory_avail = arc_stats['memory_available_bytes'] arc_size = arc_stats['size'] arc_target_size = arc_stats['c'] arc_max = arc_stats['c_max'] arc_min = arc_stats['c_min'] dnode_limit = arc_stats['arc_dnode_limit'] print('ARC status:') prt_i1('Total memory size:', f_bytes(memory_all)) prt_i2('Min target size:', f_perc(arc_min, memory_all), f_bytes(arc_min)) prt_i2('Max target size:', f_perc(arc_max, memory_all), f_bytes(arc_max)) prt_i2('Target size (adaptive):', f_perc(arc_size, arc_max), f_bytes(arc_target_size)) prt_i2('Current size:', f_perc(arc_size, arc_max), f_bytes(arc_size)) prt_i1('Free memory size:', f_bytes(memory_free)) prt_i1('Available memory size:', f_bytes(memory_avail)) print() compressed_size = arc_stats['compressed_size'] uncompressed_size = arc_stats['uncompressed_size'] overhead_size = arc_stats['overhead_size'] bonus_size = arc_stats['bonus_size'] dnode_size = arc_stats['dnode_size'] dbuf_size = arc_stats['dbuf_size'] hdr_size = arc_stats['hdr_size'] l2_hdr_size = arc_stats['l2_hdr_size'] abd_chunk_waste_size = arc_stats['abd_chunk_waste_size'] prt_1('ARC structural breakdown (current size):', f_bytes(arc_size)) prt_i2('Compressed size:', f_perc(compressed_size, arc_size), f_bytes(compressed_size)) prt_i2('Overhead size:', f_perc(overhead_size, arc_size), f_bytes(overhead_size)) prt_i2('Bonus size:', f_perc(bonus_size, arc_size), f_bytes(bonus_size)) prt_i2('Dnode size:', f_perc(dnode_size, arc_size), f_bytes(dnode_size)) prt_i2('Dbuf size:', f_perc(dbuf_size, arc_size), f_bytes(dbuf_size)) prt_i2('Header size:', f_perc(hdr_size, arc_size), f_bytes(hdr_size)) prt_i2('L2 header size:', f_perc(l2_hdr_size, arc_size), f_bytes(l2_hdr_size)) prt_i2('ABD chunk waste size:', f_perc(abd_chunk_waste_size, arc_size), f_bytes(abd_chunk_waste_size)) print() meta = arc_stats['meta'] pd = arc_stats['pd'] pm = arc_stats['pm'] data_size = arc_stats['data_size'] metadata_size = arc_stats['metadata_size'] anon_data = arc_stats['anon_data'] anon_metadata = arc_stats['anon_metadata'] mfu_data = arc_stats['mfu_data'] mfu_metadata = arc_stats['mfu_metadata'] mfu_edata = arc_stats['mfu_evictable_data'] mfu_emetadata = arc_stats['mfu_evictable_metadata'] mru_data = arc_stats['mru_data'] mru_metadata = arc_stats['mru_metadata'] mru_edata = arc_stats['mru_evictable_data'] mru_emetadata = arc_stats['mru_evictable_metadata'] mfug_data = arc_stats['mfu_ghost_data'] mfug_metadata = arc_stats['mfu_ghost_metadata'] mrug_data = arc_stats['mru_ghost_data'] mrug_metadata = arc_stats['mru_ghost_metadata'] unc_data = arc_stats['uncached_data'] unc_metadata = arc_stats['uncached_metadata'] caches_size = int(anon_data)+int(anon_metadata)+\ int(mfu_data)+int(mfu_metadata)+int(mru_data)+int(mru_metadata)+\ int(unc_data)+int(unc_metadata) prt_1('ARC types breakdown (compressed + overhead):', f_bytes(caches_size)) prt_i2('Data size:', f_perc(data_size, caches_size), f_bytes(data_size)) prt_i2('Metadata size:', f_perc(metadata_size, caches_size), f_bytes(metadata_size)) print() prt_1('ARC states breakdown (compressed + overhead):', f_bytes(caches_size)) prt_i2('Anonymous data size:', f_perc(anon_data, caches_size), f_bytes(anon_data)) prt_i2('Anonymous metadata size:', f_perc(anon_metadata, caches_size), f_bytes(anon_metadata)) s = 4294967296 v = (s-int(pd))*(s-int(meta))/s prt_i2('MFU data target:', f_perc(v, s), f_bytes(v / 65536 * caches_size / 65536)) prt_i2('MFU data size:', f_perc(mfu_data, caches_size), f_bytes(mfu_data)) prt_i2('MFU evictable data size:', f_perc(mfu_edata, caches_size), f_bytes(mfu_edata)) prt_i1('MFU ghost data size:', f_bytes(mfug_data)) v = (s-int(pm))*int(meta)/s prt_i2('MFU metadata target:', f_perc(v, s), f_bytes(v / 65536 * caches_size / 65536)) prt_i2('MFU metadata size:', f_perc(mfu_metadata, caches_size), f_bytes(mfu_metadata)) prt_i2('MFU evictable metadata size:', f_perc(mfu_emetadata, caches_size), f_bytes(mfu_emetadata)) prt_i1('MFU ghost metadata size:', f_bytes(mfug_metadata)) v = int(pd)*(s-int(meta))/s prt_i2('MRU data target:', f_perc(v, s), f_bytes(v / 65536 * caches_size / 65536)) prt_i2('MRU data size:', f_perc(mru_data, caches_size), f_bytes(mru_data)) prt_i2('MRU evictable data size:', f_perc(mru_edata, caches_size), f_bytes(mru_edata)) prt_i1('MRU ghost data size:', f_bytes(mrug_data)) v = int(pm)*int(meta)/s prt_i2('MRU metadata target:', f_perc(v, s), f_bytes(v / 65536 * caches_size / 65536)) prt_i2('MRU metadata size:', f_perc(mru_metadata, caches_size), f_bytes(mru_metadata)) prt_i2('MRU evictable metadata size:', f_perc(mru_emetadata, caches_size), f_bytes(mru_emetadata)) prt_i1('MRU ghost metadata size:', f_bytes(mrug_metadata)) prt_i2('Uncached data size:', f_perc(unc_data, caches_size), f_bytes(unc_data)) prt_i2('Uncached metadata size:', f_perc(unc_metadata, caches_size), f_bytes(unc_metadata)) print() print('ARC hash breakdown:') prt_i1('Elements:', f_hits(arc_stats['hash_elements'])) prt_i1('Collisions:', f_hits(arc_stats['hash_collisions'])) prt_i1('Chain max:', f_hits(arc_stats['hash_chain_max'])) prt_i1('Chains:', f_hits(arc_stats['hash_chains'])) print() print('ARC misc:') prt_i2('Uncompressed size:', f_perc(uncompressed_size, compressed_size), f_bytes(uncompressed_size)) prt_i1('Memory throttles:', arc_stats['memory_throttle_count']) prt_i1('Memory direct reclaims:', arc_stats['memory_direct_count']) prt_i1('Memory indirect reclaims:', arc_stats['memory_indirect_count']) prt_i1('Deleted:', f_hits(arc_stats['deleted'])) prt_i1('Mutex misses:', f_hits(arc_stats['mutex_miss'])) prt_i1('Eviction skips:', f_hits(arc_stats['evict_skip'])) prt_i1('Eviction skips due to L2 writes:', f_hits(arc_stats['evict_l2_skip'])) prt_i1('L2 cached evictions:', f_bytes(arc_stats['evict_l2_cached'])) prt_i1('L2 eligible evictions:', f_bytes(arc_stats['evict_l2_eligible'])) prt_i2('L2 eligible MFU evictions:', f_perc(arc_stats['evict_l2_eligible_mfu'], arc_stats['evict_l2_eligible']), f_bytes(arc_stats['evict_l2_eligible_mfu'])) prt_i2('L2 eligible MRU evictions:', f_perc(arc_stats['evict_l2_eligible_mru'], arc_stats['evict_l2_eligible']), f_bytes(arc_stats['evict_l2_eligible_mru'])) prt_i1('L2 ineligible evictions:', f_bytes(arc_stats['evict_l2_ineligible'])) print() def section_archits(kstats_dict): """Print information on how the caches are accessed ("arc hits"). """ arc_stats = isolate_section('arcstats', kstats_dict) all_accesses = int(arc_stats['hits'])+int(arc_stats['iohits'])+\ int(arc_stats['misses']) prt_1('ARC total accesses:', f_hits(all_accesses)) ta_todo = (('Total hits:', arc_stats['hits']), ('Total I/O hits:', arc_stats['iohits']), ('Total misses:', arc_stats['misses'])) for title, value in ta_todo: prt_i2(title, f_perc(value, all_accesses), f_hits(value)) print() dd_total = int(arc_stats['demand_data_hits']) +\ int(arc_stats['demand_data_iohits']) +\ int(arc_stats['demand_data_misses']) prt_2('ARC demand data accesses:', f_perc(dd_total, all_accesses), f_hits(dd_total)) dd_todo = (('Demand data hits:', arc_stats['demand_data_hits']), ('Demand data I/O hits:', arc_stats['demand_data_iohits']), ('Demand data misses:', arc_stats['demand_data_misses'])) for title, value in dd_todo: prt_i2(title, f_perc(value, dd_total), f_hits(value)) print() dm_total = int(arc_stats['demand_metadata_hits']) +\ int(arc_stats['demand_metadata_iohits']) +\ int(arc_stats['demand_metadata_misses']) prt_2('ARC demand metadata accesses:', f_perc(dm_total, all_accesses), f_hits(dm_total)) dm_todo = (('Demand metadata hits:', arc_stats['demand_metadata_hits']), ('Demand metadata I/O hits:', arc_stats['demand_metadata_iohits']), ('Demand metadata misses:', arc_stats['demand_metadata_misses'])) for title, value in dm_todo: prt_i2(title, f_perc(value, dm_total), f_hits(value)) print() pd_total = int(arc_stats['prefetch_data_hits']) +\ int(arc_stats['prefetch_data_iohits']) +\ int(arc_stats['prefetch_data_misses']) prt_2('ARC prefetch data accesses:', f_perc(pd_total, all_accesses), f_hits(pd_total)) pd_todo = (('Prefetch data hits:', arc_stats['prefetch_data_hits']), ('Prefetch data I/O hits:', arc_stats['prefetch_data_iohits']), ('Prefetch data misses:', arc_stats['prefetch_data_misses'])) for title, value in pd_todo: prt_i2(title, f_perc(value, pd_total), f_hits(value)) print() pm_total = int(arc_stats['prefetch_metadata_hits']) +\ int(arc_stats['prefetch_metadata_iohits']) +\ int(arc_stats['prefetch_metadata_misses']) prt_2('ARC prefetch metadata accesses:', f_perc(pm_total, all_accesses), f_hits(pm_total)) pm_todo = (('Prefetch metadata hits:', arc_stats['prefetch_metadata_hits']), ('Prefetch metadata I/O hits:', arc_stats['prefetch_metadata_iohits']), ('Prefetch metadata misses:', arc_stats['prefetch_metadata_misses'])) for title, value in pm_todo: prt_i2(title, f_perc(value, pm_total), f_hits(value)) print() all_prefetches = int(arc_stats['predictive_prefetch'])+\ int(arc_stats['prescient_prefetch']) prt_2('ARC predictive prefetches:', f_perc(arc_stats['predictive_prefetch'], all_prefetches), f_hits(arc_stats['predictive_prefetch'])) prt_i2('Demand hits after predictive:', f_perc(arc_stats['demand_hit_predictive_prefetch'], arc_stats['predictive_prefetch']), f_hits(arc_stats['demand_hit_predictive_prefetch'])) prt_i2('Demand I/O hits after predictive:', f_perc(arc_stats['demand_iohit_predictive_prefetch'], arc_stats['predictive_prefetch']), f_hits(arc_stats['demand_iohit_predictive_prefetch'])) never = int(arc_stats['predictive_prefetch']) -\ int(arc_stats['demand_hit_predictive_prefetch']) -\ int(arc_stats['demand_iohit_predictive_prefetch']) prt_i2('Never demanded after predictive:', f_perc(never, arc_stats['predictive_prefetch']), f_hits(never)) print() prt_2('ARC prescient prefetches:', f_perc(arc_stats['prescient_prefetch'], all_prefetches), f_hits(arc_stats['prescient_prefetch'])) prt_i2('Demand hits after prescient:', f_perc(arc_stats['demand_hit_prescient_prefetch'], arc_stats['prescient_prefetch']), f_hits(arc_stats['demand_hit_prescient_prefetch'])) prt_i2('Demand I/O hits after prescient:', f_perc(arc_stats['demand_iohit_prescient_prefetch'], arc_stats['prescient_prefetch']), f_hits(arc_stats['demand_iohit_prescient_prefetch'])) never = int(arc_stats['prescient_prefetch'])-\ int(arc_stats['demand_hit_prescient_prefetch'])-\ int(arc_stats['demand_iohit_prescient_prefetch']) prt_i2('Never demanded after prescient:', f_perc(never, arc_stats['prescient_prefetch']), f_hits(never)) print() print('ARC states hits of all accesses:') cl_todo = (('Most frequently used (MFU):', arc_stats['mfu_hits']), ('Most recently used (MRU):', arc_stats['mru_hits']), ('Most frequently used (MFU) ghost:', arc_stats['mfu_ghost_hits']), ('Most recently used (MRU) ghost:', arc_stats['mru_ghost_hits']), ('Uncached:', arc_stats['uncached_hits'])) for title, value in cl_todo: prt_i2(title, f_perc(value, all_accesses), f_hits(value)) print() def section_dmu(kstats_dict): """Collect information on the DMU""" zfetch_stats = isolate_section('zfetchstats', kstats_dict) zfetch_access_total = int(zfetch_stats['hits']) +\ int(zfetch_stats['future']) + int(zfetch_stats['stride']) +\ int(zfetch_stats['past']) + int(zfetch_stats['misses']) prt_1('DMU predictive prefetcher calls:', f_hits(zfetch_access_total)) prt_i2('Stream hits:', f_perc(zfetch_stats['hits'], zfetch_access_total), f_hits(zfetch_stats['hits'])) future = int(zfetch_stats['future']) + int(zfetch_stats['stride']) prt_i2('Hits ahead of stream:', f_perc(future, zfetch_access_total), f_hits(future)) prt_i2('Hits behind stream:', f_perc(zfetch_stats['past'], zfetch_access_total), f_hits(zfetch_stats['past'])) prt_i2('Stream misses:', f_perc(zfetch_stats['misses'], zfetch_access_total), f_hits(zfetch_stats['misses'])) prt_i2('Streams limit reached:', f_perc(zfetch_stats['max_streams'], zfetch_stats['misses']), f_hits(zfetch_stats['max_streams'])) prt_i1('Stream strides:', f_hits(zfetch_stats['stride'])) prt_i1('Prefetches issued', f_hits(zfetch_stats['io_issued'])) print() def section_l2arc(kstats_dict): """Collect information on L2ARC device if present. If not, tell user that we're skipping the section. """ # The L2ARC statistics live in the same section as the normal ARC stuff arc_stats = isolate_section('arcstats', kstats_dict) if arc_stats['l2_size'] == '0': print('L2ARC not detected, skipping section\n') return l2_errors = int(arc_stats['l2_writes_error']) +\ int(arc_stats['l2_cksum_bad']) +\ int(arc_stats['l2_io_error']) l2_access_total = int(arc_stats['l2_hits'])+int(arc_stats['l2_misses']) health = 'HEALTHY' if l2_errors > 0: health = 'DEGRADED' prt_1('L2ARC status:', health) l2_todo = (('Low memory aborts:', 'l2_abort_lowmem'), ('Free on write:', 'l2_free_on_write'), ('R/W clashes:', 'l2_rw_clash'), ('Bad checksums:', 'l2_cksum_bad'), ('Read errors:', 'l2_io_error'), ('Write errors:', 'l2_writes_error')) for title, value in l2_todo: prt_i1(title, f_hits(arc_stats[value])) print() prt_1('L2ARC size (adaptive):', f_bytes(arc_stats['l2_size'])) prt_i2('Compressed:', f_perc(arc_stats['l2_asize'], arc_stats['l2_size']), f_bytes(arc_stats['l2_asize'])) prt_i2('Header size:', f_perc(arc_stats['l2_hdr_size'], arc_stats['l2_size']), f_bytes(arc_stats['l2_hdr_size'])) prt_i2('MFU allocated size:', f_perc(arc_stats['l2_mfu_asize'], arc_stats['l2_asize']), f_bytes(arc_stats['l2_mfu_asize'])) prt_i2('MRU allocated size:', f_perc(arc_stats['l2_mru_asize'], arc_stats['l2_asize']), f_bytes(arc_stats['l2_mru_asize'])) prt_i2('Prefetch allocated size:', f_perc(arc_stats['l2_prefetch_asize'], arc_stats['l2_asize']), f_bytes(arc_stats['l2_prefetch_asize'])) prt_i2('Data (buffer content) allocated size:', f_perc(arc_stats['l2_bufc_data_asize'], arc_stats['l2_asize']), f_bytes(arc_stats['l2_bufc_data_asize'])) prt_i2('Metadata (buffer content) allocated size:', f_perc(arc_stats['l2_bufc_metadata_asize'], arc_stats['l2_asize']), f_bytes(arc_stats['l2_bufc_metadata_asize'])) print() prt_1('L2ARC breakdown:', f_hits(l2_access_total)) prt_i2('Hit ratio:', f_perc(arc_stats['l2_hits'], l2_access_total), f_hits(arc_stats['l2_hits'])) prt_i2('Miss ratio:', f_perc(arc_stats['l2_misses'], l2_access_total), f_hits(arc_stats['l2_misses'])) print() print('L2ARC I/O:') prt_i2('Reads:', f_bytes(arc_stats['l2_read_bytes']), f_hits(arc_stats['l2_hits'])) prt_i2('Writes:', f_bytes(arc_stats['l2_write_bytes']), f_hits(arc_stats['l2_writes_sent'])) print() print('L2ARC evicts:') prt_i1('L1 cached:', f_hits(arc_stats['l2_evict_l1cached'])) prt_i1('While reading:', f_hits(arc_stats['l2_evict_reading'])) print() def section_spl(*_): """Print the SPL parameters, if requested with alternative format and/or descriptions. This does not use kstats. """ if sys.platform.startswith('freebsd'): # No SPL support in FreeBSD return spls = get_spl_params() keylist = sorted(spls.keys()) print('Solaris Porting Layer (SPL):') if ARGS.desc: descriptions = get_descriptions('spl') for key in keylist: value = spls[key] if ARGS.desc: try: print(INDENT+'#', descriptions[key]) except KeyError: print(INDENT+'# (No description found)') # paranoid print(format_raw_line(key, value)) print() def section_tunables(*_): """Print the tunables, if requested with alternative format and/or descriptions. This does not use kstasts. """ tunables = get_tunable_params() keylist = sorted(tunables.keys()) print('Tunables:') if ARGS.desc: descriptions = get_descriptions('zfs') for key in keylist: value = tunables[key] if ARGS.desc: try: print(INDENT+'#', descriptions[key]) except KeyError: print(INDENT+'# (No description found)') # paranoid print(format_raw_line(key, value)) print() def section_zil(kstats_dict): """Collect information on the ZFS Intent Log. Some of the information taken from https://github.com/openzfs/zfs/blob/master/include/sys/zil.h """ zil_stats = isolate_section('zil', kstats_dict) prt_1('ZIL committed transactions:', f_hits(zil_stats['zil_itx_count'])) prt_i1('Commit requests:', f_hits(zil_stats['zil_commit_count'])) prt_i1('Flushes to stable storage:', f_hits(zil_stats['zil_commit_writer_count'])) prt_i2('Transactions to SLOG storage pool:', f_bytes(zil_stats['zil_itx_metaslab_slog_bytes']), f_hits(zil_stats['zil_itx_metaslab_slog_count'])) prt_i2('Transactions to non-SLOG storage pool:', f_bytes(zil_stats['zil_itx_metaslab_normal_bytes']), f_hits(zil_stats['zil_itx_metaslab_normal_count'])) print() section_calls = {'arc': section_arc, 'archits': section_archits, 'dmu': section_dmu, 'l2arc': section_l2arc, 'spl': section_spl, 'tunables': section_tunables, 'zil': section_zil} def main(): """Run program. The options to draw a graph and to print all data raw are treated separately because they come with their own call. """ - # notify user for upcoming renaming in 2.4.0 - abs_path = os.path.abspath(sys.argv[0].strip()) - script_name = os.path.basename(abs_path) - if script_name != "zarcsummary": - sys.stderr.write("Note: this script will be renamed to zarcsummary in ") - sys.stderr.write("zfs 2.4.0. Please migrate ASAP.\n") - kstats = get_kstats() if ARGS.graph: draw_graph(kstats) sys.exit(0) print_header() if ARGS.raw: print_raw(kstats) elif ARGS.section: try: section_calls[ARGS.section](kstats) except KeyError: print('Error: Section "{0}" unknown'.format(ARGS.section)) sys.exit(1) elif ARGS.page: print('WARNING: Pages are deprecated, please use "--section"\n') pages_to_calls = {1: 'arc', 2: 'archits', 3: 'l2arc', 4: 'dmu', 5: 'vdev', 6: 'tunables'} try: call = pages_to_calls[ARGS.page] except KeyError: print('Error: Page "{0}" not supported'.format(ARGS.page)) sys.exit(1) else: section_calls[call](kstats) else: # If no parameters were given, we print all sections. We might want to # change the sequence by hand calls = sorted(section_calls.keys()) for section in calls: section_calls[section](kstats) sys.exit(0) if __name__ == '__main__': main() diff --git a/cmd/arcstat.in b/cmd/arcstat.in index e153eddb36cf..10115aeb105e 100755 --- a/cmd/arcstat.in +++ b/cmd/arcstat.in @@ -1,812 +1,805 @@ #!/usr/bin/env @PYTHON_SHEBANG@ # SPDX-License-Identifier: CDDL-1.0 # # Print out ZFS ARC Statistics exported via kstat(1) # For a definition of fields, or usage, use arcstat -v # # This script was originally a fork of the original arcstat.pl (0.1) # by Neelakanth Nadgir, originally published on his Sun blog on # 09/18/2007 # http://blogs.sun.com/realneel/entry/zfs_arc_statistics # # A new version aimed to improve upon the original by adding features # and fixing bugs as needed. This version was maintained by Mike # Harsch and was hosted in a public open source repository: # http://github.com/mharsch/arcstat # # but has since moved to the illumos-gate repository. # # This Python port was written by John Hixson for FreeNAS, introduced # in commit e2c29f: # https://github.com/freenas/freenas # # and has been improved by many people since. # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or https://opensource.org/licenses/CDDL-1.0. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Fields have a fixed width. Every interval, we fill the "v" # hash with its corresponding value (v[field]=value) using calculate(). # @hdr is the array of fields that needs to be printed, so we # just iterate over this array and print the values using our pretty printer. # # This script must remain compatible with Python 3.6+. # import sys import time import getopt import re import copy import os from signal import signal, SIGINT, SIGWINCH, SIG_DFL cols = { # HDR: [Size, Scale, Description] "time": [8, -1, "Time"], "hits": [4, 1000, "ARC hits per second"], "iohs": [4, 1000, "ARC I/O hits per second"], "miss": [4, 1000, "ARC misses per second"], "read": [4, 1000, "Total ARC accesses per second"], "hit%": [4, 100, "ARC hit percentage"], "ioh%": [4, 100, "ARC I/O hit percentage"], "miss%": [5, 100, "ARC miss percentage"], "dhit": [4, 1000, "Demand hits per second"], "dioh": [4, 1000, "Demand I/O hits per second"], "dmis": [4, 1000, "Demand misses per second"], "dh%": [3, 100, "Demand hit percentage"], "di%": [3, 100, "Demand I/O hit percentage"], "dm%": [3, 100, "Demand miss percentage"], "ddhit": [5, 1000, "Demand data hits per second"], "ddioh": [5, 1000, "Demand data I/O hits per second"], "ddmis": [5, 1000, "Demand data misses per second"], "ddh%": [4, 100, "Demand data hit percentage"], "ddi%": [4, 100, "Demand data I/O hit percentage"], "ddm%": [4, 100, "Demand data miss percentage"], "dmhit": [5, 1000, "Demand metadata hits per second"], "dmioh": [5, 1000, "Demand metadata I/O hits per second"], "dmmis": [5, 1000, "Demand metadata misses per second"], "dmh%": [4, 100, "Demand metadata hit percentage"], "dmi%": [4, 100, "Demand metadata I/O hit percentage"], "dmm%": [4, 100, "Demand metadata miss percentage"], "phit": [4, 1000, "Prefetch hits per second"], "pioh": [4, 1000, "Prefetch I/O hits per second"], "pmis": [4, 1000, "Prefetch misses per second"], "ph%": [3, 100, "Prefetch hits percentage"], "pi%": [3, 100, "Prefetch I/O hits percentage"], "pm%": [3, 100, "Prefetch miss percentage"], "pdhit": [5, 1000, "Prefetch data hits per second"], "pdioh": [5, 1000, "Prefetch data I/O hits per second"], "pdmis": [5, 1000, "Prefetch data misses per second"], "pdh%": [4, 100, "Prefetch data hits percentage"], "pdi%": [4, 100, "Prefetch data I/O hits percentage"], "pdm%": [4, 100, "Prefetch data miss percentage"], "pmhit": [5, 1000, "Prefetch metadata hits per second"], "pmioh": [5, 1000, "Prefetch metadata I/O hits per second"], "pmmis": [5, 1000, "Prefetch metadata misses per second"], "pmh%": [4, 100, "Prefetch metadata hits percentage"], "pmi%": [4, 100, "Prefetch metadata I/O hits percentage"], "pmm%": [4, 100, "Prefetch metadata miss percentage"], "mhit": [4, 1000, "Metadata hits per second"], "mioh": [4, 1000, "Metadata I/O hits per second"], "mmis": [4, 1000, "Metadata misses per second"], "mread": [5, 1000, "Metadata accesses per second"], "mh%": [3, 100, "Metadata hit percentage"], "mi%": [3, 100, "Metadata I/O hit percentage"], "mm%": [3, 100, "Metadata miss percentage"], "arcsz": [5, 1024, "ARC size"], "size": [5, 1024, "ARC size"], "c": [5, 1024, "ARC target size"], "mfu": [4, 1000, "MFU list hits per second"], "mru": [4, 1000, "MRU list hits per second"], "mfug": [4, 1000, "MFU ghost list hits per second"], "mrug": [4, 1000, "MRU ghost list hits per second"], "unc": [4, 1000, "Uncached list hits per second"], "eskip": [5, 1000, "evict_skip per second"], "el2skip": [7, 1000, "evict skip, due to l2 writes, per second"], "el2cach": [7, 1024, "Size of L2 cached evictions per second"], "el2el": [5, 1024, "Size of L2 eligible evictions per second"], "el2mfu": [6, 1024, "Size of L2 eligible MFU evictions per second"], "el2mru": [6, 1024, "Size of L2 eligible MRU evictions per second"], "el2inel": [7, 1024, "Size of L2 ineligible evictions per second"], "mtxmis": [6, 1000, "mutex_miss per second"], "dread": [5, 1000, "Demand accesses per second"], "ddread": [6, 1000, "Demand data accesses per second"], "dmread": [6, 1000, "Demand metadata accesses per second"], "pread": [5, 1000, "Prefetch accesses per second"], "pdread": [6, 1000, "Prefetch data accesses per second"], "pmread": [6, 1000, "Prefetch metadata accesses per second"], "l2hits": [6, 1000, "L2ARC hits per second"], "l2miss": [6, 1000, "L2ARC misses per second"], "l2read": [6, 1000, "Total L2ARC accesses per second"], "l2hit%": [6, 100, "L2ARC access hit percentage"], "l2miss%": [7, 100, "L2ARC access miss percentage"], "l2pref": [6, 1024, "L2ARC prefetch allocated size"], "l2mfu": [5, 1024, "L2ARC MFU allocated size"], "l2mru": [5, 1024, "L2ARC MRU allocated size"], "l2data": [6, 1024, "L2ARC data allocated size"], "l2meta": [6, 1024, "L2ARC metadata allocated size"], "l2pref%": [7, 100, "L2ARC prefetch percentage"], "l2mfu%": [6, 100, "L2ARC MFU percentage"], "l2mru%": [6, 100, "L2ARC MRU percentage"], "l2data%": [7, 100, "L2ARC data percentage"], "l2meta%": [7, 100, "L2ARC metadata percentage"], "l2asize": [7, 1024, "Actual (compressed) size of the L2ARC"], "l2size": [6, 1024, "Size of the L2ARC"], "l2bytes": [7, 1024, "Bytes read per second from the L2ARC"], "l2wbytes": [8, 1024, "Bytes written per second to the L2ARC"], "grow": [4, 1000, "ARC grow disabled"], "need": [5, 1024, "ARC reclaim need"], "free": [5, 1024, "ARC free memory"], "avail": [5, 1024, "ARC available memory"], "waste": [5, 1024, "Wasted memory due to round up to pagesize"], "ztotal": [6, 1000, "zfetch total prefetcher calls per second"], "zhits": [5, 1000, "zfetch stream hits per second"], "zahead": [6, 1000, "zfetch hits ahead of streams per second"], "zpast": [5, 1000, "zfetch hits behind streams per second"], "zmisses": [7, 1000, "zfetch stream misses per second"], "zmax": [4, 1000, "zfetch limit reached per second"], "zfuture": [7, 1000, "zfetch stream future per second"], "zstride": [7, 1000, "zfetch stream strides per second"], "zissued": [7, 1000, "zfetch prefetches issued per second"], "zactive": [7, 1000, "zfetch prefetches active per second"], } # ARC structural breakdown from arc_summary structfields = { "cmp": ["compressed", "Compressed"], "ovh": ["overhead", "Overhead"], "bon": ["bonus", "Bonus"], "dno": ["dnode", "Dnode"], "dbu": ["dbuf", "Dbuf"], "hdr": ["hdr", "Header"], "l2h": ["l2_hdr", "L2 header"], "abd": ["abd_chunk_waste", "ABD chunk waste"], } structstats = { # size stats "percent": "size", # percentage of this value "sz": ["_size", "size"], } # ARC types breakdown from arc_summary typefields = { "data": ["data", "ARC data"], "meta": ["metadata", "ARC metadata"], } typestats = { # size stats "percent": "cachessz", # percentage of this value "tg": ["_target", "target"], "sz": ["_size", "size"], } # ARC states breakdown from arc_summary statefields = { "ano": ["anon", "Anonymous"], "mfu": ["mfu", "MFU"], "mru": ["mru", "MRU"], "unc": ["uncached", "Uncached"], } targetstats = { "percent": "cachessz", # percentage of this value "fields": ["mfu", "mru"], # only applicable to these fields "tg": ["_target", "target"], "dt": ["_data_target", "data target"], "mt": ["_metadata_target", "metadata target"], } statestats = { # size stats "percent": "cachessz", # percentage of this value "sz": ["_size", "size"], "da": ["_data", "data size"], "me": ["_metadata", "metadata size"], "ed": ["_evictable_data", "evictable data size"], "em": ["_evictable_metadata", "evictable metadata size"], } ghoststats = { "fields": ["mfu", "mru"], # only applicable to these fields "gsz": ["_ghost_size", "ghost size"], "gd": ["_ghost_data", "ghost data size"], "gm": ["_ghost_metadata", "ghost metadata size"], } # fields and stats fieldstats = [ [structfields, structstats], [typefields, typestats], [statefields, targetstats, statestats, ghoststats], ] for fs in fieldstats: fields, stats = fs[0], fs[1:] for field, fieldval in fields.items(): for group in stats: for stat, statval in group.items(): if stat in ["fields", "percent"] or \ ("fields" in group and field not in group["fields"]): continue colname = field + stat coldesc = fieldval[1] + " " + statval[1] cols[colname] = [len(colname), 1024, coldesc] if "percent" in group: cols[colname + "%"] = [len(colname) + 1, 100, \ coldesc + " percentage"] v = {} hdr = ["time", "read", "ddread", "ddh%", "dmread", "dmh%", "pread", "ph%", "size", "c", "avail"] xhdr = ["time", "mfu", "mru", "mfug", "mrug", "unc", "eskip", "mtxmis", "dread", "pread", "read"] zhdr = ["time", "ztotal", "zhits", "zahead", "zpast", "zmisses", "zmax", "zfuture", "zstride", "zissued", "zactive"] sint = 1 # Default interval is 1 second count = 1 # Default count is 1 hdr_intr = 20 # Print header every 20 lines of output opfile = None sep = " " # Default separator is 2 spaces l2exist = False cmd = ("Usage: arcstat [-havxp] [-f fields] [-o file] [-s string] [interval " "[count]]\n") cur = {} d = {} out = None kstat = None pretty_print = True if sys.platform.startswith('freebsd'): # Requires py-sysctl on FreeBSD import sysctl def kstat_update(): global kstat k = [ctl for ctl in sysctl.filter('kstat.zfs.misc.arcstats') if ctl.type != sysctl.CTLTYPE_NODE] k += [ctl for ctl in sysctl.filter('kstat.zfs.misc.zfetchstats') if ctl.type != sysctl.CTLTYPE_NODE] if not k: sys.exit(1) kstat = {} for s in k: if not s: continue name, value = s.name, s.value if "arcstats" in name: # Trims 'kstat.zfs.misc.arcstats' from the name kstat[name[24:]] = int(value) else: kstat["zfetch_" + name[27:]] = int(value) elif sys.platform.startswith('linux'): def kstat_update(): global kstat k1 = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')] k2 = ["zfetch_" + line.strip() for line in open('/proc/spl/kstat/zfs/zfetchstats')] if k1 is None or k2 is None: sys.exit(1) del k1[0:2] del k2[0:2] k = k1 + k2 kstat = {} for s in k: if not s: continue name, unused, value = s.split() kstat[name] = int(value) def detailed_usage(): sys.stderr.write("%s\n" % cmd) sys.stderr.write("Field definitions are as follows:\n") for key in cols: sys.stderr.write("%11s : %s\n" % (key, cols[key][2])) sys.stderr.write("\n") sys.exit(0) def usage(): sys.stderr.write("%s\n" % cmd) sys.stderr.write("\t -h : Print this help message\n") sys.stderr.write("\t -a : Print all possible stats\n") sys.stderr.write("\t -v : List all possible field headers and definitions" "\n") sys.stderr.write("\t -x : Print extended stats\n") sys.stderr.write("\t -z : Print zfetch stats\n") sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n") sys.stderr.write("\t -o : Redirect output to the specified file\n") sys.stderr.write("\t -s : Override default field separator with custom " "character or string\n") sys.stderr.write("\t -p : Disable auto-scaling of numerical fields\n") sys.stderr.write("\nExamples:\n") sys.stderr.write("\tarcstat -o /tmp/a.log 2 10\n") sys.stderr.write("\tarcstat -s \",\" -o /tmp/a.log 2 10\n") sys.stderr.write("\tarcstat -v\n") sys.stderr.write("\tarcstat -f time,hit%,dh%,ph%,mh% 1\n") sys.stderr.write("\n") sys.exit(1) def snap_stats(): global cur global kstat prev = copy.deepcopy(cur) kstat_update() cur = kstat # fill in additional values from arc_summary cur["caches_size"] = caches_size = cur["anon_data"]+cur["anon_metadata"]+\ cur["mfu_data"]+cur["mfu_metadata"]+cur["mru_data"]+cur["mru_metadata"]+\ cur["uncached_data"]+cur["uncached_metadata"] s = 4294967296 pd = cur["pd"] pm = cur["pm"] meta = cur["meta"] v = (s-int(pd))*(s-int(meta))/s cur["mfu_data_target"] = v / 65536 * caches_size / 65536 v = (s-int(pm))*int(meta)/s cur["mfu_metadata_target"] = v / 65536 * caches_size / 65536 v = int(pd)*(s-int(meta))/s cur["mru_data_target"] = v / 65536 * caches_size / 65536 v = int(pm)*int(meta)/s cur["mru_metadata_target"] = v / 65536 * caches_size / 65536 cur["data_target"] = cur["mfu_data_target"] + cur["mru_data_target"] cur["metadata_target"] = cur["mfu_metadata_target"] + cur["mru_metadata_target"] cur["mfu_target"] = cur["mfu_data_target"] + cur["mfu_metadata_target"] cur["mru_target"] = cur["mru_data_target"] + cur["mru_metadata_target"] for key in cur: if re.match(key, "class"): continue if key in prev: d[key] = cur[key] - prev[key] else: d[key] = cur[key] def isint(num): if isinstance(num, float): return num.is_integer() if isinstance(num, int): return True return False def prettynum(sz, scale, num=0): suffix = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z'] index = 0 # Special case for date field if scale == -1: return "%s" % num if scale != 100: while abs(num) > scale and index < 5: num = num / scale index += 1 width = sz - (0 if index == 0 else 1) intlen = len("%.0f" % num) # %.0f rounds to nearest int if sint == 1 and isint(num) or width < intlen + 2: decimal = 0 else: decimal = 1 return "%*.*f%s" % (width, decimal, num, suffix[index]) def print_values(): global hdr global sep global v global pretty_print if pretty_print: fmt = lambda col: prettynum(cols[col][0], cols[col][1], v[col]) else: fmt = lambda col: str(v[col]) sys.stdout.write(sep.join(fmt(col) for col in hdr)) sys.stdout.write("\n") sys.stdout.flush() def print_header(): global hdr global sep global pretty_print if pretty_print: fmt = lambda col: "%*s" % (cols[col][0], col) else: fmt = lambda col: col sys.stdout.write(sep.join(fmt(col) for col in hdr)) sys.stdout.write("\n") def get_terminal_lines(): try: import fcntl import termios import struct data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234') sz = struct.unpack('hh', data) return sz[0] except Exception: pass def update_hdr_intr(): global hdr_intr lines = get_terminal_lines() if lines and lines > 3: hdr_intr = lines - 3 def resize_handler(signum, frame): update_hdr_intr() def init(): global sint global count global hdr global xhdr global zhdr global opfile global sep global out global l2exist global pretty_print desired_cols = None aflag = False xflag = False hflag = False vflag = False zflag = False i = 1 try: opts, args = getopt.getopt( sys.argv[1:], "axzo:hvs:f:p", [ "all", "extended", "zfetch", "outfile", "help", "verbose", "separator", "columns", "parsable" ] ) except getopt.error as msg: sys.stderr.write("Error: %s\n" % str(msg)) usage() opts = None for opt, arg in opts: if opt in ('-a', '--all'): aflag = True if opt in ('-x', '--extended'): xflag = True if opt in ('-o', '--outfile'): opfile = arg i += 1 if opt in ('-h', '--help'): hflag = True if opt in ('-v', '--verbose'): vflag = True if opt in ('-s', '--separator'): sep = arg i += 1 if opt in ('-f', '--columns'): desired_cols = arg i += 1 if opt in ('-p', '--parsable'): pretty_print = False if opt in ('-z', '--zfetch'): zflag = True i += 1 argv = sys.argv[i:] sint = int(argv[0]) if argv else sint count = int(argv[1]) if len(argv) > 1 else (0 if len(argv) > 0 else 1) if hflag or (xflag and zflag) or ((zflag or xflag) and desired_cols): usage() if vflag: detailed_usage() if xflag: hdr = xhdr if zflag: hdr = zhdr update_hdr_intr() # check if L2ARC exists snap_stats() l2_size = cur.get("l2_size") if l2_size: l2exist = True if desired_cols: hdr = desired_cols.split(",") invalid = [] incompat = [] for ele in hdr: if ele not in cols: invalid.append(ele) elif not l2exist and ele.startswith("l2"): sys.stdout.write("No L2ARC Here\n%s\n" % ele) incompat.append(ele) if len(invalid) > 0: sys.stderr.write("Invalid column definition! -- %s\n" % invalid) usage() if len(incompat) > 0: sys.stderr.write("Incompatible field specified! -- %s\n" % incompat) usage() if aflag: if l2exist: hdr = cols.keys() else: hdr = [col for col in cols.keys() if not col.startswith("l2")] if opfile: try: out = open(opfile, "w") sys.stdout = out except IOError: sys.stderr.write("Cannot open %s for writing\n" % opfile) sys.exit(1) def calculate(): global d global v global l2exist v = dict() v["time"] = time.strftime("%H:%M:%S", time.localtime()) v["hits"] = d["hits"] / sint v["iohs"] = d["iohits"] / sint v["miss"] = d["misses"] / sint v["read"] = v["hits"] + v["iohs"] + v["miss"] v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0 v["ioh%"] = 100 * v["iohs"] / v["read"] if v["read"] > 0 else 0 v["miss%"] = 100 - v["hit%"] - v["ioh%"] if v["read"] > 0 else 0 v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint v["dioh"] = (d["demand_data_iohits"] + d["demand_metadata_iohits"]) / sint v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint v["dread"] = v["dhit"] + v["dioh"] + v["dmis"] v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0 v["di%"] = 100 * v["dioh"] / v["dread"] if v["dread"] > 0 else 0 v["dm%"] = 100 - v["dh%"] - v["di%"] if v["dread"] > 0 else 0 v["ddhit"] = d["demand_data_hits"] / sint v["ddioh"] = d["demand_data_iohits"] / sint v["ddmis"] = d["demand_data_misses"] / sint v["ddread"] = v["ddhit"] + v["ddioh"] + v["ddmis"] v["ddh%"] = 100 * v["ddhit"] / v["ddread"] if v["ddread"] > 0 else 0 v["ddi%"] = 100 * v["ddioh"] / v["ddread"] if v["ddread"] > 0 else 0 v["ddm%"] = 100 - v["ddh%"] - v["ddi%"] if v["ddread"] > 0 else 0 v["dmhit"] = d["demand_metadata_hits"] / sint v["dmioh"] = d["demand_metadata_iohits"] / sint v["dmmis"] = d["demand_metadata_misses"] / sint v["dmread"] = v["dmhit"] + v["dmioh"] + v["dmmis"] v["dmh%"] = 100 * v["dmhit"] / v["dmread"] if v["dmread"] > 0 else 0 v["dmi%"] = 100 * v["dmioh"] / v["dmread"] if v["dmread"] > 0 else 0 v["dmm%"] = 100 - v["dmh%"] - v["dmi%"] if v["dmread"] > 0 else 0 v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint v["pioh"] = (d["prefetch_data_iohits"] + d["prefetch_metadata_iohits"]) / sint v["pmis"] = (d["prefetch_data_misses"] + d["prefetch_metadata_misses"]) / sint v["pread"] = v["phit"] + v["pioh"] + v["pmis"] v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0 v["pi%"] = 100 * v["pioh"] / v["pread"] if v["pread"] > 0 else 0 v["pm%"] = 100 - v["ph%"] - v["pi%"] if v["pread"] > 0 else 0 v["pdhit"] = d["prefetch_data_hits"] / sint v["pdioh"] = d["prefetch_data_iohits"] / sint v["pdmis"] = d["prefetch_data_misses"] / sint v["pdread"] = v["pdhit"] + v["pdioh"] + v["pdmis"] v["pdh%"] = 100 * v["pdhit"] / v["pdread"] if v["pdread"] > 0 else 0 v["pdi%"] = 100 * v["pdioh"] / v["pdread"] if v["pdread"] > 0 else 0 v["pdm%"] = 100 - v["pdh%"] - v["pdi%"] if v["pdread"] > 0 else 0 v["pmhit"] = d["prefetch_metadata_hits"] / sint v["pmioh"] = d["prefetch_metadata_iohits"] / sint v["pmmis"] = d["prefetch_metadata_misses"] / sint v["pmread"] = v["pmhit"] + v["pmioh"] + v["pmmis"] v["pmh%"] = 100 * v["pmhit"] / v["pmread"] if v["pmread"] > 0 else 0 v["pmi%"] = 100 * v["pmioh"] / v["pmread"] if v["pmread"] > 0 else 0 v["pmm%"] = 100 - v["pmh%"] - v["pmi%"] if v["pmread"] > 0 else 0 v["mhit"] = (d["prefetch_metadata_hits"] + d["demand_metadata_hits"]) / sint v["mioh"] = (d["prefetch_metadata_iohits"] + d["demand_metadata_iohits"]) / sint v["mmis"] = (d["prefetch_metadata_misses"] + d["demand_metadata_misses"]) / sint v["mread"] = v["mhit"] + v["mioh"] + v["mmis"] v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0 v["mi%"] = 100 * v["mioh"] / v["mread"] if v["mread"] > 0 else 0 v["mm%"] = 100 - v["mh%"] - v["mi%"] if v["mread"] > 0 else 0 v["arcsz"] = cur["size"] v["size"] = cur["size"] v["c"] = cur["c"] v["mfu"] = d["mfu_hits"] / sint v["mru"] = d["mru_hits"] / sint v["mrug"] = d["mru_ghost_hits"] / sint v["mfug"] = d["mfu_ghost_hits"] / sint v["unc"] = d["uncached_hits"] / sint v["eskip"] = d["evict_skip"] / sint v["el2skip"] = d["evict_l2_skip"] / sint v["el2cach"] = d["evict_l2_cached"] / sint v["el2el"] = d["evict_l2_eligible"] / sint v["el2mfu"] = d["evict_l2_eligible_mfu"] / sint v["el2mru"] = d["evict_l2_eligible_mru"] / sint v["el2inel"] = d["evict_l2_ineligible"] / sint v["mtxmis"] = d["mutex_miss"] / sint v["ztotal"] = (d["zfetch_hits"] + d["zfetch_future"] + d["zfetch_stride"] + d["zfetch_past"] + d["zfetch_misses"]) / sint v["zhits"] = d["zfetch_hits"] / sint v["zahead"] = (d["zfetch_future"] + d["zfetch_stride"]) / sint v["zpast"] = d["zfetch_past"] / sint v["zmisses"] = d["zfetch_misses"] / sint v["zmax"] = d["zfetch_max_streams"] / sint v["zfuture"] = d["zfetch_future"] / sint v["zstride"] = d["zfetch_stride"] / sint v["zissued"] = d["zfetch_io_issued"] / sint v["zactive"] = d["zfetch_io_active"] / sint # ARC structural breakdown, ARC types breakdown, ARC states breakdown v["cachessz"] = cur["caches_size"] for fs in fieldstats: fields, stats = fs[0], fs[1:] for field, fieldval in fields.items(): for group in stats: for stat, statval in group.items(): if stat in ["fields", "percent"] or \ ("fields" in group and field not in group["fields"]): continue colname = field + stat v[colname] = cur[fieldval[0] + statval[0]] if "percent" in group: v[colname + "%"] = 100 * v[colname] / \ v[group["percent"]] if v[group["percent"]] > 0 else 0 if l2exist: l2asize = cur["l2_asize"] v["l2hits"] = d["l2_hits"] / sint v["l2miss"] = d["l2_misses"] / sint v["l2read"] = v["l2hits"] + v["l2miss"] v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0 v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0 v["l2asize"] = l2asize v["l2size"] = cur["l2_size"] v["l2bytes"] = d["l2_read_bytes"] / sint v["l2wbytes"] = d["l2_write_bytes"] / sint v["l2pref"] = cur["l2_prefetch_asize"] v["l2mfu"] = cur["l2_mfu_asize"] v["l2mru"] = cur["l2_mru_asize"] v["l2data"] = cur["l2_bufc_data_asize"] v["l2meta"] = cur["l2_bufc_metadata_asize"] v["l2pref%"] = 100 * v["l2pref"] / l2asize if l2asize > 0 else 0 v["l2mfu%"] = 100 * v["l2mfu"] / l2asize if l2asize > 0 else 0 v["l2mru%"] = 100 * v["l2mru"] / l2asize if l2asize > 0 else 0 v["l2data%"] = 100 * v["l2data"] / l2asize if l2asize > 0 else 0 v["l2meta%"] = 100 * v["l2meta"] / l2asize if l2asize > 0 else 0 v["grow"] = 0 if cur["arc_no_grow"] else 1 v["need"] = cur["arc_need_free"] v["free"] = cur["memory_free_bytes"] v["avail"] = cur["memory_available_bytes"] v["waste"] = cur["abd_chunk_waste_size"] def main(): - # notify user for upcoming renaming in 2.4.0 - abs_path = os.path.abspath(sys.argv[0].strip()) - script_name = os.path.basename(abs_path) - if script_name != "zarcstat": - sys.stderr.write("Note: this script will be renamed to zarcstat in ") - sys.stderr.write("zfs 2.4.0. Please migrate ASAP.\n") - global sint global count global hdr_intr i = 0 count_flag = 0 init() if count > 0: count_flag = 1 signal(SIGINT, SIG_DFL) signal(SIGWINCH, resize_handler) while True: if i == 0: print_header() snap_stats() calculate() print_values() if count_flag == 1: if count <= 1: break count -= 1 i = 0 if i >= hdr_intr else i + 1 time.sleep(sint) if out: out.close() if __name__ == '__main__': main() diff --git a/contrib/debian/openzfs-zfsutils.install b/contrib/debian/openzfs-zfsutils.install index 2362c83dfa3f..37284a78ad18 100644 --- a/contrib/debian/openzfs-zfsutils.install +++ b/contrib/debian/openzfs-zfsutils.install @@ -1,144 +1,142 @@ etc/default/zfs etc/zfs/zfs-functions etc/zfs/zpool.d/ lib/systemd/system-generators/ lib/systemd/system-preset/ lib/systemd/system/zfs-import-cache.service lib/systemd/system/zfs-import-scan.service lib/systemd/system/zfs-import.target lib/systemd/system/zfs-load-key.service lib/systemd/system/zfs-mount.service lib/systemd/system/zfs-mount@.service lib/systemd/system/zfs-scrub-monthly@.timer lib/systemd/system/zfs-scrub-weekly@.timer lib/systemd/system/zfs-scrub@.service lib/systemd/system/zfs-trim-monthly@.timer lib/systemd/system/zfs-trim-weekly@.timer lib/systemd/system/zfs-trim@.service lib/systemd/system/zfs-share.service lib/systemd/system/zfs-volume-wait.service lib/systemd/system/zfs-volumes.target lib/systemd/system/zfs.target lib/udev/ sbin/fsck.zfs sbin/mount.zfs sbin/zdb sbin/zfs sbin/zfs_ids_to_path sbin/zgenhostid sbin/zhack sbin/zinject sbin/zpool sbin/zstream sbin/zstreamdump usr/bin/zvol_wait usr/lib/modules-load.d/ lib/ usr/lib/zfs-linux/zpool.d/ usr/lib/zfs-linux/zpool_influxdb usr/lib/zfs-linux/zfs_prepare_disk usr/sbin/arc_summary -usr/sbin/zarcsummary usr/sbin/arcstat -usr/sbin/zarcstat usr/sbin/dbufstat usr/sbin/zilstat usr/share/zfs/compatibility.d/ usr/share/bash-completion/completions usr/share/man/man1/arcstat.1 usr/share/man/man1/zhack.1 usr/share/man/man1/zvol_wait.1 usr/share/man/man5/ usr/share/man/man8/fsck.zfs.8 usr/share/man/man8/mount.zfs.8 usr/share/man/man8/vdev_id.8 usr/share/man/man8/zdb.8 usr/share/man/man8/zfs-allow.8 usr/share/man/man8/zfs-bookmark.8 usr/share/man/man8/zfs-change-key.8 usr/share/man/man8/zfs-clone.8 usr/share/man/man8/zfs-create.8 usr/share/man/man8/zfs-destroy.8 usr/share/man/man8/zfs-diff.8 usr/share/man/man8/zfs-get.8 usr/share/man/man8/zfs-groupspace.8 usr/share/man/man8/zfs-hold.8 usr/share/man/man8/zfs-inherit.8 usr/share/man/man8/zfs-list.8 usr/share/man/man8/zfs-load-key.8 usr/share/man/man8/zfs-mount-generator.8 usr/share/man/man8/zfs-mount.8 usr/share/man/man8/zfs-program.8 usr/share/man/man8/zfs-project.8 usr/share/man/man8/zfs-projectspace.8 usr/share/man/man8/zfs-promote.8 usr/share/man/man8/zfs-receive.8 usr/share/man/man8/zfs-recv.8 usr/share/man/man8/zfs-redact.8 usr/share/man/man8/zfs-release.8 usr/share/man/man8/zfs-rename.8 usr/share/man/man8/zfs-rewrite.8 usr/share/man/man8/zfs-rollback.8 usr/share/man/man8/zfs-send.8 usr/share/man/man8/zfs-set.8 usr/share/man/man8/zfs-share.8 usr/share/man/man8/zfs-snapshot.8 usr/share/man/man8/zfs-unallow.8 usr/share/man/man8/zfs-unload-key.8 usr/share/man/man8/zfs-unmount.8 usr/share/man/man8/zfs-unzone.8 usr/share/man/man8/zfs-upgrade.8 usr/share/man/man8/zfs-userspace.8 usr/share/man/man8/zfs-wait.8 usr/share/man/man8/zfs-zone.8 usr/share/man/man8/zfs.8 usr/share/man/man8/zfs_ids_to_path.8 usr/share/man/man8/zfs_prepare_disk.8 usr/share/man/man7/zfsconcepts.7 usr/share/man/man7/zfsprops.7 usr/share/man/man8/zgenhostid.8 usr/share/man/man8/zinject.8 usr/share/man/man8/zpool-add.8 usr/share/man/man8/zpool-attach.8 usr/share/man/man8/zpool-checkpoint.8 usr/share/man/man8/zpool-clear.8 usr/share/man/man8/zpool-create.8 usr/share/man/man8/zpool-ddtprune.8 usr/share/man/man8/zpool-destroy.8 usr/share/man/man8/zpool-detach.8 usr/share/man/man8/zpool-ddtprune.8 usr/share/man/man8/zpool-events.8 usr/share/man/man8/zpool-export.8 usr/share/man/man8/zpool-get.8 usr/share/man/man8/zpool-history.8 usr/share/man/man8/zpool-import.8 usr/share/man/man8/zpool-initialize.8 usr/share/man/man8/zpool-iostat.8 usr/share/man/man8/zpool-labelclear.8 usr/share/man/man8/zpool-list.8 usr/share/man/man8/zpool-offline.8 usr/share/man/man8/zpool-online.8 usr/share/man/man8/zpool-prefetch.8 usr/share/man/man8/zpool-prefetch.8 usr/share/man/man8/zpool-reguid.8 usr/share/man/man8/zpool-remove.8 usr/share/man/man8/zpool-reopen.8 usr/share/man/man8/zpool-replace.8 usr/share/man/man8/zpool-resilver.8 usr/share/man/man8/zpool-scrub.8 usr/share/man/man8/zpool-set.8 usr/share/man/man8/zpool-split.8 usr/share/man/man8/zpool-status.8 usr/share/man/man8/zpool-sync.8 usr/share/man/man8/zpool-trim.8 usr/share/man/man8/zpool-upgrade.8 usr/share/man/man8/zpool-wait.8 usr/share/man/man8/zpool.8 usr/share/man/man7/vdevprops.7 usr/share/man/man7/zpoolconcepts.7 usr/share/man/man7/zpoolprops.7 usr/share/man/man8/zstream.8 usr/share/man/man8/zstreamdump.8 usr/share/man/man4/spl.4 usr/share/man/man4/zfs.4 usr/share/man/man7/zpool-features.7 usr/share/man/man8/zpool_influxdb.8 diff --git a/contrib/debian/rules.in b/contrib/debian/rules.in index 966e34bf9dc6..2b0568938b25 100755 --- a/contrib/debian/rules.in +++ b/contrib/debian/rules.in @@ -1,226 +1,224 @@ #!/usr/bin/make -f include /usr/share/dpkg/default.mk LSB_DISTRIBUTOR := $(shell lsb_release -is) NAME := $(shell awk '$$1 == "Name:" { print $$2; }' META) LINUX_MIN := $(shell awk '/Linux-Minimum:/{print $$2}' META) LINUX_NEXT := $(shell awk -F'[ .]' '/Linux-Maximum:/{print $$2 "." $$3+1}' META) DKMSFILES := module include config zfs.release.in autogen.sh copy-builtin META AUTHORS \ COPYRIGHT LICENSE README.md CODE_OF_CONDUCT.md NEWS NOTICE RELEASES.md ifndef KVERS KVERS=$(shell uname -r) endif non_epoch_version=$(shell echo $(KVERS) | perl -pe 's/^\d+://') PACKAGE=openzfs-zfs pmodules = $(PACKAGE)-modules-$(non_epoch_version) export DEB_BUILD_MAINT_OPTIONS = hardening=+all NUM_CPUS = $(shell nproc 2>/dev/null) PARALLEL = $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) NJOBS = -j$(or $(PARALLEL),$(NUM_CPUS),1) %: dh $@ --with autoreconf,dkms,python3,sphinxdoc override_dh_autoreconf: @# Embed the downstream version in the module. @sed -e 's/^Version:.*/Version: $(DEB_VERSION_UPSTREAM)/' -i.orig META dh_autoreconf override_dh_auto_configure: @# Build the userland, but don't build the kernel modules. dh_auto_configure -- @CFGOPTS@ \ --bindir=/usr/bin \ --sbindir=/sbin \ --libdir=/lib/"$(DEB_HOST_MULTIARCH)" \ --with-udevdir=/lib/udev \ --with-zfsexecdir=/usr/lib/zfs-linux \ --enable-systemd \ --enable-pyzfs \ --with-python=python3 \ --with-pammoduledir='/lib/$(DEB_HOST_MULTIARCH)/security' \ --with-pkgconfigdir='/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig' \ --with-systemdunitdir=/lib/systemd/system \ --with-systemdpresetdir=/lib/systemd/system-preset \ --with-systemdgeneratordir=/lib/systemd/system-generators \ --with-config=user for i in $(wildcard $(CURDIR)/debian/*.install.in) ; do \ basename "$$i" | grep _KVERS_ && continue ; \ sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' "$$i" > "$${i%%.in}" ; \ done ln -s '$(CURDIR)/etc/init.d/zfs-import' '$(CURDIR)/debian/openzfs-zfsutils.zfs-import.init' ln -s '$(CURDIR)/etc/init.d/zfs-load-key' '$(CURDIR)/debian/openzfs-zfsutils.zfs-load-key.init' ln -s '$(CURDIR)/etc/init.d/zfs-mount' '$(CURDIR)/debian/openzfs-zfsutils.zfs-mount.init' ln -s '$(CURDIR)/etc/init.d/zfs-share' '$(CURDIR)/debian/openzfs-zfsutils.zfs-share.init' ln -s '$(CURDIR)/etc/init.d/zfs-zed' '$(CURDIR)/debian/openzfs-zfs-zed.zfs-zed.init' override_dh_gencontrol: dh_gencontrol -- -Vlinux:Recommends="linux-libc-dev (<< $(LINUX_NEXT)~), linux-libc-dev (>= $(LINUX_MIN)~)," override_dh_auto_build: @# Get a bare copy of the source code for DKMS. @# This creates the $(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/ tree, which does not @# contain the userland sources. NB: Remove-userland-dist-rules.patch $(MAKE) distdir dh_auto_build override_dh_auto_install: @# Install the utilities. $(MAKE) install DESTDIR='$(CURDIR)/debian/tmp' # Move from bin_dir to /usr/sbin # Remove suffix (.py) as per policy 10.4 - Scripts # https://www.debian.org/doc/debian-policy/ch-files.html#s-scripts mkdir -p '$(CURDIR)/debian/tmp/usr/sbin/' mv '$(CURDIR)/debian/tmp/usr/bin/arc_summary' '$(CURDIR)/debian/tmp/usr/sbin/arc_summary' - mv '$(CURDIR)/debian/tmp/usr/bin/zarcsummary' '$(CURDIR)/debian/tmp/usr/sbin/zarcsummary' mv '$(CURDIR)/debian/tmp/usr/bin/arcstat' '$(CURDIR)/debian/tmp/usr/sbin/arcstat' - mv '$(CURDIR)/debian/tmp/usr/bin/zarcstat' '$(CURDIR)/debian/tmp/usr/sbin/zarcstat' mv '$(CURDIR)/debian/tmp/usr/bin/dbufstat' '$(CURDIR)/debian/tmp/usr/sbin/dbufstat' mv '$(CURDIR)/debian/tmp/usr/bin/zilstat' '$(CURDIR)/debian/tmp/usr/sbin/zilstat' @# Zed has dependencies outside of the system root. mv '$(CURDIR)/debian/tmp/sbin/zed' '$(CURDIR)/debian/tmp/usr/sbin/zed' sed -i 's|ExecStart=/sbin/|ExecStart=/usr/sbin/|g' '$(CURDIR)/debian/tmp/lib/systemd/system/zfs-zed.service' @# Install the DKMS source. @# We only want the files needed to build the modules install -D -t '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/scripts' \ '$(CURDIR)/scripts/dkms.postbuild' '$(CURDIR)/scripts/objtool-wrapper.in' $(foreach file,$(DKMSFILES),mv '$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/$(file)' '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)' || exit 1;) @# Only ever build Linux modules echo 'SUBDIRS = linux' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/include/os/Makefile.am' @# Hellish awk line: @# * Deletes from configure.ac the parts not needed for building the kernel module @# * It deletes from inside AC_CONFIG_FILES([]) everything except: @# - Makefile$ @# - include/(Makefile|sys|os/(Makefile|linux)) @# - module/ @# - zfs.release$ @# * Takes care of spaces and tabs @# * Remove reference to ZFS_AC_PACKAGE awk '/^AC_CONFIG_FILES\(\[/,/\]\)/ {\ if ($$0 !~ /^(AC_CONFIG_FILES\(\[([ \t]+)?$$|\]\)([ \t]+)?$$|([ \t]+)?(include\/(Makefile|sys|os\/(Makefile|linux))|module\/|Makefile([ \t]+)?$$|zfs\.release([ \t]+)?$$))|scripts\/objtool-wrapper.*\]\)$$/) \ {next} } {print}' \ '$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/configure.ac' | sed '/ZFS_AC_PACKAGE/d' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/configure.ac' @# Set "SUBDIRS = module include" for CONFIG_KERNEL and remove SUBDIRS for all other configs. @# Do not regenerate zfs_gitrev.h during dkms build sed '1,/CONFIG_KERNEL/s/SUBDIRS.*=.*//g;s/SUBDIRS.*=.*/SUBDIRS = module include/g;/make_gitrev.sh/d' \ '$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' @# Sanity test grep -q 'SUBDIRS = module include' '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' sed -i '/rpm.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/cmd.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/contrib.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/etc.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/lib.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/man.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/scripts.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/tests.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am sed -i '/udev.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am @# Run autogen on the stripped source tree cd '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)'; ./autogen.sh rm -fr '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/autom4te.cache' for i in `ls $(CURDIR)/debian/tmp/lib/$(DEB_HOST_MULTIARCH)/*.so`; do \ ln -s '/lib/$(DEB_HOST_MULTIARCH)/'`readlink $${i}` '$(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/'`basename $${i}`; \ rm $${i}; \ done chmod a-x '$(CURDIR)/debian/tmp/etc/zfs/zfs-functions' chmod a-x '$(CURDIR)/debian/tmp/etc/default/zfs' override_dh_python3: dh_python3 -p openzfs-python3-pyzfs override_dh_dkms: '$(CURDIR)/scripts/dkms.mkconf' -n $(NAME) -v $(DEB_VERSION_UPSTREAM) -f '$(CURDIR)/scripts/zfs-dkms.dkms' dh_dkms rm -f '$(CURDIR)/scripts/zfs-dkms.dkms' override_dh_makeshlibs: dh_makeshlibs -a -V override_dh_strip: dh_strip override_dh_auto_clean: rm -rf zfs-$(DEB_VERSION_UPSTREAM) dh_auto_clean @if test -e META.orig; then mv META.orig META; fi override_dh_install: find debian/tmp/lib -name '*.la' -delete dh_install override_dh_missing: dh_missing --fail-missing override_dh_installinit: dh_installinit -r --no-restart-after-upgrade --name zfs-import dh_installinit -r --no-restart-after-upgrade --name zfs-mount dh_installinit -r --no-restart-after-upgrade --name zfs-load-key dh_installinit -R --name zfs-share dh_installinit -R --name zfs-zed override_dh_installsystemd: mkdir -p debian/openzfs-zfsutils/lib/systemd/system ln -sr /dev/null debian/openzfs-zfsutils/lib/systemd/system/zfs-import.service dh_installsystemd --no-stop-on-upgrade -X zfs-zed.service dh_installsystemd --name zfs-zed override_dh_installdocs: dh_installdocs -A ifeq (,$(findstring nodoc, $(DEB_BUILD_OPTIONS))) http_proxy='127.0.0.1:9' sphinx-build -N -bhtml "$(CURDIR)/contrib/pyzfs/docs/source/" debian/openzfs-pyzfs-doc/usr/share/doc/openzfs-pyzfs-doc/html/ endif # ------------ override_dh_prep-deb-files: for templ in $(wildcard $(CURDIR)/debian/*_KVERS_*.in); do \ sed -e 's/##KVERS##/$(KVERS)/g ; s/#KVERS#/$(KVERS)/g ; s/_KVERS_/$(KVERS)/g ; s/##KDREV##/$(KDREV)/g ; s/#KDREV#/$(KDREV)/g ; s/_KDREV_/$(KDREV)/g ; s/_ARCH_/$(DEB_HOST_ARCH)/' \ < $$templ > `echo $$templ | sed -e 's/_KVERS_/$(KVERS)/g ; s/_ARCH_/$(DEB_HOST_ARCH)/g ; s/\.in$$//'` ; \ done sed -e 's/##KVERS##/$(KVERS)/g ; s/#KVERS#/$(KVERS)/g ; s/_KVERS_/$(KVERS)/g ; s/##KDREV##/$(KDREV)/g ; s/#KDREV#/$(KDREV)/g ; s/_KDREV_/$(KDREV)/g ; s/_ARCH_/$(DEB_HOST_ARCH)/g' \ < debian/control.modules.in > debian/control override_dh_configure_modules: override_dh_configure_modules_stamp override_dh_configure_modules_stamp: ./configure @CFGOPTS@ \ --with-config=kernel \ --with-linux=$(KSRC) \ --with-linux-obj=$(KOBJ) touch override_dh_configure_modules_stamp override_dh_binary-modules: override_dh_prep-deb-files override_dh_configure_modules dh_testdir dh_testroot dh_prep $(MAKE) $(NJOBS) -C $(CURDIR)/module modules dh_install -p${pmodules} dh_installdocs -p${pmodules} dh_installchangelogs -p${pmodules} dh_compress -p${pmodules} dh_strip -p${pmodules} dh_fixperms -p${pmodules} dh_installdeb -p${pmodules} dh_gencontrol -p${pmodules} dh_md5sums -p${pmodules} dh_builddeb -p${pmodules} debian-copyright: cme update dpkg-copyright -file debian/copyright.cme diff --git a/man/man1/arcstat.1 b/man/man1/arcstat.1 index 288b98d57a11..fe2e0407e072 100644 --- a/man/man1/arcstat.1 +++ b/man/man1/arcstat.1 @@ -1,429 +1,427 @@ .\" SPDX-License-Identifier: CDDL-1.0 .\" .\" This file and its contents are supplied under the terms of the .\" Common Development and Distribution License ("CDDL"), version 1.0. .\" You may only use this file in accordance with the terms of version .\" 1.0 of the CDDL. .\" .\" A full copy of the text of the CDDL should have accompanied this .\" source. A copy of the CDDL is also available via the Internet at .\" http://www.illumos.org/license/CDDL. .\" .\" Copyright 2014 Adam Stevko. All rights reserved. .\" Copyright (c) 2015 by Delphix. All rights reserved. .\" Copyright (c) 2020 by AJ Jordan. All rights reserved. .\" .Dd September 19, 2024 .Dt ARCSTAT 1 .Os . .Sh NAME .Nm arcstat .Nd report ZFS ARC and L2ARC statistics -.Sh NOTICE -It will be renamed to zarcstat in zfs 2.4.0. Please migrate ASAP. .Sh SYNOPSIS .Nm .Op Fl havxp .Op Fl f Ar field Ns Op , Ns Ar field Ns … .Op Fl o Ar file .Op Fl s Ar string .Op Ar interval .Op Ar count . .Sh DESCRIPTION .Nm prints various ZFS ARC and L2ARC statistics in vmstat-like fashion: .Bl -tag -compact -offset Ds -width "l2asize" .It Sy c ARC target size .It Sy dh% Demand hit percentage .It Sy di% Demand I/O hit percentage .It Sy dm% Demand miss percentage .It Sy ddh% Demand data hit percentage .It Sy ddi% Demand data I/O hit percentage .It Sy ddm% Demand data miss percentage .It Sy dmh% Demand metadata hit percentage .It Sy dmi% Demand metadata I/O hit percentage .It Sy dmm% Demand metadata miss percentage .It Sy mfu MFU list hits per second .It Sy mh% Metadata hit percentage .It Sy mi% Metadata I/O hit percentage .It Sy mm% Metadata miss percentage .It Sy mru MRU list hits per second .It Sy ph% Prefetch hits percentage .It Sy pi% Prefetch I/O hits percentage .It Sy pm% Prefetch miss percentage .It Sy pdh% Prefetch data hits percentage .It Sy pdi% Prefetch data I/O hits percentage .It Sy pdm% Prefetch data miss percentage .It Sy pmh% Prefetch metadata hits percentage .It Sy pmi% Prefetch metadata I/O hits percentage .It Sy pmm% Prefetch metadata miss percentage .It Sy dhit Demand hits per second .It Sy dioh Demand I/O hits per second .It Sy dmis Demand misses per second .It Sy ddhit Demand data hits per second .It Sy ddioh Demand data I/O hits per second .It Sy ddmis Demand data misses per second .It Sy dmhit Demand metadata hits per second .It Sy dmioh Demand metadata I/O hits per second .It Sy dmmis Demand metadata misses per second .It Sy hit% ARC hit percentage .It Sy hits ARC hits per second .It Sy ioh% ARC I/O hits percentage .It Sy iohs ARC I/O hits per second .It Sy mfug MFU ghost list hits per second .It Sy mhit Metadata hits per second .It Sy mioh Metadata I/O hits per second .It Sy miss ARC misses per second .It Sy mmis Metadata misses per second .It Sy mrug MRU ghost list hits per second .It Sy phit Prefetch hits per second .It Sy pioh Prefetch I/O hits per second .It Sy pmis Prefetch misses per second .It Sy pdhit Prefetch data hits per second .It Sy pdioh Prefetch data I/O hits per second .It Sy pdmis Prefetch data misses per second .It Sy pmhit Prefetch metadata hits per second .It Sy pmioh Prefetch metadata I/O hits per second .It Sy pmmis Prefetch metadata misses per second .It Sy read Total ARC accesses per second .It Sy time Current time .It Sy size ARC size .It Sy arcsz Alias for .Sy size .It Sy unc Uncached list hits per second .It Sy dread Demand accesses per second .It Sy ddread Demand data accesses per second .It Sy dmread Demand metadata accesses per second .It Sy eskip evict_skip per second .It Sy miss% ARC miss percentage .It Sy mread Metadata accesses per second .It Sy pread Prefetch accesses per second .It Sy pdread Prefetch data accesses per second .It Sy pmread Prefetch metadata accesses per second .It Sy l2hit% L2ARC access hit percentage .It Sy l2hits L2ARC hits per second .It Sy l2miss L2ARC misses per second .It Sy l2read Total L2ARC accesses per second .It Sy l2pref L2ARC prefetch allocated size per second .It Sy l2pref% L2ARC prefetch allocated size percentage .It Sy l2mfu L2ARC MFU allocated size per second .It Sy l2mfu% L2ARC MFU allocated size percentage .It Sy l2mru L2ARC MRU allocated size per second .It Sy l2mru% L2ARC MRU allocated size percentage .It Sy l2data L2ARC data (buf content) allocated size per second .It Sy l2data% L2ARC data (buf content) allocated size percentage .It Sy l2meta L2ARC metadata (buf content) allocated size per second .It Sy l2meta% L2ARC metadata (buf content) allocated size percentage .It Sy l2size Size of the L2ARC .It Sy mtxmis mutex_miss per second .It Sy l2bytes Bytes read per second from the L2ARC .It Sy l2wbytes Bytes written per second to the L2ARC .It Sy l2miss% L2ARC access miss percentage .It Sy l2asize Actual (compressed) size of the L2ARC .It Sy cmpsz Compressed size .It Sy cmpsz% Compressed size percentage .It Sy ovhsz Overhead size .It Sy ovhsz% Overhead size percentage .It Sy bonsz Bonus size .It Sy bonsz% Bonus size percentage .It Sy dnosz Dnode size .It Sy dnosz% Dnode size percentage .It Sy dbusz Dbuf size .It Sy dbusz% Dbuf size percentage .It Sy hdrsz Header size .It Sy hdrsz% Header size percentage .It Sy l2hsz L2 header size .It Sy l2hsz% L2 header size percentage .It Sy abdsz ABD chunk waste size .It Sy abdsz% ABD chunk waste size percentage .It Sy datatg ARC data target .It Sy datatg% ARC data target percentage .It Sy datasz ARC data size .It Sy datasz% ARC data size percentage .It Sy metatg ARC metadata target .It Sy metatg% ARC metadata target percentage .It Sy metasz ARC metadata size .It Sy metasz% ARC metadata size percentage .It Sy anosz Anonymous size .It Sy anosz% Anonymous size percentage .It Sy anoda Anonymous data size .It Sy anoda% Anonymous data size percentage .It Sy anome Anonymous metadata size .It Sy anome% Anonymous metadata size percentage .It Sy anoed Anonymous evictable data size .It Sy anoed% Anonymous evictable data size percentage .It Sy anoem Anonymous evictable metadata size .It Sy anoem% Anonymous evictable metadata size percentage .It Sy mfutg MFU target .It Sy mfutg% MFU target percentage .It Sy mfudt MFU data target .It Sy mfudt% MFU data target percentage .It Sy mfumt MFU metadata target .It Sy mfumt% MFU metadata target percentage .It Sy mfusz MFU size .It Sy mfusz% MFU size percentage .It Sy mfuda MFU data size .It Sy mfuda% MFU data size percentage .It Sy mfume MFU metadata size .It Sy mfume% MFU metadata size percentage .It Sy mfued MFU evictable data size .It Sy mfued% MFU evictable data size percentage .It Sy mfuem MFU evictable metadata size .It Sy mfuem% MFU evictable metadata size percentage .It Sy mfugsz MFU ghost size .It Sy mfugd MFU ghost data size .It Sy mfugm MFU ghost metadata size .It Sy mrutg MRU target .It Sy mrutg% MRU target percentage .It Sy mrudt MRU data target .It Sy mrudt% MRU data target percentage .It Sy mrumt MRU metadata target .It Sy mrumt% MRU metadata target percentage .It Sy mrusz MRU size .It Sy mrusz% MRU size percentage .It Sy mruda MRU data size .It Sy mruda% MRU data size percentage .It Sy mrume MRU metadata size .It Sy mrume% MRU metadata size percentage .It Sy mrued MRU evictable data size .It Sy mrued% MRU evictable data size percentage .It Sy mruem MRU evictable metadata size .It Sy mruem% MRU evictable metadata size percentage .It Sy mrugsz MRU ghost size .It Sy mrugd MRU ghost data size .It Sy mrugm MRU ghost metadata size .It Sy uncsz Uncached size .It Sy uncsz% Uncached size percentage .It Sy uncda Uncached data size .It Sy uncda% Uncached data size percentage .It Sy uncme Uncached metadata size .It Sy uncme% Uncached metadata size percentage .It Sy unced Uncached evictable data size .It Sy unced% Uncached evictable data size percentage .It Sy uncem Uncached evictable metadata size .It Sy uncem% Uncached evictable metadata size percentage .It Sy grow ARC grow disabled .It Sy need ARC reclaim needed .It Sy free The ARC's idea of how much free memory there is, which includes evictable memory in the page cache. Since the ARC tries to keep .Sy avail above zero, .Sy avail is usually more instructive to observe than .Sy free . .It Sy avail The ARC's idea of how much free memory is available to it, which is a bit less than .Sy free . May temporarily be negative, in which case the ARC will reduce the target size .Sy c . .El . .Sh OPTIONS .Bl -tag -width "-v" .It Fl a Print all possible stats. .It Fl f Display only specific fields. See .Sx DESCRIPTION for supported statistics. .It Fl h Display help message. .It Fl o Report statistics to a file instead of the standard output. .It Fl p Disable auto-scaling of numerical fields (for raw, machine-parsable values). .It Fl s Display data with a specified separator (default: 2 spaces). .It Fl x Print extended stats .Pq same as Fl f Sy time , Ns Sy mfu , Ns Sy mru , Ns Sy mfug , Ns Sy mrug , Ns Sy eskip , Ns Sy mtxmis , Ns Sy dread , Ns Sy pread , Ns Sy read . .It Fl v Show field headers and definitions .El . .Sh OPERANDS The following operands are supported: .Bl -tag -compact -offset Ds -width "interval" .It Ar interval Specify the sampling interval in seconds. .It Ar count Display only .Ar count reports. .El diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index edcfdd2d7136..1ce668e7b86d 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -1,606 +1,604 @@ %global _sbindir /sbin %global _libdir /%{_lib} # Set the default udev directory based on distribution. %if %{undefined _udevdir} %if 0%{?rhel}%{?fedora}%{?centos}%{?suse_version}%{?openEuler} %global _udevdir %{_prefix}/lib/udev %else %global _udevdir /lib/udev %endif %endif # Set the default udevrule directory based on distribution. %if %{undefined _udevruledir} %if 0%{?rhel}%{?fedora}%{?centos}%{?suse_version}%{?openEuler} %global _udevruledir %{_prefix}/lib/udev/rules.d %else %global _udevruledir /lib/udev/rules.d %endif %endif # Set the default _bashcompletiondir directory based on distribution. %if %{undefined _bashcompletiondir} %if 0%{?rhel}%{?fedora}%{?centos}%{?suse_version}%{?openEuler} %global _bashcompletiondir /etc/bash_completion.d %else %global _bashcompletiondir /usr/share/bash-completion %endif %endif # Set the default dracut directory based on distribution. %if %{undefined _dracutdir} %if 0%{?rhel}%{?fedora}%{?centos}%{?suse_version}%{?openEuler} %global _dracutdir %{_prefix}/lib/dracut %else %global _dracutdir %{_prefix}/share/dracut %endif %endif %if %{undefined _initconfdir} %global _initconfdir /etc/sysconfig %endif %if %{undefined _unitdir} %global _unitdir %{_prefix}/lib/systemd/system %endif %if %{undefined _presetdir} %global _presetdir %{_prefix}/lib/systemd/system-preset %endif %if %{undefined _modulesloaddir} %global _modulesloaddir %{_prefix}/lib/modules-load.d %endif %if %{undefined _systemdgeneratordir} %global _systemdgeneratordir %{_prefix}/lib/systemd/system-generators %endif %if %{undefined _pkgconfigdir} %global _pkgconfigdir %{_prefix}/%{_lib}/pkgconfig %endif %bcond_with debug %bcond_with debuginfo %bcond_with asan %bcond_with ubsan %bcond_with systemd %bcond_with pam %bcond_without pyzfs # Generic enable switch for systemd %if %{with systemd} %define _systemd 1 %endif # Distros below support systemd %if 0%{?rhel}%{?fedora}%{?centos}%{?suse_version}%{?openEuler} %define _systemd 1 %endif # When not specified default to distribution provided version. %if %{undefined __use_python} %define __python /usr/bin/python3 %define __python_pkg_version 3 %else %define __python %{__use_python} %define __python_pkg_version %{__use_python_pkg_version} %endif %define __python_sitelib %(%{__python} -Esc " import sysconfig; if hasattr(sysconfig, 'get_default_scheme'): scheme = sysconfig.get_default_scheme() else: scheme = sysconfig._get_default_scheme() if scheme == 'posix_local': scheme = 'posix_prefix' prefix = '%{_prefix}' if prefix == 'NONE': prefix = '%{ac_default_prefix}' sitedir = sysconfig.get_path('purelib', scheme, vars={'base': prefix}) print(sitedir);" 2>/dev/null || %{__python} -Esc "from distutils import sysconfig; print(sysconfig.get_python_lib(0,0))") Name: @PACKAGE@ Version: @VERSION@ Release: @RELEASE@%{?dist} Summary: Commands to control the kernel modules and libraries Group: System Environment/Kernel License: @ZFS_META_LICENSE@ URL: https://github.com/openzfs/zfs Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: libzpool6%{?_isa} = %{version}-%{release} Requires: libnvpair3%{?_isa} = %{version}-%{release} Requires: libuutil3%{?_isa} = %{version}-%{release} Requires: libzfs6%{?_isa} = %{version}-%{release} Requires: %{name}-kmod = %{version} Provides: %{name}-kmod-common = %{version}-%{release} Obsoletes: spl <= %{version} # zfs-fuse provides the same commands and man pages that OpenZFS does. # Renaming those on either side would conflict with all available documentation. Conflicts: zfs-fuse %if 0%{?rhel}%{?centos}%{?fedora}%{?suse_version}%{?openEuler} BuildRequires: gcc, make BuildRequires: zlib-devel BuildRequires: libuuid-devel BuildRequires: libblkid-devel BuildRequires: libudev-devel BuildRequires: libattr-devel BuildRequires: openssl-devel %if 0%{?fedora}%{?suse_version}%{?openEuler} || 0%{?rhel} >= 8 || 0%{?centos} >= 8 BuildRequires: libtirpc-devel %endif %if (0%{?fedora}%{?suse_version}%{?openEuler}) || (0%{?rhel} && 0%{?rhel} < 9) # We don't directly use it, but if this isn't installed, rpmbuild as root can # crash+corrupt rpmdb # See issue #12071 BuildRequires: ncompress %endif Requires: openssl %if 0%{?_systemd} BuildRequires: systemd %endif %endif %if 0%{?_systemd} Requires(post): systemd Requires(preun): systemd Requires(postun): systemd %endif # The zpool iostat/status -c scripts call some utilities like lsblk and iostat Requires: util-linux Requires: sysstat %description This package contains the core ZFS command line utilities. %package -n libzpool6 Summary: Native ZFS pool library for Linux Group: System Environment/Kernel Obsoletes: libzpool2 <= %{version} Obsoletes: libzpool4 <= %{version} Obsoletes: libzpool5 <= %{version} %description -n libzpool6 This package contains the zpool library, which provides support for managing zpools %if %{defined ldconfig_scriptlets} %ldconfig_scriptlets -n libzpool6 %else %post -n libzpool6 -p /sbin/ldconfig %postun -n libzpool6 -p /sbin/ldconfig %endif %package -n libnvpair3 Summary: Solaris name-value library for Linux Group: System Environment/Kernel Obsoletes: libnvpair1 <= %{version} %description -n libnvpair3 This package contains routines for packing and unpacking name-value pairs. This functionality is used to portably transport data across process boundaries, between kernel and user space, and can be used to write self describing data structures on disk. %if %{defined ldconfig_scriptlets} %ldconfig_scriptlets -n libnvpair3 %else %post -n libnvpair3 -p /sbin/ldconfig %postun -n libnvpair3 -p /sbin/ldconfig %endif %package -n libuutil3 Summary: Solaris userland utility library for Linux Group: System Environment/Kernel Obsoletes: libuutil1 <= %{version} %description -n libuutil3 This library provides a variety of compatibility functions for OpenZFS: * libspl: The Solaris Porting Layer userland library, which provides APIs that make it possible to run Solaris user code in a Linux environment with relatively minimal modification. * libavl: The Adelson-Velskii Landis balanced binary tree manipulation library. * libefi: The Extensible Firmware Interface library for GUID disk partitioning. * libshare: NFS, SMB, and iSCSI service integration for ZFS. %if %{defined ldconfig_scriptlets} %ldconfig_scriptlets -n libuutil3 %else %post -n libuutil3 -p /sbin/ldconfig %postun -n libuutil3 -p /sbin/ldconfig %endif # The library version is encoded in the package name. When updating the # version information it is important to add an obsoletes line below for # the previous version of the package. %package -n libzfs6 Summary: Native ZFS filesystem library for Linux Group: System Environment/Kernel Obsoletes: libzfs2 <= %{version} Obsoletes: libzfs4 <= %{version} Obsoletes: libzfs5 <= %{version} %description -n libzfs6 This package provides support for managing ZFS filesystems %if %{defined ldconfig_scriptlets} %ldconfig_scriptlets -n libzfs6 %else %post -n libzfs6 -p /sbin/ldconfig %postun -n libzfs6 -p /sbin/ldconfig %endif %package -n libzfs6-devel Summary: Development headers Group: System Environment/Kernel Requires: libzfs6%{?_isa} = %{version}-%{release} Requires: libzpool6%{?_isa} = %{version}-%{release} Requires: libnvpair3%{?_isa} = %{version}-%{release} Requires: libuutil3%{?_isa} = %{version}-%{release} Provides: libzpool6-devel = %{version}-%{release} Provides: libnvpair3-devel = %{version}-%{release} Provides: libuutil3-devel = %{version}-%{release} Obsoletes: zfs-devel <= %{version} Obsoletes: libzfs2-devel <= %{version} Obsoletes: libzfs4-devel <= %{version} Obsoletes: libzfs5-devel <= %{version} %description -n libzfs6-devel This package contains the header files needed for building additional applications against the ZFS libraries. %package test Summary: Test infrastructure Group: System Environment/Kernel Requires: %{name}%{?_isa} = %{version}-%{release} Requires: parted Requires: lsscsi Requires: mdadm Requires: bc Requires: ksh Requires: fio Requires: acl Requires: sudo Requires: sysstat Requires: libaio Requires: python%{__python_pkg_version} %if 0%{?rhel}%{?centos}%{?fedora}%{?suse_version}%{?openEuler} BuildRequires: libaio-devel %endif AutoReqProv: no %description test This package contains test infrastructure and support scripts for validating the file system. %package dracut Summary: Dracut module Group: System Environment/Kernel BuildArch: noarch Requires: %{name} >= %{version} Requires: dracut Requires: /usr/bin/awk Requires: grep %description dracut This package contains a dracut module used to construct an initramfs image which is ZFS aware. %if %{with pyzfs} # Enforce `python36-` package prefix for CentOS 7 # since dependencies come from EPEL and are named this way %package -n python%{__python_pkg_version}-pyzfs Summary: Python %{python_version} wrapper for libzfs_core Group: Development/Languages/Python License: Apache-2.0 BuildArch: noarch Requires: libzfs6 = %{version}-%{release} Requires: libnvpair3 = %{version}-%{release} Requires: libffi Requires: python%{__python_pkg_version} %if 0%{?centos} == 7 Requires: python36-cffi %else Requires: python%{__python_pkg_version}-cffi %endif %if 0%{?rhel}%{?centos}%{?fedora}%{?suse_version}%{?openEuler} %if 0%{?centos} == 7 BuildRequires: python36-packaging BuildRequires: python36-devel BuildRequires: python36-cffi BuildRequires: python36-setuptools %else BuildRequires: python%{__python_pkg_version}-packaging BuildRequires: python%{__python_pkg_version}-devel BuildRequires: python%{__python_pkg_version}-cffi BuildRequires: python%{__python_pkg_version}-setuptools %endif BuildRequires: libffi-devel %endif %description -n python%{__python_pkg_version}-pyzfs This package provides a python wrapper for the libzfs_core C library. %endif %if 0%{?_initramfs} %package initramfs Summary: Initramfs module Group: System Environment/Kernel Requires: %{name}%{?_isa} = %{version}-%{release} Requires: initramfs-tools %description initramfs This package contains a initramfs module used to construct an initramfs image which is ZFS aware. %endif %if %{with pam} %package -n pam_zfs_key Summary: PAM module for encrypted ZFS datasets %if 0%{?rhel}%{?centos}%{?fedora}%{?suse_version}%{?openEuler} BuildRequires: pam-devel %endif %description -n pam_zfs_key This package contains the pam_zfs_key PAM module, which provides support for unlocking datasets on user login. %endif %prep %if %{with debug} %define debug --enable-debug %else %define debug --disable-debug %endif %if %{with debuginfo} %define debuginfo --enable-debuginfo %else %define debuginfo --disable-debuginfo %endif %if %{with asan} %define asan --enable-asan %else %define asan --disable-asan %endif %if %{with ubsan} %define ubsan --enable-ubsan %else %define ubsan --disable-ubsan %endif %if 0%{?_systemd} %define systemd --enable-systemd --with-systemdunitdir=%{_unitdir} --with-systemdpresetdir=%{_presetdir} --with-systemdmodulesloaddir=%{_modulesloaddir} --with-systemdgeneratordir=%{_systemdgeneratordir} --disable-sysvinit %define systemd_svcs zfs-import-cache.service zfs-import-scan.service zfs-mount.service zfs-mount@.service zfs-share.service zfs-zed.service zfs.target zfs-import.target zfs-volume-wait.service zfs-volumes.target %else %define systemd --enable-sysvinit --disable-systemd %endif %if %{with pyzfs} %define pyzfs --enable-pyzfs %else %define pyzfs --disable-pyzfs %endif %if %{with pam} %define pam --enable-pam %else %define pam --disable-pam %endif %setup -q %build %configure \ --with-config=user \ --with-udevdir=%{_udevdir} \ --with-udevruledir=%{_udevruledir} \ --with-dracutdir=%{_dracutdir} \ --with-pamconfigsdir=%{_datadir}/pam-configs \ --with-pammoduledir=%{_libdir}/security \ --with-python=%{__python} \ --with-pkgconfigdir=%{_pkgconfigdir} \ --disable-static \ %{debug} \ %{debuginfo} \ %{asan} \ %{ubsan} \ %{systemd} \ %{pam} \ %{pyzfs} make %{?_smp_mflags} %install %{__rm} -rf $RPM_BUILD_ROOT make install DESTDIR=%{?buildroot} find %{?buildroot}%{_libdir} -name '*.la' -exec rm -f {} \; %if 0%{!?__brp_mangle_shebangs:1} find %{?buildroot}%{_bindir} \ \( -name arc_summary -or -name arcstat -or -name dbufstat \ -or -name zilstat \) \ -exec %{__sed} -i 's|^#!.*|#!%{__python}|' {} \; find %{?buildroot}%{_datadir} \ \( -name test-runner.py -or -name zts-report.py \) \ -exec %{__sed} -i 's|^#!.*|#!%{__python}|' {} \; %endif %post %if 0%{?_systemd} %if 0%{?systemd_post:1} %systemd_post %{systemd_svcs} %else if [ "$1" = "1" -o "$1" = "install" ] ; then # Initial installation systemctl preset %{systemd_svcs} >/dev/null || true fi %endif %else if [ -x /sbin/chkconfig ]; then /sbin/chkconfig --add zfs-import /sbin/chkconfig --add zfs-load-key /sbin/chkconfig --add zfs-mount /sbin/chkconfig --add zfs-share /sbin/chkconfig --add zfs-zed fi %endif exit 0 # On RHEL/CentOS 7 the static nodes aren't refreshed by default after # installing a package. This is the default behavior for Fedora. %posttrans %if 0%{?rhel} == 7 || 0%{?centos} == 7 systemctl restart kmod-static-nodes systemctl restart systemd-tmpfiles-setup-dev udevadm trigger %endif %preun %if 0%{?_systemd} %if 0%{?systemd_preun:1} %systemd_preun %{systemd_svcs} %else if [ "$1" = "0" -o "$1" = "remove" ] ; then # Package removal, not upgrade systemctl --no-reload disable %{systemd_svcs} >/dev/null || true systemctl stop %{systemd_svcs} >/dev/null || true fi %endif %else if [ "$1" = "0" -o "$1" = "remove" ] && [ -x /sbin/chkconfig ]; then /sbin/chkconfig --del zfs-import /sbin/chkconfig --del zfs-load-key /sbin/chkconfig --del zfs-mount /sbin/chkconfig --del zfs-share /sbin/chkconfig --del zfs-zed fi %endif exit 0 %postun %if 0%{?_systemd} %if 0%{?systemd_postun:1} %systemd_postun %{systemd_svcs} %else systemctl --system daemon-reload >/dev/null || true %endif %endif %files # Core utilities %{_sbindir}/* %{_bindir}/raidz_test %{_bindir}/zvol_wait # Optional Python 3 scripts %{_bindir}/arc_summary -%{_bindir}/zarcsummary %{_bindir}/arcstat -%{_bindir}/zarcstat %{_bindir}/dbufstat %{_bindir}/zilstat # Man pages %{_mandir}/man1/* %{_mandir}/man4/* %{_mandir}/man5/* %{_mandir}/man7/* %{_mandir}/man8/* # Configuration files and scripts %{_libexecdir}/%{name} %{_udevdir}/vdev_id %{_udevdir}/zvol_id %{_udevdir}/rules.d/* %{_datadir}/%{name}/compatibility.d %if ! 0%{?_systemd} || 0%{?_initramfs} # Files needed for sysvinit and initramfs-tools %{_sysconfdir}/%{name}/zfs-functions %config(noreplace) %{_initconfdir}/zfs %else %exclude %{_sysconfdir}/%{name}/zfs-functions %exclude %{_initconfdir}/zfs %endif %if 0%{?_systemd} %{_unitdir}/* %{_presetdir}/* %{_modulesloaddir}/* %{_systemdgeneratordir}/* %else %config(noreplace) %{_sysconfdir}/init.d/* %endif %config(noreplace) %{_sysconfdir}/%{name}/zed.d/* %config(noreplace) %{_sysconfdir}/%{name}/zpool.d/* %config(noreplace) %{_sysconfdir}/%{name}/vdev_id.conf.*.example %attr(440, root, root) %config(noreplace) %{_sysconfdir}/sudoers.d/* %config(noreplace) %{_bashcompletiondir}/zfs %config(noreplace) %{_bashcompletiondir}/zpool %files -n libzpool6 %{_libdir}/libzpool.so.* %files -n libnvpair3 %{_libdir}/libnvpair.so.* %files -n libuutil3 %{_libdir}/libuutil.so.* %files -n libzfs6 %{_libdir}/libzfs*.so.* %files -n libzfs6-devel %{_pkgconfigdir}/libzfs.pc %{_pkgconfigdir}/libzfsbootenv.pc %{_pkgconfigdir}/libzfs_core.pc %{_libdir}/*.so %{_includedir}/* %doc AUTHORS COPYRIGHT LICENSE NOTICE README.md %files test %{_datadir}/%{name}/zfs-tests %{_datadir}/%{name}/test-runner %{_datadir}/%{name}/runfiles %{_datadir}/%{name}/*.sh %files dracut %doc contrib/dracut/README.md %{_dracutdir}/modules.d/* %if %{with pyzfs} %files -n python%{__python_pkg_version}-pyzfs %doc contrib/pyzfs/README %doc contrib/pyzfs/LICENSE %defattr(-,root,root,-) %{__python_sitelib}/libzfs_core/* %{__python_sitelib}/pyzfs* %endif %if 0%{?_initramfs} %files initramfs %doc contrib/initramfs/README.md /usr/share/initramfs-tools/* %else # Since we're not building the initramfs package, # ignore those files. %exclude /usr/share/initramfs-tools %endif %if %{with pam} %files -n pam_zfs_key %{_libdir}/security/* %{_datadir}/pam-configs/* %endif