#define MHC 0x100 /* on multihomed chain */
#define FRC 0x200 /* on free chain */
+#define REFRW 0x1000 /* linked from something (RW) */
+#define REFRO 0x2000 /* linked from something (RO) */
+#define REFBK 0x4000 /* linked from something (BK) */
+#define REFN 0x8000 /* linked from something (name) */
+
+#define vldbread(x,y,z) vldbio(x,y,z,0)
+#define vldbwrite(x,y,z) vldbio(x,y,z,1)
+
#include <afsconfig.h>
#include <afs/param.h>
#include <afs/afsutil.h>
#include <afs/cmd.h>
+#define ADDR(x) (x/sizeof(struct nvlentry))
+
int fd;
int listentries, listservers, listheader, listuheader, verbose;
+int fix = 0;
+
struct er {
long addr;
int type;
} *record;
int serveraddrs[MAXSERVERID + 2];
+#if 0
+int
+writeUbikHeader()
+{
+ /* Bump the version number?? We could cheat and push a new db... */
+}
+#endif
#define HDRSIZE 64
int
}
int
-vldbread(position, buffer, size)
- int position;
- char *buffer;
- int size;
+vldbio(int position, char *buffer, int size, int rdwr)
{
int offset, r, p;
return (-1);
}
- /* now read the info */
- r = read(fd, buffer, size);
+ if (rdwr == 1)
+ r = write(fd, buffer, size);
+ else
+ r = read(fd, buffer, size);
+
if (r != size) {
- printf("error: read of %d bytes failed: %d %d\n", size, r, errno);
+ printf("error: %s of %d bytes failed: %d %d\n", rdwr==1?"write":"read",
+ size, r, errno);
return (-1);
}
return (0);
}
char *
-vtype(type)
- int type;
+vtype(int type)
{
static char Type[3];
}
afs_int32
-NameHash(volname)
- char *volname;
+NameHash(char *volname)
{
unsigned int hash;
char *vchar;
}
afs_int32
-IdHash(volid)
- afs_int32 volid;
+IdHash(afs_int32 volid)
{
return ((abs(volid)) % HASHSIZE);
}
#define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
int
-InvalidVolname(volname)
- char *volname;
+InvalidVolname(char *volname)
{
char *map;
size_t slen;
return (slen != strspn(volname, map));
}
-readheader(headerp)
- struct vlheader *headerp;
+void
+readheader(struct vlheader *headerp)
{
int i, j;
headerp->vital_header.headersize, sizeof(*headerp));
}
-readMH(addr, mhblockP)
- afs_int32 addr;
- struct extentaddr *mhblockP;
+void
+writeheader(struct vlheader *headerp)
+{
+ int i, j;
+
+ headerp->vital_header.vldbversion =
+ htonl(headerp->vital_header.vldbversion);
+ headerp->vital_header.headersize =
+ htonl(headerp->vital_header.headersize);
+ headerp->vital_header.freePtr = htonl(headerp->vital_header.freePtr);
+ headerp->vital_header.eofPtr = htonl(headerp->vital_header.eofPtr);
+ headerp->vital_header.allocs = htonl(headerp->vital_header.allocs);
+ headerp->vital_header.frees = htonl(headerp->vital_header.frees);
+ headerp->vital_header.MaxVolumeId =
+ htonl(headerp->vital_header.MaxVolumeId);
+ headerp->vital_header.totalEntries[0] =
+ htonl(headerp->vital_header.totalEntries[0]);
+ for (i = 0; i < MAXTYPES; i++)
+ headerp->vital_header.totalEntries[i] =
+ htonl(headerp->vital_header.totalEntries[1]);
+
+ headerp->SIT = htonl(headerp->SIT);
+ for (i = 0; i < MAXSERVERID; i++)
+ headerp->IpMappedAddr[i] = htonl(headerp->IpMappedAddr[i]);
+ for (i = 0; i < HASHSIZE; i++)
+ headerp->VolnameHash[i] = htonl(headerp->VolnameHash[i]);
+ for (i = 0; i < MAXTYPES; i++)
+ for (j = 0; j < HASHSIZE; j++)
+ headerp->VolidHash[i][j] = htonl(headerp->VolidHash[i][j]);
+
+ vldbwrite(0, headerp, sizeof(*headerp));
+}
+
+void
+readMH(afs_int32 addr, struct extentaddr *mhblockP)
{
int i, j;
struct extentaddr *e;
}
}
-readentry(addr, vlentryp, type)
- afs_int32 addr;
- struct nvlentry *vlentryp;
- afs_int32 *type;
+void
+readentry(afs_int32 addr, struct nvlentry *vlentryp, afs_int32 *type)
{
int i;
}
void
-readSIT(base, addr)
- int base;
- int addr;
+writeentry(afs_int32 addr, struct nvlentry *vlentryp)
+{
+ int i;
+
+ if (verbose)
+ printf("Writing back entry at addr %u\n", addr);
+
+ for (i = 0; i < MAXTYPES; i++)
+ vlentryp->volumeId[i] = htonl(vlentryp->volumeId[i]);
+ vlentryp->flags = htonl(vlentryp->flags);
+ vlentryp->LockAfsId = htonl(vlentryp->LockAfsId);
+ vlentryp->LockTimestamp = htonl(vlentryp->LockTimestamp);
+ vlentryp->cloneId = htonl(vlentryp->cloneId);
+ for (i = 0; i < MAXTYPES; i++)
+ vlentryp->nextIdHash[i] = htonl(vlentryp->nextIdHash[i]);
+ vlentryp->nextNameHash = htonl(vlentryp->nextNameHash);
+ for (i = 0; i < NMAXNSERVERS; i++) {
+ vlentryp->serverNumber[i] = htonl(vlentryp->serverNumber[i]);
+ vlentryp->serverPartition[i] = htonl(vlentryp->serverPartition[i]);
+ vlentryp->serverFlags[i] = htonl(vlentryp->serverFlags[i]);
+ }
+ vldbwrite(addr, vlentryp, sizeof(*vlentryp));
+}
+
+void
+readSIT(int base, int addr)
{
int i, j, a;
char sitbuf[VL_ADDREXTBLK_SIZE];
* Remember what the maximum volume id we found is and check against the header.
*/
void
-ReadAllEntries(header)
- struct vlheader *header;
+ReadAllEntries(struct vlheader *header)
{
afs_int32 type, rindex, i, j, e;
int freecount = 0, mhcount = 0, vlcount = 0;
bkcount++;
continue;
}
+ if (!vlentry.serverFlags[j]) {
+ /*e = 0;*/
+ continue;
+ }
if (e) {
printf
("VLDB entry '%s' contains an unknown RW/RO index serverFlag\n",
}
+void
+SetHashEnd(long addr, int type, long new)
+{
+ struct nvlentry vlentry;
+ afs_int32 i, rindex, type2, next = -1;
+
+ for (; addr; addr = next) {
+ readentry(addr, &vlentry, &type2);
+ switch(type & 0xf0) {
+ case RWH:
+ next = vlentry.nextIdHash[0];
+ break;
+ case ROH:
+ next = vlentry.nextIdHash[1];
+ break;
+ case BKH:
+ next = vlentry.nextIdHash[2];
+ break;
+ case NH:
+ next = vlentry.nextNameHash;
+ break;
+ default:
+ next = -1;
+ }
+
+ if (next < 1) {
+ switch(type & 0xf0) {
+ case RWH:
+ if (vlentry.nextIdHash[0] != 0) {printf("bwoop\n");}
+ vlentry.nextIdHash[0] = new;
+ break;
+ case ROH:
+ if (vlentry.nextIdHash[1] != 0) {printf("bwoop\n");}
+ vlentry.nextIdHash[1] = new;
+ break;
+ case BKH:
+ if (vlentry.nextIdHash[2] != 0) {printf("bwoop\n");}
+ vlentry.nextIdHash[2] = new;
+ break;
+ case NH:
+ if (vlentry.nextNameHash != 0) {printf("bwoop\n");}
+ vlentry.nextNameHash = new;
+ break;
+ }
+ writeentry(addr, &vlentry);
+ return;
+ }
+ }
+}
+
/*
* Follow each Name hash bucket marking it as read in the record array.
* Record we found it in the name hash within the record array.
* Check that the name is hashed correctly.
*/
-FollowNameHash(header)
- struct vlheader *header;
+void
+FollowNameHash(struct vlheader *header)
{
int count = 0, longest = 0, shortest = -1, chainlength;
struct nvlentry vlentry;
}
record[rindex].type |= NH;
+ record[rindex].type |= REFN;
+
chainlength++;
count++;
* Record we found it in the id hash within the record array.
* Check that the ID is hashed correctly.
*/
-FollowIdHash(header)
- struct vlheader *header;
+void
+FollowIdHash(struct vlheader *header)
{
int count = 0, longest = 0, shortest = -1, chainlength;
struct nvlentry vlentry;
afs_uint32 addr;
- afs_int32 i, j, hash, type, rindex;
+ afs_int32 i, j, hash, type, rindex, ref;
/* Now follow the RW, RO, and BK Hash Tables */
if (verbose)
printf("Check RW, RO, and BK id Hashes\n");
for (i = 0; i < MAXTYPES; i++) {
hash = ((i == 0) ? RWH : ((i == 1) ? ROH : BKH));
+ ref = ((i == 0) ? REFRW : ((i == 1) ? REFRO : REFBK));
count = longest = 0;
shortest = -1;
break;
}
record[rindex].type |= hash;
+ record[rindex].type |= ref;
chainlength++;
count++;
* Follow the free chain.
* Record we found it in the free chain within the record array.
*/
-FollowFreeChain(header)
- struct vlheader *header;
+void
+FollowFreeChain(struct vlheader *header)
{
afs_int32 count = 0;
struct nvlentry vlentry;
* The code does not verify if there are duplicate IP addresses in the
* list. The vlserver does this when a fileserver registeres itself.
*/
-CheckIpAddrs(header)
- struct vlheader *header;
+void
+CheckIpAddrs(struct vlheader *header)
{
int mhblocks = 0;
afs_int32 i, j, m, rindex;
}
+void
+FixBad(afs_uint32 idx, afs_uint32 addr, afs_uint32 type, afs_uint32 tmp,
+ struct nvlentry *vlentry) {
+ SetHashEnd(addr, type, tmp);
+ printf("linked unlinked chain %u (index %d) to end of chain\n",
+ tmp, ADDR(tmp));
+}
+
int
-WorkerBee(as, arock)
- struct cmd_syndesc *as;
- char *arock;
+WorkerBee(struct cmd_syndesc *as, char *arock)
{
char *dbfile;
- afs_int32 maxentries, type;
+ afs_int32 maxentries, type, tmp;
struct vlheader header;
struct nvlentry vlentry;
int i, j, help = 0;
listservers = (as->parms[3].items ? 1 : 0); /* -servers */
listentries = (as->parms[4].items ? 1 : 0); /* -entries */
verbose = (as->parms[5].items ? 1 : 0); /* -verbose */
+ fix = (as->parms[6].items ? 1 : 0); /* -fix */
/* open the vldb database file */
- fd = open(dbfile, O_RDONLY, 0);
+ fd = open(dbfile, (fix > 0)?O_RDWR:O_RDONLY, 0);
if (fd < 0) {
printf("can't open file '%s'. error = %d\n", dbfile, errno);
return 0;
if (verbose)
printf("Verify each volume entry\n");
for (i = 0; i < maxentries; i++) {
+ int nextp;
+ int reft;
+ int hash;
+ int *nextpp;
+ char *which;
+
if (record[i].type == 0)
continue;
* on the hash chains, and its server numbers are good.
*/
if (record[i].type & VL) {
+ int foundbad = 0;
+ char volidbuf[256];
+
readentry(record[i].addr, &vlentry, &type);
if (InvalidVolname(vlentry.name))
printf("Volume '%s' at addr %u has an invalid name\n",
vlentry.name, record[i].addr);
- if (!(record[i].type & NH))
- printf("Volume '%s' not found in name hash\n", vlentry.name);
+ if (!(record[i].type & NH)) {
+ nextp = ADDR(vlentry.nextNameHash);
+ reft = REFN;
+ hash = NameHash(vlentry.name);
+ nextpp = &vlentry.nextNameHash;
+ which = "name";
+ sprintf(volidbuf, "");
+ foundbad = 1;
+ }
- if (vlentry.volumeId[0] && !(record[i].type & RWH))
- printf("Volume '%s' id %u not found in RW hash chain\n",
- vlentry.name, vlentry.volumeId[0]);
+ if (vlentry.volumeId[0] && !(record[i].type & RWH)) {
+ nextp = ADDR(vlentry.nextIdHash[0]);
+ reft = REFRW;
+ hash = IdHash(vlentry.volumeId[0]);
+ nextpp = &(vlentry.nextIdHash[0]);
+ which = "RW";
+ sprintf(volidbuf, "id %u ", vlentry.volumeId[0]);
+ foundbad = 1;
+ }
- if (vlentry.volumeId[1] && !(record[i].type & ROH))
- printf("Volume '%s' id %u not found in RO hash chain\n",
- vlentry.name, vlentry.volumeId[1]);
+ if (vlentry.volumeId[1] && !(record[i].type & ROH)) {
+ nextp = ADDR(vlentry.nextIdHash[1]);
+ reft = REFRO;
+ hash = IdHash(vlentry.volumeId[1]);
+ nextpp = &(vlentry.nextIdHash[1]);
+ which = "RO";
+ sprintf(volidbuf, "id %u ", vlentry.volumeId[1]);
+ foundbad = 1;
+ }
- if (vlentry.volumeId[2] && !(record[i].type & BKH))
- printf("Volume '%s' id %u not found in BK hash chain\n",
- vlentry.name, vlentry.volumeId[2]);
+ if (vlentry.volumeId[2] && !(record[i].type & BKH)) {
+ nextp = ADDR(vlentry.nextIdHash[2]);
+ reft = REFBK;
+ hash = IdHash(vlentry.volumeId[2]);
+ nextpp = &(vlentry.nextIdHash[2]);
+ which = "BK";
+ sprintf(volidbuf, "id %u ", vlentry.volumeId[2]);
+ foundbad = 1;
+ }
+ if (foundbad) {
+ printf("%d: Volume '%s' %snot found in %s hash %d", i,
+ vlentry.name, volidbuf, which, hash);
+ if (nextp) {
+ printf(" (next %d", nextp);
+ if (!(record[nextp].type & reft)) {
+ printf(" not in chain ");
+ record[nextp].type |= reft;
+ } else if (nextp != 0) {
+ printf(" next in chain");
+ if (fix) {
+ printf(", unchaining");
+ *nextpp = 0;
+ writeentry(record[i].addr, &vlentry);
+ }
+ }
+ printf(")");
+ }
+ printf("\n");
+ }
+
for (j = 0; j < NMAXNSERVERS; j++) {
if ((vlentry.serverNumber[j] != 255)
&& (serveraddrs[vlentry.serverNumber[j]] == 0)) {
vlentry.name, j, vlentry.serverNumber[j]);
}
}
-
- if (record[i].type & 0xffffff00)
+
+ if (record[i].type & 0xffff0f00)
printf
("Volume '%s' id %u also found on other chains (0x%x)\n",
vlentry.name, vlentry.volumeId[0], record[i].type);
-
+
/* A free entry */
} else if (record[i].type & FR) {
if (!(record[i].type & FRC))
printf("Free vlentry at %u not on free chain\n",
record[i].addr);
-
+
if (record[i].type & 0xfffffdf0)
printf
("Free vlentry at %u also found on other chains (0x%x)\n",
record[i].addr, record[i].type);
-
+
/* A multihomed entry */
} else if (record[i].type & MH) {
if (!(record[i].type & MHC))
printf("Multihomed block at %u is orphaned\n",
record[i].addr);
-
+
if (record[i].type & 0xfffffef0)
printf
("Multihomed block at %u also found on other chains (0x%x)\n",
record[i].addr, record[i].type);
-
+
} else {
printf("Unknown entry type at %u (0x%x)\n", record[i].addr,
record[i].type);
}
}
+
+ /* By the time we get here, unchained entries are really unchained */
+ printf("Scanning %u entries for possible repairs\n", maxentries);
+ for (i = 0; i < maxentries; i++) {
+ if (record[i].type & VL) {
+ readentry(record[i].addr, &vlentry, &type);
+ if (!(record[i].type & REFN) && (strlen(vlentry.name)>0)) {
+ printf("%d: Record %u (type 0x%x) not in a name chain\n", i,
+ record[i].addr, record[i].type);
+ if (fix) {
+ if (header.VolnameHash[NameHash(vlentry.name)] == 0)
+ header.VolnameHash[NameHash(vlentry.name)] = record[i].addr;
+ else
+ FixBad(i, header.VolnameHash[NameHash(vlentry.name)], NH, record[i].addr, &vlentry);
+ }
+ }
+ if (vlentry.volumeId[0] && !(record[i].type & REFRW)) {
+ printf("%d: Record %u (type 0x%x) not in a RW chain\n", i,
+ record[i].addr, record[i].type);
+ if (fix) {
+ if (header.VolidHash[0][IdHash(vlentry.volumeId[0])] == 0)
+ header.VolidHash[0][IdHash(vlentry.volumeId[0])] = record[i].addr;
+ else
+ FixBad(i, header.VolidHash[0][IdHash(vlentry.volumeId[0])], RWH, record[i].addr, &vlentry);
+ }
+ }
+ if (vlentry.volumeId[1] && !(record[i].type & REFRO)) {
+ printf("%d: Record %u (type 0x%x) not in a RO chain\n", i,
+ record[i].addr, record[i].type);
+ if (fix) {
+ if (header.VolidHash[1][IdHash(vlentry.volumeId[1])] == 0)
+ header.VolidHash[1][IdHash(vlentry.volumeId[1])] = record[i].addr;
+ else
+ FixBad(i, header.VolidHash[1][IdHash(vlentry.volumeId[1])], ROH, record[i].addr, &vlentry);
+ }
+ }
+ if (vlentry.volumeId[2] && !(record[i].type & REFBK)) {
+ printf("%d: Record %u (type 0x%x) not in a BK chain\n", i,
+ record[i].addr, record[i].type);
+ if (fix) {
+ if (header.VolidHash[2][IdHash(vlentry.volumeId[2])] == 0)
+ header.VolidHash[2][IdHash(vlentry.volumeId[2])] = record[i].addr;
+ else
+ FixBad(i, header.VolidHash[2][IdHash(vlentry.volumeId[2])], BKH, record[i].addr, &vlentry);
+ }
+
+ }
+ }
+ }
+ if (fix)
+ writeheader(&header);
+
return 0;
}
-main(argc, argv)
- int argc;
- char **argv;
+int
+main(int argc, char **argv)
{
struct cmd_syndesc *ts;
"Display server list");
cmd_AddParm(ts, "-entries", CMD_FLAG, CMD_OPTIONAL, "Display entries");
cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "verbose");
+ cmd_AddParm(ts, "-fix", CMD_FLAG, CMD_OPTIONAL, "attempt to patch the database (potentially dangerous)");
return cmd_Dispatch(argc, argv);
}