ubik: remove unused UBIK_PAUSE code
[openafs.git] / src / ubik / ubik.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <sys/types.h>
16 #include <string.h>
17 #include <stdarg.h>
18 #include <time.h>
19
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #else
23 #include <sys/file.h>
24 #include <netinet/in.h>
25 #include <sys/param.h>
26 #endif
27
28 #include <lock.h>
29 #include <rx/xdr.h>
30 #include <rx/rx.h>
31 #include <afs/cellconfig.h>
32
33 #define UBIK_INTERNALS
34 #include "ubik.h"
35 #include "ubik_int.h"
36
37 #include <lwp.h>   /* temporary hack by klm */
38
39 #define ERROR_EXIT(code) do { \
40     error = (code); \
41     goto error_exit; \
42 } while (0)
43
44 /*!
45  * \file
46  * This system is organized in a hierarchical set of related modules.  Modules
47  * at one level can only call modules at the same level or below.
48  *
49  * At the bottom level (0) we have R, RFTP, LWP and IOMGR, i.e. the basic
50  * operating system primitives.
51  *
52  * At the next level (1) we have
53  *
54  * \li VOTER--The module responsible for casting votes when asked.  It is also
55  * responsible for determining whether this server should try to become
56  * a synchronization site.
57  * \li BEACONER--The module responsible for sending keep-alives out when a
58  * server is actually the sync site, or trying to become a sync site.
59  * \li DISK--The module responsible for representing atomic transactions
60  * on the local disk.  It maintains a new-value only log.
61  * \li LOCK--The module responsible for locking byte ranges in the database file.
62  *
63  * At the next level (2) we have
64  *
65  * \li RECOVERY--The module responsible for ensuring that all members of a quorum
66  * have the same up-to-date database after a new synchronization site is
67  * elected.  This module runs only on the synchronization site.
68  *
69  * At the next level (3) we have
70  *
71  * \li REMOTE--The module responsible for interpreting requests from the sync
72  * site and applying them to the database, after obtaining the appropriate
73  * locks.
74  *
75  * At the next level (4) we have
76  *
77  * \li UBIK--The module users call to perform operations on the database.
78  */
79
80
81 /* some globals */
82 afs_int32 ubik_quorum = 0;
83 struct ubik_dbase *ubik_dbase = 0;
84 struct ubik_stats ubik_stats;
85 afs_uint32 ubik_host[UBIK_MAX_INTERFACE_ADDR];
86 afs_int32 ubik_epochTime = 0;
87 afs_int32 urecovery_state = 0;
88 int (*ubik_SRXSecurityProc) (void *, struct rx_securityClass **, afs_int32 *);
89 void *ubik_SRXSecurityRock;
90 int (*ubik_SyncWriterCacheProc) (void);
91 struct ubik_server *ubik_servers;
92 short ubik_callPortal;
93
94 static int BeginTrans(struct ubik_dbase *dbase, afs_int32 transMode,
95                       struct ubik_trans **transPtr, int readAny);
96
97 struct rx_securityClass *ubik_sc[3];
98
99 #define CStampVersion       1   /* meaning set ts->version */
100
101 static_inline struct rx_connection *
102 Quorum_StartIO(struct ubik_trans *atrans, struct ubik_server *as)
103 {
104     struct rx_connection *conn;
105
106     conn = as->disk_rxcid;
107
108 #ifdef AFS_PTHREAD_ENV
109     rx_GetConnection(conn);
110     DBRELE(atrans->dbase);
111 #endif /* AFS_PTHREAD_ENV */
112
113     return conn;
114 }
115
116 static_inline void
117 Quorum_EndIO(struct ubik_trans *atrans, struct rx_connection *aconn)
118 {
119 #ifdef AFS_PTHREAD_ENV
120     DBHOLD(atrans->dbase);
121     rx_PutConnection(aconn);
122 #endif /* AFS_PTHREAD_ENV */
123 }
124
125
126 /*
127  * Iterate over all servers.  Callers pass in *ts which is used to track
128  * the current server.
129  * - Returns 1 if there are no more servers
130  * - Returns 0 with conn set to the connection for the current server if
131  *   it's up and current
132  */
133 static int
134 ContactQuorum_iterate(struct ubik_trans *atrans, int aflags, struct ubik_server **ts,
135                          struct rx_connection **conn, afs_int32 *rcode,
136                          afs_int32 *okcalls, afs_int32 code)
137 {
138     if (!*ts) {
139         /* Initial call - start iterating over servers */
140         *ts = ubik_servers;
141         *conn = NULL;
142         *rcode = 0;
143         *okcalls = 0;
144     } else {
145         if (*conn) {
146             Quorum_EndIO(atrans, *conn);
147             *conn = NULL;
148             if (code) {         /* failure */
149                 *rcode = code;
150                 (*ts)->up = 0;          /* mark as down now; beacons will no longer be sent */
151                 (*ts)->beaconSinceDown = 0;
152                 (*ts)->currentDB = 0;
153                 urecovery_LostServer(*ts);      /* tell recovery to try to resend dbase later */
154             } else {            /* success */
155                 if (!(*ts)->isClone)
156                     (*okcalls)++;       /* count up how many worked */
157                 if (aflags & CStampVersion) {
158                     (*ts)->version = atrans->dbase->version;
159                 }
160             }
161         }
162         *ts = (*ts)->next;
163     }
164     if (!(*ts))
165         return 1;
166     if (!(*ts)->up || !(*ts)->currentDB) {
167         (*ts)->currentDB = 0;   /* db is no longer current; we just missed an update */
168         return 0;               /* not up-to-date, don't bother.  NULL conn will tell caller not to use */
169     }
170     *conn = Quorum_StartIO(atrans, *ts);
171     return 0;
172 }
173
174 static int
175 ContactQuorum_rcode(int okcalls, afs_int32 rcode)
176 {
177     /*
178      * return 0 if we successfully contacted a quorum, otherwise return error code.
179      * We don't have to contact ourselves (that was done locally)
180      */
181     if (okcalls + 1 >= ubik_quorum)
182         return 0;
183     else
184         return rcode;
185 }
186
187 /*!
188  * \brief Perform an operation at a quorum, handling error conditions.
189  * \return 0 if all worked and a quorum was contacted successfully
190  * \return otherwise mark failing server as down and return #UERROR
191  *
192  * \note If any server misses an update, we must wait #BIGTIME seconds before
193  * allowing the transaction to commit, to ensure that the missing and
194  * possibly still functioning server times out and stops handing out old
195  * data.  This is done in the commit code, where we wait for a server marked
196  * down to have stayed down for #BIGTIME seconds before we allow a transaction
197  * to commit.  A server that fails but comes back up won't give out old data
198  * because it is sent the sync count along with the beacon message that
199  * marks it as \b really up (\p beaconSinceDown).
200  */
201 afs_int32
202 ContactQuorum_NoArguments(afs_int32 (*proc)(struct rx_connection *, ubik_tid *),
203                           struct ubik_trans *atrans, int aflags)
204 {
205     struct ubik_server *ts = NULL;
206     afs_int32 code = 0, rcode, okcalls;
207     struct rx_connection *conn;
208     int done;
209
210     done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
211     while (!done) {
212         if (conn)
213             code = (*proc)(conn, &atrans->tid);
214         done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
215     }
216     return ContactQuorum_rcode(okcalls, rcode);
217 }
218
219
220 afs_int32
221 ContactQuorum_DISK_Lock(struct ubik_trans *atrans, int aflags,afs_int32 file,
222                         afs_int32 position, afs_int32 length, afs_int32 type)
223 {
224     struct ubik_server *ts = NULL;
225     afs_int32 code = 0, rcode, okcalls;
226     struct rx_connection *conn;
227     int done;
228
229     done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
230     while (!done) {
231         if (conn)
232             code = DISK_Lock(conn, &atrans->tid, file, position, length, type);
233         done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
234     }
235     return ContactQuorum_rcode(okcalls, rcode);
236 }
237
238
239 afs_int32
240 ContactQuorum_DISK_Write(struct ubik_trans *atrans, int aflags,
241                          afs_int32 file, afs_int32 position, bulkdata *data)
242 {
243     struct ubik_server *ts = NULL;
244     afs_int32 code = 0, rcode, okcalls;
245     struct rx_connection *conn;
246     int done;
247
248     done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
249     while (!done) {
250         if (conn)
251             code = DISK_Write(conn, &atrans->tid, file, position, data);
252         done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
253     }
254     return ContactQuorum_rcode(okcalls, rcode);
255 }
256
257
258 afs_int32
259 ContactQuorum_DISK_Truncate(struct ubik_trans *atrans, int aflags,
260                             afs_int32 file, afs_int32 length)
261 {
262     struct ubik_server *ts = NULL;
263     afs_int32 code = 0, rcode, okcalls;
264     struct rx_connection *conn;
265     int done;
266
267     done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
268     while (!done) {
269         if (conn)
270             code = DISK_Truncate(conn, &atrans->tid, file, length);
271         done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
272     }
273     return ContactQuorum_rcode(okcalls, rcode);
274 }
275
276
277 afs_int32
278 ContactQuorum_DISK_WriteV(struct ubik_trans *atrans, int aflags,
279                           iovec_wrt * io_vector, iovec_buf *io_buffer)
280 {
281     struct ubik_server *ts = NULL;
282     afs_int32 code = 0, rcode, okcalls;
283     struct rx_connection *conn;
284     int done;
285
286     done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
287     while (!done) {
288         if (conn) {
289             code = DISK_WriteV(conn, &atrans->tid, io_vector, io_buffer);
290             if ((code <= -450) && (code > -500)) {
291                 /* An RPC interface mismatch (as defined in comerr/error_msg.c).
292                  * Un-bulk the entries and do individual DISK_Write calls
293                  * instead of DISK_WriteV.
294                  */
295                 struct ubik_iovec *iovec =
296                         (struct ubik_iovec *)io_vector->iovec_wrt_val;
297                 char *iobuf = (char *)io_buffer->iovec_buf_val;
298                 bulkdata tcbs;
299                 afs_int32 i, offset;
300
301                 Quorum_EndIO(atrans, conn);
302                 conn = Quorum_StartIO(atrans, ts);
303
304                 for (i = 0, offset = 0; i < io_vector->iovec_wrt_len; i++) {
305                     /* Sanity check for going off end of buffer */
306                     if ((offset + iovec[i].length) > io_buffer->iovec_buf_len) {
307                         code = UINTERNAL;
308                         break;
309                     }
310                     tcbs.bulkdata_len = iovec[i].length;
311                     tcbs.bulkdata_val = &iobuf[offset];
312                     code = DISK_Write(conn, &atrans->tid, iovec[i].file,
313                            iovec[i].position, &tcbs);
314                     if (code)
315                         break;
316                     offset += iovec[i].length;
317                 }
318             }
319         }
320         done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
321     }
322     return ContactQuorum_rcode(okcalls, rcode);
323 }
324
325
326 afs_int32
327 ContactQuorum_DISK_SetVersion(struct ubik_trans *atrans, int aflags,
328                               ubik_version *OldVersion,
329                               ubik_version *NewVersion)
330 {
331     struct ubik_server *ts = NULL;
332     afs_int32 code = 0, rcode, okcalls;
333     struct rx_connection *conn;
334     int done;
335
336     done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
337     while (!done) {
338         if (conn)
339             code = DISK_SetVersion(conn, &atrans->tid, OldVersion, NewVersion);
340         done = ContactQuorum_iterate(atrans, aflags, &ts, &conn, &rcode, &okcalls, code);
341     }
342     return ContactQuorum_rcode(okcalls, rcode);
343 }
344
345
346 /*!
347  * \brief This routine initializes the ubik system for a set of servers.
348  * \return 0 for success, or an error code on failure.
349  * \param serverList set of servers specified; nServers gives the number of entries in this array.
350  * \param pathName provides an initial prefix used for naming storage files used by this system.
351  * \param dbase the returned structure representing this instance of an ubik; it is passed to various calls below.
352  *
353  * \todo This routine should perhaps be generalized to a low-level disk interface providing read, write, file enumeration and sync operations.
354  *
355  * \warning The host named by myHost should not also be listed in serverList.
356  *
357  * \see ubik_ServerInit(), ubik_ServerInitByInfo()
358  */
359 int
360 ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
361                       struct afsconf_cell *info, char clones[],
362                       afs_uint32 serverList[], const char *pathName,
363                       struct ubik_dbase **dbase)
364 {
365     struct ubik_dbase *tdb;
366     afs_int32 code;
367 #ifdef AFS_PTHREAD_ENV
368     pthread_t rxServerThread;        /* pthread variables */
369     pthread_t ubeacon_InteractThread;
370     pthread_t urecovery_InteractThread;
371     pthread_attr_t rxServer_tattr;
372     pthread_attr_t ubeacon_Interact_tattr;
373     pthread_attr_t urecovery_Interact_tattr;
374 #else
375     PROCESS junk;
376     extern int rx_stackSize;
377 #endif
378
379     afs_int32 secIndex;
380     struct rx_securityClass *secClass;
381
382     struct rx_service *tservice;
383
384     initialize_U_error_table();
385
386     tdb = (struct ubik_dbase *)malloc(sizeof(struct ubik_dbase));
387     tdb->pathName = (char *)malloc(strlen(pathName) + 1);
388     strcpy(tdb->pathName, pathName);
389     tdb->activeTrans = (struct ubik_trans *)0;
390     memset(&tdb->version, 0, sizeof(struct ubik_version));
391     memset(&tdb->cachedVersion, 0, sizeof(struct ubik_version));
392 #ifdef AFS_PTHREAD_ENV
393     MUTEX_INIT(&tdb->versionLock, "version lock", MUTEX_DEFAULT, 0);
394 #else
395     Lock_Init(&tdb->versionLock);
396 #endif
397     Lock_Init(&tdb->cache_lock);
398     tdb->flags = 0;
399     tdb->read = uphys_read;
400     tdb->write = uphys_write;
401     tdb->truncate = uphys_truncate;
402     tdb->open = uphys_invalidate;       /* this function isn't used any more */
403     tdb->sync = uphys_sync;
404     tdb->stat = uphys_stat;
405     tdb->getlabel = uphys_getlabel;
406     tdb->setlabel = uphys_setlabel;
407     tdb->getnfiles = uphys_getnfiles;
408     tdb->readers = 0;
409     tdb->tidCounter = tdb->writeTidCounter = 0;
410     *dbase = tdb;
411     ubik_dbase = tdb;           /* for now, only one db per server; can fix later when we have names for the other dbases */
412
413 #ifdef AFS_PTHREAD_ENV
414     CV_INIT(&tdb->version_cond, "version", CV_DEFAULT, 0);
415     CV_INIT(&tdb->flags_cond, "flags", CV_DEFAULT, 0);
416 #endif /* AFS_PTHREAD_ENV */
417
418     /* initialize RX */
419
420     /* the following call is idempotent so when/if it got called earlier,
421      * by whatever called us, it doesn't really matter -- klm */
422     code = rx_Init(myPort);
423     if (code < 0)
424         return code;
425
426     ubik_callPortal = myPort;
427     /* try to get an additional security object */
428     ubik_sc[0] = rxnull_NewServerSecurityObject();
429     ubik_sc[1] = 0;
430     ubik_sc[2] = 0;
431     if (ubik_SRXSecurityProc) {
432         code =
433             (*ubik_SRXSecurityProc) (ubik_SRXSecurityRock, &secClass,
434                                      &secIndex);
435         if (code == 0) {
436             ubik_sc[secIndex] = secClass;
437         }
438     }
439     /* for backwards compat this should keep working as it does now
440        and not host bind */
441 #if 0
442     /* This really needs to be up above, where I have put it.  It works
443      * here when we're non-pthreaded, but the code above, when using
444      * pthreads may (and almost certainly does) end up calling on a
445      * pthread resource which gets initialized by rx_Init.  The end
446      * result is that an assert fails and the program dies. -- klm
447      */
448     code = rx_Init(myPort);
449     if (code < 0)
450         return code;
451 #endif
452
453     tservice =
454         rx_NewService(0, VOTE_SERVICE_ID, "VOTE", ubik_sc, 3,
455                       VOTE_ExecuteRequest);
456     if (tservice == (struct rx_service *)0) {
457         ubik_dprint("Could not create VOTE rx service!\n");
458         return -1;
459     }
460     rx_SetMinProcs(tservice, 2);
461     rx_SetMaxProcs(tservice, 3);
462
463     tservice =
464         rx_NewService(0, DISK_SERVICE_ID, "DISK", ubik_sc, 3,
465                       DISK_ExecuteRequest);
466     if (tservice == (struct rx_service *)0) {
467         ubik_dprint("Could not create DISK rx service!\n");
468         return -1;
469     }
470     rx_SetMinProcs(tservice, 2);
471     rx_SetMaxProcs(tservice, 3);
472
473     /* start an rx_ServerProc to handle incoming RPC's in particular the
474      * UpdateInterfaceAddr RPC that occurs in ubeacon_InitServerList. This avoids
475      * the "steplock" problem in ubik initialization. Defect 11037.
476      */
477 #ifdef AFS_PTHREAD_ENV
478 /* do assert stuff */
479     osi_Assert(pthread_attr_init(&rxServer_tattr) == 0);
480     osi_Assert(pthread_attr_setdetachstate(&rxServer_tattr, PTHREAD_CREATE_DETACHED) == 0);
481 /*    osi_Assert(pthread_attr_setstacksize(&rxServer_tattr, rx_stackSize) == 0); */
482
483     osi_Assert(pthread_create(&rxServerThread, &rxServer_tattr, (void *)rx_ServerProc, NULL) == 0);
484 #else
485     LWP_CreateProcess(rx_ServerProc, rx_stackSize, RX_PROCESS_PRIORITY,
486               NULL, "rx_ServerProc", &junk);
487 #endif
488
489     /* do basic initialization */
490     code = uvote_Init();
491     if (code)
492         return code;
493     code = urecovery_Initialize(tdb);
494     if (code)
495         return code;
496     if (info)
497         code = ubeacon_InitServerListByInfo(myHost, info, clones);
498     else
499         code = ubeacon_InitServerList(myHost, serverList);
500     if (code)
501         return code;
502
503     /* now start up async processes */
504 #ifdef AFS_PTHREAD_ENV
505 /* do assert stuff */
506     osi_Assert(pthread_attr_init(&ubeacon_Interact_tattr) == 0);
507     osi_Assert(pthread_attr_setdetachstate(&ubeacon_Interact_tattr, PTHREAD_CREATE_DETACHED) == 0);
508 /*    osi_Assert(pthread_attr_setstacksize(&ubeacon_Interact_tattr, 16384) == 0); */
509     /*  need another attr set here for priority???  - klm */
510
511     osi_Assert(pthread_create(&ubeacon_InteractThread, &ubeacon_Interact_tattr,
512            (void *)ubeacon_Interact, NULL) == 0);
513 #else
514     code = LWP_CreateProcess(ubeacon_Interact, 16384 /*8192 */ ,
515                              LWP_MAX_PRIORITY - 1, (void *)0, "beacon",
516                              &junk);
517     if (code)
518         return code;
519 #endif
520
521 #ifdef AFS_PTHREAD_ENV
522 /* do assert stuff */
523     osi_Assert(pthread_attr_init(&urecovery_Interact_tattr) == 0);
524     osi_Assert(pthread_attr_setdetachstate(&urecovery_Interact_tattr, PTHREAD_CREATE_DETACHED) == 0);
525 /*    osi_Assert(pthread_attr_setstacksize(&urecovery_Interact_tattr, 16384) == 0); */
526     /*  need another attr set here for priority???  - klm */
527
528     osi_Assert(pthread_create(&urecovery_InteractThread, &urecovery_Interact_tattr,
529            (void *)urecovery_Interact, NULL) == 0);
530
531     return 0;  /* is this correct?  - klm */
532 #else
533     code = LWP_CreateProcess(urecovery_Interact, 16384 /*8192 */ ,
534                              LWP_MAX_PRIORITY - 1, (void *)0, "recovery",
535                              &junk);
536     return code;
537 #endif
538
539 }
540
541 /*!
542  * \see ubik_ServerInitCommon()
543  */
544 int
545 ubik_ServerInitByInfo(afs_uint32 myHost, short myPort,
546                       struct afsconf_cell *info, char clones[],
547                       const char *pathName, struct ubik_dbase **dbase)
548 {
549     afs_int32 code;
550
551     code =
552         ubik_ServerInitCommon(myHost, myPort, info, clones, 0, pathName,
553                               dbase);
554     return code;
555 }
556
557 /*!
558  * \see ubik_ServerInitCommon()
559  */
560 int
561 ubik_ServerInit(afs_uint32 myHost, short myPort, afs_uint32 serverList[],
562                 const char *pathName, struct ubik_dbase **dbase)
563 {
564     afs_int32 code;
565
566     code =
567         ubik_ServerInitCommon(myHost, myPort, (struct afsconf_cell *)0, 0,
568                               serverList, pathName, dbase);
569     return code;
570 }
571
572 /*!
573  * \brief This routine begins a read or write transaction on the transaction
574  * identified by transPtr, in the dbase named by dbase.
575  *
576  * An open mode of ubik_READTRANS identifies this as a read transaction,
577  * while a mode of ubik_WRITETRANS identifies this as a write transaction.
578  * transPtr is set to the returned transaction control block.
579  * The readAny flag is set to 0 or 1 or 2 by the wrapper functions
580  * ubik_BeginTrans() or ubik_BeginTransReadAny() or
581  * ubik_BeginTransReadAnyWrite() below.
582  *
583  * \note We can only begin transaction when we have an up-to-date database.
584  */
585 static int
586 BeginTrans(struct ubik_dbase *dbase, afs_int32 transMode,
587            struct ubik_trans **transPtr, int readAny)
588 {
589     struct ubik_trans *jt;
590     struct ubik_trans *tt;
591     afs_int32 code;
592
593     if (readAny > 1 && ubik_SyncWriterCacheProc == NULL) {
594         /* it's not safe to use ubik_BeginTransReadAnyWrite without a
595          * cache-syncing function; fall back to ubik_BeginTransReadAny,
596          * which is safe but slower */
597         ubik_print("ubik_BeginTransReadAnyWrite called, but "
598                    "ubik_SyncWriterCacheProc not set; pretending "
599                    "ubik_BeginTransReadAny was called instead\n");
600         readAny = 1;
601     }
602
603     if ((transMode != UBIK_READTRANS) && readAny)
604         return UBADTYPE;
605     DBHOLD(dbase);
606     if (urecovery_AllBetter(dbase, readAny) == 0) {
607         DBRELE(dbase);
608         return UNOQUORUM;
609     }
610     /* otherwise we have a quorum, use it */
611
612     /* make sure that at most one write transaction occurs at any one time.  This
613      * has nothing to do with transaction locking; that's enforced by the lock package.  However,
614      * we can't even handle two non-conflicting writes, since our log and recovery modules
615      * don't know how to restore one without possibly picking up some data from the other. */
616     if (transMode == UBIK_WRITETRANS) {
617         /* if we're writing already, wait */
618         while (dbase->flags & DBWRITING) {
619 #ifdef AFS_PTHREAD_ENV
620             CV_WAIT(&dbase->flags_cond, &dbase->versionLock);
621 #else
622             DBRELE(dbase);
623             LWP_WaitProcess(&dbase->flags);
624             DBHOLD(dbase);
625 #endif
626         }
627
628         if (!ubeacon_AmSyncSite()) {
629             DBRELE(dbase);
630             return UNOTSYNC;
631         }
632     }
633
634     /* create the transaction */
635     code = udisk_begin(dbase, transMode, &jt);  /* can't take address of register var */
636     tt = jt;                    /* move to a register */
637     if (code || tt == (struct ubik_trans *)NULL) {
638         DBRELE(dbase);
639         return code;
640     }
641     if (readAny) {
642         tt->flags |= TRREADANY;
643         if (readAny > 1) {
644             tt->flags |= TRREADWRITE;
645         }
646     }
647     /* label trans and dbase with new tid */
648     tt->tid.epoch = ubik_epochTime;
649     /* bump by two, since tidCounter+1 means trans id'd by tidCounter has finished */
650     tt->tid.counter = (dbase->tidCounter += 2);
651
652     if (transMode == UBIK_WRITETRANS) {
653         /* for a write trans, we have to keep track of the write tid counter too */
654         dbase->writeTidCounter = tt->tid.counter;
655
656         /* next try to start transaction on appropriate number of machines */
657         code = ContactQuorum_NoArguments(DISK_Begin, tt, 0);
658         if (code) {
659             /* we must abort the operation */
660             udisk_abort(tt);
661             ContactQuorum_NoArguments(DISK_Abort, tt, 0); /* force aborts to the others */
662             udisk_end(tt);
663             DBRELE(dbase);
664             return code;
665         }
666     }
667
668     *transPtr = tt;
669     DBRELE(dbase);
670     return 0;
671 }
672
673 /*!
674  * \see BeginTrans()
675  */
676 int
677 ubik_BeginTrans(struct ubik_dbase *dbase, afs_int32 transMode,
678                 struct ubik_trans **transPtr)
679 {
680     return BeginTrans(dbase, transMode, transPtr, 0);
681 }
682
683 /*!
684  * \see BeginTrans()
685  */
686 int
687 ubik_BeginTransReadAny(struct ubik_dbase *dbase, afs_int32 transMode,
688                        struct ubik_trans **transPtr)
689 {
690     return BeginTrans(dbase, transMode, transPtr, 1);
691 }
692
693 /*!
694  * \see BeginTrans()
695  */
696 int
697 ubik_BeginTransReadAnyWrite(struct ubik_dbase *dbase, afs_int32 transMode,
698                             struct ubik_trans **transPtr)
699 {
700     return BeginTrans(dbase, transMode, transPtr, 2);
701 }
702
703 /*!
704  * \brief This routine ends a read or write transaction by aborting it.
705  */
706 int
707 ubik_AbortTrans(struct ubik_trans *transPtr)
708 {
709     afs_int32 code;
710     afs_int32 code2;
711     struct ubik_dbase *dbase;
712
713     dbase = transPtr->dbase;
714
715     if (transPtr->flags & TRCACHELOCKED) {
716         ReleaseReadLock(&dbase->cache_lock);
717         transPtr->flags &= ~TRCACHELOCKED;
718     }
719
720     ObtainWriteLock(&dbase->cache_lock);
721
722     DBHOLD(dbase);
723     memset(&dbase->cachedVersion, 0, sizeof(struct ubik_version));
724
725     ReleaseWriteLock(&dbase->cache_lock);
726
727     /* see if we're still up-to-date */
728     if (!urecovery_AllBetter(dbase, transPtr->flags & TRREADANY)) {
729         udisk_abort(transPtr);
730         udisk_end(transPtr);
731         DBRELE(dbase);
732         return UNOQUORUM;
733     }
734
735     if (transPtr->type == UBIK_READTRANS) {
736         code = udisk_abort(transPtr);
737         udisk_end(transPtr);
738         DBRELE(dbase);
739         return code;
740     }
741
742     /* below here, we know we're doing a write transaction */
743     if (!ubeacon_AmSyncSite()) {
744         udisk_abort(transPtr);
745         udisk_end(transPtr);
746         DBRELE(dbase);
747         return UNOTSYNC;
748     }
749
750     /* now it is safe to try remote abort */
751     code = ContactQuorum_NoArguments(DISK_Abort, transPtr, 0);
752     code2 = udisk_abort(transPtr);
753     udisk_end(transPtr);
754     DBRELE(dbase);
755     return (code ? code : code2);
756 }
757
758 static void
759 WritebackApplicationCache(struct ubik_dbase *dbase)
760 {
761     int code = 0;
762     if (ubik_SyncWriterCacheProc) {
763         code = ubik_SyncWriterCacheProc();
764     }
765     if (code) {
766         /* we failed to sync the local cache, so just invalidate the cache;
767          * we'll try to read the cache in again on the next read */
768         memset(&dbase->cachedVersion, 0, sizeof(dbase->cachedVersion));
769     } else {
770         memcpy(&dbase->cachedVersion, &dbase->version,
771                sizeof(dbase->cachedVersion));
772     }
773 }
774
775 /*!
776  * \brief This routine ends a read or write transaction on the open transaction identified by transPtr.
777  * \return an error code.
778  */
779 int
780 ubik_EndTrans(struct ubik_trans *transPtr)
781 {
782     afs_int32 code;
783     struct timeval tv;
784     afs_int32 realStart;
785     struct ubik_server *ts;
786     afs_int32 now;
787     int cachelocked = 0;
788     struct ubik_dbase *dbase;
789
790     if (transPtr->type == UBIK_WRITETRANS) {
791         code = ubik_Flush(transPtr);
792         if (code) {
793             ubik_AbortTrans(transPtr);
794             return (code);
795         }
796     }
797
798     dbase = transPtr->dbase;
799
800     if (transPtr->flags & TRCACHELOCKED) {
801         ReleaseReadLock(&dbase->cache_lock);
802         transPtr->flags &= ~TRCACHELOCKED;
803     }
804
805     if (transPtr->type != UBIK_READTRANS) {
806         /* must hold cache_lock before DBHOLD'ing */
807         ObtainWriteLock(&dbase->cache_lock);
808         cachelocked = 1;
809     }
810
811     DBHOLD(dbase);
812
813     /* give up if no longer current */
814     if (!urecovery_AllBetter(dbase, transPtr->flags & TRREADANY)) {
815         udisk_abort(transPtr);
816         udisk_end(transPtr);
817         DBRELE(dbase);
818         code = UNOQUORUM;
819         goto error;
820     }
821
822     if (transPtr->type == UBIK_READTRANS) {     /* reads are easy */
823         code = udisk_commit(transPtr);
824         if (code == 0)
825             goto success;       /* update cachedVersion correctly */
826         udisk_end(transPtr);
827         DBRELE(dbase);
828         goto error;
829     }
830
831     if (!ubeacon_AmSyncSite()) {        /* no longer sync site */
832         udisk_abort(transPtr);
833         udisk_end(transPtr);
834         DBRELE(dbase);
835         code = UNOTSYNC;
836         goto error;
837     }
838
839     /* now it is safe to do commit */
840     code = udisk_commit(transPtr);
841     if (code == 0) {
842         /* db data has been committed locally; update the local cache so
843          * readers can get at it */
844         WritebackApplicationCache(dbase);
845
846         ReleaseWriteLock(&dbase->cache_lock);
847
848         code = ContactQuorum_NoArguments(DISK_Commit, transPtr, CStampVersion);
849
850     } else {
851         memset(&dbase->cachedVersion, 0, sizeof(struct ubik_version));
852         ReleaseWriteLock(&dbase->cache_lock);
853     }
854     cachelocked = 0;
855     if (code) {
856         /* failed to commit, so must return failure.  Try to clear locks first, just for fun
857          * Note that we don't know if this transaction will eventually commit at this point.
858          * If it made it to a site that will be present in the next quorum, we win, otherwise
859          * we lose.  If we contact a majority of sites, then we won't be here: contacting
860          * a majority guarantees commit, since it guarantees that one dude will be a
861          * member of the next quorum. */
862         ContactQuorum_NoArguments(DISK_ReleaseLocks, transPtr, 0);
863         udisk_end(transPtr);
864         DBRELE(dbase);
865         goto error;
866     }
867     /* before we can start sending unlock messages, we must wait until all servers
868      * that are possibly still functioning on the other side of a network partition
869      * have timed out.  Check the server structures, compute how long to wait, then
870      * start the unlocks */
871     realStart = FT_ApproxTime();
872     while (1) {
873         /* wait for all servers to time out */
874         code = 0;
875         now = FT_ApproxTime();
876         /* check if we're still sync site, the guy should either come up
877          * to us, or timeout.  Put safety check in anyway */
878         if (now - realStart > 10 * BIGTIME) {
879             ubik_stats.escapes++;
880             ubik_print("ubik escaping from commit wait\n");
881             break;
882         }
883         for (ts = ubik_servers; ts; ts = ts->next) {
884             if (!ts->beaconSinceDown && now <= ts->lastBeaconSent + BIGTIME) {
885
886                 /* this guy could have some damaged data, wait for him */
887                 code = 1;
888                 tv.tv_sec = 1;  /* try again after a while (ha ha) */
889                 tv.tv_usec = 0;
890
891 #ifdef AFS_PTHREAD_ENV
892                 /* we could release the dbase outside of the loop, but we do
893                  * it here, in the loop, to avoid an unnecessary RELE/HOLD
894                  * if all sites are up */
895                 DBRELE(dbase);
896                 select(0, 0, 0, 0, &tv);
897                 DBHOLD(dbase);
898 #else
899                 IOMGR_Select(0, 0, 0, 0, &tv);  /* poll, should we wait on something? */
900 #endif
901
902                 break;
903             }
904         }
905         if (code == 0)
906             break;              /* no down ones still pseudo-active */
907     }
908
909     /* finally, unlock all the dudes.  We can return success independent of the number of servers
910      * that really unlock the dbase; the others will do it if/when they elect a new sync site.
911      * The transaction is committed anyway, since we succeeded in contacting a quorum
912      * at the start (when invoking the DiskCommit function).
913      */
914     ContactQuorum_NoArguments(DISK_ReleaseLocks, transPtr, 0);
915
916   success:
917     udisk_end(transPtr);
918     /* don't update cachedVersion here; it should have been updated way back
919      * in ubik_CheckCache, and earlier in this function for writes */
920     DBRELE(dbase);
921     if (cachelocked) {
922         ReleaseWriteLock(&dbase->cache_lock);
923     }
924     return 0;
925
926   error:
927     if (!cachelocked) {
928         ObtainWriteLock(&dbase->cache_lock);
929     }
930     memset(&dbase->cachedVersion, 0, sizeof(struct ubik_version));
931     ReleaseWriteLock(&dbase->cache_lock);
932     return code;
933 }
934
935 /*!
936  * \brief This routine reads length bytes into buffer from the current position in the database.
937  *
938  * The file pointer is updated appropriately (by adding the number of bytes actually transferred), and the length actually transferred is stored in the long integer pointed to by length.  A short read returns zero for an error code.
939  *
940  * \note *length is an INOUT parameter: at the start it represents the size of the buffer, and when done, it contains the number of bytes actually transferred.
941  */
942 int
943 ubik_Read(struct ubik_trans *transPtr, void *buffer,
944           afs_int32 length)
945 {
946     afs_int32 code;
947
948     /* reads are easy to do: handle locally */
949     DBHOLD(transPtr->dbase);
950     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY)) {
951         DBRELE(transPtr->dbase);
952         return UNOQUORUM;
953     }
954
955     code =
956         udisk_read(transPtr, transPtr->seekFile, buffer, transPtr->seekPos,
957                    length);
958     if (code == 0) {
959         transPtr->seekPos += length;
960     }
961     DBRELE(transPtr->dbase);
962     return code;
963 }
964
965 /*!
966  * \brief This routine will flush the io data in the iovec structures.
967  *
968  * It first flushes to the local disk and then uses ContactQuorum to write it
969  * to the other servers.
970  */
971 int
972 ubik_Flush(struct ubik_trans *transPtr)
973 {
974     afs_int32 code, error = 0;
975
976     if (transPtr->type != UBIK_WRITETRANS)
977         return UBADTYPE;
978     if (!transPtr->iovec_info.iovec_wrt_len
979         || !transPtr->iovec_info.iovec_wrt_val)
980         return 0;
981
982     DBHOLD(transPtr->dbase);
983     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY))
984         ERROR_EXIT(UNOQUORUM);
985     if (!ubeacon_AmSyncSite())  /* only sync site can write */
986         ERROR_EXIT(UNOTSYNC);
987
988     /* Update the rest of the servers in the quorum */
989     code =
990         ContactQuorum_DISK_WriteV(transPtr, 0, &transPtr->iovec_info,
991                                   &transPtr->iovec_data);
992     if (code) {
993         udisk_abort(transPtr);
994         ContactQuorum_NoArguments(DISK_Abort, transPtr, 0); /* force aborts to the others */
995         transPtr->iovec_info.iovec_wrt_len = 0;
996         transPtr->iovec_data.iovec_buf_len = 0;
997         ERROR_EXIT(code);
998     }
999
1000     /* Wrote the buffers out, so start at scratch again */
1001     transPtr->iovec_info.iovec_wrt_len = 0;
1002     transPtr->iovec_data.iovec_buf_len = 0;
1003
1004   error_exit:
1005     DBRELE(transPtr->dbase);
1006     return error;
1007 }
1008
1009 int
1010 ubik_Write(struct ubik_trans *transPtr, void *vbuffer,
1011            afs_int32 length)
1012 {
1013     struct ubik_iovec *iovec;
1014     afs_int32 code, error = 0;
1015     afs_int32 pos, len, size;
1016     char * buffer = (char *)vbuffer;
1017
1018     if (transPtr->type != UBIK_WRITETRANS)
1019         return UBADTYPE;
1020     if (!length)
1021         return 0;
1022
1023     if (length > IOVEC_MAXBUF) {
1024         for (pos = 0, len = length; len > 0; len -= size, pos += size) {
1025             size = ((len < IOVEC_MAXBUF) ? len : IOVEC_MAXBUF);
1026             code = ubik_Write(transPtr, buffer+pos, size);
1027             if (code)
1028                 return (code);
1029         }
1030         return 0;
1031     }
1032
1033     if (!transPtr->iovec_info.iovec_wrt_val) {
1034         transPtr->iovec_info.iovec_wrt_len = 0;
1035         transPtr->iovec_info.iovec_wrt_val =
1036             (struct ubik_iovec *)malloc(IOVEC_MAXWRT *
1037                                         sizeof(struct ubik_iovec));
1038         transPtr->iovec_data.iovec_buf_len = 0;
1039         transPtr->iovec_data.iovec_buf_val = (char *)malloc(IOVEC_MAXBUF);
1040         if (!transPtr->iovec_info.iovec_wrt_val
1041             || !transPtr->iovec_data.iovec_buf_val) {
1042             if (transPtr->iovec_info.iovec_wrt_val)
1043                 free(transPtr->iovec_info.iovec_wrt_val);
1044             transPtr->iovec_info.iovec_wrt_val = 0;
1045             if (transPtr->iovec_data.iovec_buf_val)
1046                 free(transPtr->iovec_data.iovec_buf_val);
1047             transPtr->iovec_data.iovec_buf_val = 0;
1048             return UNOMEM;
1049         }
1050     }
1051
1052     /* If this write won't fit in the structure, then flush it out and start anew */
1053     if ((transPtr->iovec_info.iovec_wrt_len >= IOVEC_MAXWRT)
1054         || ((length + transPtr->iovec_data.iovec_buf_len) > IOVEC_MAXBUF)) {
1055         code = ubik_Flush(transPtr);
1056         if (code)
1057             return (code);
1058     }
1059
1060     DBHOLD(transPtr->dbase);
1061     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY))
1062         ERROR_EXIT(UNOQUORUM);
1063     if (!ubeacon_AmSyncSite())  /* only sync site can write */
1064         ERROR_EXIT(UNOTSYNC);
1065
1066     /* Write to the local disk */
1067     code =
1068         udisk_write(transPtr, transPtr->seekFile, buffer, transPtr->seekPos,
1069                     length);
1070     if (code) {
1071         udisk_abort(transPtr);
1072         transPtr->iovec_info.iovec_wrt_len = 0;
1073         transPtr->iovec_data.iovec_buf_len = 0;
1074         DBRELE(transPtr->dbase);
1075         return (code);
1076     }
1077
1078     /* Collect writes for the other ubik servers (to be done in bulk) */
1079     iovec = (struct ubik_iovec *)transPtr->iovec_info.iovec_wrt_val;
1080     iovec[transPtr->iovec_info.iovec_wrt_len].file = transPtr->seekFile;
1081     iovec[transPtr->iovec_info.iovec_wrt_len].position = transPtr->seekPos;
1082     iovec[transPtr->iovec_info.iovec_wrt_len].length = length;
1083
1084     memcpy(&transPtr->iovec_data.
1085            iovec_buf_val[transPtr->iovec_data.iovec_buf_len], buffer, length);
1086
1087     transPtr->iovec_info.iovec_wrt_len++;
1088     transPtr->iovec_data.iovec_buf_len += length;
1089     transPtr->seekPos += length;
1090
1091   error_exit:
1092     DBRELE(transPtr->dbase);
1093     return error;
1094 }
1095
1096 /*!
1097  * \brief This sets the file pointer associated with the current transaction
1098  * to the appropriate file and byte position.
1099  *
1100  * Unlike Unix files, a transaction is labelled by both a file number \p fileid
1101  * and a byte position relative to the specified file \p position.
1102  */
1103 int
1104 ubik_Seek(struct ubik_trans *transPtr, afs_int32 fileid,
1105           afs_int32 position)
1106 {
1107     afs_int32 code;
1108
1109     DBHOLD(transPtr->dbase);
1110     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY)) {
1111         code = UNOQUORUM;
1112     } else {
1113         transPtr->seekFile = fileid;
1114         transPtr->seekPos = position;
1115         code = 0;
1116     }
1117     DBRELE(transPtr->dbase);
1118     return code;
1119 }
1120
1121 /*!
1122  * \brief This call returns the file pointer associated with the specified
1123  * transaction in \p fileid and \p position.
1124  */
1125 int
1126 ubik_Tell(struct ubik_trans *transPtr, afs_int32 * fileid,
1127           afs_int32 * position)
1128 {
1129     DBHOLD(transPtr->dbase);
1130     *fileid = transPtr->seekFile;
1131     *position = transPtr->seekPos;
1132     DBRELE(transPtr->dbase);
1133     return 0;
1134 }
1135
1136 /*!
1137  * \brief This sets the file size for the currently-selected file to \p length
1138  * bytes, if length is less than the file's current size.
1139  */
1140 int
1141 ubik_Truncate(struct ubik_trans *transPtr, afs_int32 length)
1142 {
1143     afs_int32 code, error = 0;
1144
1145     /* Will also catch if not UBIK_WRITETRANS */
1146     code = ubik_Flush(transPtr);
1147     if (code)
1148         return (code);
1149
1150     DBHOLD(transPtr->dbase);
1151     /* first, check that quorum is still good, and that dbase is up-to-date */
1152     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY))
1153         ERROR_EXIT(UNOQUORUM);
1154     if (!ubeacon_AmSyncSite())
1155         ERROR_EXIT(UNOTSYNC);
1156
1157     /* now do the operation locally, and propagate it out */
1158     code = udisk_truncate(transPtr, transPtr->seekFile, length);
1159     if (!code) {
1160         code =
1161             ContactQuorum_DISK_Truncate(transPtr, 0, transPtr->seekFile,
1162                                         length);
1163     }
1164     if (code) {
1165         /* we must abort the operation */
1166         udisk_abort(transPtr);
1167         ContactQuorum_NoArguments(DISK_Abort, transPtr, 0); /* force aborts to the others */
1168         ERROR_EXIT(code);
1169     }
1170
1171   error_exit:
1172     DBRELE(transPtr->dbase);
1173     return error;
1174 }
1175
1176 /*!
1177  * \brief set a lock; all locks are released on transaction end (commit/abort)
1178  */
1179 int
1180 ubik_SetLock(struct ubik_trans *atrans, afs_int32 apos, afs_int32 alen,
1181              int atype)
1182 {
1183     afs_int32 code = 0, error = 0;
1184
1185     if (atype == LOCKWRITE) {
1186         if (atrans->type == UBIK_READTRANS)
1187             return UBADTYPE;
1188         code = ubik_Flush(atrans);
1189         if (code)
1190             return (code);
1191     }
1192
1193     DBHOLD(atrans->dbase);
1194     if (atype == LOCKREAD) {
1195         code = ulock_getLock(atrans, atype, 1);
1196         if (code)
1197             ERROR_EXIT(code);
1198     } else {
1199         /* first, check that quorum is still good, and that dbase is up-to-date */
1200         if (!urecovery_AllBetter(atrans->dbase, atrans->flags & TRREADANY))
1201             ERROR_EXIT(UNOQUORUM);
1202         if (!ubeacon_AmSyncSite())
1203             ERROR_EXIT(UNOTSYNC);
1204
1205         /* now do the operation locally, and propagate it out */
1206         code = ulock_getLock(atrans, atype, 1);
1207         if (code == 0) {
1208             code = ContactQuorum_DISK_Lock(atrans, 0, 0, 1 /*unused */ ,
1209                                            1 /*unused */ , LOCKWRITE);
1210         }
1211         if (code) {
1212             /* we must abort the operation */
1213             udisk_abort(atrans);
1214             ContactQuorum_NoArguments(DISK_Abort, atrans, 0); /* force aborts to the others */
1215             ERROR_EXIT(code);
1216         }
1217     }
1218
1219   error_exit:
1220     DBRELE(atrans->dbase);
1221     return error;
1222 }
1223
1224 /*!
1225  * \brief utility to wait for a version # to change
1226  */
1227 int
1228 ubik_WaitVersion(struct ubik_dbase *adatabase,
1229                  struct ubik_version *aversion)
1230 {
1231     DBHOLD(adatabase);
1232     while (1) {
1233         /* wait until version # changes, and then return */
1234         if (vcmp(*aversion, adatabase->version) != 0) {
1235             DBRELE(adatabase);
1236             return 0;
1237         }
1238 #ifdef AFS_PTHREAD_ENV
1239         CV_WAIT(&adatabase->version_cond, &adatabase->versionLock);
1240 #else
1241         DBRELE(adatabase);
1242         LWP_WaitProcess(&adatabase->version);   /* same vers, just wait */
1243         DBHOLD(adatabase);
1244 #endif
1245     }
1246 }
1247
1248 /*!
1249  * \brief utility to get the version of the dbase a transaction is dealing with
1250  */
1251 int
1252 ubik_GetVersion(struct ubik_trans *atrans,
1253                 struct ubik_version *avers)
1254 {
1255     *avers = atrans->dbase->version;
1256     return 0;
1257 }
1258
1259 /*!
1260  * \brief Facility to simplify database caching.
1261  * \return zero if last trans was done on the local server and was successful.
1262  * \return -1 means bad (NULL) argument.
1263  *
1264  * If return value is non-zero and the caller is a server caching part of the
1265  * Ubik database, it should invalidate that cache.
1266  */
1267 static int
1268 ubik_CacheUpdate(struct ubik_trans *atrans)
1269 {
1270     if (!(atrans && atrans->dbase))
1271         return -1;
1272     return vcmp(atrans->dbase->cachedVersion, atrans->dbase->version) != 0;
1273 }
1274
1275 /**
1276  * check and possibly update cache of ubik db.
1277  *
1278  * If the version of the cached db data is out of date, this calls (*check) to
1279  * update the cache. If (*check) returns success, we update the version of the
1280  * cached db data.
1281  *
1282  * Checking the version of the cached db data is done under a read lock;
1283  * updating the cache (and thus calling (*check)) is done under a write lock
1284  * so is guaranteed not to interfere with another thread's (*check). On
1285  * successful return, a read lock on the cached db data is obtained, which
1286  * will be released by ubik_EndTrans or ubik_AbortTrans.
1287  *
1288  * @param[in] atrans ubik transaction
1289  * @param[in] check  function to call to check/update cache
1290  * @param[in] rock   rock to pass to *check
1291  *
1292  * @return operation status
1293  *   @retval 0       success
1294  *   @retval nonzero error; cachedVersion not updated
1295  *
1296  * @post On success, application cache is read-locked, and cache data is
1297  *       up-to-date
1298  */
1299 int
1300 ubik_CheckCache(struct ubik_trans *atrans, ubik_updatecache_func cbf, void *rock)
1301 {
1302     int ret = 0;
1303
1304     if (!(atrans && atrans->dbase))
1305         return -1;
1306
1307     ObtainReadLock(&atrans->dbase->cache_lock);
1308
1309     while (ubik_CacheUpdate(atrans) != 0) {
1310
1311         ReleaseReadLock(&atrans->dbase->cache_lock);
1312         ObtainSharedLock(&atrans->dbase->cache_lock);
1313
1314         if (ubik_CacheUpdate(atrans) != 0) {
1315
1316             BoostSharedLock(&atrans->dbase->cache_lock);
1317
1318             ret = (*cbf) (atrans, rock);
1319             if (ret == 0) {
1320                 memcpy(&atrans->dbase->cachedVersion, &atrans->dbase->version,
1321                        sizeof(atrans->dbase->cachedVersion));
1322             }
1323         }
1324
1325         /* It would be nice if we could convert from a shared lock to a read
1326          * lock... instead, just release the shared and acquire the read */
1327         ReleaseSharedLock(&atrans->dbase->cache_lock);
1328
1329         if (ret) {
1330             /* if we have an error, don't retry, and don't hold any locks */
1331             return ret;
1332         }
1333
1334         ObtainReadLock(&atrans->dbase->cache_lock);
1335     }
1336
1337     atrans->flags |= TRCACHELOCKED;
1338
1339     return 0;
1340 }
1341
1342 /*!
1343  * "Who said anything about panicking?" snapped Arthur.
1344  * "This is still just the culture shock. You wait till I've settled down
1345  * into the situation and found my bearings. \em Then I'll start panicking!"
1346  * --Authur Dent
1347  *
1348  * \returns There is no return from panic.
1349  */
1350 void
1351 panic(char *format, ...)
1352 {
1353     va_list ap;
1354
1355     va_start(ap, format);
1356     ubik_print("Ubik PANIC: ");
1357     ubik_vprint(format, ap);
1358     va_end(ap);
1359
1360     abort();
1361     ubik_print("BACK FROM ABORT\n");    /* shouldn't come back */
1362     exit(1);                    /* never know, though  */
1363 }
1364
1365 /*!
1366  * This function takes an IP addresses as its parameter. It returns the
1367  * the primary IP address that is on the host passed in, or 0 if not found.
1368  */
1369 afs_uint32
1370 ubikGetPrimaryInterfaceAddr(afs_uint32 addr)
1371 {
1372     struct ubik_server *ts;
1373     int j;
1374
1375     for (ts = ubik_servers; ts; ts = ts->next)
1376         for (j = 0; j < UBIK_MAX_INTERFACE_ADDR; j++)
1377             if (ts->addr[j] == addr)
1378                 return ts->addr[0];     /* net byte order */
1379     return 0;                   /* if not in server database, return error */
1380 }