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