From 3479a425923271fc0cda55d85bd08a821aa1b6ed Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Sun, 25 Jan 2009 14:52:49 +0000 Subject: [PATCH] DEVEL15-disconnected-symlink-support-20090125 LICENSE IPL10 FIXES 124177 allow creation of symlinks while disconnected (cherry picked from commit d2960e5442bb7a7f4730d2a918d8cfb5a409d05c) --- src/afs/VNOPS/afs_vnop_create.c | 2 +- src/afs/VNOPS/afs_vnop_dirops.c | 6 +- src/afs/VNOPS/afs_vnop_symlink.c | 124 ++++++++---- src/afs/afs_disconnected.c | 338 +++++++++++++++++++------------ src/afs/discon.h | 8 +- 5 files changed, 299 insertions(+), 179 deletions(-) diff --git a/src/afs/VNOPS/afs_vnop_create.c b/src/afs/VNOPS/afs_vnop_create.c index 88e965654..d8d46eed4 100644 --- a/src/afs/VNOPS/afs_vnop_create.c +++ b/src/afs/VNOPS/afs_vnop_create.c @@ -372,7 +372,7 @@ afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, /* Generate a fake FID for disconnected mode. */ newFid.Cell = adp->fid.Cell; newFid.Fid.Volume = adp->fid.Fid.Volume; - afs_GenFakeFid(&newFid, VREG); + afs_GenFakeFid(&newFid, VREG, 1); #endif } /* if (!AFS_IS_DISCON_RW) */ diff --git a/src/afs/VNOPS/afs_vnop_dirops.c b/src/afs/VNOPS/afs_vnop_dirops.c index ae721c339..58fe67626 100644 --- a/src/afs/VNOPS/afs_vnop_dirops.c +++ b/src/afs/VNOPS/afs_vnop_dirops.c @@ -91,9 +91,11 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, goto done; } - if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) + if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) { /*printf("Network is down in afs_mkdir\n");*/ code = ENETDOWN; + goto done; + } InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP; InStatus.ClientModTime = osi_Time(); InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */ @@ -151,7 +153,7 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, /* If not mount point, generate a new fid. */ newFid.Cell = adp->fid.Cell; newFid.Fid.Volume = adp->fid.Fid.Volume; - afs_GenFakeFid(&newFid, VDIR); + afs_GenFakeFid(&newFid, VDIR, 1); } /* XXX: If mount point???*/ diff --git a/src/afs/VNOPS/afs_vnop_symlink.c b/src/afs/VNOPS/afs_vnop_symlink.c index f30671548..0e331bb9d 100644 --- a/src/afs/VNOPS/afs_vnop_symlink.c +++ b/src/afs/VNOPS/afs_vnop_symlink.c @@ -39,6 +39,33 @@ extern afs_rwlock_t afs_xcbhash; * is just a performance hit. */ +#ifdef AFS_DISCON_ENV +static int +afs_DisconCreateSymlink(struct vcache *avc, char *aname, + struct vrequest *areq) { + struct dcache *tdc; + struct osi_file *tfile; + afs_size_t offset, len; + + tdc = afs_GetDCache(avc, 0, areq, &offset, &len, 0); + if (!tdc) { + printf("afs_DisconCreateSymlink: can't get new dcache for symlink.\n"); + return ENOENT; + } + + len = strlen(aname); + avc->m.Length = len; + + ObtainWriteLock(&tdc->lock, 720); + afs_AdjustSize(tdc, len); + tdc->validPos = len; + tfile = afs_CFileOpen(tdc->f.inode); + afs_CFileWrite(tfile, 0, aname, len); + afs_CFileClose(tfile); + ReleaseWriteLock(&tdc->lock); + return 0; +} +#endif /* don't set CDirty in here because RPC is called synchronously */ int @@ -47,7 +74,7 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, { afs_uint32 now = 0; struct vrequest treq; - afs_int32 code; + afs_int32 code = 0; struct afs_conn *tc; struct VenusFid newFid; struct dcache *tdc; @@ -107,7 +134,7 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, goto done; } - if (AFS_IS_DISCONNECTED) { + if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) { code = ENETDOWN; goto done; } @@ -130,36 +157,45 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, ObtainWriteLock(&tdc->lock, 636); ObtainSharedLock(&afs_xvcache, 17); /* prevent others from creating this entry */ /* XXX Pay attention to afs_xvcache around the whole thing!! XXX */ - do { - tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK); - if (tc) { - hostp = tc->srvr->server; - XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SYMLINK); - if (adp->states & CForeign) { - now = osi_Time(); - RX_AFS_GUNLOCK(); - code = - RXAFS_DFSSymlink(tc->id, (struct AFSFid *)&adp->fid.Fid, - aname, atargetName, &InStatus, - (struct AFSFid *)&newFid.Fid, - &OutFidStatus, &OutDirStatus, &CallBack, - &tsync); - RX_AFS_GLOCK(); - } else { - RX_AFS_GUNLOCK(); - code = - RXAFS_Symlink(tc->id, (struct AFSFid *)&adp->fid.Fid, - aname, atargetName, &InStatus, - (struct AFSFid *)&newFid.Fid, &OutFidStatus, - &OutDirStatus, &tsync); - RX_AFS_GLOCK(); - } - XSTATS_END_TIME; - } else - code = -1; - } while (afs_Analyze - (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_SYMLINK, - SHARED_LOCK, NULL)); + if (!AFS_IS_DISCON_RW) { + do { + tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK); + if (tc) { + hostp = tc->srvr->server; + XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SYMLINK); + if (adp->states & CForeign) { + now = osi_Time(); + RX_AFS_GUNLOCK(); + code = + RXAFS_DFSSymlink(tc->id, + (struct AFSFid *)&adp->fid.Fid, + aname, atargetName, &InStatus, + (struct AFSFid *)&newFid.Fid, + &OutFidStatus, &OutDirStatus, + &CallBack, &tsync); + RX_AFS_GLOCK(); + } else { + RX_AFS_GUNLOCK(); + code = + RXAFS_Symlink(tc->id, (struct AFSFid *)&adp->fid.Fid, + aname, atargetName, &InStatus, + (struct AFSFid *)&newFid.Fid, + &OutFidStatus, &OutDirStatus, &tsync); + RX_AFS_GLOCK(); + } + XSTATS_END_TIME; + } else + code = -1; + } while (afs_Analyze + (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_SYMLINK, + SHARED_LOCK, NULL)); + } else { +#ifdef AFS_DISCON_ENV + newFid.Cell = adp->fid.Cell; + newFid.Fid.Volume = adp->fid.Fid.Volume; + afs_GenFakeFid(&newFid, VREG, 0); +#endif + } UpgradeSToWLock(&afs_xvcache, 40); if (code) { @@ -179,12 +215,12 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, goto done; } /* otherwise, we should see if we can make the change to the dir locally */ - if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) { + if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) { /* we can do it locally */ ObtainWriteLock(&afs_xdcache, 293); code = afs_dir_Create(tdc, aname, &newFid.Fid); ReleaseWriteLock(&afs_xdcache); - if (code) { + if (code && !AFS_IS_DISCON_RW) { ZapDCE(tdc); /* surprise error -- use invalid value */ DZap(tdc); } @@ -224,7 +260,25 @@ afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, /* since it never expires, we don't have to queue the callback */ } ReleaseWriteLock(&afs_xcbhash); - afs_ProcessFS(tvc, &OutFidStatus, &treq); + + if (AFS_IS_DISCON_RW) { +#ifdef AFS_DISCON_ENV + attrs->va_mode = InStatus.UnixModeBits; + afs_GenDisconStatus(adp, tvc, &newFid, attrs, &treq, VLNK); + code = afs_DisconCreateSymlink(tvc, atargetName, &treq); + if (code) { + /* XXX - When this goes wrong, we need to tidy up the changes we made to + * the parent, and get rid of the vcache we just created */ + ReleaseWriteLock(&tvc->lock); + ReleaseWriteLock(&afs_xvcache); + afs_PutVCache(tvc); + goto done; + } + afs_DisconAddDirty(tvc, VDisconCreate, 0); +#endif + } else { + afs_ProcessFS(tvc, &OutFidStatus, &treq); + } if (!tvc->linkData) { tvc->linkData = (char *)afs_osi_Alloc(alen); diff --git a/src/afs/afs_disconnected.c b/src/afs/afs_disconnected.c index 9a6bf6d0f..72a0080a5 100644 --- a/src/afs/afs_disconnected.c +++ b/src/afs/afs_disconnected.c @@ -53,6 +53,8 @@ afs_int32 afs_ConflictPolicy = SERVER_WINS; static void afs_DisconResetVCache(struct vcache *, struct AFS_UCRED *); static void afs_DisconDiscardAllShadows(int, struct AFS_UCRED *); +void afs_DbgListDirEntries(struct VenusFid *afid); + /*! * Find the first dcache of a file that has the specified fid. @@ -161,21 +163,31 @@ int afs_GetParentDirFid(struct vcache *avc, struct VenusFid *afid) afid->Cell = avc->fid.Cell; afid->Fid.Volume = avc->fid.Fid.Volume; - if (vType(avc) == VREG) { + switch (vType(avc)) { + case VREG: + case VLNK: /* Normal files have the dir fid embedded in the vcache. */ afid->Fid.Vnode = avc->parentVnode; afid->Fid.Unique = avc->parentUnique; - - } else if (vType(avc) == VDIR) { + break; + case VDIR: /* If dir or parent dir created locally*/ tdc = afs_FindDCacheByFid(&avc->fid); if (tdc) { + afid->Fid.Unique = 0; /* Lookup each entry for the fid. It should be the first. */ afs_dir_EnumerateDir(tdc, &get_parent_dir_fid_hook, afid); afs_PutDCache(tdc); + if (afid->Fid.Unique == 0) { + return -1; + } } else { return -1; } + break; + default: + return -1; + break; } return 0; @@ -283,6 +295,7 @@ int afs_GetVnodeName(struct vcache *avc, if (tnf.name_len == -1) code = ENOENT; } else { + printf("Directory dcache not found!\n"); code = ENOENT; } @@ -472,6 +485,60 @@ void afs_DbgListDirEntries(struct VenusFid *afid) } } +/*! + * Find the parent vcache for a given child + * + * \param avc The vcache whose parent is required + * \param afid Fid structure in which parent's fid should be stored + * \param aname An AFSNAMEMAX sized buffer to hold the parents name + * \param adp A pointer to a struct vcache* which will be set to the + * parent vcache + * + * \return An error code. 0 indicates success, EAGAIN that the vnode should + * be deferred to later in the resync process + */ + +int +afs_GetParentVCache(struct vcache *avc, int deleted, struct VenusFid *afid, + char *aname, struct vcache **adp) +{ + int code; + + *adp = NULL; + + if (afs_GetParentDirFid(avc, afid)) { + printf("afs_GetParentVCache: Couldn't find parent dir's FID.\n"); + return ENOENT; + } + + code = afs_GetVnodeName(avc, afid, aname, deleted); + if (code) { + printf("afs_GetParentVCache: Couldn't find file name\n"); + goto end; + } + + ObtainSharedLock(&afs_xvcache, 766); + *adp = afs_FindVCache(afid, 0, 1); + ReleaseSharedLock(&afs_xvcache); + if (!*adp) { + printf("afs_GetParentVCache: Couldn't find parent dir's vcache\n"); + code = ENOENT; + goto end; + } + + if ((*adp)->ddirty_flags & VDisconCreate) { + printf("afs_GetParentVCache: deferring until parent exists\n"); + code = EAGAIN; + goto end; + } + +end: + if (code && *adp) + afs_PutVCache(*adp); + return code; +} + + /*! * Handles file renaming on reconnection: * - Get the old name from the old dir's shadow dir. @@ -521,9 +588,7 @@ int afs_ProcessOpRename(struct vcache *avc, struct vrequest *areq) memcpy(&new_pdir_fid, &old_pdir_fid, sizeof(struct VenusFid)); } else { /* Get parent dir's FID.*/ - new_pdir_fid.Fid.Unique = 0; - afs_GetParentDirFid(avc, &new_pdir_fid); - if (!new_pdir_fid.Fid.Unique) { + if (afs_GetParentDirFid(avc, &new_pdir_fid)) { printf("afs_ProcessOpRename: Couldn't find new parent dir FID.\n"); code = ENOENT; goto done; @@ -581,63 +646,68 @@ done: * - Handle errors. * - Reorder vhash and dcaches in their hashes, using the newly acquired fid. */ -int afs_ProcessOpCreate(struct vcache *avc, - struct vrequest *areq, - struct AFS_UCRED *acred) +int afs_ProcessOpCreate(struct vcache *avc, struct vrequest *areq, + struct AFS_UCRED *acred) { - char *tname = NULL; + char *tname = NULL, *ttargetName = NULL; struct AFSStoreStatus InStatus; struct AFSFetchStatus OutFidStatus, OutDirStatus; struct VenusFid pdir_fid, newFid; - struct server *hostp = NULL; struct AFSCallBack CallBack; struct AFSVolSync tsync; struct vcache *tdp = NULL, *tvc = NULL; struct dcache *tdc = NULL; struct afs_conn *tc; - afs_int32 now, hash, new_hash, index; - int code = 0; + afs_int32 hash, new_hash, index; + afs_size_t tlen; + int code, op; XSTATS_DECLS; - /* Get parent dir's FID. */ - pdir_fid.Fid.Unique = 0; - afs_GetParentDirFid(avc, &pdir_fid); - if (!pdir_fid.Fid.Unique) { - printf("afs_ProcessOpCreate: Couldn't find parent dir's FID.\n"); - return ENOENT; - } - tname = afs_osi_Alloc(AFSNAMEMAX); - if (!tname) { - printf("afs_ProcessOpCreate: Couldn't alloc space for file name\n"); + if (!tname) return ENOMEM; - } - /* Get vnode's name. */ - code = afs_GetVnodeName(avc, &pdir_fid, tname, 0); - if (code) { - printf("afs_ProcessOpCreate: Couldn't find file name\n"); + code = afs_GetParentVCache(avc, 0, &pdir_fid, tname, &tdp); + if (code) goto end; - } - /* Get parent dir vcache. */ - ObtainSharedLock(&afs_xvcache, 760); - tdp = afs_FindVCache(&pdir_fid, 0, 1); - ReleaseSharedLock(&afs_xvcache); - if (!tdp) { - printf("afs_ProcessOpCreate: Couldn't find parent dir's vcache\n"); - code = ENOENT; - goto end; - } + /* This data may also be in linkData, but then we have to deal with + * the joy of terminating NULLs and . and file modes. So just get + * it from the dcache where it won't have been fiddled with. + */ + if (vType(avc) == VLNK) { + afs_size_t offset; + struct dcache *tdc; + struct osi_file *tfile; - if (tdp->ddirty_flags & VDisconCreate) { - /* If the parent dir has been created locally, defer - * this vnode for later */ - printf("afs_ProcessOpCreate: deferring this vcache\n"); - code = EAGAIN; - goto end; - } + tdc = afs_GetDCache(avc, 0, areq, &offset, &tlen, 0); + if (!tdc) { + code = ENOENT; + goto end; + } + if (tlen > 1024) { + afs_PutDCache(tdc); + code = EFAULT; + goto end; + } + + tlen++; /* space for NULL */ + ttargetName = afs_osi_Alloc(tlen); + if (!ttargetName) { + afs_PutDCache(tdc); + return ENOMEM; + } + ObtainReadLock(&tdc->lock); + tfile = afs_CFileOpen(&tdc->f.inode); + code = afs_CFileRead(tfile, 0, ttargetName, tlen); + ttargetName[tlen-1] = '\0'; + afs_CFileClose(tfile); + ReleaseReadLock(&tdc->lock); + afs_PutDCache(tdc); + printf("Read target name as %s\n",ttargetName); + } + /* Set status. */ InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP; InStatus.ClientModTime = avc->m.Date; @@ -646,70 +716,58 @@ int afs_ProcessOpCreate(struct vcache *avc, /* Only care about protection bits. */ InStatus.UnixModeBits = avc->m.Mode & 0xffff; - /* Connect to server. */ - if (vType(avc) == VREG) { - /* Make file on server. */ - do { - tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK); - if (tc) { - /* Remember for callback processing. */ - hostp = tc->srvr->server; - now = osi_Time(); - XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE); + do { + tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK); + if (tc) { + switch (vType(avc)) { + case VREG: + /* Make file on server. */ + op = AFS_STATS_FS_RPCIDX_CREATEFILE; + XSTATS_START_TIME(op); RX_AFS_GUNLOCK(); code = RXAFS_CreateFile(tc->id, - (struct AFSFid *)&tdp->fid.Fid, - tname, - &InStatus, - (struct AFSFid *) &newFid.Fid, - &OutFidStatus, - &OutDirStatus, - &CallBack, - &tsync); + (struct AFSFid *)&tdp->fid.Fid, + tname, &InStatus, + (struct AFSFid *) &newFid.Fid, + &OutFidStatus, &OutDirStatus, + &CallBack, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; - CallBack.ExpirationTime += now; - } else - code = -1; - } while (afs_Analyze(tc, - code, - &tdp->fid, - areq, - AFS_STATS_FS_RPCIDX_CREATEFILE, - SHARED_LOCK, - NULL)); - - } else if (vType(avc) == VDIR) { - /* Make dir on server. */ - do { - tc = afs_Conn(&tdp->fid, areq, SHARED_LOCK); - if (tc) { - XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR); - now = osi_Time(); + break; + case VDIR: + /* Make dir on server. */ + op = AFS_STATS_FS_RPCIDX_MAKEDIR; + XSTATS_START_TIME(op); RX_AFS_GUNLOCK(); - code = RXAFS_MakeDir(tc->id, - (struct AFSFid *) &tdp->fid.Fid, - tname, - &InStatus, - (struct AFSFid *) &newFid.Fid, - &OutFidStatus, - &OutDirStatus, - &CallBack, - &tsync); + code = RXAFS_MakeDir(tc->id, (struct AFSFid *) &tdp->fid.Fid, + tname, &InStatus, + (struct AFSFid *) &newFid.Fid, + &OutFidStatus, &OutDirStatus, + &CallBack, &tsync); RX_AFS_GLOCK(); XSTATS_END_TIME; - CallBack.ExpirationTime += now; - /* DON'T forget to set the callback at some point. */ - } else - code = -1; - } while (afs_Analyze(tc, - code, - &tdp->fid, - areq, - AFS_STATS_FS_RPCIDX_MAKEDIR, - SHARED_LOCK, - NULL)); - } /* Do server changes. */ + break; + case VLNK: + /* Make symlink on server. */ + op = AFS_STATS_FS_RPCIDX_SYMLINK; + XSTATS_START_TIME(op); + RX_AFS_GUNLOCK(); + code = RXAFS_Symlink(tc->id, + (struct AFSFid *) &tdp->fid.Fid, + tname, ttargetName, &InStatus, + (struct AFSFid *) &newFid.Fid, + &OutFidStatus, &OutDirStatus, &tsync); + RX_AFS_GLOCK(); + XSTATS_END_TIME; + break; + default: + op = AFS_STATS_FS_RPCIDX_CREATEFILE; + code = 1; + break; + } + } else + code = -1; + } while (afs_Analyze(tc, code, &tdp->fid, areq, op, SHARED_LOCK, NULL)); /* TODO: Handle errors. */ if (code) { @@ -825,6 +883,8 @@ end: if (tdp) afs_PutVCache(tdp); afs_osi_Free(tname, AFSNAMEMAX); + if (ttargetName) + afs_osi_Free(ttargetName, tlen); return code; } @@ -853,26 +913,15 @@ int afs_ProcessOpRemove(struct vcache *avc, struct vrequest *areq) int code = 0; XSTATS_DECLS; - /* Get parent dir's FID. */ - pdir_fid.Fid.Unique = 0; - afs_GetParentDirFid(avc, &pdir_fid); - if (!pdir_fid.Fid.Unique) { - printf("afs_ProcessOpRemove: Couldn't find parent dir's FID.\n"); - return ENOENT; - } - tname = afs_osi_Alloc(AFSNAMEMAX); if (!tname) { printf("afs_ProcessOpRemove: Couldn't alloc space for file name\n"); return ENOMEM; } - /* Get file name. */ - code = afs_GetVnodeName(avc, &pdir_fid, tname, 1); - if (code) { - printf("afs_ProcessOpRemove: Couldn't find file name\n"); + code = afs_GetParentVCache(avc, 1, &pdir_fid, tname, &tdp); + if (code) goto end; - } if ((vType(avc) == VDIR) && (afs_CheckDeletedChildren(avc))) { /* Deleted children of this dir remain unsynchronized. @@ -882,7 +931,7 @@ int afs_ProcessOpRemove(struct vcache *avc, struct vrequest *areq) goto end; } - if (vType(avc) == VREG) { + if (vType(avc) == VREG || vType(avc) == VLNK) { /* Remove file on server. */ do { tc = afs_Conn(&pdir_fid, areq, SHARED_LOCK); @@ -1050,7 +1099,7 @@ int afs_SendChanges(struct vcache *avc, struct vrequest *areq) int afs_ResyncDisconFiles(struct vrequest *areq, struct AFS_UCRED *acred) { struct afs_conn *tc; - struct vcache *tvc, *tmp; + struct vcache *tvc; struct AFSFetchStatus fstat; struct AFSCallBack callback; struct AFSVolSync tsync; @@ -1380,28 +1429,37 @@ void afs_GenShadowFid(struct VenusFid *afid) * afs_DisconVNode and the uniquifier by getting the highest * uniquifier on a hash chain and incrementing it by one. * - * \param avc afid The fid structre that will be filled. + * \param afid The fid structre that will be filled. * \param avtype Vnode type: VDIR/VREG. + * \param lock True indicates that xvcache may be obtained, + * False that it is already held * * \note The cell number must be completed somewhere else. */ -void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype) +void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype, int lock) { struct vcache *tvc; - afs_uint32 max_unique = 1, i; + afs_uint32 max_unique = 0, i; - if (avtype == VDIR) + switch (avtype) { + case VDIR: afid->Fid.Vnode = afs_DisconVnode + 1; - else if (avtype == VREG) + break; + case VREG: + case VLNK: afid->Fid.Vnode = afs_DisconVnode; + break; + } - ObtainWriteLock(&afs_xvcache, 736); + if (lock) + ObtainWriteLock(&afs_xvcache, 736); i = VCHash(afid); for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { if (tvc->fid.Fid.Unique > max_unique) max_unique = tvc->fid.Fid.Unique; } - ReleaseWriteLock(&afs_xvcache); + if (lock) + ReleaseWriteLock(&afs_xvcache); afid->Fid.Unique = max_unique + 1; afs_DisconVnode += 2; @@ -1421,13 +1479,9 @@ void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype) * * \note Call with avc write locked. */ -void afs_GenDisconStatus( - struct vcache *adp, - struct vcache *avc, - struct VenusFid *afid, - struct vattr *attrs, - struct vrequest *areq, - int file_type) +void afs_GenDisconStatus(struct vcache *adp, struct vcache *avc, + struct VenusFid *afid, struct vattr *attrs, + struct vrequest *areq, int file_type) { memcpy(&avc->fid, afid, sizeof(struct VenusFid)); avc->m.Mode = attrs->va_mode; @@ -1442,16 +1496,30 @@ void afs_GenDisconStatus( hset64(avc->m.DataVersion, 0, 0); avc->m.Length = attrs->va_size; avc->m.Date = osi_Time(); - if (file_type == VREG) { - vSetType(avc, VREG); + switch(file_type) { + case VREG: + vSetType(avc, VREG); avc->m.Mode |= S_IFREG; avc->m.LinkCount = 1; - } else if (file_type == VDIR) { + avc->parentVnode = adp->fid.Fid.Vnode; + avc->parentUnique = adp->fid.Fid.Unique; + break; + case VDIR: vSetType(avc, VDIR); avc->m.Mode |= S_IFDIR; avc->m.LinkCount = 2; + break; + case VLNK: + vSetType(avc, VLNK); + avc->m.Mode |= S_IFLNK; + if ((avc->m.Mode & 0111) == 0) + avc->mvstat = 1; + avc->parentVnode = adp->fid.Fid.Vnode; + avc->parentUnique = adp->fid.Fid.Unique; + break; + default: + break; } - avc->anyAccess = adp->anyAccess; afs_AddAxs(avc->Access, areq->uid, adp->Access->axess); diff --git a/src/afs/discon.h b/src/afs/discon.h index 0010179e9..b659eda2c 100644 --- a/src/afs/discon.h +++ b/src/afs/discon.h @@ -28,18 +28,14 @@ extern afs_int32 afs_ConflictPolicy; extern afs_uint32 afs_DisconVnode; /* XXX: not protected. */ -/* For afs_GenFakeFid. */ -extern struct vcache *afs_FindVCache(struct VenusFid *afid, - afs_int32 *retry, - afs_int32 flag); - extern int afs_WriteVCacheDiscon(register struct vcache *avc, register struct AFSStoreStatus *astatus, struct vattr *attrs); extern int afs_ResyncDisconFiles(struct vrequest *areq, struct AFS_UCRED *acred); extern void afs_RemoveAllConns(void); -extern void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype); +extern void afs_GenFakeFid(struct VenusFid *afid, afs_uint32 avtype, + int lock); extern void afs_GenShadowFid(struct VenusFid *afid); extern void afs_GenDisconStatus(struct vcache *adp, struct vcache *avc, -- 2.39.5