sgi-afs-rename-decl-fix-20050610
[openafs.git] / src / afs / VNOPS / afs_vnop_rename.c
index ed451f5..1af38a2 100644 (file)
  */
 
 #include <afsconfig.h>
-#include "../afs/param.h"
+#include "afs/param.h"
 
-RCSID("$Header$");
+RCSID
+    ("$Header$");
 
-#include "../afs/sysincludes.h"        /* Standard vendor system headers */
-#include "../afs/afsincludes.h"        /* Afs-based standard headers */
-#include "../afs/afs_stats.h" /* statistics */
-#include "../afs/afs_cbqueue.h"
-#include "../afs/nfsclient.h"
-#include "../afs/afs_osidnlc.h"
+#include "afs/sysincludes.h"   /* Standard vendor system headers */
+#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afs_stats.h"     /* statistics */
+#include "afs/afs_cbqueue.h"
+#include "afs/nfsclient.h"
+#include "afs/afs_osidnlc.h"
 
 extern afs_rwlock_t afs_xcbhash;
 
 /* Note that we don't set CDirty here, this is OK because the rename
  * RPC is called synchronously. */
 
-afsrename(aodp, aname1, andp, aname2, acred)
-    register struct vcache *aodp, *andp;
-    char *aname1, *aname2;
-    struct AFS_UCRED *acred; {
-    struct vrequest treq;
+int
+afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
+         char *aname2, struct AFS_UCRED *acred, struct vrequest *areq)
+{
     register struct conn *tc;
     register afs_int32 code;
     afs_int32 returnCode;
@@ -46,28 +46,34 @@ afsrename(aodp, aname1, andp, aname2, acred)
     struct dcache *tdc1, *tdc2;
     struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
     struct AFSVolSync tsync;
-    XSTATS_DECLS
-
+    XSTATS_DECLS;
     AFS_STATCNT(afs_rename);
-    afs_Trace4(afs_iclSetp, CM_TRACE_RENAME, ICL_TYPE_POINTER, aodp, 
+    afs_Trace4(afs_iclSetp, CM_TRACE_RENAME, ICL_TYPE_POINTER, aodp,
               ICL_TYPE_STRING, aname1, ICL_TYPE_POINTER, andp,
               ICL_TYPE_STRING, aname2);
 
-    if (code = afs_InitReq(&treq, acred)) return code;
+    if (strlen(aname1) > AFSNAMEMAX || strlen(aname2) > AFSNAMEMAX) {
+       code = ENAMETOOLONG;
+       goto done;
+    }
 
     /* verify the latest versions of the stat cache entries */
-tagain:
-    code = afs_VerifyVCache(aodp, &treq);
-    if (code) goto done;
-    code = afs_VerifyVCache(andp, &treq);
-    if (code) goto done;
-    
+  tagain:
+    code = afs_VerifyVCache(aodp, areq);
+    if (code)
+       goto done;
+    code = afs_VerifyVCache(andp, areq);
+    if (code)
+       goto done;
+
     /* lock in appropriate order, after some checks */
-    if (aodp->fid.Cell != andp->fid.Cell || aodp->fid.Fid.Volume != andp->fid.Fid.Volume) {
+    if (aodp->fid.Cell != andp->fid.Cell
+       || aodp->fid.Fid.Volume != andp->fid.Fid.Volume) {
        code = EXDEV;
        goto done;
     }
     oneDir = 0;
+    code = 0;
     if (andp->fid.Fid.Vnode == aodp->fid.Fid.Vnode) {
        if (!strcmp(aname1, aname2)) {
            /* Same directory and same name; this is a noop and just return success
@@ -76,94 +82,111 @@ tagain:
            code = 0;
            goto done;
        }
-       ObtainWriteLock(&andp->lock,147);
-       oneDir = 1;         /* only one dude locked */
-    }
-    else if ((andp->states & CRO) || (aodp->states & CRO)) {
-       code = EROFS;
-       goto done;
-     }
-    else if (andp->fid.Fid.Vnode < aodp->fid.Fid.Vnode) {
-       ObtainWriteLock(&andp->lock,148);       /* lock smaller one first */
-       ObtainWriteLock(&aodp->lock,149);
-    }
-    else {
-       ObtainWriteLock(&aodp->lock,150);       /* lock smaller one first */
-       ObtainWriteLock(&andp->lock,557);
+       ObtainWriteLock(&andp->lock, 147);
+       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
+       if (!tdc1) {
+           code = ENOENT;
+       } else {
+           ObtainWriteLock(&tdc1->lock, 643);
+       }
+       tdc2 = tdc1;
+       oneDir = 1;             /* only one dude locked */
+    } else if ((andp->states & CRO) || (aodp->states & CRO)) {
+       code = EROFS;
+       goto done;
+    } else if (andp->fid.Fid.Vnode < aodp->fid.Fid.Vnode) {
+       ObtainWriteLock(&andp->lock, 148);      /* lock smaller one first */
+       ObtainWriteLock(&aodp->lock, 149);
+       tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
+       if (tdc2)
+           ObtainWriteLock(&tdc2->lock, 644);
+       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
+       if (tdc1)
+           ObtainWriteLock(&tdc1->lock, 645);
+       else
+           code = ENOENT;
+    } else {
+       ObtainWriteLock(&aodp->lock, 150);      /* lock smaller one first */
+       ObtainWriteLock(&andp->lock, 557);
+       tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
+       if (tdc1)
+           ObtainWriteLock(&tdc1->lock, 646);
+       else
+           code = ENOENT;
+       tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
+       if (tdc2)
+           ObtainWriteLock(&tdc2->lock, 647);
     }
 
-    osi_dnlc_remove (aodp, aname1, 0);
-    osi_dnlc_remove (andp, aname2, 0);
-    afs_symhint_inval(aodp); 
-    afs_symhint_inval(andp);
+    osi_dnlc_remove(aodp, aname1, 0);
+    osi_dnlc_remove(andp, aname2, 0);
 
-    /* before doing the rename, lookup the fileFid, just in case we
-     * don't make it down the path below that looks it up.  We always need
-     * fileFid in order to handle ".." invalidation at the very end.
-     */
-    code = 0;
-    tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, &treq, &offset, &len, 0);
-    if (!tdc1) {
-       code = ENOENT;
-    }
     /*
      * Make sure that the data in the cache is current. We may have
      * received a callback while we were waiting for the write lock.
      */
-    else if (!(aodp->states & CStatd)
-       || !hsame(aodp->m.DataVersion, tdc1->f.versionNo)) {
-       ReleaseWriteLock(&aodp->lock);
-       if (!oneDir) ReleaseWriteLock(&andp->lock);
-       afs_PutDCache(tdc1);
-       goto tagain;
+    if (tdc1) {
+       if (!(aodp->states & CStatd)
+           || !hsame(aodp->m.DataVersion, tdc1->f.versionNo)) {
+
+           ReleaseWriteLock(&aodp->lock);
+           if (!oneDir) {
+               if (tdc2) {
+                   ReleaseWriteLock(&tdc2->lock);
+                   afs_PutDCache(tdc2);
+               }
+               ReleaseWriteLock(&andp->lock);
+           }
+           ReleaseWriteLock(&tdc1->lock);
+           afs_PutDCache(tdc1);
+           goto tagain;
+       }
     }
 
     if (code == 0)
-       code = afs_dir_Lookup(&tdc1->f.inode, aname1, &fileFid.Fid);
+       code = afs_dir_Lookup(tdc1, aname1, &fileFid.Fid);
     if (code) {
-       if (tdc1) afs_PutDCache(tdc1);
+       if (tdc1) {
+           ReleaseWriteLock(&tdc1->lock);
+           afs_PutDCache(tdc1);
+       }
        ReleaseWriteLock(&aodp->lock);
-       if (!oneDir) ReleaseWriteLock(&andp->lock);
+       if (!oneDir) {
+           if (tdc2) {
+               ReleaseWriteLock(&tdc2->lock);
+               afs_PutDCache(tdc2);
+           }
+           ReleaseWriteLock(&andp->lock);
+       }
        goto done;
     }
-    afs_PutDCache(tdc1);
 
     /* locks are now set, proceed to do the real work */
     do {
-       tc = afs_Conn(&aodp->fid, &treq, SHARED_LOCK);
+       tc = afs_Conn(&aodp->fid, areq, SHARED_LOCK);
        if (tc) {
-          XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
-#ifdef RX_ENABLE_LOCKS
-         AFS_GUNLOCK();
-#endif /* RX_ENABLE_LOCKS */
-         code = RXAFS_Rename(tc->id, (struct AFSFid *) &aodp->fid.Fid, aname1,
-                               (struct AFSFid *) &andp->fid.Fid, aname2,
-                               &OutOldDirStatus, &OutNewDirStatus, &tsync);
-#ifdef RX_ENABLE_LOCKS
-         AFS_GLOCK();
-#endif /* RX_ENABLE_LOCKS */
-          XSTATS_END_TIME;
-       } else code = -1;
+           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
+           RX_AFS_GUNLOCK();
+           code =
+               RXAFS_Rename(tc->id, (struct AFSFid *)&aodp->fid.Fid, aname1,
+                            (struct AFSFid *)&andp->fid.Fid, aname2,
+                            &OutOldDirStatus, &OutNewDirStatus, &tsync);
+           RX_AFS_GLOCK();
+           XSTATS_END_TIME;
+       } else
+           code = -1;
+
+    } while (afs_Analyze
+            (tc, code, &andp->fid, areq, AFS_STATS_FS_RPCIDX_RENAME,
+             SHARED_LOCK, NULL));
 
-    } while
-       (afs_Analyze(tc, code, &andp->fid, &treq,
-                    AFS_STATS_FS_RPCIDX_RENAME, SHARED_LOCK, (struct cell *)0));
+    returnCode = code;         /* remember for later */
 
-    returnCode = code;     /* remember for later */
-    
     /* Now we try to do things locally.  This is really loathsome code. */
     unlinkFid.Fid.Vnode = 0;
     if (code == 0) {
-       tdc1 = tdc2 = 0;
-       /* don't use GetDCache because we don't want to worry about what happens if
-           we have to stat the file (updating the stat block) before finishing
-           local hero stuff (which may put old (from rename) data version number
-           back in the cache entry).
-           In any event, we don't really care if the data is not
-           in the cache; if it isn't, we won't do the update locally.  */
-       tdc1 = afs_FindDCache(aodp, 0);
-       if (!oneDir) tdc2 = afs_FindDCache(andp, 0);
-       else tdc2 = tdc1;
+       /*  In any event, we don't really care if the data (tdc2) is not
+        * in the cache; if it isn't, we won't do the update locally.  */
        /* see if version numbers increased properly */
        doLocally = 1;
        if (oneDir) {
@@ -171,8 +194,7 @@ tagain:
            if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1)) {
                doLocally = 0;
            }
-       }
-       else {
+       } else {
            /* two separate dirs, each increasing by 1 */
            if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1))
                doLocally = 0;
