s390utils/SOURCES/s390utils-2.16.0-rhel.patch

3523 lines
108 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 02fb523c7cf1619cb53803a52ca73a56bd43f7e2 Mon Sep 17 00:00:00 2001
From: Ingo Franzki <ifranzki@linux.ibm.com>
Date: Tue, 23 Feb 2021 08:52:26 +0100
Subject: [PATCH 1/7] zkey: Fix build error when the compiler flags are
overridden
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When the compiler flags are overridden, the build of zkey may fail with:
kms.c:44:2: error: #error KMS_PLUGIN_LOCATION must be defined
44 | #error KMS_PLUGIN_LOCATION must be defined
| ^~~~~
The Makefile uses CFLAGS variable for defining the KMS_PLUGIN_LOCATION,
but it should rather use ALL_CFLAGS.
Also use ALL_CPPFLAGS for defining HAVE_LUKS2_SUPPORT.
Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/108
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
(cherry picked from commit 3f3f063c98278f53ad3b34e68b70fca62eaea8fb)
---
zkey/Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/zkey/Makefile b/zkey/Makefile
index 41129bc..f74e209 100644
--- a/zkey/Makefile
+++ b/zkey/Makefile
@@ -18,7 +18,7 @@ ifneq (${HAVE_CRYPTSETUP2},0)
ifneq (${HAVE_OPENSSL},0)
BUILD_TARGETS += zkey-cryptsetup
INSTALL_TARGETS += install-zkey-cryptsetup
- CPPFLAGS += -DHAVE_LUKS2_SUPPORT
+ ALL_CPPFLAGS += -DHAVE_LUKS2_SUPPORT
else
BUILD_TARGETS += zkey-cryptsetup-skip-openssl
INSTALL_TARGETS += zkey-cryptsetup-skip-openssl
@@ -34,7 +34,7 @@ endif
libs = $(rootdir)/libutil/libutil.a
-CFLAGS += -DKMS_PLUGIN_LOCATION=\"$(ZKEYKMSPLUGINDIR)\"
+ALL_CFLAGS += -DKMS_PLUGIN_LOCATION=\"$(ZKEYKMSPLUGINDIR)\"
detect-libcryptsetup.dep:
echo "#include <libcryptsetup.h>" > detect-libcryptsetup.dep
--
2.31.1
From ea06d53a2d775bd1ad54482202ea021aaa93a1d8 Mon Sep 17 00:00:00 2001
From: Marc Hartmayer <mhartmay@linux.ibm.com>
Date: Wed, 24 Feb 2021 15:04:11 +0000
Subject: [PATCH 2/7] genprotimg: use `pv_` namespace for our Buffer
implementation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use `pv_` namespace for our Buffer implementation so a symbol clash with other
libraries is less likely.
Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/109
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
(cherry picked from commit b6bdd7744aba06d82f30b0c84012f0b06ccb01de)
---
genprotimg/src/pv/pv_comp.c | 26 +++++------
genprotimg/src/pv/pv_comp.h | 4 +-
genprotimg/src/pv/pv_comps.c | 10 ++---
genprotimg/src/pv/pv_comps.h | 4 +-
genprotimg/src/pv/pv_hdr.c | 24 +++++------
genprotimg/src/pv/pv_hdr.h | 4 +-
genprotimg/src/pv/pv_image.c | 70 +++++++++++++++---------------
genprotimg/src/pv/pv_image.h | 14 +++---
genprotimg/src/pv/pv_ipib.c | 4 +-
genprotimg/src/pv/pv_ipib.h | 2 +-
genprotimg/src/pv/pv_stage3.c | 26 +++++------
genprotimg/src/pv/pv_stage3.h | 10 ++---
genprotimg/src/utils/buffer.c | 18 ++++----
genprotimg/src/utils/buffer.h | 16 +++----
genprotimg/src/utils/crypto.c | 72 +++++++++++++++----------------
genprotimg/src/utils/crypto.h | 28 ++++++------
genprotimg/src/utils/file_utils.c | 4 +-
genprotimg/src/utils/file_utils.h | 2 +-
18 files changed, 169 insertions(+), 169 deletions(-)
diff --git a/genprotimg/src/pv/pv_comp.c b/genprotimg/src/pv/pv_comp.c
index 1f64eea..21879ae 100644
--- a/genprotimg/src/pv/pv_comp.c
+++ b/genprotimg/src/pv/pv_comp.c
@@ -73,12 +73,12 @@ PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
return pv_component_new(type, size, DATA_FILE, (void **)&file, err);
}
-PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
+PvComponent *pv_component_new_buf(PvComponentType type, const PvBuffer *buf,
GError **err)
{
g_assert(buf);
- g_autoptr(Buffer) dup_buf = buffer_dup(buf, FALSE);
+ g_autoptr(PvBuffer) dup_buf = pv_buffer_dup(buf, FALSE);
return pv_component_new(type, buf->size, DATA_BUFFER, (void **)&dup_buf,
err);
}
@@ -90,7 +90,7 @@ void pv_component_free(PvComponent *component)
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER:
- buffer_clear(&component->buf);
+ pv_buffer_clear(&component->buf);
break;
case DATA_FILE:
comp_file_free(component->file);
@@ -162,21 +162,21 @@ gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_pat
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER: {
- g_autoptr(Buffer) enc_buf = NULL;
+ g_autoptr(PvBuffer) enc_buf = NULL;
if (!(IS_PAGE_ALIGNED(pv_component_size(component)))) {
- g_autoptr(Buffer) new = NULL;
+ g_autoptr(PvBuffer) new = NULL;
/* create a page aligned copy */
- new = buffer_dup(component->buf, TRUE);
- buffer_clear(&component->buf);
+ new = pv_buffer_dup(component->buf, TRUE);
+ pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&new);
}
enc_buf = encrypt_buf(parms, component->buf, err);
if (!enc_buf)
return -1;
- buffer_clear(&component->buf);
+ pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&enc_buf);
return 0;
}
@@ -220,10 +220,10 @@ gint pv_component_align(PvComponent *component, const gchar *tmp_path,
switch (component->d_type) {
case DATA_BUFFER: {
- g_autoptr(Buffer) buf = NULL;
+ g_autoptr(PvBuffer) buf = NULL;
- buf = buffer_dup(component->buf, TRUE);
- buffer_clear(&component->buf);
+ buf = pv_buffer_dup(component->buf, TRUE);
+ pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&buf);
return 0;
} break;
@@ -301,7 +301,7 @@ int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
switch (comp->d_type) {
case DATA_BUFFER: {
- const Buffer *buf = comp->buf;
+ const PvBuffer *buf = comp->buf;
g_assert(buf->size <= INT64_MAX);
g_assert(buf->size == size);
@@ -425,7 +425,7 @@ gint pv_component_write(const PvComponent *component, FILE *f, GError **err)
switch (component->d_type) {
case DATA_BUFFER: {
- const Buffer *buf = component->buf;
+ const PvBuffer *buf = component->buf;
if (seek_and_write_buffer(f, buf, offset, err) < 0)
return -1;
diff --git a/genprotimg/src/pv/pv_comp.h b/genprotimg/src/pv/pv_comp.h
index aa1b5ae..a4ffae8 100644
--- a/genprotimg/src/pv/pv_comp.h
+++ b/genprotimg/src/pv/pv_comp.h
@@ -41,7 +41,7 @@ typedef struct {
gint d_type; /* PvComponentDataType */
union {
struct comp_file *file;
- Buffer *buf;
+ PvBuffer *buf;
void *data;
};
uint64_t src_addr;
@@ -51,7 +51,7 @@ typedef struct {
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
GError **err);
-PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
+PvComponent *pv_component_new_buf(PvComponentType type, const PvBuffer *buf,
GError **err);
void pv_component_free(PvComponent *component);
gint pv_component_type(const PvComponent *component);
diff --git a/genprotimg/src/pv/pv_comps.c b/genprotimg/src/pv/pv_comps.c
index 15d32f0..2d364fd 100644
--- a/genprotimg/src/pv/pv_comps.c
+++ b/genprotimg/src/pv/pv_comps.c
@@ -210,13 +210,13 @@ GSList *pv_img_comps_get_comps(const PvImgComps *comps)
return comps->comps;
}
-gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
- Buffer **ald_digest, Buffer **tld_digest,
+gint pv_img_comps_finalize(PvImgComps *comps, PvBuffer **pld_digest,
+ PvBuffer **ald_digest, PvBuffer **tld_digest,
uint64_t *nep, GError **err)
{
- g_autoptr(Buffer) tmp_pld_digest = NULL;
- g_autoptr(Buffer) tmp_ald_digest = NULL;
- g_autoptr(Buffer) tmp_tld_digest = NULL;
+ g_autoptr(PvBuffer) tmp_pld_digest = NULL;
+ g_autoptr(PvBuffer) tmp_ald_digest = NULL;
+ g_autoptr(PvBuffer) tmp_tld_digest = NULL;
comps->finalized = TRUE;
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
diff --git a/genprotimg/src/pv/pv_comps.h b/genprotimg/src/pv/pv_comps.h
index d555e36..891ecdf 100644
--- a/genprotimg/src/pv/pv_comps.h
+++ b/genprotimg/src/pv/pv_comps.h
@@ -32,8 +32,8 @@ gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
GError **err);
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n);
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err);
-gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
- Buffer **ald_digest, Buffer **tld_digest,
+gint pv_img_comps_finalize(PvImgComps *comps, PvBuffer **pld_digest,
+ PvBuffer **ald_digest, PvBuffer **tld_digest,
uint64_t *nep, GError **err);
void pv_img_comps_free(PvImgComps *comps);
diff --git a/genprotimg/src/pv/pv_hdr.c b/genprotimg/src/pv/pv_hdr.c
index 45e721d..e46e176 100644
--- a/genprotimg/src/pv/pv_hdr.c
+++ b/genprotimg/src/pv/pv_hdr.c
@@ -76,17 +76,17 @@ uint64_t pv_hdr_get_nks(const PvHdr *hdr)
}
/* In-place modification of ``buf`` */
-static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, Buffer *buf,
+static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, PvBuffer *buf,
GError **err)
{
uint32_t hdr_len = pv_hdr_size(hdr);
uint32_t aad_len = pv_hdr_aad_size(hdr);
guint tag_len = pv_hdr_tag_size(hdr);
uint32_t enc_len = pv_hdr_enc_size_casted(hdr);
- const Buffer aad_part = { .data = buf->data, .size = aad_len };
- Buffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
+ const PvBuffer aad_part = { .data = buf->data, .size = aad_len };
+ PvBuffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
.size = enc_len };
- Buffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
+ PvBuffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
.size = tag_len };
struct cipher_parms parms;
int64_t c_len;
@@ -119,9 +119,9 @@ static gint pv_hdr_aad_init(PvHdr *hdr, const PvImage *img, GError **err)
g_autofree union ecdh_pub_key *cust_pub_key = NULL;
struct pv_hdr_key_slot *hdr_slot = hdr->slots;
struct pv_hdr_head *head = &hdr->head;
- g_autoptr(Buffer) pld = NULL;
- g_autoptr(Buffer) ald = NULL;
- g_autoptr(Buffer) tld = NULL;
+ g_autoptr(PvBuffer) pld = NULL;
+ g_autoptr(PvBuffer) ald = NULL;
+ g_autoptr(PvBuffer) tld = NULL;
uint64_t nep = 0;
g_assert(sizeof(head->iv) == img->gcm_iv->size);
@@ -250,7 +250,7 @@ PvHdr *pv_hdr_new(const PvImage *img, GError **err)
return g_steal_pointer(&ret);
}
-static void pv_hdr_memcpy(const PvHdr *hdr, const Buffer *dst)
+static void pv_hdr_memcpy(const PvHdr *hdr, const PvBuffer *dst)
{
uint64_t nks = pv_hdr_get_nks(hdr);
uint8_t *data;
@@ -270,13 +270,13 @@ static void pv_hdr_memcpy(const PvHdr *hdr, const Buffer *dst)
}
}
-Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
- enum PvCryptoMode mode, GError **err)
+PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
+ enum PvCryptoMode mode, GError **err)
{
uint32_t hdr_size = pv_hdr_size(hdr);
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
- ret = buffer_alloc(hdr_size);
+ ret = pv_buffer_alloc(hdr_size);
pv_hdr_memcpy(hdr, ret);
if (mode == PV_ENCRYPT) {
diff --git a/genprotimg/src/pv/pv_hdr.h b/genprotimg/src/pv/pv_hdr.h
index 8df7a6f..fbcc9e9 100644
--- a/genprotimg/src/pv/pv_hdr.h
+++ b/genprotimg/src/pv/pv_hdr.h
@@ -23,8 +23,8 @@
PvHdr *pv_hdr_new(const PvImage *img, GError **err);
void pv_hdr_free(PvHdr *hdr);
G_GNUC_UNUSED gboolean pv_hdr_uses_encryption(const PvHdr *hdr);
-Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
- enum PvCryptoMode mode, GError **err);
+PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
+ enum PvCryptoMode mode, GError **err);
uint32_t pv_hdr_size(const PvHdr *hdr);
uint32_t pv_hdr_aad_size(const PvHdr *hdr);
uint64_t pv_hdr_enc_size(const PvHdr *hdr);
diff --git a/genprotimg/src/pv/pv_image.c b/genprotimg/src/pv/pv_image.c
index 59eca5e..375e40f 100644
--- a/genprotimg/src/pv/pv_image.c
+++ b/genprotimg/src/pv/pv_image.c
@@ -56,7 +56,7 @@ static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
GError **err)
{
struct cipher_parms parms = { 0 };
- g_autoptr(Buffer) tweak = NULL;
+ g_autoptr(PvBuffer) tweak = NULL;
prepare_func func = NULL;
void *opaque = NULL;
gint rc;
@@ -76,7 +76,7 @@ static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
EVP_CIPHER_iv_length(cipher));
g_assert(img->xts_key->size <= UINT_MAX);
- tweak = buffer_alloc(sizeof(comp->tweak.data));
+ tweak = pv_buffer_alloc(sizeof(comp->tweak.data));
memcpy(tweak->data, comp->tweak.data, tweak->size);
func = pv_component_align_and_encrypt;
parms.cipher = cipher;
@@ -93,11 +93,11 @@ static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
return 0;
}
-static Buffer *pv_img_read_key(const gchar *path, guint key_size,
- GError **err)
+static PvBuffer *pv_img_read_key(const gchar *path, guint key_size,
+ GError **err)
{
- g_autoptr(Buffer) tmp_ret = NULL;
- Buffer *ret = NULL;
+ g_autoptr(PvBuffer) tmp_ret = NULL;
+ PvBuffer *ret = NULL;
gsize bytes_read;
FILE *f = NULL;
gsize size;
@@ -116,7 +116,7 @@ static Buffer *pv_img_read_key(const gchar *path, guint key_size,
if (!f)
return NULL;
- tmp_ret = buffer_alloc(size);
+ tmp_ret = pv_buffer_alloc(size);
if (file_read(f, tmp_ret->data, 1, tmp_ret->size, &bytes_read, err) < 0)
goto err;
@@ -160,8 +160,8 @@ static HostKeyList *pv_img_get_host_keys(GSList *host_keys_with_path, gint nid,
return g_steal_pointer(&ret);
}
-static Buffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
- GError **err)
+static PvBuffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
+ GError **err)
{
gint key_len = EVP_CIPHER_key_length(cipher);
@@ -173,8 +173,8 @@ static Buffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
return generate_aes_key((guint)key_len, err);
}
-static Buffer *pv_img_get_iv(const EVP_CIPHER *cipher, const gchar *path,
- GError **err)
+static PvBuffer *pv_img_get_iv(const EVP_CIPHER *cipher, const gchar *path,
+ GError **err)
{
gint iv_len = EVP_CIPHER_iv_length(cipher);
@@ -485,23 +485,23 @@ static void pv_hdr_key_slot_free(PvHdrKeySlot *slot)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvHdrKeySlot, pv_hdr_key_slot_free)
static PvHdrKeySlot *pv_hdr_key_slot_new(const EVP_CIPHER *gcm_cipher,
- const Buffer *cust_root_key,
+ const PvBuffer *cust_root_key,
EVP_PKEY *cust_key, EVP_PKEY *host_key,
GError **err)
{
g_autoptr(PvHdrKeySlot) ret = g_new0(PvHdrKeySlot, 1);
g_autofree union ecdh_pub_key *pub = NULL;
- g_autoptr(Buffer) exchange_key = NULL;
- g_autoptr(Buffer) digest_key = NULL;
- g_autoptr(Buffer) iv = NULL;
- Buffer pub_buf;
+ g_autoptr(PvBuffer) exchange_key = NULL;
+ g_autoptr(PvBuffer) digest_key = NULL;
+ g_autoptr(PvBuffer) iv = NULL;
+ PvBuffer pub_buf;
/* No AAD data is used */
- Buffer aad = { .data = NULL, .size = 0 };
+ PvBuffer aad = { .data = NULL, .size = 0 };
/* Set the output buffers for the encrypted data and the
* generated GCM tag
*/
- Buffer enc = { .data = ret->wrapped_key, .size = sizeof(ret->wrapped_key) };
- Buffer tag = { .data = ret->tag, .size = sizeof(ret->tag) };
+ PvBuffer enc = { .data = ret->wrapped_key, .size = sizeof(ret->wrapped_key) };
+ PvBuffer tag = { .data = ret->tag, .size = sizeof(ret->tag) };
struct cipher_parms parms;
int64_t c_len = 0;
@@ -530,7 +530,7 @@ static PvHdrKeySlot *pv_hdr_key_slot_new(const EVP_CIPHER *gcm_cipher,
g_assert(exchange_key->size == (guint)EVP_CIPHER_key_length(gcm_cipher));
/* create zero IV */
- iv = buffer_alloc((guint)EVP_CIPHER_iv_length(gcm_cipher));
+ iv = pv_buffer_alloc((guint)EVP_CIPHER_iv_length(gcm_cipher));
parms.iv_or_tweak = iv;
parms.key = exchange_key;
parms.cipher = gcm_cipher;
@@ -637,13 +637,13 @@ void pv_img_free(PvImage *img)
g_slist_free_full(img->key_slots, (GDestroyNotify)pv_hdr_key_slot_free);
g_slist_free_full(img->host_pub_keys, (GDestroyNotify)EVP_PKEY_free);
EVP_PKEY_free(img->cust_pub_priv_key);
- buffer_clear(&img->stage3a);
+ pv_buffer_clear(&img->stage3a);
pv_img_comps_free(img->comps);
g_free(img->tmp_dir);
- buffer_free(img->xts_key);
- buffer_free(img->cust_root_key);
- buffer_free(img->gcm_iv);
- buffer_free(img->cust_comm_key);
+ pv_buffer_free(img->xts_key);
+ pv_buffer_free(img->cust_root_key);
+ pv_buffer_free(img->gcm_iv);
+ pv_buffer_free(img->cust_comm_key);
g_free(img);
}
@@ -684,13 +684,13 @@ gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err)
return 0;
}
-gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
- Buffer **tld, uint64_t *nep, GError **err)
+gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, PvBuffer **pld, PvBuffer **ald,
+ PvBuffer **tld, uint64_t *nep, GError **err)
{
return pv_img_comps_finalize(img->comps, pld, ald, tld, nep, err);
}
-static gint pv_img_build_stage3b(PvImage *img, Buffer *stage3b, GError **err)
+static gint pv_img_build_stage3b(PvImage *img, PvBuffer *stage3b, GError **err)
{
g_autofree struct stage3b_args *args = NULL;
@@ -708,7 +708,7 @@ static gint pv_img_build_stage3b(PvImage *img, Buffer *stage3b, GError **err)
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err)
{
g_autoptr(PvComponent) comp = NULL;
- g_autoptr(Buffer) stage3b = NULL;
+ g_autoptr(PvBuffer) stage3b = NULL;
stage3b = stage3b_getblob(path, err);
if (!stage3b)
@@ -825,7 +825,7 @@ static gint get_stage3a_data_size(const PvImage *img, gsize *data_size,
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err)
{
- g_autoptr(Buffer) stage3a = NULL;
+ g_autoptr(PvBuffer) stage3a = NULL;
gsize bin_size, data_size = 0;
if (get_stage3a_data_size(img, &data_size, err) < 0)
@@ -845,8 +845,8 @@ gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err)
}
/* Creates the PV IPIB and sets the stage3a arguments */
-static gint pv_img_build_stage3a(Buffer *stage3a, gsize stage3a_bin_size,
- GSList *comps, const Buffer *hdr, GError **err)
+static gint pv_img_build_stage3a(PvBuffer *stage3a, gsize stage3a_bin_size,
+ GSList *comps, const PvBuffer *hdr, GError **err)
{
g_autofree struct ipl_parameter_block *ipib = NULL;
@@ -866,9 +866,9 @@ static gint pv_img_build_stage3a(Buffer *stage3a, gsize stage3a_bin_size,
}
/* Creates the actual PV header (serialized and AES-GCM encrypted) */
-static Buffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
+static PvBuffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
{
- g_autoptr(Buffer) hdr_buf = NULL;
+ g_autoptr(PvBuffer) hdr_buf = NULL;
g_autoptr(PvHdr) hdr = NULL;
hdr = pv_hdr_new(img, err);
@@ -887,7 +887,7 @@ static Buffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
*/
gint pv_img_finalize(PvImage *pv, const gchar *stage3b_path, GError **err)
{
- g_autoptr(Buffer) hdr = NULL;
+ g_autoptr(PvBuffer) hdr = NULL;
/* load stage3b template into memory and add it to the list of
* components. This must be done before calling
diff --git a/genprotimg/src/pv/pv_image.h b/genprotimg/src/pv/pv_image.h
index 7c624e2..116fb1a 100644
--- a/genprotimg/src/pv/pv_image.h
+++ b/genprotimg/src/pv/pv_image.h
@@ -25,7 +25,7 @@
typedef struct {
gchar *tmp_dir; /* directory used for temporary files */
- Buffer *stage3a; /* stage3a containing IPIB and PV header */
+ PvBuffer *stage3a; /* stage3a containing IPIB and PV header */
gsize stage3a_bin_size; /* size of stage3a.bin */
struct psw_t stage3a_psw; /* (short) PSW that is written to
* location 0 of the created image
@@ -35,15 +35,15 @@ typedef struct {
GSList *host_pub_keys; /* public host keys */
gint nid; /* Elliptic Curve used for the key derivation */
/* keys and cipher used for the AES-GCM encryption */
- Buffer *cust_root_key;
- Buffer *gcm_iv;
+ PvBuffer *cust_root_key;
+ PvBuffer *gcm_iv;
const EVP_CIPHER *gcm_cipher;
/* Information for the IPIB and PV header */
uint64_t pcf;
uint64_t scf;
- Buffer *cust_comm_key;
+ PvBuffer *cust_comm_key;
const EVP_CIPHER *cust_comm_cipher;
- Buffer *xts_key;
+ PvBuffer *xts_key;
const EVP_CIPHER *xts_cipher;
GSList *key_slots;
GSList *optional_items;
@@ -54,8 +54,8 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err);
void pv_img_free(PvImage *img);
gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err);
gint pv_img_finalize(PvImage *img, const gchar *stage3b_path, GError **err);
-gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
- Buffer **tld, uint64_t *nep, GError **err);
+gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, PvBuffer **pld, PvBuffer **ald,
+ PvBuffer **tld, uint64_t *nep, GError **err);
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err);
const PvComponent *pv_img_get_stage3b_comp(const PvImage *img, GError **err);
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err);
diff --git a/genprotimg/src/pv/pv_ipib.c b/genprotimg/src/pv/pv_ipib.c
index 2517e54..59fe008 100644
--- a/genprotimg/src/pv/pv_ipib.c
+++ b/genprotimg/src/pv/pv_ipib.c
@@ -35,7 +35,7 @@ uint64_t pv_ipib_get_size(uint32_t num_comp)
}
static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
- const Buffer *hdr)
+ const PvBuffer *hdr)
{
g_assert(sizeof(struct ipl_pl_hdr) <= UINT32_MAX);
g_assert(sizeof(struct ipl_pb0_pv_comp) <= UINT32_MAX);
@@ -100,7 +100,7 @@ static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
return 0;
}
-IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err)
+IplParameterBlock *pv_ipib_new(GSList *comps, const PvBuffer *hdr, GError **err)
{
uint64_t ipib_size = pv_ipib_get_size(g_slist_length(comps));
g_autoptr(IplParameterBlock) ret = NULL;
diff --git a/genprotimg/src/pv/pv_ipib.h b/genprotimg/src/pv/pv_ipib.h
index 9331790..4b66643 100644
--- a/genprotimg/src/pv/pv_ipib.h
+++ b/genprotimg/src/pv/pv_ipib.h
@@ -19,7 +19,7 @@
typedef struct ipl_parameter_block IplParameterBlock;
uint64_t pv_ipib_get_size(uint32_t num_comp);
-IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err);
+IplParameterBlock *pv_ipib_new(GSList *comps, const PvBuffer *hdr, GError **err);
void pv_ipib_free(IplParameterBlock *ipib);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(IplParameterBlock, pv_ipib_free)
diff --git a/genprotimg/src/pv/pv_stage3.c b/genprotimg/src/pv/pv_stage3.c
index a1e5b16..bff9db7 100644
--- a/genprotimg/src/pv/pv_stage3.c
+++ b/genprotimg/src/pv/pv_stage3.c
@@ -24,12 +24,12 @@
((struct stage3a_args *)((uint64_t)data_ptr + loader_size - \
sizeof(struct stage3a_args)))
-static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
- gsize args_size, gsize data_size,
- gboolean data_aligned, GError **err)
+static PvBuffer *loader_getblob(const gchar *filename, gsize *loader_size,
+ gsize args_size, gsize data_size,
+ gboolean data_aligned, GError **err)
{
g_autoptr(GMappedFile) mapped_file = NULL;
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
gsize size, tmp_loader_size;
gchar *loader_data;
@@ -60,7 +60,7 @@ static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
size = (data_aligned ? PAGE_ALIGN(tmp_loader_size) : tmp_loader_size) +
data_size;
- ret = buffer_alloc(size);
+ ret = pv_buffer_alloc(size);
/* copy the loader "template" */
memcpy(ret->data, loader_data, tmp_loader_size);
@@ -71,8 +71,8 @@ static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
return g_steal_pointer(&ret);
}
-Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
- gsize data_size, GError **err)
+PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
+ gsize data_size, GError **err)
{
return loader_getblob(filename, loader_size,
sizeof(struct stage3a_args), data_size, TRUE,
@@ -83,8 +83,8 @@ Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
/* Set the right offsets and sizes in the stage3a template + add
* the IPIB block with the PV header
*/
-static gint stage3a_set_data(Buffer *loader, gsize loader_size,
- const Buffer *hdr, struct ipl_parameter_block *ipib,
+static gint stage3a_set_data(PvBuffer *loader, gsize loader_size,
+ const PvBuffer *hdr, struct ipl_parameter_block *ipib,
GError **err)
{
uint32_t ipib_size = GUINT32_FROM_BE(ipib->hdr.len);
@@ -126,15 +126,15 @@ static gint stage3a_set_data(Buffer *loader, gsize loader_size,
return 0;
}
-gint build_stage3a(Buffer *loader, gsize loader_size, const Buffer *hdr,
+gint build_stage3a(PvBuffer *loader, gsize loader_size, const PvBuffer *hdr,
struct ipl_parameter_block *ipib, GError **err)
{
return stage3a_set_data(loader, loader_size, hdr, ipib, err);
}
-Buffer *stage3b_getblob(const gchar *filename, GError **err)
+PvBuffer *stage3b_getblob(const gchar *filename, GError **err)
{
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
gsize rb_size;
ret = loader_getblob(filename, &rb_size, sizeof(struct stage3b_args), 0,
@@ -146,7 +146,7 @@ Buffer *stage3b_getblob(const gchar *filename, GError **err)
return g_steal_pointer(&ret);
}
-void build_stage3b(Buffer *stage3b, const struct stage3b_args *args)
+void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args)
{
g_assert(stage3b->size > sizeof(*args));
diff --git a/genprotimg/src/pv/pv_stage3.h b/genprotimg/src/pv/pv_stage3.h
index baaf921..364408e 100644
--- a/genprotimg/src/pv/pv_stage3.h
+++ b/genprotimg/src/pv/pv_stage3.h
@@ -19,12 +19,12 @@
#include "boot/stage3b.h"
#include "utils/buffer.h"
-Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
- gsize data_size, GError **err);
-gint build_stage3a(Buffer *dc, gsize dc_size, const Buffer *hdr,
+PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
+ gsize data_size, GError **err);
+gint build_stage3a(PvBuffer *dc, gsize dc_size, const PvBuffer *hdr,
struct ipl_parameter_block *ipib, GError **err);
-Buffer *stage3b_getblob(const gchar *filename, GError **err);
-void build_stage3b(Buffer *stage3b, const struct stage3b_args *args);
+PvBuffer *stage3b_getblob(const gchar *filename, GError **err);
+void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args);
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size);
#endif
diff --git a/genprotimg/src/utils/buffer.c b/genprotimg/src/utils/buffer.c
index 35aed74..509dc0d 100644
--- a/genprotimg/src/utils/buffer.c
+++ b/genprotimg/src/utils/buffer.c
@@ -17,18 +17,18 @@
#include "common.h"
#include "file_utils.h"
-Buffer *buffer_alloc(gsize size)
+PvBuffer *pv_buffer_alloc(gsize size)
{
- Buffer *ret = g_new0(Buffer, 1);
+ PvBuffer *ret = g_new0(PvBuffer, 1);
ret->data = g_malloc0(size);
ret->size = size;
return ret;
}
-Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned)
+PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned)
{
- Buffer *ret;
+ PvBuffer *ret;
gsize size;
if (!buf)
@@ -38,19 +38,19 @@ Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned)
if (page_aligned)
size = PAGE_ALIGN(size);
- ret = buffer_alloc(size);
+ ret = pv_buffer_alloc(size);
/* content will be 0-right-padded */
memcpy(ret->data, buf->data, buf->size);
return ret;
}
-gint buffer_write(const Buffer *buf, FILE *file, GError **err)
+gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err)
{
return file_write(file, buf->data, buf->size, 1, NULL, err);
}
-void buffer_free(Buffer *buf)
+void pv_buffer_free(PvBuffer *buf)
{
if (!buf)
return;
@@ -59,11 +59,11 @@ void buffer_free(Buffer *buf)
g_free(buf);
}
-void buffer_clear(Buffer **buf)
+void pv_buffer_clear(PvBuffer **buf)
{
if (!buf || !*buf)
return;
- buffer_free(*buf);
+ pv_buffer_free(*buf);
*buf = NULL;
}
diff --git a/genprotimg/src/utils/buffer.h b/genprotimg/src/utils/buffer.h
index 7239d5c..824b72c 100644
--- a/genprotimg/src/utils/buffer.h
+++ b/genprotimg/src/utils/buffer.h
@@ -15,17 +15,17 @@
#include "common.h"
-typedef struct Buffer {
+typedef struct PvBuffer {
void *data;
gsize size; /* in bytes */
-} Buffer;
+} PvBuffer;
-Buffer *buffer_alloc(gsize size);
-void buffer_free(Buffer *buf);
-void buffer_clear(Buffer **buf);
-gint buffer_write(const Buffer *buf, FILE *file, GError **err);
-Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned);
+PvBuffer *pv_buffer_alloc(gsize size);
+void pv_buffer_free(PvBuffer *buf);
+void pv_buffer_clear(PvBuffer **buf);
+gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err);
+PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned);
-WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Buffer, buffer_free)
+WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvBuffer, pv_buffer_free)
#endif
diff --git a/genprotimg/src/utils/crypto.c b/genprotimg/src/utils/crypto.c
index 44facc2..05c3e83 100644
--- a/genprotimg/src/utils/crypto.c
+++ b/genprotimg/src/utils/crypto.c
@@ -89,15 +89,15 @@ EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err)
return g_steal_pointer(&ctx);
}
-Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
+PvBuffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
{
gint md_size = EVP_MD_size(EVP_MD_CTX_md(ctx));
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
guint digest_size;
g_assert(md_size > 0);
- ret = buffer_alloc((guint)md_size);
+ ret = pv_buffer_alloc((guint)md_size);
if (EVP_DigestFinal_ex(ctx, ret->data, &digest_size) != 1) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestFinal_ex failed"));
@@ -110,10 +110,10 @@ Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
}
/* Returns the digest of @buf using the hash algorithm @md */
-static Buffer *digest_buffer(const EVP_MD *md, const Buffer *buf, GError **err)
+static PvBuffer *digest_buffer(const EVP_MD *md, const PvBuffer *buf, GError **err)
{
g_autoptr(EVP_MD_CTX) md_ctx = NULL;
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
g_assert(buf);
md_ctx = digest_ctx_new(md, err);
@@ -134,9 +134,9 @@ static Buffer *digest_buffer(const EVP_MD *md, const Buffer *buf, GError **err)
}
/* Returns the SHA256 digest of @buf */
-Buffer *sha256_buffer(const Buffer *buf, GError **err)
+PvBuffer *sha256_buffer(const PvBuffer *buf, GError **err)
{
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
ret = digest_buffer(EVP_sha256(), buf, err);
if (!ret)
@@ -207,10 +207,10 @@ union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err)
return g_steal_pointer(&ret);
}
-static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
+static PvBuffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
{
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
gsize key_size;
ctx = EVP_PKEY_CTX_new(cust, NULL);
@@ -236,7 +236,7 @@ static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
return NULL;
}
- ret = buffer_alloc(key_size);
+ ret = pv_buffer_alloc(key_size);
if (EVP_PKEY_derive(ctx, ret->data, &key_size) != 1) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
_("Key derivation failed"));
@@ -247,11 +247,11 @@ static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
return g_steal_pointer(&ret);
}
-Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
+PvBuffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
{
- g_autoptr(Buffer) raw = buffer_alloc(70);
- g_autoptr(Buffer) ret = NULL;
- g_autoptr(Buffer) key = NULL;
+ g_autoptr(PvBuffer) raw = pv_buffer_alloc(70);
+ g_autoptr(PvBuffer) ret = NULL;
+ g_autoptr(PvBuffer) key = NULL;
guchar *data;
key = derive_key(cust, host, err);
@@ -290,10 +290,10 @@ gint generate_tweak(union tweak *tweak, uint16_t i, GError **err)
return 0;
}
-static Buffer *generate_rand_data(guint size, const gchar *err_msg,
- GError **err)
+static PvBuffer *generate_rand_data(guint size, const gchar *err_msg,
+ GError **err)
{
- g_autoptr(Buffer) buf = buffer_alloc(size);
+ g_autoptr(PvBuffer) buf = pv_buffer_alloc(size);
g_assert(size <= INT_MAX);
@@ -307,14 +307,14 @@ static Buffer *generate_rand_data(guint size, const gchar *err_msg,
return g_steal_pointer(&buf);
}
-Buffer *generate_aes_iv(guint size, GError **err)
+PvBuffer *generate_aes_iv(guint size, GError **err)
{
return generate_rand_data(size,
_("Generating a IV failed because the required amount of random data is not available"),
err);
}
-Buffer *generate_aes_key(guint size, GError **err)
+PvBuffer *generate_aes_key(guint size, GError **err)
{
return generate_rand_data(size,
_("Generating a key failed because the required amount of random data is not available"),
@@ -1756,8 +1756,8 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
gint cipher_block_size = EVP_CIPHER_block_size(cipher);
guchar in_buf[PAGE_SIZE],
out_buf[PAGE_SIZE + (guint)cipher_block_size];
- const Buffer *key = parms->key;
- const Buffer *tweak = parms->iv_or_tweak;
+ const PvBuffer *key = parms->key;
+ const PvBuffer *tweak = parms->iv_or_tweak;
g_autofree guchar *tmp_tweak = NULL;
gint out_len, tweak_size;
gsize tmp_size_in = 0, tmp_size_out = 0;
@@ -1895,11 +1895,11 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
return 0;
}
-static Buffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
- const Buffer *in, gboolean encrypt,
- GError **err)
+static PvBuffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
+ const PvBuffer *in, gboolean encrypt,
+ GError **err)
{
- g_autoptr(Buffer) ret = NULL;
+ g_autoptr(PvBuffer) ret = NULL;
g_autoptr(BIO) b_out = NULL;
g_autoptr(BIO) b_in = NULL;
gsize in_size, out_size;
@@ -1927,19 +1927,19 @@ static Buffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
return NULL;
}
- ret = buffer_alloc((unsigned long)data_size);
+ ret = pv_buffer_alloc((unsigned long)data_size);
memcpy(ret->data, data, ret->size);
return g_steal_pointer(&ret);
}
-Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
- GError **err)
+PvBuffer *encrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
+ GError **err)
{
return __encrypt_decrypt_buffer(parms, in, TRUE, err);
}
-Buffer *decrypt_buf(const struct cipher_parms *parms, const Buffer *in,
- GError **err)
+PvBuffer *decrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
+ GError **err)
{
return __encrypt_decrypt_buffer(parms, in, FALSE, err);
}
@@ -1993,16 +1993,16 @@ G_GNUC_UNUSED static gint decrypt_file(const struct cipher_parms *parms,
}
/* GCM mode uses (zero-)padding */
-static int64_t gcm_encrypt_decrypt(const Buffer *in, const Buffer *aad,
+static int64_t gcm_encrypt_decrypt(const PvBuffer *in, const PvBuffer *aad,
const struct cipher_parms *parms,
- Buffer *out, Buffer *tag,
+ PvBuffer *out, PvBuffer *tag,
enum PvCryptoMode mode, GError **err)
{
g_autoptr(EVP_CIPHER_CTX) ctx = NULL;
const EVP_CIPHER *cipher = parms->cipher;
- const Buffer *iv = parms->iv_or_tweak;
+ const PvBuffer *iv = parms->iv_or_tweak;
gboolean encrypt = mode == PV_ENCRYPT;
- const Buffer *key = parms->key;
+ const PvBuffer *key = parms->key;
int64_t ret = -1;
gint len = -1;
@@ -2097,8 +2097,8 @@ static int64_t gcm_encrypt_decrypt(const Buffer *in, const Buffer *aad,
return ret;
}
-int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
- const struct cipher_parms *parms, Buffer *out, Buffer *tag,
+int64_t gcm_encrypt(const PvBuffer *in, const PvBuffer *aad,
+ const struct cipher_parms *parms, PvBuffer *out, PvBuffer *tag,
GError **err)
{
return gcm_encrypt_decrypt(in, aad, parms, out, tag, PV_ENCRYPT, err);
diff --git a/genprotimg/src/utils/crypto.h b/genprotimg/src/utils/crypto.h
index 286cf45..3cda450 100644
--- a/genprotimg/src/utils/crypto.h
+++ b/genprotimg/src/utils/crypto.h
@@ -117,8 +117,8 @@ union tweak {
struct cipher_parms {
const EVP_CIPHER *cipher;
- const Buffer *key;
- const Buffer *iv_or_tweak;
+ const PvBuffer *key;
+ const PvBuffer *iv_or_tweak;
};
int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
@@ -152,24 +152,24 @@ X509_CRL *get_first_valid_crl(X509_STORE_CTX *ctx, X509 *cert, GError **err);
void store_setup_crl_download(X509_STORE *st);
EVP_PKEY *read_ec_pubkey_cert(X509 *cert, gint nid, GError **err);
-Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
-Buffer *generate_aes_key(guint size, GError **err);
-Buffer *generate_aes_iv(guint size, GError **err);
+PvBuffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
+PvBuffer *generate_aes_key(guint size, GError **err);
+PvBuffer *generate_aes_iv(guint size, GError **err);
EVP_PKEY *generate_ec_key(gint nid, GError **err);
gint generate_tweak(union tweak *tweak, uint16_t i, GError **err);
union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err);
EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err);
-Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
-Buffer *sha256_buffer(const Buffer *buf, GError **err);
-int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
- const struct cipher_parms *parms, Buffer *out,
- Buffer *tag, GError **err);
+PvBuffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
+PvBuffer *sha256_buffer(const PvBuffer *buf, GError **err);
+int64_t gcm_encrypt(const PvBuffer *in, const PvBuffer *aad,
+ const struct cipher_parms *parms, PvBuffer *out,
+ PvBuffer *tag, GError **err);
gint encrypt_file(const struct cipher_parms *parms, const gchar *in_path,
const gchar *path_out, gsize *in_size, gsize *out_size,
GError **err);
-Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
- GError **err);
-G_GNUC_UNUSED Buffer *decrypt_buf(const struct cipher_parms *parms,
- const Buffer *in, GError **err);
+PvBuffer *encrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
+ GError **err);
+G_GNUC_UNUSED PvBuffer *decrypt_buf(const struct cipher_parms *parms,
+ const PvBuffer *in, GError **err);
#endif
diff --git a/genprotimg/src/utils/file_utils.c b/genprotimg/src/utils/file_utils.c
index 1d6fc37..ba33400 100644
--- a/genprotimg/src/utils/file_utils.c
+++ b/genprotimg/src/utils/file_utils.c
@@ -171,13 +171,13 @@ err:
return ret;
}
-gint seek_and_write_buffer(FILE *o, const Buffer *buf, uint64_t offset,
+gint seek_and_write_buffer(FILE *o, const PvBuffer *buf, uint64_t offset,
GError **err)
{
if (file_seek(o, offset, err) < 0)
return -1;
- if (buffer_write(buf, o, err) < 0)
+ if (pv_buffer_write(buf, o, err) < 0)
return -1;
return 0;
diff --git a/genprotimg/src/utils/file_utils.h b/genprotimg/src/utils/file_utils.h
index 47df114..456e7ac 100644
--- a/genprotimg/src/utils/file_utils.h
+++ b/genprotimg/src/utils/file_utils.h
@@ -26,7 +26,7 @@ gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
gsize *count_written, GError **err);
gint pad_file_right(const gchar *path_out, const gchar *path_in,
gsize *size_out, guint padding, GError **err);
-gint seek_and_write_buffer(FILE *out, const Buffer *buf, uint64_t offset,
+gint seek_and_write_buffer(FILE *out, const PvBuffer *buf, uint64_t offset,
GError **err);
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
GError **err);
--
2.31.1
From 5997d2b96e05fd8d228bd05a8b56850822747944 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20H=C3=B6ppner?= <hoeppner@linux.ibm.com>
Date: Fri, 26 Feb 2021 16:47:23 +0100
Subject: [PATCH 3/7] ttyrun-getty: Avoid conflicts with serial-getty@
(#1907781)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Starting ttyrun-getty@ will fail as it conflicts with the serial-getty@
service. Add Conflicts= option to avoid any conflicts.
Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/105
Suggested-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
(cherry picked from commit d23558f1d1b8268f1ebcb4c05c692a89f2a433c0)
---
systemd/ttyrun-getty@.service.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/systemd/ttyrun-getty@.service.in b/systemd/ttyrun-getty@.service.in
index eb4299b..37554b4 100644
--- a/systemd/ttyrun-getty@.service.in
+++ b/systemd/ttyrun-getty@.service.in
@@ -16,7 +16,7 @@ After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
After=rc-local.service
Before=getty.target
IgnoreOnIsolate=yes
-
+Conflicts=serial-getty@%i.service
[Service]
Environment=TERM=linux
--
2.31.1
From 3040c1e6c8962b1aca1291586de304ba3ee6d67f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
Date: Fri, 2 Jul 2021 11:46:33 +0200
Subject: [PATCH 4/7] zdsfs: transparent dataset conversion (#1919238)
Summary: zdsfs: transparent dataset conversion
Description: The zdsfs tool is used to access z/OS data sets from
Linux. Many text based data sets in z/OS are EBCDIC
encoded. To perform actual work in Linux those data sets
usually have to be converted to ASCII. This is currently
done by first copying the data set to Linux using zdsfs
and run a separate conversion tool afterwards.
This item aims to improve the user experience by allowing
the user to do the conversion while the data is
transferred using zdsfs.
Upstream-ID: 4b0403a9630dd64d93efcf443d2e5231458a812e
Upstream-ID: cdf716a7a92b33c6bb64e66da2a4914fc2bd80f9
Upstream-ID: 7244785279ddcf66cf1da92f6167a824e2ee119c
Upstream-ID: 0fafbcf3bb44a49a7eea41011d60049f61063c00
Upstream-ID: 2ece47ee1ac3d5b448680264d948f6c50a76af56
Problem-ID: IO1811
---
include/lib/libzds.h | 7 +-
libzds/libzds.c | 186 +++++++++++++++++++-
zdsfs/zdsfs.1 | 167 ++++++++++++------
zdsfs/zdsfs.c | 399 ++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 697 insertions(+), 62 deletions(-)
diff --git a/include/lib/libzds.h b/include/lib/libzds.h
index 9135485..2647107 100644
--- a/include/lib/libzds.h
+++ b/include/lib/libzds.h
@@ -115,7 +115,7 @@
#include "lib/util_base.h"
#include "lib/util_list.h"
#include "vtoc.h"
-
+#include <iconv.h>
/**
@@ -834,6 +834,11 @@ void lzds_dshandle_get_errorlog(struct dshandle *dsh, struct errorlog **log);
int lzds_dshandle_set_seekbuffer(struct dshandle *dsh,
unsigned long long seek_buffer_size);
+/**
+ * @brief Set iconv handle for codepage conversion.
+ */
+int lzds_dshandle_set_iconv(struct dshandle *dsh, iconv_t *iconv);
+
/**
* @brief Get the size of the data set in number of tracks (sum of all extents).
*/
diff --git a/libzds/libzds.c b/libzds/libzds.c
index a6c6912..dbf810d 100644
--- a/libzds/libzds.c
+++ b/libzds/libzds.c
@@ -61,6 +61,9 @@ struct errorlog {
#define BUSIDSIZE 8
+#define EBCDIC_SP 0x40
+#define EBCDIC_LF 0x25
+
/**
* @brief An internal structure that represents an entry in the error log.
*/
@@ -307,6 +310,8 @@ struct dshandle {
struct errorlog *log;
char *session_ref;
+ iconv_t *iconv;
+ char *convbuffer;
};
/** @endcond */
@@ -2812,6 +2817,38 @@ int lzds_dshandle_set_keepRDW(struct dshandle *dsh, int keepRDW)
return 0;
}
+/**
+ * @pre The dsh must not be open when this function is called.
+ *
+ * @param[in] dsh The dshandle we want to modify.
+ * @param[in] iconv_t The iconv handle for codepage conversion.
+ *
+ * @return 0 on success, otherwise one of the following error codes:
+ * - EBUSY The handle is already open.
+ */
+int lzds_dshandle_set_iconv(struct dshandle *dsh, iconv_t *iconv)
+{
+ errorlog_clear(dsh->log);
+ if (dsh->is_open)
+ return errorlog_add_message(
+ &dsh->log, NULL, EBUSY,
+ "dshandle: cannot set iconv while handle is open\n");
+
+ /*
+ * if conversion is enabled the returned data might in worst case
+ * be 4 times the size of the input buffer. So realloc the buffer.
+ * If for whatever very unlikely reason the converted size is still
+ * larger the conversion will fail.
+ */
+ if (iconv) {
+ dsh->databufmax *= 4;
+ dsh->databuffer = util_realloc(dsh->databuffer,
+ dsh->databufmax);
+ }
+ dsh->iconv = iconv;
+ return 0;
+}
+
/**
* @param[in] dsh The dshandle that we want to know the member of.
* @param[out] keepRDW Reference to a variable in which the previously
@@ -2946,6 +2983,8 @@ void lzds_dshandle_close(struct dshandle *dsh)
for (i = 0; i < MAXVOLUMESPERDS; ++i)
if (dsh->dasdhandle[i])
lzds_dasdhandle_close(dsh->dasdhandle[i]);
+ free(dsh->convbuffer);
+ free(dsh->iconv);
dsh->is_open = 0;
}
@@ -3280,10 +3319,130 @@ int lzds_dshandle_open(struct dshandle *dsh)
return rc;
}
}
+ if (dsh->iconv)
+ dsh->convbuffer = util_zalloc(dsh->databufmax);
+
dsh->is_open = 1;
return 0;
}
+/**
+ * @brief subroutine of parse_fixed_record for codepage conversion
+ *
+ * Converts the provided data from one codepage to another using iconv.
+ * Stores converted data directly in the target buffer.
+ * Adds a linebreak at the end of each record to end the line.
+ * Also remove trailing spaces.
+ *
+ * @param[in] dsh The dshandle that keeps track of the I/O operations.
+ * @param[in] rec Pointer to the record buffer.
+ * @param[in] targetdata Pointer to the data buffer.
+ * @return Number of copied data bytes on success,
+ * otherwise one of the following (negative) error codes:
+ * - -EPROTO The record is malformed.
+ */
+static ssize_t convert_fixed_record(struct dshandle *dsh,
+ char *rec, char *targetdata)
+{
+ struct eckd_count *ecount = (struct eckd_count *)rec;
+ size_t in_count, out_count, max_count;
+ int reclen, blocksize, reccount;
+ char *inbuf, *outbuf;
+ char *src, *target;
+ size_t rc;
+ int i;
+
+ blocksize = ecount->dl;
+ reclen = dsh->ds->dsp[0]->f1->DS1LRECL;
+ reccount = blocksize / reclen;
+
+ outbuf = targetdata;
+ out_count = max_count =
+ (unsigned long)dsh->databuffer + dsh->databufmax -
+ (unsigned long)targetdata;
+ in_count = 0;
+ inbuf = dsh->convbuffer;
+
+ /* skip block header */
+ src = (rec + sizeof(*ecount) + ecount->kl);
+ target = inbuf;
+ /* for each record aka line */
+ for (i = 0; i < reccount; i++) {
+ /* remove trailing spaces */
+ while (reclen && (*(src + reclen - 1) == EBCDIC_SP))
+ reclen--;
+ /* move remaining data and add linebreak at end of record */
+ memcpy(target, src, reclen);
+ target += reclen;
+ *target = EBCDIC_LF;
+ target++;
+ /* count how much chars remain after whitespace cleanup */
+ in_count += reclen + 1;
+
+ /* reset for next line */
+ reclen = dsh->ds->dsp[0]->f1->DS1LRECL;
+ src += reclen;
+ }
+ /* convert directly into target buffer */
+ rc = iconv(*(dsh->iconv), &inbuf, &in_count, &outbuf, &out_count);
+ if ((rc == (size_t) -1) || (in_count != 0))
+ return -errorlog_add_message(
+ &dsh->log, NULL, EPROTO,
+ "fixed record parser: codepage conversion failed\n");
+ /* return how much was written in the target buffer */
+ return max_count - out_count;
+}
+
+/**
+ * @brief subroutine of parse_variable_record for codepage conversion
+ *
+ * Converts the record data from one codepage to another using iconv.
+ * Stores converted data directly in the target buffer
+ *
+ * @param[in] dsh The dshandle that keeps track of the I/O operations.
+ * @param[in] reclen Length of the record.
+ * @param[in] rec Pointer to the record buffer.
+ * @param[in] targetdata Pointer to the data buffer.
+ * @return Number of copied data bytes on success,
+ * otherwise one of the following (negative) error codes:
+ * - -EPROTO The record is malformed.
+ */
+static ssize_t convert_variable_record(struct dshandle *dsh, int reclen,
+ char *rec, char *targetdata)
+{
+ size_t in_count, out_count, max_count;
+ char *inbuf, *outbuf;
+ size_t rc;
+
+ inbuf = rec;
+ outbuf = targetdata;
+ in_count = reclen + 1;
+ out_count = max_count =
+ (unsigned long)dsh->databuffer + dsh->databufmax -
+ (unsigned long)targetdata;
+ /*
+ * we can not overwrite the track end marker since it is still used
+ * for this case we have to make a copy of the source data to add the
+ * linebreak
+ */
+ if (inbuf[reclen] == 0xFF) {
+ inbuf = dsh->convbuffer;
+ memcpy(inbuf, rec, reclen);
+ }
+
+ /* add linebreak */
+ inbuf[reclen] = 0x25;
+
+ rc = iconv(*(dsh->iconv), &inbuf, &in_count, &outbuf, &out_count);
+ if ((rc == (size_t) -1) || (in_count != 0))
+ return -errorlog_add_message(
+ &dsh->log, NULL, EPROTO,
+ "variable record parser: codepage conversion failed\n");
+
+ /* return how much was written in the target buffer */
+ return max_count - out_count;
+}
+
/**
* @brief subroutine of dshandle_extract_data_from_trackbuffer
*
@@ -3298,6 +3457,7 @@ static ssize_t parse_fixed_record(struct dshandle *dsh,
char *rec, char *targetdata)
{
struct eckd_count *ecount;
+ int count;
ecount = (struct eckd_count *)rec;
/* Make sure that we do not copy data beyond the end of
@@ -3308,8 +3468,13 @@ static ssize_t parse_fixed_record(struct dshandle *dsh,
return - errorlog_add_message(
&dsh->log, NULL, EPROTO,
"fixed record to long for target buffer\n");
- memcpy(targetdata, (rec + sizeof(*ecount) + ecount->kl), ecount->dl);
- return ecount->dl;
+ if (dsh->iconv) {
+ count = convert_fixed_record(dsh, rec, targetdata);
+ } else {
+ memcpy(targetdata, (rec + sizeof(*ecount) + ecount->kl), ecount->dl);
+ count = ecount->dl;
+ }
+ return count;
}
/**
@@ -3333,6 +3498,7 @@ static ssize_t parse_variable_record(struct dshandle *dsh, char *rec,
struct segment_header *blockhead;
struct segment_header *seghead;
size_t totaldatalength;
+ int count;
/* We must not rely on the data in rec, as it was read from disk and
* may be broken. Wherever we interprete the data we must have sanity
@@ -3398,9 +3564,19 @@ static ssize_t parse_variable_record(struct dshandle *dsh, char *rec,
&dsh->log, NULL, EPROTO,
"variable record parser: "
"record to long for target buffer\n");
- memcpy(targetdata, data, segmentlength);
- targetdata += segmentlength;
- totaldatalength += segmentlength;
+ if (dsh->iconv) {
+ count = convert_variable_record(dsh, segmentlength,
+ data, targetdata);
+ if (count < 0)
+ return count;
+
+ totaldatalength += count;
+ targetdata += count;
+ } else {
+ memcpy(targetdata, data, segmentlength);
+ totaldatalength += segmentlength;
+ targetdata += segmentlength;
+ }
data += segmentlength;
}
return totaldatalength;
diff --git a/zdsfs/zdsfs.1 b/zdsfs/zdsfs.1
index 677bea5..21acb70 100644
--- a/zdsfs/zdsfs.1
+++ b/zdsfs/zdsfs.1
@@ -32,29 +32,23 @@ Only read access is supported.
Data sets on tape devices are not supported.
-To maintain data consistency, a DASD must not be modified while it is
-in use by zdsfs. This can be assured by varying the device offline
-in z/OS before setting it online in Linux or by using z/OSMF REST
-services to notify z/OS about access to data sets.
-
-Device access by Linux is not subject to RACF or other
-z/OS auditing mechanisms unless the z/OSMF REST services are used for
-a coordinated read access.
-The safety of the data on the device must be established by
-therespective Linux mechanisms. By default, zdsfs grants access to the
-files in the fuse file system only to the user who started the
-tool. This behavior can be changed by using the options `allow_other',
-`default_permissions', `umask', `uid', and `gid'.
-
-When using the z/OSMF REST services for coordinated read access, a
-connection is established for every opened file. The z/OSMF REST
-services confirm that the z/OS userid that is specified in the .netrc
-configuration file has the required access rights for the data set.
-Using this mechanism also an exclusive ENQ is obtained to mark the
-data set as in use to z/OS. The ENQ prevents z/OS applications from
-modifying the data set during zdsfs access.
-If the ENQ cannot be obtained, the access from Linux fails with an
-error.
+If the z/OSMF REST services are not used for a coordinated-read
+access, access to the device by Linux is not subject to RACF or any
+other z/OS auditing mechanism. Ensure the security of the data on the
+device by using the well-known Linux methods. By default, zdsfs grants
+access to the files in the fuse file system only to the user who
+started the tool. Configure file access behavior by using the
+allow_other, default_permissions, umask, uid, and gid
+options.
+
+When using the z/OSMF REST services for coordinated read access, every
+file open establishes a connection to the z/OSMF REST server. This
+checks that the accessing z/OS user ID has the appropriate access
+rights for the data set. Using this mechanism, an exclusive ENQ is
+obtained that marks the data set as in-use to z/OS. An ENQ is a z/OS
+method to control a serially reusable resource. While the ENQ is held,
+no z/OS application can modify the data set. If the ENQ cannot be
+obtained, the access attempt from Linux fails.
Only physical sequential (PS) and partitioned data sets (PDS) are
supported. Supported record formats are: V, F, U, B, S, A, and M.
@@ -171,20 +165,50 @@ instance.
.TP
\fB\-c\fR \fI<config_file>\fR
-zdsfs configuration file. The default is /etc/zdsfs.conf.
+Provide a configuration file for zdsfs. The default is /etc/zdsfs.conf.
.TP
\fB\-o\fR restapi
-Make zdsfs use z/OSMF REST services for coordinated read access to
-data sets. The user credentials are taken from .netrc file in the
-user's home directory or where the NETRC environment variable points
+Use z/OSMF REST services for coordinated read-access to data sets. The
+user credentials are read from the .netrc file in the user's home
+directory, or from the location the NETRC environment variable points
to.
.TP
\fB\-o\fR restserver=<server_URL>
-Specify up to 3 server URLs to z/OSMF REST services.
-For multiple specifications, the URLs are tried sequentially, and the
-first functioning URL is used.
+Specify up to three server URLs to z/OSMF REST services. If more than
+one server is specified, the first that responds is used. If a server
+does not respond any longer during operation all specified server are probed again.
+
+.TP
+\fB\-x\fR \fI<dataset_file>\fR
+Use a config file with code-page conversion options for
+specific data sets.
+
+.TP
+\fB\-o\fR codepage_convert
+Enable code-page conversion for all data sets. Unless specified
+otherwise, the source code-page is EBCDIC CP1047 and the target
+code-page is UTF-8.
+
+You can change the default for the source code-page with the -o
+codepage_from option and for the target code-page with the -o
+codepage_to option. To specify source and target code-pages for
+individual data sets use a data set config file.
+
+.TP
+\fB\-o\fR codepage_from=\fI<n>\fR
+Override EBCDIC CP1047 as the default code-page for the source. Must
+be combined with \fB\-o\fR codepage_to=\fI<n>\fR. Overrides settings
+in a data set config file. Issue iconv -l for a list of valid
+specifications for <n>.
+
+.TP
+\fB\-o\fR codepage_to=\fI<n>\fR
+Override UTF-8 as the default code-page for the target. Must be
+combined with \fB\-o\fR codepage_from=\fI<n>\fR. Overrides settings
+in a data set configu file. Issue iconv -l for a list of valid
+specifications for <n>.
.SS "Applicable FUSE options (version 2.8):"
This is a selected subset of all FUSE options. Use the zdsfs
@@ -273,44 +297,81 @@ directory:
\fBuser.dsorg\fR: The data set organization of a file.
-.SH zdsfs configuration file
-
-The default search path is /etc/zdsfs.conf.
-Use the \fB\-c\fR \fI<config_file>\fR option to specify other zdsfs
-configuration file locations.
+.SH zdsfs config file
+The default path is /etc/zdsfs.conf. Specify a different zdsfs config
+file location with the \fB\-c\fR \fI<config_file>\fR option.
.br
-
-The configuration file can contain the following options:
+The config file may contain the following options:
.PP
.B restapi
=
.IR 0 / 1
.IP
-Setting this option to 1 enables the z/OSMF REST services.
-The z/OSMF REST services require a valid URL specification for a REST
-server, and a .netrc file with a valid z/OS user ID and password.
+Determines whether the z/OSMF REST services should be used. If
+enabled, a valid REST server must be specified, as well as a .netrc
+file with a valid z/OS user ID and password.
.PP
.B restserver
=
.IR URL
.IP
-Specifies the URL of the z/OSMF REST server that is
-used for coordinated read access. For failover, up to 3 different
-server addresses can be provided.
+Specifies the address of the z/OSMF REST server that is used for
+coordinating read-access. For failover scenarios, provide up to three
+different server addresses. These will be tried in the specified order
+when one of the servers cannot be reached during mount or operation.
.PP
.B keepalive
=
-.I timeout
-(in seconds)
+.I timeout (in seconds)
+.IP
+Optionally change the keepalive timer for ENQs. By default the
+keepalive refreshes the access after 540 seconds (9 minutes).The 9
+minutes are chosen to prevent a timeout by z/OS after 10 minutes.
+
+.SH data-set config file <dataset_file>
+Provides code-page conversion settings for individual data sets.
+The default config file is /etc/zdsfs-dataset.conf. Use the \fB\-x\fR
+\fI<dataset_file>\fR option to specify a different file.
+.br
+Each config-file entry must contain the following options:
+.PP
+
+.B
+DATASET.TITLE
+.IP
+Specifies the data-set title or a pattern of titles to which the entry
+applies. The title can have a trailing asterisk to match all titles
+that begin with the leading characters.
+.PP
+
+.B conv
+=
+.IR 0 / 1 / <codepage_from>,<codepage_to>
+.IP
+\fI0\fR disables code-page conversion.
+.br
+\fI1\fR performs conversion with the default conversion table.
+.br
+An explicit specification of source and target code-page overrides the default conversion tables
+The code-page specifications must be separated by a comma.
+Issue iconv -l for a list of valid code-page specifications.
+
+.PP
+
+.B rdw
+=
+.I 0 / 1
.IP
-Specifies the keepalive timer for ENQs.
-By default the timer is set to 540 seconds to prevent the ENQ from a
-timeout after 10 minutes in case access to the data set takes longer
-than this.
+\fI0\fR omits the record descriptor word from the data stream.
+.br
+\fI1\fR keeps the record descriptor word from the data stream.
+.br
+Code-page conversion can render data unreadable if the record descriptor word is kept.
+
.SH EXAMPLES
To mount the z/OS disk with the name dasde enter:
@@ -341,9 +402,15 @@ assuming the z/OS disk was mounted on /mnt:
To mount the z/OS disk using the z/OSMF REST services for coordinated
read access:
+
+ # ./zdsfs -o restapi -o restserver=zos1.server.tld/zosmf /dev/dasde /mnt/
+
.br
+To mount the z/OS disk and enable code-page conversion for all data
+sets using a custom source and target code page:
+
+ # ./zdsfs -o codepage_from=CP037 -o codepage_to=ISO-8859-1 /dev/dasde /mnt/
- # ./zdsfs -o restapi -o restserver=zos1.server.tld/zosmf /dev/dasde /mnt/
.SH SEE ALSO
getfattr(1), fuse(8), z/OS DFSMS Using Data Sets,
diff --git a/zdsfs/zdsfs.c b/zdsfs/zdsfs.c
index 87c1bea..ceadd34 100644
--- a/zdsfs/zdsfs.c
+++ b/zdsfs/zdsfs.c
@@ -25,6 +25,8 @@
#include <time.h>
#include <signal.h>
+#include <iconv.h>
+
#ifdef HAVE_SETXATTR
#include <linux/xattr.h>
#endif
@@ -34,6 +36,7 @@
#include "lib/zt_common.h"
#define COMP "zdsfs: "
+
#define METADATAFILE "metadata.txt"
/* defaults for file and directory permissions (octal) */
@@ -42,6 +45,10 @@
/* default timer interval 9 minutes, enq times out after 10 minutes */
#define DEFAULT_KEEPALIVE_SEC 540
+#define SECTION_ENTRIES 3
+static char CODEPAGE_EDF[] = "CP1047";
+static char CODEPAGE_LINUX[] = "UTF-8";
+
struct zdsfs_info {
int devcount;
int allow_inclomplete_multi_volume;
@@ -61,6 +68,12 @@ struct zdsfs_info {
int active_server;
char *server[MAX_SERVER];
long keepalive;
+ int codepage_convert;
+ char *codepage_from;
+ char *codepage_to;
+ iconv_t iconv;
+ struct util_list *dsclist;
+ char *dsfile;
};
static struct zdsfs_info zdsfsinfo;
@@ -82,6 +95,18 @@ struct zdsfs_file_info {
size_t metaread; /* how many bytes have already been read */
};
+struct dsconvert {
+ char *name;
+ char *codepage_from;
+ char *codepage_to;
+ bool keeprdw;
+};
+
+struct dsc_node {
+ struct util_list_node node;
+ struct dsconvert *dsc;
+};
+
/* Allocate and initialize a new list of struct dsh_node. */
static struct util_list *dshlist_alloc(void)
{
@@ -144,6 +169,65 @@ void dshlist_remove(struct util_list *list, struct dshandle *dsh)
}
}
+/* Allocate and initialize a new list of struct dsc_node. */
+static struct util_list *dsclist_alloc(void)
+{
+ struct util_list *list;
+
+ list = util_malloc(sizeof(struct util_list));
+ util_list_init(list, struct dsc_node, node);
+
+ return list;
+}
+
+/* free struct dsconvert. */
+static void dsc_free(struct dsconvert *dsc)
+{
+ free(dsc->name);
+ free(dsc->codepage_from);
+ free(dsc->codepage_to);
+ free(dsc);
+}
+
+/* free list of struct dsc_node. */
+static void dsclist_free(struct util_list *list)
+{
+ struct dsc_node *s, *n;
+
+ if (!list)
+ return;
+
+ util_list_iterate_safe(list, s, n) {
+ util_list_remove(list, s);
+ dsc_free(s->dsc);
+ free(s);
+ }
+
+ free(list);
+}
+
+/* add dsc to list */
+static void dsclist_add(struct util_list *list, struct dsconvert *dsc)
+{
+ struct dsc_node *s;
+
+ s = util_malloc(sizeof(struct dsc_node));
+ s->dsc = dsc;
+ util_list_add_tail(list, s);
+}
+
+/* Find a dsc_node by name. */
+static struct dsc_node *dsclist_find_by_name(struct util_list *list, char *name)
+{
+ struct dsc_node *s;
+
+ util_list_iterate(list, s) {
+ if (strcmp(s->dsc->name, name) == 0)
+ return s;
+ }
+
+ return NULL;
+}
/* normalize the given path name to a dataset name
* so that we can compare it to the names in the vtoc. This means:
@@ -176,6 +260,16 @@ static void path_to_member_name(const char *path, char *normds, size_t size)
}
}
+static int setup_iconv(iconv_t *conv, const char *from, const char *to)
+{
+ *conv = iconv_open(to, from);
+ if (*conv == ((iconv_t) -1)) {
+ fprintf(stderr, "error when setting up iconv\n");
+ return -1;
+ }
+ return 0;
+}
+
static void setup_timer(long sec)
{
static struct itimerval timer;
@@ -531,6 +625,102 @@ static int zdsfs_test_restserver(void)
return 0;
}
+/*
+ * check if a dsconvert entry exists that match the given DS name
+ * if the dsconvert entry ends in an asterisk only match the prefix
+ * otherwise look for an exact match
+ */
+static struct dsconvert *zdsfs_get_matching_dsc(char *name)
+{
+ struct dsconvert *dsc;
+ unsigned int length;
+ struct dsc_node *n;
+ char *match;
+
+ util_list_iterate(zdsfsinfo.dsclist, n) {
+ dsc = n->dsc;
+ match = dsc->name;
+ length = strlen(match);
+ if (strcmp(&match[length - 1], "*") == 0)
+ length--;
+ else if (strlen(name) != length)
+ continue;
+
+ if (strncmp(name, match, length) == 0)
+ return dsc;
+ }
+ return NULL;
+}
+
+/*
+ * Setup iconv conversion for a given dataset.
+ * The codepage settings can be obtained from (in descending priority)
+ * - globally set codepage settings
+ * - a dsconvert entry matching the DS name
+ * - default codepage settings.
+ */
+static int zdsfs_setup_conversion(struct dshandle *dsh, struct dataset *ds)
+{
+ struct dsconvert *dsc;
+ const char *from, *to;
+ struct errorlog *log;
+ iconv_t *iconv;
+ char *dsname;
+ int rc;
+
+ from = to = NULL;
+ lzds_dataset_get_name(ds, &dsname);
+ dsc = zdsfs_get_matching_dsc(dsname);
+ /* the DS matches a dsconvert entry */
+ if (dsc) {
+ from = dsc->codepage_from;
+ to = dsc->codepage_to;
+ }
+
+ /* globally set conversion overwriting possible config file settings */
+ if (zdsfsinfo.codepage_from && zdsfsinfo.codepage_to) {
+ from = zdsfsinfo.codepage_from;
+ to = zdsfsinfo.codepage_to;
+ }
+
+ /*
+ * globally set conversion using defaults
+ * if not specified otherwise already
+ */
+ if (zdsfsinfo.codepage_convert) {
+ if (!from)
+ from = CODEPAGE_EDF;
+ if (!to)
+ to = CODEPAGE_LINUX;
+ }
+
+ /* no conversion */
+ if (!from || !to)
+ return 0;
+
+ iconv = util_malloc(sizeof(*iconv));
+ rc = setup_iconv(iconv, from, to);
+ if (rc) {
+ fprintf(stderr, "Error when preparing iconv setting:\n");
+ lzds_dshandle_get_errorlog(dsh, &log);
+ lzds_errorlog_fprint(log, stderr);
+ rc = -rc;
+ goto out;
+ }
+ rc = lzds_dshandle_set_iconv(dsh, iconv);
+ if (rc) {
+ fprintf(stderr, "Error when setting iconv handle:\n");
+ lzds_dshandle_get_errorlog(dsh, &log);
+ lzds_errorlog_fprint(log, stderr);
+ rc = -rc;
+ goto out;
+ }
+ return 0;
+out:
+ free(iconv);
+ return rc;
+}
+
static int zdsfs_open(const char *path, struct fuse_file_info *fi)
{
@@ -620,6 +810,7 @@ static int zdsfs_open(const char *path, struct fuse_file_info *fi)
rc = -rc;
goto error2;
}
+ zdsfs_setup_conversion(dsh, ds);
retry:
if (zdsfsinfo.restapi && zdsfsinfo.active_server >= 0) {
@@ -660,7 +851,6 @@ error2:
error1:
free(zfi);
return rc;
-
}
static int zdsfs_release(const char *UNUSED(path), struct fuse_file_info *fi)
@@ -1012,7 +1202,10 @@ enum {
KEY_TRACKS,
KEY_SEEKBUFFER,
KEY_CONFIG,
+ KEY_DSCONFIG,
KEY_SERVER,
+ KEY_CODE_FROM,
+ KEY_CODE_TO,
};
#define ZDSFS_OPT(t, p, v) { t, offsetof(struct zdsfs_info, p), v }
@@ -1026,11 +1219,15 @@ static const struct fuse_opt zdsfs_opts[] = {
FUSE_OPT_KEY("tracks=", KEY_TRACKS),
FUSE_OPT_KEY("seekbuffer=", KEY_SEEKBUFFER),
FUSE_OPT_KEY("-c %s", KEY_CONFIG),
+ FUSE_OPT_KEY("-x %s", KEY_DSCONFIG),
FUSE_OPT_KEY("restserver=", KEY_SERVER),
+ FUSE_OPT_KEY("codepage_from=", KEY_CODE_FROM),
+ FUSE_OPT_KEY("codepage_to=", KEY_CODE_TO),
ZDSFS_OPT("rdw", keepRDW, 1),
ZDSFS_OPT("ignore_incomplete", allow_inclomplete_multi_volume, 1),
ZDSFS_OPT("check_host_count", host_count, 1),
ZDSFS_OPT("restapi", restapi, 1),
+ ZDSFS_OPT("codepage_convert", codepage_convert, 1),
FUSE_OPT_END
};
@@ -1052,6 +1249,8 @@ static void usage(const char *progname)
" nodes\n"
" -c config_file Text file that contains configuration options\n"
" for zdsfs\n"
+" -x ds_config_file Text file that contains conversion options\n"
+" for specific datasets\n"
" -o rdw Keep record descriptor words in byte stream\n"
" -o ignore_incomplete Continue processing even if parts of a multi"
" volume\n"
@@ -1065,6 +1264,10 @@ static void usage(const char *progname)
" access to datasets\n"
" -o restserver=URL The URL of the z/OSMF REST server to be used for\n"
" coordinated access to datasets\n"
+" -o codepage_convert Enable codepage conversion using default codepages\n"
+" from 'CP1047' to 'UTF-8'\n"
+" -o codepage_from=from Set codepage for source. See 'iconv -l' for a list\n"
+" -o codepage_to=to Set codepage for target. See 'iconv -l' for a list\n"
, progname);
}
@@ -1167,7 +1370,7 @@ static void zdsfs_process_device_file(const char *devfile)
void remove_whitespace(const char *s, char *t)
{
while (*s != '\0') {
- if (!isspace(*s)) {
+ if (!isblank(*s)) {
*t = *s;
t++;
}
@@ -1176,7 +1379,6 @@ void remove_whitespace(const char *s, char *t)
*t = '\0';
}
-
static void zdsfs_process_config_file(const char *config)
{
char line[MAX_LINE_LENGTH];
@@ -1198,7 +1400,7 @@ static void zdsfs_process_config_file(const char *config)
continue;
/* remove all whitespaces */
- tmp = util_malloc(strlen(line));
+ tmp = util_malloc(strlen(line) + 1);
remove_whitespace(line, tmp);
key = strtok(tmp, delimiter);
@@ -1225,6 +1427,163 @@ static void zdsfs_process_config_file(const char *config)
fclose(fd);
}
+static struct dsconvert *zdsfs_allocate_dsc(char *name, const char *config)
+{
+ struct dsconvert *dsc;
+
+ /* check for duplicate entries */
+ if (dsclist_find_by_name(zdsfsinfo.dsclist, name)) {
+ fprintf(stderr,
+ "Error in config file %s. Duplicate entry found: %s\n",
+ config, name);
+ return NULL;
+ }
+ dsc = util_zalloc(sizeof(*dsc));
+ dsc->name = util_strdup(name);
+
+ return dsc;
+}
+
+static int zdsfs_check_codepage_setting(char *from, char *to)
+{
+ iconv_t iconv;
+
+ /* no conversion is OK */
+ if (!from && !to)
+ return 0;
+
+ /* partial setup is not OK */
+ if ((from && !to) || (to && !from))
+ return 1;
+
+ /* return if the codepages are valid */
+ return setup_iconv(&iconv, from, to);
+}
+
+/*
+ * process a dataset configuration file that specifies conversion on a per dataset basis
+ *
+ * expect a section title each 3 lines
+ * the section should contain a rdw= and conv= line
+ * valid values for rdw= are 0/1
+ * valid values for conv= are 0/1 or a comma separated list
+ * of codepage_from and codepage_to arguments
+ */
+static int zdsfs_process_dataset_conf(const char *config)
+{
+ char line[MAX_LINE_LENGTH];
+ char delimiter[] = " =#\n";
+ char *tmp, *key, *value;
+ int linecount, in_section;
+ unsigned long enabled;
+ struct dsconvert *dsc;
+ int rc = 1;
+ FILE *fd;
+
+ fd = fopen(config, "r");
+ if (!fd) {
+ fprintf(stderr, "could not open file %s: %s\n",
+ config, strerror(errno));
+ return 0;
+ }
+ in_section = 0;
+ linecount = 0;
+ dsc = NULL;
+ tmp = NULL;
+ while (fgets(line, sizeof(line), fd)) {
+ linecount++;
+ /* remove all whitespaces */
+ tmp = util_malloc(strlen(line) + 1);
+ remove_whitespace(line, tmp);
+ /* skip empty lines */
+ if (*tmp == '\n' || *tmp == '#') {
+ free(tmp);
+ tmp = NULL;
+ continue;
+ }
+ if (!in_section) {
+ /* the section title should not contain a '=' */
+ if (strchr(line, '=') != NULL) {
+ fprintf(stderr,
+ "Error in config file %s line %d. Expected section title instead of %s\n",
+ config, linecount, line);
+ goto out;
+ }
+ }
+ key = strtok(tmp, delimiter);
+ if (!in_section) {
+ dsc = zdsfs_allocate_dsc(key, config);
+ if (!dsc)
+ goto out;
+ in_section = SECTION_ENTRIES;
+ } else if (strcmp(key, "rdw") == 0) {
+ value = strtok(NULL, delimiter);
+ enabled = strtoul(value, NULL, 0);
+ if (enabled == 1)
+ dsc->keeprdw = true;
+ else
+ dsc->keeprdw = false;
+ } else if (strcmp(key, "conv") == 0) {
+ value = strtok(NULL, delimiter);
+ if (strchr(value, ',') != NULL) {
+ /* use provided codepages */
+ value = strtok(value, ",");
+ dsc->codepage_from = util_strdup(value);
+ value = strtok(NULL, delimiter);
+ dsc->codepage_to = util_strdup(value);
+ } else if (strcmp(value, "1") == 0) {
+ /* use default codepages */
+ dsc->codepage_from = CODEPAGE_EDF;
+ dsc->codepage_to = CODEPAGE_LINUX;
+ } else if (strcmp(value, "0") == 0) {
+ /* disable conversion */
+ dsc->codepage_from = NULL;
+ dsc->codepage_to = NULL;
+ } else {
+ fprintf(stderr,
+ "Error in config file %s line %d. Invalid 'conv' statement: %s.\n",
+ config, linecount, value);
+ goto out;
+ }
+ } else {
+ fprintf(stderr,
+ "Error in config file %s line %d. Missing 'rdw' or 'conv' statement.\n",
+ config, linecount);
+ goto out;
+ }
+ in_section--;
+ /* if the section was parsed completely, add the dsc to the list */
+ if (!in_section) {
+ if (zdsfs_check_codepage_setting(dsc->codepage_from,
+ dsc->codepage_to)) {
+ fprintf(stderr,
+ "Error in config file %s. Invalid codepage setting: %s %s.\n",
+ config, dsc->codepage_from,
+ dsc->codepage_to);
+ goto out;
+ }
+ dsclist_add(zdsfsinfo.dsclist, dsc);
+ dsc = NULL;
+ }
+ free(tmp);
+ tmp = NULL;
+ }
+ /* find incomplete last section */
+ if (in_section)
+ fprintf(stderr,
+ "Error in config file %s. Missing 'rdw' or 'conv' statement.\n",
+ config);
+ else
+ rc = 0;
+
+out:
+ fclose(fd);
+ free(tmp);
+ dsc_free(dsc);
+
+ return rc;
+}
+
static int zdsfs_process_args(void *UNUSED(data), const char *arg, int key,
struct fuse_args *outargs)
{
@@ -1313,6 +1672,10 @@ static int zdsfs_process_args(void *UNUSED(data), const char *arg, int key,
/* note that arg starts with "-c" */
zdsfsinfo.configfile = util_strdup(arg + 2);
return 0;
+ case KEY_DSCONFIG:
+ /* note that arg starts with "-x" */
+ zdsfsinfo.dsfile = util_strdup(arg + 2);
+ return 0;
case KEY_SERVER:
if (zdsfsinfo.nr_server >= MAX_SERVER)
return 0;
@@ -1321,6 +1684,16 @@ static int zdsfs_process_args(void *UNUSED(data), const char *arg, int key,
util_strdup(value);
zdsfsinfo.nr_server++;
return 0;
+ case KEY_CODE_FROM:
+ value = arg + strlen("codepage_from=");
+ zdsfsinfo.codepage_from =
+ util_strdup(value);
+ return 0;
+ case KEY_CODE_TO:
+ value = arg + strlen("codepage_to=");
+ zdsfsinfo.codepage_to =
+ util_strdup(value);
+ return 0;
default:
fprintf(stderr, "Unknown argument key %x\n", key);
exit(1);
@@ -1340,11 +1713,14 @@ int main(int argc, char *argv[])
zdsfsinfo.tracks_per_frame = 128;
zdsfsinfo.seek_buffer_size = 1048576;
zdsfsinfo.configfile = "/etc/zdsfs.conf";
+ zdsfsinfo.dsfile = "/etc/zdsfs-dataset.conf";
zdsfsinfo.keepalive = DEFAULT_KEEPALIVE_SEC;
zdsfsinfo.active_server = -1;
rc = lzds_zdsroot_alloc(&zdsfsinfo.zdsroot);
open_dsh = dshlist_alloc();
+ zdsfsinfo.dsclist = dsclist_alloc();
+
if (rc) {
fprintf(stderr, "Could not allocate internal structures\n");
exit(1);
@@ -1354,8 +1730,19 @@ int main(int argc, char *argv[])
fprintf(stderr, "Failed to parse option\n");
exit(1);
}
+ if (zdsfs_check_codepage_setting(zdsfsinfo.codepage_from,
+ zdsfsinfo.codepage_to)) {
+ fprintf(stderr, "Ivalid codepage setting from '%s' to '%s'\n",
+ zdsfsinfo.codepage_from,
+ zdsfsinfo.codepage_to);
+ rc = -EINVAL;
+ goto cleanup;
+ }
zdsfs_process_config_file(zdsfsinfo.configfile);
-
+ if (zdsfs_process_dataset_conf(zdsfsinfo.dsfile)) {
+ rc = -EACCES;
+ goto cleanup;
+ }
if (!zdsfsinfo.devcount) {
fprintf(stderr, "Please specify a block device\n");
fprintf(stderr, "Try '%s --help' for more information\n",
@@ -1390,12 +1777,12 @@ int main(int argc, char *argv[])
goto cleanup;
}
}
-
rc = fuse_main(args.argc, args.argv, &rdf_oper, NULL);
cleanup:
curl_global_cleanup();
dshlist_free(open_dsh);
+ dsclist_free(zdsfsinfo.dsclist);
lzds_zdsroot_free(zdsfsinfo.zdsroot);
fuse_opt_free_args(&args);
--
2.31.1
From 994e280ae9292821f77d49138f0f17827965e5a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
Date: Fri, 2 Jul 2021 11:49:28 +0200
Subject: [PATCH 5/7] dasd: change default scheduler to reduce CPU consumption
(#1972038)
Description: dasd: change default scheduler to reduce CPU consumption
Symptom: CPU consumption up to 20% higher for mq-deadline
compared to none scheduler for DASD devices with no
difference in throughput.
Problem: Performance analysis showed that with recent DASD
device drivers using multi-queue block queuing the
throughput of mq-deadline and none scheduler is nearly
identical but the CPU consumption of mq-deadline
scheduler due to its optimizations is up to 20% higher
compared to none scheduler.
Solution: Set none scheduler as default in the DASD udev rule.
Reproduction: Use DASD devices with mq-deadline scheduler.
Upstream-ID: a65bc51cf4e5c1fe628bb182cc1a02ee83eb102d
Problem-ID: 192049
---
etc/udev/rules.d/59-dasd.rules | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/etc/udev/rules.d/59-dasd.rules b/etc/udev/rules.d/59-dasd.rules
index 98fbd18..06c1bf2 100644
--- a/etc/udev/rules.d/59-dasd.rules
+++ b/etc/udev/rules.d/59-dasd.rules
@@ -26,10 +26,10 @@ KERNEL=="dasd*[0-9]", ENV{ID_XUID}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env
LABEL="dasd_symlinks_end"
-# on device add set request queue scheduler to deadline
+# on device add set request queue scheduler to none
SUBSYSTEM!="block", GOTO="sched_end"
ACTION!="change", GOTO="sched_end"
-KERNEL=="dasd*[!0-9]", TEST=="queue/scheduler", ATTR{queue/scheduler}="deadline"
+KERNEL=="dasd*[!0-9]", TEST=="queue/scheduler", ATTR{queue/scheduler}="none"
LABEL="sched_end"
--
2.31.1
From 6141192f0487ce450106dfc32a8d6f3d7a89908b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
Date: Fri, 2 Jul 2021 11:50:35 +0200
Subject: [PATCH 6/7] dbginfo.sh: Collect /proc/kallsyms, issue additional
commands (#1972041)
Description: dbginfo.sh: Collect /proc/kallsyms, issue additional commands
Symptom: - Required data gets not collected during run of dbginfo.sh
- vmcp q cache command always fails
Problem: - some commands yet missing in dbginfo.sh script
- command vmcp q cache is missing a mandatory parameter
Solution: Stop to issue a vmcp q cache command (fails always) and add
- collect /proc/kallsyms as a tgz file (because of huge size)
- lscpu -ye
- vmcp q memassist
- vmcp q pcifunction
- vmcp q vmrelocate
Reproduction: Run the dbginfo.sh and check for results in DBGINFOxxx.tgz file
- /proc/kallsyms
- zvm_runtime.out
- runtime.out
Upstream-ID: eb1fd47a85c93ec247d89a4d02b0a5a2c5a8d444
Problem-ID: 192022
---
scripts/dbginfo.sh | 32 +++++++++++++++++++++++++++-----
scripts/dbginfo.sh.1 | 8 ++++----
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/scripts/dbginfo.sh b/scripts/dbginfo.sh
index 705b5f0..405dcb3 100755
--- a/scripts/dbginfo.sh
+++ b/scripts/dbginfo.sh
@@ -2,7 +2,7 @@
#
# dbginfo.sh - Tool to collect runtime, configuration, and trace information
#
-# Copyright IBM Corp. 2002, 2020
+# Copyright IBM Corp. 2002, 2021
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
@@ -21,7 +21,7 @@ readonly SCRIPTNAME="${0##*/}"
print_version() {
cat <<EOF
${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
-Copyright IBM Corp. 2002, 2020
+Copyright IBM Corp. 2002, 2021
EOF
}
@@ -37,8 +37,8 @@ print_usage()
Usage: ${SCRIPTNAME} [OPTIONS]
-This script collects runtime, configuration and trace information about
-your Linux on System z installation for debugging purposes.
+This script collects runtime, configuration and trace information on
+a Linux on IBM Z installation for debugging purposes.
It also traces information about z/VM if the Linux runs under z/VM.
@@ -253,6 +253,7 @@ PROCFILES="\
/proc/driver/z90crypt\
/proc/interrupts\
/proc/iomem\
+ /proc/kallsyms\
/proc/mdstat\
/proc/meminfo\
/proc/misc\
@@ -435,6 +436,7 @@ CMDS="uname -a\
:lschp\
:lscss\
:lscpu -ae\
+ :lscpu -ye\
:lsmem\
:lsdasd\
:lsdasd -u\
@@ -532,7 +534,7 @@ VM_CMDS="q userid\
:q lan\
:q lan all details\
:q lan all access\
- :q cache\
+ :q memassist\
:q nic\
:q pav\
:q proc\
@@ -549,6 +551,8 @@ VM_CMDS="q userid\
:q dumpdev\
:q reorder VMUSERID\
:q quickdsp VMUSERID\
+ :q pcifunction\
+ :q vmrelocate\
:ind load\
:ind sp\
:ind user\
@@ -1008,6 +1012,22 @@ post_processing() {
touch --time=mtime -t "${file_mtime}" "${file_name}"
done
+ find "${WORKPATH}proc/" -name "kallsyms" 2>/dev/null | while IFS= read -r file_name; do
+ tmp_file=${file_name}-`uname -r`.tgz
+ ch_dir="${WORKPATH}proc/"
+ orig_file="kallsyms"
+
+
+ echo " ${file_name}"
+ if ! test -e "${file_name}"; then
+ echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}"
+ echo
+ fi
+
+ tar -cvzf "${tmp_file}" -C "${ch_dir}" "${orig_file}"
+ rm -f "${file_name}"
+
+ done
pr_log_stdout " "
}
@@ -1124,6 +1144,8 @@ create_package()
pr_stdout "Finalizing: Creating archive with collected data"
cd "${WORKDIR_BASE}"
+ touch "${WORKARCHIVE}"
+ chmod 0600 "${WORKARCHIVE}"
tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"
rc_tar=$?
if [ $rc_tar -eq 0 ]; then
diff --git a/scripts/dbginfo.sh.1 b/scripts/dbginfo.sh.1
index ef9fe89..a59e4c0 100644
--- a/scripts/dbginfo.sh.1
+++ b/scripts/dbginfo.sh.1
@@ -2,7 +2,7 @@
.SH NAME
dbginfo.sh \- collect runtime, configuration and trace information
-for debugging Linux on System z
+for debugging Linux on IBM Z
.SH SYNOPSIS
.br
@@ -12,7 +12,7 @@ for debugging Linux on System z
.SH DESCRIPTION
This script collects runtime, configuration and trace information that can
-be used to debug a Linux on System z instance.
+be used to debug a Linux on IBM Z instance.
For Linux on z/VM, the script also traces information about the z/VM system.
The debug information is written to a file
/tmp/DBGINFO\-<date>\-<time>\-<hostname>\-<processorid>.tgz
@@ -52,7 +52,7 @@ Sample invocation:
.br
dbginfo.sh: Debug information script version %S390_TOOLS_VERSION%
.br
-Copyright IBM Corp. 2002, 2019
+Copyright IBM Corp. 2002, 2021
.PP
Hardware platform = s390x
.br
@@ -104,4 +104,4 @@ Run the script with root authority.
For Linux on z/VM, only z/VM guest virtual machines with class B privileges
yield the complete debug information.
.SH AUTHOR
-Linux on System z development <linux390@de.ibm.com>
+Linux on IBM Z development <linux390@de.ibm.com>
--
2.31.1
From 29f70132b4ce9ee59f1b34f77172cf966d574808 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
Date: Tue, 20 Jul 2021 10:58:42 +0200
Subject: [PATCH 7/7] s390-tools: Add support for complete counter set
extraction
Summary: s390-tools: Add support for complete counter set extraction
Description: cpumf/lshwc: Program to extract complete counter sets
Program reads complete counter sets from any CPU by opening
device /dev/hwctr.
The counter sets and CPUs can be specified on the command line.
Upstream-ID: 27a562da0ad55032649e0258205d208c07db16ca
---
cpumf/Makefile | 5 +-
cpumf/lshwc.c | 775 ++++++++++++++++++++++++++++++++++++++++++++++
cpumf/lshwc.h | 92 ++++++
cpumf/man/lshwc.1 | 134 ++++++++
4 files changed, 1004 insertions(+), 2 deletions(-)
create mode 100644 cpumf/lshwc.c
create mode 100644 cpumf/lshwc.h
create mode 100644 cpumf/man/lshwc.1
diff --git a/cpumf/Makefile b/cpumf/Makefile
index ecb3515..78612e7 100644
--- a/cpumf/Makefile
+++ b/cpumf/Makefile
@@ -1,7 +1,7 @@
include ../common.mak
-BIN_FILES = lscpumf chcpumf
-MAN_FILES = lscpumf.1 chcpumf.8
+BIN_FILES = lscpumf chcpumf lshwc
+MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
all: $(BIN_FILES)
@@ -9,6 +9,7 @@ libs = $(rootdir)/libutil/libutil.a
lscpumf: lscpumf.o $(libs)
chcpumf: chcpumf.o $(libs)
+lshwc: lshwc.o $(libs)
install: all install-man
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
diff --git a/cpumf/lshwc.c b/cpumf/lshwc.c
new file mode 100644
index 0000000..39c9fbe
--- /dev/null
+++ b/cpumf/lshwc.c
@@ -0,0 +1,775 @@
+/* Copyright IBM Corp. 2021
+ *
+ * s390-tools is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+/* CPU Measurements counter facility counter sets can be extracted by a
+ * device driver accessible by opening device /dev/hwctr.
+ * This program extracts complete counter set using this device.
+ * Counter sets are per CPU, the interface allows to specify counter sets
+ * for individual CPUs. The supported flags are executed from left to
+ * right, the first error encountered stops the execution of the program.
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/user.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "lib/util_opt.h"
+#include "lib/util_prg.h"
+#include "lib/util_base.h"
+#include "lib/util_path.h"
+#include "lib/util_scandir.h"
+#include "lib/util_libc.h"
+
+#include "lshwc.h"
+
+#define SERVICELEVEL "/proc/service_levels"
+#define CPUS_ONLINE "/sys/devices/system/cpu/online"
+#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
+#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
+#define MAXCTRS 512
+
+static const unsigned int ioctlsleep = 60;
+static unsigned int read_interval = ioctlsleep, cfvn, csvn, authorization;
+static unsigned long loop_count = 1;
+static unsigned char *ioctlbuffer;
+static bool allcpu;
+
+static unsigned int max_possible_cpus; /* No of possible CPUs */
+struct ctrname { /* List of defined counters */
+ char *name; /* Counter name */
+ bool hitcnt; /* Counter number read from ioctl() */
+ unsigned long total; /* Total counter value */
+ unsigned long *ccv; /* Per CPU counter value */
+} ctrname[MAXCTRS];
+
+/* Open file and extract counter number */
+static int read_counter(const char *p)
+{
+ FILE *fp = fopen(p, "r");
+ int rc = 0, ctr;
+
+ if (fp) {
+ rc = fscanf(fp, "event=%x", &ctr);
+ fclose(fp);
+ }
+ return rc == 1 ? ctr : -EINVAL;
+}
+
+static int add_countername(char *name, int nr)
+{
+ ctrname[nr].name = strdup(name);
+ return ctrname[nr].name ? 0 : -ENOMEM;
+}
+
+static bool read_counternames(void)
+{
+ struct dirent **namelist = NULL;
+ int i, ctr = 0, count = 0;
+ char *path, *ctrpath;
+
+ path = util_path_sysfs("/bus/event_source/devices/cpum_cf/events/");
+ count = util_scandir(&namelist, alphasort, path, "[^.]");
+ if (count <= 0) {
+ warnx("Cannot open %s", path);
+ free(path);
+ return false;
+ }
+ for (i = 0; i < count && ctr >= 0; i++) {
+ util_asprintf(&ctrpath, "%s/%s", path, namelist[i]->d_name);
+ ctr = read_counter(ctrpath);
+ free(ctrpath);
+ if (ctr >= 0)
+ ctr = add_countername(namelist[i]->d_name, ctr);
+ }
+ if (ctr < 0)
+ warnx("Cannot parse %s", path);
+ util_scandir_free(namelist, count);
+ free(path);
+ return ctr < 0 ? false : true;
+}
+
+static void free_counternames(void)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
+ free(ctrname[i].name);
+ free(ctrname[i].ccv);
+ }
+}
+
+static struct check_result {
+ bool cpu_pos; /* CPU Number possible */
+ bool cpu_req; /* CPU Number requested */
+ bool cpu_hit; /* CPU Number received */
+ unsigned char sets_req; /* Counters sets requested */
+ unsigned char sets_hit; /* Counters sets received */
+} *check;
+
+static bool check_set(unsigned long a, unsigned long b, unsigned long sets)
+{
+ if (a > b)
+ return false;
+ for (; a <= b; ++a) {
+ if (a >= max_possible_cpus || !check[a].cpu_pos)
+ return false;
+ check[a].cpu_req = true;
+ check[a].sets_req = sets;
+ }
+ return true;
+}
+
+/*
+ * Functions to parse command line parameters
+ * Convert a number from ascii to int.
+ */
+static unsigned long getnumber(char *word, char stopchar)
+{
+ unsigned long no;
+ char *endp;
+
+ no = strtoul(word, &endp, 0);
+ if (*endp != stopchar)
+ errx(EXIT_FAILURE, "Invalid parameter %s", word);
+ return no;
+}
+
+/* Remove all whitespace from string. */
+static void kill_whitespace(char *s)
+{
+ char *cp = s;
+
+ for (; *s != '\0'; ++s) {
+ if (isspace(*s))
+ continue;
+ if (isprint(*s))
+ *cp++ = *s;
+ }
+ *cp = '\0';
+}
+
+/* Read file to get all online CPUs */
+static bool get_cpus(char *file, char *buf, size_t bufsz)
+{
+ char fmt[16];
+ FILE *slp;
+ int rc;
+
+ slp = fopen(file, "r");
+ if (!slp) {
+ warnx("Cannot open %s", file);
+ return false;
+ }
+ snprintf(fmt, sizeof(fmt), "%%%zus", bufsz - 1);
+ rc = fscanf(slp, fmt, buf);
+ fclose(slp);
+ if (rc != 1)
+ warnx("Cannot parse %s", file);
+ return rc == 1 ? true : false;
+}
+
+/* Parse counter set specification */
+static unsigned long parse_ctrset(char *cp)
+{
+ unsigned long x = 0;
+
+ for (; *cp; ++cp) {
+ switch (tolower(*cp)) {
+ case 'b':
+ x |= S390_HWCTR_BASIC;
+ break;
+ case 'c':
+ x |= S390_HWCTR_CRYPTO;
+ break;
+ case 'e':
+ x |= S390_HWCTR_EXT;
+ break;
+ case 'm':
+ x |= S390_HWCTR_MT_DIAG;
+ break;
+ case 'p':
+ case 'u':
+ x |= S390_HWCTR_USER;
+ break;
+ case 'a':
+ x |= S390_HWCTR_ALL;
+ break;
+ default:
+ errx(EXIT_FAILURE,
+ "Invalid counter set specification '%c'", *cp);
+ }
+ }
+ return x;
+}
+
+static char *show_ctrset(unsigned long set)
+{
+ static char text[16];
+ int i = 0;
+
+ if (set & S390_HWCTR_BASIC)
+ text[i++] = 'B';
+ if (set & S390_HWCTR_CRYPTO)
+ text[i++] = 'C';
+ if (set & S390_HWCTR_EXT)
+ text[i++] = 'E';
+ if (set & S390_HWCTR_MT_DIAG)
+ text[i++] = 'M';
+ if (set & S390_HWCTR_USER)
+ text[i++] = 'U';
+ text[i] = '\0';
+ return text;
+}
+
+/* Parse CPU list and counter sets */
+static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
+{
+ __u64 *words = start->cpumask;
+ unsigned long i, no_a, no_b;
+ char *cp, *tokens[16]; /* Used to parse command line params */
+ char cpubuf[256];
+
+ start->data_bytes = 0;
+ if (parm)
+ kill_whitespace(parm);
+ if (!parm || *parm == ':') {
+ /* No CPU list or just counter sets */
+ if (!get_cpus(CPUS_ONLINE, cpubuf, sizeof(cpubuf)))
+ exit(EXIT_FAILURE);
+ if (parm)
+ strcat(cpubuf, parm);
+ parm = cpubuf;
+ }
+
+ cp = strchr(parm, ':');
+ if (cp) { /* Handle counter set */
+ *cp = '\0';
+ start->counter_sets = parse_ctrset(++cp);
+ } else {
+ start->counter_sets = S390_HWCTR_ALL;
+ }
+ /* Check with authorized counter sets */
+ if ((start->counter_sets & authorization) != start->counter_sets) {
+ unsigned int noton = ~(start->counter_sets & authorization);
+
+ start->counter_sets &= authorization;
+ if (!start->counter_sets)
+ errx(EXIT_FAILURE, "No counter sets are authorized");
+ warnx("One or more counter sets are not authorized: %s",
+ show_ctrset(noton));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ",")) != 0;
+ ++i, parm = 0) {
+ cp = strchr(tokens[i], '-'); /* Range character? */
+ if (cp) {
+ no_a = getnumber(tokens[i], *cp);
+ no_b = getnumber(++cp, '\0');
+ } else {
+ no_b = getnumber(tokens[i], '\0');
+ no_a = no_b;
+ }
+ if (!check_set(no_a, no_b, start->counter_sets))
+ errx(EXIT_FAILURE, "Invalid CPU list %s", tokens[i]);
+ }
+
+ /* Convert the CPU list to a bitmask for kernel cpumask_t */
+ for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
+ if (check[i].cpu_req) {
+ no_a = i % __BITS_PER_LONG;
+ no_b = i / __BITS_PER_LONG;
+ words[no_b] |= 1ULL << no_a;
+ }
+ }
+ /* no_b is highest used index, swap array */
+ start->cpumask_len = (no_b + 1) * 8;
+ for (no_a = 0; no_a < no_b; ++no_a, --no_b) {
+ __u64 tmp = words[no_a];
+
+ words[no_a] = words[no_b];
+ words[no_b] = tmp;
+ }
+ start->version = S390_HWCTR_START_VERSION;
+}
+
+static bool check_setpossible(void)
+{
+ char *cp, *parm, *tokens[16]; /* Used to parse command line params */
+ unsigned long i, no_a, no_b;
+ char cpubuf[1024];
+
+ if (!get_cpus(CPUS_KERNELMAX, cpubuf, sizeof(cpubuf)))
+ return false;
+ max_possible_cpus = getnumber(cpubuf, '\0') + 1;
+ check = calloc(max_possible_cpus, sizeof(*check));
+ if (!check)
+ err(EXIT_FAILURE, "Maximum CPUs %u", max_possible_cpus);
+ if (!get_cpus(CPUS_POSSIBLE, cpubuf, sizeof(cpubuf))) {
+ free(check);
+ return false;
+ }
+ parm = cpubuf;
+ for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
+ ++i, parm = 0) {
+ cp = strchr(tokens[i], '-');
+ if (cp) { /* Range */
+ no_a = getnumber(tokens[i], *cp);
+ no_b = getnumber(++cp, '\0');
+ } else {
+ no_b = getnumber(tokens[i], '\0');
+ no_a = no_b;
+ }
+ for (; no_a <= no_b; ++no_a)
+ check[no_a].cpu_pos = true;
+ }
+ return true;
+}
+
+static void show_header(void)
+{
+ static bool header;
+ bool comma = false;
+
+ if (header)
+ return; /* Printed already */
+ printf("Date,Time,CPU,"); /* Print counter name and number */
+ for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
+ if (!ctrname[i].hitcnt)
+ continue;
+ if (comma)
+ putchar(',');
+ printf("%s(%ld)", ctrname[i].name ?: "Counter", i);
+ comma = true;
+ }
+ putchar('\n');
+ header = true;
+}
+
+static void line(char *header)
+{
+ bool comma;
+
+ show_header();
+ if (allcpu) {
+ for (unsigned int h = 0; h < max_possible_cpus; ++h) {
+ char txt[16];
+
+ if (!check[h].cpu_hit)
+ continue;
+ comma = false;
+ snprintf(txt, sizeof(txt), "CPU%d,", h);
+ printf("%s%s", header, txt);
+ for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
+ if (!ctrname[i].hitcnt)
+ continue;
+ if (comma)
+ putchar(',');
+ printf("%ld", ctrname[i].ccv[h]);
+ comma = true;
+ }
+ putchar('\n');
+ }
+ }
+
+ /* Print total count of all CPUs */
+ printf("%sTotal,", header);
+ comma = false;
+ for (size_t i = 0; i < ARRAY_SIZE(ctrname); ++i) {
+ if (!ctrname[i].hitcnt)
+ continue;
+ if (comma)
+ putchar(',');
+ printf("%ld", ctrname[i].total);
+ comma = true;
+ }
+ putchar('\n');
+}
+
+static void show(void)
+{
+ time_t now = time(NULL);
+ struct tm *now_tm;
+ char now_text[32];
+
+ now_tm = localtime(&now);
+ strftime(now_text, sizeof(now_text), "%F,%T,", now_tm);
+ line(now_text);
+}
+
+/* Return Counter set size numbers (in counters) */
+static unsigned int ctrset_size(int set)
+{
+ switch (set) {
+ case S390_HWCTR_BASIC:
+ return 6;
+ case S390_HWCTR_USER:
+ return (cfvn == 1) ? 6 : 2;
+ case S390_HWCTR_CRYPTO:
+ return (csvn <= 5) ? 16 : 20;
+ case S390_HWCTR_EXT:
+ switch (csvn) {
+ case 1: return 32;
+ case 2: return 48;
+ case 3:
+ case 4:
+ case 5: return 128;
+ }
+ return 160;
+ case S390_HWCTR_MT_DIAG:
+ switch (csvn) {
+ case 1:
+ case 2:
+ case 3: return 0;
+ }
+ return 48;
+ }
+ return 0;
+}
+
+/* Return counter set offset numbers */
+static int ctrset_offset(int set)
+{
+ switch (set) {
+ case S390_HWCTR_BASIC:
+ return 0;
+ case S390_HWCTR_USER:
+ return 32;
+ case S390_HWCTR_CRYPTO:
+ return 64;
+ case S390_HWCTR_EXT:
+ return 128;
+ case S390_HWCTR_MT_DIAG:
+ return 448;
+ }
+ return 0;
+}
+
+static bool set_and_size_ok(struct s390_hwctr_setdata *p)
+{
+ switch (p->set) {
+ case S390_HWCTR_BASIC:
+ case S390_HWCTR_USER:
+ case S390_HWCTR_CRYPTO:
+ case S390_HWCTR_EXT:
+ case S390_HWCTR_MT_DIAG:
+ return p->no_cnts == ctrset_size(p->set);
+ }
+ return false;
+}
+
+static bool add_countervalue(size_t idx, unsigned int cpu, unsigned long value)
+{
+ if (idx >= ARRAY_SIZE(ctrname)) {
+ warnx("Invalid counter number %zu", idx);
+ return false;
+ }
+ if (cpu >= max_possible_cpus) {
+ warnx("Invalid CPU number %d", cpu);
+ return false;
+ }
+ if (!ctrname[idx].ccv) /* Unknown counter */
+ ctrname[idx].ccv = calloc(max_possible_cpus,
+ sizeof(unsigned long));
+ if (ctrname[idx].ccv)
+ ctrname[idx].ccv[cpu] += value;
+ ctrname[idx].total += value;
+ ctrname[idx].hitcnt = true;
+ return true;
+}
+
+static int test_read(struct s390_hwctr_read *read)
+{
+ void *base = &read->data;
+ size_t offset = 0;
+
+ /* Clear previous hit counters */
+ for (unsigned int i = 0; i < max_possible_cpus; ++i) {
+ check[i].sets_hit = 0;
+ check[i].cpu_hit = false;
+ }
+
+ /* Iterate over all CPUs */
+ for (unsigned int i = 0; i < read->no_cpus; ++i) {
+ struct s390_hwctr_cpudata *cp = base + offset;
+
+ check[cp->cpu_nr].cpu_hit = true;
+ check[cp->cpu_nr].sets_hit = 0;
+
+ offset += sizeof(cp->cpu_nr) + sizeof(cp->no_sets);
+ /* Iterate over all counter sets */
+ for (unsigned int j = 0; j < cp->no_sets; ++j) {
+ struct s390_hwctr_setdata *sp = base + offset;
+
+ check[cp->cpu_nr].sets_hit |= sp->set;
+ offset += sizeof(sp->set) + sizeof(sp->no_cnts);
+ if (!set_and_size_ok(sp)) {
+ warnx("CPU %d inconsistent set %d size %d",
+ cp->cpu_nr, sp->set, sp->no_cnts);
+ return -1;
+ }
+ /* Iterate over all counters in each set */
+ for (unsigned int k = 0; k < sp->no_cnts; ++k) {
+ __u64 value;
+ void *addr = base + offset;
+ size_t idx = ctrset_offset(sp->set) + k;
+
+ memcpy(&value, addr, sizeof(value));
+ offset += sizeof(value);
+ if (!add_countervalue(idx, cp->cpu_nr, value))
+ return -1;
+ }
+ }
+ }
+ show();
+ return 0;
+}
+
+static int do_open(void)
+{
+ int fd = open(S390_HWCTR_DEVICE, O_RDWR);
+
+ if (fd < 0)
+ warn(S390_HWCTR_DEVICE);
+ return fd;
+}
+
+static int do_stop(int ioctlfd)
+{
+ int rc = ioctl(ioctlfd, S390_HWCTR_STOP, 0);
+
+ if (rc < 0)
+ warn("ioctl S390_HWCTR_STOP");
+ return rc;
+}
+
+static int do_start(int ioctlfd, struct s390_hwctr_start *start)
+{
+ int rc = ioctl(ioctlfd, S390_HWCTR_START, start);
+
+ if (rc < 0)
+ warn("ioctl S390_HWCTR_START");
+ return rc;
+}
+
+static int do_read(int ioctlfd)
+{
+ size_t ioctlbuffer_len = PAGE_SIZE * max_possible_cpus +
+ sizeof(struct s390_hwctr_read);
+ struct s390_hwctr_read *read;
+ int rc;
+
+ if (!ioctlbuffer) {
+ ioctlbuffer = malloc(ioctlbuffer_len);
+ if (!ioctlbuffer) {
+ warn("ioctl S390_HWCTR_START");
+ return -ENOMEM;
+ }
+ }
+ read = (struct s390_hwctr_read *)ioctlbuffer;
+ rc = ioctl(ioctlfd, S390_HWCTR_READ, read);
+ if (!rc)
+ rc = test_read(read);
+ else
+ warn("ioctl S390_HWCTR_READ");
+ return rc;
+}
+
+static void do_sleep(void)
+{
+ struct timespec req = {
+ .tv_sec = read_interval,
+ .tv_nsec = 0
+ };
+
+ nanosleep(&req, NULL);
+}
+
+/* Execute commands and report first error */
+static int do_it(char *s)
+{
+ struct s390_hwctr_start start;
+ int ioctlfd;
+ int rc;
+
+ memset(&start, 0, sizeof(start));
+ rc = max_possible_cpus / sizeof(__u64);
+ start.cpumask = alloca(max_possible_cpus / sizeof(__u64));
+ memset(start.cpumask, 0, rc);
+ parse_cpulist(s, &start);
+ errno = 0;
+ ioctlfd = do_open();
+ if (ioctlfd < 0)
+ return EXIT_FAILURE;
+
+ rc = do_start(ioctlfd, &start);
+ if (rc < 0) {
+ close(ioctlfd);
+ return EXIT_FAILURE;
+ }
+
+ for (unsigned long i = 0; !rc && i < loop_count; ++i) {
+ rc = do_read(ioctlfd);
+ if (rc) {
+ close(ioctlfd);
+ return EXIT_FAILURE;
+ }
+ if (read_interval && i + 1 < loop_count)
+ do_sleep();
+ }
+ rc = do_stop(ioctlfd);
+ close(ioctlfd);
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+/* Read counter first and second version number */
+static bool get_cvn(void)
+{
+ char *linep = NULL;
+ bool good = false;
+ size_t line_sz;
+ ssize_t nbytes;
+ FILE *slp;
+
+ slp = fopen(SERVICELEVEL, "r");
+ if (!slp) {
+ warn(SERVICELEVEL);
+ return false;
+ }
+ while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
+ if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
+ int rc;
+
+ rc = sscanf(linep, "CPU-MF: Counter facility: version=%d.%d authorization=%x",
+ &cfvn, &csvn, &authorization);
+ good = rc == 3;
+ if (!good)
+ warnx("Cannot parse line %s", linep);
+ break;
+ }
+ }
+ fclose(slp);
+ free(linep);
+ return good;
+}
+
+static struct util_opt opt_vec[] = {
+ UTIL_OPT_SECTION("OPTIONS"),
+ {
+ .option = { "all", no_argument, NULL, 'a' },
+ .desc = "Displays all CPUs in output"
+ },
+ {
+ .option = { "loop", required_argument, NULL, 'l' },
+ .argument = "NUMBER",
+ .desc = "Specifies loop count for next read"
+ },
+ {
+ .option = { "interval", required_argument, NULL, 'i' },
+ .argument = "NUMBER",
+ .desc = "Specifies interval between read operations (seconds)"
+ },
+ UTIL_OPT_HELP,
+ UTIL_OPT_VERSION,
+ UTIL_OPT_END
+};
+
+static const struct util_prg prg = {
+ .desc = "Read CPU Measurement facility counter sets",
+ .copyright_vec = {
+ {
+ .owner = "IBM Corp.",
+ .pub_first = 2021,
+ .pub_last = 2021,
+ },
+ UTIL_PRG_COPYRIGHT_END
+ }
+};
+
+/* Check for hardware support and exit if not available */
+static void have_support(void)
+{
+ struct stat statbuf;
+
+ if (stat(S390_HWCTR_DEVICE, &statbuf) == -1)
+ errx(EXIT_FAILURE,
+ "No support for CPU Measurement Counter set facility");
+}
+
+int main(int argc, char **argv)
+{
+ char *slash;
+ int ch;
+
+ util_prg_init(&prg);
+ util_opt_init(opt_vec, NULL);
+
+ while ((ch = util_opt_getopt_long(argc, argv)) != -1) {
+ switch (ch) {
+ default:
+ util_opt_print_parse_error(ch, argv);
+ return EXIT_FAILURE;
+ case 'h':
+ util_prg_print_help();
+ util_opt_print_help();
+ return EXIT_SUCCESS;
+ case 'v':
+ util_prg_print_version();
+ return EXIT_SUCCESS;
+ case 'l':
+ errno = 0;
+ loop_count = strtoul(optarg, &slash, 0);
+ if (errno || *slash)
+ errx(EXIT_FAILURE, "Invalid argument for -%c",
+ ch);
+ break;
+ case 'i':
+ errno = 0;
+ read_interval = (unsigned int)strtoul(optarg, &slash, 0);
+ if (errno || *slash)
+ errx(EXIT_FAILURE, "Invalid argument for -%c", ch);
+ break;
+ case 'a':
+ allcpu = true;
+ break;
+ }
+ }
+
+ have_support();
+ if (!get_cvn())
+ return EXIT_FAILURE;
+ if (!check_setpossible())
+ return EXIT_FAILURE;
+ if (!read_counternames()) {
+ free(check);
+ return EXIT_FAILURE;
+ }
+
+ if (optind >= argc) {
+ ch = do_it(NULL);
+ } else {
+ while (optind < argc) {
+ ch = do_it(argv[optind++]);
+ if (ch)
+ break;
+ }
+ }
+ free_counternames();
+ free(check);
+ return ch;
+}
diff --git a/cpumf/lshwc.h b/cpumf/lshwc.h
new file mode 100644
index 0000000..d8044dc
--- /dev/null
+++ b/cpumf/lshwc.h
@@ -0,0 +1,92 @@
+/* Copyright IBM Corp. 2021
+ *
+ * s390-tools is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+/*
+ * CPU Measurement counter facility application for device driver.
+ *
+ * Ioctl system call definitions.
+ */
+
+#ifndef LSHWC_H
+#define LSHWC_H
+
+#include <sys/ioctl.h>
+
+enum {
+ S390_HWCTR_BASIC = 0x2, /* BASIC counter set */
+ S390_HWCTR_USER = 0x4, /* Problem-State Counter Set */
+ S390_HWCTR_CRYPTO = 0x8, /* Crypto-Activity Counter Set */
+ S390_HWCTR_EXT = 0x1, /* Extended Counter Set */
+ S390_HWCTR_MT_DIAG = 0x20, /* MT-diagnostic Counter Set */
+ S390_HWCTR_ALL = S390_HWCTR_BASIC | S390_HWCTR_USER |
+ S390_HWCTR_CRYPTO | S390_HWCTR_EXT |
+ S390_HWCTR_MT_DIAG
+};
+
+/* The ioctl(..., S390_HWCTR_READ, ...) is the only subcommand which returns
+ * data. It requires member data_bytes to be positive and indicates the
+ * maximum amount of data available to store counter set data. The other
+ * ioctl() subcommands do not use this member and it should be set to zero.
+ *
+ * The cpuset data is flattened using the following scheme, stored in member
+ * data:
+ *
+ * 0x0 0x8 0xc 0x10 0x14 0x18 0x20 0x28 0xU-1
+ * +---------+-----+---------+-----+---------+-----+-----+------+------+
+ * | no_cpus | cpu | no_sets | set | no_cnts | cv1 | cv2 | .... | cv_n |
+ * +---------+-----+---------+-----+---------+-----+-----+------+------+
+ *
+ * 0xU 0xU+4 0xU+8 0xU+10 0xV-1
+ * +-----+---------+-----+-----+------+------+
+ * | set | no_cnts | cv1 | cv2 | .... | cv_n |
+ * +-----+---------+-----+-----+------+------+
+ *
+ * 0xV 0xV+4 0xV+8 0xV+c
+ * +-----+---------+-----+---------+-----+-----+------+------+
+ * | cpu | no_sets | set | no_cnts | cv1 | cv2 | .... | cv_n |
+ * +-----+---------+-----+---------+-----+-----+------+------+
+ *
+ * U and V denote arbitrary hexadezimal addresses.
+ * In fact the first int represents the number of CPUs data was extracted
+ * from. This is followed by CPU number and number of counter sets extracted.
+ * Both are two integer values. This is followed by the set number and number
+ * of counters extracted. Both are two integer values. This is followed by
+ * the counter values, each element is eight bytes in size.
+ */
+
+struct s390_hwctr_start { /* Set CPUs to operate on */
+ __u64 version; /* Version of interface */
+ __u64 data_bytes; /* # of bytes required */
+ __u64 cpumask_len; /* Length of CPU mask in bytes */
+ __u64 *cpumask; /* Pointer to CPU mask */
+ __u64 counter_sets; /* Bit mask of counter set to get */
+};
+
+struct s390_hwctr_setdata { /* Counter set data */
+ __u32 set; /* Counter set number */
+ __u32 no_cnts; /* # of counters stored in cv[] */
+ __u64 cv[0]; /* Counter values (variable length) */
+};
+
+struct s390_hwctr_cpudata { /* Counter set data per CPU */
+ __u32 cpu_nr; /* Counter set number */
+ __u32 no_sets; /* # of counters sets in data[] */
+ struct s390_hwctr_setdata data[0];
+};
+
+struct s390_hwctr_read { /* Structure to get all ctr sets */
+ __u64 no_cpus; /* Total # of CPUs data taken from */
+ struct s390_hwctr_cpudata data[0];
+};
+
+#define S390_HWCTR_MAGIC 'C' /* Random magic # for ioctls */
+#define S390_HWCTR_START _IOWR(S390_HWCTR_MAGIC, 1, struct s390_hwctr_start)
+#define S390_HWCTR_STOP _IO(S390_HWCTR_MAGIC, 2)
+#define S390_HWCTR_READ _IOWR(S390_HWCTR_MAGIC, 3, struct s390_hwctr_read)
+
+#define S390_HWCTR_START_VERSION 1 /* Version # s390_hwctr_start */
+#define S390_HWCTR_DEVICE "/dev/hwctr" /* Device name */
+#endif
diff --git a/cpumf/man/lshwc.1 b/cpumf/man/lshwc.1
new file mode 100644
index 0000000..b7b6943
--- /dev/null
+++ b/cpumf/man/lshwc.1
@@ -0,0 +1,134 @@
+.\" lshwc.1
+.\"
+.\"
+.\" Copyright IBM Corp. 2021
+.\" s390-tools is free software; you can redistribute it and/or modify
+.\" it under the terms of the MIT license. See LICENSE for details.
+.\" ----------------------------------------------------------------------
+.ds c \fBlshwc\fP
+.
+.TH \*c "1" "February 2021" "s390-tools" "CPU-MF management programs"
+.
+.SH NAME
+\*c \- extract CPU Measurement Facilities counter sets
+.
+.SH SYNOPSIS
+\*c
+.RB [ \-a ]
+.RB [ \-l
+.IR count ]
+.RB [ \-i
+.IR interval ]
+\fR[\fIcpulist\fR][:\fIsets\fR]\fP
+.br
+\*c
+.BR \-h | \-\-help
+.br
+\*c
+.BR \-v | \-\-version
+.
+.
+.SH DESCRIPTION
+The \*c command extracts complete counter sets from the CPU
+Measurement Facilities for Linux on Z.
+Counter sets can be specified and extracted for individual CPUs.
+The output is a comma-separated values file.
+Each line starts with a timestamp and the CPU number,
+followed by the extracted counter values.
+.
+.SH OPTIONS
+.TP
+.BR \-h ", " \-\-help
+Displays help information, then exits.
+.
+.TP
+.BR \-v ", " \-\-version
+Displays version information, then exits.
+.
+.TP
+.BR \-a ", " \-\-allcpu
+Displays counter values from each CPU.
+The default is a total summary line of all counters from all CPUs.
+.
+.TP
+.BR \-i ", " \-\-interval \fI\ seconds\fP
+Specifies a time interval, in seconds,
+that the command waits between read operations.
+The default is 60 seconds.
+.
+.TP
+.BR \-l ", " \-\-loop \fI\ count\fP
+Performs the specified number of read operations.
+.
+.TP
+\fR[\fIcpulist\fR][:\fIsets\fR]\fP
+A comma-separated list of CPUs.
+Each CPU can optionally be followed by characters that specify the counter set.
+See below for details.
+.
+.SS "CPU List and counter-set specification"
+In the comma-separated list of CPUs,
+each element is a CPU or a range of CPUs.
+By default, \*c lists all CPUs.
+.P
+The CPU list can be followed by an optional list
+of characters that specify the counter sets to be extracted,
+preceded by a colon.
+The characters can be upper or lower case.
+By default, all counter sets are used.
+.IP b
+Include the basic counter set.
+.IP c
+Include the crypto counter set.
+.IP e
+Include the extended counter set.
+.IP m
+Include the MT_Diagnostic counter set.
+.IP p|u
+Include the problem counter set.
+.IP a
+Include all known counter sets (default).
+.SH "Concurrency with perf tool"
+The \*c tool and the linux
+.B perf
+tool use the same hardware and cannot be used concurrently.
+Both tools print an error message and abort when they
+detect this situation.
+.SH "EXAMPLES"
+The first example enables the basic and problem counter sets on CPU 0 and 1.
+Two read operations are performed and a summary line is printed for each
+read operation.
+.sp 1
+.nf
+.ft CW
+# lshwc -l2 0-1:BP
+Date,Time,CPU,CPU_CYCLES(0),INSTRUCTIONS(1),L1I_DIR_WRITES(2),L1I_PENALTY_CYCLES(3),L1D_DIR_WRITES(4),
+ L1D_PENALTY_CYCLES(5),PROBLEM_STATE_CPU_CYCLES(32),PROBLEM_STATE_INSTRUCTIONS(33)
+2021-04-01,11:50:32,Total,125422,39421,304,13953,454,
+ 97489,0,0
+2021-04-01,11:51:32,Total,68074231,16386850,194028,21382384,317227,
+ 104503489,777383,14198
+.ft
+.fi
+.sp 1
+This example shows the counter values of the problem state counter set
+per CPU. CPU 0 and CPU 1 is selected.
+.nf
+.ft CW
+.sp 1
+# lshwc -l3 -a 0-1:P
+Date,Time,CPU,PROBLEM_STATE_CPU_CYCLES(32),PROBLEM_STATE_INSTRUCTIONS(33)
+2021-04-01,11:54:47,CPU0,0,0
+2021-04-01,11:54:47,CPU1,0,0
+2021-04-01,11:54:47,Total,0,0
+2021-04-01,11:55:47,CPU0,818775,14198
+2021-04-01,11:55:47,CPU1,125689,1306
+2021-04-01,11:55:47,Total,944464,15504
+2021-04-01,11:56:47,CPU0,3207071426,1489122591
+2021-04-01,11:56:47,CPU1,3225092021,1489278312
+2021-04-01,11:56:47,Total,6432163447,2978400903
+.ft
+.fi
+.SH "SEE ALSO"
+.BR lscpumf (1)
+.BR chcpumf (8)
--
2.31.1