rx: Remove RX_CALL_BUSY
[openafs.git] / src / afs / afs_analyze.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  */
13 #include <afsconfig.h>
14 #include "afs/param.h"
15
16
17 #include "afs/stds.h"
18 #include "afs/sysincludes.h"    /* Standard vendor system headers */
19
20 #ifndef UKERNEL
21 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
22 #include <net/if.h>
23 #include <netinet/in.h>
24 #endif
25
26 #ifdef AFS_SGI62_ENV
27 #include "h/hashing.h"
28 #endif
29 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV) && !defined(AFS_DARWIN_ENV)
30 #include <netinet/in_var.h>
31 #endif
32 #endif /* !UKERNEL */
33
34 #include "afsincludes.h"        /* Afs-based standard headers */
35 #include "afs/afs_stats.h"      /* afs statistics */
36 #include "afs/afs_util.h"
37 #include "afs/unified_afs.h"
38
39 #if     defined(AFS_SUN5_ENV)
40 #include <inet/led.h>
41 #include <inet/common.h>
42 #include <netinet/ip6.h>
43 #include <inet/ip.h>
44 #endif
45
46 /* shouldn't do it this way, but for now will do */
47 #ifndef ERROR_TABLE_BASE_U
48 #define ERROR_TABLE_BASE_U      (5376L)
49 #endif /* ubik error base define */
50
51 /* shouldn't do it this way, but for now will do */
52 #ifndef ERROR_TABLE_BASE_uae
53 #define ERROR_TABLE_BASE_uae    (49733376L)
54 #endif /* unified afs error base define */
55
56 /* same hack for vlserver error base as for ubik error base */
57 #ifndef ERROR_TABLE_BASE_VL
58 #define ERROR_TABLE_BASE_VL     (363520L)
59 #define VL_NOENT                (363524L)
60 #endif /* vlserver error base define */
61
62
63 int afs_BusyWaitPeriod = 15;    /**< poll period, in seconds */
64
65 afs_int32 hm_retry_RO = 0;      /**< enable read-only hard-mount retry */
66 afs_int32 hm_retry_RW = 0;      /**< enable read-write hard-mount retry */
67 afs_int32 hm_retry_int = 0;     /**< hard-mount retry interval, in seconds */
68
69 #define VSleep(at)      afs_osi_Wait((at)*1000, 0, 0)
70
71
72 int lastcode;
73 #define DIFFERENT 0
74 #define SAME 1
75 #define DUNNO 2
76 /*!
77  * \brief
78  *      Request vldb record to determined if it has changed.
79  *
80  * \retval 0 if the vldb record for a specific volume is different from what
81  *           we have cached -- perhaps the volume has moved.
82  * \retval 1 if the vldb record is the same
83  * \retval 2 if we can't tell if it's the same or not.
84  *
85  * \note
86  *      If 0 returned, the caller will probably start over at the beginning of our
87  *      list of servers for this volume and try to find one that is up.  If
88  *      not 0, we will probably just keep plugging with what we have
89  *      cached.   If we fail to contact the VL server, we  should just keep
90  *      trying with the information we have, rather than failing.
91  */
92 static int
93 VLDB_Same(struct VenusFid *afid, struct vrequest *areq)
94 {
95     struct vrequest *treq = NULL;
96     struct afs_conn *tconn;
97     int i, type = 0;
98     union {
99         struct vldbentry tve;
100         struct nvldbentry ntve;
101         struct uvldbentry utve;
102     } *v;
103     struct volume *tvp;
104     struct cell *tcell;
105     char *bp, tbuf[CVBS];       /* biggest volume id is 2^32, ~ 4*10^9 */
106     unsigned int changed;
107     struct server *(oldhosts[NMAXNSERVERS]);
108     struct rx_connection *rxconn;
109
110     AFS_STATCNT(CheckVLDB);
111     afs_FinalizeReq(areq);
112
113     if ((i = afs_CreateReq(&treq, afs_osi_credp)))
114         return DUNNO;
115     v = afs_osi_Alloc(sizeof(*v));
116     osi_Assert(v != NULL);
117     tcell = afs_GetCell(afid->Cell, READ_LOCK);
118     bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume);
119     do {
120         VSleep(2);              /* Better safe than sorry. */
121         tconn =
122             afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum,
123                              treq, SHARED_LOCK, 0, &rxconn);
124         if (tconn) {
125             if ( tconn->parent->srvr->server->flags & SNO_LHOSTS) {
126                 type = 0;
127                 RX_AFS_GUNLOCK();
128                 i = VL_GetEntryByNameO(rxconn, bp, &v->tve);
129                 RX_AFS_GLOCK();
130             } else if (tconn->parent->srvr->server->flags & SYES_LHOSTS) {
131                 type = 1;
132                 RX_AFS_GUNLOCK();
133                 i = VL_GetEntryByNameN(rxconn, bp, &v->ntve);
134                 RX_AFS_GLOCK();
135             } else {
136                 type = 2;
137                 RX_AFS_GUNLOCK();
138                 i = VL_GetEntryByNameU(rxconn, bp, &v->utve);
139                 RX_AFS_GLOCK();
140                 if (!(tconn->parent->srvr->server->flags & SVLSRV_UUID)) {
141                     if (i == RXGEN_OPCODE) {
142                         type = 1;
143                         RX_AFS_GUNLOCK();
144                         i = VL_GetEntryByNameN(rxconn, bp, &v->ntve);
145                         RX_AFS_GLOCK();
146                         if (i == RXGEN_OPCODE) {
147                             type = 0;
148                             tconn->parent->srvr->server->flags |= SNO_LHOSTS;
149                             RX_AFS_GUNLOCK();
150                             i = VL_GetEntryByNameO(rxconn, bp, &v->tve);
151                             RX_AFS_GLOCK();
152                         } else if (!i)
153                             tconn->parent->srvr->server->flags |= SYES_LHOSTS;
154                     } else if (!i)
155                         tconn->parent->srvr->server->flags |= SVLSRV_UUID;
156                 }
157                 lastcode = i;
158             }
159         } else
160             i = -1;
161     } while (afs_Analyze(tconn, rxconn, i, NULL, treq, -1,      /* no op code for this */
162                          SHARED_LOCK, tcell));
163
164     afs_PutCell(tcell, READ_LOCK);
165     afs_Trace2(afs_iclSetp, CM_TRACE_CHECKVLDB, ICL_TYPE_FID, &afid,
166                ICL_TYPE_INT32, i);
167
168     if (i) {
169         afs_DestroyReq(treq);
170         afs_osi_Free(v, sizeof(*v));
171         return DUNNO;
172     }
173     /* have info, copy into serverHost array */
174     changed = 0;
175     tvp = afs_FindVolume(afid, WRITE_LOCK);
176     if (tvp) {
177         ObtainWriteLock(&tvp->lock, 107);
178         for (i = 0; i < NMAXNSERVERS && tvp->serverHost[i]; i++) {
179             oldhosts[i] = tvp->serverHost[i];
180         }
181         ReleaseWriteLock(&tvp->lock);
182
183         if (type == 2) {
184             LockAndInstallUVolumeEntry(tvp, &v->utve, afid->Cell, tcell, treq);
185         } else if (type == 1) {
186             LockAndInstallNVolumeEntry(tvp, &v->ntve, afid->Cell);
187         } else {
188             LockAndInstallVolumeEntry(tvp, &v->tve, afid->Cell);
189         }
190
191         if (i < NMAXNSERVERS && tvp->serverHost[i]) {
192             changed = 1;
193         }
194         for (--i; !changed && i >= 0; i--) {
195             if (tvp->serverHost[i] != oldhosts[i]) {
196                 changed = 1;    /* also happens if prefs change.  big deal. */
197             }
198         }
199
200         ReleaseWriteLock(&tvp->lock);
201         afs_PutVolume(tvp, WRITE_LOCK);
202     } else {                    /* can't find volume */
203         tvp = afs_GetVolume(afid, treq, WRITE_LOCK);
204         if (tvp) {
205             afs_PutVolume(tvp, WRITE_LOCK);
206             afs_DestroyReq(treq);
207             afs_osi_Free(v, sizeof(*v));
208             return DIFFERENT;
209         } else {
210             afs_DestroyReq(treq);
211             afs_osi_Free(v, sizeof(*v));
212             return DUNNO;
213         }
214     }
215
216     afs_DestroyReq(treq);
217     afs_osi_Free(v, sizeof(*v));
218     return (changed ? DIFFERENT : SAME);
219 }                               /*VLDB_Same */
220
221 /*!
222  * \brief
223  *      Mark a server as invalid for further attempts of this request only.
224  *
225  * \param[in,out] areq  The request record associated with this operation.
226  * \param[in]     afid  The FID of the file involved in the action.  This argument
227  *                      may be null if none was involved.
228  * \param[in,out] tsp   pointer to a server struct for the server we wish to
229  *                      blacklist.
230  *
231  * \returns
232  *      Non-zero value if further servers are available to try,
233  *      zero otherwise.
234  *
235  * \note
236  *      This routine is typically called in situations where we believe
237  *      one server out of a pool may have an error condition.
238  *
239  * \note
240  *      The afs_Conn* routines use the list of invalidated servers to
241  *      avoid reusing a server marked as invalid for this request.
242  */
243 static afs_int32
244 afs_BlackListOnce(struct vrequest *areq, struct VenusFid *afid,
245                   struct server *tsp)
246 {
247     struct volume *tvp;
248     afs_int32 i;
249     afs_int32 serversleft = 0;
250
251     if (afid) {
252         tvp = afs_FindVolume(afid, READ_LOCK);
253         if (tvp) {
254             for (i = 0; i < AFS_MAXHOSTS; i++) {
255                 if (tvp->serverHost[i] == tsp) {
256                     areq->skipserver[i] = 1;
257                 }
258                 if (tvp->serverHost[i] &&
259                     (tvp->serverHost[i]->addr->sa_flags &
260                       SRVR_ISDOWN)) {
261                     areq->skipserver[i] = 1;
262                 }
263             }
264             for (i = 0; i < AFS_MAXHOSTS; i++) {
265                 if (tvp->serverHost[i] && areq->skipserver[i] == 0) {
266                     serversleft = 1;
267                     break;
268                 }
269             }
270             afs_PutVolume(tvp, READ_LOCK);
271             return serversleft;
272         }
273     }
274     return serversleft;
275 }
276
277 /*!
278  * \brief
279  *      Analyze the outcome of an RPC operation, taking whatever support
280  *      actions are necessary.
281  *
282  * \param[in]     afid   The FID of the file involved in the action.  This argument
283  *                       may be null if none was involved.
284  * \param[in]     op     which RPC we are analyzing.
285  * \param[in,out] avp    A pointer to the struct volume, if we already have one.
286  *
287  * \returns
288  *      Non-zero value if the related RPC operation can be retried,
289  *      zero otherwise.
290  *
291  * \note
292  *      This routine is called when we got a network error,
293  *      and discards state if the operation was a data-mutating
294  *      operation.
295  */
296 static int
297 afs_ClearStatus(struct VenusFid *afid, int op, struct volume *avp)
298 {
299     struct volume *tvp = NULL;
300
301     /* if it's not a write op, we have nothing to veto and shouldn't clear. */
302     if (!AFS_STATS_FS_RPCIDXES_ISWRITE(op)) {
303         return 1;
304     }
305
306     if (avp)
307         tvp = avp;
308     else if (afid)
309         tvp = afs_FindVolume(afid, READ_LOCK);
310
311     /* don't assume just discarding will fix if no cached volume */
312     if (tvp) {
313         struct vcache *tvc;
314         ObtainReadLock(&afs_xvcache);
315         if ((tvc = afs_FindVCache(afid, 0, 0))) {
316             ReleaseReadLock(&afs_xvcache);
317             tvc->f.states &= ~(CStatd | CUnique);
318             afs_PutVCache(tvc);
319         } else {
320             ReleaseReadLock(&afs_xvcache);
321         }
322         if (!avp)
323             afs_PutVolume(tvp, READ_LOCK);
324     }
325
326     if (AFS_STATS_FS_RPCIDXES_WRITE_RETRIABLE(op))
327         return 1;
328
329     /* not retriable: we may have raced ourselves */
330     return 0;
331 }
332
333 /*!
334  * \brief
335  *      Print the last errors from the servers for the volume on
336  *      this request.
337  *
338  * \param[in] areq   The request record associated with this operation.
339  * \param[in] afid   The FID of the file involved in the action.  This argument
340  *                   may be null if none was involved.
341  *
342  * \return
343  *      None
344  *
345  * \note
346  *      This routine is called before a hard-mount retry, to display
347  *      the servers by primary address and the errors encountered.
348  */
349 static void
350 afs_PrintServerErrors(struct vrequest *areq, struct VenusFid *afid)
351 {
352     int i;
353     struct volume *tvp;
354     struct srvAddr *sa;
355     afs_uint32 address;
356     char *sep = " (";
357     char *term = "";
358
359     if (afid) {
360         tvp = afs_FindVolume(afid, READ_LOCK);
361         if (tvp) {
362             for (i = 0; i < AFS_MAXHOSTS; i++) {
363                 if (areq->lasterror[i] && tvp->serverHost[i]) {
364                     sa = tvp->serverHost[i]->addr;
365                     if (sa) {
366                         address = ntohl(sa->sa_ip);
367                         afs_warnuser("%s%d.%d.%d.%d code=%d", sep,
368                                      (address >> 24), (address >> 16) & 0xff,
369                                      (address >> 8) & 0xff, (address) & 0xff,
370                                      areq->lasterror[i]);
371                         sep = ", ";
372                         term = ")";
373                     }
374                 }
375             }
376             afs_PutVolume(tvp, READ_LOCK);
377         }
378     }
379     afs_warnuser("%s\n", term);
380 }
381
382 /*!
383  * \brief
384  *      Analyze the outcome of an RPC operation, taking whatever support
385  *      actions are necessary.
386  *
387  * \param[in]     aconn  Ptr to the relevant connection on which the call was made.
388  * \param[in]     acode  The return code experienced by the RPC.
389  * \param[in]     fid    The FID of the file involved in the action.  This argument
390  *                       may be null if none was involved.
391  * \param[in,out] areq   The request record associated with this operation.
392  * \param[in]     op     which RPC we are analyzing.
393  * \param[in]     cellp  pointer to a cell struct.  Must provide either fid or cell.
394  *
395  * \returns
396  *      Non-zero value if the related RPC operation should be retried,
397  *      zero otherwise.
398  *
399  * \note
400  *      This routine is typically called in a do-while loop, causing the
401  *      embedded RPC operation to be called repeatedly if appropriate
402  *      until whatever error condition (if any) is intolerable.
403  *
404  * \note
405  *      The retry return value is used by afs_StoreAllSegments to determine
406  *      if this is a temporary or permanent error.
407  */
408 int
409 afs_Analyze(struct afs_conn *aconn, struct rx_connection *rxconn,
410             afs_int32 acode, struct VenusFid *afid, struct vrequest *areq,
411             int op, afs_int32 locktype, struct cell *cellp)
412 {
413     afs_int32 i;
414     struct srvAddr *sa;
415     struct server *tsp;
416     struct volume *tvp = NULL;
417     afs_int32 shouldRetry = 0;
418     afs_int32 serversleft = 1;
419     struct afs_stats_RPCErrors *aerrP;
420     afs_uint32 address;
421
422     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
423         /* On reconnection, act as connected. XXX: for now.... */
424         /* SXW - This may get very tired after a while. We should try and
425          *       intercept all RPCs before they get here ... */
426         /*printf("afs_Analyze: disconnected\n");*/
427         afs_FinalizeReq(areq);
428         if (aconn) {
429             /* SXW - I suspect that this will _never_ happen - we shouldn't
430              *       get a connection because we're disconnected !!!*/
431             afs_PutConn(aconn, rxconn, locktype);
432         }
433         return 0;
434     }
435
436     AFS_STATCNT(afs_Analyze);
437     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
438                ICL_TYPE_POINTER, aconn, ICL_TYPE_INT32, acode, ICL_TYPE_LONG,
439                areq->uid);
440
441     aerrP = (struct afs_stats_RPCErrors *)0;
442
443     if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS))
444         aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]);
445
446     afs_FinalizeReq(areq);
447     if (!aconn && areq->busyCount) {    /* one RPC or more got VBUSY/VRESTARTING */
448
449         tvp = afs_FindVolume(afid, READ_LOCK);
450         if (tvp) {
451             afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n",
452                          (afid ? afid->Fid.Volume : 0),
453                          (tvp->name ? tvp->name : ""),
454                          ((tvp->serverHost[0]
455                            && tvp->serverHost[0]->cell) ? tvp->serverHost[0]->
456                           cell->cellName : ""));
457
458             for (i = 0; i < AFS_MAXHOSTS; i++) {
459                 if (tvp->status[i] != not_busy && tvp->status[i] != offline) {
460                     tvp->status[i] = not_busy;
461                 }
462                 if (tvp->status[i] == not_busy)
463                     shouldRetry = 1;
464             }
465             afs_PutVolume(tvp, READ_LOCK);
466         } else {
467             afs_warnuser("afs: Waiting for busy volume %u\n",
468                          (afid ? afid->Fid.Volume : 0));
469         }
470
471         if (areq->busyCount > 100) {
472             if (aerrP)
473                 (aerrP->err_Volume)++;
474             areq->volumeError = VOLBUSY;
475             shouldRetry = 0;
476         } else {
477             VSleep(afs_BusyWaitPeriod); /* poll periodically */
478         }
479         if (shouldRetry != 0)
480             areq->busyCount++;
481
482         return shouldRetry;     /* should retry */
483     }
484
485     if (!aconn || !aconn->parent->srvr) {
486         if (!areq->volumeError) {
487             if (aerrP)
488                 (aerrP->err_Network)++;
489             if (hm_retry_int && !(areq->flags & O_NONBLOCK) &&  /* "hard" mount */
490                 ((afid && afs_IsPrimaryCellNum(afid->Cell))
491                  || (cellp && afs_IsPrimaryCell(cellp)))) {
492                 if (!afid) {
493                     static int afs_vl_hm = 0;
494                     int warn = 0;
495                     if (!afs_vl_hm) {
496                         afs_vl_hm = warn = 1;
497                     }
498                     if (warn) {
499                         afs_warnuser
500                             ("afs: hard-mount waiting for a vlserver to return to service\n");
501                     }
502                     VSleep(hm_retry_int);
503                     afs_CheckServers(1, cellp);
504                     shouldRetry = 1;
505
506                     if (warn) {
507                         afs_vl_hm = 0;
508                     }
509                 } else {
510                     static int afs_unknown_vhm = 0;
511                     int warn = 0, vp_vhm = 0;
512
513                     tvp = afs_FindVolume(afid, READ_LOCK);
514                     if (!tvp || (tvp->states & VRO)) {
515                         shouldRetry = hm_retry_RO;
516                     } else {
517                         shouldRetry = hm_retry_RW;
518                     }
519
520                     /* Set 'warn' if we should afs_warnuser. Only let one
521                      * caller call afs_warnuser per hm_retry_int interval per
522                      * volume. */
523                     if (shouldRetry) {
524                         if (tvp) {
525                             if (!(tvp->states & VHardMount)) {
526                                 tvp->states |= VHardMount;
527                                 warn = vp_vhm = 1;
528                             }
529                         } else {
530                             if (!afs_unknown_vhm) {
531                                 afs_unknown_vhm = 1;
532                                 warn = 1;
533                             }
534                         }
535                     }
536
537                     if (tvp)
538                         afs_PutVolume(tvp, READ_LOCK);
539
540                     if (shouldRetry) {
541                         if (warn) {
542                             afs_warnuser
543                                 ("afs: hard-mount waiting for volume %u",
544                                  afid->Fid.Volume);
545                             afs_PrintServerErrors(areq, afid);
546                         }
547
548                         VSleep(hm_retry_int);
549                         afs_CheckServers(1, cellp);
550                         /* clear the black listed servers on this request. */
551                         memset(areq->skipserver, 0, sizeof(areq->skipserver));
552
553                         if (vp_vhm) {
554                             tvp = afs_FindVolume(afid, READ_LOCK);
555                             if (tvp) {
556                                 tvp->states &= ~VHardMount;
557                                 afs_PutVolume(tvp, READ_LOCK);
558                             }
559                         } else if (warn) {
560                             afs_unknown_vhm = 0;
561                         }
562                     }
563                 }
564             } /* if (hm_retry_int ... */
565             else {
566                 if (acode == RX_MSGSIZE)
567                     shouldRetry = 1;
568                 else {
569                     areq->networkError = 1;
570                     /* do not promote to shouldRetry if not already */
571                     if (afs_ClearStatus(afid, op, NULL) == 0)
572                         shouldRetry = 0;
573                 }
574             }
575         }
576         if (aconn) /* simply lacking aconn->server doesn't absolve this */
577             afs_PutConn(aconn, rxconn, locktype);
578         return shouldRetry;
579     }
580
581     /* Find server associated with this connection. */
582     sa = aconn->parent->srvr;
583     tsp = sa->server;
584     address = ntohl(sa->sa_ip);
585
586     /* Before we do anything with acode, make sure we translate it back to
587      * a system error */
588     if ((acode & ~0xff) == ERROR_TABLE_BASE_uae)
589         acode = et_to_sys_error(acode);
590
591     if (acode == 0) {
592         /* If we previously took an error, mark this volume not busy */
593         if (areq->volumeError) {
594             tvp = afs_FindVolume(afid, READ_LOCK);
595             if (tvp) {
596                 for (i = 0; i < AFS_MAXHOSTS; i++) {
597                     if (tvp->serverHost[i] == tsp) {
598                         tvp->status[i] = not_busy;
599                     }
600                 }
601                 afs_PutVolume(tvp, READ_LOCK);
602             }
603         }
604
605         afs_PutConn(aconn, rxconn, locktype);
606         return 0;
607     }
608
609     /* Save the last code of this server on this request. */
610     tvp = afs_FindVolume(afid, READ_LOCK);
611     if (tvp) {
612         for (i = 0; i < AFS_MAXHOSTS; i++) {
613             if (tvp->serverHost[i] == tsp) {
614                 areq->lasterror[i] = acode;
615             }
616         }
617         afs_PutVolume(tvp, READ_LOCK);
618     }
619
620 #ifdef AFS_64BIT_CLIENT
621     if (acode == -455)
622         acode = 455;
623 #endif /* AFS_64BIT_CLIENT */
624     if (acode == RX_MSGSIZE) {
625         shouldRetry = 1;
626         goto out;
627     }
628     if (acode == RX_CALL_TIMEOUT || acode == VNOSERVICE) {
629         serversleft = afs_BlackListOnce(areq, afid, tsp);
630         if (afid)
631             tvp = afs_FindVolume(afid, READ_LOCK);
632         if ((serversleft == 0) && tvp &&
633             ((tvp->states & VRO) || (tvp->states & VBackup))) {
634             shouldRetry = 0;
635         } else {
636             shouldRetry = 1;
637         }
638         if (!afid || !tvp || (tvp->states & VRO))
639             areq->idleError++;
640         else if (afs_ClearStatus(afid, op, tvp) == 0)
641             shouldRetry = 0;
642
643         if (tvp)
644             afs_PutVolume(tvp, READ_LOCK);
645         /* By doing this, we avoid ever marking a server down
646          * in an idle timeout case. That's because the server is
647          * still responding and may only be letting a single vnode
648          * time out. We otherwise risk having the server continually
649          * be marked down, then up, then down again...
650          */
651         goto out;
652     }
653     /* If network troubles, mark server as having bogued out again. */
654     /* VRESTARTING is < 0 because of backward compatibility issues
655      * with 3.4 file servers and older cache managers */
656     if ((acode < 0) && (acode != VRESTARTING)) {
657         afs_ServerDown(sa, acode, rxconn);
658         ForceNewConnections(sa); /* multi homed clients lock:afs_xsrvAddr? */
659         if (aerrP)
660             (aerrP->err_Server)++;
661     }
662
663     if (acode == VBUSY || acode == VRESTARTING) {
664         if (acode == VBUSY) {
665             areq->busyCount++;
666             if (aerrP)
667                 (aerrP->err_VolumeBusies)++;
668         } else
669             areq->busyCount = 1;
670
671         tvp = afs_FindVolume(afid, READ_LOCK);
672         if (tvp) {
673             for (i = 0; i < AFS_MAXHOSTS; i++) {
674                 if (tvp->serverHost[i] == tsp) {
675                     tvp->status[i] = rdwr_busy; /* can't tell which yet */
676                     /* to tell which, have to look at the op code. */
677                 }
678             }
679             afs_PutVolume(tvp, READ_LOCK);
680         } else {
681             afs_warnuser("afs: Waiting for busy volume %u in cell %s (server %d.%d.%d.%d)\n",
682                          (afid ? afid->Fid.Volume : 0), tsp->cell->cellName,
683                          (address >> 24), (address >> 16) & 0xff,
684                          (address >> 8) & 0xff, (address) & 0xff);
685             VSleep(afs_BusyWaitPeriod); /* poll periodically */
686         }
687         shouldRetry = 1;
688         acode = 0;
689     } else if (acode == VICETOKENDEAD
690                || (acode & ~0xff) == ERROR_TABLE_BASE_RXK) {
691         /* any rxkad error is treated as token expiration */
692         struct unixuser *tu;
693         /*
694          * I'm calling these errors protection errors, since they involve
695          * faulty authentication.
696          */
697         if (aerrP)
698             (aerrP->err_Protection)++;
699
700         tu = afs_FindUser(areq->uid, tsp->cell->cellNum, READ_LOCK);
701         if (tu) {
702             if (acode == VICETOKENDEAD) {
703                 aconn->forceConnectFS = 1;
704             } else if (acode == RXKADEXPIRED) {
705                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
706                 aconn->parent->user->states |= UTokensBad;
707                 afs_NotifyUser(tu, UTokensDropped);
708                 afs_warnuser
709                     ("afs: Tokens for user of AFS id %d for cell %s have expired (server %d.%d.%d.%d)\n",
710                      tu->viceId, aconn->parent->srvr->server->cell->cellName,
711                      (address >> 24), (address >> 16) & 0xff,
712                      (address >> 8) & 0xff, (address) & 0xff);
713             } else {
714                 serversleft = afs_BlackListOnce(areq, afid, tsp);
715                 areq->tokenError++;
716
717                 if (serversleft) {
718                     afs_warnuser
719                         ("afs: Tokens for user of AFS id %d for cell %s: rxkad error=%d (server %d.%d.%d.%d)\n",
720                          tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
721                          (address >> 24), (address >> 16) & 0xff,
722                          (address >> 8) & 0xff, (address) & 0xff);
723                     shouldRetry = 1;
724                 } else {
725                     areq->tokenError = 0;
726                     aconn->forceConnectFS = 0;  /* don't check until new tokens set */
727                     aconn->parent->user->states |= UTokensBad;
728                     afs_NotifyUser(tu, UTokensDropped);
729                     afs_warnuser
730                         ("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d, server %d.%d.%d.%d)\n",
731                          tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
732                          (address >> 24), (address >> 16) & 0xff,
733                          (address >> 8) & 0xff, (address) & 0xff);
734                 }
735             }
736             afs_PutUser(tu, READ_LOCK);
737         } else {
738             /* The else case shouldn't be possible and should probably be replaced by a panic? */
739             if (acode == VICETOKENDEAD) {
740                 aconn->forceConnectFS = 1;
741             } else if (acode == RXKADEXPIRED) {
742                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
743                 aconn->parent->user->states |= UTokensBad;
744                 afs_NotifyUser(tu, UTokensDropped);
745                 afs_warnuser
746                     ("afs: Tokens for user %d for cell %s have expired (server %d.%d.%d.%d)\n",
747                      areq->uid, aconn->parent->srvr->server->cell->cellName,
748                      (address >> 24), (address >> 16) & 0xff,
749                      (address >> 8) & 0xff, (address) & 0xff);
750             } else {
751                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
752                 aconn->parent->user->states |= UTokensBad;
753                 afs_NotifyUser(tu, UTokensDropped);
754                 afs_warnuser
755                     ("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d, server %d.%d.%d.%d)\n",
756                      areq->uid, aconn->parent->srvr->server->cell->cellName,
757                      acode,
758                      (address >> 24), (address >> 16) & 0xff,
759                      (address >> 8) & 0xff, (address) & 0xff);
760
761             }
762         }
763         shouldRetry = 1;        /* Try again (as root). */
764     }
765     /* Check for access violation. */
766     else if (acode == EACCES) {
767         /* should mark access error in non-existent per-user global structure */
768         if (aerrP)
769             (aerrP->err_Protection)++;
770         areq->accessError = 1;
771         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
772             areq->permWriteError = 1;
773         shouldRetry = 0;
774     }
775     /* check for ubik errors; treat them like crashed servers */
776     else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U + 255) {
777         afs_ServerDown(sa, acode, rxconn);
778         if (aerrP)
779             (aerrP->err_Server)++;
780         shouldRetry = 1;        /* retryable (maybe one is working) */
781         VSleep(1);              /* just in case */
782     }
783     /* Check for bad volume data base / missing volume. */
784     else if (acode == VSALVAGE || acode == VOFFLINE || acode == VNOVOL
785              || acode == VMOVED) {
786         struct cell *tcell;
787         int same;
788
789         shouldRetry = 1;
790         areq->volumeError = VOLMISSING;
791         if (aerrP)
792             (aerrP->err_Volume)++;
793         if (afid && (tcell = afs_GetCell(afid->Cell, 0))) {
794             same = VLDB_Same(afid, areq);
795             tvp = afs_FindVolume(afid, READ_LOCK);
796             if (tvp) {
797                 for (i = 0; i < AFS_MAXHOSTS && tvp->serverHost[i]; i++) {
798                     if (tvp->serverHost[i] == tsp) {
799                         if (tvp->status[i] == end_not_busy)
800                             tvp->status[i] = offline;
801                         else
802                             tvp->status[i]++;
803                     } else if (!same) {
804                         tvp->status[i] = not_busy;      /* reset the others */
805                     }
806                 }
807                 afs_PutVolume(tvp, READ_LOCK);
808             }
809         }
810     } else if (acode >= ERROR_TABLE_BASE_VL && acode <= ERROR_TABLE_BASE_VL + 255) {    /* vlserver errors */
811         shouldRetry = 0;
812         areq->volumeError = VOLMISSING;
813     } else if (acode >= 0) {
814         if (aerrP)
815             (aerrP->err_Other)++;
816         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
817             areq->permWriteError = 1;
818         shouldRetry = 0;        /* Other random Vice error. */
819     } else if (acode == RX_MSGSIZE) {   /* same meaning as EMSGSIZE... */
820         afs_warnuser
821             ("afs: Path MTU may have been exceeded, retrying (server %d.%d.%d.%d)\n",
822              (address >> 24), (address >> 16) & 0xff,
823              (address >> 8) & 0xff, (address) & 0xff);
824
825         VSleep(1);              /* Just a hack for desperate times. */
826         if (aerrP)
827             (aerrP->err_Other)++;
828         shouldRetry = 1;        /* packet was too big, please retry call */
829     }
830
831     if (acode < 0 && acode != RX_MSGSIZE && acode != VRESTARTING) {
832         /* If we get here, code < 0 and we have network/Server troubles.
833          * areq->networkError is not set here, since we always
834          * retry in case there is another server.  However, if we find
835          * no connection (aconn == 0) we set the networkError flag.
836          */
837         afs_ServerDown(sa, acode, rxconn);
838         if (aerrP)
839             (aerrP->err_Server)++;
840         VSleep(1);              /* Just a hack for desperate times. */
841         shouldRetry = 1;
842     }
843 out:
844     /* now unlock the connection and return */
845     afs_PutConn(aconn, rxconn, locktype);
846     return (shouldRetry);
847 }                               /*afs_Analyze */