/** * * @param volid Volume ID. If it's 0, get it from the name. * @param aname Volume name. * @param ve Volume entry. * @param tcell The cell containing this volume. * @param agood * @param type Type of volume. * @param areq Request. * @return Volume or NULL if failure. */ static struct volume * afs_SetupVolume(afs_int32 volid, char *aname, void *ve, struct cell *tcell, afs_int32 agood, afs_int32 type, struct vrequest *areq) { struct volume *tv; struct vldbentry *ove = (struct vldbentry *)ve; struct nvldbentry *nve = (struct nvldbentry *)ve; struct uvldbentry *uve = (struct uvldbentry *)ve; int whichType; /* which type of volume to look for */ int i, j, err = 0; if (!volid) { int len; /* special hint from file server to use vlserver */ len = strlen(aname); if (len >= 8 && strcmp(aname + len - 7, ".backup") == 0) whichType = BACKVOL; else if (len >= 10 && strcmp(aname + len - 9, ".readonly") == 0) whichType = ROVOL; else whichType = RWVOL; /* figure out which one we're really interested in (a set is returned) */ volid = afs_vtoi(aname); if (volid == 0) { if (type == 2) { volid = uve->volumeId[whichType]; } else if (type == 1) { volid = nve->volumeId[whichType]; } else { volid = ove->volumeId[whichType]; } } /* end of if (volid == 0) */ } /* end of if (!volid) */ ObtainWriteLock(&afs_xvolume, 108); i = VHash(volid); for (tv = afs_volumes[i]; tv; tv = tv->next) { if (tv->volume == volid && tv->cell == tcell->cellNum) { break; } } if (!tv) { struct fvolume *tf = 0; tv = afs_GetVolSlot(); if (!tv) { ReleaseWriteLock(&afs_xvolume); return NULL; } memset(tv, 0, sizeof(struct volume)); for (j = fvTable[FVHash(tcell->cellNum, volid)]; j != 0; j = tf->next) { if (afs_FVIndex != j) { struct osi_file *tfile; tfile = osi_UFSOpen(&volumeInode); err = afs_osi_Read(tfile, sizeof(struct fvolume) * j, &staticFVolume, sizeof(struct fvolume)); osi_UFSClose(tfile); if (err != sizeof(struct fvolume)) { afs_warn("afs_SetupVolume: error %d reading volumeinfo\n", (int)err); /* put tv back on the free list; the data in it is not valid */ tv->next = afs_freeVolList; afs_freeVolList = tv; /* staticFVolume contents are not valid */ afs_FVIndex = -1; ReleaseWriteLock(&afs_xvolume); return NULL; } afs_FVIndex = j; } tf = &staticFVolume; if (tf->cell == tcell->cellNum && tf->volume == volid) break; } tv->cell = tcell->cellNum; AFS_RWLOCK_INIT(&tv->lock, "volume lock"); tv->next = afs_volumes[i]; /* thread into list */ afs_volumes[i] = tv; tv->volume = volid; if (tf && (j != 0)) { tv->vtix = afs_FVIndex; tv->mtpoint = tf->mtpoint; tv->dotdot = tf->dotdot; tv->rootVnode = tf->rootVnode; tv->rootUnique = tf->rootUnique; } else { tv->vtix = -1; tv->rootVnode = tv->rootUnique = 0; afs_GetDynrootMountFid(&tv->dotdot); afs_GetDynrootMountFid(&tv->mtpoint); tv->mtpoint.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, tcell->cellIndex << 2); tv->mtpoint.Fid.Unique = volid; } } tv->refCount++; tv->states &= ~VRecheck; /* just checked it */ tv->accessTime = osi_Time(); ReleaseWriteLock(&afs_xvolume); if (type == 2) { LockAndInstallUVolumeEntry(tv, uve, tcell->cellNum, tcell, areq); } else if (type == 1) LockAndInstallNVolumeEntry(tv, nve, tcell->cellNum); else LockAndInstallVolumeEntry(tv, ove, tcell->cellNum); if (agood) { if (!tv->name) { tv->name = afs_osi_Alloc(strlen(aname) + 1); osi_Assert(tv->name != NULL); strcpy(tv->name, aname); } } for (i = 0; i < NMAXNSERVERS; i++) { tv->status[i] = not_busy; } ReleaseWriteLock(&tv->lock); return tv; }
static struct dentry *afs_export_get_parent(struct dentry *child) { struct VenusFid tfid; struct vrequest treq; struct cell *tcell; struct vcache *vcp; struct dentry *dp = NULL; cred_t *credp; afs_uint32 cellidx; int code; if (!child->d_inode) { /* can't find the parent of a negative dentry */ #ifdef OSI_EXPORT_DEBUG printk("afs: get_parent(%s): no inode\n", child->d_name.name ? (char *)child->d_name.name : "?"); #endif return ERR_PTR(-EIO); } credp = crref(); AFS_GLOCK(); vcp = VTOAFS(child->d_inode); if (afs_IsDynrootMount(vcp)) { /* the dynmount directory; parent is always the AFS root */ tfid = afs_globalVp->f.fid; } else if (afs_IsDynrootAny(vcp) && VNUM_TO_VNTYPE(vcp->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) { /* a mount point in the dynmount directory */ afs_GetDynrootMountFid(&tfid); } else if (vcp->mvstat == 2) { /* volume root */ ObtainReadLock(&vcp->lock); if (vcp->mvid && vcp->mvid->Fid.Volume) { tfid = *vcp->mvid; ReleaseReadLock(&vcp->lock); } else { ReleaseReadLock(&vcp->lock); tcell = afs_GetCell(vcp->f.fid.Cell, READ_LOCK); if (!tcell) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_parent(0x%08x/%d/%d.%d): no cell\n", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique); #endif dp = ERR_PTR(-ENOENT); goto done; } cellidx = tcell->cellIndex; afs_PutCell(tcell, READ_LOCK); afs_GetDynrootMountFid(&tfid); tfid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, cellidx << 2); tfid.Fid.Unique = vcp->f.fid.Fid.Volume; } } else { /* any other vnode */ if (vType(vcp) == VDIR && !vcp->f.parent.vnode && vcp->mvstat != 1) { code = afs_InitReq(&treq, credp); if (code) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_parent(0x%08x/%d/%d.%d): InitReq: %d\n", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code); #endif dp = ERR_PTR(-ENOENT); goto done; } else { code = update_dir_parent(&treq, vcp); if (code) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_parent(0x%08x/%d/%d.%d): update_dir_parent: %d\n", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code); #endif dp = ERR_PTR(-ENOENT); goto done; } } } tfid.Cell = vcp->f.fid.Cell; tfid.Fid.Volume = vcp->f.fid.Fid.Volume; tfid.Fid.Vnode = vcp->f.parent.vnode; tfid.Fid.Unique = vcp->f.parent.unique; } #ifdef OSI_EXPORT_DEBUG printk("afs: get_parent(0x%08x/%d/%d.%d): => 0x%08x/%d/%d.%d\n", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, tfid.Cell, tfid.Fid.Volume, tfid.Fid.Vnode, tfid.Fid.Unique); #endif dp = get_dentry_from_fid(credp, &tfid); if (!dp) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_parent(0x%08x/%d/%d.%d): no dentry\n", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique); #endif dp = ERR_PTR(-ENOENT); } done: AFS_GUNLOCK(); crfree(credp); return dp; }
/* * Regenerates the dynroot contents from the current list of * cells. Useful when the list of cells has changed due to * an AFSDB lookup, for instance. */ static void afs_RebuildDynroot(void) { int cellidx, maxcellidx, i; int aliasidx, maxaliasidx; struct cell *c; struct cell_alias *ca; int curChunk, curPage; int dirSize, dotLen; char *newDir, *dotCell; struct DirHeader *dirHeader; int linkCount = 0; struct afs_dynSymlink *ts; int newVersion; ObtainReadLock(&afs_dynrootDirLock); newVersion = afs_dynrootVersion; ReleaseReadLock(&afs_dynrootDirLock); /* * Compute the amount of space we need for the fake dir */ curChunk = 13; curPage = 0; /* Reserve space for "." and ".." */ curChunk += 2; /* Reserve space for the dynamic-mount directory */ afs_dynroot_computeDirEnt(AFS_DYNROOT_MOUNTNAME, &curPage, &curChunk); for (cellidx = 0;; cellidx++) { c = afs_GetCellByIndex(cellidx, READ_LOCK); if (!c) break; if (c->cellNum == afs_dynrootCell) continue; dotLen = strlen(c->cellName) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, c->cellName); afs_dynroot_computeDirEnt(c->cellName, &curPage, &curChunk); afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk); afs_osi_Free(dotCell, dotLen); afs_PutCell(c, READ_LOCK); } maxcellidx = cellidx; for (aliasidx = 0;; aliasidx++) { ca = afs_GetCellAlias(aliasidx); if (!ca) break; dotLen = strlen(ca->alias) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, ca->alias); afs_dynroot_computeDirEnt(ca->alias, &curPage, &curChunk); afs_dynroot_computeDirEnt(dotCell, &curPage, &curChunk); afs_osi_Free(dotCell, dotLen); afs_PutCellAlias(ca); } maxaliasidx = aliasidx; ObtainReadLock(&afs_dynSymlinkLock); ts = afs_dynSymlinkBase; while (ts) { afs_dynroot_computeDirEnt(ts->name, &curPage, &curChunk); ts = ts->next; } dirSize = (curPage + 1) * AFS_PAGESIZE; newDir = afs_osi_Alloc(dirSize); /* * Now actually construct the directory. */ curChunk = 13; curPage = 0; dirHeader = (struct DirHeader *)newDir; dirHeader->header.pgcount = 0; dirHeader->header.tag = htons(1234); dirHeader->header.freecount = 0; dirHeader->header.freebitmap[0] = 0xff; dirHeader->header.freebitmap[1] = 0x1f; for (i = 2; i < EPP / 8; i++) dirHeader->header.freebitmap[i] = 0; dirHeader->alloMap[0] = EPP - DHE - 1; for (i = 1; i < MAXPAGES; i++) dirHeader->alloMap[i] = EPP; for (i = 0; i < NHASHENT; i++) dirHeader->hashTable[i] = 0; /* Install ".", "..", and the dynamic mount directory */ afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ".", 1); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, "..", 1); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, AFS_DYNROOT_MOUNTNAME, AFS_DYNROOT_MOUNT_VNODE); linkCount += 3; for (cellidx = 0; cellidx < maxcellidx; cellidx++) { c = afs_GetCellByIndex(cellidx, READ_LOCK); if (!c) continue; if (c->cellNum == afs_dynrootCell) continue; dotLen = strlen(c->cellName) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, c->cellName); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, c->cellName, VNUM_FROM_CIDX_RW(cellidx, 0)); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell, VNUM_FROM_CIDX_RW(cellidx, 1)); afs_osi_Free(dotCell, dotLen); linkCount += 2; afs_PutCell(c, READ_LOCK); } for (aliasidx = 0; aliasidx < maxaliasidx; aliasidx++) { ca = afs_GetCellAlias(aliasidx); if (!ca) continue; dotLen = strlen(ca->alias) + 2; dotCell = afs_osi_Alloc(dotLen); strcpy(dotCell, "."); afs_strcat(dotCell, ca->alias); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ca->alias, VNUM_FROM_CAIDX_RW(aliasidx, 0)); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, dotCell, VNUM_FROM_CAIDX_RW(aliasidx, 1)); afs_osi_Free(dotCell, dotLen); afs_PutCellAlias(ca); } ts = afs_dynSymlinkBase; while (ts) { int vnum = VNUM_FROM_TYPEID(VN_TYPE_SYMLINK, ts->index); afs_dynroot_addDirEnt(dirHeader, &curPage, &curChunk, ts->name, vnum); ts = ts->next; } ReleaseReadLock(&afs_dynSymlinkLock); ObtainWriteLock(&afs_dynrootDirLock, 549); if (afs_dynrootDir) afs_osi_Free(afs_dynrootDir, afs_dynrootDirLen); afs_dynrootDir = newDir; afs_dynrootDirLen = dirSize; afs_dynrootDirLinkcnt = linkCount; afs_dynrootDirVersion = newVersion; ReleaseWriteLock(&afs_dynrootDirLock); }
static struct dentry *afs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type, int (*acceptable)(void *, struct dentry *), void *context) #endif { struct VenusFid fid; struct cell *tc; struct dentry *result; #if defined(NEW_EXPORT_OPS) __u32 *fh = (__u32 *)fh_fid->raw; #endif switch (fh_type) { case AFSFH_VENUSFID: if (fh_len != 4) return NULL; fid.Cell = fh[0]; fid.Fid.Volume = fh[1]; fid.Fid.Vnode = fh[2]; fid.Fid.Unique = fh[3]; break; case AFSFH_CELLFID: if (fh_len != 7) return NULL; AFS_GLOCK(); tc = afs_GetCellByHandle((void *)fh, READ_LOCK); if (!tc) { AFS_GUNLOCK(); return NULL; } fid.Cell = tc->cellNum; fid.Fid.Volume = fh[4]; fid.Fid.Vnode = fh[5]; fid.Fid.Unique = fh[6]; afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); break; case AFSFH_NET_VENUSFID: fid.Cell = ntohl(fh[0]); fid.Fid.Volume = ntohl(fh[1]); fid.Fid.Vnode = ntohl(fh[2]); fid.Fid.Unique = ntohl(fh[3]); break; case AFSFH_NET_CELLFID: if (fh_len != 7) return NULL; AFS_GLOCK(); tc = afs_GetCellByHandle((void *)fh, READ_LOCK); if (!tc) { AFS_GUNLOCK(); return NULL; } fid.Cell = tc->cellNum; fid.Fid.Volume = ntohl(fh[4]); fid.Fid.Vnode = ntohl(fh[5]); fid.Fid.Unique = ntohl(fh[6]); afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); break; case AFSFH_DYN_RO_CELL: case AFSFH_DYN_RW_CELL: if (fh_len != 4) return NULL; AFS_GLOCK(); tc = afs_GetCellByHandle((void *)fh, READ_LOCK); if (!tc) { AFS_GUNLOCK(); return NULL; } afs_GetDynrootFid(&fid); fid.Fid.Vnode = VNUM_FROM_CIDX_RW(tc->cellIndex, fh_type & 1); fid.Fid.Unique = 1; afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); break; case AFSFH_DYN_RO_LINK: case AFSFH_DYN_RW_LINK: if (fh_len != 4) return NULL; AFS_GLOCK(); tc = afs_GetCellByHandle((void *)fh, READ_LOCK); if (!tc) { AFS_GUNLOCK(); return NULL; } afs_GetDynrootFid(&fid); fid.Fid.Vnode = VNUM_FROM_CAIDX_RW(tc->cellIndex, fh_type & 1); fid.Fid.Unique = 1; afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); break; case AFSFH_DYN_MOUNT: if (fh_len != 5) return NULL; AFS_GLOCK(); tc = afs_GetCellByHandle((void *)fh, READ_LOCK); if (!tc) { AFS_GUNLOCK(); return NULL; } afs_GetDynrootFid(&fid); fid.Fid.Vnode = VNUM_FROM_TYPEID(VN_TYPE_MOUNT, tc->cellIndex << 2); fid.Fid.Unique = ntohl(fh[4]); afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); break; case AFSFH_DYN_SYMLINK: /* XXX parse dynroot symlink filehandle */ /* break; */ default: return NULL; } #if defined(NEW_EXPORT_OPS) result = afs_export_get_dentry(sb, &fid); #else result = sb->s_export_op->find_exported_dentry(sb, &fid, 0, acceptable, context); #endif #ifdef OSI_EXPORT_DEBUG if (!result) { printk("afs: decode_fh(0x%08x/%d/%d.%d): no dentry\n", fid.Cell, fid.Fid.Volume, fid.Fid.Vnode, fid.Fid.Unique); } else if (IS_ERR(result)) { printk("afs: decode_fh(0x%08x/%d/%d.%d): error %ld\n", fid.Cell, fid.Fid.Volume, fid.Fid.Vnode, fid.Fid.Unique, PTR_ERR(result)); } #endif return result; }