afsdb-callout-and-userspace-implementation-20010430
authorNickolai Zeldovich <kolya@mit.edu>
Mon, 30 Apr 2001 23:08:39 +0000 (23:08 +0000)
committerDerrick Brashear <shadow@dementia.org>
Mon, 30 Apr 2001 23:08:39 +0000 (23:08 +0000)
"This patch implements AFSDB support for both user-space programs
and for the kernel.. I've tested these on sun4x_57 (64-bit) and
on i386_linux22."

not currently enabled in any configuration

src/afs/afs.h
src/afs/afs_call.c
src/afs/afs_cell.c
src/afs/afs_init.c
src/afs/afs_pioctl.c
src/afsd/afsd.c
src/auth/cellconfig.c
src/auth/cellconfig.p.h
src/config/afs_args.h

index 4f80931..8a957a6 100644 (file)
@@ -194,6 +194,7 @@ struct cell {
     u_short vlport;                        /* volume server port */
     short states;                          /* state flags */
     short cellIndex;                       /* relative index number per cell */
+    time_t timeout;                        /* data expire time, if non-zero */
 };
 
 #define        afs_PutCell(cellp, locktype)
index 930b294..ef33045 100644 (file)
@@ -284,7 +284,7 @@ long parm, parm2, parm3, parm4, parm5, parm6;
                AFS_COPYIN((char *)parm3, tcell.cellName, parm4, code);
                if (!code) 
                    afs_NewCell(tcell.cellName, tcell.hosts, parm5,
-                               (char *)0, (u_short)0, (u_short)0);
+                               (char *)0, (u_short)0, (u_short)0, (int)0);
            }
        }
     } else if (parm == AFSOP_ADDCELL2) {
@@ -314,7 +314,7 @@ long parm, parm2, parm3, parm4, parm5, parm6;
                }
                if (!code)
                    afs_NewCell(tbuffer1, tcell.hosts, cflags, 
-                               lcnamep, (u_short)0, (u_short)0);
+                               lcnamep, (u_short)0, (u_short)0, (int)0);
            }
        }
        osi_FreeSmallSpace(tbuffer);
@@ -595,7 +595,22 @@ long parm, parm2, parm3, parm4, parm5, parm6;
 #endif /* !AFS_SUN5_ENV */
       if (!code) 
         AFS_COPYOUT ((caddr_t)&mask, (caddr_t)parm3, sizeof(afs_int32), code);
-  } else
+    }
+#ifdef AFS_AFSDB_ENV
+    else if (parm == AFSOP_AFSDB_HANDLER) {
+       int sizeArg = (int)parm4;
+       int kmsgLen = sizeArg & 0xffff;
+       int cellLen = (sizeArg & 0xffff0000) >> 16;
+       afs_int32 *kmsg = afs_osi_Alloc(kmsgLen);
+       char *cellname = afs_osi_Alloc(cellLen);
+       AFS_COPYIN((afs_int32 *)parm3, kmsg, kmsgLen, code);
+       if (!code) code = afs_AfsdbHandler(cellname, cellLen, kmsg);
+       if (!code) AFS_COPYOUT(cellname, (char *)parm2, cellLen, code);
+       afs_osi_Free(kmsg, kmsgLen);
+       afs_osi_Free(cellname, cellLen);
+    }
+#endif
+    else
       code = EINVAL;
 
 out:
index 2b271e1..f1a0f0c 100644 (file)
 afs_rwlock_t afs_xcell;                        /* allocation lock for cells */
 struct afs_q CellLRU;
 afs_int32 afs_cellindex=0;
+afs_uint32 afs_nextCellNum = 0x100;
 
 
 /* Local variables. */
 struct cell *afs_rootcell = 0;
 
