root/fs/afs/fs_probe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. afs_fs_probe_done
  2. afs_fileserver_probe_result
  3. afs_do_probe_fileserver
  4. afs_probe_fileservers
  5. afs_wait_for_fs_probes

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* AFS fileserver 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 static bool afs_fs_probe_done(struct afs_server *server)
  15 {
  16         if (!atomic_dec_and_test(&server->probe_outstanding))
  17                 return false;
  18 
  19         wake_up_var(&server->probe_outstanding);
  20         clear_bit_unlock(AFS_SERVER_FL_PROBING, &server->flags);
  21         wake_up_bit(&server->flags, AFS_SERVER_FL_PROBING);
  22         return true;
  23 }
  24 
  25 /*
  26  * Process the result of probing a fileserver.  This is called after successful
  27  * or failed delivery of an FS.GetCapabilities operation.
  28  */
  29 void afs_fileserver_probe_result(struct afs_call *call)
  30 {
  31         struct afs_addr_list *alist = call->alist;
  32         struct afs_server *server = call->server;
  33         unsigned int server_index = call->server_index;
  34         unsigned int index = call->addr_ix;
  35         unsigned int rtt_us;
  36         bool have_result = false;
  37         int ret = call->error;
  38 
  39         _enter("%pU,%u", &server->uuid, index);
  40 
  41         spin_lock(&server->probe_lock);
  42 
  43         switch (ret) {
  44         case 0:
  45                 server->probe.error = 0;
  46                 goto responded;
  47         case -ECONNABORTED:
  48                 if (!server->probe.responded) {
  49                         server->probe.abort_code = call->abort_code;
  50                         server->probe.error = ret;
  51                 }
  52                 goto responded;
  53         case -ENOMEM:
  54         case -ENONET:
  55                 server->probe.local_failure = true;
  56                 afs_io_error(call, afs_io_error_fs_probe_fail);
  57                 goto out;
  58         case -ECONNRESET: /* Responded, but call expired. */
  59         case -ERFKILL:
  60         case -EADDRNOTAVAIL:
  61         case -ENETUNREACH:
  62         case -EHOSTUNREACH:
  63         case -EHOSTDOWN:
  64         case -ECONNREFUSED:
  65         case -ETIMEDOUT:
  66         case -ETIME:
  67         default:
  68                 clear_bit(index, &alist->responded);
  69                 set_bit(index, &alist->failed);
  70                 if (!server->probe.responded &&
  71                     (server->probe.error == 0 ||
  72                      server->probe.error == -ETIMEDOUT ||
  73                      server->probe.error == -ETIME))
  74                         server->probe.error = ret;
  75                 afs_io_error(call, afs_io_error_fs_probe_fail);
  76                 goto out;
  77         }
  78 
  79 responded:
  80         set_bit(index, &alist->responded);
  81         clear_bit(index, &alist->failed);
  82 
  83         if (call->service_id == YFS_FS_SERVICE) {
  84                 server->probe.is_yfs = true;
  85                 set_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
  86                 alist->addrs[index].srx_service = call->service_id;
  87         } else {
  88                 server->probe.not_yfs = true;
  89                 if (!server->probe.is_yfs) {
  90                         clear_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
  91                         alist->addrs[index].srx_service = call->service_id;
  92                 }
  93         }
  94 
  95         rtt_us = rxrpc_kernel_get_srtt(call->net->socket, call->rxcall);
  96         if (rtt_us < server->probe.rtt) {
  97                 server->probe.rtt = rtt_us;
  98                 alist->preferred = index;
  99                 have_result = true;
 100         }
 101 
 102         smp_wmb(); /* Set rtt before responded. */
 103         server->probe.responded = true;
 104         set_bit(AFS_SERVER_FL_PROBED, &server->flags);
 105 out:
 106         spin_unlock(&server->probe_lock);
 107 
 108         _debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
 109                server_index, index, &alist->addrs[index].transport, rtt_us, ret);
 110 
 111         have_result |= afs_fs_probe_done(server);
 112         if (have_result) {
 113                 server->probe.have_result = true;
 114                 wake_up_var(&server->probe.have_result);
 115                 wake_up_all(&server->probe_wq);
 116         }
 117 }
 118 
 119 /*
 120  * Probe all of a fileserver's addresses to find out the best route and to
 121  * query its capabilities.
 122  */
 123 static int afs_do_probe_fileserver(struct afs_net *net,
 124                                    struct afs_server *server,
 125                                    struct key *key,
 126                                    unsigned int server_index,
 127                                    struct afs_error *_e)
 128 {
 129         struct afs_addr_cursor ac = {
 130                 .index = 0,
 131         };
 132         struct afs_call *call;
 133         bool in_progress = false;
 134 
 135         _enter("%pU", &server->uuid);
 136 
 137         read_lock(&server->fs_lock);
 138         ac.alist = rcu_dereference_protected(server->addresses,
 139                                              lockdep_is_held(&server->fs_lock));
 140         afs_get_addrlist(ac.alist);
 141         read_unlock(&server->fs_lock);
 142 
 143         atomic_set(&server->probe_outstanding, ac.alist->nr_addrs);
 144         memset(&server->probe, 0, sizeof(server->probe));
 145         server->probe.rtt = UINT_MAX;
 146 
 147         for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
 148                 call = afs_fs_get_capabilities(net, server, &ac, key, server_index);
 149                 if (!IS_ERR(call)) {
 150                         afs_put_call(call);
 151                         in_progress = true;
 152                 } else {
 153                         afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code);
 154                 }
 155         }
 156 
 157         if (!in_progress)
 158                 afs_fs_probe_done(server);
 159         afs_put_addrlist(ac.alist);
 160         return in_progress;
 161 }
 162 
 163 /*
 164  * Send off probes to all unprobed servers.
 165  */
 166 int afs_probe_fileservers(struct afs_net *net, struct key *key,
 167                           struct afs_server_list *list)
 168 {
 169         struct afs_server *server;
 170         struct afs_error e;
 171         bool in_progress = false;
 172         int i;
 173 
 174         e.error = 0;
 175         e.responded = false;
 176         for (i = 0; i < list->nr_servers; i++) {
 177                 server = list->servers[i].server;
 178                 if (test_bit(AFS_SERVER_FL_PROBED, &server->flags))
 179                         continue;
 180 
 181                 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags) &&
 182                     afs_do_probe_fileserver(net, server, key, i, &e))
 183                         in_progress = true;
 184         }
 185 
 186         return in_progress ? 0 : e.error;
 187 }
 188 
 189 /*
 190  * Wait for the first as-yet untried fileserver to respond.
 191  */
 192 int afs_wait_for_fs_probes(struct afs_server_list *slist, unsigned long untried)
 193 {
 194         struct wait_queue_entry *waits;
 195         struct afs_server *server;
 196         unsigned int rtt = UINT_MAX;
 197         bool have_responders = false;
 198         int pref = -1, i;
 199 
 200         _enter("%u,%lx", slist->nr_servers, untried);
 201 
 202         /* Only wait for servers that have a probe outstanding. */
 203         for (i = 0; i < slist->nr_servers; i++) {
 204                 if (test_bit(i, &untried)) {
 205                         server = slist->servers[i].server;
 206                         if (!test_bit(AFS_SERVER_FL_PROBING, &server->flags))
 207                                 __clear_bit(i, &untried);
 208                         if (server->probe.responded)
 209                                 have_responders = true;
 210                 }
 211         }
 212         if (have_responders || !untried)
 213                 return 0;
 214 
 215         waits = kmalloc(array_size(slist->nr_servers, sizeof(*waits)), GFP_KERNEL);
 216         if (!waits)
 217                 return -ENOMEM;
 218 
 219         for (i = 0; i < slist->nr_servers; i++) {
 220                 if (test_bit(i, &untried)) {
 221                         server = slist->servers[i].server;
 222                         init_waitqueue_entry(&waits[i], current);
 223                         add_wait_queue(&server->probe_wq, &waits[i]);
 224                 }
 225         }
 226 
 227         for (;;) {
 228                 bool still_probing = false;
 229 
 230                 set_current_state(TASK_INTERRUPTIBLE);
 231                 for (i = 0; i < slist->nr_servers; i++) {
 232                         if (test_bit(i, &untried)) {
 233                                 server = slist->servers[i].server;
 234                                 if (server->probe.responded)
 235                                         goto stop;
 236                                 if (test_bit(AFS_SERVER_FL_PROBING, &server->flags))
 237                                         still_probing = true;
 238                         }
 239                 }
 240 
 241                 if (!still_probing || signal_pending(current))
 242                         goto stop;
 243                 schedule();
 244         }
 245 
 246 stop:
 247         set_current_state(TASK_RUNNING);
 248 
 249         for (i = 0; i < slist->nr_servers; i++) {
 250                 if (test_bit(i, &untried)) {
 251                         server = slist->servers[i].server;
 252                         if (server->probe.responded &&
 253                             server->probe.rtt < rtt) {
 254                                 pref = i;
 255                                 rtt = server->probe.rtt;
 256                         }
 257 
 258                         remove_wait_queue(&server->probe_wq, &waits[i]);
 259                 }
 260         }
 261 
 262         kfree(waits);
 263 
 264         if (pref == -1 && signal_pending(current))
 265                 return -ERESTARTSYS;
 266 
 267         if (pref >= 0)
 268                 slist->preferred = pref;
 269         return 0;
 270 }

/* [<][>][^][v][top][bottom][index][help] */