From: Nickolai Zeldovich Date: Mon, 30 Apr 2001 23:08:39 +0000 (+0000) Subject: afsdb-callout-and-userspace-implementation-20010430 X-Git-Tag: openafs-stable-1_1_0~175 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=f816a53b265ce8172fa25bc4e84fc4331ac3880d;p=packages%2Fo%2Fopenafs.git afsdb-callout-and-userspace-implementation-20010430 "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 --- diff --git a/src/afs/afs.h b/src/afs/afs.h index 4f80931dd..8a957a687 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -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) diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index 930b294fe..ef3304510 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -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: diff --git a/src/afs/afs_cell.c b/src/afs/afs_cell.c index 2b271e1b5..f1a0f0cf8 100644 --- a/src/afs/afs_cell.c +++ b/src/afs/afs_cell.c @@ -42,14 +42,177 @@ 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= 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 #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)); } diff --git a/src/auth/cellconfig.c b/src/auth/cellconfig.c index 48850d6f9..53e0cddda 100644 --- a/src/auth/cellconfig.c +++ b/src/auth/cellconfig.c @@ -26,7 +26,11 @@ #include #include #include -#endif +#ifdef AFS_AFSDB_ENV +#include +#include +#endif /* AFS_AFSDB_ENV */ +#endif /* AFS_NT40_ENV */ #include #include #include @@ -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; inumServers; 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 */ } } diff --git a/src/auth/cellconfig.p.h b/src/auth/cellconfig.p.h index 3632973b1..7e6091e44 100644 --- a/src/auth/cellconfig.p.h +++ b/src/auth/cellconfig.p.h @@ -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 { diff --git a/src/config/afs_args.h b/src/config/afs_args.h index 43c2d8978..51427adee 100644 --- a/src/config/afs_args.h +++ b/src/config/afs_args.h @@ -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