initial-freebsd-port-work-20010414
[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 "../afs/param.h"       /* Should be always first */
14 #include "../afs/stds.h"
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16
17 #ifndef UKERNEL
18 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
19 #include <net/if.h>
20 #include <netinet/in.h>
21 #endif
22
23 #ifdef AFS_SGI62_ENV
24 #include "../h/hashing.h"
25 #endif
26 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_FBSD_ENV)
27 #include <netinet/in_var.h>
28 #endif
29 #endif /* !UKERNEL */
30
31 #include "../afs/afsincludes.h" /* Afs-based standard headers */
32 #include "../afs/afs_stats.h"   /* afs statistics */
33 #include "../afs/afs_util.h"
34 #include "../afs/afs_prototypes.h"
35
36 #if     defined(AFS_SUN56_ENV)
37 #include <inet/led.h>
38 #include <inet/common.h>
39 #if     defined(AFS_SUN58_ENV)
40 #include <netinet/ip6.h>
41 #endif
42 #include <inet/ip.h>
43 #endif
44
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 /* same hack for vlserver error base as for ubik error base */
52 #ifndef ERROR_TABLE_BASE_vl
53 #define ERROR_TABLE_BASE_vl     (363520L)
54 #define VL_NOENT                (363524L)
55 #endif /* vlserver error base define */
56
57
58 int afs_BusyWaitPeriod = 15; /* poll every 15 seconds */
59
60
61 afs_int32 hm_retry_RO=0;    /* don't wait */
62 afs_int32 hm_retry_RW=0;    /* don't wait */
63 afs_int32 hm_retry_int=0;   /* don't wait */
64
65 void afs_CopyError(afrom, ato)
66     register struct vrequest *afrom;
67     register struct vrequest *ato;
68
69 {
70     AFS_STATCNT(afs_CopyError);
71     if (!afrom->initd)
72         return;
73     afs_FinalizeReq(ato);
74     if (afrom->accessError)
75         ato->accessError = 1;
76     if (afrom->volumeError)
77         ato->volumeError = 1;
78     if (afrom->networkError)
79         ato->networkError = 1;
80     if (afrom->permWriteError)
81         ato->permWriteError = 1;
82
83 } /*afs_CopyError*/
84
85
86 void afs_FinalizeReq(areq)
87     register struct vrequest *areq;
88
89 {
90     AFS_STATCNT(afs_FinalizeReq);
91     if (areq->initd)
92         return;
93     areq->busyCount = 0;
94     areq->accessError = 0;
95     areq->volumeError = 0;
96     areq->networkError = 0;
97     areq->permWriteError = 0;
98     areq->initd = 1;
99
100 } /*afs_FinalizeReq*/
101
102
103 afs_CheckCode(acode, areq, where)
104     afs_int32 acode;
105     struct vrequest *areq;
106     int where;
107
108 {
109     AFS_STATCNT(afs_CheckCode);
110     if (acode) { 
111         afs_Trace2(afs_iclSetp, CM_TRACE_CHECKCODE,
112                    ICL_TYPE_INT32, acode, ICL_TYPE_INT32, where);
113     }
114     if (!areq || !areq->initd)
115         return acode;
116     if (areq->networkError)
117         return ETIMEDOUT;
118     if (acode == 0)
119         return 0;
120     if (areq->accessError)
121         return EACCES;
122     if (areq->volumeError == VOLMISSING)
123         return ENODEV;
124     if (areq->volumeError == VOLBUSY)
125         return EWOULDBLOCK;
126     if (acode == VNOVNODE)
127         return ENOENT;
128     return acode;
129
130 } /*afs_CheckCode*/
131
132
133 #define VSleep(at)      afs_osi_Wait((at)*1000, 0, 0)
134
135
136 int lastcode;
137 /* returns:
138  * 0   if the vldb record for a specific volume is different from what
139  *     we have cached -- perhaps the volume has moved.
140  * 1   if the vldb record is the same
141  * 2   if we can't tell if it's the same or not. 
142  *
143  * If 0, the caller will probably start over at the beginning of our
144  * list of servers for this volume and try to find one that is up.  If
145  * not 0, we will probably just keep plugging with what we have
146  * cached.   If we fail to contact the VL server, we  should just keep
147  * trying with the information we have, rather than failing. */
148 #define DIFFERENT 0
149 #define SAME 1
150 #define DUNNO 2
151 static int VLDB_Same (afid, areq)
152     struct VenusFid *afid;
153     struct vrequest *areq;
154 {
155     struct vrequest treq;
156     struct conn *tconn;
157     int i, type=0;
158     union { 
159       struct vldbentry tve;
160       struct nvldbentry ntve;
161       struct uvldbentry utve;
162     } v;
163     struct volume *tvp;
164     struct cell *tcell;
165     char *bp, tbuf[CVBS]; /* biggest volume id is 2^32, ~ 4*10^9 */
166     unsigned int changed;
167     struct server *(oldhosts[NMAXNSERVERS]);
168
169     AFS_STATCNT(CheckVLDB);
170     afs_FinalizeReq(areq);
171
172     if (i = afs_InitReq(&treq, &afs_osi_cred)) return DUNNO;
173     tcell = afs_GetCell(afid->Cell, READ_LOCK);
174     bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume);
175     do {
176         VSleep(2);      /* Better safe than sorry. */
177         tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport,
178                                  tcell->cell, &treq, SHARED_LOCK);
179         if (tconn) {
180             if (tconn->srvr->server->flags & SNO_LHOSTS) {
181                 type = 0;
182 #ifdef RX_ENABLE_LOCKS
183                 AFS_GUNLOCK();
184 #endif /* RX_ENABLE_LOCKS */
185                 i = VL_GetEntryByNameO(tconn->id, bp, &v.tve);
186 #ifdef RX_ENABLE_LOCKS
187                 AFS_GLOCK();
188 #endif /* RX_ENABLE_LOCKS */
189             } else if (tconn->srvr->server->flags & SYES_LHOSTS) {
190                 type = 1;
191 #ifdef RX_ENABLE_LOCKS
192                 AFS_GUNLOCK();
193 #endif /* RX_ENABLE_LOCKS */
194                 i = VL_GetEntryByNameN(tconn->id, bp, &v.ntve);
195 #ifdef RX_ENABLE_LOCKS
196                 AFS_GLOCK();
197 #endif /* RX_ENABLE_LOCKS */
198             } else {
199                 type = 2;
200 #ifdef RX_ENABLE_LOCKS
201                 AFS_GUNLOCK();
202 #endif /* RX_ENABLE_LOCKS */
203                 i = VL_GetEntryByNameU(tconn->id, bp, &v.utve);
204 #ifdef RX_ENABLE_LOCKS
205                 AFS_GLOCK();
206 #endif /* RX_ENABLE_LOCKS */
207                 if (!(tconn->srvr->server->flags & SVLSRV_UUID)) {
208                     if (i == RXGEN_OPCODE) {
209                         type = 1;
210 #ifdef RX_ENABLE_LOCKS
211                         AFS_GUNLOCK();
212 #endif /* RX_ENABLE_LOCKS */
213                         i = VL_GetEntryByNameN(tconn->id, bp, &v.ntve);
214 #ifdef RX_ENABLE_LOCKS
215                         AFS_GLOCK();
216 #endif /* RX_ENABLE_LOCKS */
217                         if (i == RXGEN_OPCODE) {
218                             type = 0;
219                             tconn->srvr->server->flags |= SNO_LHOSTS;
220 #ifdef RX_ENABLE_LOCKS
221                             AFS_GUNLOCK();
222 #endif /* RX_ENABLE_LOCKS */
223                             i = VL_GetEntryByNameO(tconn->id, bp, &v.tve);
224 #ifdef RX_ENABLE_LOCKS
225                             AFS_GLOCK();
226 #endif /* RX_ENABLE_LOCKS */
227                         } else if (!i)
228                             tconn->srvr->server->flags |= SYES_LHOSTS;
229                     } else if (!i)
230                             tconn->srvr->server->flags |= SVLSRV_UUID;
231                 }
232             lastcode = i;
233             }
234         } else
235             i = -1;
236     } while (afs_Analyze(tconn, i, (struct VenusFid *) 0, &treq,
237                          -1, /* no op code for this */
238                          SHARED_LOCK, tcell));
239
240     afs_PutCell(tcell, READ_LOCK);
241     afs_Trace2(afs_iclSetp, CM_TRACE_CHECKVLDB, ICL_TYPE_FID, &afid,
242                ICL_TYPE_INT32, i);
243
244     if (i) {
245         return DUNNO;
246     }
247     /* have info, copy into serverHost array */
248     changed = 0;
249     tvp = afs_FindVolume(afid, WRITE_LOCK);
250     if (tvp) {
251        ObtainWriteLock(&tvp->lock,107); 
252        for (i=0; i < NMAXNSERVERS && tvp->serverHost[i]; i++) {
253            oldhosts[i] = tvp->serverHost[i];
254        }
255
256        if (type == 2) {
257           InstallUVolumeEntry(tvp, &v.utve, afid->Cell, tcell, &treq);
258        }
259        else if (type == 1) {
260           InstallNVolumeEntry(tvp, &v.ntve, afid->Cell);
261        }
262        else {
263           InstallVolumeEntry(tvp, &v.tve, afid->Cell);
264        }
265
266        if (i < NMAXNSERVERS && tvp->serverHost[i]) {
267             changed = 1;
268        }
269        for (--i;!changed && i >= 0; i--) {
270           if (tvp->serverHost[i] != oldhosts[i]) {
271              changed = 1; /* also happens if prefs change.  big deal. */
272           }
273        }
274
275        ReleaseWriteLock(&tvp->lock);
276        afs_PutVolume(tvp, WRITE_LOCK);
277     }
278     else {      /* can't find volume */
279       tvp = afs_GetVolume(afid, &treq, WRITE_LOCK);
280       if (tvp) {
281         afs_PutVolume(tvp, WRITE_LOCK);
282         return DIFFERENT;
283       }
284       else return DUNNO;
285     }
286
287     return (changed ? DIFFERENT : SAME);
288 } /*VLDB_Same */
289
290
291 /*------------------------------------------------------------------------
292  * EXPORTED afs_Analyze
293  *
294  * Description:
295  *      Analyze the outcome of an RPC operation, taking whatever support
296  *      actions are necessary.
297  *
298  * Arguments:
299  *      aconn : Ptr to the relevant connection on which the call was made.
300  *      acode : The return code experienced by the RPC.
301  *      afid  : The FID of the file involved in the action.  This argument
302  *              may be null if none was involved.
303  *      areq  : The request record associated with this operation.
304  *      op    : which RPC we are analyzing.
305  *      cellp : pointer to a cell struct.  Must provide either fid or cell.
306  *
307  * Returns:
308  *      Non-zero value if the related RPC operation should be retried,
309  *      zero otherwise.
310  *
311  * Environment:
312  *      This routine is typically called in a do-while loop, causing the
313  *      embedded RPC operation to be called repeatedly if appropriate
314  *      until whatever error condition (if any) is intolerable.
315  *
316  * Side Effects:
317  *      As advertised.
318  *
319  * NOTE:
320  *      The retry return value is used by afs_StoreAllSegments to determine
321  *      if this is a temporary or permanent error.
322  *------------------------------------------------------------------------*/
323 int afs_Analyze(aconn, acode, afid, areq, op, locktype, cellp)
324     register struct conn *aconn;
325     afs_int32 acode;
326     register struct vrequest *areq;
327     struct VenusFid *afid;
328     int op;
329     afs_int32 locktype;
330     struct cell *cellp;
331 { /*afs_Analyze*/
332
333    afs_int32 i, code;
334    struct srvAddr *sa;
335    struct server *tsp;
336    struct volume *tvp;
337    afs_int32 shouldRetry = 0;
338    struct afs_stats_RPCErrors *aerrP;
339    XSTATS_DECLS;
340
341     AFS_STATCNT(afs_Analyze);
342     afs_Trace4(afs_iclSetp, CM_TRACE_ANALYZE, ICL_TYPE_INT32, op,
343                ICL_TYPE_POINTER, aconn,
344                ICL_TYPE_INT32, acode, ICL_TYPE_LONG, areq->uid);
345
346     aerrP = (struct afs_stats_RPCErrors *) 0;
347
348     if ((op >= 0) && (op < AFS_STATS_NUM_FS_RPC_OPS))
349       aerrP = &(afs_stats_cmfullperf.rpc.fsRPCErrors[op]);
350
351     afs_FinalizeReq(areq);
352     if (!aconn && areq->busyCount) { /* one RPC or more got VBUSY/VRESTARTING */
353
354       tvp = afs_FindVolume(afid, READ_LOCK);
355       if (tvp) {
356          afs_warnuser("afs: Waiting for busy volume %u (%s) in cell %s\n", 
357                       (afid ? afid->Fid.Volume : 0),
358                       (tvp->name ? tvp->name : ""),
359                       ((tvp->serverHost[0] && tvp->serverHost[0]->cell) ?
360                        tvp->serverHost[0]->cell->cellName : ""));
361
362          for (i=0; i < MAXHOSTS; i++) {
363             if (tvp->status[i] != not_busy && tvp->status[i] != offline) {
364                tvp->status[i] = not_busy; 
365             }
366             if (tvp->status[i] == not_busy)
367                  shouldRetry = 1;
368          }
369          afs_PutVolume(tvp, READ_LOCK);
370       } else {
371          afs_warnuser("afs: Waiting for busy volume %u\n", 
372                       (afid ? afid->Fid.Volume : 0));
373       }
374
375       if (areq->busyCount > 100) {
376         if (aerrP)
377           (aerrP->err_Volume)++;
378         areq->volumeError = VOLBUSY;
379         shouldRetry = 0;
380       } else {
381         VSleep(afs_BusyWaitPeriod);         /* poll periodically */
382       }
383       return shouldRetry; /* should retry */
384     }
385           
386     if (!aconn) {
387         if (!areq->volumeError) {
388             if (aerrP)
389                 (aerrP->err_Network)++;
390             if (hm_retry_int && !(areq->flags & O_NONBLOCK) &&  /* "hard" mount */
391                 ((afid && afid->Cell == LOCALCELL) || 
392                  (cellp && cellp->cell == LOCALCELL))) { 
393                 if (!afid) {
394                     afs_warnuser("afs: hard-mount waiting for a vlserver to return to service\n");
395                     VSleep(hm_retry_int);
396                     afs_CheckServers(1,cellp);
397                     shouldRetry=1;
398                 } else {
399                     tvp = afs_FindVolume(afid, READ_LOCK);
400                     if (!tvp || (tvp->states & VRO)) {
401                            shouldRetry = hm_retry_RO;
402                     } else { 
403                            shouldRetry = hm_retry_RW;
404                     }
405                     if (tvp)
406                         afs_PutVolume(tvp, READ_LOCK);
407                     if (shouldRetry) {
408                         afs_warnuser("afs: hard-mount waiting for volume %u\n",
409                                  afid->Fid.Volume);
410                         VSleep(hm_retry_int);
411                         afs_CheckServers(1,cellp);
412                     }
413                 }
414             } /* if (hm_retry_int ... */
415             else {
416                 areq->networkError = 1;
417             }
418         }
419         return shouldRetry;
420     }
421
422     /* Find server associated with this connection. */
423     sa = aconn->srvr;
424     tsp = sa->server;
425
426     if (acode == 0) {
427        /* If we previously took an error, mark this volume not busy */
428        if (areq->volumeError) {
429           tvp = afs_FindVolume(afid, READ_LOCK);
430           if (tvp) {
431              for (i=0; i<MAXHOSTS ; i++) {
432                 if (tvp->serverHost[i] == tsp) {
433                    tvp->status[i] = not_busy ;
434                 }
435              }
436              afs_PutVolume(tvp, READ_LOCK);
437           }
438        }
439
440        afs_PutConn(aconn, locktype);
441        return 0;
442     }
443
444     /* If network troubles, mark server as having bogued out again. */
445     /* VRESTARTING is < 0 because of backward compatibility issues 
446      * with 3.4 file servers and older cache managers */
447     if ((acode < 0) && (acode != VRESTARTING)) { 
448         afs_ServerDown(sa);
449         ForceNewConnections(sa); /*multi homed clients lock:afs_xsrvAddr?*/
450         if (aerrP)
451             (aerrP->err_Server)++;
452     }
453
454     if (acode == VBUSY || acode == VRESTARTING) {
455         if (acode == VBUSY) {
456           areq->busyCount++;
457           if (aerrP)
458             (aerrP->err_VolumeBusies)++;
459         }
460         else areq->busyCount = 1;
461
462         tvp = afs_FindVolume(afid, READ_LOCK);
463         if (tvp) {
464           for (i=0; i < MAXHOSTS ; i++ ) {
465             if (tvp->serverHost[i] == tsp) {
466               tvp->status[i] = rdwr_busy ; /* can't tell which yet */
467               /* to tell which, have to look at the op code. */
468             }
469           }
470           afs_PutVolume(tvp, READ_LOCK);
471         }
472         else {
473           afs_warnuser("afs: Waiting for busy volume %u in cell %s\n",
474                        (afid? afid->Fid.Volume : 0), tsp->cell->cellName);
475           VSleep(afs_BusyWaitPeriod);       /* poll periodically */
476         }
477         shouldRetry = 1;
478         acode = 0;
479     }
480     else if (acode == VICETOKENDEAD || (acode & ~0xff) == ERROR_TABLE_BASE_rxk) {
481         /* any rxkad error is treated as token expiration */
482         struct unixuser *tu;
483
484         /*
485          * I'm calling these errors protection errors, since they involve
486          * faulty authentication.
487          */
488         if (aerrP)
489             (aerrP->err_Protection)++;
490
491         tu = afs_FindUser(areq->uid, tsp->cell->cell, READ_LOCK);
492         if (tu) {
493             if ((acode == VICETOKENDEAD) || (acode == RXKADEXPIRED))
494                 afs_warnuser("afs: Tokens for user of AFS id %d for cell %s have expired\n", 
495                         tu->vid, aconn->srvr->server->cell->cellName);
496             else
497                 afs_warnuser("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d)\n", 
498                         tu->vid, aconn->srvr->server->cell->cellName, acode);
499             afs_PutUser(tu, READ_LOCK); 
500         } else {
501             /* The else case shouldn't be possible and should probably be replaced by a panic? */
502             if ((acode == VICETOKENDEAD) || (acode == RXKADEXPIRED))
503                 afs_warnuser("afs: Tokens for user %d for cell %s have expired\n", 
504                         areq->uid, aconn->srvr->server->cell->cellName);
505             else
506                 afs_warnuser("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d)\n", 
507                         areq->uid, aconn->srvr->server->cell->cellName, acode);
508         }
509         aconn->forceConnectFS = 0;       /* don't check until new tokens set */
510         aconn->user->states |= UTokensBad;
511         shouldRetry = 1;                        /* Try again (as root). */
512     }
513     /* Check for access violation. */
514     else if (acode == EACCES) {
515         /* should mark access error in non-existent per-user global structure */
516         if (aerrP)
517             (aerrP->err_Protection)++;
518         areq->accessError = 1;
519         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
520             areq->permWriteError = 1;
521         shouldRetry = 0;
522     }
523     /* check for ubik errors; treat them like crashed servers */
524     else if (acode >= ERROR_TABLE_BASE_u && acode < ERROR_TABLE_BASE_u+255) {
525         afs_ServerDown(sa);
526         if (aerrP)
527             (aerrP->err_Server)++;
528         shouldRetry = 1;                 /* retryable (maybe one is working) */
529         VSleep(1);                      /* just in case */
530     }
531     /* Check for bad volume data base / missing volume. */
532     else if (acode == VSALVAGE || acode == VOFFLINE 
533              || acode == VNOVOL || acode == VNOSERVICE || acode == VMOVED) {
534         struct cell *tcell;
535         int same; 
536
537         shouldRetry = 1;
538         areq->volumeError = VOLMISSING;
539         if (aerrP)
540              (aerrP->err_Volume)++;
541         if (afid && (tcell = afs_GetCell(afid->Cell, 0))) {
542            same = VLDB_Same(afid, areq);
543            tvp = afs_FindVolume(afid, READ_LOCK);
544            if (tvp) {
545               for (i=0; i < MAXHOSTS && tvp->serverHost[i]; i++ ) {
546                  if (tvp->serverHost[i] == tsp) {
547                     if (tvp->status[i] == end_not_busy)
548                        tvp->status[i] = offline ;
549                     else
550                        tvp->status[i]++;
551                  }
552                  else if (!same) {
553                     tvp->status[i] = not_busy; /* reset the others */
554                  }
555               }
556               afs_PutVolume(tvp, READ_LOCK);
557            }
558         }
559      }
560     else if (acode >= ERROR_TABLE_BASE_vl
561              && acode <= ERROR_TABLE_BASE_vl + 255) /* vlserver errors */ {
562        shouldRetry = 0;
563        areq->volumeError = VOLMISSING;
564     }
565     else if (acode >= 0) {
566         if (aerrP)
567             (aerrP->err_Other)++;
568         if (op == AFS_STATS_FS_RPCIDX_STOREDATA)
569             areq->permWriteError = 1;
570         shouldRetry = 0;                /* Other random Vice error. */
571     } else if (acode == RX_MSGSIZE) {   /* same meaning as EMSGSIZE... */
572         VSleep(1);                 /* Just a hack for desperate times. */
573         if (aerrP)
574             (aerrP->err_Other)++;
575         shouldRetry = 1;           /* packet was too big, please retry call */
576     } 
577
578     if (acode < 0  && acode != RX_MSGSIZE && acode != VRESTARTING) {
579         /* If we get here, code < 0 and we have network/Server troubles.
580          * areq->networkError is not set here, since we always
581          * retry in case there is another server.  However, if we find
582          * no connection (aconn == 0) we set the networkError flag.
583          */
584         afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
585         if (aerrP)
586             (aerrP->err_Server)++;
587         VSleep(1);              /* Just a hack for desperate times. */
588         shouldRetry = 1;
589     }
590     
591     /* now unlock the connection and return */
592     afs_PutConn(aconn, locktype);
593     return (shouldRetry);
594 } /*afs_Analyze*/
595