-struct cell *afs_GetCellByName(acellName, locktype)
+static char afs_AfsdbHandlerWait;
+static char afs_AfsdbLookupWait;
+
+char afs_AfsdbHandlerPresent = 0;
+char afs_AfsdbHandlerInuse = 0;
+
+char *afs_AfsdbHandler_CellName;
+afs_int32 *afs_AfsdbHandler_CellHosts;
+int *afs_AfsdbHandler_Timeout;
+
+char afs_AfsdbHandler_ReqPending;
+char afs_AfsdbHandler_Completed;
+
+
+struct cell *afs_GetCellByName_int();
+
+int afs_strcasecmp(s1, s2)
+    register char *s1, *s2;
+{
+    while (*s1 && *s2) {
+       register char c1, c2;
+
+       c1 = *s1++;
+       c2 = *s2++;
+       if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
+       if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
+       if (c1 != c2)
+           return c1-c2;
+    }
+
+    return *s1 - *s2;
+}
+
+
+#ifdef AFS_AFSDB_ENV
+int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
+    char *acellName;
+    int acellNameLen;
+    afs_int32 *kernelMsg;
+{
+    /* afs_syscall_call() has already grabbed the global lock */
+
+    afs_AfsdbHandlerPresent = 1;
+
+    if (afs_AfsdbHandler_ReqPending) {
+       int i, hostCount;
+
+       hostCount = kernelMsg[0];
+       *afs_AfsdbHandler_Timeout = kernelMsg[1];
+       if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
+
+       for (i=0; i<MAXCELLHOSTS; i++) {
+           if (i >= hostCount)
+               afs_AfsdbHandler_CellHosts[i] = 0;
+           else
+               afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
+       }
+
+       /* Request completed, wake up the relevant thread */
+       afs_AfsdbHandler_ReqPending = 0;
+       afs_AfsdbHandler_Completed = 1;
+       afs_osi_Wakeup(&afs_AfsdbLookupWait);
+    }
+
+    /* Wait for a request */
+    while (afs_AfsdbHandler_ReqPending == 0)
+       afs_osi_Sleep(&afs_AfsdbHandlerWait);
+
+    /* Copy the requested cell name into the request buffer */
+    strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
+
+    /* Return the lookup request to userspace */    
+    return 0;
+}
+#endif
+
+
+int afs_GetCellHostsFromDns(acellName, acellHosts, timeout)
+    char *acellName;
+    afs_int32 *acellHosts;
+    int *timeout;
+{
+#ifdef AFS_AFSDB_ENV
+    char grab_glock = 0;
+
+    if (!afs_AfsdbHandlerPresent) return ENOENT;
+
+    if (!ISAFS_GLOCK()) {
+       grab_glock = 1;
+       AFS_GLOCK();
+    }
+
+    /* Wait until the AFSDB handler is available, and grab it */
+    while (afs_AfsdbHandlerInuse)
+       afs_osi_Sleep(&afs_AfsdbLookupWait);
+    afs_AfsdbHandlerInuse = 1;
+
+    /* Set up parameters for the handler */
+    afs_AfsdbHandler_CellName = acellName;
+    afs_AfsdbHandler_CellHosts = acellHosts;
+    afs_AfsdbHandler_Timeout = timeout;
+
+    /* Wake up the AFSDB handler */
+    afs_AfsdbHandler_Completed = 0;
+    afs_AfsdbHandler_ReqPending = 1;
+    afs_osi_Wakeup(&afs_AfsdbHandlerWait);
+
+    /* Wait for the handler to get back to us with the reply */
+    while (!afs_AfsdbHandler_Completed)
+       afs_osi_Sleep(&afs_AfsdbLookupWait);
+
+    /* Release the AFSDB handler and wake up others waiting for it */
+    afs_AfsdbHandlerInuse = 0;
+    afs_osi_Wakeup(&afs_AfsdbLookupWait);
+
+    if (grab_glock) AFS_GUNLOCK();
+
+    if (*acellHosts) return 0;
+    return ENOENT;
+#else
+    return ENOENT;
+#endif
+}
+
+
+void afs_RefreshCell(tc)
+    register struct cell *tc;
+{
+    afs_int32 acellHosts[MAXCELLHOSTS];
+    int timeout;
+
+    /* Don't need to do anything if no timeout or it's not expired */
+    if (!tc->timeout || tc->timeout > osi_Time()) return;
+
+    if (!afs_GetCellHostsFromDns(tc->cellName, acellHosts, &timeout)) {
+       afs_NewCell(tc->cellName, acellHosts, tc->states,
+                   tc->lcellp ? tc->lcellp->cellName : (char *) 0,
+                   tc->fsport, tc->vlport, timeout);
+    }
+
+    /* In case of a DNS failure, keep old cell data.. */
+    return;
+}
+
+
+struct cell *afs_GetCellByName_Dns(acellName, locktype)
+    register char *acellName;
+    afs_int32 locktype;
+{
+    afs_int32 acellHosts[MAXCELLHOSTS];
+    int timeout;
+
+    if (afs_GetCellHostsFromDns(acellName, acellHosts, &timeout))
+       return (struct cell *) 0;
+    if (afs_NewCell(acellName, acellHosts, CNoSUID, (char *) 0, 0, 0, timeout))
+       return (struct cell *) 0;
+
+    return afs_GetCellByName_int(acellName, locktype, 0);
+}
+
+
+struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
     register char *acellName;
     afs_int32 locktype;
