/*! * Check if entries have been deleted in a vnode's shadow * dir. * * \return Returns the number of dirty children. * * \note afs_DDirtyVCListLock must be write locked. */ int afs_CheckDeletedChildren(struct vcache *avc) { struct dcache *tdc; struct DirtyChildrenCount dcc; struct VenusFid shadow_fid; if (!avc->f.shadow.vnode) /* Empty dir. */ return 0; shadow_fid.Cell = avc->f.fid.Cell; shadow_fid.Fid.Volume = avc->f.fid.Fid.Volume; shadow_fid.Fid.Vnode = avc->f.shadow.vnode; shadow_fid.Fid.Unique = avc->f.shadow.unique; dcc.count = 0; /* Get shadow dir's dcache. */ tdc = afs_FindDCacheByFid(&shadow_fid); if (tdc) { dcc.vc = avc; afs_dir_EnumerateDir(tdc, &chk_del_children_hook, &dcc); afs_PutDCache(tdc); } return dcc.count; }
static void ListDir(char *name) { dirhandle dir; OpenDir(name, &dir); afs_dir_EnumerateDir(&dir, ListEntry, 0); }
void afs_DbgListDirEntries(struct VenusFid *afid) { struct dcache *tdc; /* Get shadow dir's dcache. */ tdc = afs_FindDCacheByFid(afid); if (tdc) { afs_dir_EnumerateDir(tdc, &list_dir_hook, NULL); afs_PutDCache(tdc); } }
/*! * Fixes the parentVnode and parentUnique fields of all * files (not dirs) contained in the directory pointed by * old_fid. This is useful on resync, when a locally created dir * get's a new fid and all the children references must be updated * to reflect the new fid. * * \note The dir's fid hasn't been changed yet, it is still referenced * with the old fid. * * \param old_fid The current dir's fid. * \param new_fid The new dir's fid. */ void afs_FixChildrenFids(struct VenusFid *old_fid, struct VenusFid *new_fid) { struct dcache *tdc; /* Get shadow dir's dcache. */ tdc = afs_FindDCacheByFid(old_fid); /* Change the fids. */ if (tdc) { afs_dir_EnumerateDir(tdc, &fix_children_fids_hook, new_fid); afs_PutDCache(tdc); } }
/*! * Get a the dir's fid by looking in the vcache for simple files and * in the ".." entry for directories. * * \param avc The file's vhash entry. * \param afid Put the fid here. * * \return 0 on success, -1 on failure */ int afs_GetParentDirFid(struct vcache *avc, struct VenusFid *afid) { struct dcache *tdc; afid->Cell = avc->f.fid.Cell; afid->Fid.Volume = avc->f.fid.Fid.Volume; switch (vType(avc)) { case VREG: case VLNK: /* Normal files have the dir fid embedded in the vcache. */ afid->Fid.Vnode = avc->f.parent.vnode; afid->Fid.Unique = avc->f.parent.unique; break; case VDIR: /* If dir or parent dir created locally*/ tdc = afs_FindDCacheByFid(&avc->f.fid); if (tdc) { afid->Fid.Unique = 0; /* Lookup each entry for the fid. It should be the first. */ afs_dir_EnumerateDir(tdc, &get_parent_dir_fid_hook, afid); afs_PutDCache(tdc); if (afid->Fid.Unique == 0) { return -1; } } else { return -1; } break; default: return -1; } return 0; }
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; }
/*! * Try to get a vnode's name by comparing all parent dir's entries * to the given fid. It can also return the dir's dcache. * * \param avc The file's vcache. * \param afid The parent dir's fid. * \param aname A preallocated string for the name. * \param deleted Has this file been deleted? If yes, use the shadow * dir for looking up the name. */ int afs_GetVnodeName(struct vcache *avc, struct VenusFid *afid, char *aname, int deleted) { int code = 0; struct dcache *tdc; struct vcache *parent_vc; struct NameAndFid tnf; struct VenusFid parent_fid; struct VenusFid shadow_fid; /* List dir contents and get it's tdc. */ if (deleted) { /* For deleted files, get the shadow dir's tdc: */ /* Get the parent dir's vcache that contains the shadow fid. */ parent_fid.Cell = avc->f.fid.Cell; parent_fid.Fid.Volume = avc->f.fid.Fid.Volume; if (avc->f.ddirty_flags & VDisconRename) { /* For renames the old dir fid is needed. */ parent_fid.Fid.Vnode = avc->f.oldParent.vnode; parent_fid.Fid.Unique = avc->f.oldParent.unique; } else { parent_fid.Fid.Vnode = afid->Fid.Vnode; parent_fid.Fid.Unique = afid->Fid.Unique; } /* Get the parent dir's vcache that contains the shadow fid. */ ObtainSharedLock(&afs_xvcache, 755); parent_vc = afs_FindVCache(&parent_fid, 0, 1); ReleaseSharedLock(&afs_xvcache); if (!parent_vc) { return ENOENT; } shadow_fid.Cell = parent_vc->f.fid.Cell; shadow_fid.Fid.Volume = parent_vc->f.fid.Fid.Volume; shadow_fid.Fid.Vnode = parent_vc->f.shadow.vnode; shadow_fid.Fid.Unique = parent_vc->f.shadow.unique; afs_PutVCache(parent_vc); /* Get shadow dir's dcache. */ tdc = afs_FindDCacheByFid(&shadow_fid); } else { /* For normal files, look into the current dir's entry. */ tdc = afs_FindDCacheByFid(afid); } /* if (deleted) */ if (tdc) { tnf.fid = &avc->f.fid; tnf.name_len = -1; tnf.name = aname; afs_dir_EnumerateDir(tdc, &get_vnode_name_hook, &tnf); afs_PutDCache(tdc); if (tnf.name_len == -1) code = ENOENT; } else { /* printf("Directory dcache not found!\n"); */ code = ENOENT; } return code; }