FBSD, DFBSD (future) vnode_pager_setsize updates
[openafs.git] / src / afs / VNOPS / afs_vnop_rename.c
index 3fa86a7..45aaefa 100644 (file)
@@ -17,8 +17,6 @@
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
 
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
 #include "afsincludes.h"       /* Afs-based standard headers */
@@ -34,10 +32,10 @@ extern afs_rwlock_t afs_xcbhash;
 
 int
 afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
-         char *aname2, struct AFS_UCRED *acred, struct vrequest *areq)
+         char *aname2, afs_ucred_t *acred, struct vrequest *areq)
 {
-    register struct conn *tc;
-    register afs_int32 code;
+    struct afs_conn *tc;
+    afs_int32 code = 0;
     afs_int32 returnCode;
     int oneDir, doLocally;
     afs_size_t offset, len;
@@ -46,7 +44,8 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
     struct dcache *tdc1, *tdc2;
     struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
     struct AFSVolSync tsync;
-    XSTATS_DECLS AFS_STATCNT(afs_rename);
+    XSTATS_DECLS;
+    AFS_STATCNT(afs_rename);
     afs_Trace4(afs_iclSetp, CM_TRACE_RENAME, ICL_TYPE_POINTER, aodp,
               ICL_TYPE_STRING, aname1, ICL_TYPE_POINTER, andp,
               ICL_TYPE_STRING, aname2);
@@ -66,14 +65,14 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
        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->f.fid.Cell != andp->f.fid.Cell
+       || aodp->f.fid.Fid.Volume != andp->f.fid.Fid.Volume) {
        code = EXDEV;
        goto done;
     }
     oneDir = 0;
     code = 0;
