Index: src/afs/afs_pioctl.c =================================================================== RCS file: /cvs/openafs/src/afs/afs_pioctl.c,v retrieving revision 1.110.2.34 diff -u -r1.110.2.34 afs_pioctl.c --- src/afs/afs_pioctl.c 18 Mar 2009 13:41:35 -0000 1.110.2.34 +++ src/afs/afs_pioctl.c 16 Apr 2009 22:30:04 -0000 @@ -119,6 +119,11 @@ DECL_PIOCTL(PNFSNukeCreds); DECL_PIOCTL(PNewUuid); DECL_PIOCTL(PPrecache); +/* + * Patch for Google Summer of Code - implementing a random server + * rank + */ +DECL_PIOCTL(PSetSPrefsRand); #if defined(AFS_CACHE_BYPASS) DECL_PIOCTL(PSetCachingThreshold); DECL_PIOCTL(PSetCachingBlkSize); @@ -221,6 +226,7 @@ PResidencyCmd, /* 67 -- MR-AFS: generic commnd interface */ PBogus, /* 68 -- arla: fetch stats */ PGetVnodeXStatus2, /* 69 - get caller access and some vcache status */ + PSetSPrefsRand, /* 70 - Randomize the server preference list */ }; static pioctlFunction CpioctlSw[] = { @@ -3484,6 +3490,128 @@ return 0; } + +static void * +ReSortCells_cbRand(struct cell *cell, void *arg) +{ + afs_int32 *p = (afs_int32 *) arg; + afs_int32 *l = p + 1; + int i, s = p[0]; + + for (i = 0; i < s; i++) { + if (l[i] == cell->cellNum) { + ObtainWriteLock(&cell->lock, 690); + afs_SortServersRand(cell->cellHosts, MAXCELLHOSTS); + ReleaseWriteLock(&cell->lock); + } + } + + return NULL; +} + +static void +ReSortCellsRand(int s, afs_int32 * l, int vlonly) +{ + int i; + struct volume *j; + register int k; + + if (vlonly) { + afs_int32 *p; + p = (afs_int32 *) afs_osi_Alloc(sizeof(afs_int32) * (s + 1)); + p[0] = s; + memcpy(p + 1, l, s * sizeof(afs_int32)); + afs_TraverseCells(&ReSortCells_cbRand, p); + afs_osi_Free(p, sizeof(afs_int32) * (s + 1)); + return; + } + + ObtainReadLock(&afs_xvolume); + for (i = 0; i < NVOLS; i++) { + for (j = afs_volumes[i]; j; j = j->next) { + for (k = 0; k < s; k++) + if (j->cell == l[k]) { + ObtainWriteLock(&j->lock, 233); + afs_SortServersRand(j->serverHost, MAXHOSTS); + ReleaseWriteLock(&j->lock); + break; + } + } + } + ReleaseReadLock(&afs_xvolume); +} + +static int +afs_setsprefsrand(struct spref *sp, unsigned int num, unsigned int vlonly) +{ + struct srvAddr *sa; + int i, j, k, matches, touchedSize; + struct server *srvr = NULL; + afs_int32 touched[34]; + int isfs; + + touchedSize = 0; + for (k = 0; k < num; sp++, k++) { + if (debugsetsp) { + printf("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank); + } + matches = 0; + ObtainReadLock(&afs_xserver); + + i = SHash(sp->host.s_addr); + for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { + if (sa->sa_ip == sp->host.s_addr) { + srvr = sa->server; + isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport)) + || (sa->sa_portal == AFS_FSPORT); + if ((!vlonly && isfs) || (vlonly && !isfs)) { + matches++; + break; + } + } + } + + if (sa && matches) { /* found one! */ + if (debugsetsp) { + printf("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank); + } + sa->sa_iprank = sp->rank + afs_randomMod15(); + afs_SortOneServer(sa->server); + + if (srvr->cell) { + /* if we don't know yet what cell it's in, this is moot */ + for (j = touchedSize - 1; + j >= 0 && touched[j] != srvr->cell->cellNum; j--) + /* is it in our list of touched cells ? */ ; + if (j < 0) { /* no, it's not */ + touched[touchedSize++] = srvr->cell->cellNum; + if (touchedSize >= 32) { /* watch for ovrflow */ + ReleaseReadLock(&afs_xserver); + ReSortCellsRand(touchedSize, touched, vlonly); + touchedSize = 0; + ObtainReadLock(&afs_xserver); + } + } + } + } + + ReleaseReadLock(&afs_xserver); + /* if we didn't find one, start to create one. */ + /* Note that it doesn't have a cell yet... */ + if (!matches) { + afs_uint32 temp = sp->host.s_addr; + srvr = + afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT), + WRITE_LOCK, (afsUUID *) 0, 0); + srvr->addr->sa_iprank = sp->rank + afs_randomMod15(); + afs_PutServer(srvr, WRITE_LOCK); + } + } /* for all cited preferences */ + + ReSortCellsRand(touchedSize, touched, vlonly); + return 0; +} + /*! * VIOC_SETPREFS (46) - Set server ranks * @@ -3548,6 +3676,120 @@ return 0; } +/* + * VIOC_SETSPREFSRAND (70) - Set server ranks randomly + * + * \param[in] ain the server preferences to be set + * \param[out] aout not in use + * + * \retval EIO Error if the afs daemon hasn't started yet + * \retval EACCES Error if the user doesn't have super-user credentials + * + * \post set the server preferences, calling a function + * + * \notes this may only be performed by the local root user. + */ + +DECL_PIOCTL(PSetSPrefsRand) +{ + struct sprefrequest *spin; /* input */ + struct setspref *sp; /* input for randomization */ + struct sprefinfo *spout; /* output */ + struct spref *srvout; /* one output component */ + int i, j; /* counters for hash table traversal */ + struct server *srvr; /* one of CM's server structs */ + struct srvAddr *sa; + int vlonly; /* just return vlservers ? */ + int isfs; + struct server *servers[NSERVERS]; + + AFS_STATCNT(PGetSPrefs); + if (!afs_resourceinit_flag) /* afs daemons haven't started yet */ + return EIO; /* Inappropriate ioctl for device */ + + + if (ainSize < sizeof(struct sprefrequest_33)) { + return ENOENT; + } else { + spin = ((struct sprefrequest *)ain); + } + + if (ainSize > sizeof(struct sprefrequest_33)) { + vlonly = (spin->flags & DBservers); + } else + vlonly = 0; + + /* struct sprefinfo includes 1 server struct... that size gets added + * in during the loop that follows. + */ + *aoutSize = sizeof(struct sprefinfo) - sizeof(struct spref); + spout = (struct sprefinfo *)aout; + spout->next_offset = spin->offset; + spout->num_servers = 0; + srvout = spout->servers; + + /* sp = (struct setspref *)ain; + afs_setsprefsrand(&(sp->servers[0]), sp->num_servers, + (sp->flags & DBservers)); JUMP */ + +/*********************************************************************** + * I EITHER NEED TO CALL afs_SortServers() FROM WITHIN THIS FUNCTION + * OR I NEED TO USE THE HASH TABLE TO GET A RESORTED LIST + * FOR afs_SortServer() I'LL NEED TO GO FROM HASH TABLE TO AN ARRAY OF + * struct server*. afs_SortServer() WILL ALSO ENTAIL PUTTING SORTED LIST + * INTO *aout + ************************************************************************/ + + ObtainReadLock(&afs_xserver); + for (i = 0, j = 0; j < NSERVERS; j++) { /* sift through hash table */ + for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) { + if (spin->offset > (unsigned short)i) { + continue; /* catch up to where we left off */ + } + spout->next_offset++; + + srvr = sa->server; + servers[j] = sa->server; +/* isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport)) + || (sa->sa_portal == AFS_FSPORT); + + if ((vlonly && isfs) || (!vlonly && !isfs)) { + /* only report ranks for vl servers NEEDS END COMMENT + continue; + } + + srvout->host.s_addr = sa->sa_ip; + srvout->rank = sa->sa_iprank; + *aoutSize += sizeof(struct spref); + spout->num_servers++; + srvout++; + + if (*aoutSize > (PIGGYSIZE - sizeof(struct spref))) { + ReleaseReadLock(&afs_xserver); /* no more room! NEEDS END COMMENT + return 0; + }*/ + } + } + + if(!afs_SortServersRand(servers, NSERVERS)) + return ENOENT; + + for(j = 0; j < NSERVERS; j++) { + srvout->host.s_addr = servers[j]->addr->sa_ip; /*sa->sa_ip;*/ + srvout->rank = servers[j]->addr->sa_iprank; /*a->sa_iprank;*/ + *aoutSize += sizeof(struct spref); + spout->num_servers++; + srvout++; + } + ReleaseReadLock(&afs_xserver); + + spout->next_offset = 0; /* start over from the beginning next time*/ + + return 0; +} + + + /* * VIOC_GETSPREFS (43) - Get server ranks * Index: src/afs/afs_server.c =================================================================== RCS file: /cvs/openafs/src/afs/afs_server.c,v retrieving revision 1.43.4.11 diff -u -r1.43.4.11 afs_server.c --- src/afs/afs_server.c 18 Mar 2009 13:41:35 -0000 1.43.4.11 +++ src/afs/afs_server.c 16 Apr 2009 22:30:27 -0000 @@ -940,6 +940,50 @@ } } /*afs_SortServers */ +/* + * For Summer of Code Patch, should make the server rank random + */ +void +afs_SortServersRand(struct server *aservers[], int count) +{ + struct server *ts, *index; + int i, j, low, k, l; + + AFS_STATCNT(afs_SortServers); + for (i = 0; i < count; i++) { + if (!aservers[i]) + break; + aservers[i]->addr->sa_iprank = afs_randomMod15(); + + for (low = i, j = i + 1; j <= count; j++) { + if ((!aservers[j]) || (!aservers[j]->addr)) + break; + if ((!aservers[low]) || (!aservers[low]->addr)) + break; + if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) { + low = j; + } + } + if (low != i) { + ts = aservers[i]; + aservers[i] = aservers[low]; + aservers[low] = ts; + } + } + + for (k=1; k < count; k++) + { + index = aservers[k]; + l = k; + while ((l > 0) && (aservers[l-1]->addr->sa_iprank > index->addr->sa_iprank)) + { + aservers[l] = aservers[l-1]; + l = l - 1; + } + aservers[l] = index; + } +} /*afs_SortServers */ + /* afs_SetServerPrefs is rather system-dependent. It pokes around in kernel data structures to determine what the local IP addresses and subnet masks are in order to choose which server(s) are on the local subnet. Index: src/venus/fs.c =================================================================== RCS file: /cvs/openafs/src/venus/fs.c,v retrieving revision 1.30.2.21 diff -u -r1.30.2.21 fs.c --- src/venus/fs.c 16 Mar 2009 13:24:37 -0000 1.30.2.21 +++ src/venus/fs.c 16 Apr 2009 22:30:40 -0000 @@ -3213,6 +3213,78 @@ } static int +GetPrefCmdRand(struct cmd_syndesc *as, void *arock) +{ + afs_int32 code; + struct cmd_item *ti; + char *name, tbuffer[20]; + afs_int32 addr; + FILE *outfd; + int resolve; + int vlservers = 0; + struct ViceIoctl blob; + struct sprefrequest *in; + struct sprefinfo *out; + int i; + + ti = as->parms[0].items; /* -file */ + if (ti) { + if (debug) + fprintf(stderr, "opening file %s\n", ti->data); + if (!(outfd = freopen(ti->data, "w", stdout))) { + perror(ti->data); + return 1; + } + } + + ti = as->parms[1].items; /* -numeric */ + resolve = !(ti); + ti = as->parms[2].items; /* -vlservers */ + vlservers |= (ti ? DBservers : 0); + /* ti = as->parms[3].items; -cell */ + + in = (struct sprefrequest *)space; + in->offset = 0; + + do { + blob.in_size = sizeof(struct sprefrequest); + blob.in = (char *)in; + blob.out = space; + blob.out_size = MAXSIZE; + + in->num_servers = + (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref); + in->flags = vlservers; + + code = pioctl(0, VIOC_GETSPREFSRAND, &blob, 1); /* VIOC_GETSPREFSRAND */ + if (code) { + perror("randomserverprefs pioctl"); + return 1; + } + + out = (struct sprefinfo *)blob.out; + + for (i = 0; i < out->num_servers; i++) { + if (resolve) { + name = hostutil_GetNameByINet(out->servers[i].server.s_addr); + } else { + addr = ntohl(out->servers[i].server.s_addr); + sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff, + (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); + name = tbuffer; + } + printf("%-50s %5u\n", name, out->servers[i].rank); + } + + in->offset = out->next_offset; + } while (out->next_offset > 0); + + return 0; +} + + + +static int StoreBehindCmd(struct cmd_syndesc *as, void *arock) { afs_int32 code = 0; @@ -3507,6 +3579,16 @@ /* cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */ cmd_CreateAlias(ts, "gp"); + ts = cmd_CreateSyntax("randomserverprefs", GetPrefCmdRand, NULL, + "get server ranks"); + cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, + "output to named file"); + cmd_AddParm(ts, "-numeric", CMD_FLAG, CMD_OPTIONAL, "addresses only"); + cmd_AddParm(ts, "-vlservers", CMD_FLAG, CMD_OPTIONAL, "VL servers"); +/* cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */ + cmd_CreateAlias(ts, "gp"); + + ts = cmd_CreateSyntax("setacl", SetACLCmd, NULL, "set access control list"); cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory"); cmd_AddParm(ts, "-acl", CMD_LIST, 0, "access list entries"); Index: src/config/venus.h =================================================================== RCS file: /cvs/openafs/src/config/venus.h,v retrieving revision 1.12.2.8 diff -u -r1.12.2.8 venus.h --- src/config/venus.h 20 Jan 2009 03:32:38 -0000 1.12.2.8 +++ src/config/venus.h 16 Apr 2009 22:32:05 -0000 @@ -159,6 +159,7 @@ #define VIOCGETVCXSTATUS _VICEIOCTL(41) #define VIOC_SETSPREFS33 _VICEIOCTL(42) /* Set server ranks */ #define VIOC_GETSPREFS _VICEIOCTL(43) /* Get server ranks */ +#define VIOC_GETSPREFSRAND _VICEIOCTL(70) /* randomize server ranks */ #define VIOC_GAG _VICEIOCTL(44) /* silence CM */ #define VIOC_TWIDDLE _VICEIOCTL(45) /* adjust RX knobs */ #define VIOC_SETSPREFS _VICEIOCTL(46) /* Set server ranks */