ubik: take DB lock in ubik_GetVersion
[openafs.git] / src / ubik / ubik.c
index a2d6fc0..ae8c350 100644 (file)
 
 #include <roken.h>
 
-#include <sys/types.h>
-#include <string.h>
-#include <stdarg.h>
-#include <time.h>
-
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#else
-#include <sys/file.h>
-#include <netinet/in.h>
-#include <sys/param.h>
-#endif
-
 #include <lock.h>
 #include <rx/xdr.h>
 #include <rx/rx.h>
@@ -85,16 +72,33 @@ struct ubik_stats ubik_stats;
 afs_uint32 ubik_host[UBIK_MAX_INTERFACE_ADDR];
 afs_int32 ubik_epochTime = 0;
 afs_int32 urecovery_state = 0;
-int (*ubik_SRXSecurityProc) (void *, struct rx_securityClass **, afs_int32 *);
-void *ubik_SRXSecurityRock;
 int (*ubik_SyncWriterCacheProc) (void);
 struct ubik_server *ubik_servers;
 short ubik_callPortal;
 
+/* These global variables were used to control the server security layers.
+ * They are retained for backwards compatibility with legacy callers.
+ *
+ * The ubik_SetServerSecurityProcs() interface should be used instead.
+ */
+
+int (*ubik_SRXSecurityProc) (void *, struct rx_securityClass **, afs_int32 *);
+void *ubik_SRXSecurityRock;
+int (*ubik_CheckRXSecurityProc) (void *, struct rx_call *);
+void *ubik_CheckRXSecurityRock;
+
+
+
 static int BeginTrans(struct ubik_dbase *dbase, afs_int32 transMode,
                      struct ubik_trans **transPtr, int readAny);
 
-struct rx_securityClass *ubik_sc[3];
+static struct rx_securityClass **ubik_sc = NULL;
+static void (*buildSecClassesProc)(void *, struct rx_securityClass ***,
+                                  afs_int32 *) = NULL;
+static int (*checkSecurityProc)(void *, struct rx_call *) = NULL;
+static void *securityRock = NULL;
+
+struct version_data version_globals;
 
 #define        CStampVersion       1   /* meaning set ts->version */
 
