kernel-reduce-stack-use-20030529
[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     v = afs_osi_Alloc(sizeof(*v));
309     tcell = afs_GetCell(afid->Cell, READ_LOCK);
310     bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume);
311     do {
312         VSleep(2);      /* Better safe than sorry. */
313         tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport,
314                                  tcell->cellNum, &treq, SHARED_LOCK);
315         if (tconn) {
316             if (tconn->srvr->server->flags & SNO_LHOSTS) {
317                 type = 0;
318                 RX_AFS_GUNLOCK();
319                 i = VL_GetEntryByNameO(tconn->id, bp, &v->tve);
320                 RX_AFS_GLOCK();
321             } else if (tconn->srvr->server->flags & SYES_LHOSTS) {
322                 type = 1;
323                 RX_AFS_GUNLOCK();
324                 i = VL_GetEntryByNameN(tconn->id, bp, &v->ntve);
325                 RX_AFS_GLOCK();
326             } else {
327                 type = 2;
328                 RX_AFS_GUNLOCK();
329                 i = VL_GetEntryByNameU(tconn->id, bp, &v->utve);
330                 RX_AFS_GLOCK();
331                 if (!(tconn->srvr->server->flags & SVLSRV_UUID)) {
332                     if (i == RXGEN_OPCODE) {
333                         type = 1;
334                         RX_AFS_GUNLOCK();
335                         i = VL_GetEntryByNameN(tconn->id, bp, &v->ntve);
336                         RX_AFS_GLOCK();
337                         if (i == RXGEN_OPCODE) {
338                             type = 0;
339                             tconn->srvr->server->flags |= SNO_LHOSTS;
340                             RX_AFS_GUNLOCK();
341                             i = VL_GetEntryByNameO(tconn->id, bp, &v->tve);
342                             RX_AFS_GLOCK();
343                         } else if (!i)
344                             tconn->srvr->server->flags |= SYES_LHOSTS;
345                     } else if (!i)
346                             tconn->srvr->server->flags |= SVLSRV_UUID;
347                 }
348             lastcode = i;
349             }
350         } else
351             i = -1;
352     } while (afs_Analyze(tconn, i, NULL, &treq,
353                          -1, /* no op code for this */
354                          SHARED_LOCK, tcell));
355
356     afs_PutCell(tcell, READ_LOCK);
357     afs_Trace2(afs_iclSetp, CM_TRACE_CHECKVLDB, ICL_TYPE_FID, &afid,
358                ICL_TYPE_INT32, i);
359
360     if (i) {
361         afs_osi_Free(v, sizeof(*v));
362         return DUNNO;
363     }
364     /* have info, copy into serverHost array */
365     changed = 0;
366     tvp = afs_FindVolume(afid, WRITE_LOCK);
367     if (tvp) {
368        ObtainWriteLock(&tvp->lock,107); 
369        for (i=0; i < NMAXNSERVERS && tvp->serverHost[i]; i++) {
370            oldhosts[i] = tvp->serverHost[i];
371        }
372
373        if (type == 2) {
374           InstallUVolumeEntry(tvp, &v->utve, afid->Cell, tcell, &treq);
375        }
376        else if (type == 1) {
377           InstallNVolumeEntry(tvp, &v->ntve, afid->Cell);
378        }
379        else {
380           InstallVolumeEntry(tvp, &v->tve, afid->Cell);
381        }
382
383        if (i < NMAXNSERVERS && tvp->serverHost[i]) {
384             changed = 1;
385        }
386        for (--i;!changed && i >= 0; i--) {
387           if (tvp->serverHost[i] != oldhosts[i]) {
388              changed = 1; /* also happens if prefs change.  big deal. */
389           }
390        }
391
392        ReleaseWriteLock(&tvp->lock);
393        afs_PutVolume(tvp, WRITE_LOCK);
394     }
395     else {      /* can't find volume */
396       tvp = afs_GetVolume(afid, &treq, WRITE_LOCK);
397       if (tvp) {
398         afs_PutVolume(tvp, WRITE_LOCK);
399         afs_osi_Free(v, sizeof(*v));
400         return DIFFERENT;
401       }
402       else {
403         afs_osi_Free(v, sizeof(*v));
404         return DUNNO;
405       }
406     }
407
408     afs_osi_Free(v, sizeof(*v));
409     return (changed ? DIFFERENT : SAME);
410 } /*VLDB_Same */
411
412
413 /*------------------------------------------------------------------------
414  * EXPORTED afs_Analyze
415  *
416  * Description:
417  *      Analyze the outcome of an RPC operation, taking whatever support
418  *      actions are necessary.
419  *
420  * Arguments:
421  *      aconn : Ptr to the relevant connection on which the call was made.
422  *      acode : The return code experienced by the RPC.
423  *      afid  : The FID of the file involved in the action.  This argument
424  *              may be null if none was involved.
425  *      areq  : The request record associated with this operation.
426  *      op    : which RPC we are analyzing.
427  *      cellp : pointer to a cell struct.  Must provide either fid or cell.
428  *
429  * Returns:
430  *      Non-zero value if the related RPC operation should be retried,
431  *      zero otherwise.
432  *
433  * Environment:
434  *      This routine is typically called in a do-while loop, causing the
435  *      embedded RPC operation to be called repeatedly if appropriate
436  *      until whatever error condition (if any) is intolerable.
437  *
438  * Side Effects:
439  *      As advertised.
440  *
441  * NOTE:
442  *      The retry return value is used by afs_StoreAllSegments to determine
443  *      if this is a temporary or permanent error.
444  *------------------------------------------------------------------------*/
445 int afs_Analyze(register struct conn *aconn, afs_int32 acode, 
446         struct VenusFid *afid, register struct vrequest *areq, int op,
447         afs_int32 locktype, struct cell *cellp)
448 {
449     afs_int32 i;
450     struct srvAddr *sa;
451     struct server *tsp;
452     struct volume *tvp;
453     afs_int32 shouldRetry = 0;
454     struct afs_stats_RPCErrors *aerrP;
455
456     AFS_STATCNT(afs_Analyze);
457     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
458                ICL_TYPE_POINTER, aconn,
459                ICL_TYPE_INT32, acode, ICL_TYPE_LONG, areq->uid);
460
461     aerrP = (struct afs_stats_RPCErrors *) 0;
462
463     if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS))
464       aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]);
465
466     afs_FinalizeReq(areq);
467     if (!aconn && areq->busyCount) { /* one RPC or more got VBUSY/VRESTARTING */
468
469       tvp = afs_FindVolume(afid, READ_LOCK);
470       if (tvp) {
471          afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n", 
472                       (afid ? afid->Fid.Volume : 0),
473                       (tvp->name ? tvp->name : ""),
474                       ((tvp->serverHost[0] && tvp->serverHost[0]->cell) ?
475                        tvp->serverHost[0]->cell->cellName : ""));
476
477          for (i=0; i < MAXHOSTS; i++) {
478             if (tvp->status[i] != not_busy && tvp->status[i] != offline) {
479                 tvp->status[i] = not_busy; 
480             }
481             if (tvp->status[i] == not_busy) 
482                 shouldRetry = 1;
483          }
484          afs_PutVolume(tvp, READ_LOCK);
485       } else {
486          afs_warnuser("afs: Waiting for busy volume %u\n", 
487                       (afid ? afid->Fid.Volume : 0));
488       }
489
490       if (areq->busyCount > 100) {
491         if (aerrP)
492           (aerrP->err_Volume)++;
493         areq->volumeError = VOLBUSY;
494         shouldRetry = 0;
495       } else {
496         VSleep(afs_BusyWaitPeriod);         /* poll periodically */
497       }
498       if (shouldRetry != 0)
499           areq->busyCount++;
500
501       return shouldRetry; /* should retry */
502     }
503           
504     if (!aconn) {
505         if (!areq->volumeError) {
506             if (aerrP)
507                 (aerrP->err_Network)++;
508             if (hm_retry_int && !(areq->flags & O_NONBLOCK) &&  /* "hard" mount */
509                 ((afid && afs_IsPrimaryCellNum(afid->Cell)) || 
510                  (cellp && afs_IsPrimaryCell(cellp)))) { 
511                 if (!afid) {
512                     afs_warnuser("afs: hard-mount waiting for a vlserver to return to service\n");
513                     VSleep(hm_retry_int);
514                     afs_CheckServers(1,cellp);
515                     shouldRetry=1;
516                 } else {
517                     tvp = afs_FindVolume(afid, READ_LOCK);
518                     if (!tvp || (tvp->states & VRO)) {
519                            shouldRetry = hm_retry_RO;
520                     } else { 
521                            shouldRetry = hm_retry_RW;
522                     }
523                     if (tvp)
524                         afs_PutVolume(tvp, READ_LOCK);
525                     if (shouldRetry) {
526                         afs_warnuser("afs: hard-mount waiting for volume %u\n",
527                                  afid->Fid.Volume);
528                         VSleep(hm_retry_int);
529                         afs_CheckServers(1,cellp);
530                     }
531                 }
532             } /* if (hm_retry_int ... */
533             else {
534                 areq->networkError = 1;
535             }
536         }
537         return shouldRetry;
538     }
539
540     /* Find server associated with this connection. */
541     sa = aconn->srvr;
542     tsp = sa->server;
543
544     /* Before we do anything with acode, make sure we translate it back to
545        a system error */
546     if ((acode & ~0xff) == ERROR_TABLE_BASE_uae) 
547         acode = et_to_sys_error(acode);
548
549     if (acode == 0) {
550        /* If we previously took an error, mark this volume not busy */
551        if (areq->volumeError) {
552           tvp = afs_FindVolume(afid, READ_LOCK);
553           if (tvp) {
554              for (i=0; i<MAXHOSTS ; i++) {
555                 if (tvp->serverHost[i] == tsp) {
556                    tvp->status[i] = not_busy ;
557                 }
558              }
559              afs_PutVolume(tvp, READ_LOCK);
560           }
561        }
562
563        afs_PutConn(aconn, locktype);
564        return 0;
565     }
566
567     /* If network troubles, mark server as having bogued out again. */
568     /* VRESTARTING is < 0 because of backward compatibility issues 
569      * with 3.4 file servers and older cache managers */
570 #ifdef AFS_64BIT_CLIENT
571     if (acode == -455)
572         acode = 455;
573 #endif /* AFS_64BIT_CLIENT */
574     if ((acode < 0) && (acode != VRESTARTING)) { 
575         afs_ServerDown(sa);
576         ForceNewConnections(sa); /*multi homed clients lock:afs_xsrvAddr?*/
577         if (aerrP)
578             (aerrP->err_Server)++;
579     }
580
581     if (acode == VBUSY || acode == VRESTARTING) {
582         if (acode == VBUSY) {
583           areq->busyCount++;
584           if (aerrP)
585             (aerrP->err_VolumeBusies)++;
586         }
587         else areq->busyCount = 1;
588
589         tvp = afs_FindVolume(afid, READ_LOCK);
590         if (tvp) {
591           for (i=0; i < MAXHOSTS ; i++ ) {
592             if (tvp->serverHost[i] == tsp) {
593               tvp->status[i] = rdwr_busy ; /* can't tell which yet */
594               /* to tell which, have to look at the op code. */
595             }
596           }
597           afs_PutVolume(tvp, READ_LOCK);
598         }
599         else {
600           afs_warnuser("afs: Waiting for busy volume %u in cell %s\n",
601                        (afid? afid->Fid.Volume : 0), tsp->cell->cellName);
602           VSleep(afs_BusyWaitPeriod);       /* poll periodically */
603         }
604         shouldRetry = 1;
605         acode = 0;
606     }
607     else if (acode == VICETOKENDEAD || (acode & ~0xff) == ERROR_TABLE_BASE_RXK) {
608         /* any rxkad error is treated as token expiration */
609         struct unixuser *tu;
610
611         /*
612          * I'm calling these errors protection errors, since they involve
613          * faulty authentication.
614          */
615         if (aerrP)
616             (aerrP->err_Protection)++;
617
618         tu = afs_FindUser(areq->uid, tsp->cell->cellNum, READ_LOCK);
619         if (tu) {
620             if ((acode == VICETOKENDEAD) || (acode == RXKADEXPIRED))
621                 afs_warnuser("afs: Tokens for user of AFS id %d for cell %s have expired\n", 
622                         tu->vid, aconn->srvr->server->cell->cellName);
623             else
624                 afs_warnuser("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d)\n", 
625                         tu->vid, aconn->srvr->server->cell->cellName, acode);
626             afs_PutUser(tu, READ_LOCK); 
627         } else {
628             /* The else case shouldn't be possible and should probably be replaced by a panic? */
629             if ((acode == VICETOKENDEAD) || (acode == RXKADEXPIRED))
630                 afs_warnuser("afs: Tokens for user %d for cell %s have expired\n", 
631                         areq->uid, aconn->srvr->server->cell->cellName);
632             else
633                 afs_warnuser("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d)\n", 
634                         areq->uid, aconn->srvr->server->cell->cellName, acode);
635         }
636         aconn->forceConnectFS = 0;       /* don't check until new tokens set */
637         aconn->user->states |= UTokensBad;
638         shouldRetry = 1;                        /* Try again (as root). */
639     }
640     /* Check for access violation. */
641     else if (acode == EACCES) {
642         /* should mark access error in non-existent per-user global structure */
643         if (aerrP)
644             (aerrP->err_Protection)++;
645         areq->accessError = 1;
646         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
647             areq->permWriteError = 1;
648         shouldRetry = 0;
649     }
650     /* check for ubik errors; treat them like crashed servers */
651     else if (acode >= ERROR_TABLE_BASE_U && acode < ERROR_TABLE_BASE_U+255) {
652         afs_ServerDown(sa);
653         if (aerrP)
654             (aerrP->err_Server)++;
655         shouldRetry = 1;                 /* retryable (maybe one is working) */
656         VSleep(1);                      /* just in case */
657     }
658     /* Check for bad volume data base / missing volume. */
659     else if (acode == VSALVAGE || acode == VOFFLINE 
660              || acode == VNOVOL || acode == VNOSERVICE || acode == VMOVED) {
661         struct cell *tcell;
662         int same; 
663
664         shouldRetry = 1;
665         areq->volumeError = VOLMISSING;
666         if (aerrP)
667              (aerrP->err_Volume)++;
668         if (afid && (tcell = afs_GetCell(afid->Cell, 0))) {
669            same = VLDB_Same(afid, areq);
670            tvp = afs_FindVolume(afid, READ_LOCK);
671            if (tvp) {
672               for (i=0; i < MAXHOSTS && tvp->serverHost[i]; i++ ) {
673                  if (tvp->serverHost[i] == tsp) {
674                     if (tvp->status[i] == end_not_busy)
675                        tvp->status[i] = offline ;
676                     else
677                        tvp->status[i]++;
678                  }
679                  else if (!same) {
680                     tvp->status[i] = not_busy; /* reset the others */
681                  }
682               }
683               afs_PutVolume(tvp, READ_LOCK);
684            }
685         }
686      }
687     else if (acode >= ERROR_TABLE_BASE_VL
688              && acode <= ERROR_TABLE_BASE_VL + 255) /* vlserver errors */ {
689        shouldRetry = 0;
690        areq->volumeError = VOLMISSING;
691     }
692     else if (acode >= 0) {
693         if (aerrP)
694             (aerrP->err_Other)++;
695         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
696             areq->permWriteError = 1;
697         shouldRetry = 0;                /* Other random Vice error. */
698     } else if (acode == RX_MSGSIZE) {   /* same meaning as EMSGSIZE... */
699         VSleep(1);                 /* Just a hack for desperate times. */
700         if (aerrP)
701             (aerrP->err_Other)++;
702         shouldRetry = 1;           /* packet was too big, please retry call */
703     } 
704
705     if (acode < 0  && acode != RX_MSGSIZE && acode != VRESTARTING) {
706         /* If we get here, code < 0 and we have network/Server troubles.
707          * areq->networkError is not set here, since we always
708          * retry in case there is another server.  However, if we find
709          * no connection (aconn == 0) we set the networkError flag.
710          */
711         afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
712         if (aerrP)
713             (aerrP->err_Server)++;
714         VSleep(1);              /* Just a hack for desperate times. */
715         shouldRetry = 1;
716     }
717     
718     /* now unlock the connection and return */
719     afs_PutConn(aconn, locktype);
720     return (shouldRetry);
721 } /*afs_Analyze*/
722