/* * Inform dynroot that a new vnode is being created. Return value * is non-zero if this vnode is handled by dynroot, in which case * FetchStatus will be filled in. */ int afs_DynrootNewVnode(struct vcache *avc, struct AFSFetchStatus *status) { char *bp, tbuf[CVBS]; if (_afs_IsDynrootFid(&avc->f.fid)) { if (!afs_dynrootEnable) return 0; afs_GetDynroot(0, 0, status); afs_PutDynroot(); return 1; } if (afs_IsDynrootMount(avc)) { afs_GetDynrootMount(0, 0, status); afs_PutDynroot(); return 1; } /* * Check if this is an entry under /afs, e.g. /afs/cellname. */ if (avc->f.fid.Cell == afs_dynrootCell && avc->f.fid.Fid.Volume == AFS_DYNROOT_VOLUME) { struct cell *c; struct cell_alias *ca; int namelen, linklen, cellidx, rw; memset(status, 0, sizeof(struct AFSFetchStatus)); status->FileType = SymbolicLink; status->LinkCount = 1; status->DataVersion = 1; status->CallerAccess = PRSFS_LOOKUP | PRSFS_READ; status->AnonymousAccess = PRSFS_LOOKUP | PRSFS_READ; status->ParentVnode = 1; status->ParentUnique = 1; if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_SYMLINK) { struct afs_dynSymlink *ts; int index = VNUM_TO_VNID(avc->f.fid.Fid.Vnode); ObtainReadLock(&afs_dynSymlinkLock); ts = afs_dynSymlinkBase; while (ts) { if (ts->index == index) break; ts = ts->next; } if (ts) { linklen = strlen(ts->target); avc->linkData = afs_osi_Alloc(linklen + 1); strcpy(avc->linkData, ts->target); status->Length = linklen; status->UnixModeBits = 0755; } ReleaseReadLock(&afs_dynSymlinkLock); return ts ? 1 : 0; } if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_CELL && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_ALIAS && VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) != VN_TYPE_MOUNT) { afs_warn("dynroot vnode inconsistency, unknown VNTYPE %d\n", VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode)); return 0; } cellidx = VNUM_TO_CIDX(avc->f.fid.Fid.Vnode); rw = VNUM_TO_RW(avc->f.fid.Fid.Vnode); if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_ALIAS) { char *realName; ca = afs_GetCellAlias(cellidx); if (!ca) { afs_warn("dynroot vnode inconsistency, can't find alias %d\n", cellidx); return 0; } /* * linkData needs to contain the name of the cell * we're aliasing for. */ realName = ca->cell; if (!realName) { afs_warn("dynroot: alias %s missing real cell name\n", ca->alias); avc->linkData = afs_strdup("unknown"); linklen = 7; } else { int namelen = strlen(realName); linklen = rw + namelen; avc->linkData = afs_osi_Alloc(linklen + 1); strcpy(avc->linkData, rw ? "." : ""); afs_strcat(avc->linkData, realName); } status->UnixModeBits = 0755; afs_PutCellAlias(ca); } else if (VNUM_TO_VNTYPE(avc->f.fid.Fid.Vnode) == VN_TYPE_MOUNT) { c = afs_GetCellByIndex(cellidx, READ_LOCK); if (!c) { afs_warn("dynroot vnode inconsistency, can't find cell %d\n", cellidx); return 0; } /* * linkData needs to contain "%cell:volumeid" */ namelen = strlen(c->cellName); bp = afs_cv2string(&tbuf[CVBS], avc->f.fid.Fid.Unique); linklen = 2 + namelen + strlen(bp); avc->linkData = afs_osi_Alloc(linklen + 1); strcpy(avc->linkData, "%"); afs_strcat(avc->linkData, c->cellName); afs_strcat(avc->linkData, ":"); afs_strcat(avc->linkData, bp); status->UnixModeBits = 0644; status->ParentVnode = AFS_DYNROOT_MOUNT_VNODE; afs_PutCell(c, READ_LOCK); } else { c = afs_GetCellByIndex(cellidx, READ_LOCK); if (!c) { afs_warn("dynroot vnode inconsistency, can't find cell %d\n", cellidx); return 0; } /* * linkData needs to contain "#cell:root.cell" or "%cell:root.cell" */ namelen = strlen(c->cellName); linklen = 1 + namelen + 10; avc->linkData = afs_osi_Alloc(linklen + 1); strcpy(avc->linkData, rw ? "%" : "#"); afs_strcat(avc->linkData, c->cellName); afs_strcat(avc->linkData, ":root.cell"); status->UnixModeBits = 0644; afs_PutCell(c, READ_LOCK); } status->Length = linklen; return 1; } return 0; }
static int afs_encode_fh(struct dentry *de, __u32 *fh, int *max_len, int connectable) { struct vcache *tvc; struct cell *tc; int vntype; if (!de->d_inode) /* encode a negative dentry?! */ return 255; if (*max_len < 4) /* not enough space */ return 255; tvc = VTOAFS(de->d_inode); #ifdef OSI_EXPORT_DEBUG printk("afs: encode_fh(0x%08x/%d/%d.%d)\n", tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode, tvc->f.fid.Fid.Unique); #endif if (afs_IsDynrootAnyFid(&tvc->f.fid)) { vntype = VNUM_TO_VNTYPE(tvc->f.fid.Fid.Vnode); switch (vntype) { case 0: /* encode as a normal filehandle */ break; case VN_TYPE_MOUNT: if (*max_len < 5) { return 255; } /* fall through */ case VN_TYPE_CELL: case VN_TYPE_ALIAS: AFS_GLOCK(); tc = afs_GetCellByIndex(VNUM_TO_CIDX(tvc->f.fid.Fid.Vnode), READ_LOCK); if (!tc) { AFS_GUNLOCK(); return 255; } memcpy((void *)fh, tc->cellHandle, 16); afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); if (vntype == VN_TYPE_MOUNT) { fh[4] = htonl(tvc->f.fid.Fid.Unique); *max_len = 5; return AFSFH_DYN_MOUNT; } *max_len = 4; if (vntype == VN_TYPE_CELL) { return AFSFH_DYN_RO_CELL | VNUM_TO_RW(tvc->f.fid.Fid.Vnode); } else { return AFSFH_DYN_RO_LINK | VNUM_TO_RW(tvc->f.fid.Fid.Vnode); } case VN_TYPE_SYMLINK: /* XXX fill in filehandle for dynroot symlink */ /* XXX return AFSFH_DYN_SYMLINK; */ default: return 255; } } if (*max_len < 7) { /* not big enough for a migratable filehandle */ /* always encode in network order */ fh[0] = htonl(tvc->f.fid.Cell); fh[1] = htonl(tvc->f.fid.Fid.Volume); fh[2] = htonl(tvc->f.fid.Fid.Vnode); fh[3] = htonl(tvc->f.fid.Fid.Unique); *max_len = 4; return AFSFH_NET_VENUSFID; } AFS_GLOCK(); tc = afs_GetCell(tvc->f.fid.Cell, READ_LOCK); if (!tc) { AFS_GUNLOCK(); return 255; } memcpy((void *)fh, tc->cellHandle, 16); afs_PutCell(tc, READ_LOCK); AFS_GUNLOCK(); /* always encode in network order */ fh[4] = htonl(tvc->f.fid.Fid.Volume); fh[5] = htonl(tvc->f.fid.Fid.Vnode); fh[6] = htonl(tvc->f.fid.Fid.Unique); *max_len = 7; return AFSFH_NET_CELLFID; }
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; }
static int afs_export_get_name(struct dentry *parent, char *name, struct dentry *child) { struct afs_fakestat_state fakestate; struct get_name_data data; struct vrequest treq; struct volume *tvp; struct vcache *vcp; struct dcache *tdc; cred_t *credp; afs_size_t dirOffset, dirLen; afs_int32 code = 0; if (!parent->d_inode) { #ifdef OSI_EXPORT_DEBUG /* can't lookup name in a negative dentry */ printk("afs: get_name(%s, %s): no parent inode\n", parent->d_name.name ? (char *)parent->d_name.name : "?", child->d_name.name ? (char *)child->d_name.name : "?"); #endif return -EIO; } if (!child->d_inode) { #ifdef OSI_EXPORT_DEBUG /* can't find the FID of negative dentry */ printk("afs: get_name(%s, %s): no child inode\n", parent->d_name.name ? (char *)parent->d_name.name : "?", child->d_name.name ? (char *)child->d_name.name : "?"); #endif return -ENOENT; } afs_InitFakeStat(&fakestate); credp = crref(); AFS_GLOCK(); vcp = VTOAFS(child->d_inode); /* special case dynamic mount directory */ if (afs_IsDynrootMount(vcp)) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): this is the dynmount dir\n", parent->d_name.name ? (char *)parent->d_name.name : "?", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique); #endif data.fid = vcp->f.fid; if (VTOAFS(parent->d_inode) == afs_globalVp) strcpy(name, AFS_DYNROOT_MOUNTNAME); else code = -ENOENT; goto done; } /* Figure out what FID to look for */ if (vcp->mvstat == 2) { /* volume root */ tvp = afs_GetVolume(&vcp->f.fid, 0, READ_LOCK); if (!tvp) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no volume for root\n", parent->d_name.name ? (char *)parent->d_name.name : "?", vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique); #endif code = ENOENT; goto done; } data.fid = tvp->mtpoint; afs_PutVolume(tvp, READ_LOCK); } else { data.fid = vcp->f.fid; } vcp = VTOAFS(parent->d_inode); #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): parent is 0x%08x/%d/%d.%d\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique); #endif code = afs_InitReq(&treq, credp); if (code) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): afs_InitReq: %d\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, code); #endif goto done; } /* a dynamic mount point in the dynamic mount directory */ if (afs_IsDynrootMount(vcp) && afs_IsDynrootAnyFid(&data.fid) && VNUM_TO_VNTYPE(data.fid.Fid.Vnode) == VN_TYPE_MOUNT) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dynamic mount point\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique); #endif vcp = afs_GetVCache(&data.fid, &treq, NULL, NULL); if (vcp) { ObtainReadLock(&vcp->lock); if (strlen(vcp->linkData + 1) <= NAME_MAX) strcpy(name, vcp->linkData + 1); else code = ENOENT; ReleaseReadLock(&vcp->lock); afs_PutVCache(vcp); } else { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): no vcache\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique); #endif code = ENOENT; } goto done; } code = afs_EvalFakeStat(&vcp, &fakestate, &treq); if (code) goto done; if (vcp->f.fid.Cell != data.fid.Cell || vcp->f.fid.Fid.Volume != data.fid.Fid.Volume) { /* parent is not the expected cell and volume; thus it * cannot possibly contain the fid we are looking for */ #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): wrong parent 0x%08x/%d\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, vcp->f.fid.Cell, vcp->f.fid.Fid.Volume); #endif code = ENOENT; goto done; } redo: if (!(vcp->f.states & CStatd)) { if ((code = afs_VerifyVCache2(vcp, &treq))) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): VerifyVCache2(0x%08x/%d/%d.%d): %d\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code); #endif goto done; } } tdc = afs_GetDCache(vcp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1); if (!tdc) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): GetDCache(0x%08x/%d/%d.%d): %d\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code); #endif code = EIO; goto done; } ObtainReadLock(&vcp->lock); ObtainReadLock(&tdc->lock); /* * Make sure that the data in the cache is current. There are two * cases we need to worry about: * 1. The cache data is being fetched by another process. * 2. The cache data is no longer valid */ while ((vcp->f.states & CStatd) && (tdc->dflags & DFFetching) && hsame(vcp->f.m.DataVersion, tdc->f.versionNo)) { ReleaseReadLock(&tdc->lock); ReleaseReadLock(&vcp->lock); afs_osi_Sleep(&tdc->validPos); ObtainReadLock(&vcp->lock); ObtainReadLock(&tdc->lock); } if (!(vcp->f.states & CStatd) || !hsame(vcp->f.m.DataVersion, tdc->f.versionNo)) { ReleaseReadLock(&tdc->lock); ReleaseReadLock(&vcp->lock); afs_PutDCache(tdc); #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): dir (0x%08x/%d/%d.%d) changed; retrying\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique); #endif goto redo; } data.name = name; data.found = 0; code = afs_dir_EnumerateDir(tdc, get_name_hook, &data); if (!code && !data.found) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): not found\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique); #endif code = ENOENT; } else if (code) { #ifdef OSI_EXPORT_DEBUG printk("afs: get_name(%s, 0x%08x/%d/%d.%d): Enumeratedir(0x%08x/%d/%d.%d): %d\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, vcp->f.fid.Cell, vcp->f.fid.Fid.Volume, vcp->f.fid.Fid.Vnode, vcp->f.fid.Fid.Unique, code); #endif } ReleaseReadLock(&tdc->lock); ReleaseReadLock(&vcp->lock); afs_PutDCache(tdc); done: if (!code) { printk("afs: get_name(%s, 0x%08x/%d/%d.%d) => %s\n", parent->d_name.name ? (char *)parent->d_name.name : "?", data.fid.Cell, data.fid.Fid.Volume, data.fid.Fid.Vnode, data.fid.Fid.Unique, name); } afs_PutFakeStat(&fakestate); AFS_GUNLOCK(); crfree(credp); code = afs_CheckCode(code, &treq, 102); return -code; }