cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

zfcp_diag.c (8056B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * zfcp device driver
      4 *
      5 * Functions to handle diagnostics.
      6 *
      7 * Copyright IBM Corp. 2018
      8 */
      9
     10#include <linux/spinlock.h>
     11#include <linux/jiffies.h>
     12#include <linux/string.h>
     13#include <linux/errno.h>
     14#include <linux/slab.h>
     15
     16#include "zfcp_diag.h"
     17#include "zfcp_ext.h"
     18#include "zfcp_def.h"
     19
     20static DECLARE_WAIT_QUEUE_HEAD(__zfcp_diag_publish_wait);
     21
     22/**
     23 * zfcp_diag_adapter_setup() - Setup storage for adapter diagnostics.
     24 * @adapter: the adapter to setup diagnostics for.
     25 *
     26 * Creates the data-structures to store the diagnostics for an adapter. This
     27 * overwrites whatever was stored before at &zfcp_adapter->diagnostics!
     28 *
     29 * Return:
     30 * * 0	     - Everyting is OK
     31 * * -ENOMEM - Could not allocate all/parts of the data-structures;
     32 *	       &zfcp_adapter->diagnostics remains unchanged
     33 */
     34int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter)
     35{
     36	struct zfcp_diag_adapter *diag;
     37	struct zfcp_diag_header *hdr;
     38
     39	diag = kzalloc(sizeof(*diag), GFP_KERNEL);
     40	if (diag == NULL)
     41		return -ENOMEM;
     42
     43	diag->max_age = (5 * 1000); /* default value: 5 s */
     44
     45	/* setup header for port_data */
     46	hdr = &diag->port_data.header;
     47
     48	spin_lock_init(&hdr->access_lock);
     49	hdr->buffer = &diag->port_data.data;
     50	hdr->buffer_size = sizeof(diag->port_data.data);
     51	/* set the timestamp so that the first test on age will always fail */
     52	hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age);
     53
     54	/* setup header for config_data */
     55	hdr = &diag->config_data.header;
     56
     57	spin_lock_init(&hdr->access_lock);
     58	hdr->buffer = &diag->config_data.data;
     59	hdr->buffer_size = sizeof(diag->config_data.data);
     60	/* set the timestamp so that the first test on age will always fail */
     61	hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age);
     62
     63	adapter->diagnostics = diag;
     64	return 0;
     65}
     66
     67/**
     68 * zfcp_diag_adapter_free() - Frees all adapter diagnostics allocations.
     69 * @adapter: the adapter whose diagnostic structures should be freed.
     70 *
     71 * Frees all data-structures in the given adapter that store diagnostics
     72 * information. Can savely be called with partially setup diagnostics.
     73 */
     74void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter)
     75{
     76	kfree(adapter->diagnostics);
     77	adapter->diagnostics = NULL;
     78}
     79
     80/**
     81 * zfcp_diag_update_xdata() - Update a diagnostics buffer.
     82 * @hdr: the meta data to update.
     83 * @data: data to use for the update.
     84 * @incomplete: flag stating whether the data in @data is incomplete.
     85 */
     86void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr,
     87			    const void *const data, const bool incomplete)
     88{
     89	const unsigned long capture_timestamp = jiffies;
     90	unsigned long flags;
     91
     92	spin_lock_irqsave(&hdr->access_lock, flags);
     93
     94	/* make sure we never go into the past with an update */
     95	if (!time_after_eq(capture_timestamp, hdr->timestamp))
     96		goto out;
     97
     98	hdr->timestamp = capture_timestamp;
     99	hdr->incomplete = incomplete;
    100	memcpy(hdr->buffer, data, hdr->buffer_size);
    101out:
    102	spin_unlock_irqrestore(&hdr->access_lock, flags);
    103}
    104
    105/**
    106 * zfcp_diag_update_port_data_buffer() - Implementation of
    107 *					 &typedef zfcp_diag_update_buffer_func
    108 *					 to collect and update Port Data.
    109 * @adapter: Adapter to collect Port Data from.
    110 *
    111 * This call is SYNCHRONOUS ! It blocks till the respective command has
    112 * finished completely, or has failed in some way.
    113 *
    114 * Return:
    115 * * 0		- Successfully retrieved new Diagnostics and Updated the buffer;
    116 *		  this also includes cases where data was retrieved, but
    117 *		  incomplete; you'll have to check the flag ``incomplete``
    118 *		  of &struct zfcp_diag_header.
    119 * * see zfcp_fsf_exchange_port_data_sync() for possible error-codes (
    120 *   excluding -EAGAIN)
    121 */
    122int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter)
    123{
    124	int rc;
    125
    126	rc = zfcp_fsf_exchange_port_data_sync(adapter->qdio, NULL);
    127	if (rc == -EAGAIN)
    128		rc = 0; /* signaling incomplete via struct zfcp_diag_header */
    129
    130	/* buffer-data was updated in zfcp_fsf_exchange_port_data_handler() */
    131
    132	return rc;
    133}
    134
    135/**
    136 * zfcp_diag_update_config_data_buffer() - Implementation of
    137 *					   &typedef zfcp_diag_update_buffer_func
    138 *					   to collect and update Config Data.
    139 * @adapter: Adapter to collect Config Data from.
    140 *
    141 * This call is SYNCHRONOUS ! It blocks till the respective command has
    142 * finished completely, or has failed in some way.
    143 *
    144 * Return:
    145 * * 0		- Successfully retrieved new Diagnostics and Updated the buffer;
    146 *		  this also includes cases where data was retrieved, but
    147 *		  incomplete; you'll have to check the flag ``incomplete``
    148 *		  of &struct zfcp_diag_header.
    149 * * see zfcp_fsf_exchange_config_data_sync() for possible error-codes (
    150 *   excluding -EAGAIN)
    151 */
    152int zfcp_diag_update_config_data_buffer(struct zfcp_adapter *const adapter)
    153{
    154	int rc;
    155
    156	rc = zfcp_fsf_exchange_config_data_sync(adapter->qdio, NULL);
    157	if (rc == -EAGAIN)
    158		rc = 0; /* signaling incomplete via struct zfcp_diag_header */
    159
    160	/* buffer-data was updated in zfcp_fsf_exchange_config_data_handler() */
    161
    162	return rc;
    163}
    164
    165static int __zfcp_diag_update_buffer(struct zfcp_adapter *const adapter,
    166				     struct zfcp_diag_header *const hdr,
    167				     zfcp_diag_update_buffer_func buffer_update,
    168				     unsigned long *const flags)
    169	__must_hold(hdr->access_lock)
    170{
    171	int rc;
    172
    173	if (hdr->updating == 1) {
    174		rc = wait_event_interruptible_lock_irq(__zfcp_diag_publish_wait,
    175						       hdr->updating == 0,
    176						       hdr->access_lock);
    177		rc = (rc == 0 ? -EAGAIN : -EINTR);
    178	} else {
    179		hdr->updating = 1;
    180		spin_unlock_irqrestore(&hdr->access_lock, *flags);
    181
    182		/* unlocked, because update function sleeps */
    183		rc = buffer_update(adapter);
    184
    185		spin_lock_irqsave(&hdr->access_lock, *flags);
    186		hdr->updating = 0;
    187
    188		/*
    189		 * every thread waiting here went via an interruptible wait,
    190		 * so its fine to only wake those
    191		 */
    192		wake_up_interruptible_all(&__zfcp_diag_publish_wait);
    193	}
    194
    195	return rc;
    196}
    197
    198static bool
    199__zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_adapter *const diag,
    200				    const struct zfcp_diag_header *const hdr)
    201	__must_hold(hdr->access_lock)
    202{
    203	const unsigned long now = jiffies;
    204
    205	/*
    206	 * Should not happen (data is from the future).. if it does, still
    207	 * signal that it needs refresh
    208	 */
    209	if (!time_after_eq(now, hdr->timestamp))
    210		return false;
    211
    212	if (jiffies_to_msecs(now - hdr->timestamp) >= diag->max_age)
    213		return false;
    214
    215	return true;
    216}
    217
    218/**
    219 * zfcp_diag_update_buffer_limited() - Collect diagnostics and update a
    220 *				       diagnostics buffer rate limited.
    221 * @adapter: Adapter to collect the diagnostics from.
    222 * @hdr: buffer-header for which to update with the collected diagnostics.
    223 * @buffer_update: Specific implementation for collecting and updating.
    224 *
    225 * This function will cause an update of the given @hdr by calling the also
    226 * given @buffer_update function. If called by multiple sources at the same
    227 * time, it will synchornize the update by only allowing one source to call
    228 * @buffer_update and the others to wait for that source to complete instead
    229 * (the wait is interruptible).
    230 *
    231 * Additionally this version is rate-limited and will only exit if either the
    232 * buffer is fresh enough (within the limit) - it will do nothing if the buffer
    233 * is fresh enough to begin with -, or if the source/thread that started this
    234 * update is the one that made the update (to prevent endless loops).
    235 *
    236 * Return:
    237 * * 0		- If the update was successfully published and/or the buffer is
    238 *		  fresh enough
    239 * * -EINTR	- If the thread went into the wait-state and was interrupted
    240 * * whatever @buffer_update returns
    241 */
    242int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter,
    243				    struct zfcp_diag_header *const hdr,
    244				    zfcp_diag_update_buffer_func buffer_update)
    245{
    246	unsigned long flags;
    247	int rc;
    248
    249	spin_lock_irqsave(&hdr->access_lock, flags);
    250
    251	for (rc = 0;
    252	     !__zfcp_diag_test_buffer_age_isfresh(adapter->diagnostics, hdr);
    253	     rc = 0) {
    254		rc = __zfcp_diag_update_buffer(adapter, hdr, buffer_update,
    255					       &flags);
    256		if (rc != -EAGAIN)
    257			break;
    258	}
    259
    260	spin_unlock_irqrestore(&hdr->access_lock, flags);
    261
    262	return rc;
    263}