]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
STABLE14-readdir-report-correct-inums-20041108
authorJeffrey Hutzelman <jhutz@cmu.edu>
Tue, 9 Nov 2004 17:19:16 +0000 (17:19 +0000)
committerDerrick Brashear <shadow@dementia.org>
Tue, 9 Nov 2004 17:19:16 +0000 (17:19 +0000)
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.

(cherry picked from commit c3d9ed3cb553747b9b317fc4794755ba98afc24b)

src/afs/VNOPS/afs_vnop_readdir.c

index 9954d145904e68bab84949c535a9ee45100b60c4..8bbd74b4e54e74640ac2b56c0d16bddab76fd21f 100644 (file)
@@ -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)