@@ -181,115 +203,123 @@ tagain:
            if (!doLocally) {
                if (tdc1) {
                    ZapDCE(tdc1);
-                   DZap(&tdc1->f.inode);
+                   DZap(tdc1);
                }
                if (tdc2) {
                    ZapDCE(tdc2);
-                   DZap(&tdc2->f.inode);
+                   DZap(tdc2);
                }
            }
        }
        /* now really do the work */
        if (doLocally) {
            /* first lookup the fid of the dude we're moving */
-           code = afs_dir_Lookup(&tdc1->f.inode, aname1, &fileFid.Fid);
+           code = afs_dir_Lookup(tdc1, aname1, &fileFid.Fid);
            if (code == 0) {
                /* delete the source */
-               code = afs_dir_Delete(&tdc1->f.inode, aname1);
+               code = afs_dir_Delete(tdc1, aname1);
            }
            /* first see if target is there */
-           if (code == 0 &&
-               afs_dir_Lookup(&tdc2->f.inode, aname2, &unlinkFid.Fid) == 0) {
+           if (code == 0
+               && afs_dir_Lookup(tdc2, aname2,
+                                 &unlinkFid.Fid) == 0) {
                /* target already exists, and will be unlinked by server */
-               code = afs_dir_Delete(&tdc2->f.inode, aname2);
+               code = afs_dir_Delete(tdc2, aname2);
            }
            if (code == 0) {
-               code = afs_dir_Create(&tdc2->f.inode, aname2, &fileFid.Fid);
+               code = afs_dir_Create(tdc2, aname2, &fileFid.Fid);
            }
            if (code != 0) {
                ZapDCE(tdc1);
-               DZap(&tdc1->f.inode);
+               DZap(tdc1);
                if (!oneDir) {
                    ZapDCE(tdc2);
-                   DZap(&tdc2->f.inode);
+                   DZap(tdc2);
                }
            }
        }
-       if (tdc1) afs_PutDCache(tdc1);
-       if ((!oneDir) && tdc2) afs_PutDCache(tdc2);
 
        /* update dir link counts */
        aodp->m.LinkCount = OutOldDirStatus.LinkCount;
        if (!oneDir)
            andp->m.LinkCount = OutNewDirStatus.LinkCount;
 
-    }
-    else {     /* operation failed (code != 0) */
-       if (code < 0) { 
+    } else {                   /* operation failed (code != 0) */
+       if (code < 0) {
            /* if failed, server might have done something anyway, and 
             * assume that we know about it */
-         ObtainWriteLock(&afs_xcbhash, 498);
-         afs_DequeueCallback(aodp);
-         afs_DequeueCallback(andp);
-         andp->states &= ~CStatd;
-         aodp->states &= ~CStatd;
-         ReleaseWriteLock(&afs_xcbhash);
-         osi_dnlc_purgedp(andp);
-         osi_dnlc_purgedp(aodp);
+           ObtainWriteLock(&afs_xcbhash, 498);
+           afs_DequeueCallback(aodp);
+           afs_DequeueCallback(andp);
+           andp->states &= ~CStatd;
+           aodp->states &= ~CStatd;
+           ReleaseWriteLock(&afs_xcbhash);
+           osi_dnlc_purgedp(andp);
+           osi_dnlc_purgedp(aodp);
        }
     }
 
     /* release locks */
+    if (tdc1) {
+       ReleaseWriteLock(&tdc1->lock);
+       afs_PutDCache(tdc1);
+    }
+
+    if ((!oneDir) && tdc2) {
+       ReleaseWriteLock(&tdc2->lock);
+       afs_PutDCache(tdc2);
+    }
+
     ReleaseWriteLock(&aodp->lock);
-    if (!oneDir) ReleaseWriteLock(&andp->lock);
-    
+    if (!oneDir)
+       ReleaseWriteLock(&andp->lock);
+
     if (returnCode) {
        code = returnCode;
        goto done;
     }
 
     /* now, some more details.  if unlinkFid.Fid.Vnode then we should decrement
-       the link count on this file.  Note that if fileFid is a dir, then we don't
-       have to invalidate its ".." entry, since its DataVersion # should have
-       changed. However, interface is not good enough to tell us the
-       *file*'s new DataVersion, so we're stuck.  Our hack: delete mark
-       the data as having an "unknown" version (effectively discarding the ".."
-       entry */
+     * the link count on this file.  Note that if fileFid is a dir, then we don't
+     * have to invalidate its ".." entry, since its DataVersion # should have
+     * changed. However, interface is not good enough to tell us the
+     * *file*'s new DataVersion, so we're stuck.  Our hack: delete mark
+     * the data as having an "unknown" version (effectively discarding the ".."
+     * entry */
     if (unlinkFid.Fid.Vnode) {
        unlinkFid.Fid.Volume = aodp->fid.Fid.Volume;
        unlinkFid.Cell = aodp->fid.Cell;
-       tvc = (struct vcache *)0;
+       tvc = NULL;
        if (!unlinkFid.Fid.Unique) {
-           tvc = afs_LookupVCache(&unlinkFid, &treq, (afs_int32 *)0, WRITE_LOCK,
-                                  aodp, aname1);
+           tvc = afs_LookupVCache(&unlinkFid, areq, NULL, aodp, aname1);
        }
-       if (!tvc) /* lookup failed or wasn't called */
-          tvc = afs_GetVCache(&unlinkFid, &treq, (afs_int32 *)0,
-                              (struct vcache*)0, WRITE_LOCK);
+       if (!tvc)               /* lookup failed or wasn't called */
+           tvc = afs_GetVCache(&unlinkFid, areq, NULL, NULL);
 
        if (tvc) {
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
            afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
 #endif
-           ObtainWriteLock(&tvc->lock,151);
+           ObtainWriteLock(&tvc->lock, 151);
            tvc->m.LinkCount--;
-           tvc->states &= ~CUnique;            /* For the dfs xlator */
+           tvc->states &= ~CUnique;    /* For the dfs xlator */
            if (tvc->m.LinkCount == 0 && !osi_Active(tvc)) {
                /* if this was last guy (probably) discard from cache.
-                 * We have to be careful to not get rid of the stat
-                 * information, since otherwise operations will start
-                 * failing even if the file was still open (or
-                 * otherwise active), and the server no longer has the
-                 * info.  If the file still has valid links, we'll get
-                 * a break-callback msg from the server, so it doesn't
-                 * matter that we don't discard the status info */
-               if (!AFS_NFSXLATORREQ(acred)) afs_TryToSmush(tvc, acred, 0);
+                * We have to be careful to not get rid of the stat
+                * information, since otherwise operations will start
+                * failing even if the file was still open (or
+                * otherwise active), and the server no longer has the
+                * info.  If the file still has valid links, we'll get
+                * a break-callback msg from the server, so it doesn't
+                * matter that we don't discard the status info */
+               if (!AFS_NFSXLATORREQ(acred))
+                   afs_TryToSmush(tvc, acred, 0);
            }
            ReleaseWriteLock(&tvc->lock);
-#if    defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV)  || defined(AFS_SUN5_ENV)
+#ifdef AFS_BOZONLOCK_ENV
            afs_BozonUnlock(&tvc->pvnLock, tvc);
 #endif
-           afs_PutVCache(tvc, WRITE_LOCK);
+           afs_PutVCache(tvc);
        }
     }
 
@@ -298,65 +328,62 @@ tagain:
        fileFid.Fid.Volume = aodp->fid.Fid.Volume;
        fileFid.Cell = aodp->fid.Cell;
        if (!fileFid.Fid.Unique)
-           tvc = afs_LookupVCache(&fileFid, &treq, (afs_int32 *)0, WRITE_LOCK, andp, aname2);
+           tvc = afs_LookupVCache(&fileFid, areq, NULL, andp, aname2);
        else
-           tvc = afs_GetVCache(&fileFid, &treq, (afs_int32 *)0,
-                               (struct vcache*)0, WRITE_LOCK);
+           tvc = afs_GetVCache(&fileFid, areq, NULL, (struct vcache *)0);
        if (tvc && (vType(tvc) == VDIR)) {
-           ObtainWriteLock(&tvc->lock,152);
-           tdc1 = afs_FindDCache(tvc, 0);
+           ObtainWriteLock(&tvc->lock, 152);
+           tdc1 = afs_FindDCache(tvc, (afs_size_t) 0);
            if (tdc1) {
+               ObtainWriteLock(&tdc1->lock, 648);
                ZapDCE(tdc1);   /* mark as unknown */
-               DZap(&tdc1->f.inode);
+               DZap(tdc1);
+               ReleaseWriteLock(&tdc1->lock);
                afs_PutDCache(tdc1);    /* put it back */
            }
            osi_dnlc_remove(tvc, "..", 0);
            ReleaseWriteLock(&tvc->lock);
-           afs_PutVCache(tvc, WRITE_LOCK);
+           afs_PutVCache(tvc);
        } else if (tvc) {
            /* True we shouldn't come here since tvc SHOULD be a dir, but we
             * 'syntactically' need to unless  we change the 'if' above...
             */
-           afs_PutVCache(tvc, WRITE_LOCK);
+           afs_PutVCache(tvc);
        }
     }
     code = returnCode;
-done:
-    code = afs_CheckCode(code, &treq, 25);
+  done:
     return code;
 }
 
