DEVEL15-disconnected-shadow-directory-fixes-20090121
authorSimon Wilkinson <sxw@inf.ed.ac.uk>
Wed, 21 Jan 2009 21:17:47 +0000 (21:17 +0000)
committerDerrick Brashear <shadow@dementia.org>
Wed, 21 Jan 2009 21:17:47 +0000 (21:17 +0000)
LICENSE IPL10
FIXES 124173

fix bugs in disconnected's directory shadowing

(cherry picked from commit 4045f3d5350955de91e019b09ad2ed7941f6dadb)

src/afs/VNOPS/afs_vnop_dirops.c
src/afs/VNOPS/afs_vnop_remove.c
src/afs/VNOPS/afs_vnop_rename.c
src/afs/afs_dcache.c
src/afs/discon.h

index 2ea01a3..df2be83 100644 (file)
@@ -420,19 +420,11 @@ afs_rmdir(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
        }
 
        /* Make a shadow copy of the parent dir (if not done already).
-        * There's no need to make a shadow copy of the deleted directory
-        * because a dir must be empty in order to be rmdir'ed.
-        * If the deleted dir has no shadow, it means that it was empty.
+        * If we were created locally, then we don't need to have a shadow
+        * directory (as there's no server state to remember)
         */
-       if (!adp->shVnode) {
-           /* If tdc available, then it is locked.
-            * afs_MakeShadowDir unlocks it.
-            */
-           if (tdc)
-               ReleaseSharedLock(&tdc->lock);
-           afs_MakeShadowDir(adp);
-           if (tdc)
-               ObtainSharedLock(&tdc->lock, 732);
+       if (!adp->shVnode && !(adp->ddirty_flags & VDisconCreate)) {
+           afs_MakeShadowDir(adp, tdc);
        }
 
        adp->m.LinkCount--;
index 5b63167..b1c89cd 100644 (file)
@@ -313,11 +313,6 @@ afs_remove(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
     
     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
     ObtainWriteLock(&adp->lock, 142);
-#if defined(AFS_DISCON_ENV)
-    if (AFS_IS_DISCON_RW && !adp->shVnode)
-       /* Make shadow copy of parent dir. */
-       afs_MakeShadowDir(adp);
-#endif
     if (tdc)
        ObtainSharedLock(&tdc->lock, 638);
 
@@ -364,6 +359,11 @@ afs_remove(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
 
 #if defined(AFS_DISCON_ENV)
     if (AFS_IS_DISCON_RW) {
+       if (!adp->shVnode && !(adp->ddirty_flags & VDisconCreate)) {
+           /* Make shadow copy of parent dir. */
+           afs_MakeShadowDir(adp, tdc);
+       }
+
        /* Can't hold a dcache lock whilst we're getting a vcache one */
        if (tdc)
            ReleaseSharedLock(&tdc->lock);
index f71dcc6..f36050f 100644 (file)
@@ -204,6 +204,7 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
        ReleaseSharedLock(&afs_xvcache);
 
        if (tvc) {
+           /* XXX - We're locking this vcache whilst holding dcaches. Ooops */
            ObtainWriteLock(&tvc->lock, 750);
            if (!(tvc->ddirty_flags & (VDisconRename|VDisconCreate))) {
                /* If the vnode was created locally, then we don't care
@@ -214,11 +215,7 @@ afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
                
                if (!aodp->shVnode) {
                    /* Make shadow copy of parent dir only. */
-                   if (tdc1)
-                       ReleaseWriteLock(&tdc1->lock);
-                   afs_MakeShadowDir(aodp);
-                   if (tdc1)
-                       ObtainWriteLock(&tdc1->lock, 753);
+                   afs_MakeShadowDir(aodp, tdc1);
                }
 
                afs_DisconAddDirty(tvc, 
index fc0ea5f..964047f 100644 (file)
@@ -3751,23 +3751,23 @@ afs_ObtainDCacheForWriting(struct vcache *avc, afs_size_t filePos,
 #if defined(AFS_DISCON_ENV)
 
 /*!
- * Make a shadow copy of a dir's dcaches. It's used for disconnected
+ * Make a shadow copy of a dir's dcache. It's used for disconnected
  * operations like remove/create/rename to keep the original directory data.
  * On reconnection, we can diff the original data with the server and get the
  * server changes and with the local data to get the local changes.
  *
  * \param avc The dir vnode.
+ * \param adc The dir dcache.
  *
  * \return 0 for success.
  *
- * \note The only lock allowed to be set is the dir's vcache entry, and it
- * must be set in write mode.
  * \note The vcache entry must be write locked.
+ * \note The dcache entry must be read locked.
  */
-int afs_MakeShadowDir(struct vcache *avc)
+int afs_MakeShadowDir(struct vcache *avc, struct dcache *adc)
 {
-    int j, i, index, code, ret_code = 0, offset, trans_size, block;
-    struct dcache *tdc, *new_dc = NULL;
+    int i, code, ret_code = 0, written, trans_size;
+    struct dcache *new_dc = NULL;
     struct osi_file *tfile_src, *tfile_dst;
     struct VenusFid shadow_fid;
     char *data;
@@ -3785,126 +3785,81 @@ int afs_MakeShadowDir(struct vcache *avc)
     shadow_fid.Fid.Volume = avc->fid.Fid.Volume;
     afs_GenShadowFid(&shadow_fid);
 
-    /* For each dcache, copy it into a new fresh one. */
     ObtainWriteLock(&afs_xdcache, 716);
-    i = DVHash(&avc->fid);
-    for (index = afs_dvhashTbl[i]; index != NULLIDX; index = i) {
-        i = afs_dvnextTbl[index];
-        if (afs_indexUnique[index] == avc->fid.Fid.Unique) {
-            tdc = afs_GetDSlot(index, NULL);
-
-           ReleaseReadLock(&tdc->tlock);
-
-           if (!FidCmp(&tdc->f.fid, &avc->fid)) {
-               /* Get a fresh dcache. */
-               new_dc = afs_AllocDCache(avc, 0, 0, &shadow_fid);
 
-               /* XXX - The lock ordering here is broken. We can't lock
-                * tdc whilst we're holding xdcache, and we can't free 
-                * xdcache without having to start again on the hash chain
-                * we're currently on
-                */
-               ObtainReadLock(&tdc->lock);
-
-               ObtainReadLock(&tdc->mflock);
-
-               /* Set up the new fid. */
-               /* Copy interesting data from original dir dcache. */
-               new_dc->mflags = tdc->mflags; /* tdc->mflock */
-               new_dc->dflags = tdc->dflags; /* tdc->lock */
-               new_dc->f.modTime = tdc->f.modTime; /* tdc->lock */
-               new_dc->f.versionNo = tdc->f.versionNo; /* tdc->lock */
-               new_dc->f.states = tdc->f.states; /* tdc->lock */
-               new_dc->f.chunk= tdc->f.chunk; /* tdc->lock */
-               new_dc->f.chunkBytes = tdc->f.chunkBytes; /* tdc->lock */
+    /* Get a fresh dcache. */
+    new_dc = afs_AllocDCache(avc, 0, 0, &shadow_fid);
 
-               ReleaseReadLock(&tdc->mflock);
-               /*
-                * Now add to the two hash chains - note that i is still set
-                * from the above DCHash call.
-                */
+    ObtainReadLock(&adc->mflock);
 
-               j = DCHash(&shadow_fid, 0);
-               afs_dcnextTbl[new_dc->index] = afs_dchashTbl[j];
-               afs_dchashTbl[j] = new_dc->index;
+    /* Set up the new fid. */
+    /* Copy interesting data from original dir dcache. */
+    new_dc->mflags = adc->mflags;
+    new_dc->dflags = adc->dflags;
+    new_dc->f.modTime = adc->f.modTime;
+    new_dc->f.versionNo = adc->f.versionNo;
+    new_dc->f.states = adc->f.states;
+    new_dc->f.chunk= adc->f.chunk;
+    new_dc->f.chunkBytes = adc->f.chunkBytes;
 
-               j = DVHash(&shadow_fid);
-               afs_dvnextTbl[new_dc->index] = afs_dvhashTbl[j];
-               afs_dvhashTbl[j] = new_dc->index;
-               afs_MaybeWakeupTruncateDaemon();
-
-               ReleaseWriteLock(&afs_xdcache);
-
-               /* Make sure and flush dir buffers back into the disk cache */
-               DFlushDCache(tdc);
+    ReleaseReadLock(&adc->mflock);
+    
+    /* Now add to the two hash chains */
+    i = DCHash(&shadow_fid, 0);
+    afs_dcnextTbl[new_dc->index] = afs_dchashTbl[i];
+    afs_dchashTbl[i] = new_dc->index;
 
-               /* Alloc a 4k block. */
-               data = (char *) afs_osi_Alloc(4096);
-               if (!data) {
-                   printf("afs_MakeShadowDir: could not alloc data\n");
-                   ret_code = ENOMEM;
-                   goto done;
-               }
+    i = DVHash(&shadow_fid);
+    afs_dvnextTbl[new_dc->index] = afs_dvhashTbl[i];
+    afs_dvhashTbl[i] = new_dc->index;
 
-               /* Open the files. */
-               tfile_src = afs_CFileOpen(tdc->f.inode);
-               tfile_dst = afs_CFileOpen(new_dc->f.inode);
+    ReleaseWriteLock(&afs_xdcache);
 
-               /* Init no of blocks to be read and offset. */
-               block = (tdc->f.chunkBytes / 4096);
-               offset = 0;
+    /* Alloc a 4k block. */
+    data = (char *) afs_osi_Alloc(4096);
+    if (!data) {
+       printf("afs_MakeShadowDir: could not alloc data\n");
+       ret_code = ENOMEM;
+       goto done;
+    }
 
-               /* And now copy dir dcache data into this dcache,
-                * 4k at a time.
-                */
-               while (block >= 0) {
-
-                   /* Last chunk might have less bytes to transfer. */
-                   if (!block) {
-                       /* Last block. */
-                       trans_size = (tdc->f.chunkBytes % 4096);
-                       if (!trans_size)
-                           /* An exact no of 4k blocks. */
-                           break;
-                   } else
-                       trans_size = 4096;
-
-                   /* Read a chunk from the dcache. */
-                   code = afs_CFileRead(tfile_src, offset, data, trans_size);
-                   if (code < trans_size) {
-                       /* Can't access file, stop doing stuff and return error. */
-                       ret_code = EIO;
-                       break;
-                   }
+    /* Open the files. */
+    tfile_src = afs_CFileOpen(adc->f.inode);
+    tfile_dst = afs_CFileOpen(new_dc->f.inode);
 
-                   /* Write it to the new dcache. */
-                   code = afs_CFileWrite(tfile_dst, offset, data, trans_size);
-                   if (code < trans_size) {
-                       ret_code = EIO;
-                       break;
-                   }
+    /* And now copy dir dcache data into this dcache,
+     * 4k at a time.
+     */
+    written = 0;
+    while (written < adc->f.chunkBytes) {
+       trans_size = adc->f.chunkBytes - written;
+       if (trans_size > 4096)
+           trans_size = 4096;
+
+       /* Read a chunk from the dcache. */
+       code = afs_CFileRead(tfile_src, written, data, trans_size);
+       if (code < trans_size) {
+           ret_code = EIO;
+           break;
+       }
 
-                   block--;
-                   offset += 4096;
-               }               /* while (block) */
+       /* Write it to the new dcache. */
+       code = afs_CFileWrite(tfile_dst, written, data, trans_size);
+       if (code < trans_size) {
+           ret_code = EIO;
+           break;
+       }
 
-               afs_CFileClose(tfile_dst);
-               afs_CFileClose(tfile_src);
+       written+=trans_size;
+    }
 
-               afs_osi_Free(data, 4096);
+    afs_CFileClose(tfile_dst);
+    afs_CFileClose(tfile_src);
 
-               ReleaseWriteLock(&new_dc->lock);
-               ReleaseReadLock(&tdc->lock);
+    afs_osi_Free(data, 4096);
 
-               afs_PutDCache(new_dc);
-               ObtainWriteLock(&afs_xdcache, 720);
-               
-           }                   /* if dcache fid match */
-            afs_PutDCache(tdc);
-        }                      /* if unuiquifier match */
-    }
-done:
-    ReleaseWriteLock(&afs_xdcache);
+    ReleaseWriteLock(&new_dc->lock);
+    afs_PutDCache(new_dc);
 
     if (!ret_code) {
        ObtainWriteLock(&afs_xvcache, 763);
@@ -3918,6 +3873,7 @@ done:
        avc->shUnique = shadow_fid.Fid.Unique;
     }
 
+done:
     return ret_code;
 }
 
index 497291b..4190160 100644 (file)
@@ -43,7 +43,7 @@ extern void afs_GenDisconStatus(struct vcache *adp,
                                        struct vattr *attrs,
                                        struct vrequest *areq,
                                        int file_type);
-extern int afs_MakeShadowDir(struct vcache *avc);
+extern int afs_MakeShadowDir(struct vcache *avc, struct dcache *adc);
 extern void afs_DeleteShadowDir(struct vcache *avc);
 extern struct dcache *afs_FindDCacheByFid(struct VenusFid *afid);
 extern void afs_UpdateStatus(struct vcache *avc,