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

vl_rotate.c (8720B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Handle vlserver selection and rotation.
      3 *
      4 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/sched.h>
     10#include <linux/sched/signal.h>
     11#include "internal.h"
     12#include "afs_vl.h"
     13
     14/*
     15 * Begin an operation on a volume location server.
     16 */
     17bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cell,
     18				  struct key *key)
     19{
     20	memset(vc, 0, sizeof(*vc));
     21	vc->cell = cell;
     22	vc->key = key;
     23	vc->error = -EDESTADDRREQ;
     24	vc->ac.error = SHRT_MAX;
     25
     26	if (signal_pending(current)) {
     27		vc->error = -EINTR;
     28		vc->flags |= AFS_VL_CURSOR_STOP;
     29		return false;
     30	}
     31
     32	return true;
     33}
     34
     35/*
     36 * Begin iteration through a server list, starting with the last used server if
     37 * possible, or the last recorded good server if not.
     38 */
     39static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
     40{
     41	struct afs_cell *cell = vc->cell;
     42	unsigned int dns_lookup_count;
     43
     44	if (cell->dns_source == DNS_RECORD_UNAVAILABLE ||
     45	    cell->dns_expiry <= ktime_get_real_seconds()) {
     46		dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count);
     47		set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags);
     48		afs_queue_cell(cell, afs_cell_trace_get_queue_dns);
     49
     50		if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
     51			if (wait_var_event_interruptible(
     52				    &cell->dns_lookup_count,
     53				    smp_load_acquire(&cell->dns_lookup_count)
     54				    != dns_lookup_count) < 0) {
     55				vc->error = -ERESTARTSYS;
     56				return false;
     57			}
     58		}
     59
     60		/* Status load is ordered after lookup counter load */
     61		if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
     62			vc->error = -EDESTADDRREQ;
     63			return false;
     64		}
     65	}
     66
     67	read_lock(&cell->vl_servers_lock);
     68	vc->server_list = afs_get_vlserverlist(
     69		rcu_dereference_protected(cell->vl_servers,
     70					  lockdep_is_held(&cell->vl_servers_lock)));
     71	read_unlock(&cell->vl_servers_lock);
     72	if (!vc->server_list->nr_servers)
     73		return false;
     74
     75	vc->untried = (1UL << vc->server_list->nr_servers) - 1;
     76	vc->index = -1;
     77	return true;
     78}
     79
     80/*
     81 * Select the vlserver to use.  May be called multiple times to rotate
     82 * through the vlservers.
     83 */
     84bool afs_select_vlserver(struct afs_vl_cursor *vc)
     85{
     86	struct afs_addr_list *alist;
     87	struct afs_vlserver *vlserver;
     88	struct afs_error e;
     89	u32 rtt;
     90	int error = vc->ac.error, i;
     91
     92	_enter("%lx[%d],%lx[%d],%d,%d",
     93	       vc->untried, vc->index,
     94	       vc->ac.tried, vc->ac.index,
     95	       error, vc->ac.abort_code);
     96
     97	if (vc->flags & AFS_VL_CURSOR_STOP) {
     98		_leave(" = f [stopped]");
     99		return false;
    100	}
    101
    102	vc->nr_iterations++;
    103
    104	/* Evaluate the result of the previous operation, if there was one. */
    105	switch (error) {
    106	case SHRT_MAX:
    107		goto start;
    108
    109	default:
    110	case 0:
    111		/* Success or local failure.  Stop. */
    112		vc->error = error;
    113		vc->flags |= AFS_VL_CURSOR_STOP;
    114		_leave(" = f [okay/local %d]", vc->ac.error);
    115		return false;
    116
    117	case -ECONNABORTED:
    118		/* The far side rejected the operation on some grounds.  This
    119		 * might involve the server being busy or the volume having been moved.
    120		 */
    121		switch (vc->ac.abort_code) {
    122		case AFSVL_IO:
    123		case AFSVL_BADVOLOPER:
    124		case AFSVL_NOMEM:
    125			/* The server went weird. */
    126			vc->error = -EREMOTEIO;
    127			//write_lock(&vc->cell->vl_servers_lock);
    128			//vc->server_list->weird_mask |= 1 << vc->index;
    129			//write_unlock(&vc->cell->vl_servers_lock);
    130			goto next_server;
    131
    132		default:
    133			vc->error = afs_abort_to_error(vc->ac.abort_code);
    134			goto failed;
    135		}
    136
    137	case -ERFKILL:
    138	case -EADDRNOTAVAIL:
    139	case -ENETUNREACH:
    140	case -EHOSTUNREACH:
    141	case -EHOSTDOWN:
    142	case -ECONNREFUSED:
    143	case -ETIMEDOUT:
    144	case -ETIME:
    145		_debug("no conn %d", error);
    146		vc->error = error;
    147		goto iterate_address;
    148
    149	case -ECONNRESET:
    150		_debug("call reset");
    151		vc->error = error;
    152		vc->flags |= AFS_VL_CURSOR_RETRY;
    153		goto next_server;
    154
    155	case -EOPNOTSUPP:
    156		_debug("notsupp");
    157		goto next_server;
    158	}
    159
    160restart_from_beginning:
    161	_debug("restart");
    162	afs_end_cursor(&vc->ac);
    163	afs_put_vlserverlist(vc->cell->net, vc->server_list);
    164	vc->server_list = NULL;
    165	if (vc->flags & AFS_VL_CURSOR_RETRIED)
    166		goto failed;
    167	vc->flags |= AFS_VL_CURSOR_RETRIED;
    168start:
    169	_debug("start");
    170
    171	if (!afs_start_vl_iteration(vc))
    172		goto failed;
    173
    174	error = afs_send_vl_probes(vc->cell->net, vc->key, vc->server_list);
    175	if (error < 0)
    176		goto failed_set_error;
    177
    178pick_server:
    179	_debug("pick [%lx]", vc->untried);
    180
    181	error = afs_wait_for_vl_probes(vc->server_list, vc->untried);
    182	if (error < 0)
    183		goto failed_set_error;
    184
    185	/* Pick the untried server with the lowest RTT. */
    186	vc->index = vc->server_list->preferred;
    187	if (test_bit(vc->index, &vc->untried))
    188		goto selected_server;
    189
    190	vc->index = -1;
    191	rtt = U32_MAX;
    192	for (i = 0; i < vc->server_list->nr_servers; i++) {
    193		struct afs_vlserver *s = vc->server_list->servers[i].server;
    194
    195		if (!test_bit(i, &vc->untried) ||
    196		    !test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
    197			continue;
    198		if (s->probe.rtt < rtt) {
    199			vc->index = i;
    200			rtt = s->probe.rtt;
    201		}
    202	}
    203
    204	if (vc->index == -1)
    205		goto no_more_servers;
    206
    207selected_server:
    208	_debug("use %d", vc->index);
    209	__clear_bit(vc->index, &vc->untried);
    210
    211	/* We're starting on a different vlserver from the list.  We need to
    212	 * check it, find its address list and probe its capabilities before we
    213	 * use it.
    214	 */
    215	ASSERTCMP(vc->ac.alist, ==, NULL);
    216	vlserver = vc->server_list->servers[vc->index].server;
    217	vc->server = vlserver;
    218
    219	_debug("USING VLSERVER: %s", vlserver->name);
    220
    221	read_lock(&vlserver->lock);
    222	alist = rcu_dereference_protected(vlserver->addresses,
    223					  lockdep_is_held(&vlserver->lock));
    224	afs_get_addrlist(alist);
    225	read_unlock(&vlserver->lock);
    226
    227	memset(&vc->ac, 0, sizeof(vc->ac));
    228
    229	if (!vc->ac.alist)
    230		vc->ac.alist = alist;
    231	else
    232		afs_put_addrlist(alist);
    233
    234	vc->ac.index = -1;
    235
    236iterate_address:
    237	ASSERT(vc->ac.alist);
    238	/* Iterate over the current server's address list to try and find an
    239	 * address on which it will respond to us.
    240	 */
    241	if (!afs_iterate_addresses(&vc->ac))
    242		goto next_server;
    243
    244	_debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs);
    245
    246	_leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].transport);
    247	return true;
    248
    249next_server:
    250	_debug("next");
    251	afs_end_cursor(&vc->ac);
    252	goto pick_server;
    253
    254no_more_servers:
    255	/* That's all the servers poked to no good effect.  Try again if some
    256	 * of them were busy.
    257	 */
    258	if (vc->flags & AFS_VL_CURSOR_RETRY)
    259		goto restart_from_beginning;
    260
    261	e.error = -EDESTADDRREQ;
    262	e.responded = false;
    263	for (i = 0; i < vc->server_list->nr_servers; i++) {
    264		struct afs_vlserver *s = vc->server_list->servers[i].server;
    265
    266		if (test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
    267			e.responded = true;
    268		afs_prioritise_error(&e, READ_ONCE(s->probe.error),
    269				     s->probe.abort_code);
    270	}
    271
    272	error = e.error;
    273
    274failed_set_error:
    275	vc->error = error;
    276failed:
    277	vc->flags |= AFS_VL_CURSOR_STOP;
    278	afs_end_cursor(&vc->ac);
    279	_leave(" = f [failed %d]", vc->error);
    280	return false;
    281}
    282
    283/*
    284 * Dump cursor state in the case of the error being EDESTADDRREQ.
    285 */
    286static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
    287{
    288	static int count;
    289	int i;
    290
    291	if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3)
    292		return;
    293	count++;
    294
    295	rcu_read_lock();
    296	pr_notice("EDESTADDR occurred\n");
    297	pr_notice("VC: ut=%lx ix=%u ni=%hu fl=%hx err=%hd\n",
    298		  vc->untried, vc->index, vc->nr_iterations, vc->flags, vc->error);
    299
    300	if (vc->server_list) {
    301		const struct afs_vlserver_list *sl = vc->server_list;
    302		pr_notice("VC: SL nr=%u ix=%u\n",
    303			  sl->nr_servers, sl->index);
    304		for (i = 0; i < sl->nr_servers; i++) {
    305			const struct afs_vlserver *s = sl->servers[i].server;
    306			pr_notice("VC: server %s+%hu fl=%lx E=%hd\n",
    307				  s->name, s->port, s->flags, s->probe.error);
    308			if (s->addresses) {
    309				const struct afs_addr_list *a =
    310					rcu_dereference(s->addresses);
    311				pr_notice("VC:  - nr=%u/%u/%u pf=%u\n",
    312					  a->nr_ipv4, a->nr_addrs, a->max_addrs,
    313					  a->preferred);
    314				pr_notice("VC:  - R=%lx F=%lx\n",
    315					  a->responded, a->failed);
    316				if (a == vc->ac.alist)
    317					pr_notice("VC:  - current\n");
    318			}
    319		}
    320	}
    321
    322	pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
    323		  vc->ac.tried, vc->ac.index, vc->ac.abort_code, vc->ac.error,
    324		  vc->ac.responded, vc->ac.nr_iterations);
    325	rcu_read_unlock();
    326}
    327
    328/*
    329 * Tidy up a volume location server cursor and unlock the vnode.
    330 */
    331int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
    332{
    333	struct afs_net *net = vc->cell->net;
    334
    335	if (vc->error == -EDESTADDRREQ ||
    336	    vc->error == -EADDRNOTAVAIL ||
    337	    vc->error == -ENETUNREACH ||
    338	    vc->error == -EHOSTUNREACH)
    339		afs_vl_dump_edestaddrreq(vc);
    340
    341	afs_end_cursor(&vc->ac);
    342	afs_put_vlserverlist(net, vc->server_list);
    343
    344	if (vc->error == -ECONNABORTED)
    345		vc->error = afs_abort_to_error(vc->ac.abort_code);
    346
    347	return vc->error;
    348}