-    if (andp->fid.Fid.Vnode == aodp->fid.Fid.Vnode) {
+    if (andp->f.fid.Fid.Vnode == aodp->f.fid.Fid.Vnode) {
        if (!strcmp(aname1, aname2)) {
            /* Same directory and same name; this is a noop and just return success
             * to save cycles and follow posix standards */
@@ -81,6 +80,12 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
            code = 0;
            goto done;
        }
+       
+       if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
+           code = ENETDOWN;
+           goto done;
+       }
+       
        ObtainWriteLock(&andp->lock, 147);
        tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
        if (!tdc1) {
@@ -90,10 +95,10 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
        }
        tdc2 = tdc1;
        oneDir = 1;             /* only one dude locked */
-    } else if ((andp->states & CRO) || (aodp->states & CRO)) {
+    } else if ((andp->f.states & CRO) || (aodp->f.states & CRO)) {
        code = EROFS;
        goto done;
-    } else if (andp->fid.Fid.Vnode < aodp->fid.Fid.Vnode) {
+    } else if (andp->f.fid.Fid.Vnode < aodp->f.fid.Fid.Vnode) {
        ObtainWriteLock(&andp->lock, 148);      /* lock smaller one first */
        ObtainWriteLock(&aodp->lock, 149);
        tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
@@ -119,16 +124,14 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
 
     osi_dnlc_remove(aodp, aname1, 0);
     osi_dnlc_remove(andp, aname2, 0);
-    afs_symhint_inval(aodp);
-    afs_symhint_inval(andp);
 
     /*
      * Make sure that the data in the cache is current. We may have
      * received a callback while we were waiting for the write lock.
      */
     if (tdc1) {
-       if (!(aodp->states & CStatd)
-           || !hsame(aodp->m.DataVersion, tdc1->f.versionNo)) {
+       if (!(aodp->f.states & CStatd)
+           || !hsame(aodp->f.m.DataVersion, tdc1->f.versionNo)) {
 
            ReleaseWriteLock(&aodp->lock);
            if (!oneDir) {
@@ -145,7 +148,7 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
     }
 
     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) {
            ReleaseWriteLock(&tdc1->lock);
@@ -162,25 +165,74 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
        goto done;
     }
 
-    /* locks are now set, proceed to do the real work */
-    do {
-       tc = afs_Conn(&aodp->fid, areq, SHARED_LOCK);
-       if (tc) {
-           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,
+    if (!AFS_IS_DISCON_RW) {
+       /* Connected. */
+       do {
+           tc = afs_Conn(&aodp->f.fid, areq, SHARED_LOCK);
+           if (tc) {
+               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
+               RX_AFS_GUNLOCK();
+               code =
+                   RXAFS_Rename(tc->id,
+                                       (struct AFSFid *)&aodp->f.fid.Fid,
+                                       aname1,
+                                       (struct AFSFid *)&andp->f.fid.Fid,
+                                       aname2,
+                                       &OutOldDirStatus,
+                                       &OutNewDirStatus,
+                                       &tsync);
+               RX_AFS_GLOCK();
+               XSTATS_END_TIME;
+           } else
+               code = -1;
+
+       } while (afs_Analyze
+            (tc, code, &andp->f.fid, areq, AFS_STATS_FS_RPCIDX_RENAME,
              SHARED_LOCK, NULL));
 
+    } else {
+       /* Disconnected. */
+
+       /* Seek moved file vcache. */
+       fileFid.Cell = aodp->f.fid.Cell;
+       fileFid.Fid.Volume = aodp->f.fid.Fid.Volume;
+       ObtainSharedLock(&afs_xvcache, 754);
+       tvc = afs_FindVCache(&fileFid, 0 , 1);
+       ReleaseSharedLock(&afs_xvcache);
+
+       if (tvc) {
+           /* XXX - We're locking this vcache whilst holding dcaches. Ooops */
+           ObtainWriteLock(&tvc->lock, 750);
+           if (!(tvc->f.ddirty_flags & (VDisconRename|VDisconCreate))) {
+               /* If the vnode was created locally, then we don't care
+                * about recording the rename - we'll do it automatically
+                * on replay. If we've already renamed, we've already stored
+                * the required information about where we came from.
+                */
+               
+               if (!aodp->f.shadow.vnode) {
+                   /* Make shadow copy of parent dir only. */
+                   afs_MakeShadowDir(aodp, tdc1);
+               }
+
+               /* Save old parent dir fid so it will be searchable
+                * in the shadow dir.
+                */
+               tvc->f.oldParent.vnode = aodp->f.fid.Fid.Vnode;
+               tvc->f.oldParent.unique = aodp->f.fid.Fid.Unique;
+
+               afs_DisconAddDirty(tvc, 
+                                  VDisconRename 
+                                    | (oneDir ? VDisconRenameSameDir:0), 
+                                  1);
+           }
+
+           ReleaseWriteLock(&tvc->lock);
+           afs_PutVCache(tvc);
+       } else {
+           code = ENOENT;
+       }                       /* if (tvc) */
+    }                          /* if !(AFS_IS_DISCON_RW)*/
     returnCode = code;         /* remember for later */
 
     /* Now we try to do things locally.  This is really loathsome code. */
@@ -190,60 +242,74 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
         * in the cache; if it isn't, we won't do the update locally.  */
        /* see if version numbers increased properly */
        doLocally = 1;
-       if (oneDir) {
-           /* number increases by 1 for whole rename operation */
-           if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1)) {
-               doLocally = 0;
-           }
-       } else {
-           /* two separate dirs, each increasing by 1 */
-           if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1))
-               doLocally = 0;
-           if (!afs_LocalHero(andp, tdc2, &OutNewDirStatus, 1))
-               doLocally = 0;
-           if (!doLocally) {
-               if (tdc1) {
-                   ZapDCE(tdc1);
-                   DZap(&tdc1->f.inode);
-               }
-               if (tdc2) {
-                   ZapDCE(tdc2);
-                   DZap(&tdc2->f.inode);
-               }
+       if (!AFS_IS_DISCON_RW) {
+           if (oneDir) {
+               /* number increases by 1 for whole rename operation */
+               if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1)) {
+                   doLocally = 0;
+               }
+           } else {
+               /* two separate dirs, each increasing by 1 */
+               if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1))
+                   doLocally = 0;
+               if (!afs_LocalHero(andp, tdc2, &OutNewDirStatus, 1))
+                   doLocally = 0;
+               if (!doLocally) {
+                   if (tdc1) {
+                       ZapDCE(tdc1);
+                       DZap(tdc1);
+                   }
+                   if (tdc2) {
+                       ZapDCE(tdc2);
+                       DZap(tdc2);
+                   }
+               }
            }
-       }
+       }                       /* if (!AFS_IS_DISCON_RW) */
+
        /* 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,
+               && 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);
+               ObtainWriteLock(&afs_xdcache, 292);
+               code = afs_dir_Create(tdc2, aname2, &fileFid.Fid);
+               ReleaseWriteLock(&afs_xdcache);
            }
            if (code != 0) {
                ZapDCE(tdc1);
-               DZap(&tdc1->f.inode);
+               DZap(tdc1);
                if (!oneDir) {
                    ZapDCE(tdc2);
-                   DZap(&tdc2->f.inode);
+                   DZap(tdc2);
                }
            }
        }
 
+
        /* update dir link counts */