+    char trydns;
 {
     register struct cell *tc;
     register struct afs_q *cq, *tq;
@@ -58,15 +221,26 @@ struct cell *afs_GetCellByName(acellName, locktype)
     ObtainWriteLock(&afs_xcell,100);
     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
        tc = QTOC(cq); tq = QNext(cq);
-       if (!strcmp(tc->cellName, acellName)) {
+       if (!afs_strcasecmp(tc->cellName, acellName)) {
            QRemove(&tc->lruq);
            QAdd(&CellLRU, &tc->lruq);
            ReleaseWriteLock(&afs_xcell);
+           afs_RefreshCell(tc);
            return tc;
        }
     }
     ReleaseWriteLock(&afs_xcell);
-    return (struct cell *) 0;
+    return trydns ? afs_GetCellByName_Dns(acellName, locktype)
+                 : (struct cell *) 0;
+
+} /*afs_GetCellByName_int*/
+
+
+struct cell *afs_GetCellByName(acellName, locktype)
+    register char *acellName;
+    afs_int32 locktype;
+{
+    return afs_GetCellByName_int(acellName, locktype, 1);
 
 } /*afs_GetCellByName*/
 
@@ -87,6 +261,7 @@ struct cell *afs_GetCell(acell, locktype)
            QRemove(&tc->lruq);
            QAdd(&CellLRU, &tc->lruq);
            ReleaseWriteLock(&afs_xcell);
+           afs_RefreshCell(tc);
            return tc;
        }
     }
@@ -111,6 +286,7 @@ struct cell *afs_GetCellByIndex(cellindex, locktype)
            QRemove(&tc->lruq);
            QAdd(&CellLRU, &tc->lruq);
            ReleaseWriteLock(&afs_xcell);
+           afs_RefreshCell(tc);
            return tc;
        }
     }
@@ -120,12 +296,13 @@ struct cell *afs_GetCellByIndex(cellindex, locktype)
 } /*afs_GetCellByIndex*/
 
 
-afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport)
+afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout)
     int aflags;
     char *acellName;
     register afs_int32 *acellHosts;
     char *linkedcname;
     u_short fsport, vlport;
