afs-analyze-avoid-potential-loop-20030423
[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 RCSID("$Header$");
17
18 #include "afs/stds.h"
19 #include "afs/sysincludes.h"    /* Standard vendor system headers */
20
21 #ifndef UKERNEL
22 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
23 #include <net/if.h>
24 #include <netinet/in.h>
25 #endif
26
27 #ifdef AFS_SGI62_ENV
28 #include "h/hashing.h"
29 #endif
30 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV) && !defined(AFS_DARWIN60_ENV)
31 #include <netinet/in_var.h>
32 #endif
33 #endif /* !UKERNEL */
34
35 #include "afsincludes.h"        /* Afs-based standard headers */
36 #include "afs/afs_stats.h"   /* afs statistics */
37 #include "afs/afs_util.h"
38 #include "afs/unified_afs.h"
39
40 #if     defined(AFS_SUN56_ENV)
41 #include <inet/led.h>
42 #include <inet/common.h>
43 #if     defined(AFS_SUN58_ENV)
44 #include <netinet/ip6.h>
45 #endif
46 #include <inet/ip.h>
47 #endif
48
49
50 /* shouldn't do it this way, but for now will do */
51 #ifndef ERROR_TABLE_BASE_U
52 #define ERROR_TABLE_BASE_U      (5376L)
53 #endif /* ubik error base define */
54
55 /* shouldn't do it this way, but for now will do */
56 #ifndef ERROR_TABLE_BASE_uae
57 #define ERROR_TABLE_BASE_uae    (49733376L)
58 #endif /* unified afs error base define */
59
60 /* same hack for vlserver error base as for ubik error base */
61 #ifndef ERROR_TABLE_BASE_VL
62 #define ERROR_TABLE_BASE_VL     (363520L)
63 #define VL_NOENT                (363524L)
64 #endif /* vlserver error base define */
65
66
67 int afs_BusyWaitPeriod = 15; /* poll every 15 seconds */
68
69 afs_int32 hm_retry_RO=0;    /* don't wait */
70 afs_int32 hm_retry_RW=0;    /* don't wait */
71 afs_int32 hm_retry_int=0;   /* don't wait */
72
73 static int et2sys[512];
74
75 void init_et_to_sys_error(void) {
76     memset(&et2sys, 0, sizeof(et2sys));
77     et2sys[(UAEPERM-ERROR_TABLE_BASE_uae)] = EPERM;
78     et2sys[(UAENOENT-ERROR_TABLE_BASE_uae)] = ENOENT;
79     et2sys[(UAESRCH-ERROR_TABLE_BASE_uae)] = ESRCH;
80     et2sys[(UAEINTR-ERROR_TABLE_BASE_uae)] = EINTR;
81     et2sys[(UAEIO-ERROR_TABLE_BASE_uae)] = EIO;
82     et2sys[(UAENXIO-ERROR_TABLE_BASE_uae)] = ENXIO;
83     et2sys[(UAE2BIG-ERROR_TABLE_BASE_uae)] = E2BIG;
84     et2sys[(UAENOEXEC-ERROR_TABLE_BASE_uae)] = ENOEXEC;
85     et2sys[(UAEBADF-ERROR_TABLE_BASE_uae)] = EBADF;
86     et2sys[(UAECHILD-ERROR_TABLE_BASE_uae)] = ECHILD;
87     et2sys[(UAEAGAIN-ERROR_TABLE_BASE_uae)] = EAGAIN;
88     et2sys[(UAENOMEM-ERROR_TABLE_BASE_uae)] = ENOMEM;
89     et2sys[(UAEACCES-ERROR_TABLE_BASE_uae)] = EACCES;
90     et2sys[(UAEFAULT-ERROR_TABLE_BASE_uae)] = EFAULT;
91     et2sys[(UAENOTBLK-ERROR_TABLE_BASE_uae)] = ENOTBLK;
92     et2sys[(UAEBUSY-ERROR_TABLE_BASE_uae)] = EBUSY;
93     et2sys[(UAEEXIST-ERROR_TABLE_BASE_uae)] = EEXIST;
94     et2sys[(UAEXDEV-ERROR_TABLE_BASE_uae)] = EXDEV;
95     et2sys[(UAENODEV-ERROR_TABLE_BASE_uae)] = ENODEV;
96     et2sys[(UAENOTDIR-ERROR_TABLE_BASE_uae)] = ENOTDIR;
97     et2sys[(UAEISDIR-ERROR_TABLE_BASE_uae)] = EISDIR;
98     et2sys[(UAEINVAL-ERROR_TABLE_BASE_uae)] = EINVAL;
99     et2sys[(UAENFILE-ERROR_TABLE_BASE_uae)] = ENFILE;
100     et2sys[(UAEMFILE-ERROR_TABLE_BASE_uae)] = EMFILE;
101     et2sys[(UAENOTTY-ERROR_TABLE_BASE_uae)] = ENOTTY;
102     et2sys[(UAETXTBSY-ERROR_TABLE_BASE_uae)] = ETXTBSY;
103     et2sys[(UAEFBIG-ERROR_TABLE_BASE_uae)] = EFBIG;
104     et2sys[(UAENOSPC-ERROR_TABLE_BASE_uae)] = ENOSPC;
105     et2sys[(UAESPIPE-ERROR_TABLE_BASE_uae)] = ESPIPE;
106     et2sys[(UAEROFS-ERROR_TABLE_BASE_uae)] = EROFS;
107     et2sys[(UAEMLINK-ERROR_TABLE_BASE_uae)] = EMLINK;
108     et2sys[(UAEPIPE-ERROR_TABLE_BASE_uae)] = EPIPE;
109     et2sys[(UAEDOM-ERROR_TABLE_BASE_uae)] = EDOM;
110     et2sys[(UAERANGE-ERROR_TABLE_BASE_uae)] = ERANGE;
111     et2sys[(UAEDEADLK-ERROR_TABLE_BASE_uae)] = EDEADLK;
112     et2sys[(UAENAMETOOLONG-ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
113     et2sys[(UAENOLCK-ERROR_TABLE_BASE_uae)] = ENOLCK;
114     et2sys[(UAENOSYS-ERROR_TABLE_BASE_uae)] = ENOSYS;
115     et2sys[(UAENOTEMPTY-ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
116     et2sys[(UAELOOP-ERROR_TABLE_BASE_uae)] = ELOOP;
117     et2sys[(UAEWOULDBLOCK-ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
118     et2sys[(UAENOMSG-ERROR_TABLE_BASE_uae)] = ENOMSG;
119     et2sys[(UAEIDRM-ERROR_TABLE_BASE_uae)] = EIDRM;
120     et2sys[(UAECHRNG-ERROR_TABLE_BASE_uae)] = ECHRNG;
121     et2sys[(UAEL2NSYNC-ERROR_TABLE_BASE_uae)] = EL2NSYNC;
122     et2sys[(UAEL3HLT-ERROR_TABLE_BASE_uae)] = EL3HLT;
123     et2sys[(UAEL3RST-ERROR_TABLE_BASE_uae)] = EL3RST;
124     et2sys[(UAELNRNG-ERROR_TABLE_BASE_uae)] = ELNRNG;
125     et2sys[(UAEUNATCH-ERROR_TABLE_BASE_uae)] = EUNATCH;
126     et2sys[(UAENOCSI-ERROR_TABLE_BASE_uae)] = ENOCSI;
127     et2sys[(UAEL2HLT-ERROR_TABLE_BASE_uae)] = EL2HLT;
128     et2sys[(UAEBADE-ERROR_TABLE_BASE_uae)] = EBADE;
129     et2sys[(UAEBADR-ERROR_TABLE_BASE_uae)] = EBADR;
130     et2sys[(UAEXFULL-ERROR_TABLE_BASE_uae)] = EXFULL;
131     et2sys[(UAENOANO-ERROR_TABLE_BASE_uae)] = ENOANO;
132     et2sys[(UAEBADRQC-ERROR_TABLE_BASE_uae)] = EBADRQC;
133     et2sys[(UAEBADSLT-ERROR_TABLE_BASE_uae)] = EBADSLT;
134     et2sys[(UAEDEADLK-ERROR_TABLE_BASE_uae)] = EDEADLK;
135     et2sys[(UAEBFONT-ERROR_TABLE_BASE_uae)] = EBFONT;
136     et2sys[(UAENOSTR-ERROR_TABLE_BASE_uae)] = ENOSTR;
137     et2sys[(UAENODATA-ERROR_TABLE_BASE_uae)] = ENODATA;
138     et2sys[(UAETIME-ERROR_TABLE_BASE_uae)] = ETIME;
139     et2sys[(UAENOSR-ERROR_TABLE_BASE_uae)] = ENOSR;
140     et2sys[(UAENONET-ERROR_TABLE_BASE_uae)] = ENONET;
141     et2sys[(UAENOPKG-ERROR_TABLE_BASE_uae)] = ENOPKG;
142     et2sys[(UAEREMOTE-ERROR_TABLE_BASE_uae)] = EREMOTE;
143     et2sys[(UAENOLINK-ERROR_TABLE_BASE_uae)] = ENOLINK;
144     et2sys[(UAEADV-ERROR_TABLE_BASE_uae)] = EADV;
145     et2sys[(UAESRMNT-ERROR_TABLE_BASE_uae)] = ESRMNT;
146     et2sys[(UAECOMM-ERROR_TABLE_BASE_uae)] = ECOMM;
147     et2sys[(UAEPROTO-ERROR_TABLE_BASE_uae)] = EPROTO;
148     et2sys[(UAEMULTIHOP-ERROR_TABLE_BASE_uae)] = EMULTIHOP;
149     et2sys[(UAEDOTDOT-ERROR_TABLE_BASE_uae)] = EDOTDOT;
150     et2sys[(UAEBADMSG-ERROR_TABLE_BASE_uae)] = EBADMSG;
151     et2sys[(UAEOVERFLOW-ERROR_TABLE_BASE_uae)] = EOVERFLOW;
152     et2sys[(UAENOTUNIQ-ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
153     et2sys[(UAEBADFD-ERROR_TABLE_BASE_uae)] = EBADFD;
154     et2sys[(UAEREMCHG-ERROR_TABLE_BASE_uae)] = EREMCHG;
155     et2sys[(UAELIBACC-ERROR_TABLE_BASE_uae)] = ELIBACC;
156     et2sys[(UAELIBBAD-ERROR_TABLE_BASE_uae)] = ELIBBAD;
157     et2sys[(UAELIBSCN-ERROR_TABLE_BASE_uae)] = ELIBSCN;
158     et2sys[(UAELIBMAX-ERROR_TABLE_BASE_uae)] = ELIBMAX;
159     et2sys[(UAELIBEXEC-ERROR_TABLE_BASE_uae)] = ELIBEXEC;
160     et2sys[(UAEILSEQ-ERROR_TABLE_BASE_uae)] = EILSEQ;
161     et2sys[(UAERESTART-ERROR_TABLE_BASE_uae)] = ERESTART;
162     et2sys[(UAESTRPIPE-ERROR_TABLE_BASE_uae)] = ESTRPIPE;
163     et2sys[(UAEUSERS-ERROR_TABLE_BASE_uae)] = EUSERS;
164     et2sys[(UAENOTSOCK-ERROR_TABLE_BASE_uae)] = ENOTSOCK;
165     et2sys[(UAEDESTADDRREQ-ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
166     et2sys[(UAEMSGSIZE-ERROR_TABLE_BASE_uae)] = EMSGSIZE;
167     et2sys[(UAEPROTOTYPE-ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
168     et2sys[(UAENOPROTOOPT-ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
169     et2sys[(UAEPROTONOSUPPORT-ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
170     et2sys[(UAESOCKTNOSUPPORT-ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
171     et2sys[(UAEOPNOTSUPP-ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
172     et2sys[(UAEPFNOSUPPORT-ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
173     et2sys[(UAEAFNOSUPPORT-ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
174     et2sys[(UAEADDRINUSE-ERROR_TABLE_BASE_uae)] = EADDRINUSE;
175     et2sys[(UAEADDRNOTAVAIL-ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
176     et2sys[(UAENETDOWN-ERROR_TABLE_BASE_uae)] = ENETDOWN;
177     et2sys[(UAENETUNREACH-ERROR_TABLE_BASE_uae)] = ENETUNREACH;
178     et2sys[(UAENETRESET-ERROR_TABLE_BASE_uae)] = ENETRESET;
179     et2sys[(UAECONNABORTED-ERROR_TABLE_BASE_uae)] = ECONNABORTED;
180     et2sys[(UAECONNRESET-ERROR_TABLE_BASE_uae)] = ECONNRESET;
181     et2sys[(UAENOBUFS-ERROR_TABLE_BASE_uae)] = ENOBUFS;
182     et2sys[(UAEISCONN-ERROR_TABLE_BASE_uae)] = EISCONN;
183     et2sys[(UAENOTCONN-ERROR_TABLE_BASE_uae)] = ENOTCONN;
184     et2sys[(UAESHUTDOWN-ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
185     et2sys[(UAETOOMANYREFS-ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
186     et2sys[(UAETIMEDOUT-ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
187     et2sys[(UAECONNREFUSED-ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
188     et2sys[(UAEHOSTDOWN-ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
189     et2sys[(UAEHOSTUNREACH-ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
190     et2sys[(UAEALREADY-ERROR_TABLE_BASE_uae)] = EALREADY;
191     et2sys[(UAEINPROGRESS-ERROR_TABLE_BASE_uae)] = EINPROGRESS;
192     et2sys[(UAESTALE-ERROR_TABLE_BASE_uae)] = ESTALE;
193     et2sys[(UAEUCLEAN-ERROR_TABLE_BASE_uae)] = EUCLEAN;
194     et2sys[(UAENOTNAM-ERROR_TABLE_BASE_uae)] = ENOTNAM;
195     et2sys[(UAENAVAIL-ERROR_TABLE_BASE_uae)] = ENAVAIL;
196     et2sys[(UAEISNAM-ERROR_TABLE_BASE_uae)] = EISNAM;
197     et2sys[(UAEREMOTEIO-ERROR_TABLE_BASE_uae)] = EREMOTEIO;
198     et2sys[(UAEDQUOT-ERROR_TABLE_BASE_uae)] = EDQUOT;
199     et2sys[(UAENOMEDIUM-ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
200     et2sys[(UAEMEDIUMTYPE-ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
201 }
202
203 static afs_int32 et_to_sys_error(afs_int32 in) {
204     if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512) 
205         return in;
206     if (et2sys[in-ERROR_TABLE_BASE_uae] != 0) 
207         return et2sys[in-ERROR_TABLE_BASE_uae];
208     return in;
209 }
210
211 void afs_CopyError(register struct vrequest *afrom, register struct vrequest *ato)
212 {
213     AFS_STATCNT(afs_CopyError);
214     if (!afrom->initd)
215         return;
216     afs_FinalizeReq(ato);
217     if (afrom->accessError)
218         ato->accessError = 1;
219     if (afrom->volumeError)
220         ato->volumeError = 1;
221     if (afrom->networkError)
222         ato->networkError = 1;
223     if (afrom->permWriteError)
224         ato->permWriteError = 1;
225
226 }
227
228 void afs_FinalizeReq(register struct vrequest *areq)
229 {
230     AFS_STATCNT(afs_FinalizeReq);
231     if (areq->initd)
232         return;
233     areq->busyCount = 0;
234     areq->accessError = 0;
235     areq->volumeError = 0;
236     areq->networkError = 0;
237     areq->permWriteError = 0;
238     areq->initd = 1;
239
240 }
241
242 int afs_CheckCode(afs_int32 acode, struct vrequest *areq, int where)
243 {
244     AFS_STATCNT(afs_CheckCode);
245     if (acode) { 
246         afs_Trace2(afs_iclSetp, CM_TRACE_CHECKCODE,
247                    ICL_TYPE_INT32, acode, ICL_TYPE_INT32, where);
248     }
249     if ((acode & ~0xff) == ERROR_TABLE_BASE_uae) 
250         acode = et_to_sys_error(acode);
251     if (!areq || !areq->initd)
252         return acode;
253     if (areq->networkError)
254         return ETIMEDOUT;
255     if (acode == 0)
256         return 0;
257     if (areq->accessError)
258         return EACCES;
259     if (areq->volumeError == VOLMISSING)
260         return ENODEV;
261     if (areq->volumeError == VOLBUSY)
262         return EWOULDBLOCK;
263     if (acode == VNOVNODE)
264         return ENOENT;
265     return acode;
266
267 } /*afs_CheckCode*/
268
269
270 #define VSleep(at)      afs_osi_Wait((at)*1000, 0, 0)
271
272
273 int lastcode;
274 /* returns:
275  * 0   if the vldb record for a specific volume is different from what
276  *     we have cached -- perhaps the volume has moved.
277  * 1   if the vldb record is the same
278  * 2   if we can't tell if it's the same or not. 
279  *
280  * If 0, the caller will probably start over at the beginning of our
281  * list of servers for this volume and try to find one that is up.  If
282  * not 0, we will probably just keep plugging with what we have
283  * cached.   If we fail to contact the VL server, we  should just keep
284  * trying with the information we have, rather than failing. */
285 #define DIFFERENT 0
286 #define SAME 1
287 #define DUNNO 2
288 static int VLDB_Same (struct VenusFid *afid, struct vrequest *areq)
289 {
290     struct vrequest treq;
291     struct conn *tconn;
292     int i, type=0;
293     union { 
294       struct vldbentry tve;
295       struct nvldbentry ntve;
296       struct uvldbentry utve;
297     } v;
298     struct volume *tvp;
299     struct cell *tcell;
300     char *bp, tbuf[CVBS]; /* biggest volume id is 2^32, ~ 4*10^9 */
301     unsigned int changed;
302     struct server *(oldhosts[NMAXNSERVERS]);
303
304     AFS_STATCNT(CheckVLDB);
305     afs_FinalizeReq(areq);
306
307     if ((i = afs_InitReq(&treq, &afs_osi_cred))) return DUNNO;
308     tcell = afs_GetCell(afid->Cell, READ_LOCK);
309     bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume);
310     do {
311         VSleep(2);      /* Better safe than sorry. */
312         tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport,
313                                  tcell->cellNum, &treq, SHARED_LOCK);
314         if (tconn) {
315             if (tconn->srvr->server->flags & SNO_LHOSTS) {
316                 type = 0;
317                 RX_AFS_GUNLOCK();
318                 i = VL_GetEntryByNameO(tconn->id, bp, &v.tve);
319                 RX_AFS_GLOCK();
320             } else if (tconn->srvr->server->flags & SYES_LHOSTS) {
321                 type = 1;
322                 RX_AFS_GUNLOCK();
323                 i = VL_GetEntryByNameN(tconn->id, bp, &v.ntve);
324                 RX_AFS_GLOCK();
325             } else {
326                 type = 2;
327                 RX_AFS_GUNLOCK();
328                 i = VL_GetEntryByNameU(tconn->id, bp, &v.utve);
329                 RX_AFS_GLOCK();
330                 if (!(tconn->srvr->server->flags & SVLSRV_UUID)) {
331                     if (i == RXGEN_OPCODE) {
332                         type = 1;
333                         RX_AFS_GUNLOCK();
334                         i = VL_GetEntryByNameN(tconn->id, bp, &v.ntve);
335                         RX_AFS_GLOCK();
336                         if (i == RXGEN_OPCODE) {
337                             type = 0;
338                             tconn->srvr->server->flags |= SNO_LHOSTS;
339                             RX_AFS_GUNLOCK();
340                             i = VL_GetEntryByNameO(tconn->id, bp, &v.tve);
341                             RX_AFS_GLOCK();
342                         } else if (!i)
343                             tconn->srvr->server->flags |= SYES_LHOSTS;
344                     } else if (!i)
345                             tconn->srvr->server->flags |= SVLSRV_UUID;
346                 }
347             lastcode = i;
348             }
349         } else
350             i = -1;
351     } while (afs_Analyze(tconn, i, NULL, &treq,
352                          -1, /* no op code for this */
353                          SHARED_LOCK, tcell));
354
355     afs_PutCell(tcell, READ_LOCK);
356     afs_Trace2(afs_iclSetp, CM_TRACE_CHECKVLDB, ICL_TYPE_FID, &afid,
357                ICL_TYPE_INT32, i);
358
359     if (i) {
360         return DUNNO;
361     }
362     /* have info, copy into serverHost array */
363     changed = 0;
364     tvp = afs_FindVolume(afid, WRITE_LOCK);
365     if (tvp) {
366        ObtainWriteLock(&tvp->lock,107); 
367        for (i=0; i < NMAXNSERVERS && tvp->serverHost[i]; i++) {
368            oldhosts[i] = tvp->serverHost[i];
369        }
370
371        if (type == 2) {
372           InstallUVolumeEntry(tvp, &v.utve, afid->Cell, tcell, &treq);
373        }
374        else if (type == 1) {
375           InstallNVolumeEntry(tvp, &v.ntve, afid->Cell);
376        }
377        else {
378           InstallVolumeEntry(tvp, &v.tve, afid->Cell);
379        }
380
381        if (i < NMAXNSERVERS && tvp->serverHost[i]) {
382             changed = 1;
383        }
384        for (--i;!changed && i >= 0; i--) {
385           if (tvp->serverHost[i] != oldhosts[i]) {
386              changed = 1; /* also happens if prefs change.  big deal. */
387           }
388        }
389
390        ReleaseWriteLock(&tvp->lock);
391        afs_PutVolume(tvp, WRITE_LOCK);
392     }
393     else {      /* can't find volume */
394       tvp = afs_GetVolume(afid, &treq, WRITE_LOCK);
395       if (tvp) {
396         afs_PutVolume(tvp, WRITE_LOCK);
397         return DIFFERENT;
398       }
399       else return DUNNO;
400     }
401
402     return (changed ? DIFFERENT : SAME);
403 } /*VLDB_Same */
404
405
406 /*------------------------------------------------------------------------
407  * EXPORTED afs_Analyze
408  *
409  * Description:
410  *      Analyze the outcome of an RPC operation, taking whatever support
411  *      actions are necessary.
412  *
413  * Arguments:
414  *      aconn : Ptr to the relevant connection on which the call was made.
415  *      acode : The return code experienced by the RPC.
416  *      afid  : The FID of the file involved in the action.  This argument
417  *              may be null if none was involved.
418  *      areq  : The request record associated with this operation.
419  *      op    : which RPC we are analyzing.
420  *      cellp : pointer to a cell struct.  Must provide either fid or cell.
421  *
422  * Returns:
423  *      Non-zero value if the related RPC operation should be retried,
424  *      zero otherwise.
425  *
426  * Environment:
427  *      This routine is typically called in a do-while loop, causing the
428  *      embedded RPC operation to be called repeatedly if appropriate
429  *      until whatever error condition (if any) is intolerable.
430  *
431  * Side Effects:
432  *      As advertised.
433  *
434  * NOTE:
435  *      The retry return value is used by afs_StoreAllSegments to determine
436  *      if this is a temporary or permanent error.
437  *------------------------------------------------------------------------*/
438 int afs_Analyze(register struct conn *aconn, afs_int32 acode, 
439         struct VenusFid *afid, register struct vrequest *areq, int op,
440         afs_int32 locktype, struct cell *cellp)
441 {
442     afs_int32 i;
443     struct srvAddr *sa;
444     struct server *tsp;
445     struct volume *tvp;
446     afs_int32 shouldRetry = 0;
447     struct afs_stats_RPCErrors *aerrP;
448
449     AFS_STATCNT(afs_Analyze);
450     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
451                ICL_TYPE_POINTER, aconn,
452                ICL_TYPE_INT32, acode, ICL_TYPE_LONG, areq->uid);
453
454     aerrP = (struct afs_stats_RPCErrors *) 0;
455
456     if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS))
457       aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]);
458
459     afs_FinalizeReq(areq);
460     if (!aconn && areq->busyCount) { /* one RPC or more got VBUSY/VRESTARTING */
461
462       tvp = afs_FindVolume(afid, READ_LOCK);
463       if (tvp) {
464          afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n", 
465                       (afid ? afid->Fid.Volume : 0),
466                       (tvp->name ? tvp->name : ""),
467                       ((tvp->serverHost[0] && tvp->serverHost[0]->cell) ?
468                        tvp->serverHost[0]->cell->cellName : ""));
469
470          for (i=0; i < MAXHOSTS; i++) {
471             if (tvp->status[i] != not_busy && tvp->status[i] != offline) {
472                 tvp->status[i] = not_busy; 
473             }
474             if (tvp->status[i] == not_busy) 
475                 shouldRetry = 1;
476          }
477          afs_PutVolume(tvp, READ_LOCK);
478       } else {
479          afs_warnuser("afs: Waiting for busy volume %u\n", 
480                       (afid ? afid->Fid.Volume : 0));
481       }
482
483       if (areq->busyCount > 100) {
484         if (aerrP)
485           (aerrP->err_Volume)++;
486         areq->volumeError = VOLBUSY;
487         shouldRetry = 0;
488       } else {
489         VSleep(afs_BusyWaitPeriod);         /* poll periodically */
490       }
491       if (shouldRetry != 0)
492           areq->busyCount++;
493
494       return shouldRetry; /* should retry */
495     }
496           
497     if (!aconn) {
498         if (!areq->volumeError) {
499             if (aerrP)
500                 (aerrP->err_Network)++;
501             if (hm_retry_int && !(areq->flags & O_NONBLOCK) &&  /* "hard" mount */
502                 ((afid && afs_IsPrimaryCellNum(afid->Cell)) || 
503                  (cellp && afs_IsPrimaryCell(cellp)))) { 
504                 if (!afid) {
505                     afs_warnuser("afs: hard-mount waiting for a vlserver to return to service\n");
506                     VSleep(hm_retry_int);
507                     afs_CheckServers(1,cellp);
508                     shouldRetry=1;
509                 } else {
510                     tvp = afs_FindVolume(afid, READ_LOCK);
511                     if (!tvp || (tvp->states & VRO)) {
512                            shouldRetry = hm_retry_RO;
513                     } else { 
514                            shouldRetry = hm_retry_RW;
515                     }
516                     if (tvp)
517                         afs_PutVolume(tvp, READ_LOCK);
518                     if (shouldRetry) {
519                         afs_warnuser("afs: hard-mount waiting for volume %u\n",
520                                  afid->Fid.Volume);
521                         VSleep(hm_retry_int);
522                         afs_CheckServers(1,cellp);
523                     }
524                 }
525             } /* if (hm_retry_int ... */
526             else {
527                 areq->networkError = 1;
528             }
529         }
530         return shouldRetry;
531     }
532
533     /* Find server associated with this connection. */
534     sa = aconn->srvr;
535     tsp = sa->server;
536
537     /* Before we do anything with acode, make sure we translate it back to
538        a system error */
539     if ((acode & ~0xff) == ERROR_TABLE_BASE_uae) 
540         acode = et_to_sys_error(acode);
541
542     if (acode == 0) {
543        /* If we previously took an error, mark this volume not busy */
544        if (areq->volumeError) {
545           tvp = afs_FindVolume(afid, READ_LOCK);
546           if (tvp) {
547              for (i=0; i<MAXHOSTS ; i++) {
548                 if (tvp->serverHost[i] == tsp) {
549                    tvp->status[i] = not_busy ;
550                 }
551              }
552              afs_PutVolume(tvp, READ_LOCK);
553           }
554        }
555
556        afs_PutConn(aconn, locktype);
557        return 0;
558     }
559
560     /* If network troubles, mark server as having bogued out again. */
561     /* VRESTARTING is < 0 because of backward compatibility issues 
562      * with 3.4 file servers and older cache managers */
563 #ifdef AFS_64BIT_CLIENT
564     if (acode == -455)
565         acode = 455;
566 #endif /* AFS_64BIT_CLIENT */
567     if ((acode < 0) && (acode != VRESTARTING)) { 
568         afs_ServerDown(sa);
569         ForceNewConnections(sa); /*multi homed clients lock:afs_xsrvAddr?*/
570         if (aerrP)
571             (aerrP->err_Server)++;
572     }
573
574     if (acode == VBUSY || acode == VRESTARTING) {
575         if (acode == VBUSY) {
576           areq->busyCount++;
577           if (aerrP)
578             (aerrP->err_VolumeBusies)++;
579         }
580         else areq->busyCount = 1;
581
582         tvp = afs_FindVolume(afid, READ_LOCK);
583         if (tvp) {
584           for (i=0; i < MAXHOSTS ; i++ ) {
585             if (tvp->serverHost[i] == tsp) {
586               tvp->status[i] = rdwr_busy ; /* can't tell which yet */
587               /* to tell which, have to look at the op code. */
588             }
589           }
590           afs_PutVolume(tvp, READ_LOCK);
591         }
592         else {
593           afs_warnuser("afs: Waiting for busy volume %u in cell %s\n",
594                        (afid? afid->Fid.Volume : 0), tsp->cell->cellName);
595           VSleep(afs_BusyWaitPeriod);       /* poll periodically */
596         }
597         shouldRetry = 1;
598         acode = 0;
599     }
600     else if (acode == VICETOKENDEAD || (acode & ~0xff) == ERROR_TABLE_BASE_RXK) {
601         /* any rxkad error is treated as token expiration */
602         struct unixuser *tu;
603
604         /*
605          * I'm calling these errors protection errors, since they involve
606          * faulty authentication.
607          */
608         if (aerrP)
609             (aerrP->err_Protection)++;
610
611         tu = afs_FindUser(areq->uid, tsp->cell->cellNum, READ_LOCK);
612         if (tu) {
613             if ((acode == VICETOKENDEAD) || (acode == RXKADEXPIRED))
614                 afs_warnuser("afs: Tokens for user of AFS id %d for cell %s have expired\n", 
615                         tu->vid, aconn->srvr->server->cell->cellName);
616             else
617                 afs_warnuser("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d)\n", 
618                         tu->vid, aconn->srvr->server->cell->cellName, acode);
619             afs_PutUser(tu, READ_LOCK); 
620         } else {
621             /* The else case shouldn't be possible and should probably be replaced by a panic? */
622             if ((acode == VICETOKENDEAD) || (acode == RXKADEXPIRED))
623                 afs_warnuser("afs: Tokens for user %d for cell %s have expired\n", 
624                         areq->uid, aconn->srvr->server->cell->cellName);
625             else
626                 afs_warnuser("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d)\n", 
627                         areq->uid, aconn->srvr->server->cell->cellName, acode);
628         }
629         aconn->forceConnectFS = 0;       /* don't check until new tokens set */
630         aconn->user->states |= UTokensBad;
631         shouldRetry = 1;                        /* Try again (as root). */
632     }
633     /* Check for access violation. */
634     else if (acode == EACCES) {
635         /* should mark access error in non-existent per-user global structure */
636         if (aerrP)
637             (aerrP->err_Protection)++;
638         areq->accessError = 1;
639         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
640             areq->permWriteError = 1;
641         shouldRetry = 0;
642     }
643     /* check for ubik errors; treat them like crashed servers */
644     else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U+255) {
645         afs_ServerDown(sa);
646         if (aerrP)
647             (aerrP->err_Server)++;
648         shouldRetry = 1;                 /* retryable (maybe one is working) */
649         VSleep(1);                      /* just in case */
650     }
651     /* Check for bad volume data base / missing volume. */
652     else if (acode == VSALVAGE || acode == VOFFLINE 
653              || acode == VNOVOL || acode == VNOSERVICE || acode == VMOVED) {
654         struct cell *tcell;
655         int same; 
656
657         shouldRetry = 1;
658         areq->volumeError = VOLMISSING;
659         if (aerrP)
660              (aerrP->err_Volume)++;
661         if (afid && (tcell = afs_GetCell(afid->Cell, 0))) {
662            same = VLDB_Same(afid, areq);
663            tvp = afs_FindVolume(afid, READ_LOCK);
664            if (tvp) {
665               for (i=0; i < MAXHOSTS && tvp->serverHost[i]; i++ ) {
666                  if (tvp->serverHost[i] == tsp) {
667                     if (tvp->status[i] == end_not_busy)
668                        tvp->status[i] = offline ;
669                     else
670                        tvp->status[i]++;
671                  }
672                  else if (!same) {
673                     tvp->status[i] = not_busy; /* reset the others */
674                  }
675               }
676               afs_PutVolume(tvp, READ_LOCK);
677            }
678         }
679      }
680     else if (acode >= ERROR_TABLE_BASE_VL
681              && acode <= ERROR_TABLE_BASE_VL + 255) /* vlserver errors */ {
682        shouldRetry = 0;
683        areq->volumeError = VOLMISSING;
684     }
685     else if (acode >= 0) {
686         if (aerrP)
687             (aerrP->err_Other)++;
688         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
689             areq->permWriteError = 1;
690         shouldRetry = 0;                /* Other random Vice error. */
691     } else if (acode == RX_MSGSIZE) {   /* same meaning as EMSGSIZE... */
692         VSleep(1);                 /* Just a hack for desperate times. */
693         if (aerrP)
694             (aerrP->err_Other)++;
695         shouldRetry = 1;           /* packet was too big, please retry call */
696     } 
697
698     if (acode < 0  && acode != RX_MSGSIZE && acode != VRESTARTING) {
699         /* If we get here, code < 0 and we have network/Server troubles.
700          * areq->networkError is not set here, since we always
701          * retry in case there is another server.  However, if we find
702          * no connection (aconn == 0) we set the networkError flag.
703          */
704         afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
705         if (aerrP)
706             (aerrP->err_Server)++;
707         VSleep(1);              /* Just a hack for desperate times. */
708         shouldRetry = 1;
709     }
710     
711     /* now unlock the connection and return */
712     afs_PutConn(aconn, locktype);
713     return (shouldRetry);
714 } /*afs_Analyze*/
715