-       aodp->m.LinkCount = OutOldDirStatus.LinkCount;
-       if (!oneDir)
-           andp->m.LinkCount = OutNewDirStatus.LinkCount;
+       if (AFS_IS_DISCON_RW) {
+           if (!oneDir) {
+               aodp->f.m.LinkCount--;
+               andp->f.m.LinkCount++;
+           }
+           /* If we're in the same directory, link count doesn't change */
+       } else {
+           aodp->f.m.LinkCount = OutOldDirStatus.LinkCount;
+           if (!oneDir)
+               andp->f.m.LinkCount = OutNewDirStatus.LinkCount;
+       }
 
     } else {                   /* operation failed (code != 0) */
        if (code < 0) {
@@ -252,8 +318,8 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
            ObtainWriteLock(&afs_xcbhash, 498);
            afs_DequeueCallback(aodp);
            afs_DequeueCallback(andp);
-           andp->states &= ~CStatd;
-           aodp->states &= ~CStatd;
+           andp->f.states &= ~CStatd;
+           aodp->f.states &= ~CStatd;
            ReleaseWriteLock(&afs_xcbhash);
            osi_dnlc_purgedp(andp);
            osi_dnlc_purgedp(aodp);
@@ -272,8 +338,10 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
     }
 
     ReleaseWriteLock(&aodp->lock);
-    if (!oneDir)
+
+    if (!oneDir) {
        ReleaseWriteLock(&andp->lock);
+    }
 
     if (returnCode) {
        code = returnCode;
@@ -288,8 +356,9 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
      * 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;
+
+       unlinkFid.Fid.Volume = aodp->f.fid.Fid.Volume;
+       unlinkFid.Cell = aodp->f.fid.Cell;
        tvc = NULL;
        if (!unlinkFid.Fid.Unique) {
            tvc = afs_LookupVCache(&unlinkFid, areq, NULL, aodp, aname1);
@@ -298,13 +367,13 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
            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);
-           tvc->m.LinkCount--;
-           tvc->states &= ~CUnique;    /* For the dfs xlator */
-           if (tvc->m.LinkCount == 0 && !osi_Active(tvc)) {
+           tvc->f.m.LinkCount--;
+           tvc->f.states &= ~CUnique;  /* For the dfs xlator */
+           if (tvc->f.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
@@ -317,7 +386,7 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
                    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);
@@ -326,8 +395,8 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
 
     /* now handle ".." invalidation */
     if (!oneDir) {
-       fileFid.Fid.Volume = aodp->fid.Fid.Volume;
-       fileFid.Cell = aodp->fid.Cell;
+       fileFid.Fid.Volume = aodp->f.fid.Fid.Volume;
+       fileFid.Cell = aodp->f.fid.Cell;
        if (!fileFid.Fid.Unique)
            tvc = afs_LookupVCache(&fileFid, areq, NULL, andp, aname2);
        else
@@ -336,15 +405,27 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
            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);
-               ReleaseWriteLock(&tdc1->lock);
-               afs_PutDCache(tdc1);    /* put it back */
+               if (AFS_IS_DISCON_RW) {
+                   /* If disconnected, we need to fix (not discard) the "..".*/
+                   afs_dir_ChangeFid(tdc1,
+                       "..",
+                       &aodp->f.fid.Fid.Vnode,
+                       &andp->f.fid.Fid.Vnode);
+               } else {
+                   ObtainWriteLock(&tdc1->lock, 648);
+                   ZapDCE(tdc1);       /* mark as unknown */
+                   DZap(tdc1);
+                   ReleaseWriteLock(&tdc1->lock);
+                   afs_PutDCache(tdc1);        /* put it back */
+               }
            }
            osi_dnlc_remove(tvc, "..", 0);
            ReleaseWriteLock(&tvc->lock);
            afs_PutVCache(tvc);
+       } else if (AFS_IS_DISCON_RW && tvc && (vType(tvc) == VREG)) {
+           /* XXX - Should tvc not get locked here? */
+           tvc->f.parent.vnode = andp->f.fid.Fid.Vnode;
+           tvc->f.parent.unique = andp->f.fid.Fid.Unique;
        } 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...
@@ -358,39 +439,26 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
 }
 
 int
-#ifdef AFS_OSF_ENV
-afs_rename(fndp, tndp)
-     struct nameidata *fndp, *tndp;
-{
-    struct vcache *aodp = VTOAFS(fndp->ni_dvp);
-    char *aname1 = fndp->ni_dent.d_name;
-    struct vcache *andp = VTOAFS(tndp->ni_dvp);
-    char *aname2 = tndp->ni_dent.d_name;
-    struct ucred *acred = tndp->ni_cred;
-#else /* AFS_OSF_ENV */
 #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, afs_ucred_t *acred)
 #else
-afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
+afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, afs_ucred_t *acred)
 #endif
-    OSI_VC_DECL(aodp);
-     struct vcache *andp;
-     char *aname1, *aname2;
-     struct AFS_UCRED *acred;
 {
-#endif
-    register afs_int32 code;
+    afs_int32 code;
     struct afs_fakestat_state ofakestate;
     struct afs_fakestat_state nfakestate;
     struct vrequest treq;
-    OSI_VC_CONVERT(aodp)
+    OSI_VC_CONVERT(aodp);
 
-       code = afs_InitReq(&treq, acred);
+    code = afs_InitReq(&treq, acred);
     if (code)
        return code;
     afs_InitFakeStat(&ofakestate);
     afs_InitFakeStat(&nfakestate);
+
+    AFS_DISCON_LOCK();
+    
     code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
     if (code)
        goto done;
@@ -401,14 +469,9 @@ afs_rename(OSI_VC_ARG(aodp), aname1, andp, aname2, acred)
   done:
     afs_PutFakeStat(&ofakestate);
     afs_PutFakeStat(&nfakestate);
-#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 */
+
+    AFS_DISCON_UNLOCK();
+    
     code = afs_CheckCode(code, &treq, 25);
     return code;
 }