+    int timeout;
 {
     register struct cell *tc, *tcl=0;
     register afs_int32 i, newc=0, code=0;
@@ -141,7 +318,7 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
     /* Find the cell and mark its servers as not down but gone */
     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
        tc = QTOC(cq); tq = QNext(cq);
-       if (strcmp(tc->cellName, acellName) == 0) {
+       if (afs_strcasecmp(tc->cellName, acellName) == 0) {
            /* we don't want to keep pinging old vlservers which were down,
             * since they don't matter any more.  It's easier to do this than
             * to remove the server from its various hash tables. */
@@ -169,7 +346,7 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
            afs_rootcell = tc;
            afs_rootCellIndex = tc->cellIndex;
        } else {
-           tc->cell = *acellHosts; /* won't be reused by another cell */
+           tc->cell = afs_nextCellNum++;
        }
        tc->states = 0;
        tc->lcellp = (struct cell *)0;
@@ -186,7 +363,7 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
        }
        for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
            tcl = QTOC(cq); tq = QNext(cq);
-           if (!strcmp(tcl->cellName, linkedcname)) {
+           if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
                break;
            }
            tcl = 0;
@@ -203,6 +380,7 @@ afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport
        tcl->lcellp = tc;
     }
     tc->states |= aflags;
+    tc->timeout = timeout;
  
     bzero((char *)tc->cellHosts, sizeof(tc->cellHosts));
     for (i=0; i<MAXCELLHOSTS; i++) {
index 9cfb261..6276984 100644 (file)
@@ -45,6 +45,7 @@ extern afs_int32 fvTable[NFENTRIES];
 extern afs_rwlock_t afs_xcell;
 extern struct afs_q CellLRU;
 extern afs_int32 afs_cellindex;
+extern afs_int32 afs_nextCellNum;
 
 /* afs_conn.c */
 extern afs_rwlock_t afs_xconn;
@@ -844,6 +845,7 @@ void shutdown_AFS()
       afs_volCounter = 1;
       afs_waitForever = afs_waitForeverCount = 0;
       afs_cellindex = 0;
+      afs_nextCellNum = 0x100;
       afs_FVIndex = -1;
       afs_server = (struct rx_service *)0;
       RWLOCK_INIT(&afs_xconn, "afs_xconn");
index 80a8154..6ae1db2 100644 (file)
@@ -2277,7 +2277,7 @@ static PNewCell(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
     }
 
     linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
-    code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport);
+    code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0);
     return code;
 }
 
index bf4b9aa..9c76118 100644 (file)
@@ -213,6 +213,9 @@ static int nBiods = 5;                      /* AIX3.1 only */
 static int preallocs = 400;            /* Def # of allocated memory blocks */
 static int enable_peer_stats = 0;      /* enable rx stats */
 static int enable_process_stats = 0;   /* enable rx stats */
+#ifdef AFS_AFSDB_ENV
+static int enable_afsdb = 0;           /* enable AFSDB support */
+#endif
 #ifdef notdef
 static int inodes = 60;                        /* VERY conservative, but has to be */
 #endif
@@ -709,6 +712,41 @@ struct afsconf_dir *adir; {
     return 0;
 }
 
+#ifdef AFS_AFSDB_ENV
+static AfsdbLookupHandler()
+{
+    afs_int32 kernelMsg[64];
+    char acellName[128];
+    afs_int32 code;
+    struct afsconf_cell acellInfo;
+    int i;
+
+    while (1) {
+       /* On some platforms you only get 4 args to an AFS call */
+       int sizeArg = ((sizeof acellName) << 16) | (sizeof kernelMsg);
+       code = call_syscall(AFSOP_AFSDB_HANDLER, acellName, kernelMsg, sizeArg);
+       if (code) {             /* Something is wrong? */
+           sleep(1);
+           continue;
+       }
+
+       code = afsconf_GetAfsdbInfo(acellName, 0, &acellInfo);
+       if (code) {
+           kernelMsg[0] = 0;
+           kernelMsg[1] = 0;
+       } else {
+           kernelMsg[0] = acellInfo.numServers;
+           if (acellInfo.timeout)
+               kernelMsg[1] = acellInfo.timeout - time(0);
+           else
+               kernelMsg[1] = 0;
+           for (i=0; i<acellInfo.numServers; i++)
+               kernelMsg[i+2] = acellInfo.hostAddr[i].sin_addr.s_addr;
+       }    
+    }
+}
+#endif
+
 #ifdef mac2
 #include <sys/ioctl.h>
 #endif /* mac2 */
