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