afs: document missing afs_Analyze parm
[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]     rxconn Ptr to the rx_connection.
389  * \param[in]     acode  The return code experienced by the RPC.
390  * \param[in]     fid    The FID of the file involved in the action.  This argument
391  *                       may be null if none was involved.
392  * \param[in,out] areq   The request record associated with this operation.
393  * \param[in]     op     which RPC we are analyzing.
394  * \param[in]     cellp  pointer to a cell struct.  Must provide either fid or cell.
395  *
396  * \returns
397  *      Non-zero value if the related RPC operation should be retried,
398  *      zero otherwise.
399  *
400  * \note
401  *      This routine is typically called in a do-while loop, causing the
402  *      embedded RPC operation to be called repeatedly if appropriate
403  *      until whatever error condition (if any) is intolerable.
404  *
405  * \note
406  *      The retry return value is used by afs_StoreAllSegments to determine
407  *      if this is a temporary or permanent error.
408  */
409 int
410 afs_Analyze(struct afs_conn *aconn, struct rx_connection *rxconn,
411             afs_int32 acode, struct VenusFid *afid, struct vrequest *areq,
412             int op, afs_int32 locktype, struct cell *cellp)
413 {
414     afs_int32 i;
415     struct srvAddr *sa;
416     struct server *tsp;
417     struct volume *tvp = NULL;
418     afs_int32 shouldRetry = 0;
419     afs_int32 serversleft = 1;
420     struct afs_stats_RPCErrors *aerrP;
421     afs_uint32 address;
422
423     if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
424         /* On reconnection, act as connected. XXX: for now.... */
425         /* SXW - This may get very tired after a while. We should try and
426          *       intercept all RPCs before they get here ... */
427         /*printf("afs_Analyze: disconnected\n");*/
428         afs_FinalizeReq(areq);
429         if (aconn) {
430             /* SXW - I suspect that this will _never_ happen - we shouldn't
431              *       get a connection because we're disconnected !!!*/
432             afs_PutConn(aconn, rxconn, locktype);
433         }
434         return 0;
435     }
436
437     AFS_STATCNT(afs_Analyze);
438     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
439                ICL_TYPE_POINTER, aconn, ICL_TYPE_INT32, acode, ICL_TYPE_LONG,
440                areq->uid);
441
442     aerrP = (struct afs_stats_RPCErrors *)0;
443
444     if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS))
445         aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]);
446
447     afs_FinalizeReq(areq);
448     if (!aconn && areq->busyCount) {    /* one RPC or more got VBUSY/VRESTARTING */
449
450         tvp = afs_FindVolume(afid, READ_LOCK);
451         if (tvp) {
452             afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n",
453                          (afid ? afid->Fid.Volume : 0),
454                          (tvp->name ? tvp->name : ""),
455                          ((tvp->serverHost[0]
456                            && tvp->serverHost[0]->cell) ? tvp->serverHost[0]->
457                           cell->cellName : ""));
458
459             for (i = 0; i < AFS_MAXHOSTS; i++) {
460                 if (tvp->status[i] != not_busy && tvp->status[i] != offline) {
461                     tvp->status[i] = not_busy;
462                 }
463                 if (tvp->status[i] == not_busy)
464                     shouldRetry = 1;
465             }
466             afs_PutVolume(tvp, READ_LOCK);
467         } else {
468             afs_warnuser("afs: Waiting for busy volume %u\n",
469                          (afid ? afid->Fid.Volume : 0));
470         }
471
472         if (areq->busyCount > 100) {
473             if (aerrP)
474                 (aerrP->err_Volume)++;
475             areq->volumeError = VOLBUSY;
476             shouldRetry = 0;
477         } else {
478             VSleep(afs_BusyWaitPeriod); /* poll periodically */
479         }
480         if (shouldRetry != 0)
481             areq->busyCount++;
482
483         return shouldRetry;     /* should retry */
484     }
485
486     if (!aconn || !aconn->parent->srvr) {
487         if (!areq->volumeError) {
488             if (aerrP)
489                 (aerrP->err_Network)++;
490             if (hm_retry_int && !(areq->flags & O_NONBLOCK) &&  /* "hard" mount */
491                 ((afid && afs_IsPrimaryCellNum(afid->Cell))
492                  || (cellp && afs_IsPrimaryCell(cellp)))) {
493                 if (!afid) {
494                     static int afs_vl_hm = 0;
495                     int warn = 0;
496                     if (!afs_vl_hm) {
497                         afs_vl_hm = warn = 1;
498                     }
499                     if (warn) {
500                         afs_warnuser
501                             ("afs: hard-mount waiting for a vlserver to return to service\n");
502                     }
503                     VSleep(hm_retry_int);
504                     afs_CheckServers(1, cellp);
505                     shouldRetry = 1;
506
507                     if (warn) {
508                         afs_vl_hm = 0;
509                     }
510                 } else {
511                     static int afs_unknown_vhm = 0;
512                     int warn = 0, vp_vhm = 0;
513
514                     tvp = afs_FindVolume(afid, READ_LOCK);
515                     if (!tvp || (tvp->states & VRO)) {
516                         shouldRetry = hm_retry_RO;
517                     } else {
518                         shouldRetry = hm_retry_RW;
519                     }
520
521                     /* Set 'warn' if we should afs_warnuser. Only let one
522                      * caller call afs_warnuser per hm_retry_int interval per
523                      * volume. */
524                     if (shouldRetry) {
525                         if (tvp) {
526                             if (!(tvp->states & VHardMount)) {
527                                 tvp->states |= VHardMount;
528                                 warn = vp_vhm = 1;
529                             }
530                         } else {
531                             if (!afs_unknown_vhm) {
532                                 afs_unknown_vhm = 1;
533                                 warn = 1;
534                             }
535                         }
536                     }
537
538                     if (tvp)
539                         afs_PutVolume(tvp, READ_LOCK);
540
541                     if (shouldRetry) {
542                         if (warn) {
543                             afs_warnuser
544                                 ("afs: hard-mount waiting for volume %u",
545                                  afid->Fid.Volume);
546                             afs_PrintServerErrors(areq, afid);
547                         }
548
549                         VSleep(hm_retry_int);
550                         afs_CheckServers(1, cellp);
551                         /* clear the black listed servers on this request. */
552                         memset(areq->skipserver, 0, sizeof(areq->skipserver));
553
554                         if (vp_vhm) {
555                             tvp = afs_FindVolume(afid, READ_LOCK);
556                             if (tvp) {
557                                 tvp->states &= ~VHardMount;
558                                 afs_PutVolume(tvp, READ_LOCK);
559                             }
560                         } else if (warn) {
561                             afs_unknown_vhm = 0;
562                         }
563                     }
564                 }
565             } /* if (hm_retry_int ... */
566             else {
567                 if (acode == RX_MSGSIZE)
568                     shouldRetry = 1;
569                 else {
570                     areq->networkError = 1;
571                     /* do not promote to shouldRetry if not already */
572                     if (afs_ClearStatus(afid, op, NULL) == 0)
573                         shouldRetry = 0;
574                 }
575             }
576         }
577         if (aconn) /* simply lacking aconn->server doesn't absolve this */
578             afs_PutConn(aconn, rxconn, locktype);
579         return shouldRetry;
580     }
581
582     /* Find server associated with this connection. */
583     sa = aconn->parent->srvr;
584     tsp = sa->server;
585     address = ntohl(sa->sa_ip);
586
587     /* Before we do anything with acode, make sure we translate it back to
588      * a system error */
589     if ((acode & ~0xff) == ERROR_TABLE_BASE_uae)
590         acode = et_to_sys_error(acode);
591
592     if (acode == 0) {
593         /* If we previously took an error, mark this volume not busy */
594         if (areq->volumeError) {
595             tvp = afs_FindVolume(afid, READ_LOCK);
596             if (tvp) {
597                 for (i = 0; i < AFS_MAXHOSTS; i++) {
598                     if (tvp->serverHost[i] == tsp) {
599                         tvp->status[i] = not_busy;
600                     }
601                 }
602                 afs_PutVolume(tvp, READ_LOCK);
603             }
604         }
605
606         afs_PutConn(aconn, rxconn, locktype);
607         return 0;
608     }
609
610     /* Save the last code of this server on this request. */
611     tvp = afs_FindVolume(afid, READ_LOCK);
612     if (tvp) {
613         for (i = 0; i < AFS_MAXHOSTS; i++) {
614             if (tvp->serverHost[i] == tsp) {
615                 areq->lasterror[i] = acode;
616             }
617         }
618         afs_PutVolume(tvp, READ_LOCK);
619     }
620
621 #ifdef AFS_64BIT_CLIENT
622     if (acode == -455)
623         acode = 455;
624 #endif /* AFS_64BIT_CLIENT */
625     if (acode == RX_MSGSIZE) {
626         shouldRetry = 1;
627         goto out;
628     }
629     if (acode == RX_CALL_TIMEOUT || acode == VNOSERVICE) {
630         serversleft = afs_BlackListOnce(areq, afid, tsp);
631         if (afid)
632             tvp = afs_FindVolume(afid, READ_LOCK);
633         if ((serversleft == 0) && tvp &&
634             ((tvp->states & VRO) || (tvp->states & VBackup))) {
635             shouldRetry = 0;
636         } else {
637             shouldRetry = 1;
638         }
639         if (!afid || !tvp || (tvp->states & VRO))
640             areq->idleError++;
641         else if (afs_ClearStatus(afid, op, tvp) == 0)
642             shouldRetry = 0;
643
644         if (tvp)
645             afs_PutVolume(tvp, READ_LOCK);
646         /* By doing this, we avoid ever marking a server down
647          * in an idle timeout case. That's because the server is
648          * still responding and may only be letting a single vnode
649          * time out. We otherwise risk having the server continually
650          * be marked down, then up, then down again...
651          */
652         goto out;
653     }
654     /* If network troubles, mark server as having bogued out again. */
655     /* VRESTARTING is < 0 because of backward compatibility issues
656      * with 3.4 file servers and older cache managers */
657     if ((acode < 0) && (acode != VRESTARTING)) {
658         afs_ServerDown(sa, acode, rxconn);
659         ForceNewConnections(sa); /* multi homed clients lock:afs_xsrvAddr? */
660         if (aerrP)
661             (aerrP->err_Server)++;
662     }
663
664     if (acode == VBUSY || acode == VRESTARTING) {
665         if (acode == VBUSY) {
666             areq->busyCount++;
667             if (aerrP)
668                 (aerrP->err_VolumeBusies)++;
669         } else
670             areq->busyCount = 1;
671
672         tvp = afs_FindVolume(afid, READ_LOCK);
673         if (tvp) {
674             for (i = 0; i < AFS_MAXHOSTS; i++) {
675                 if (tvp->serverHost[i] == tsp) {
676                     tvp->status[i] = rdwr_busy; /* can't tell which yet */
677                     /* to tell which, have to look at the op code. */
678                 }
679             }
680             afs_PutVolume(tvp, READ_LOCK);
681         } else {
682             afs_warnuser("afs: Waiting for busy volume %u in cell %s (server %d.%d.%d.%d)\n",
683                          (afid ? afid->Fid.Volume : 0), tsp->cell->cellName,
684                          (address >> 24), (address >> 16) & 0xff,
685                          (address >> 8) & 0xff, (address) & 0xff);
686             VSleep(afs_BusyWaitPeriod); /* poll periodically */
687         }
688         shouldRetry = 1;
689         acode = 0;
690     } else if (acode == VICETOKENDEAD
691                || (acode & ~0xff) == ERROR_TABLE_BASE_RXK) {
692         /* any rxkad error is treated as token expiration */
693         struct unixuser *tu;
694         /*
695          * I'm calling these errors protection errors, since they involve
696          * faulty authentication.
697          */
698         if (aerrP)
699             (aerrP->err_Protection)++;
700
701         tu = afs_FindUser(areq->uid, tsp->cell->cellNum, READ_LOCK);
702         if (tu) {
703             if (acode == VICETOKENDEAD) {
704                 aconn->forceConnectFS = 1;
705             } else if (acode == RXKADEXPIRED) {
706                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
707                 aconn->parent->user->states |= UTokensBad;
708                 afs_NotifyUser(tu, UTokensDropped);
709                 afs_warnuser
710                     ("afs: Tokens for user of AFS id %d for cell %s have expired (server %d.%d.%d.%d)\n",
711                      tu->viceId, aconn->parent->srvr->server->cell->cellName,
712                      (address >> 24), (address >> 16) & 0xff,
713                      (address >> 8) & 0xff, (address) & 0xff);
714             } else {
715                 serversleft = afs_BlackListOnce(areq, afid, tsp);
716                 areq->tokenError++;
717
718                 if (serversleft) {
719                     afs_warnuser
720                         ("afs: Tokens for user of AFS id %d for cell %s: rxkad error=%d (server %d.%d.%d.%d)\n",
721                          tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
722                          (address >> 24), (address >> 16) & 0xff,
723                          (address >> 8) & 0xff, (address) & 0xff);
724                     shouldRetry = 1;
725                 } else {
726                     areq->tokenError = 0;
727                     aconn->forceConnectFS = 0;  /* don't check until new tokens set */
728                     aconn->parent->user->states |= UTokensBad;
729                     afs_NotifyUser(tu, UTokensDropped);
730                     afs_warnuser
731                         ("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d, server %d.%d.%d.%d)\n",
732                          tu->viceId, aconn->parent->srvr->server->cell->cellName, acode,
733                          (address >> 24), (address >> 16) & 0xff,
734                          (address >> 8) & 0xff, (address) & 0xff);
735                 }
736             }
737             afs_PutUser(tu, READ_LOCK);
738         } else {
739             /* The else case shouldn't be possible and should probably be replaced by a panic? */
740             if (acode == VICETOKENDEAD) {
741                 aconn->forceConnectFS = 1;
742             } else if (acode == RXKADEXPIRED) {
743                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
744                 aconn->parent->user->states |= UTokensBad;
745                 afs_NotifyUser(tu, UTokensDropped);
746                 afs_warnuser
747                     ("afs: Tokens for user %d for cell %s have expired (server %d.%d.%d.%d)\n",
748                      areq->uid, aconn->parent->srvr->server->cell->cellName,
749                      (address >> 24), (address >> 16) & 0xff,
750                      (address >> 8) & 0xff, (address) & 0xff);
751             } else {
752                 aconn->forceConnectFS = 0;      /* don't check until new tokens set */
753                 aconn->parent->user->states |= UTokensBad;
754                 afs_NotifyUser(tu, UTokensDropped);
755                 afs_warnuser
756                     ("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d, server %d.%d.%d.%d)\n",
757                      areq->uid, aconn->parent->srvr->server->cell->cellName,
758                      acode,
759                      (address >> 24), (address >> 16) & 0xff,
760                      (address >> 8) & 0xff, (address) & 0xff);
761
762             }
763         }
764         shouldRetry = 1;        /* Try again (as root). */
765     }
766     /* Check for access violation. */
767     else if (acode == EACCES) {
768         /* should mark access error in non-existent per-user global structure */
769         if (aerrP)
770             (aerrP->err_Protection)++;
771         areq->accessError = 1;
772         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
773             areq->permWriteError = 1;
774         shouldRetry = 0;
775     }
776     /* check for ubik errors; treat them like crashed servers */
777     else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U + 255) {
778         afs_ServerDown(sa, acode, rxconn);
779         if (aerrP)
780             (aerrP->err_Server)++;
781         shouldRetry = 1;        /* retryable (maybe one is working) */
782         VSleep(1);              /* just in case */
783     }
784     /* Check for bad volume data base / missing volume. */
785     else if (acode == VSALVAGE || acode == VOFFLINE || acode == VNOVOL
786              || acode == VMOVED) {
787         struct cell *tcell;
788         int same;
789
790         shouldRetry = 1;
791         areq->volumeError = VOLMISSING;
792         if (aerrP)
793             (aerrP->err_Volume)++;
794         if (afid && (tcell = afs_GetCell(afid->Cell, 0))) {
795             same = VLDB_Same(afid, areq);
796             tvp = afs_FindVolume(afid, READ_LOCK);
797             if (tvp) {
798                 for (i = 0; i < AFS_MAXHOSTS && tvp->serverHost[i]; i++) {
799                     if (tvp->serverHost[i] == tsp) {
800                         if (tvp->status[i] == end_not_busy)
801                             tvp->status[i] = offline;
802                         else
803                             tvp->status[i]++;
804                     } else if (!same) {
805                         tvp->status[i] = not_busy;      /* reset the others */
806                     }
807                 }
808                 afs_PutVolume(tvp, READ_LOCK);
809             }
810         }
811     } else if (acode >= ERROR_TABLE_BASE_VL && acode <= ERROR_TABLE_BASE_VL + 255) {    /* vlserver errors */
812         shouldRetry = 0;
813         areq->volumeError = VOLMISSING;
814     } else if (acode >= 0) {
815         if (aerrP)
816             (aerrP->err_Other)++;
817         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
818             areq->permWriteError = 1;
819         shouldRetry = 0;        /* Other random Vice error. */
820     } else if (acode == RX_MSGSIZE) {   /* same meaning as EMSGSIZE... */
821         afs_warnuser
822             ("afs: Path MTU may have been exceeded, retrying (server %d.%d.%d.%d)\n",
823              (address >> 24), (address >> 16) & 0xff,
824              (address >> 8) & 0xff, (address) & 0xff);
825
826         VSleep(1);              /* Just a hack for desperate times. */
827         if (aerrP)
828             (aerrP->err_Other)++;
829         shouldRetry = 1;        /* packet was too big, please retry call */
830     }
831
832     if (acode < 0 && acode != RX_MSGSIZE && acode != VRESTARTING) {
833         /* If we get here, code < 0 and we have network/Server troubles.
834          * areq->networkError is not set here, since we always
835          * retry in case there is another server.  However, if we find
836          * no connection (aconn == 0) we set the networkError flag.
837          */
838         afs_ServerDown(sa, acode, rxconn);
839         if (aerrP)
840             (aerrP->err_Server)++;
841         VSleep(1);              /* Just a hack for desperate times. */
842         shouldRetry = 1;
843     }
844 out:
845     /* now unlock the connection and return */
846     afs_PutConn(aconn, rxconn, locktype);
847     return (shouldRetry);
848 }                               /*afs_Analyze */