@@ -896,6 +934,14 @@ mainproc(as, arock)
        /* -mem_alloc_sleep */
        cacheFlags |= AFSCALL_INIT_MEMCACHE_SLEEP;
     }
+    if (as->parms[24].items) {
+       /* -afsdb */
+#ifdef AFS_AFSDB_ENV
+       enable_afsdb = 1;
+#else
+       printf("afsd: No AFSDB support; ignoring -afsdb");
+#endif
+    }
 
     /*
      * Pull out all the configuration info for the workstation's AFS cache and
@@ -1115,6 +1161,18 @@ mainproc(as, arock)
     }
 #endif
 
+#ifdef AFS_AFSDB_ENV
+    if (enable_afsdb) {
+       if (afsd_verbose)
+           printf("%s: Forking AFSDB lookup handler.\n", rn);
+       code = fork();
+       if (code == 0) {
+           AfsdbLookupHandler();
+           exit(1);
+       }
+    }
+#endif
+
     /* Initialize AFS daemon threads. */
     if (afsd_verbose)
        printf("%s: Forking AFS daemon.\n", rn);
@@ -1187,8 +1245,8 @@ mainproc(as, arock)
     }
 
     /*
-         * If the root volume has been explicitly set, tell the kernel.
-         */
+     * If the root volume has been explicitly set, tell the kernel.
+     */
     if (rootVolSet) {
        if (afsd_verbose)
            printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n",
@@ -1460,6 +1518,11 @@ char **argv; {
     cmd_AddParm(ts, "-enable_peer_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics by peer");
     cmd_AddParm(ts, "-enable_process_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics for this process");
     cmd_AddParm(ts, "-mem_alloc_sleep", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE), "Allow sleeps when allocating memory cache");
+    cmd_AddParm(ts, "-afsdb", CMD_FLAG, (CMD_OPTIONAL
+#ifndef AFS_AFSDB_ENV
+               | CMD_HIDE
+#endif
+               ), "Enable AFSDB support");
     return (cmd_Dispatch(argc, argv));
 }
 
index 48850d6..53e0cdd 100644 (file)
 #include <netdb.h>
 #include <sys/file.h>
 #include <sys/time.h>
-#endif
+#ifdef AFS_AFSDB_ENV
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif /* AFS_AFSDB_ENV */
+#endif /* AFS_NT40_ENV */
 #include <errno.h>
 #include <ctype.h>
 #include <time.h>
@@ -542,6 +546,97 @@ afsconf_GetExtendedCellInfo(adir, acellName, aservice, acellInfo, clones)
     return code;
 }
 
