libafs: initialize hard mount last errors
[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;
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_InitReq(&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_osi_Free(v, sizeof(*v));
170         return DUNNO;
171     }
172     /* have info, copy into serverHost array */
173     changed = 0;
174     tvp = afs_FindVolume(afid, WRITE_LOCK);
175     if (tvp) {
176         ObtainWriteLock(&tvp->lock, 107);
177         for (i = 0; i < NMAXNSERVERS && tvp->serverHost[i]; i++) {
178             oldhosts[i] = tvp->serverHost[i];
179         }
180         ReleaseWriteLock(&tvp->lock);
181
182         if (type == 2) {
183             LockAndInstallUVolumeEntry(tvp, &v->utve, afid->Cell, tcell, &treq);
184         } else if (type == 1) {
185             LockAndInstallNVolumeEntry(tvp, &v->ntve, afid->Cell);
186         } else {
187             LockAndInstallVolumeEntry(tvp, &v->tve, afid->Cell);
188         }
189
190         if (i < NMAXNSERVERS && tvp->serverHost[i]) {
191             changed = 1;
192         }
193         for (--i; !changed && i >= 0; i--) {
194             if (tvp->serverHost[i] != oldhosts[i]) {
195                 changed = 1;    /* also happens if prefs change.  big deal. */
196             }
197         }
198
199         ReleaseWriteLock(&tvp->lock);
200         afs_PutVolume(tvp, WRITE_LOCK);
201     } else {                    /* can't find volume */
202         tvp = afs_GetVolume(afid, &treq, WRITE_LOCK);
203         if (tvp) {
204             afs_PutVolume(tvp, WRITE_LOCK);
205             afs_osi_Free(v, sizeof(*v));
206             return DIFFERENT;
207         } else {
208             afs_osi_Free(v, sizeof(*v));
209             return DUNNO;
210         }
211     }
212
213     afs_osi_Free(v, sizeof(*v));
214     return (changed ? DIFFERENT : SAME);
215 }                               /*VLDB_Same */
216
217 /*!
218  * \brief
219  *      Mark a server as invalid for further attempts of this request only.
220  *
221  * \param[in,out] areq  The request record associated with this operation.
222  * \param[in]     afid  The FID of the file involved in the action.  This argument
223  *                      may be null if none was involved.
224  * \param[in,out] tsp   pointer to a server struct for the server we wish to
225  *                      blacklist.
226  *
227  * \returns
228  *      Non-zero value if further servers are available to try,
229  *      zero otherwise.
230  *
231  * \note
232  *      This routine is typically called in situations where we believe
233  *      one server out of a pool may have an error condition.
234  *
235  * \note
236  *      The afs_Conn* routines use the list of invalidated servers to
237  *      avoid reusing a server marked as invalid for this request.
238  */
239 static afs_int32
240 afs_BlackListOnce(struct vrequest *areq, struct VenusFid *afid,
241                   struct server *tsp)
242 {
243     struct volume *tvp;
244     afs_int32 i;
245     afs_int32 serversleft = 0;
246
247     if (afid) {
248         tvp = afs_FindVolume(afid, READ_LOCK);
249         if (tvp) {
250             for (i = 0; i < AFS_MAXHOSTS; i++) {
251                 if (tvp->serverHost[i] == tsp) {
252                     areq->skipserver[i] = 1;
253                 }
254                 if (tvp->serverHost[i] &&
255                     (tvp->serverHost[i]->addr->sa_flags &
256                       SRVR_ISDOWN)) {
257                     areq->skipserver[i] = 1;
258                 }
259             }
260             for (i = 0; i < AFS_MAXHOSTS; i++) {
261                 if (tvp->serverHost[i] && areq->skipserver[i] == 0) {
262                     serversleft = 1;
263                     break;
264                 }
265             }
266             afs_PutVolume(tvp, READ_LOCK);
267             return serversleft;
268         }
269     }
270     return serversleft;
271 }
272
273 /*!
274  * \brief
275  *      Analyze the outcome of an RPC operation, taking whatever support
276  *      actions are necessary.
277  *
278  * \param[in]     afid   The FID of the file involved in the action.  This argument
279  *                       may be null if none was involved.
280  * \param[in]     op     which RPC we are analyzing.
281  * \param[in,out] avp    A pointer to the struct volume, if we already have one.
282  *
283  * \returns
284  *      Non-zero value if the related RPC operation can be retried,
285  *      zero otherwise.
286  *
287  * \note
288  *      This routine is called when we got a network error,
289  *      and discards state if the operation was a data-mutating
290  *      operation.
291  */
292 static int
293 afs_ClearStatus(struct VenusFid *afid, int op, struct volume *avp)
294 {
295     struct volume *tvp = NULL;
296
297     /* if it's not a write op, we have nothing to veto and shouldn't clear. */
298     if (!AFS_STATS_FS_RPCIDXES_ISWRITE(op)) {
299         return 1;
300     }
301
302     if (avp)
303         tvp = avp;
304     else if (afid)
305         tvp = afs_FindVolume(afid, READ_LOCK);
306
307     /* don't assume just discarding will fix if no cached volume */
308     if (tvp) {
309         struct vcache *tvc;
310         ObtainReadLock(&afs_xvcache);
311         if ((tvc = afs_FindVCache(afid, 0, 0))) {
312             ReleaseReadLock(&afs_xvcache);
313             tvc->f.states &= ~(CStatd | CUnique);
314             afs_PutVCache(tvc);
315         } else {
316             ReleaseReadLock(&afs_xvcache);
317         }
318         if (!avp)
319             afs_PutVolume(tvp, READ_LOCK);
320     }
321
322     if (AFS_STATS_FS_RPCIDXES_WRITE_RETRIABLE(op))
323         return 1;
324
325     /* not retriable: we may have raced ourselves */
326     return 0;
327 }
328
329 /*!
330  * \brief
331  *      Print the last errors from the servers for the volume on
332  *      this request.
333  *
334  * \param[in] areq   The request record associated with this operation.
335  * \param[in] afid   The FID of the file involved in the action.  This argument
336  *                   may be null if none was involved.
337  *
338  * \return
339  *      None
340  *
341  * \note
342  *      This routine is called before a hard-mount retry, to display
343  *      the servers by primary address and the errors encountered.
344  */
345 static void
346 afs_PrintServerErrors(struct vrequest *areq, struct VenusFid *afid)
347 {
348     int i;
349     struct volume *tvp;
350     struct srvAddr *sa;
351     afs_uint32 address;
352     char *sep = " (";
353     char *term = "";
354
355     if (afid) {
356         tvp = afs_FindVolume(afid, READ_LOCK);
357         if (tvp) {
358             for (i = 0; i < AFS_MAXHOSTS; i++) {
359                 if (areq->lasterror[i] && tvp->serverHost[i]) {
360                     sa = tvp->serverHost[i]->addr;
361                     if (sa) {
362                         address = ntohl(sa->sa_ip);
363                         afs_warnuser("%s%d.%d.%d.%d code=%d", sep,
364                                      (address >> 24), (address >> 16) & 0xff,
365                                      (address >> 8) & 0xff, (address) & 0xff,
366                                      areq->lasterror[i]);
367                         sep = ", ";
368                         term = ")";
369                     }
370                 }
371             }
372             afs_PutVolume(tvp, READ_LOCK);
373         }
374     }
375     afs_warnuser("%s\n", term);
376 }
377
378 /*!
379  * \brief
380  *      Analyze the outcome of an RPC operation, taking whatever support
381  *      actions are necessary.
382  *
383  * \param[in]     aconn  Ptr to the relevant connection on which the call was made.
384  * \param[in]     acode  The return code experienced by the RPC.
385  * \param[in]     fid    The FID of the file involved in the action.  This argument
386  *                       may be null if none was involved.
387  * \param[in,out] areq   The request record associated with this operation.
388  * \param[in]     op     which RPC we are analyzing.
389  * \param[in]     cellp  pointer to a cell struct.  Must provide either fid or cell.
390  *
391  * \returns
392  *      Non-zero value if the related RPC operation should be retried,
393  *      zero otherwise.
394  *
395  * \note
396  *      This routine is typically called in a do-while loop, causing the
397  *      embedded RPC operation to be called repeatedly if appropriate
398  *      until whatever error condition (if any) is intolerable.
399  *
400  * \note
401  *      The retry return value is used by afs_StoreAllSegments to determine
402  *      if this is a temporary or permanent error.
403  */
404 int
405 afs_Analyze(struct afs_conn *aconn, struct rx_connection *rxconn,
406             afs_int32 acode, struct VenusFid *afid, struct vrequest *areq,
407             int op, afs_int32 locktype, struct cell *cellp)
408 {
409     afs_int32 i;
410     struct srvAddr *sa;
411     struct server *tsp;
412     struct volume *tvp = NULL;
413     afs_int32 shouldRetry = 0;
414     afs_int32 serversleft = 1;
415     struct afs_stats_RPCErrors *aerrP;
416     afs_uint32 address;
417
418     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
419         /* On reconnection, act as connected. XXX: for now.... */
420         /* SXW - This may get very tired after a while. We should try and
421          *       intercept all RPCs before they get here ... */
422         /*printf("afs_Analyze: disconnected\n");*/
423         afs_FinalizeReq(areq);
424         if (aconn) {
425             /* SXW - I suspect that this will _never_ happen - we shouldn't
426              *       get a connection because we're disconnected !!!*/
427             afs_PutConn(aconn, rxconn, locktype);
428         }
429         return 0;
430     }
431
432     AFS_STATCNT(afs_Analyze);
433     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
434                ICL_TYPE_POINTER, aconn, ICL_TYPE_INT32, acode, ICL_TYPE_LONG,
435                areq->uid);
436
437     aerrP = (struct afs_stats_RPCErrors *)0;
438
439     if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS))
440         aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]);
441
442     afs_FinalizeReq(areq);
443     if (!aconn && areq->busyCount) {    /* one RPC or more got VBUSY/VRESTARTING */
444
445         tvp = afs_FindVolume(afid, READ_LOCK);
446         if (tvp) {
447             afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n",
448                          (afid ? afid->Fid.Volume : 0),
449                          (tvp->name ? tvp->name : ""),
450                          ((tvp->serverHost[0]
451                            && tvp->serverHost[0]->cell) ? tvp->serverHost[0]->
452                           cell->cellName : ""));
453
454             for (i = 0; i < AFS_MAXHOSTS; i++) {
455                 if (tvp->status[i] != not_busy && tvp->status[i] != offline) {
456                     tvp->status[i] = not_busy;
457                 }
458                 if (tvp->status[i] == not_busy)
459                     shouldRetry = 1;
460             }
461             afs_PutVolume(tvp, READ_LOCK);
462         } else {
463             afs_warnuser("afs: Waiting for busy volume %u\n",
464                          (afid ? afid->Fid.Volume : 0));
465         }
466
467         if (areq->busyCount > 100) {
468             if (aerrP)
469                 (aerrP->err_Volume)++;
470             areq->volumeError = VOLBUSY;
471             shouldRetry = 0;
472         } else {
473             VSleep(afs_BusyWaitPeriod); /* poll periodically */
474         }
475         if (shouldRetry != 0)
476             areq->busyCount++;
477
478         return shouldRetry;     /* should retry */
479     }
480
481     if (!aconn || !aconn->parent->srvr) {
482         if (!areq->volumeError) {
483             if (aerrP)
484                 (aerrP->err_Network)++;
485             if (hm_retry_int && !(areq->flags & O_NONBLOCK) &&  /* "hard" mount */
486                 ((afid && afs_IsPrimaryCellNum(afid->Cell))
487                  || (cellp && afs_IsPrimaryCell(cellp)))) {
488                 if (!afid) {
489                     static int afs_vl_hm = 0;
490                     int warn = 0;
491                     if (!afs_vl_hm) {
492                         afs_vl_hm = warn = 1;
493                     }
494                     if (warn) {
495                         afs_warnuser
496                             ("afs: hard-mount waiting for a vlserver to return to service\n");
497                     }
498                     VSleep(hm_retry_int);
499                     afs_CheckServers(1, cellp);
500                     shouldRetry = 1;
501
502                     if (warn) {
503                         afs_vl_hm = 0;
504                     }
505                 } else {
506                     static int afs_unknown_vhm = 0;
507                     int warn = 0, vp_vhm = 0;
508
509                     tvp = afs_FindVolume(afid, READ_LOCK);
510                     if (!tvp || (tvp->states & VRO)) {
511                         shouldRetry = hm_retry_RO;
512                     } else {
513                         shouldRetry = hm_retry_RW;
514                     }
515
516                     /* Set 'warn' if we should afs_warnuser. Only let one
517                      * caller call afs_warnuser per hm_retry_int interval per
518                      * volume. */
519                     if (shouldRetry) {
520                         if (tvp) {
521                             if (!(tvp->states & VHardMount)) {
522                                 tvp->states |= VHardMount;
523                                 warn = vp_vhm = 1;
524                             }
525                         } else {
526                             if (!afs_unknown_vhm) {
527                                 afs_unknown_vhm = 1;
528                                 warn = 1;
529                             }
530                         }
531                     }
532
533                     if (tvp)
534                         afs_PutVolume(tvp, READ_LOCK);
535
536                     if (shouldRetry) {
537                         if (warn) {
538                             afs_warnuser
539                                 ("afs: hard-mount waiting for volume %u",
540                                  afid->Fid.Volume);
541                             afs_PrintServerErrors(areq, afid);
542                         }
543
544                         VSleep(hm_retry_int);
545                         afs_CheckServers(1, cellp);
546                         /* clear the black listed servers on this request. */
547                         memset(areq->skipserver, 0, sizeof(areq->skipserver));
548
549                         if (vp_vhm) {
550                             tvp = afs_FindVolume(afid, READ_LOCK);
551                             if (tvp) {
552                                 tvp->states &= ~VHardMount;
553                                 afs_PutVolume(tvp, READ_LOCK);
554                             }
555                         } else if (warn) {
556                             afs_unknown_vhm = 0;
557                         }
558                     }
559                 }
560             } /* if (hm_retry_int ... */
561             else {
562                 if (acode == RX_MSGSIZE)
563                     shouldRetry = 1;
564                 else {
565                     areq->networkError = 1;
566                     /* do not promote to shouldRetry if not already */
567                     if (afs_ClearStatus(afid, op, NULL) == 0)
568                         shouldRetry = 0;
569                 }
570             }
571         }
572         if (aconn) /* simply lacking aconn->server doesn't absolve this */
573             afs_PutConn(aconn, rxconn, locktype);
574         return shouldRetry;
575     }
576
577     /* Find server associated with this connection. */
578     sa = aconn->parent->srvr;
579     tsp = sa->server;
580     address = ntohl(sa->sa_ip);
581
582     /* Before we do anything with acode, make sure we translate it back to
583      * a system error */
584     if ((acode & ~0xff) == ERROR_TABLE_BASE_uae)
585         acode = et_to_sys_error(acode);
586
587     if (acode == 0) {
588         /* If we previously took an error, mark this volume not busy */
589         if (areq->volumeError) {
590             tvp = afs_FindVolume(afid, READ_LOCK);
591             if (tvp) {
592                 for (i = 0; i < AFS_MAXHOSTS; i++) {
593                     if (tvp->serverHost[i] == tsp) {
594                         tvp->status[i] = not_busy;
595                     }
596                 }
597                 afs_PutVolume(tvp, READ_LOCK);
598             }
599         }
600
601         afs_PutConn(aconn, rxconn, locktype);
602         return 0;
603     }
604
605     /* Save the last code of this server on this request. */
606     tvp = afs_FindVolume(afid, READ_LOCK);
607     if (tvp) {
608         for (i = 0; i < AFS_MAXHOSTS; i++) {
609             if (tvp->serverHost[i] == tsp) {
610                 areq->lasterror[i] = acode;
611             }
612         }
613         afs_PutVolume(tvp, READ_LOCK);
614     }
615
616 #ifdef AFS_64BIT_CLIENT
617     if (acode == -455)
618         acode = 455;
619 #endif /* AFS_64BIT_CLIENT */
620     if (acode == RX_MSGSIZE || acode == RX_CALL_BUSY) {
621         shouldRetry = 1;
622         goto out;
623     }
624     if (acode == RX_CALL_TIMEOUT || acode == RX_CALL_IDLE || acode == VNOSERVICE) {
625         serversleft = afs_BlackListOnce(areq, afid, tsp);
626         if (afid)
627             tvp = afs_FindVolume(afid, READ_LOCK);
628         if ((serversleft == 0) && tvp &&
629             ((tvp->states & VRO) || (tvp->states & VBackup))) {
630             shouldRetry = 0;
631         } else {
632             shouldRetry = 1;
633         }
634         if (!afid || !tvp || (tvp->states & VRO))
635             areq->idleError++;
636         else if (afs_ClearStatus(afid, op, tvp) == 0)
637             shouldRetry = 0;
638
639         if (tvp)
640             afs_PutVolume(tvp, READ_LOCK);
641         /* By doing this, we avoid ever marking a server down
642          * in an idle timeout case. That's because the server is
643          * still responding and may only be letting a single vnode
644          * time out. We otherwise risk having the server continually
645          * be marked down, then up, then down again...
646          */
647         goto out;
648     }
649     /* If network troubles, mark server as having bogued out again. */
650     /* VRESTARTING is < 0 because of backward compatibility issues
651      * with 3.4 file servers and older cache managers */
652     if ((acode < 0) && (acode != VRESTARTING)) {
653         afs_ServerDown(sa, acode, rxconn);
654         ForceNewConnections(sa); /* multi homed clients lock:afs_xsrvAddr? */
655         if (aerrP)
656             (aerrP->err_Server)++;
657     }
658
659     if (acode == VBUSY || acode == VRESTARTING) {
660         if (acode == VBUSY) {
661             areq->busyCount++;
662             if (aerrP)
663                 (aerrP->err_VolumeBusies)++;
664         } else
665             areq->busyCount = 1;
666
667         tvp = afs_FindVolume(afid, READ_LOCK);
668         if (tvp) {
669             for (i = 0; i < AFS_MAXHOSTS; i++) {
670                 if (tvp->serverHost[i] == tsp) {
671                     tvp->status[i] = rdwr_busy; /* can't tell which yet */
672                     /* to tell which, have to look at the op code. */
673                 }
674             }
675             afs_PutVolume(tvp, READ_LOCK);
676         } else {
677             afs_warnuser("afs: Waiting for busy volume %u in cell %s (server %d.%d.%d.%d)\n",
678                          (afid ? afid->Fid.Volume : 0), tsp->cell->cellName,
679                          (address >> 24), (address >> 16) & 0xff,
680                          (address >> 8) & 0xff, (address) & 0xff);
681             VSleep(afs_BusyWaitPeriod); /* poll periodically */
682         }
683         shouldRetry = 1;
684         acode = 0;
685     } else if (acode == VICETOKENDEAD
686                || (acode & ~0xff) == ERROR_TABLE_BASE_RXK) {
687         /* any rxkad error is treated as token expiration */
688         struct unixuser *tu;
689         /*
690          * I'm calling these errors protection errors, since they involve
691          * faulty authentication.
692          */
693         if (aerrP)
694             (aerrP->err_Protection)++;
695
696         tu = afs_FindUser(areq->uid, tsp->cell->cellNum, READ_LOCK);
697         if (tu) {
698             if (acode == VICETOKENDEAD) {
699                 aconn->forceConnectFS = 1;
700             } else if (acode == RXKADEXPIRED) {
701                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
702                 aconn->parent->user->states |= UTokensBad;
703                 afs_NotifyUser(tu, UTokensDropped);
704                 afs_warnuser
705                     ("afs: Tokens for user of AFS id %d for cell %s have expired (server %d.%d.%d.%d)\n",
706                      tu->viceId, aconn->parent->srvr->server->cell->cellName,
707                      (address >> 24), (address >> 16) & 0xff,
708                      (address >> 8) & 0xff, (address) & 0xff);
709             } else {
710                 serversleft = afs_BlackListOnce(areq, afid, tsp);
711                 areq->tokenError++;
712
713                 if (serversleft) {
714                     afs_warnuser
715                         ("afs: Tokens for user of AFS id %d for cell %s: rxkad error=%d (server %d.%d.%d.%d)\n",
716                          tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
717                          (address >> 24), (address >> 16) & 0xff,
718                          (address >> 8) & 0xff, (address) & 0xff);
719                     shouldRetry = 1;
720                 } else {
721                     areq->tokenError = 0;
722                     aconn->forceConnectFS = 0;  /* don't check until new tokens set */
723                     aconn->parent->user->states |= UTokensBad;
724                     afs_NotifyUser(tu, UTokensDropped);
725                     afs_warnuser
726                         ("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d, server %d.%d.%d.%d)\n",
727                          tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
728                          (address >> 24), (address >> 16) & 0xff,
729                          (address >> 8) & 0xff, (address) & 0xff);
730                 }
731             }
732             afs_PutUser(tu, READ_LOCK);
733         } else {
734             /* The else case shouldn't be possible and should probably be replaced by a panic? */
735             if (acode == VICETOKENDEAD) {
736                 aconn->forceConnectFS = 1;
737             } else if (acode == RXKADEXPIRED) {
738                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
739                 aconn->parent->user->states |= UTokensBad;
740                 afs_NotifyUser(tu, UTokensDropped);
741                 afs_warnuser
742                     ("afs: Tokens for user %d for cell %s have expired (server %d.%d.%d.%d)\n",
743                      areq->uid, aconn->parent->srvr->server->cell->cellName,
744                      (address >> 24), (address >> 16) & 0xff,
745                      (address >> 8) & 0xff, (address) & 0xff);
746             } else {
747                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
748                 aconn->parent->user->states |= UTokensBad;
749                 afs_NotifyUser(tu, UTokensDropped);
750                 afs_warnuser
751                     ("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d, server %d.%d.%d.%d)\n",
752                      areq->uid, aconn->parent->srvr->server->cell->cellName,
753                      acode,
754                      (address >> 24), (address >> 16) & 0xff,
755                      (address >> 8) & 0xff, (address) & 0xff);
756
757             }
758         }
759         shouldRetry = 1;        /* Try again (as root). */
760     }
761     /* Check for access violation. */
762     else if (acode == EACCES) {
763         /* should mark access error in non-existent per-user global structure */
764         if (aerrP)
765             (aerrP->err_Protection)++;
766         areq->accessError = 1;
767         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
768             areq->permWriteError = 1;
769         shouldRetry = 0;
770     }
771     /* check for ubik errors; treat them like crashed servers */
772     else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U + 255) {
773         afs_ServerDown(sa, acode, rxconn);
774         if (aerrP)
775             (aerrP->err_Server)++;
776         shouldRetry = 1;        /* retryable (maybe one is working) */
777         VSleep(1);              /* just in case */
778     }
779     /* Check for bad volume data base / missing volume. */
780     else if (acode == VSALVAGE || acode == VOFFLINE || acode == VNOVOL
781              || acode == VMOVED) {
782         struct cell *tcell;
783         int same;
784
785         shouldRetry = 1;
786         areq->volumeError = VOLMISSING;
787         if (aerrP)
788             (aerrP->err_Volume)++;
789         if (afid && (tcell = afs_GetCell(afid->Cell, 0))) {
790             same = VLDB_Same(afid, areq);
791             tvp = afs_FindVolume(afid, READ_LOCK);
792             if (tvp) {
793                 for (i = 0; i < AFS_MAXHOSTS && tvp->serverHost[i]; i++) {
794                     if (tvp->serverHost[i] == tsp) {
795                         if (tvp->status[i] == end_not_busy)
796                             tvp->status[i] = offline;
797                         else
798                             tvp->status[i]++;
799                     } else if (!same) {
800                         tvp->status[i] = not_busy;      /* reset the others */
801                     }
802                 }
803                 afs_PutVolume(tvp, READ_LOCK);
804             }
805         }
806     } else if (acode >= ERROR_TABLE_BASE_VL && acode <= ERROR_TABLE_BASE_VL + 255) {    /* vlserver errors */
807         shouldRetry = 0;
808         areq->volumeError = VOLMISSING;
809     } else if (acode >= 0) {
810         if (aerrP)
811             (aerrP->err_Other)++;
812         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
813             areq->permWriteError = 1;
814         shouldRetry = 0;        /* Other random Vice error. */
815     } else if (acode == RX_MSGSIZE) {   /* same meaning as EMSGSIZE... */
816         afs_warnuser
817             ("afs: Path MTU may have been exceeded, retrying (server %d.%d.%d.%d)\n",
818              (address >> 24), (address >> 16) & 0xff,
819              (address >> 8) & 0xff, (address) & 0xff);
820
821         VSleep(1);              /* Just a hack for desperate times. */
822         if (aerrP)
823             (aerrP->err_Other)++;
824         shouldRetry = 1;        /* packet was too big, please retry call */
825     }
826
827     if (acode < 0 && acode != RX_MSGSIZE && acode != VRESTARTING) {
828         /* If we get here, code < 0 and we have network/Server troubles.
829          * areq->networkError is not set here, since we always
830          * retry in case there is another server.  However, if we find
831          * no connection (aconn == 0) we set the networkError flag.
832          */
833         afs_ServerDown(sa, acode, rxconn);
834         if (aerrP)
835             (aerrP->err_Server)++;
836         VSleep(1);              /* Just a hack for desperate times. */
837         shouldRetry = 1;
838     }
839 out:
840     /* now unlock the connection and return */
841     afs_PutConn(aconn, rxconn, locktype);
842     return (shouldRetry);
843 }                               /*afs_Analyze */