/** * @param aname Volume name. * @param acell Cell id. * @param agood * @param areq Request type. * @param locktype Type of lock to be used. * @return Volume or NULL if failure. */ static struct volume * afs_NewVolumeByName(char *aname, afs_int32 acell, int agood, struct vrequest *areq, afs_int32 locktype) { afs_int32 code, type = 0; struct volume *tv, *tv1; struct vldbentry *tve; struct nvldbentry *ntve; struct uvldbentry *utve; struct cell *tcell; char *tbuffer, *ve; struct afs_conn *tconn; struct vrequest treq; struct rx_connection *rxconn; if (strlen(aname) > VL_MAXNAMELEN) /* Invalid volume name */ return NULL; tcell = afs_GetCell(acell, READ_LOCK); if (!tcell) { return NULL; } /* allow null request if we don't care about ENODEV/ETIMEDOUT distinction */ if (!areq) areq = &treq; afs_Trace2(afs_iclSetp, CM_TRACE_GETVOL, ICL_TYPE_STRING, aname, ICL_TYPE_POINTER, aname); tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ); tve = (struct vldbentry *)(tbuffer + 1024); ntve = (struct nvldbentry *)tve; utve = (struct uvldbentry *)tve; afs_InitReq(&treq, afs_osi_credp); /* *must* be unauth for vldb */ do { tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum, &treq, SHARED_LOCK, 0, &rxconn); if (tconn) { if (tconn->srvr->server->flags & SNO_LHOSTS) { type = 0; RX_AFS_GUNLOCK(); code = VL_GetEntryByNameO(rxconn, aname, tve); RX_AFS_GLOCK(); } else if (tconn->srvr->server->flags & SYES_LHOSTS) { type = 1; RX_AFS_GUNLOCK(); code = VL_GetEntryByNameN(rxconn, aname, ntve); RX_AFS_GLOCK(); } else { type = 2; RX_AFS_GUNLOCK(); code = VL_GetEntryByNameU(rxconn, aname, utve); RX_AFS_GLOCK(); if (!(tconn->srvr->server->flags & SVLSRV_UUID)) { if (code == RXGEN_OPCODE) { type = 1; RX_AFS_GUNLOCK(); code = VL_GetEntryByNameN(rxconn, aname, ntve); RX_AFS_GLOCK(); if (code == RXGEN_OPCODE) { type = 0; tconn->srvr->server->flags |= SNO_LHOSTS; RX_AFS_GUNLOCK(); code = VL_GetEntryByNameO(rxconn, aname, tve); RX_AFS_GLOCK(); } else if (!code) tconn->srvr->server->flags |= SYES_LHOSTS; } else if (!code) tconn->srvr->server->flags |= SVLSRV_UUID; } lastnvcode = code; } } else code = -1; } while (afs_Analyze(tconn, rxconn, code, NULL, &treq, -1, /* no op code for this */ SHARED_LOCK, tcell)); if (code) { /* If the client has yet to contact this cell and contact failed due * to network errors, mark the VLDB servers as back up. * That the client tried and failed can be determined from the * fact that there was a downtime incident, but CHasVolRef is not set. */ /* RT 48959 - unclear if this should really go */ #if 0 if (areq->networkError && !(tcell->states & CHasVolRef)) { int i; struct server *sp; struct srvAddr *sap; for (i = 0; i < AFS_MAXCELLHOSTS; i++) { if ((sp = tcell->cellHosts[i]) == NULL) break; for (sap = sp->addr; sap; sap = sap->next_sa) afs_MarkServerUpOrDown(sap, 0); } } #endif afs_CopyError(&treq, areq); osi_FreeLargeSpace(tbuffer); afs_PutCell(tcell, READ_LOCK); return NULL; } /* * Check to see if this cell has not yet referenced a volume. If * it hasn't, it's just about to change its status, and we need to mark * this fact down. Note that it is remotely possible that afs_SetupVolume * could fail and we would still not have a volume reference. */ if (!(tcell->states & CHasVolRef)) { tcell->states |= CHasVolRef; afs_stats_cmperf.numCellsContacted++; } /*First time a volume in this cell has been referenced */ if (type == 2) ve = (char *)utve; else if (type == 1) ve = (char *)ntve; else ve = (char *)tve; tv = afs_SetupVolume(0, aname, ve, tcell, agood, type, &treq); if ((agood == 3) && tv && tv->backVol) { /* * This means that very soon we'll ask for the BK volume so * we'll prefetch it (well we did already.) */ tv1 = afs_SetupVolume(tv->backVol, (char *)0, ve, tcell, 0, type, &treq); if (tv1) { tv1->refCount--; } } if ((agood >= 2) && tv && tv->roVol) { /* * This means that very soon we'll ask for the RO volume so * we'll prefetch it (well we did already.) */ tv1 = afs_SetupVolume(tv->roVol, NULL, ve, tcell, 0, type, &treq); if (tv1) { tv1->refCount--; } } osi_FreeLargeSpace(tbuffer); afs_PutCell(tcell, READ_LOCK); return tv; } /*afs_NewVolumeByName */
static int VLDB_Same(struct VenusFid *afid, struct vrequest *areq) { struct vrequest treq; struct afs_conn *tconn; int i, type = 0; union { struct vldbentry tve; struct nvldbentry ntve; struct uvldbentry utve; } *v; struct volume *tvp; struct cell *tcell; char *bp, tbuf[CVBS]; /* biggest volume id is 2^32, ~ 4*10^9 */ unsigned int changed; struct server *(oldhosts[NMAXNSERVERS]); AFS_STATCNT(CheckVLDB); afs_FinalizeReq(areq); if ((i = afs_InitReq(&treq, afs_osi_credp))) return DUNNO; v = afs_osi_Alloc(sizeof(*v)); tcell = afs_GetCell(afid->Cell, READ_LOCK); bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume); do { VSleep(2); /* Better safe than sorry. */ tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum, &treq, SHARED_LOCK); if (tconn) { if (tconn->srvr->server->flags & SNO_LHOSTS) { type = 0; RX_AFS_GUNLOCK(); i = VL_GetEntryByNameO(tconn->id, bp, &v->tve); RX_AFS_GLOCK(); } else if (tconn->srvr->server->flags & SYES_LHOSTS) { type = 1; RX_AFS_GUNLOCK(); i = VL_GetEntryByNameN(tconn->id, bp, &v->ntve); RX_AFS_GLOCK(); } else { type = 2; RX_AFS_GUNLOCK(); i = VL_GetEntryByNameU(tconn->id, bp, &v->utve); RX_AFS_GLOCK(); if (!(tconn->srvr->server->flags & SVLSRV_UUID)) { if (i == RXGEN_OPCODE) { type = 1; RX_AFS_GUNLOCK(); i = VL_GetEntryByNameN(tconn->id, bp, &v->ntve); RX_AFS_GLOCK(); if (i == RXGEN_OPCODE) { type = 0; tconn->srvr->server->flags |= SNO_LHOSTS; RX_AFS_GUNLOCK(); i = VL_GetEntryByNameO(tconn->id, bp, &v->tve); RX_AFS_GLOCK(); } else if (!i) tconn->srvr->server->flags |= SYES_LHOSTS; } else if (!i) tconn->srvr->server->flags |= SVLSRV_UUID; } lastcode = i; } } else i = -1; } while (afs_Analyze(tconn, i, NULL, &treq, -1, /* no op code for this */ SHARED_LOCK, tcell)); afs_PutCell(tcell, READ_LOCK); afs_Trace2(afs_iclSetp, CM_TRACE_CHECKVLDB, ICL_TYPE_FID, &afid, ICL_TYPE_INT32, i); if (i) { afs_osi_Free(v, sizeof(*v)); return DUNNO; } /* have info, copy into serverHost array */ changed = 0; tvp = afs_FindVolume(afid, WRITE_LOCK); if (tvp) { ObtainWriteLock(&tvp->lock, 107); for (i = 0; i < NMAXNSERVERS && tvp->serverHost[i]; i++) { oldhosts[i] = tvp->serverHost[i]; } if (type == 2) { InstallUVolumeEntry(tvp, &v->utve, afid->Cell, tcell, &treq); } else if (type == 1) { InstallNVolumeEntry(tvp, &v->ntve, afid->Cell); } else { InstallVolumeEntry(tvp, &v->tve, afid->Cell); } if (i < NMAXNSERVERS && tvp->serverHost[i]) { changed = 1; } for (--i; !changed && i >= 0; i--) { if (tvp->serverHost[i] != oldhosts[i]) { changed = 1; /* also happens if prefs change. big deal. */ } } ReleaseWriteLock(&tvp->lock); afs_PutVolume(tvp, WRITE_LOCK); } else { /* can't find volume */ tvp = afs_GetVolume(afid, &treq, WRITE_LOCK); if (tvp) { afs_PutVolume(tvp, WRITE_LOCK); afs_osi_Free(v, sizeof(*v)); return DIFFERENT; } else { afs_osi_Free(v, sizeof(*v)); return DUNNO; } } afs_osi_Free(v, sizeof(*v)); return (changed ? DIFFERENT : SAME); } /*VLDB_Same */
void LockAndInstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell, struct cell *tcell, struct vrequest *areq) { struct server *ts; struct afs_conn *tconn; struct cell *cellp; int i, j; afs_uint32 serverid; afs_int32 mask; int k; char type = 0; struct server *serverHost[AFS_MAXHOSTS]; AFS_STATCNT(InstallVolumeEntry); memset(serverHost, 0, sizeof(serverHost)); /* Determine type of volume we want */ if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) { mask = VLSF_RWVOL; } else if ((ve->flags & VLF_ROEXISTS) && av->volume == ve->volumeId[ROVOL]) { mask = VLSF_ROVOL; type |= VRO; } else if ((ve->flags & VLF_BACKEXISTS) && (av->volume == ve->volumeId[BACKVOL])) { /* backup always is on the same volume as parent */ mask = VLSF_RWVOL; type |= (VRO | VBackup); } else { mask = 0; /* Can't find volume in vldb entry */ } cellp = afs_GetCell(acell, 0); /* Gather the list of servers the VLDB says the volume is on * and initialize the ve->serverHost[] array. If a server struct * is not found, then get the list of addresses for the * server, VL_GetAddrsU(), and create a server struct, afs_GetServer(). */ for (i = 0, j = 0; i < ve->nServers; i++) { if (((ve->serverFlags[i] & mask) == 0) || (ve->serverFlags[i] & VLSF_DONTUSE)) { continue; /* wrong volume don't use this volume */ } if (!(ve->serverFlags[i] & VLSERVER_FLAG_UUID)) { /* The server has no uuid */ serverid = htonl(ve->serverNumber[i].time_low); ts = afs_GetServer(&serverid, 1, acell, cellp->fsport, WRITE_LOCK, (afsUUID *) 0, 0, av); } else { ts = afs_FindServer(0, cellp->fsport, &ve->serverNumber[i], 0); if (ts && (ts->sr_addr_uniquifier == ve->serverUnique[i]) && ts->addr) { /* uuid, uniquifier, and portal are the same */ } else { afs_uint32 *addrp, code; afs_int32 nentries, unique; bulkaddrs addrs; ListAddrByAttributes attrs; afsUUID uuid; struct rx_connection *rxconn; memset(&attrs, 0, sizeof(attrs)); attrs.Mask = VLADDR_UUID; attrs.uuid = ve->serverNumber[i]; memset(&uuid, 0, sizeof(uuid)); memset(&addrs, 0, sizeof(addrs)); do { tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum, areq, SHARED_LOCK, 0, &rxconn); if (tconn) { RX_AFS_GUNLOCK(); code = VL_GetAddrsU(rxconn, &attrs, &uuid, &unique, &nentries, &addrs); RX_AFS_GLOCK(); } else { code = -1; } /* Handle corrupt VLDB (defect 7393) */ if (code == 0 && nentries == 0) code = VL_NOENT; } while (afs_Analyze (tconn, rxconn, code, NULL, areq, -1, SHARED_LOCK, tcell)); if (code) { /* Better handing of such failures; for now we'll simply retry this call */ areq->volumeError = 1; return; } addrp = addrs.bulkaddrs_val; for (k = 0; k < nentries; k++) { addrp[k] = htonl(addrp[k]); } ts = afs_GetServer(addrp, nentries, acell, cellp->fsport, WRITE_LOCK, &ve->serverNumber[i], ve->serverUnique[i], av); xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs); } #if defined(AFS_LINUX26_ENV) && !defined(UKERNEL) if (afs_compare_serveruuid(&ve->serverNumber[i])) av->states |= VPartVisible; #endif } serverHost[j] = ts; /* The cell field could be 0 if the server entry was created * first with the 'fs setserverprefs' call which doesn't set * the cell field. Thus if the afs_GetServer call above * follows later on it will find the server entry thus it will * simply return without setting any fields, so we set the * field ourselves below. */ if (!ts->cell) ts->cell = cellp; afs_PutServer(ts, WRITE_LOCK); j++; } ObtainWriteLock(&av->lock, 111); memcpy(av->serverHost, serverHost, sizeof(serverHost)); /* from above */ av->states |= type; /* fill in volume types */ av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0); av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0); av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0); if (ve->flags & VLF_DFSFILESET) av->states |= VForeign; afs_SortServers(av->serverHost, AFS_MAXHOSTS); } /*InstallVolumeEntry */
void InstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell, struct cell *tcell, struct vrequest *areq) { register struct server *ts; struct afs_conn *tconn; struct cell *cellp; register int i, j; afs_uint32 serverid; afs_int32 mask; int k; AFS_STATCNT(InstallVolumeEntry); /* Determine type of volume we want */ if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) { mask = VLSF_RWVOL; } else if ((ve->flags & VLF_ROEXISTS) && av->volume == ve->volumeId[ROVOL]) { mask = VLSF_ROVOL; av->states |= VRO; } else if ((ve->flags & VLF_BACKEXISTS) && (av->volume == ve->volumeId[BACKVOL])) { /* backup always is on the same volume as parent */ mask = VLSF_RWVOL; av->states |= (VRO | VBackup); } else { mask = 0; /* Can't find volume in vldb entry */ } /* fill in volume types */ av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0); av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0); av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0); if (ve->flags & VLF_DFSFILESET) av->states |= VForeign; cellp = afs_GetCell(acell, 0); /* This volume, av, is locked. Zero out the serverHosts[] array * so that if afs_GetServer() decides to replace the server * struct, we don't deadlock trying to afs_ResetVolumeInfo() * this volume. */ for (j = 0; j < MAXHOSTS; j++) { av->serverHost[j] = 0; } /* Gather the list of servers the VLDB says the volume is on * and initialize the ve->serverHost[] array. If a server struct * is not found, then get the list of addresses for the * server, VL_GetAddrsU(), and create a server struct, afs_GetServer(). */ for (i = 0, j = 0; i < ve->nServers; i++) { if (((ve->serverFlags[i] & mask) == 0) || (ve->serverFlags[i] & VLSF_DONTUSE)) { continue; /* wrong volume don't use this volume */ } if (!(ve->serverFlags[i] & VLSERVER_FLAG_UUID)) { /* The server has no uuid */ serverid = htonl(ve->serverNumber[i].time_low); ts = afs_GetServer(&serverid, 1, acell, cellp->fsport, WRITE_LOCK, (afsUUID *) 0, 0); } else { ts = afs_FindServer(0, cellp->fsport, &ve->serverNumber[i], 0); if (ts && (ts->sr_addr_uniquifier == ve->serverUnique[i]) && ts->addr) { /* uuid, uniquifier, and portal are the same */ } else { afs_uint32 *addrp, nentries, code, unique; bulkaddrs addrs; ListAddrByAttributes attrs; afsUUID uuid; memset((char *)&attrs, 0, sizeof(attrs)); attrs.Mask = VLADDR_UUID; attrs.uuid = ve->serverNumber[i]; memset((char *)&uuid, 0, sizeof(uuid)); memset((char *)&addrs, 0, sizeof(addrs)); do { tconn = afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum, areq, SHARED_LOCK); if (tconn) { RX_AFS_GUNLOCK(); code = VL_GetAddrsU(tconn->id, &attrs, &uuid, &unique, &nentries, &addrs); RX_AFS_GLOCK(); } else { code = -1; } /* Handle corrupt VLDB (defect 7393) */ if (code == 0 && nentries == 0) code = VL_NOENT; } while (afs_Analyze (tconn, code, NULL, areq, -1, SHARED_LOCK, tcell)); if (code) { /* Better handing of such failures; for now we'll simply retry this call */ areq->volumeError = 1; return; } addrp = addrs.bulkaddrs_val; for (k = 0; k < nentries; k++) { addrp[k] = htonl(addrp[k]); } ts = afs_GetServer(addrp, nentries, acell, cellp->fsport, WRITE_LOCK, &ve->serverNumber[i], ve->serverUnique[i]); afs_osi_Free(addrs.bulkaddrs_val, addrs.bulkaddrs_len * sizeof(*addrp)); } } av->serverHost[j] = ts; /* The cell field could be 0 if the server entry was created * first with the 'fs setserverprefs' call which doesn't set * the cell field. Thus if the afs_GetServer call above * follows later on it will find the server entry thus it will * simply return without setting any fields, so we set the * field ourselves below. */ if (!ts->cell) ts->cell = cellp; afs_PutServer(ts, WRITE_LOCK); j++; } afs_SortServers(av->serverHost, MAXHOSTS); } /*InstallVolumeEntry */