-#ifdef AFS_OSF_ENV
-afs_rename(fndp, tndp)
-    struct nameidata *fndp, *tndp; {
-    register struct vcache *aodp = (struct vcache *)fndp->ni_dvp;
-    char *aname1 = fndp->ni_dent.d_name;
-    register struct vcache *andp = (struct vcache *)tndp->ni_dvp;
-    char *aname2 = tndp->ni_dent.d_name;
-    struct ucred *acred = tndp->ni_cred;
-#else  /* AFS_OSF_ENV */
+int
 #if defined(AFS_SGI_ENV)
-afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, npnp, acred)
-    struct pathname *npnp;
+afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, struct pathname *npnp, struct AFS_UCRED *acred)
 #else
-afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
-#endif
-    OSI_VC_DECL(aodp);
-    register struct vcache *andp;
-    char *aname1, *aname2;
-    struct AFS_UCRED *acred; {
+afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, struct AFS_UCRED *acred)
 #endif
+{
     register afs_int32 code;
-    OSI_VC_CONVERT(aodp)
+    struct afs_fakestat_state ofakestate;
+    struct afs_fakestat_state nfakestate;
+    struct vrequest treq;
+    OSI_VC_CONVERT(aodp);
 
-    code = afsrename(aodp, aname1, andp, aname2, acred);
-#ifdef AFS_OSF_ENV
-    AFS_RELE(tndp->ni_dvp);
-    if (tndp->ni_vp != NULL) {
-       AFS_RELE(tndp->ni_vp);
-    }
-    AFS_RELE(fndp->ni_dvp);
-    AFS_RELE(fndp->ni_vp);
-#endif /* AFS_OSF_ENV */
+    code = afs_InitReq(&treq, acred);
+    if (code)
+       return code;
+    afs_InitFakeStat(&ofakestate);
+    afs_InitFakeStat(&nfakestate);
+    code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
+    if (code)
+       goto done;
+    code = afs_EvalFakeStat(&andp, &nfakestate, &treq);
+    if (code)
+       goto done;
+    code = afsrename(aodp, aname1, andp, aname2, acred, &treq);
+  done:
+    afs_PutFakeStat(&ofakestate);
+    afs_PutFakeStat(&nfakestate);
+    code = afs_CheckCode(code, &treq, 25);
     return code;
 }