+#ifdef AFS_AFSDB_ENV
+afsconf_GetAfsdbInfo(acellName, aservice, acellInfo)
+    char *acellName;
+    char *aservice;
+    struct afsconf_cell *acellInfo;
+{
+    afs_int32 code;
+    int tservice, len, i;
+    unsigned char answer[1024];
+    unsigned char *p;
+    char host[256];
+    int server_num = 0;
+    int minttl = 0;
+
+    /* The resolver isn't always MT-safe.. Perhaps this ought to be
+     * replaced with a more fine-grained lock just for the resolver
+     * operations.
+     */
+    LOCK_GLOBAL_MUTEX
+    len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
+    UNLOCK_GLOBAL_MUTEX
+
+    if (len < 0)
+       return AFSCONF_NOTFOUND;
+
+    p = answer + sizeof(HEADER);       /* Skip header */
+    code = dn_expand(answer, answer + len, p, host, sizeof(host));
+    if (code < 0)
+       return AFSCONF_NOTFOUND;
+    strncpy(acellInfo->name, host, sizeof(acellInfo->name));
+
+    p += code + QFIXEDSZ;      /* Skip name */
+
+    while (p < answer + len) {
+       int type, ttl, size;
+
+       code = dn_expand(answer, answer + len, p, host, sizeof(host));
+       if (code < 0)
+           return AFSCONF_NOTFOUND;
+
+       p += code;      /* Skip the name */
+       type = (p[0] << 8) | p[1];
+       p += 4;         /* Skip type and class */
+       ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+       p += 4;         /* Skip the TTL */
+       size = (p[0] << 8) | p[1];
+       p += 2;         /* Skip the size */
+
+       if (type == T_AFSDB) {
+           struct hostent *he;
+
+           code = dn_expand(answer, answer+len, p+2, host, sizeof(host));
+           if (code < 0)
+               return AFSCONF_NOTFOUND;
+
+           /* Do we want to get TTL data for the A record as well? */
+           he = gethostbyname(host);
+           if (he && server_num < MAXHOSTSPERCELL) {
+               afs_int32 ipaddr;
+               memcpy(&ipaddr, he->h_addr, he->h_length);
+               acellInfo->hostAddr[server_num].sin_addr.s_addr = ipaddr;
+               strncpy(acellInfo->hostName[server_num], host,
+                       sizeof(acellInfo->hostName[server_num]));
+               server_num++;
+
+               if (!minttl || ttl < minttl) minttl = ttl;
+           }
+       }
+
+       p += size;
+    }
+
+    if (server_num == 0)               /* No AFSDB records */
+       return AFSCONF_NOTFOUND;
+    acellInfo->numServers = server_num;
+
+    if (aservice) {
+       tservice = afsconf_FindService(aservice);
+       if (tservice < 0)
+           return AFSCONF_NOTFOUND;  /* service not found */
+       for (i=0; i<acellInfo->numServers; i++) {
+           acellInfo->hostAddr[i].sin_port = tservice;
+       }
+    }
+
+    acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
+
+    return 0;
+}
+#endif /* AFS_AFSDB_ENV */
+
 afsconf_GetCellInfo(adir, acellName, aservice, acellInfo)
 struct afsconf_dir *adir;
 char *aservice;
@@ -603,12 +698,17 @@ struct afsconf_cell *acellInfo; {
                acellInfo->hostAddr[i].sin_port = tservice;
            }
        }
+       acellInfo->timeout = 0;
        UNLOCK_GLOBAL_MUTEX
        return 0;
     }
     else {
        UNLOCK_GLOBAL_MUTEX
+#ifdef AFS_AFSDB_ENV
+       return afsconf_GetAfsdbInfo(acellName, aservice, acellInfo);
+#else
        return AFSCONF_NOTFOUND;
+#endif /* AFS_AFSDB_ENV */
     }
 }
 
index 3632973..7e6091e 100644 (file)
@@ -66,6 +66,7 @@ struct afsconf_cell {
     struct sockaddr_in hostAddr[MAXHOSTSPERCELL];      /*IP addresses for cell's servers*/
     char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];      /*Names for cell's servers*/
     char *linkedCell;                          /* Linked cell name, if any */
+    int timeout;                               /* Data timeout, if non-zero */
 };
 
 struct afsconf_entry {
index 43c2d89..51427ad 100644 (file)
@@ -38,6 +38,7 @@
 #define        AFSOP_GETIFADDRS         21     /* get machine's ethernet interfaces */
 
 #define        AFSOP_ADDCELL2           29     /* 2nd add cell protocol interface */
+#define        AFSOP_AFSDB_HANDLER      30     /* userspace AFSDB lookup handler */
 
 /* The range 20-30 is reserved for AFS system offsets in the afs_syscall */
 #define        AFSCALL_PIOCTL          20