Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP4:Update
s390-tools.28248
s390-tools-sles15sp4-04-libap-Add-library-for-a...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles15sp4-04-libap-Add-library-for-ap-vfio-ap-management-tools.patch of Package s390-tools.28248
Subject: [PATCH] [FEAT VS1822] libap: Add library for ap / vfio-ap management tools From: Matthew Rosato <mjrosato@linux.ibm.com> Summary: ap_tools: add ap-check and the ap device type to zdev Description: This feature adds multiple components in support of persistent configuration of vfio-ap mediated devices. The ap-check utility is added as a callout function for the mdevctl utility. This allows for meaningful error messages to be presented to end-users when vfio-ap configuration errors are detected while using mdevctl to create/modify vfio-ap mediated devices. Additionally, the 'ap' device type is added to zdev, providing a command-line interface for managing the apmask and aqmask, which determine what AP resources are available for vfio-ap usage. 'chzdev' is updated to allow for modifying the active masks as well as to specify persistent mask values via a udev rule. 'lszdev' is updated to allow for querying of the active and persistent mask values. Upstream-ID: bf71e3bb1fc39e1e552f012b5346f5816b454097 Problem-ID: VS1822 Upstream-Description: libap: Add library for ap / vfio-ap management tools libap is intended to provide utility functions to be used by tooling supporting the ap bus and vfio-ap mediated devices. Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com> Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com> Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> --- .gitignore | 2 Makefile | 2 common.mak | 4 include/lib/ap.h | 94 ++++++ libap/Makefile | 37 ++ libap/ap.c | 760 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 898 insertions(+), 1 deletion(-) --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,8 @@ iucvterm/src/iucvconn iucvterm/src/iucvtty iucvterm/src/ttyrun iucvterm/test/test_afiucv +libap/check-dep-lock +libap/check-dep-json libekmfweb/check-dep-libekmfweb libekmfweb/detect-openssl-version.dep libekmfweb/libekmfweb.so --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ include common.mak # BASELIB_DIRS = libutil libseckey LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \ - libkmipclient libpv + libkmipclient libpv libap TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \ tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \ vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \ --- a/common.mak +++ b/common.mak @@ -387,6 +387,10 @@ $(rootdir)/libpv/libpv.a: $(rootdir)/lib $(MAKE) -C $(rootdir)/libpv libpv.a .PHONY: $(rootdir)/libpv +$(rootdir)/libap/libap.a: $(rootdir)/libap + $(MAKE) -C $(rootdir)/libap/ libap.a +.PHONY: $(rootdir)/libap + $(rootdir)/zipl/boot/data.o: $(MAKE) -C $(rootdir)/zipl/boot/ data.o --- /dev/null +++ b/include/lib/ap.h @@ -0,0 +1,94 @@ +/* + * libap - A collection of tools for ap/vfio-ap management + * + * Copyright IBM Corp. 2022 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIB_AP_H +#define LIB_AP_H + +#include <stdbool.h> + +#include "lib/util_list.h" + +#define VFIO_AP_PATH "/sys/devices/vfio_ap" +#define VFIO_AP_PARENT_PATH "devices/vfio_ap/matrix" +#define VFIO_AP_CONFIG_PATH "/etc/mdevctl.d/matrix" +#define VFIO_AP_TYPE "vfio_ap-passthrough" +#define AP_UDEV_FILE "/etc/udev/rules.d/41-ap.rules" +#define AP_LOCKFILE "/run/lock/s390apconfig.lock" + +#define AP_LOCK_RETRIES 15 + +/* apmask and aqmask are each represented as 67 character strings with: + * '0x' leading characters + * 64 hex digits (to represent 256 bits) + * terminating character + */ +#define AP_MASK_SIZE 67 +#define AP_MAX_MASK_VALUE 255 + +/* List structure used for keeping track of lists of adapter/domain IDs */ +struct vfio_ap_node { + struct util_list_node node; /* prev/next list info */ + unsigned int id; /* list entry (adapter, domain, etc) */ +}; + +/* + * Structure used to represent a vfio_ap-passthrough device configuration. + * The list of adapters and domains can be used to derive the APQNs for the + * device. The type value is used to verify that the device (when read from + * a mdevctl config file) is of type vfio_ap-passthrough. The manual value + * represents whether the device is started on-demand after boot (true) or + * automatically during boot (false). + */ +struct vfio_ap_device { + char *uuid; /* Unique ID for this mdev */ + struct util_list *adapters; /* List of adapters for device */ + struct util_list *domains; /* List of usage domains for device */ + struct util_list *controls; /* List of control domains for device */ + char *type; /* mdev type string */ + bool manual; /* manual/auto start setting for mdev */ +}; + +/* General Utility Functions */ +void print_ap_device(struct vfio_ap_device *dev); +bool is_valid_uuid(const char *uuid); +int ap_test_bit(int n, const char *hexbytestr); +void ap_set_bit(int n, char *hexbytestr, bool val); + +/* Path-related functions */ +char *path_get_vfio_ap_mdev(const char *uuid); +char *path_get_vfio_ap_mdev_config(const char *uuid); +char *path_get_vfio_ap_attr(const char *uuid, const char *attr); +char *path_get_ap_udev(void); + +/* Functions for manipulating sysfs to read active device info */ +void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix); +void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev); +void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control); + +/* Functions for reading JSON device config */ +int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev); + +/* Functions for managing vfio_ap device structures */ +struct vfio_ap_device *vfio_ap_device_new(void); +void vfio_ap_device_clear(struct vfio_ap_device *dev); +void vfio_ap_device_free(struct vfio_ap_device *dev); + +/* Functions for acquiring current vfio_ap device info */ +int ap_read_sysfs_masks(char *ap, char *aq, int size); +bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap, + bool *read_aq); +void ap_mask_to_list(char *mask, struct util_list *list); +void ap_list_remove_all(struct util_list *list); + +/* Lock Functions */ +int ap_get_lock(void); +int ap_get_lock_callout(void); +int ap_release_lock(void); + +#endif /* LIB_AP_H */ --- /dev/null +++ b/libap/Makefile @@ -0,0 +1,37 @@ +include ../common.mak + +lib = libap.a + +check-dep-lock: + touch check-dep-lock +ifneq (${HAVE_LOCKFILE},0) + $(call check_dep, \ + "libap", \ + "lockfile.h", \ + "liblockfile-devel", \ + "HAVE_LOCKFILE=0") +ALL_CPPFLAGS += -DHAVE_LOCKFILE +endif + +check-dep-json: + touch check-dep-json +ifneq (${HAVE_JSONC},0) + $(call check_dep, \ + "libap", \ + "json-c/json.h", \ + "json-c-devel", \ + "HAVE_JSONC=0") +ALL_CPPFLAGS += -DHAVE_JSONC +endif + +all: $(lib) +objects = ap.o + +$(lib): $(objects) + +$(objects): check-dep-lock check-dep-json + +install: all + +clean: + rm -f *.o check-dep-lock check-dep-json $(lib) --- /dev/null +++ b/libap/ap.c @@ -0,0 +1,760 @@ +/* + * libap - A collection of tools for ap/vfio-ap management + * + * Copyright IBM Corp. 2022 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <ctype.h> +#include <dirent.h> +#include <err.h> +#include <errno.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_JSONC +#include <json-c/json.h> +#endif /* HAVE_JSONC */ + +#ifdef HAVE_LOCKFILE +#include <lockfile.h> +#endif /* HAVE_LOCKFILE */ + +#include "lib/ap.h" +#include "lib/util_file.h" +#include "lib/util_libc.h" +#include "lib/util_panic.h" +#include "lib/util_path.h" +#include "lib/util_udev.h" + +/* + * Return sysfs path to a bus attribute + * Note: caller is responsible for freeing the returned string + */ +static char *path_get_bus_attr(const char *bus, const char *attr) +{ + return util_path_sysfs("bus/%s/%s", bus, attr); +} + +/* + * Compare two vfio_ap nodes based upon their id value. Return: + * -1: a < b + * 1: a > b + * 0: a == b + */ +static int vfio_ap_node_cmp(void *a, void *b, void *UNUSED(data)) +{ + struct vfio_ap_node *a_node = a, *b_node = b; + + if (a_node->id < b_node->id) + return -1; + return (a_node->id > b_node->id); +} + +static void vfio_ap_node_add_tail(struct util_list *list, unsigned int val) +{ + struct vfio_ap_node *node = util_zalloc(sizeof(struct vfio_ap_node)); + + node->id = val; + util_list_add_tail(list, node); +} + +/* Remove duplicate entries from a sorted vfio_ap_node list */ +static void vfio_ap_node_remove_dupes(struct util_list *list) +{ + struct vfio_ap_node *node, *check, *next; + + util_list_iterate(list, node) { + /* Remove any subsequent duplicates */ + check = util_list_next(list, node); + + while (check) { + next = util_list_next(list, check); + if (node->id == check->id) { + util_list_remove(list, check); + free(check); + } + check = next; + } + } +} + +static bool starts_with(const char *str, const char *s) +{ + size_t len = strlen(s); + + return (strncmp(str, s, len) == 0); +} + +/* + * Pass a comma-delimited string of IDs (adapter, domains or control domains) + * and add these IDs to the input list. The resulting list will be sorted + * and duplicates removed before returning. + */ +static void modify_device_attr(struct util_list *list, char *value) +{ + unsigned int val; + char *curr; + + curr = strtok(value, ","); + if (curr == NULL) + return; + + /* Create list from input setting */ + while (curr != NULL) { + val = strtol(curr, NULL, 0); + vfio_ap_node_add_tail(list, val); + curr = strtok(NULL, ","); + } + + /* Cleanup the list */ + util_list_sort(list, vfio_ap_node_cmp, NULL); + vfio_ap_node_remove_dupes(list); +} + +static void load_attr_to_device(struct vfio_ap_device *dev, char *attr, + const char *value) +{ + char *v = util_strdup(value); + + if (strcmp(attr, "assign_adapter") == 0) + modify_device_attr(dev->adapters, v); + else if (strcmp(attr, "assign_domain") == 0) + modify_device_attr(dev->domains, v); + else if (strcmp(attr, "assign_control_domain") == 0) + modify_device_attr(dev->controls, v); + + free(v); +} + +/** + * Print the contents of the vfio-ap device struct to stderr. Used for + * debugging. + * + * @param[in] dev vfio-ap device strcucture to print + */ +void print_ap_device(struct vfio_ap_device *dev) +{ + struct vfio_ap_node *node; + + warnx("Device %s:", dev->uuid); + warnx("Type: %s", dev->type); + if (dev->manual) + warnx("Start: MANUAL"); + else + warnx("Start: AUTO"); + if (util_list_is_empty(dev->adapters)) { + warnx("Adapters: (none)"); + } else { + warnx("Adapters:"); + util_list_iterate(dev->adapters, node) { + warnx(" %u", node->id); + } + } + if (util_list_is_empty(dev->domains)) { + warnx("Domains: (none)"); + } else { + warnx("Domains:"); + util_list_iterate(dev->domains, node) { + warnx(" %u", node->id); + } + } + if (util_list_is_empty(dev->controls)) { + warnx("Controls: (none)"); + } else { + warnx("Controls:"); + util_list_iterate(dev->controls, node) { + warnx(" %u", node->id); + } + } +} + +/** + * Determine if the input string is a valid Universally Unique Identifier + * + * @param[in] uuid Character string to inspect + * + * @retval true Specified string is a valid UUID + * @retval false Specified string is not a valid UUID + */ +bool is_valid_uuid(const char *uuid) +{ + uint32_t s1, s2, s3, s4; + uint64_t s5; + char d; + + return (strlen(uuid) == 36 && sscanf(uuid, "%8x-%4x-%4x-%4x-%12x %c", + &s1, &s2, &s3, &s4, + (unsigned int *) &s5, &d) == 5); +} + +/* + * For an input string of hex characters, find the nth character and return its + * numeric value to the caller. + */ +static int get_hexbyte_value(int n, const char *hexbytestr) +{ + int i = 0, v = 0; + char c; + + if (strncmp(hexbytestr, "0x", 2) == 0) + i = 2; + + /* + * The specified mask is only valid if it includes at least 64 hex + * digits. The specified mask may optionally include a leading '0x' + */ + util_assert((strlen(hexbytestr) >= (size_t)(AP_MASK_SIZE - i - 1)), + "Invalid hex string provided for mask: %s", hexbytestr); + + c = hexbytestr[i + n / 4]; + if (c >= '0' && c <= '9') + v = c - '0'; + else if (c >= 'a' && c <= 'f') + v = 10 + c - 'a'; + else if (c >= 'A' && c <= 'F') + v = 10 + c - 'A'; + else + util_assert(false, "Could not parse hex digit '%c'", c); + + return v; +} + +/** + * For an input hex string, determine if the specified nth bit is ON or OFF. + * + * @param[in] n Bit number to test + * @param[in, out] hexbytestr Character string of hex characters + * + * @retval 0 Specified bit is OFF + * @retval != 0 Specified bit is ON + */ +int ap_test_bit(int n, const char *hexbytestr) +{ + int v; + + v = get_hexbyte_value(n, hexbytestr); + + return v & (1 << (3 - (n % 4))); +} + +/** + * For an input hex string, set the nth bit true/false + * + * @param[in] n Bit number to set + * @param[in, out] hexbytestr Character string of hex characters + * @param[in] val Bit is to be set ON (true) or OFF (false) + */ +void ap_set_bit(int n, char *hexbytestr, bool val) +{ + char c = 0; + int v, m, i = 0; + + v = get_hexbyte_value(n, hexbytestr); + + /* Calculate the bit mask */ + m = (1 << (3 - (n % 4))); + + /* Return if bit already at correct value */ + if (((val) && ((v & m) != 0)) || (!val && ((v & m) == 0))) + return; + + if (val) + v = v + m; + else + v = v - m; + + if (v < 10) + c = '0' + v; + else if (v >= 10 && v <= 15) + c = 'a' + (v - 10); + else + util_assert(false, "Could not set bit value '%d'", v); + + if (strncmp(hexbytestr, "0x", 2) == 0) + i = 2; + + /* Set the new value */ + hexbytestr[i + n / 4] = c; +} + +/** + * Return sysfs path to vfio_ap mdev + * Note: caller is responsible for freeing the returned string + * + * @param[in] uuid Character string containing an mdev UUID + * + * @retval != 0 sysfs path for a vfio-ap device with this UUID + */ +char *path_get_vfio_ap_mdev(const char *uuid) +{ + return util_path_sysfs("%s/%s", VFIO_AP_PARENT_PATH, uuid); +} + +/** + * Return path to mdevctl config file for specified UUID + * Note: caller is responsible for freeing the returned string + * + * @param[in] uuid Character string containing an mdev UUID + * + * @retval != 0 config file path for vfio-ap device with this UUID + */ +char *path_get_vfio_ap_mdev_config(const char *uuid) +{ + char *path; + + util_asprintf(&path, "%s/%s", VFIO_AP_CONFIG_PATH, uuid); + return path; +} + +/** + * Return sysfs path to vfio_ap mdev attribute (matrix, remove, ...) + * Note: caller is responsible for freeing the returned string + * + * @param[in] uuid Character string containing an mdev UUID + * @param[in] attr Character string containing device attribute name + * + * @retval != 0 sysfs path to specified attribute for this device + */ +char *path_get_vfio_ap_attr(const char *uuid, const char *attr) +{ + return util_path_sysfs("%s/%s/%s", VFIO_AP_PARENT_PATH, uuid, attr); +} + +/** + * Return path to ap udev config file + * Note: caller is responsible for freeing the returned string + * + * @retval != 0 path to the ap udev config file + */ +char *path_get_ap_udev(void) +{ + char *path; + + util_asprintf(&path, "%s", AP_UDEV_FILE); + return path; +} + +/** + * Take one line from the active 'matrix' attribute and parse it + * into a list of adapters and domains. Each line of the 'matrix' + * attribute is presented as a "adapter.domain" (e.g. "03.0005") where the + * numeric values are always hexadecimal. + * In a case where no adapters are assigned, a valid string might be ".0005" + * In a case where no domains are assigned, a valid string might be "03." + * + * @param[in, out] dev Vfio-ap struct that will be updated + * @param[in] matrix Character string to parse + */ +void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix) +{ + char *curr; + int val; + + if (!matrix) + return; + + if (*matrix != '.') { + /* Handle a device with adapters */ + curr = strtok(matrix, "."); + val = strtol(curr, NULL, 16); + vfio_ap_node_add_tail(dev->adapters, val); + curr = strtok(NULL, "\n"); + } else { + /* Handle a device with no adapters */ + curr = strtok(matrix + 1, "\n"); + } + + /* Leave now if the device has no domains */ + if (!curr) + return; + /* Get the domain */ + val = strtol(curr, NULL, 16); + vfio_ap_node_add_tail(dev->domains, val); +} + +/** + * Function to sort the results of repeated vfio_ap_parse_matrix calls + * + * @param[in, out] dev Vfio-ap struct whose lists will be sorted + */ +void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev) +{ + /* Sort the lists for later use */ + util_list_sort(dev->adapters, vfio_ap_node_cmp, NULL); + util_list_sort(dev->domains, vfio_ap_node_cmp, NULL); + + /* Run the lists and delete duplicates */ + vfio_ap_node_remove_dupes(dev->adapters); + vfio_ap_node_remove_dupes(dev->domains); +} + +/** + * Take the string provided by the active 'control_domains' attribute and + * parse it into a list of control domains + * + * @param[in, out] dev Vfio-ap struct that will be updated + * @param[in] control Character string to parse + */ +void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control) +{ + char *curr; + int val; + + curr = strtok(control, "\n"); + + while (curr != NULL) { + val = strtol(curr, NULL, 16); + vfio_ap_node_add_tail(dev->controls, val); + curr = strtok(NULL, "\n"); + } +} + +#ifdef HAVE_JSONC + +/** + * For a given path, read in the contents. If no path is provided, get the + * input from stdin instead. + * + * @param[in] path Path to mdevctl config file + * @param[in, out] dev Vfio-ap struct that will be updated + * + * @retval 0 Config read successfully, dev updated + * @retval -1 Failed to read config, dev may have partial info + */ +int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev) +{ + json_object *root, *type, *start, *attrs, *attr; + int i, len, rc = 0; + const char *val; + + if (path == NULL) + root = json_object_from_fd(STDIN_FILENO); + else + root = json_object_from_file(path); + if (root == NULL) + return -1; + + if (json_object_object_get_ex(root, "mdev_type", &type)) { + val = json_object_get_string(type); + if (!val) + goto err; + dev->type = util_strdup(val); + if (strcmp(val, "vfio_ap-passthrough") != 0) + goto err; + } + + if (json_object_object_get_ex(root, "start", &start)) { + val = json_object_get_string(start); + if (!val) + goto err; + if (strcmp(val, "auto") == 0) + dev->manual = false; + else if (strcmp(val, "manual") == 0) + dev->manual = true; + else + goto err; + } + + if (json_object_object_get_ex(root, "attrs", &attrs)) { + len = json_object_array_length(attrs); + for (i = 0; i < len; i++) { + attr = json_object_array_get_idx(attrs, i); + json_object_object_foreach(attr, key, setting) { + val = json_object_get_string(setting); + load_attr_to_device(dev, key, val); + } + } + } + +out: + json_object_put(root); + return rc; + +err: + rc = -1; + goto out; +} + +#else +int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev) +{ + return -1; +} +#endif /* HAVE_JSONC */ + +/** + * Allocate and initialize a vfio-ap device structure. + * + * @retval !=0 Address of the new vfio-ap device structure + */ +struct vfio_ap_device *vfio_ap_device_new(void) +{ + struct vfio_ap_device *dev; + + dev = util_zalloc(sizeof(struct vfio_ap_device)); + + dev->manual = false; + dev->type = NULL; + dev->uuid = NULL; + + dev->adapters = util_list_new(struct vfio_ap_node, node); + dev->domains = util_list_new(struct vfio_ap_node, node); + dev->controls = util_list_new(struct vfio_ap_node, node); + + return dev; +} + +/** + * Re-initialize a vfio-ap device structure, leaving the structure allocated. + * + * @param[in, out] dev Vfio-ap struct that will be re-initialized + */ +void vfio_ap_device_clear(struct vfio_ap_device *dev) +{ + if (dev == NULL) + return; + + dev->manual = false; + if (dev->type) { + free(dev->type); + dev->type = NULL; + } + if (dev->uuid) { + free(dev->uuid); + dev->uuid = NULL; + } + + ap_list_remove_all(dev->adapters); + ap_list_remove_all(dev->domains); + ap_list_remove_all(dev->controls); +} + +/** + * Clear and release a vfio-ap device structure. + * + * @param[in, out] dev Vfio-ap struct that will be freed + */ +void vfio_ap_device_free(struct vfio_ap_device *dev) +{ + if (dev == NULL) + return; + + vfio_ap_device_clear(dev); + util_list_free(dev->adapters); + util_list_free(dev->domains); + util_list_free(dev->controls); + free(dev); +} + +static int read_sysfs_mask(const char *path, char *mask, int size) +{ + return util_file_read_line(mask, size, "%s", path); +} + +/** + * Get the apmask and aqmask from sysfs + * + * @param[in, out] ap Buffer to hold apmask contents + * @param[in, out] aq Buffer to hold aqmask contents + * @param[in] size Size of the mask buffers + * + * @retval 0 Both mask values read successfully + * @retval != 0 Failed to read one or both mask values + */ +int ap_read_sysfs_masks(char *ap, char *aq, int size) +{ + char *path; + int rc = 0; + + path = path_get_bus_attr("ap", "apmask"); + rc = read_sysfs_mask(path, ap, size); + free(path); + if (rc != 0) + goto out; + path = path_get_bus_attr("ap", "aqmask"); + rc = read_sysfs_mask(path, aq, size); + free(path); + +out: + return rc; +} + +/** + * Get the apmask and aqmask from udev, falling back to sysfs if a udev rule + * is not available or does not provide values for both masks. + * The values in read_ap and read_aq tell the caller whether each mask was + * successfully loaded from udev or if the sysfs value was substituted + * Note: both ap and aq must point to a string that is at least AP_MASK_SIZE + * in length. + * + * @param[in] path Path to the ap udev file + * @param[in, out] ap Buffer to hold apmask contents + * @param[in, out] aq Buffer to hold aqmask contents + * @param[out] read_ap Specifies if an apmask value was read from udev + * @param[out] read_aq Specifies if an aqmask value was read from udev + * + * @retval true Udev file read successfully or did not exist + * @retval false Udev file exists but error was encountered + */ +bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap, + bool *read_aq) +{ + struct util_udev_entry_node *entry; + struct util_udev_file *file = NULL; + struct util_udev_line_node *line; + char sysap[AP_MASK_SIZE]; + char sysaq[AP_MASK_SIZE]; + int rc; + + /* Assume we fail to read both masks */ + *read_ap = *read_aq = false; + + /* If a udev file doesn't exist, quietly use the active masks */ + if (!util_path_exists(path)) + goto out; + + rc = util_udev_read_file(path, &file); + + /* If errors were encountered reading the udev file, exit now */ + if (rc) + return false; + + util_list_iterate(&file->lines, line) { + entry = util_list_start(&line->entries); + + /* Skip comments and empty lines. */ + if (!entry) + continue; + + if (starts_with(entry->key, "ATTR{")) { + if (strstr(entry->key, "apmask")) { + util_strlcpy(ap, entry->value, AP_MASK_SIZE); + *read_ap = true; + } else if (strstr(entry->key, "aqmask")) { + util_strlcpy(aq, entry->value, AP_MASK_SIZE); + *read_aq = true; + } + } + } + + util_udev_free_file(file); + +out: + /* If we didn't read in masks, use current sysfs values */ + if ((!*read_ap) || (!*read_aq)) { + rc = ap_read_sysfs_masks(sysap, sysaq, AP_MASK_SIZE); + if (rc != 0) + return false; + if (!*read_ap) + strcpy(ap, sysap); + if (!*read_aq) + strcpy(aq, sysaq); + } + + return true; +} + +/** + * For a given bitmask, create a list of vfio_ap_node entries corresponding + * to the ON bits in the mask. + * + * @param[in] mask Character string of hex characters + * @param[in, out] list List to be updated with entries for each ON bit + */ +void ap_mask_to_list(char *mask, struct util_list *list) +{ + int i; + + if (mask == NULL || list == NULL) + return; + + for (i = 0; i <= AP_MAX_MASK_VALUE; i++) { + if (ap_test_bit(i, mask)) + vfio_ap_node_add_tail(list, i); + } + + /* Could have duplicates if the input list was not empty */ + util_list_sort(list, vfio_ap_node_cmp, NULL); + vfio_ap_node_remove_dupes(list); +} + +/** + * For the specified list, remove all elements and free each node + * + * @param[in, out] list List that will have all entries removed + */ +void ap_list_remove_all(struct util_list *list) +{ + struct ap_node *node; + + while (!util_list_is_empty(list)) { + node = util_list_start(list); + util_list_remove(list, node); + free(node); + } +} + +#ifdef HAVE_LOCKFILE +static int ap_lockfile_create(int flags) +{ + return lockfile_create(AP_LOCKFILE, AP_LOCK_RETRIES, flags); +} + +/** + * Acquire the ap config lock using this process PID (L_PID) + * + * @retval 0 Lock successfully acquired on behalf of L_PID + * @retval != 0 Error, lock was not obtained + */ +int ap_get_lock(void) +{ + return ap_lockfile_create(L_PID); +} + +/** + * Acquire the ap config lock using the parent process PID (L_PPID) -- intended + * for use by the mdevctl callout ap-check utility + * + * @retval 0 Lock successfully acquired on behalf of L_PPID + * @retval != 0 Error, lock was not obtained + */ +int ap_get_lock_callout(void) +{ + return ap_lockfile_create(L_PPID); +} + +/** + * Release the ap config lock + * + * @retval 0 Lock successfully released or file didn't exist + * @retval != 0 Error removing the lockfile + */ +int ap_release_lock(void) +{ + return lockfile_remove(AP_LOCKFILE); +} +#else +/* If no liblockfile, actions are performed without acquiring the file lock */ +int ap_get_lock(void) +{ + return 0; +} + +int ap_get_lock_callout(void) +{ + return 0; +} + +int ap_release_lock(void) +{ + return 0; +} + +#endif /* HAVE_LOCKFILE */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor