From: Simon Wilkinson Date: Wed, 21 Jan 2009 21:17:09 +0000 (+0000) Subject: disconnected-shadow-directory-fixes-20090121 X-Git-Tag: openafs-devel-1_5_61~592 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=4045f3d5350955de91e019b09ad2ed7941f6dadb;p=packages%2Fo%2Fopenafs.git disconnected-shadow-directory-fixes-20090121 LICENSE IPL10 FIXES 124173 fix bugs in disconnected's directory shadowing --- diff --git a/src/afs/VNOPS/afs_vnop_dirops.c b/src/afs/VNOPS/afs_vnop_dirops.c index 2ea01a36e..df2be83eb 100644 --- a/src/afs/VNOPS/afs_vnop_dirops.c +++ b/src/afs/VNOPS/afs_vnop_dirops.c @@ -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--; diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index 5b63167b4..b1c89cd5c 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -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); diff --git a/src/afs/VNOPS/afs_vnop_rename.c b/src/afs/VNOPS/afs_vnop_rename.c index f71dcc6d5..f36050f12 100644 --- a/src/afs/VNOPS/afs_vnop_rename.c +++ b/src/afs/VNOPS/afs_vnop_rename.c @@ -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, diff --git a/src/afs/afs_dcache.c b/src/afs/afs_dcache.c index c1984cbbd..eef6fa612 100644 --- a/src/afs/afs_dcache.c +++ b/src/afs/afs_dcache.c @@ -3729,23 +3729,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; @@ -3763,126 +3763,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); @@ -3896,6 +3851,7 @@ done: avc->shUnique = shadow_fid.Fid.Unique; } +done: return ret_code; } diff --git a/src/afs/discon.h b/src/afs/discon.h index 497291b33..4190160a1 100644 --- a/src/afs/discon.h +++ b/src/afs/discon.h @@ -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,