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_probe.c (7620B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* AFS vlserver probing
      3 *
      4 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#include <linux/sched.h>
      9#include <linux/slab.h>
     10#include "afs_fs.h"
     11#include "internal.h"
     12#include "protocol_yfs.h"
     13
     14
     15/*
     16 * Handle the completion of a set of probes.
     17 */
     18static void afs_finished_vl_probe(struct afs_vlserver *server)
     19{
     20	if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) {
     21		server->rtt = UINT_MAX;
     22		clear_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
     23	}
     24
     25	clear_bit_unlock(AFS_VLSERVER_FL_PROBING, &server->flags);
     26	wake_up_bit(&server->flags, AFS_VLSERVER_FL_PROBING);
     27}
     28
     29/*
     30 * Handle the completion of a probe RPC call.
     31 */
     32static void afs_done_one_vl_probe(struct afs_vlserver *server, bool wake_up)
     33{
     34	if (atomic_dec_and_test(&server->probe_outstanding)) {
     35		afs_finished_vl_probe(server);
     36		wake_up = true;
     37	}
     38
     39	if (wake_up)
     40		wake_up_all(&server->probe_wq);
     41}
     42
     43/*
     44 * Process the result of probing a vlserver.  This is called after successful
     45 * or failed delivery of an VL.GetCapabilities operation.
     46 */
     47void afs_vlserver_probe_result(struct afs_call *call)
     48{
     49	struct afs_addr_list *alist = call->alist;
     50	struct afs_vlserver *server = call->vlserver;
     51	unsigned int server_index = call->server_index;
     52	unsigned int rtt_us = 0;
     53	unsigned int index = call->addr_ix;
     54	bool have_result = false;
     55	int ret = call->error;
     56
     57	_enter("%s,%u,%u,%d,%d", server->name, server_index, index, ret, call->abort_code);
     58
     59	spin_lock(&server->probe_lock);
     60
     61	switch (ret) {
     62	case 0:
     63		server->probe.error = 0;
     64		goto responded;
     65	case -ECONNABORTED:
     66		if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)) {
     67			server->probe.abort_code = call->abort_code;
     68			server->probe.error = ret;
     69		}
     70		goto responded;
     71	case -ENOMEM:
     72	case -ENONET:
     73	case -EKEYEXPIRED:
     74	case -EKEYREVOKED:
     75	case -EKEYREJECTED:
     76		server->probe.flags |= AFS_VLSERVER_PROBE_LOCAL_FAILURE;
     77		if (server->probe.error == 0)
     78			server->probe.error = ret;
     79		trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail);
     80		goto out;
     81	case -ECONNRESET: /* Responded, but call expired. */
     82	case -ERFKILL:
     83	case -EADDRNOTAVAIL:
     84	case -ENETUNREACH:
     85	case -EHOSTUNREACH:
     86	case -EHOSTDOWN:
     87	case -ECONNREFUSED:
     88	case -ETIMEDOUT:
     89	case -ETIME:
     90	default:
     91		clear_bit(index, &alist->responded);
     92		set_bit(index, &alist->failed);
     93		if (!(server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED) &&
     94		    (server->probe.error == 0 ||
     95		     server->probe.error == -ETIMEDOUT ||
     96		     server->probe.error == -ETIME))
     97			server->probe.error = ret;
     98		trace_afs_io_error(call->debug_id, ret, afs_io_error_vl_probe_fail);
     99		goto out;
    100	}
    101
    102responded:
    103	set_bit(index, &alist->responded);
    104	clear_bit(index, &alist->failed);
    105
    106	if (call->service_id == YFS_VL_SERVICE) {
    107		server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS;
    108		set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
    109		alist->addrs[index].srx_service = call->service_id;
    110	} else {
    111		server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS;
    112		if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) {
    113			clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
    114			alist->addrs[index].srx_service = call->service_id;
    115		}
    116	}
    117
    118	if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
    119	    rtt_us < server->probe.rtt) {
    120		server->probe.rtt = rtt_us;
    121		server->rtt = rtt_us;
    122		alist->preferred = index;
    123	}
    124
    125	smp_wmb(); /* Set rtt before responded. */
    126	server->probe.flags |= AFS_VLSERVER_PROBE_RESPONDED;
    127	set_bit(AFS_VLSERVER_FL_PROBED, &server->flags);
    128	set_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags);
    129	have_result = true;
    130out:
    131	spin_unlock(&server->probe_lock);
    132
    133	_debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
    134	       server_index, index, &alist->addrs[index].transport, rtt_us, ret);
    135
    136	afs_done_one_vl_probe(server, have_result);
    137}
    138
    139/*
    140 * Probe all of a vlserver's addresses to find out the best route and to
    141 * query its capabilities.
    142 */
    143static bool afs_do_probe_vlserver(struct afs_net *net,
    144				  struct afs_vlserver *server,
    145				  struct key *key,
    146				  unsigned int server_index,
    147				  struct afs_error *_e)
    148{
    149	struct afs_addr_cursor ac = {
    150		.index = 0,
    151	};
    152	struct afs_call *call;
    153	bool in_progress = false;
    154
    155	_enter("%s", server->name);
    156
    157	read_lock(&server->lock);
    158	ac.alist = rcu_dereference_protected(server->addresses,
    159					     lockdep_is_held(&server->lock));
    160	read_unlock(&server->lock);
    161
    162	atomic_set(&server->probe_outstanding, ac.alist->nr_addrs);
    163	memset(&server->probe, 0, sizeof(server->probe));
    164	server->probe.rtt = UINT_MAX;
    165
    166	for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
    167		call = afs_vl_get_capabilities(net, &ac, key, server,
    168					       server_index);
    169		if (!IS_ERR(call)) {
    170			afs_put_call(call);
    171			in_progress = true;
    172		} else {
    173			afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code);
    174			afs_done_one_vl_probe(server, false);
    175		}
    176	}
    177
    178	return in_progress;
    179}
    180
    181/*
    182 * Send off probes to all unprobed servers.
    183 */
    184int afs_send_vl_probes(struct afs_net *net, struct key *key,
    185		       struct afs_vlserver_list *vllist)
    186{
    187	struct afs_vlserver *server;
    188	struct afs_error e;
    189	bool in_progress = false;
    190	int i;
    191
    192	e.error = 0;
    193	e.responded = false;
    194	for (i = 0; i < vllist->nr_servers; i++) {
    195		server = vllist->servers[i].server;
    196		if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags))
    197			continue;
    198
    199		if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, &server->flags) &&
    200		    afs_do_probe_vlserver(net, server, key, i, &e))
    201			in_progress = true;
    202	}
    203
    204	return in_progress ? 0 : e.error;
    205}
    206
    207/*
    208 * Wait for the first as-yet untried server to respond.
    209 */
    210int afs_wait_for_vl_probes(struct afs_vlserver_list *vllist,
    211			   unsigned long untried)
    212{
    213	struct wait_queue_entry *waits;
    214	struct afs_vlserver *server;
    215	unsigned int rtt = UINT_MAX, rtt_s;
    216	bool have_responders = false;
    217	int pref = -1, i;
    218
    219	_enter("%u,%lx", vllist->nr_servers, untried);
    220
    221	/* Only wait for servers that have a probe outstanding. */
    222	for (i = 0; i < vllist->nr_servers; i++) {
    223		if (test_bit(i, &untried)) {
    224			server = vllist->servers[i].server;
    225			if (!test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
    226				__clear_bit(i, &untried);
    227			if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)
    228				have_responders = true;
    229		}
    230	}
    231	if (have_responders || !untried)
    232		return 0;
    233
    234	waits = kmalloc(array_size(vllist->nr_servers, sizeof(*waits)), GFP_KERNEL);
    235	if (!waits)
    236		return -ENOMEM;
    237
    238	for (i = 0; i < vllist->nr_servers; i++) {
    239		if (test_bit(i, &untried)) {
    240			server = vllist->servers[i].server;
    241			init_waitqueue_entry(&waits[i], current);
    242			add_wait_queue(&server->probe_wq, &waits[i]);
    243		}
    244	}
    245
    246	for (;;) {
    247		bool still_probing = false;
    248
    249		set_current_state(TASK_INTERRUPTIBLE);
    250		for (i = 0; i < vllist->nr_servers; i++) {
    251			if (test_bit(i, &untried)) {
    252				server = vllist->servers[i].server;
    253				if (server->probe.flags & AFS_VLSERVER_PROBE_RESPONDED)
    254					goto stop;
    255				if (test_bit(AFS_VLSERVER_FL_PROBING, &server->flags))
    256					still_probing = true;
    257			}
    258		}
    259
    260		if (!still_probing || signal_pending(current))
    261			goto stop;
    262		schedule();
    263	}
    264
    265stop:
    266	set_current_state(TASK_RUNNING);
    267
    268	for (i = 0; i < vllist->nr_servers; i++) {
    269		if (test_bit(i, &untried)) {
    270			server = vllist->servers[i].server;
    271			rtt_s = READ_ONCE(server->rtt);
    272			if (test_bit(AFS_VLSERVER_FL_RESPONDING, &server->flags) &&
    273			    rtt_s < rtt) {
    274				pref = i;
    275				rtt = rtt_s;
    276			}
    277
    278			remove_wait_queue(&server->probe_wq, &waits[i]);
    279		}
    280	}
    281
    282	kfree(waits);
    283
    284	if (pref == -1 && signal_pending(current))
    285		return -ERESTARTSYS;
    286
    287	if (pref >= 0)
    288		vllist->preferred = pref;
    289
    290	_leave(" = 0 [%u]", pref);
    291	return 0;
    292}