From c3d9ed3cb553747b9b317fc4794755ba98afc24b Mon Sep 17 00:00:00 2001 From: Jeffrey Hutzelman Date: Mon, 8 Nov 2004 06:26:01 +0000 Subject: [PATCH] readdir-report-correct-inums-20041108 FIXES 15962 We currently try fairly hard to make stat() on a volume root return the same vnode number as is listed for the mount point by readdir(). This behaviour is desirable; in fact, getcwd would not work otherwise. However, we are _not_ careful about making readdir list correct inode numbers for "." in a volume root or ".." in a directory whose parent is a volume root. This means that applications which examine these entries will still see inconsistent inode numbers. Clearly, it would be more desirable to report consistent inode numbers in all cases, instead of only in some cases. The attached patch, written while I was tracking down some NFS translator problems (which ultimately proved to be unrelated), makes readdir return consistent inode numbers for volume roots. We are running this on a few machines and have seen no problems, but it has not been extensively tested. --- src/afs/VNOPS/afs_vnop_readdir.c | 86 +++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/afs/VNOPS/afs_vnop_readdir.c b/src/afs/VNOPS/afs_vnop_readdir.c index 9954d1459..8bbd74b4e 100644 --- a/src/afs/VNOPS/afs_vnop_readdir.c +++ b/src/afs/VNOPS/afs_vnop_readdir.c @@ -292,6 +292,9 @@ afs_readdir_move(de, vc, auio, slen, rlen, off) afs_size_t off; { int code = 0; + struct volume *tvp; + afs_uint32 Volume = vc->fid.Fid.Volume; + afs_uint32 Vnode = de->fid.vnode; #if defined(AFS_SUN56_ENV) struct dirent64 *direntp; #else @@ -304,6 +307,79 @@ afs_readdir_move(de, vc, auio, slen, rlen, off) #endif /* AFS_SGI53_ENV */ AFS_STATCNT(afs_readdir_move); + +#define READDIR_CORRECT_INUMS +#ifdef READDIR_CORRECT_INUMS + if (de->name[0] == '.' && !de->name[1]) { + /* This is the '.' entry; if we are a volume root, we need to + * ignore the directory and use the inum for the mount point. + */ + if (!FidCmp(&afs_rootFid, &vc->fid)) { + Volume = 0; + Vnode = 2; + } else if (vc->mvstat == 2) { + tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK); + if (tvp) { + Volume = tvp->mtpoint.Fid.Volume; + Vnode = tvp->mtpoint.Fid.Vnode; + afs_PutVolume(tvp, READ_LOCK); + } + } + } + else if (de->name[0] == '.' && de->name[1] == '.' && !de->name[2]) { + /* This is the '..' entry. Getting this right is very tricky, + * because we might be a volume root (so our parent is in a + * different volume), or our parent might be a volume root + * (so we actually want the mount point) or BOTH! */ + if (!FidCmp(&afs_rootFid, &vc->fid)) { + /* We are the root of the AFS root, and thus our own parent */ + Volume = 0; + Vnode = 2; + } else if (vc->mvstat == 2) { + /* We are a volume root, which means our parent is in another + * volume. Luckily, we should have his fid cached... */ + if (vc->mvid) { + if (!FidCmp(&afs_rootFid, vc->mvid)) { + /* Parent directory is the root of the AFS root */ + Volume = 0; + Vnode = 2; + } else if (vc->mvid->Fid.Vnode == 1 + && vc->mvid->Fid.Unique == 1) { + /* XXX The above test is evil and probably breaks DFS */ + /* Parent directory is the target of a mount point */ + tvp = afs_GetVolume(vc->mvid, 0, READ_LOCK); + if (tvp) { + Volume = tvp->mtpoint.Fid.Volume; + Vnode = tvp->mtpoint.Fid.Vnode; + afs_PutVolume(tvp, READ_LOCK); + } + } else { + /* Parent directory is not a volume root */ + Volume = vc->mvid->Fid.Volume; + Vnode = vc->mvid->Fid.Vnode; + } + } + } else if (de->fid.vnode == 1 && de->fid.vunique == 1) { + /* XXX The above test is evil and probably breaks DFS */ + /* Parent directory is a volume root; use the right inum */ + tvp = afs_GetVolume(&vc->fid, 0, READ_LOCK); + if (tvp) { + if (tvp->cell == afs_rootFid.Cell + && tvp->volume == afs_rootFid.Fid.Volume) { + /* Parent directory is the root of the AFS root */ + Volume = 0; + Vnode = 2; + } else { + /* Parent directory is the target of a mount point */ + Volume = tvp->mtpoint.Fid.Volume; + Vnode = tvp->mtpoint.Fid.Vnode; + } + afs_PutVolume(tvp, READ_LOCK); + } + } + } +#endif + #ifdef AFS_SGI53_ENV { afs_int32 use64BitDirent; @@ -328,8 +404,7 @@ afs_readdir_move(de, vc, auio, slen, rlen, off) if (use64BitDirent) { struct min_dirent sdirEntry; - sdirEntry.d_fileno = - (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode); + sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode); FIXUPSTUPIDINODE(sdirEntry.d_fileno); sdirEntry.d_reclen = rlen; sdirEntry.d_off = (off_t) off; @@ -352,8 +427,7 @@ afs_readdir_move(de, vc, auio, slen, rlen, off) } } else { struct irix5_min_dirent sdirEntry; - sdirEntry.d_fileno = - (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode); + sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode); FIXUPSTUPIDINODE(sdirEntry.d_fileno); sdirEntry.d_reclen = rlen; sdirEntry.d_off = (afs_int32) off; @@ -384,7 +458,7 @@ afs_readdir_move(de, vc, auio, slen, rlen, off) #else direntp = (struct dirent *)osi_AllocLargeSpace(AFS_LRALLOCSIZ); #endif - direntp->d_ino = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode); + direntp->d_ino = (Volume << 16) + ntohl(Vnode); FIXUPSTUPIDINODE(direntp->d_ino); #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL) direntp->d_offset = off; @@ -398,7 +472,7 @@ afs_readdir_move(de, vc, auio, slen, rlen, off) osi_FreeLargeSpace((char *)direntp); #else /* AFS_SUN5_ENV */ /* Note the odd mechanism for building the inode number */ - sdirEntry.d_fileno = (vc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode); + sdirEntry.d_fileno = (Volume << 16) + ntohl(Vnode); FIXUPSTUPIDINODE(sdirEntry.d_fileno); sdirEntry.d_reclen = rlen; #if !defined(AFS_SGI_ENV) -- 2.39.5