Hello community, here is the log from the commit of package qclib for openSUSE:Factory checked in at 2017-12-06 08:53:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qclib (Old) and /work/SRC/openSUSE:Factory/.qclib.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "qclib" Wed Dec 6 08:53:42 2017 rev:2 rq:546853 version:1.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/qclib/qclib.changes 2017-04-14 13:40:29.475900486 +0200 +++ /work/SRC/openSUSE:Factory/.qclib.new/qclib.changes 2017-12-06 08:53:44.087646993 +0100 @@ -1,0 +2,20 @@ +Thu Nov 2 20:03:27 UTC 2017 - [email protected] + +- Upgraded to version 1.3.0 + Changes: + * Added STHYI support in LPAR + * Added new env variable QC_DEBUG_FILE (see qc_open()) + Note: Failure to open a file for logging is now treated as a fatal error + * Added script qc_dump to collect debug data in a standardized manner + * Added attributes qc_layer_uuid and qc_layer_extended_name to LPAR layer + * /proc/sysinfo parsing: Switch from "KVM/Linux" to the less strict "KVM" + to detect KVM systems + * Detect unregistered and closed handles + * Makefile: Compile SONAME into shared library + Bug fixes: + * STHYI: Properly support cc==3&&rc==4 as introduced in APAR VM65419 + * Logs: Fix month in timestamp (was off by 1) + * qc_test: Fix flags for qc_layer_name in QC_LAYER_TYPE_ZVM_HYPERVISOR +- Dropped obsolete patch qclib.correctly.interpret.sthyi.check.patch + +------------------------------------------------------------------- Old: ---- qclib-1.2.0.tgz qclib.correctly.interpret.sthyi.check.patch New: ---- qclib-1.3.0.tgz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qclib.spec ++++++ --- /var/tmp/diff_new_pack.AFA8A0/_old 2017-12-06 08:53:44.823620050 +0100 +++ /var/tmp/diff_new_pack.AFA8A0/_new 2017-12-06 08:53:44.823620050 +0100 @@ -17,7 +17,7 @@ Name: qclib -Version: 1.2.0 +Version: 1.3.0 Release: 0 Summary: Query Capacity library License: BSD-3-Clause @@ -26,7 +26,6 @@ Source: %{name}-%{version}.tgz Source1: %{name}-rpmlintrc Patch1: qclib.makefile.libdir.patch -Patch2: qclib.correctly.interpret.sthyi.check.patch BuildRequires: doxygen BuildRequires: gcc-c++ BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -77,8 +76,8 @@ %package devel Summary: Development files for Query Capacity library -Requires: libqc1 = %{version}-%{release} Group: Development/Libraries/C and C++ +Requires: libqc1 = %{version}-%{release} %description devel qclib provides a C API for extraction of system information for Linux on z @@ -86,9 +85,9 @@ %package devel-static Summary: Development files for Query Capacity library +Group: Development/Libraries/C and C++ Requires: libqc1 = %{version}-%{release} Requires: qclib-devel = %{version}-%{release} -Group: Development/Libraries/C and C++ %description devel-static qclib provides a C API for extraction of system information for Linux on z @@ -97,7 +96,6 @@ %prep %setup -q %patch1 -p1 -%patch2 -p1 %build MYCFLAGS=$(grep ^CFLAGS Makefile | cut -f2 -d=) ++++++ qclib-1.2.0.tgz -> qclib-1.3.0.tgz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/Makefile new/qclib-1.3.0/Makefile --- old/qclib-1.2.0/Makefile 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/Makefile 2017-10-24 07:02:42.000000000 +0200 @@ -1,12 +1,12 @@ -# Copyright IBM Corp. 2013, 2015 +# Copyright IBM Corp. 2013, 2017 # Versioning scheme: major.minor.bugfix # major : Backwards compatible changes to the API # minor : Additions leaving the API unmodified # bugfix: Bugfixes only -VERM = 1 -VERSION = $(VERM).2.0 -CFLAGS = -g -Wall -O2 +VERSION = 1.3.0 +VERM = $(shell echo $(VERSION) | cut -d '.' -f 1) +CFLAGS ?= -g -Wall -O2 CFILES = query_capacity.c query_capacity_data.c query_capacity_sysinfo.c query_capacity_ocf.c \ query_capacity_hypfs.c query_capacity_sthyi.c OBJECTS = $(patsubst %.c,%.o,$(CFILES)) @@ -37,7 +37,9 @@ $(AR) rcs $@ $^ libqc.so.$(VERSION): $(OBJECTS) - $(LINK) -shared $^ -o $@ + $(LINK) -Wl,-soname,libqc.so.$(VERM) -shared $^ -o $@ + -rm libqc.so.$(VERM) 2>/dev/null + ln -s libqc.so.$(VERSION) libqc.so.$(VERM) qc_test: qc_test.c libqc.a $(CC) $(CFLAGS) -static $< -L. -lqc -o $@ @@ -81,4 +83,4 @@ clean: echo " CLEAN" rm -f $(OBJECTS) libqc.a libqc.so.$(VERSION) qc_test qc_test-sh hcpinfbk_qclib.h - rm -rf html + rm -rf html libqc.so.$(VERM) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/README new/qclib-1.3.0/README --- old/qclib-1.2.0/README 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/README 2017-10-24 07:02:42.000000000 +0200 @@ -7,7 +7,7 @@ For instance, it will provide the number of CPUs * on the machine (CEC, Central Electronic Complex) layer * on the PR/SM (Processor Resource/Systems Manager) layer, i.e. visible to - LPARs + LPARs, including LPAR groups * in z/VM hosts, guests and CPU pools * in KVM hosts and guests This allows calculating the upper limit of CPU resources a highest level guest @@ -28,6 +28,9 @@ Instruction'. * hypfs file system - for more information, refer to 'Device Drivers, Features, and Commands', chapter 'S/390 hypervisor file system'. + * Firmware interface /sys/firmware/ocf - for more information, refer to + 'Device Drivers, Features, and Commands', chapter 'Identifying the z + Systems hardware'. Please refer to: http://www.ibm.com/developerworks/linux/linux390/qclib.html @@ -52,6 +55,8 @@ sample programs 'qc_test' (statically linked) and 'qc_test-sh' (dynamically linked). * 'test': Build and run the statically linked test program qc_test. + Note: Requires a static version of glibc, which some + distributions do not install per default. * 'test-sh': Build and run the dynamically linked test program qc_test. @@ -79,15 +84,33 @@ If you want to report bugs or suggest enhancements, please contact: [email protected] and put "[qclib]" as the first word in the subject line of your mail. -For bug reports, always attach a log file and a dump (see QC_DEBUG as -described in query_capacity.h), and describe the scenario in which you -observed the bug, so that the problem can be reproduced. +For bug reports, at a minimum attach a log file and a dump (see QC_DEBUG as +described in query_capacity.h or, yet better, use the qc_dump utility), and +describe the scenario in which you observed the bug, so that the problem can +be reproduced. For enhancements, please describe the proposed change and its benefits. Release History: ================ +1.3.0 + Changes: + - Added STHYI support in LPAR + - Added new env variable QC_DEBUG_FILE (see qc_open()) + Note: Failure to open a file for logging is now treated as a fatal error + - Added script qc_dump to collect debug data in a standardized manner + - Added attributes qc_layer_uuid and qc_layer_extended_name to LPAR layer + - /proc/sysinfo parsing: Switch from "KVM/Linux" to the less strict "KVM" + to detect KVM systems + - Detect unregistered and closed handles + - Makefile: Compile SONAME into shared library + + Bug fixes: + - STHYI: Properly support cc==3&&rc==4 as introduced in APAR VM65419 + - Logs: Fix month in timestamp (was off by 1) + - qc_test: Fix flags for qc_layer_name in QC_LAYER_TYPE_ZVM_HYPERVISOR + 1.2.0 Changes: - Removed source [S] for attributes qc_num_cpu_dedicated and @@ -187,4 +210,4 @@ -Copyright IBM Corp. 2013, 2016 +Copyright IBM Corp. 2013, 2017 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/qc_dump new/qclib-1.3.0/qc_dump --- old/qclib-1.2.0/qc_dump 1970-01-01 01:00:00.000000000 +0100 +++ new/qclib-1.3.0/qc_dump 2017-10-24 07:02:42.000000000 +0200 @@ -0,0 +1,46 @@ +#!/bin/bash + +# Copyright IBM Corp. 2016, 2017 + +if [ $# -lt 1 ]; then + echo; + echo "Usage: qc_test <qc_test binary>"; + echo; + echo "Creates a qclib dump enriched with add'l info"; + echo; + echo "Note: Specification of qc_test binary is required to avoid usage of"; + echo " the wrong qc_test version in case there are multiple installed"; + echo; + exit 1; +fi + +# Let callers provide path to qc_test, since we might chose the wrong one +qctest="$1"; + +if [ ! -x $qctest ]; then + echo "Error: $qctest not found or not executable"; + exit 2; +fi + +echo "Executing $qctest..."; +QC_DEBUG=2 $qctest >/tmp/ref_result.txt; + +if [ $? -ne 0 ]; then + echo "Error: $qctest failed"; + exit 3; +fi + + +echo "Adding further content..."; +cd /tmp +dump="`ls -rtd qclib-??????.dump-1 | tail -1`"; +mv ref_result.txt $dump; +lscpu -e > $dump/lscpu.output; +hostname > $dump/hostname.output; +tgt=${dump%.*}.tgz; +echo "Creating package..."; +tar cvfz $tgt $dump| sed -e 's/^/ /g'; + +echo "Dump written to $PWD/$tgt"; + +exit 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/qc_test.c new/qclib-1.3.0/qc_test.c --- old/qclib-1.2.0/qc_test.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/qc_test.c 2017-10-24 07:02:42.000000000 +0200 @@ -1,4 +1,4 @@ -/* Copyright IBM Corp. 2013, 2016 */ +/* Copyright IBM Corp. 2013, 2017 */ #include <stdlib.h> #include <stdio.h> @@ -515,6 +515,8 @@ print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); print_string_attr(hdl, qc_layer_name, "S V", layer, indent); + print_string_attr(hdl, qc_layer_extended_name, "S ", layer, indent); + print_string_attr(hdl, qc_layer_uuid, "S ", layer, indent); print_int_attr(hdl, qc_partition_number, "S V", layer, indent); print_string_attr(hdl, qc_partition_char, "S ", layer, indent); print_int_attr(hdl, qc_partition_char_num, "S ", layer, indent); @@ -555,7 +557,7 @@ print_string_attr(hdl, qc_layer_category, "n/a", layer, indent); print_int_attr(hdl, qc_layer_type_num, "n/a", layer, indent); print_int_attr(hdl, qc_layer_category_num, "n/a", layer, indent); - print_string_attr(hdl, qc_layer_name, "S V", layer, indent); + print_string_attr(hdl, qc_layer_name, " V", layer, indent); print_string_attr(hdl, qc_cluster_name, " V", layer, indent); print_string_attr(hdl, qc_control_program_id, "S ", layer, indent); print_int_attr(hdl, qc_adjustment, "S ", layer, indent); @@ -733,6 +735,14 @@ void *hdl = NULL, *hdl2 = NULL; err_cnt = 0; + if (fulltest) { + // First sanity check: Call with invalid handle before any were opened + qc_get_num_layers((void*)0x1, &i); + if (i >= 0) { + printf("Error: qc_get_num_layers(0x1, &rc) worked, returning '%d'\n", i); + err_cnt++; + } + } if (get_handle(&hdl, &layers, quiet) != 0) { err_cnt++; goto out; @@ -851,7 +861,7 @@ if (!hdls) return 1; if (optind < argc) { - // dump(s) specified on command line - dump all, and close handels later on + // dump(s) specified on command line - dump all, and close handles later on for (j = 0, i = optind; i < argc; ++i, ++j) { setenv("QC_USE_DUMP", argv[i], 1); if ((hdls[j] = run_test(quiet, 0)) == NULL) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity.c new/qclib-1.3.0/query_capacity.c --- old/qclib-1.2.0/query_capacity.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity.c 2017-10-24 07:02:42.000000000 +0200 @@ -1,4 +1,4 @@ -/* IBM Corp. 2013, 2016 */ +/* Copyright IBM Corp. 2013, 2016 */ //_GNU_SOURCE used for getline and posix_memalign #define _GNU_SOURCE @@ -21,6 +21,12 @@ static unsigned int qc_dbg_dump_idx; static iconv_t qc_cd = (iconv_t)-1; +struct qc_reg_hdl { + struct qc_handle *hdl; + struct qc_reg_hdl *next; +}; + +static struct qc_reg_hdl *qc_hdls = NULL; static void __attribute__((destructor)) qc_destructor() { if (qc_cd != (iconv_t)-1) @@ -85,18 +91,28 @@ int fd; if (!qc_dbg_file_name) { - qc_dbg_file_name = strdup(QC_DBGFILE); - if (!qc_dbg_file_name) - goto out_err; - fd = mkstemp(qc_dbg_file_name); - if (fd == -1) - goto out_err; - qc_dbg_file = fdopen(fd, "w"); - if (!qc_dbg_file) { - close(fd); - goto out_err; + char *s = getenv("QC_DEBUG_FILE"); + if (s) { + qc_dbg_file_name = strdup(s); + if (!qc_dbg_file_name) + goto out_err; + qc_dbg_file = fopen(qc_dbg_file_name, "w"); + if (!qc_dbg_file) + goto out_err; + } else { + qc_dbg_file_name = strdup(QC_DBGFILE); + if (!qc_dbg_file_name) + goto out_err; + fd = mkstemp(qc_dbg_file_name); + if (fd == -1) + goto out_err; + qc_dbg_file = fdopen(fd, "w"); + if (!qc_dbg_file) { + close(fd); + goto out_err; + } } - qc_debug(NULL, "This is qclib v1.2.0, level a7ecaf7, date 2016-06-03 09:04:14 +0200\n"); + qc_debug(NULL, "This is qclib v1.3.0, level 9c8868c, date 2017-10-20 10:15:56 +0200\n"); } return 0; @@ -104,6 +120,7 @@ out_err: free(qc_dbg_file_name); qc_dbg_file_name = NULL; + qc_dbg_level = 0; return -1; } @@ -112,7 +129,7 @@ int i; if (!qc_dbg_file_name && qc_debug_file_init()) - return -1; + return -1; for (i = 0, ++qc_dbg_dump_idx; i < 100; ++i, ++qc_dbg_dump_idx) { free(qc_dbg_dump_dir); qc_dbg_dump_dir = NULL; @@ -169,9 +186,8 @@ } qc_update_dbg_level(); if (qc_dbg_level > 0 && !qc_dbg_file) { - // open the log file - failure to do so is not a fatal error if (qc_debug_file_init()) { - qc_dbg_level = 0; + rc = 1; goto out_err; } qc_debug(NULL, "Log level set to %ld\n", qc_dbg_level); @@ -300,36 +316,6 @@ } } -void qc_close(void *hdl) { - qc_debug(hdl, "qc_close()\n"); - qc_debug_indent_inc(); - - qc_debug_deinit(hdl); - qc_hdl_reinit(hdl); - free(hdl); - - qc_debug_indent_dec(); -} - -int qc_get_num_layers(void *config, int *rc) { - struct qc_handle *hdl = config; - - qc_debug(hdl, "qc_get_num_layers()\n"); - qc_debug_indent_inc(); - if (!hdl) { - qc_debug_indent_dec(); - *rc = -EFAULT; - return *rc; - } - while (hdl->next) - hdl = hdl->next; - qc_debug(hdl, "Return %d layers\n", hdl->layer_no + 1); - *rc = 0; - qc_debug_indent_dec(); - - return hdl->layer_no + 1; -} - #define ATTR_UNDEF qc_layer_name /** Verifies that a + (b (+ c)) <= d (b and c are optional, where b being unset (==ATTR_UNDEF) implies c being unset, too) * for the respective int-attributes holds true. @@ -609,10 +595,12 @@ if (qc_dbg_level > 1 || (qc_dbg_autodump && *rc < 0)) { qc_debug(hdl, "Create dump\n"); qc_debug_indent_inc(); - qc_debug_open_dump_dir(hdl); // get a new dump directory - for (i = 0; (src = sources[i]) != NULL; i++) - src->dump(hdl, src->priv); - qc_debug_close_dump_dir(hdl); + if (qc_debug_open_dump_dir(hdl) == 0) { // get a new dump directory + for (i = 0; (src = sources[i]) != NULL; i++) + src->dump(hdl, src->priv); + qc_debug_close_dump_dir(hdl); + } else + qc_debug(hdl, "Failed, could not open directory\n"); qc_debug_indent_dec(); } @@ -625,6 +613,56 @@ return hdl; } +static int qc_register_hdl(struct qc_handle *hdl) { + struct qc_reg_hdl *entry; + + entry = malloc(sizeof(struct qc_reg_hdl)); + if (!entry) { + qc_debug(hdl, "Error: Failed register hdl\n"); + return -1; + } + entry->hdl = hdl; + if (qc_hdls) + entry->next = qc_hdls; + else + entry->next = NULL; + qc_hdls = entry; + + return 0; +} + +static int qc_verify_hdl(struct qc_handle *hdl, const char *func) { + struct qc_reg_hdl *entry; + + if (!hdl) + return -1; + for (entry = qc_hdls; entry != NULL; entry = entry->next) { + if (entry->hdl == hdl) + return 0; + } + qc_debug(NULL, "Error: %s() called with unknown handle 0x%p\n", func, hdl); + + return -1; +} + +static void qc_unregister_hdl(struct qc_handle *hdl) { + struct qc_reg_hdl *entry, *prev = NULL; + + for (entry = qc_hdls; entry != NULL; prev = entry, entry = entry->next) { + if (entry->hdl == hdl) { + if (prev && entry->next) + prev->next = entry->next; + else if (!prev) + qc_hdls = entry->next; + else + prev->next = NULL; + free(entry); + break; + } + } + return; +} + void *qc_open(int *rc) { struct qc_handle *hdl = NULL; char *s, *end; @@ -669,6 +707,8 @@ if (*rc > 0) { qc_debug(hdl, "Warning: Unable to retrieve consistent data, giving up\n"); } + if (*rc == 0) + *rc = qc_register_hdl(hdl); out: qc_debug(hdl, "Return %p, rc=%d\n", *rc ? NULL : hdl, *rc); @@ -681,12 +721,42 @@ return hdl; } +void qc_close(void *hdl) { + if (qc_verify_hdl(hdl, "qc_close")) + return; + qc_debug(hdl, "qc_close()\n"); + qc_debug_indent_inc(); + + qc_debug_deinit(hdl); + qc_hdl_reinit(hdl); + qc_unregister_hdl(hdl); + free(hdl); + + qc_debug_indent_dec(); +} + +int qc_get_num_layers(void *cfg, int *rc) { + struct qc_handle *hdl = cfg; + + if (qc_verify_hdl(hdl, "qc_get_num_layers")) { + *rc = -EFAULT; + return *rc; + } + qc_debug(hdl, "qc_get_num_layers()\n"); + qc_debug_indent_inc(); + while (hdl->next) + hdl = hdl->next; + qc_debug(hdl, "Return %d layers\n", hdl->layer_no + 1); + *rc = 0; + qc_debug_indent_dec(); + + return hdl->layer_no + 1; +} + static struct qc_handle *qc_get_layer_handle(void *config, int layer) { struct qc_handle *hdl = config; do { - if (!hdl) - return NULL; if (hdl->layer_no == layer) return hdl; hdl = hdl->next; @@ -700,10 +770,13 @@ } int qc_get_attribute_string(void *cfg, enum qc_attr_id id, int layer, const char **value) { - struct qc_handle *hdl = qc_get_layer_handle(cfg, layer); + struct qc_handle *hdl; int rc; *value = NULL; + if (qc_verify_hdl(cfg, "qc_get_attribute_string")) + return -4; + hdl = qc_get_layer_handle(cfg, layer); qc_debug(cfg, "qc_get_attribute_string(attr=%d, layer=%d)\n", id, layer); qc_debug_indent_inc(); if (!hdl) { @@ -733,11 +806,14 @@ } int qc_get_attribute_int(void *cfg, enum qc_attr_id id, int layer, int *value) { - struct qc_handle *hdl = qc_get_layer_handle(cfg, layer); + struct qc_handle *hdl; void *ptr = NULL; int rc; *value = -EINVAL; + if (qc_verify_hdl(cfg, "qc_get_attribute_int")) + return -4; + hdl = qc_get_layer_handle(cfg, layer); qc_debug(cfg, "qc_get_attribute_int(attr=%d, layer=%d)\n", id, layer); qc_debug_indent_inc(); if (!hdl) { @@ -772,11 +848,14 @@ int qc_get_attribute_float(void *cfg, enum qc_attr_id id, int layer, float *value) { - struct qc_handle *hdl = qc_get_layer_handle(cfg, layer); + struct qc_handle *hdl; void *ptr = NULL; int rc; *value = -EINVAL; + if (qc_verify_hdl(cfg, "qc_get_attribute_float")) + return -4; + hdl = qc_get_layer_handle(cfg, layer); qc_debug(cfg, "qc_get_attribute_float(attr=%d, layer=%d)\n", id, layer); qc_debug_indent_inc(); if (!hdl) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity.h new/qclib-1.3.0/query_capacity.h --- old/qclib-1.2.0/query_capacity.h 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity.h 2017-10-24 07:02:42.000000000 +0200 @@ -1,4 +1,4 @@ -/* Copyright IBM Corp. 2013, 2016 */ +/* Copyright IBM Corp. 2013, 2017 */ /** @file */ @@ -15,36 +15,30 @@ * what layers. The letter encoding in the 'Src' column describes how the * value is gained: * - **S**: Provided by \c /proc/sysinfo, which is present in all Linux on z flavors. - * - **O**: Provided by \c /sys/firmware/oci. Available in Linux 3.0 or higher. + * - **O**: Provided by \c /sys/firmware/ocf. Available in Linux kernel 3.0 or higher. * - **H**: Provided by hypfs, which is (preferably) available through \c debugfs at * \c /sys/kernel/debug/s390_hypfs, or \c s390_hypfs (typically mounted at - * \c /sys/hypervisor/s390. + * \c /sys/hypervisor/s390). * Proper file access privileges required. * - **h**: See H, but provided by \c debugfs exclusively. - * - **V**: Provided by the STHYI instruction in z/VM. Requires z/VM 6.3 with APAR - * VM65419 or higher. UM34746 for z/VM 6.3.0 APAR VM65716 is required for - * LPAR groups support (see layer \c QC_LAYER_TYPE_LPAR_GROUP). + * - **V**: Provided by the STHYI instruction. + * - <i>z/VM Linux guests</i>: Requires z/VM 6.3 with APAR VM65419 or higher. + * UM34746 for z/VM 6.3.0 APAR VM65716 is required for LPAR groups support + * (see layer \c QC_LAYER_TYPE_LPAR_GROUP). + * - <i>KVM Linux guests</i>: Requires Linux kernel 4.8 or higher in the KVM host. + * - <i>Linux LPAR</i>: Requires Linux kernel 4.15 or higher in the KVM host. * * Several letters indicate the order in which the value is attempted to be * acquired. If the extraction of the value in a later phase succeeds, it will * overwrite the value acquired in an earlier phase. If the extraction of the * value in a later phase does not succeed, it will not dismiss the existing - * value, if a previous phase has set it before. + * value, if a previous phase has set it before.<br> * - * For platform agnostic processing (not caring about what layers are - * present in the system), it is recommended to walk through all layers, - * - processing #qc_num_cpu_total, #qc_num_cpu_dedicated, and #qc_num_cpu_shared, if the - * layer is of the category \c "HOST" or \c "GUEST", and - * - process pool capping values, if the layer is in the \c "POOL" category. - * Then find the minimal number of the stack for a single virtual server; for - * running on multiple virtual servers, use #qc_layer_name to identify layers - * (since several higher layer entities could run on the same lower layer entity). - * Using only said attributes should result in a high probability of - * good results -- those attributes should be presented by all layers and - * provided by all sane setups. - * - * <b>Notes</b>: - * - The term <i>CPU</i> is used synonymously with <I>core</I> when MT is enabled. + * ### Notes ### + * - Special care needs to be taken with respect to [5] when processing #qc_num_cpu_total, + * #qc_num_cpu_dedicated and #qc_num_cpu_shared in layers of type QC_LAYER_TYPE_LPAR. + * - When MT is enabled, all layers above the LPAR layer will report each thread as a separate + * CPU. Otherwise, the term <i>CPU</i> is synonymous with <I>core</I>. * - A z/VM-guest running in a z/VM-CPU-pool is a layer higher than the z/VM-CPU-pool * - All strings (char pointers) carry the trailing zero byte. * - See #qc_attr_id for general explanation of attributes, and the \c 'Comment' column @@ -96,7 +90,9 @@ * #qc_layer_category_num | int | | Hardcoded to \c QC_LAYER_CAT_GUEST * #qc_layer_type |string| | Hardcoded to \c "LPAR" * #qc_layer_category |string| | Hardcoded to \c "GUEST" - * #qc_layer_name |string|<CODE>S V</CODE>| Name of LPAR + * #qc_layer_name |string|<CODE>S V</CODE>| Name of LPAR, limited to 8 characters + * #qc_layer_extended_name |string|<CODE>S </CODE>| Name of LPAR with up to 256 characters<br><b>Note</b>: Requires Linux kernel 4.10 or higher + * #qc_layer_uuid |string|<CODE>S </CODE>| <b>Note</b>: Requires Linux kernel 4.10 or higher * #qc_partition_number | int |<CODE>S </CODE>| \n * #qc_partition_char |string|<CODE>S </CODE>| \n * #qc_partition_char_num | int |<CODE>S </CODE>| \n @@ -214,8 +210,8 @@ * #qc_layer_type |string| | Hardcoded to \c "KVM-guest" * #qc_layer_category |string| | Hardcoded to \c "GUEST" * #qc_layer_name |string|<CODE>S </CODE>| Guest name truncated to 8 characters<br><b>Note</b>: \b [1] - * #qc_layer_extended_name |string|<CODE>S </CODE>| Guest name with up to 256 characters<br><b>Note</b>: \b [1] - * #qc_layer_uuid |string|<CODE>S </CODE>| Guest's universal unique ID + * #qc_layer_extended_name |string|<CODE>S </CODE>| Guest name with up to 256 characters<br><b>Note</b>: Requires Linux kernel 3.19 or higher, [1] + * #qc_layer_uuid |string|<CODE>S </CODE>| <b>Note</b>: Requires Linux kernel 3.19 or higher * #qc_num_cpu_total | int |<CODE>S </CODE>| Sum of #qc_num_cpu_configured, #qc_num_cpu_standby and #qc_num_cpu_reserved, or #qc_num_cpu_dedicated and #qc_num_cpu_shared * #qc_num_cpu_configured | int |<CODE>S </CODE>| \n * #qc_num_cpu_standby | int |<CODE>S </CODE>| \n @@ -322,7 +318,7 @@ qc_cp_weight_capping = 14, /** 1 if SRM hardlimit setting is consumption<BR> 0 if deadline<br>See \c SET \c SRM command in [3] */ qc_hardlimit_consumption = 15, - /** 1 if guest has multiple CPU types,<BR> 0 if not */ + /** 1 if layer has multiple CPU types (e.g. CPs and IFLs),<BR> 0 if not */ qc_has_multiple_cpu_types = 16, /** IFL absolute capping value -- scaled value where 0x10000 equals one CPU, or 0 if no capping set */ qc_ifl_absolute_capping = 17, @@ -350,7 +346,7 @@ qc_layer_type = 28, /** Numeric representation of layer type, see enum #qc_layer_types */ qc_layer_type_num = 29, - /** Guest's universal unique ID */ + /** Universal unique ID */ qc_layer_uuid = 30, /** Company that manufactured box */ qc_manufacturer = 31, @@ -418,11 +414,15 @@ * system.<BR> * Use the following environment variables to operate built-in service facilities: * - \c QC_DEBUG: Set to an integer value - * - >0 to enable logging to a file \c /tmp/qclib-XXXXXX. - * - >1 to have data dumped to a directory named \c /tmp/qclib-XXXXXX.dump-XXX - * on every qc_open() call.<br> - * To disable logging, either see qc_close(), or set \c QC_DEBUG to a value + * - >0 to enable logging to a file \c /tmp/qclib-XXXXXX or as specified by + * \c QC_DEBUG_FILE if set. + * - >1 to have data dumped to a directory named \c \<STEM\>.dump-XXX + * on every qc_open() call (where STEM is \c /tmp/qclib-XXXXXX or as specified + * by \c QC_DEBUG_FILE if set.<br> + * To disable logging, either see qc_close(), or set \c QC_DEBUG to a value * <=0 on the next qc_open() call.<BR> + * - \c QC_DEBUG_FILE: Stem to use for log files and dump directories (see \c + * QC_DEBUG). Defaults to \c /tmp/qclib-XXXXXX. * - \c QC_AUTODUMP: Set to a value >0 to trigger a dump to a directory named * \c /tmp/qclib-XXXXXX.dump-XXX if an error is encountered within qc_open().<br> * <b>Note</b>: This will also create an empty log file for technical reasons, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity_data.c new/qclib-1.3.0/query_capacity_data.c --- old/qclib-1.2.0/query_capacity_data.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity_data.c 2017-10-24 07:02:42.000000000 +0200 @@ -1,4 +1,4 @@ -/* IBM Corp. 2013, 2016 */ +/* Copyright IBM Corp. 2013, 2017 */ //_GNU_SOURCE used for getline and posix_memalign #define _GNU_SOURCE @@ -72,6 +72,8 @@ char partition_char[26]; int partition_char_num; char layer_name[9]; + char layer_extended_name[257]; + char layer_uuid[37]; int adjustment; int num_cpu_total; int num_cpu_configured; @@ -262,6 +264,8 @@ {qc_partition_char, string, offsetof(struct qc_lpar_values, partition_char)}, {qc_partition_char_num, integer, offsetof(struct qc_lpar_values, partition_char_num)}, {qc_layer_name, string, offsetof(struct qc_lpar_values, layer_name)}, + {qc_layer_extended_name, string, offsetof(struct qc_lpar_values, layer_extended_name)}, + {qc_layer_uuid, string, offsetof(struct qc_lpar_values, layer_uuid)}, {qc_adjustment, integer, offsetof(struct qc_lpar_values, adjustment)}, {qc_num_cpu_total, integer, offsetof(struct qc_lpar_values, num_cpu_total)}, {qc_num_cpu_configured, integer, offsetof(struct qc_lpar_values, num_cpu_configured)}, @@ -709,22 +713,9 @@ return rc; } -// Certain parts assume that empty strings might also consist of spaces -// Returns >0 if not empty, 0 if empty, and <0 for errors -int qc_is_nonempty_ebcdic(struct qc_handle *hdl, const unsigned char *buf, unsigned int buflen) { - char str[9] = ""; // suffices for all users of this function - - if (*buf == '\0') - return 0; - if (buflen > sizeof(str)) { - qc_debug(hdl, "Error: Insufficient static buffer length\n"); - return -1; - } - memcpy(str, buf, buflen); - if (qc_ebcdic_to_ascii(hdl, str, sizeof(str))) - return -2; - - return *str != '\0'; +int qc_is_nonempty_ebcdic(__u64 *str) { + // CPU Pools in STHYI have all EBCDIC spaces if not set + return *str != 0x0 && *str != 0x4040404040404040ULL; } // Sets attribute 'id' in layer as pointed to by 'hdl' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity_hypfs.c new/qclib-1.3.0/query_capacity_hypfs.c --- old/qclib-1.2.0/query_capacity_hypfs.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity_hypfs.c 2017-10-24 07:02:42.000000000 +0200 @@ -4,7 +4,6 @@ #define _DEFAULT_SOURCE #include <sys/stat.h> -#include <linux/types.h> #include <fcntl.h> #include <unistd.h> #include <dirent.h> @@ -364,7 +363,6 @@ struct dfs_sys_hdr *sys_hdr, *tgt_lpar; struct dfs_cpu_info *cpu; struct qc_handle *group; - __u64 *p; qc_debug(hdl, "Add LPAR values from binary hypfs API\n"); qc_debug_indent_inc(); @@ -435,7 +433,7 @@ qc_set_attr_int(hdl, qc_ifl_weight_capping, ifl_weight ? *ifl_sh * 0x10000 * ifl_weight / ifl_all_weight : 0, ATTR_SRC_HYPFS))) goto out_err; } - if (*(p = (__u64 *)tgt_lpar->grp_name) != 0) { + if (qc_is_nonempty_ebcdic((__u64*)tgt_lpar->grp_name)) { /* LPAR group is only defined in case group name is not binary zero */ qc_debug(hdl, "Insert LPAR group layer\n"); if (qc_insert_handle(hdl, &group, QC_LAYER_TYPE_LPAR_GROUP)) { @@ -691,7 +689,7 @@ if ((*hdl = qc_get_zvm_hdl(*hdl, &s)) == NULL) return -1; - qc_debug(*hdl, "Found data for %llu z/VM guest(s)\n", htobe64(hdr->count)); + qc_debug(*hdl, "Found data for %" PRIu64 " z/VM guest(s)\n", htobe64((uint64_t)hdr->count)); for (i = 0, *data = (struct dfs_diag2fc*)(hdr + 1); i < htobe64(hdr->count); ++i, ++*data) { memset(&name, 0, QC_NAME_LEN + 1); memcpy(name, (*data)->guest_name, QC_NAME_LEN); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity_int.h new/qclib-1.3.0/query_capacity_int.h --- old/qclib-1.2.0/query_capacity_int.h 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity_int.h 2017-10-24 07:02:42.000000000 +0200 @@ -10,6 +10,8 @@ #include <errno.h> #include <time.h> #include <iconv.h> +#include <inttypes.h> +#include <linux/types.h> #include "query_capacity.h" @@ -61,7 +63,7 @@ /* Utility functions */ int qc_ebcdic_to_ascii(struct qc_handle *hdl, char *inbuf, size_t insz); -int qc_is_nonempty_ebcdic(struct qc_handle *hdl, const unsigned char *buf, unsigned int buflen); +int qc_is_nonempty_ebcdic(__u64 *str); int qc_new_handle(struct qc_handle *hdl, struct qc_handle **tgthdl, int layer_no, int layer_type); // Insert new layer 'inserted_hdl' of type 'type' before 'hdl'. Won't support inserting a new root int qc_insert_handle(struct qc_handle *hdl, struct qc_handle **inserted_hdl, int type); @@ -93,7 +95,7 @@ time(&t); \ tm = localtime(&t); \ fprintf(qc_dbg_file, "%02d/%02d,%02d:%02d:%02d,%-10p: %*s" arg, \ - tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, qc_get_root_handle(hdl), qc_dbg_indent, "", ##__VA_ARGS__); \ + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, qc_get_root_handle(hdl), qc_dbg_indent, "", ##__VA_ARGS__); \ } #else #define qc_debug(hdl, arg, ...) if (qc_dbg_level > 0) { \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity_ocf.c new/qclib-1.3.0/query_capacity_ocf.c --- old/qclib-1.2.0/query_capacity_ocf.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity_ocf.c 2017-10-24 07:02:42.000000000 +0200 @@ -22,7 +22,7 @@ qc_debug(hdl, "Dump ocf\n"); qc_debug_indent_inc(); if (!data) - return; + goto out; if (asprintf(&path, "%s/ocf", qc_dbg_dump_dir) == -1) { qc_debug(hdl, "Error: Mem alloc failure, cannot dump sysinfo\n"); goto out_err; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity_sthyi.c new/qclib-1.3.0/query_capacity_sthyi.c --- old/qclib-1.2.0/query_capacity_sthyi.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity_sthyi.c 2017-10-24 07:02:42.000000000 +0200 @@ -1,13 +1,14 @@ -/* Copyright IBM Corp. 2013, 2016 */ +/* Copyright IBM Corp. 2013, 2017 */ #define _GNU_SOURCE #define _DEFAULT_SOURCE -#include <signal.h> #include <iconv.h> #include <fcntl.h> #include <unistd.h> #include <endian.h> +#include <linux/types.h> +#include <sys/auxv.h> #include "query_capacity_int.h" #include "query_capacity_data.h" @@ -32,43 +33,37 @@ int avail; }; -#if defined __s390x__ || __s390__ -static void qc_stfle_signal_handler(int signal) { - qc_debug(NULL, "Signal handler invoked with signal %d\n", signal); - - return; -} -#endif - -static int qc_is_sthyi_available(void) { -#if defined __s390x__ || __s390__ - /* initialize for signal handler case */ +#if defined __s390__ +static int qc_is_sthyi_facility_available() { unsigned long long stfle_buffer[(STHYI_FACILITY_BIT/64)+1] __attribute__ ((aligned (8))) = { 0,}; - sighandler_t old_handler; - - /* we assume STFLE is available, cannot check, since we are - * in problem state and /proc/cpuinfo features might not be present. - * Therefore set up signal handler to ignore illegal instructions - * on older machines */ - old_handler = signal(SIGILL, qc_stfle_signal_handler); { register unsigned long reg0 asm("0") = STHYI_FACILITY_BIT/64 ; asm volatile (".insn s,0xb2b00000,%0" : "=m" (stfle_buffer), "+d" (reg0) : : "cc", "memory"); } - signal(SIGILL, old_handler); return (stfle_buffer[STHYI_FACILITY_BIT/64] >> (63 - (STHYI_FACILITY_BIT%64))) & 1; -#else - return 0; +} +#endif + +static int qc_is_sthyi_available_vm(struct qc_handle *hdl) { +#if defined __s390__ + unsigned long aux = getauxval(AT_HWCAP); + + if (aux & HWCAP_S390_STFLE) + return qc_is_sthyi_facility_available(); + else + qc_debug(hdl, "STFLE not available\n"); #endif + + return 0; } -static int qc_sthyi(char *sthyi_buffer) { -#if defined __s390x__ || __s390__ +static int qc_sthyi_vm(struct sthyi_priv *priv) { +#if defined __s390__ register unsigned long function_code asm("2") = 0; - register unsigned long buffer asm("4") = (unsigned long) sthyi_buffer; + register unsigned long buffer asm("4") = (unsigned long) priv->data; register unsigned long return_code asm("5"); int cc = -1; @@ -78,17 +73,39 @@ : "=d" (cc), "=d" (return_code) : "d" (function_code), "d" (buffer) : "memory", "cc"); - if (cc == 0) { - /* buffer was updated */ + if (cc == 3 && return_code == 4) return 1; - } - /* if cc==-1: exception. never mind, return 0 */ - /* if cc==3: never mind, r carries return code */ + if (cc == 0) + /* buffer was updated */ + priv->avail = STHYI_AVAILABLE; #endif return 0; } +static int qc_sthyi_lpar(struct qc_handle *hdl, struct sthyi_priv *priv) { +#if defined __s390__ + uint64_t cc; + long sthyi = 380; + +#ifdef __NR_s390_sthyi + sthyi = __NR_s390_sthyi +#endif + qc_debug(hdl, "Try STHYI@LPAR\n"); + if (syscall(sthyi, 0, priv->data, &cc, 0) || cc) { + if (errno == ENOSYS) { + qc_debug(hdl, "STHYI@LPAR is not available\n"); + return 0; + } + qc_debug(hdl, "Error: STHYI@LPAR execution failed: errno='%s', cc=%" PRIu64 "\n", strerror(errno), cc); + return -1; + } + qc_debug(hdl, "STHYI@LPAR succeeded\n"); + priv->avail = STHYI_AVAILABLE; +#endif + + return 0; +} static int qc_parse_sthyi_machine(struct qc_handle *cec, struct inf0mac *machine) { qc_debug(cec, "Add CEC values from STHYI\n"); @@ -162,7 +179,7 @@ goto out_err; } - if (partition->infpval1 & INFPLGVL && (rc = qc_is_nonempty_ebcdic(lpar, partition->infplgnm, sizeof(partition->infplgnm))) > 0) { + if (partition->infpval1 & INFPLGVL && (rc = qc_is_nonempty_ebcdic((__u64*)partition->infplgnm)) > 0) { /* LPAR group is only defined in case group name is not empty */ qc_debug(lpar, "Insert LPAR group layer\n"); if (qc_insert_handle(lpar, &group, QC_LAYER_TYPE_LPAR_GROUP)) { @@ -211,7 +228,6 @@ static int qc_parse_sthyi_guest(struct qc_handle *gst, struct inf0gst *guest) { struct qc_handle *pool_hdl; - int rc; qc_debug(gst, "Add Guest values from STHYI\n"); if (qc_set_attr_int(gst, qc_mobility_eligible, (guest->infgflg1 & INFGMOB) ? 1 : 0, ATTR_SRC_STHYI) || @@ -245,7 +261,7 @@ return -5; /* if pool name is empty then we're done */ - if ((rc = qc_is_nonempty_ebcdic(gst, guest->infgpnam, sizeof(guest->infgpnam))) > 0) { + if (qc_is_nonempty_ebcdic((__u64*)guest->infgpnam)) { qc_debug(gst, "Add Pool values\n"); qc_debug(gst, "Layer %2d: z/VM pool\n", gst->layer_no); if (qc_insert_handle(gst, &pool_hdl, QC_LAYER_TYPE_ZVM_CPU_POOL)) { @@ -260,10 +276,9 @@ qc_set_attr_int(pool_hdl, qc_cp_capped_capacity, htobe32(guest->infgpccc), ATTR_SRC_STHYI) || qc_set_attr_int(pool_hdl, qc_ifl_capped_capacity, htobe32(guest->infgpicc), ATTR_SRC_STHYI)) return -7; - rc = 0; } - return rc; + return 0; } static int qc_get_num_vm_layers(struct qc_handle *hdl, int *rc) { @@ -490,20 +505,21 @@ goto out; priv->avail = STHYI_AVAILABLE; } else { - if (!qc_is_sthyi_available()) { - qc_debug(hdl, "STHYI not available\n"); - goto out; - } - qc_debug(hdl, "STHYI is available\n"); - /* we assume we are not relocated at this spot, between STFLE and STHYI */ - if (!qc_sthyi(priv->data)) { - qc_debug(hdl, "Error: STHYI execution failed\n"); - rc = -3; - goto out; + /* There is no way for us to check programmatically whether + we're in an LPAR or in a VM, so we simply try out both */ + if (qc_is_sthyi_available_vm(hdl)) { + qc_debug(hdl, "Executing STHYI@VM\n"); + /* we assume we are not relocated at this spot, between STFLE and STHYI */ + if (qc_sthyi_vm(priv)) { + qc_debug(hdl, "Error: STHYI@VM execution failed\n"); + rc = -3; + goto out; + } + } else { + qc_debug(hdl, "STHYI@VM is not available\n"); + rc = qc_sthyi_lpar(hdl, priv); } - priv->avail = STHYI_AVAILABLE; } - goto out; out: qc_debug_indent_dec(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qclib-1.2.0/query_capacity_sysinfo.c new/qclib-1.3.0/query_capacity_sysinfo.c --- old/qclib-1.2.0/query_capacity_sysinfo.c 2016-06-03 09:14:01.000000000 +0200 +++ new/qclib-1.3.0/query_capacity_sysinfo.c 2017-10-24 07:02:42.000000000 +0200 @@ -1,4 +1,4 @@ -/* Copyright IBM Corp. 2013, 2015 */ +/* Copyright IBM Corp. 2013, 2017 */ #define _GNU_SOURCE #include <sys/types.h> @@ -195,7 +195,7 @@ vmxx[j] = c; // Parse file till we find control program ID and name (which precedes) // Note: strtok_r will skip empty lines - hence we can't start out reading the next line - // start of the loop, or we'd we skipping a line when looping in the big loop + // start of the loop, or we'd skip a line when looping in the big loop layer_name[0] = '\0'; do { if (strncmp(*line, vmxx, 5) != 0) @@ -224,7 +224,7 @@ guesttype = QC_LAYER_TYPE_ZVM_GUEST; qc_debug(hdl, "Layer %2d: z/VM-host\n", hdl->layer_no + 1); qc_debug(hdl, "Layer %2d: z/VM-guest\n", hdl->layer_no + 2); - } else if (!strncmp(str_buf, "KVM/Linux", strlen("KVM/Linux"))) { + } else if (!strncmp(str_buf, "KVM", strlen("KVM"))) { hosttype = QC_LAYER_TYPE_KVM_HYPERVISOR; guesttype = QC_LAYER_TYPE_KVM_GUEST; qc_debug(hdl, "Layer %2d: KVM-host\n", hdl->layer_no + 1); @@ -338,6 +338,8 @@ QC_SYSINFO_PARSE_LINE_INT(hdl, "Dedicated: %i", qc_num_cpu_dedicated); QC_SYSINFO_PARSE_LINE_INT(hdl, "Shared: %i", qc_num_cpu_shared); } + QC_SYSINFO_PARSE_LINE_STR(hdl, "Extended Name: %256[^\n]", 256, qc_layer_extended_name); + QC_SYSINFO_PARSE_LINE_STR(hdl, "UUID: %36s", 36, qc_layer_uuid); } rc = qc_derive_part_char_num(hdl);