@@ -103,11 +107,15 @@ Quorum_StartIO(struct ubik_trans *atrans, struct ubik_server *as)
 {
     struct rx_connection *conn;
 
+    UBIK_ADDR_LOCK;
     conn = as->disk_rxcid;
 
 #ifdef AFS_PTHREAD_ENV
     rx_GetConnection(conn);
+    UBIK_ADDR_UNLOCK;
     DBRELE(atrans->dbase);
+#else
+    UBIK_ADDR_UNLOCK;
 #endif /* AFS_PTHREAD_ENV */
 
     return conn;
@@ -147,8 +155,10 @@ ContactQuorum_iterate(struct ubik_trans *atrans, int aflags, struct ubik_server
            *conn = NULL;
            if (code) {         /* failure */
                *rcode = code;
+               UBIK_BEACON_LOCK;
                (*ts)->up = 0;          /* mark as down now; beacons will no longer be sent */
                (*ts)->beaconSinceDown = 0;
+               UBIK_BEACON_UNLOCK;
                (*ts)->currentDB = 0;
                urecovery_LostServer(*ts);      /* tell recovery to try to resend dbase later */
            } else {            /* success */
@@ -163,10 +173,13 @@ ContactQuorum_iterate(struct ubik_trans *atrans, int aflags, struct ubik_server
     }
     if (!(*ts))
        return 1;
+    UBIK_BEACON_LOCK;
     if (!(*ts)->up || !(*ts)->currentDB) {
+       UBIK_BEACON_UNLOCK;
        (*ts)->currentDB = 0;   /* db is no longer current; we just missed an update */
        return 0;               /* not up-to-date, don't bother.  NULL conn will tell caller not to use */
     }
+    UBIK_BEACON_UNLOCK;
     *conn = Quorum_StartIO(atrans, *ts);
     return 0;
 }
@@ -298,9 +311,6 @@ ContactQuorum_DISK_WriteV(struct ubik_trans *atrans, int aflags,
                bulkdata tcbs;
                afs_int32 i, offset;
 
-               Quorum_EndIO(atrans, conn);
-               conn = Quorum_StartIO(atrans, ts);
-
                for (i = 0, offset = 0; i < io_vector->iovec_wrt_len; i++) {
                    /* Sanity check for going off end of buffer */
                    if ((offset + iovec[i].length) > io_buffer->iovec_buf_len) {
@@ -342,6 +352,15 @@ ContactQuorum_DISK_SetVersion(struct ubik_trans *atrans, int aflags,
     return ContactQuorum_rcode(okcalls, rcode);
 }
 
+#if defined(AFS_PTHREAD_ENV)
+static int
+ubik_thread_create(pthread_attr_t *tattr, pthread_t *thread, void *proc) {
+    osi_Assert(pthread_attr_init(tattr) == 0);
+    osi_Assert(pthread_attr_setdetachstate(tattr, PTHREAD_CREATE_DETACHED) == 0);
+    osi_Assert(pthread_create(thread, tattr, proc, NULL) == 0);
+    return 0;
+}
+#endif
 
 /*!
  * \brief This routine initializes the ubik system for a set of servers.
@@ -378,6 +397,7 @@ ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
 
     afs_int32 secIndex;
     struct rx_securityClass *secClass;
+    int numClasses;
 
     struct rx_service *tservice;
 
@@ -391,6 +411,9 @@ ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
     memset(&tdb->cachedVersion, 0, sizeof(struct ubik_version));
 #ifdef AFS_PTHREAD_ENV
     MUTEX_INIT(&tdb->versionLock, "version lock", MUTEX_DEFAULT, 0);
+    MUTEX_INIT(&beacon_globals.beacon_lock, "beacon lock", MUTEX_DEFAULT, 0);
+    MUTEX_INIT(&vote_globals.vote_lock, "vote lock", MUTEX_DEFAULT, 0);
+    MUTEX_INIT(&addr_globals.addr_lock, "address lock", MUTEX_DEFAULT, 0);
 #else
     Lock_Init(&tdb->versionLock);
 #endif
@@ -424,36 +447,43 @@ ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
        return code;
 
     udisk_Init(ubik_nBuffers);
+    ulock_Init();
+
+    code = uvote_Init();
+    if (code)
+       return code;
+    code = urecovery_Initialize(tdb);
+    if (code)
+       return code;
+    if (info)
+       code = ubeacon_InitServerListByInfo(myHost, info, clones);
+    else
+       code = ubeacon_InitServerList(myHost, serverList);
+    if (code)
+       return code;
 
     ubik_callPortal = myPort;
     /* try to get an additional security object */
-    ubik_sc[0] = rxnull_NewServerSecurityObject();
-    ubik_sc[1] = 0;
-    ubik_sc[2] = 0;
-    if (ubik_SRXSecurityProc) {
-       code =
-           (*ubik_SRXSecurityProc) (ubik_SRXSecurityRock, &secClass,
-                                    &secIndex);
-       if (code == 0) {
-           ubik_sc[secIndex] = secClass;
+    if (buildSecClassesProc == NULL) {
+       numClasses = 3;
+       ubik_sc = calloc(numClasses, sizeof(struct rx_securityClass *));
+       ubik_sc[0] = rxnull_NewServerSecurityObject();
+       if (ubik_SRXSecurityProc) {
+           code = (*ubik_SRXSecurityProc) (ubik_SRXSecurityRock,
+                                           &secClass,
+                                           &secIndex);
+           if (code == 0) {
+                ubik_sc[secIndex] = secClass;
+           }
        }
+    } else {
+        (*buildSecClassesProc) (securityRock, &ubik_sc, &numClasses);
     }
     /* for backwards compat this should keep working as it does now
        and not host bind */
-#if 0
-    /* This really needs to be up above, where I have put it.  It works
-     * here when we're non-pthreaded, but the code above, when using
-     * pthreads may (and almost certainly does) end up calling on a
-     * pthread resource which gets initialized by rx_Init.  The end
-     * result is that an assert fails and the program dies. -- klm
-     */
-    code = rx_Init(myPort);
-    if (code < 0)
-       return code;
-#endif
 
     tservice =
-       rx_NewService(0, VOTE_SERVICE_ID, "VOTE", ubik_sc, 3,
+       rx_NewService(0, VOTE_SERVICE_ID, "VOTE", ubik_sc, numClasses,
                      VOTE_ExecuteRequest);
     if (tservice == (struct rx_service *)0) {
        ubik_dprint("Could not create VOTE rx service!\n");
@@ -463,7 +493,7 @@ ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
     rx_SetMaxProcs(tservice, 3);
 
     tservice =
-       rx_NewService(0, DISK_SERVICE_ID, "DISK", ubik_sc, 3,
+       rx_NewService(0, DISK_SERVICE_ID, "DISK", ubik_sc, numClasses,
                      DISK_ExecuteRequest);
     if (tservice == (struct rx_service *)0) {
        ubik_dprint("Could not create DISK rx service!\n");
@@ -477,41 +507,16 @@ ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
      * the "steplock" problem in ubik initialization. Defect 11037.
      */
 #ifdef AFS_PTHREAD_ENV
-/* do assert stuff */
-    osi_Assert(pthread_attr_init(&rxServer_tattr) == 0);
-    osi_Assert(pthread_attr_setdetachstate(&rxServer_tattr, PTHREAD_CREATE_DETACHED) == 0);
-/*    osi_Assert(pthread_attr_setstacksize(&rxServer_tattr, rx_stackSize) == 0); */
-
-    osi_Assert(pthread_create(&rxServerThread, &rxServer_tattr, (void *)rx_ServerProc, NULL) == 0);
+    ubik_thread_create(&rxServer_tattr, &rxServerThread, (void *)rx_ServerProc);
 #else
     LWP_CreateProcess(rx_ServerProc, rx_stackSize, RX_PROCESS_PRIORITY,
               NULL, "rx_ServerProc", &junk);
 #endif
 
-    /* do basic initialization */
-    code = uvote_Init();
-    if (code)
-       return code;
-    code = urecovery_Initialize(tdb);
-    if (code)
-       return code;
-    if (info)
-       code = ubeacon_InitServerListByInfo(myHost, info, clones);
-    else
-       code = ubeacon_InitServerList(myHost, serverList);
-    if (code)
-       return code;
-
     /* now start up async processes */
 #ifdef AFS_PTHREAD_ENV
-/* do assert stuff */
-    osi_Assert(pthread_attr_init(&ubeacon_Interact_tattr) == 0);
-    osi_Assert(pthread_attr_setdetachstate(&ubeacon_Interact_tattr, PTHREAD_CREATE_DETACHED) == 0);
-/*    osi_Assert(pthread_attr_setstacksize(&ubeacon_Interact_tattr, 16384) == 0); */
-    /*  need another attr set here for priority???  - klm */
-
-    osi_Assert(pthread_create(&ubeacon_InteractThread, &ubeacon_Interact_tattr,
-           (void *)ubeacon_Interact, NULL) == 0);
+    ubik_thread_create(&ubeacon_Interact_tattr, &ubeacon_InteractThread,
+               (void *)ubeacon_Interact);
 #else
     code = LWP_CreateProcess(ubeacon_Interact, 16384 /*8192 */ ,
                             LWP_MAX_PRIORITY - 1, (void *)0, "beacon",
@@ -521,15 +526,8 @@ ubik_ServerInitCommon(afs_uint32 myHost, short myPort,
 #endif
 
 #ifdef AFS_PTHREAD_ENV
-/* do assert stuff */
-    osi_Assert(pthread_attr_init(&urecovery_Interact_tattr) == 0);
-    osi_Assert(pthread_attr_setdetachstate(&urecovery_Interact_tattr, PTHREAD_CREATE_DETACHED) == 0);
-/*    osi_Assert(pthread_attr_setstacksize(&urecovery_Interact_tattr, 16384) == 0); */
-    /*  need another attr set here for priority???  - klm */
-
-    osi_Assert(pthread_create(&urecovery_InteractThread, &urecovery_Interact_tattr,
-           (void *)urecovery_Interact, NULL) == 0);
-
+    ubik_thread_create(&urecovery_Interact_tattr, &urecovery_InteractThread,
+               (void *)urecovery_Interact);
     return 0;  /* is this correct?  - klm */
 #else
     code = LWP_CreateProcess(urecovery_Interact, 16384 /*8192 */ ,
@@ -640,6 +638,7 @@ BeginTrans(struct ubik_dbase *dbase, afs_int32 transMode,
        DBRELE(dbase);
        return code;
     }
+    UBIK_VERSION_LOCK;
     if (readAny) {
        tt->flags |= TRREADANY;
        if (readAny > 1) {
@@ -662,12 +661,14 @@ BeginTrans(struct ubik_dbase *dbase, afs_int32 transMode,
            udisk_abort(tt);
            ContactQuorum_NoArguments(DISK_Abort, tt, 0); /* force aborts to the others */
            udisk_end(tt);
+           UBIK_VERSION_UNLOCK;
            DBRELE(dbase);
            return code;
        }
     }
 
     *transPtr = tt;
+    UBIK_VERSION_UNLOCK;
     DBRELE(dbase);
     return 0;
 }
@@ -883,7 +884,9 @@ ubik_EndTrans(struct ubik_trans *transPtr)
            break;
        }
        for (ts = ubik_servers; ts; ts = ts->next) {
+           UBIK_BEACON_LOCK;
            if (!ts->beaconSinceDown && now <= ts->lastBeaconSent + BIGTIME) {
+               UBIK_BEACON_UNLOCK;
 
                /* this guy could have some damaged data, wait for him */
                code = 1;
@@ -903,6 +906,7 @@ ubik_EndTrans(struct ubik_trans *transPtr)
 
                break;
            }
+           UBIK_BEACON_UNLOCK;
        }
        if (code == 0)
            break;              /* no down ones still pseudo-active */
@@ -977,11 +981,14 @@ ubik_Flush(struct ubik_trans *transPtr)
 
     if (transPtr->type != UBIK_WRITETRANS)
        return UBADTYPE;
+
+    DBHOLD(transPtr->dbase);
     if (!transPtr->iovec_info.iovec_wrt_len
-       || !transPtr->iovec_info.iovec_wrt_val)
+       || !transPtr->iovec_info.iovec_wrt_val) {
+       DBRELE(transPtr->dbase);
        return 0;
+    }
 
-    DBHOLD(transPtr->dbase);
     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY))
        ERROR_EXIT(UNOQUORUM);
     if (!ubeacon_AmSyncSite()) /* only sync site can write */
@@ -1032,6 +1039,7 @@ ubik_Write(struct ubik_trans *transPtr, void *vbuffer,
        return 0;
     }
 
+    DBHOLD(transPtr->dbase);
     if (!transPtr->iovec_info.iovec_wrt_val) {
        transPtr->iovec_info.iovec_wrt_len = 0;
        transPtr->iovec_info.iovec_wrt_val =
@@ -1047,6 +1055,7 @@ ubik_Write(struct ubik_trans *transPtr, void *vbuffer,
            if (transPtr->iovec_data.iovec_buf_val)
                free(transPtr->iovec_data.iovec_buf_val);
            transPtr->iovec_data.iovec_buf_val = 0;
+           DBRELE(transPtr->dbase);
            return UNOMEM;
        }
     }
@@ -1054,12 +1063,14 @@ ubik_Write(struct ubik_trans *transPtr, void *vbuffer,
     /* If this write won't fit in the structure, then flush it out and start anew */
     if ((transPtr->iovec_info.iovec_wrt_len >= IOVEC_MAXWRT)
        || ((length + transPtr->iovec_data.iovec_buf_len) > IOVEC_MAXBUF)) {
+       /* Can't hold the DB lock over ubik_Flush */
+       DBRELE(transPtr->dbase);
        code = ubik_Flush(transPtr);
        if (code)
            return (code);
+       DBHOLD(transPtr->dbase);
     }
 
-    DBHOLD(transPtr->dbase);
     if (!urecovery_AllBetter(transPtr->dbase, transPtr->flags & TRREADANY))
        ERROR_EXIT(UNOQUORUM);
     if (!ubeacon_AmSyncSite()) /* only sync site can write */
@@ -1254,7 +1265,9 @@ int
 ubik_GetVersion(struct ubik_trans *atrans,
                struct ubik_version *avers)
 {
+    DBHOLD(atrans->dbase);
     *avers = atrans->dbase->version;
+    DBRELE(atrans->dbase);
     return 0;
 }
 
@@ -1374,9 +1387,36 @@ ubikGetPrimaryInterfaceAddr(afs_uint32 addr)
     struct ubik_server *ts;
     int j;
 
+    UBIK_ADDR_LOCK;
     for (ts = ubik_servers; ts; ts = ts->next)
        for (j = 0; j < UBIK_MAX_INTERFACE_ADDR; j++)
-           if (ts->addr[j] == addr)
+           if (ts->addr[j] == addr) {
+               UBIK_ADDR_UNLOCK;
                return ts->addr[0];     /* net byte order */
+           }
+    UBIK_ADDR_UNLOCK;
     return 0;                  /* if not in server database, return error */
 }
+
+int
+ubik_CheckAuth(struct rx_call *acall)
+{
+    if (checkSecurityProc)
+       return (*checkSecurityProc) (securityRock, acall);
+    else if (ubik_CheckRXSecurityProc) {
+       return (*ubik_CheckRXSecurityProc) (ubik_CheckRXSecurityRock, acall);
+    } else
+       return 0;
+}
+
+void
+ubik_SetServerSecurityProcs(void (*buildproc) (void *,
+                                              struct rx_securityClass ***,
+                                              afs_int32 *),
+                           int (*checkproc) (void *, struct rx_call *),
+                           void *rock)
+{
+    buildSecClassesProc = buildproc;
+    checkSecurityProc = checkproc;
+    securityRock = rock;
+}