OPENAFS-SA-2016-002 AFSStoreStatus information leak
[openafs.git] / src / afs / VNOPS / afs_vnop_dirops.c
index a5fd19e..d1d2ab2 100644 (file)
  */
 
 #include <afsconfig.h>
-#include "../afs/param.h"
+#include "afs/param.h"
 
-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_xvcache;
 extern afs_rwlock_t afs_xcbhash;
 
 /* don't set CDirty in here because RPC is called synchronously */
 
-#ifdef AFS_OSF_ENV
-afs_mkdir(ndp, attrs)
-    struct nameidata *ndp;
-    struct vattr *attrs; {
-    register struct vcache *adp = VTOAFS(ndp->ni_dvp);
-    char *aname = ndp->ni_dent.d_name;
-    register struct vcache **avcp = (struct vcache **)&(ndp->ni_vp);
-    struct ucred *acred = ndp->ni_cred;
-#else  /* AFS_OSF_ENV */
-afs_mkdir(OSI_VC_ARG(adp), aname, attrs, avcp, acred)
-    OSI_VC_DECL(adp);
-    register struct vcache **avcp;
-    char *aname;
-    struct vattr *attrs;
-    struct AFS_UCRED *acred; {
-#endif
-    struct vrequest treq;
-    register afs_int32 code;
-    register struct conn *tc;
+int
+afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, 
+     struct vcache **avcp, afs_ucred_t *acred)
+{
+    struct vrequest *treq = NULL;
+    afs_int32 code;
+    struct afs_conn *tc;
+    struct rx_connection *rxconn;
     struct VenusFid newFid;
-    register struct dcache *tdc;
+    struct dcache *tdc;
+    struct dcache *new_dc;
     afs_size_t offset, len;
-    register struct vcache *tvc;
+    struct vcache *tvc;
     struct AFSStoreStatus InStatus;
-    struct AFSFetchStatus OutFidStatus, OutDirStatus;
+    struct AFSFetchStatus *OutFidStatus, *OutDirStatus;
     struct AFSCallBack CallBack;
     struct AFSVolSync tsync;
     afs_int32 now;
     struct afs_fakestat_state fakestate;
-    XSTATS_DECLS
-    OSI_VC_CONVERT(adp)
+    XSTATS_DECLS;
+    OSI_VC_CONVERT(adp);
 
     AFS_STATCNT(afs_mkdir);
     afs_Trace2(afs_iclSetp, CM_TRACE_MKDIR, ICL_TYPE_POINTER, adp,
               ICL_TYPE_STRING, aname);
 
-    if ((code = afs_InitReq(&treq, acred))) 
+    OutFidStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
+    OutDirStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
+    memset(&InStatus, 0, sizeof(InStatus));
+
+    if ((code = afs_CreateReq(&treq, acred)))
        goto done2;
     afs_InitFakeStat(&fakestate);
 
     if (strlen(aname) > AFSNAMEMAX) {
        code = ENAMETOOLONG;
-       goto done;
+       goto done3;
     }
 
     if (!afs_ENameOK(aname)) {
        code = EINVAL;
-       goto done;
+       goto done3;
     }
-    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
-    if (code) goto done;
-    code = afs_VerifyVCache(adp, &treq);
-    if (code) goto done;
+    
+    AFS_DISCON_LOCK();
+
+    code = afs_EvalFakeStat(&adp, &fakestate, treq);
+    if (code)
+       goto done;
+    code = afs_VerifyVCache(adp, treq);
+    if (code)
+       goto done;
 
     /** If the volume is read-only, return error without making an RPC to the
       * fileserver
       */
-    if ( adp->states & CRO ) {
-        code = EROFS;
-        goto done;
+    if (adp->f.states & CRO) {
+       code = EROFS;
+       goto done;
+    }
+   
+    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 */
-    InStatus.Group = (afs_int32)acred->cr_gid;
-    tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
-    ObtainWriteLock(&adp->lock,153);
-    do {
-       tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
-       if (tc) {
-          XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
-         now = osi_Time();
-         RX_AFS_GUNLOCK();
-         code = RXAFS_MakeDir(tc->id, (struct AFSFid *) &adp->fid.Fid, aname,
-                             &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 value... */
-       }
-       else code = -1;
-    } while
-      (afs_Analyze(tc, code, &adp->fid, &treq,
-                  AFS_STATS_FS_RPCIDX_MAKEDIR, SHARED_LOCK, NULL));
-
-    if (code) {
-       if (code < 0) {
-         ObtainWriteLock(&afs_xcbhash, 490);
-         afs_DequeueCallback(adp);
-         adp->states &= ~CStatd;
-         ReleaseWriteLock(&afs_xcbhash);
-         osi_dnlc_purgedp(adp);
+    InStatus.UnixModeBits = attrs->va_mode & 0xffff;   /* only care about protection bits */
+    InStatus.Group = (afs_int32) afs_cr_gid(acred);
+    tdc = afs_GetDCache(adp, (afs_size_t) 0, treq, &offset, &len, 1);
+    ObtainWriteLock(&adp->lock, 153);
+
+    if (!AFS_IS_DISCON_RW) {
+       do {
+           tc = afs_Conn(&adp->f.fid, treq, SHARED_LOCK, &rxconn);
+           if (tc) {
+               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
+               now = osi_Time();
+               RX_AFS_GUNLOCK();
+               code =
+                   RXAFS_MakeDir(rxconn,
+                               (struct AFSFid *)&adp->f.fid.Fid,
+                               aname,
+                               &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 value... */
+           } else
+               code = -1;
+       } while (afs_Analyze
+                   (tc, rxconn, code, &adp->f.fid, treq, AFS_STATS_FS_RPCIDX_MAKEDIR,
+                    SHARED_LOCK, NULL));
+
+       if (code) {
+           if (code < 0) {
+               ObtainWriteLock(&afs_xcbhash, 490);
+               afs_DequeueCallback(adp);
+               adp->f.states &= ~CStatd;
+               ReleaseWriteLock(&afs_xcbhash);
+               osi_dnlc_purgedp(adp);
+           }
+           ReleaseWriteLock(&adp->lock);
+           if (tdc)
+               afs_PutDCache(tdc);
+           goto done;
+        }
+
+    } else {
+       /* Disconnected. */
+
+       /* We have the dir entry now, we can use it while disconnected. */
+       if (adp->mvid.target_root == NULL) {
+           /* If not mount point, generate a new fid. */
+           newFid.Cell = adp->f.fid.Cell;
+           newFid.Fid.Volume = adp->f.fid.Fid.Volume;
+           afs_GenFakeFid(&newFid, VDIR, 1);
        }
-       ReleaseWriteLock(&adp->lock);
-       if (tdc) afs_PutDCache(tdc);
-       goto done;
-    }
+       /* XXX: If mount point???*/
+
+       /* Operations with the actual dir's cache entry are further
+        * down, where the dir entry gets created.
+        */
+    }                  /* if (!AFS_IS_DISCON_RW) */
+
     /* otherwise, we should see if we can make the change to the dir locally */
-    if (tdc) ObtainWriteLock(&tdc->lock, 632);
-    if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
-        /* we can do it locally */
-        code = afs_dir_Create(&tdc->f.inode, aname, &newFid.Fid);
-        if (code) {
+    if (tdc)
+       ObtainWriteLock(&tdc->lock, 632);
+    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, OutDirStatus, 1)) {
+       /* we can do it locally */
+       ObtainWriteLock(&afs_xdcache, 294);
+       code = afs_dir_Create(tdc, aname, &newFid.Fid);
+       ReleaseWriteLock(&afs_xdcache);
+       if (code) {
            ZapDCE(tdc);        /* surprise error -- use invalid value */
-           DZap(&tdc->f.inode);
+           DZap(tdc);
        }
     }
     if (tdc) {
        ReleaseWriteLock(&tdc->lock);
        afs_PutDCache(tdc);
     }
-    adp->m.LinkCount = OutDirStatus.LinkCount;
-    newFid.Cell = adp->fid.Cell;
-    newFid.Fid.Volume = adp->fid.Fid.Volume;
+
+    if (AFS_IS_DISCON_RW)
+       /* We will have to settle with the local link count. */
+       adp->f.m.LinkCount++;
+    else
+       adp->f.m.LinkCount = OutDirStatus->LinkCount;
+    newFid.Cell = adp->f.fid.Cell;
+    newFid.Fid.Volume = adp->f.fid.Fid.Volume;
     ReleaseWriteLock(&adp->lock);
-    /* now we're done with parent dir, create the real dir's cache entry */
-    tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);
-    if (tvc) {
-       code = 0;
-       *avcp = tvc;
-    }
-    else code = ENOENT;
-done:
+    if (AFS_IS_DISCON_RW) {
+       /* When disconnected, we have to create the full dir here. */
+
+       /* Generate a new vcache and fill it. */
+       tvc = afs_NewVCache(&newFid, NULL);
+       if (tvc) {
+           *avcp = tvc;
+       } else {
+           code = EIO;
+           goto done;
+       }
+
+       ObtainWriteLock(&tvc->lock, 738);
+       afs_GenDisconStatus(adp, tvc, &newFid, attrs, treq, VDIR);
+       ReleaseWriteLock(&tvc->lock);
+
+       /* And now make an empty dir, containing . and .. : */
+       /* Get a new dcache for it first. */
+       new_dc = afs_GetDCache(tvc, (afs_size_t) 0, treq, &offset, &len, 1);
+       if (!new_dc) {
+           /* printf("afs_mkdir: can't get new dcache for dir.\n"); */
+           code = EIO;
+           goto done;
+       }
+
+       ObtainWriteLock(&afs_xdcache, 739);
+       code = afs_dir_MakeDir(new_dc,
+                              (afs_int32 *) &newFid.Fid,
+                              (afs_int32 *) &adp->f.fid.Fid);
+       ReleaseWriteLock(&afs_xdcache);
+       /* if (code) printf("afs_mkdir: afs_dirMakeDir code = %u\n", code); */
+
+       afs_PutDCache(new_dc);
+
+       ObtainWriteLock(&tvc->lock, 731);
+       /* Update length in the vcache. */
+       tvc->f.m.Length = new_dc->f.chunkBytes;
+
+       afs_DisconAddDirty(tvc, VDisconCreate, 1);
+       ReleaseWriteLock(&tvc->lock);
+    } else {
+       /* now we're done with parent dir, create the real dir's cache entry */
+       tvc = afs_GetVCache(&newFid, treq, NULL, NULL);
+       if (tvc) {
+           code = 0;
+           *avcp = tvc;
+
+       } else {
+           /* For some reason, we cannot fetch the vcache for our
+            * newly-created dir. */
+           code = EIO;
+       }
+    }                          /* if (AFS_DISCON_RW) */
+
+  done:
+    AFS_DISCON_UNLOCK();
+  done3:
     afs_PutFakeStat(&fakestate);
-    code = afs_CheckCode(code, &treq, 26);
-done2:
-#ifdef AFS_OSF_ENV
-    AFS_RELE(ndp->ni_dvp);
-#endif /* AFS_OSF_ENV */
+    code = afs_CheckCode(code, treq, 26);
+    afs_DestroyReq(treq);
+  done2:
+    osi_FreeSmallSpace(OutFidStatus);
+    osi_FreeSmallSpace(OutDirStatus);
     return code;
 }
 
 
-#ifdef AFS_OSF_ENV
-afs_rmdir(ndp)
-    struct nameidata *ndp; {
-    register struct vcache *adp = VTOAFS(ndp->ni_dvp);
-    char *aname = ndp->ni_dent.d_name;
-    struct ucred *acred = ndp->ni_cred;
-#else  /* AFS_OSF_ENV */
+int
 /* don't set CDirty in here because RPC is called synchronously */
 #if    defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
-afs_rmdir(OSI_VC_ARG(adp), aname, cdirp, acred)
-    struct vnode *cdirp;
+afs_rmdir(OSI_VC_DECL(adp), char *aname, struct vnode *cdirp, 
+         afs_ucred_t *acred)
 #else
-afs_rmdir(adp, aname, acred)
-#endif
-    OSI_VC_DECL(adp);
-    char *aname;
-    struct AFS_UCRED *acred; {
+afs_rmdir(OSI_VC_DECL(adp), char *aname, afs_ucred_t *acred)
 #endif
-    struct vrequest treq;
-    register struct dcache *tdc;
-    register struct vcache *tvc = NULL;
-    register afs_int32 code;
-    register struct conn *tc;
+{
+    struct vrequest *treq = NULL;
+    struct dcache *tdc;
+    struct vcache *tvc = NULL;
+    afs_int32 code;
+    struct afs_conn *tc;
     afs_size_t offset, len;
     struct AFSFetchStatus OutDirStatus;
     struct AFSVolSync tsync;
     struct afs_fakestat_state fakestate;
-    XSTATS_DECLS
-    OSI_VC_CONVERT(adp)
+    struct rx_connection *rxconn;
+    XSTATS_DECLS;
+    OSI_VC_CONVERT(adp);
 
     AFS_STATCNT(afs_rmdir);
 
-    afs_Trace2(afs_iclSetp, CM_TRACE_RMDIR, ICL_TYPE_POINTER, adp, 
+    afs_Trace2(afs_iclSetp, CM_TRACE_RMDIR, ICL_TYPE_POINTER, adp,
               ICL_TYPE_STRING, aname);
 
-    if ((code = afs_InitReq(&treq, acred)))
+    if ((code = afs_CreateReq(&treq, acred)))
        goto done2;
     afs_InitFakeStat(&fakestate);
 
@@ -213,83 +293,159 @@ afs_rmdir(adp, aname, acred)
        goto done;
     }
 
-    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
+    AFS_DISCON_LOCK();
+
+    code = afs_EvalFakeStat(&adp, &fakestate, treq);
     if (code)
        goto done;
 
-    code = afs_VerifyVCache(adp, &treq);
-    if (code) goto done;
+    code = afs_VerifyVCache(adp, treq);
+    if (code)
+       goto done;
 
     /** If the volume is read-only, return error without making an RPC to the
       * fileserver
       */
-    if ( adp->states & CRO ) {
-        code = EROFS;
+    if (adp->f.states & CRO) {
+       code = EROFS;
+       goto done;
+    }
+
+   if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
+       /* Disconnected read only mode. */
+        code = ENETDOWN;
         goto done;
     }
 
-    tdc        = afs_GetDCache(adp, (afs_size_t) 0,    &treq, &offset, &len, 1);       /* test for error below */
-    ObtainWriteLock(&adp->lock,154);
-    if (tdc) ObtainSharedLock(&tdc->lock, 633);
-    if (tdc && (adp->states & CForeign)) {
+    tdc = afs_GetDCache(adp, (afs_size_t) 0, treq, &offset, &len, 1);  /* test for error below */
+    ObtainWriteLock(&adp->lock, 154);
+    if (tdc)
+       ObtainSharedLock(&tdc->lock, 633);
+    if (tdc && (adp->f.states & CForeign)) {
        struct VenusFid unlinkFid;
 
        unlinkFid.Fid.Vnode = 0;
-       code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
-       if (code == 0) {        
-           afs_int32 cached=0;
+       code = afs_dir_Lookup(tdc, aname, &unlinkFid.Fid);
+       if (code == 0) {
+           afs_int32 cached = 0;
 
-           unlinkFid.Cell = adp->fid.Cell;
-           unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
+           unlinkFid.Cell = adp->f.fid.Cell;
+           unlinkFid.Fid.Volume = adp->f.fid.Fid.Volume;
            if (unlinkFid.Fid.Unique == 0) {
-               tvc = afs_LookupVCache(&unlinkFid, &treq, &cached, adp, aname);
+               tvc =
+                   afs_LookupVCache(&unlinkFid, treq, &cached, adp, aname);
            } else {
                ObtainReadLock(&afs_xvcache);
-               tvc = afs_FindVCache(&unlinkFid, 0, 1/* do xstats */);
+               tvc = afs_FindVCache(&unlinkFid, 0, 1 /* do xstats */ );
                ReleaseReadLock(&afs_xvcache);
            }
        }
     }
 
-    do {
-       tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
-       if (tc) {
-          XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
-         RX_AFS_GUNLOCK();
-           code = RXAFS_RemoveDir(tc->id, (struct AFSFid *) &adp->fid.Fid,
-                                  aname, &OutDirStatus, &tsync);
-         RX_AFS_GLOCK();
-          XSTATS_END_TIME;
+    if (!AFS_IS_DISCON_RW) {
+       /* Not disconnected, can connect to server. */
+       do {
+           tc = afs_Conn(&adp->f.fid, treq, SHARED_LOCK, &rxconn);
+           if (tc) {
+               XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
+               RX_AFS_GUNLOCK();
+               code =
+                   RXAFS_RemoveDir(rxconn,
+                               (struct AFSFid *)&adp->f.fid.Fid,
+                               aname,
+                               &OutDirStatus,
+                               &tsync);
+               RX_AFS_GLOCK();
+               XSTATS_END_TIME;
+           } else
+               code = -1;
+       } while (afs_Analyze
+                (tc, rxconn, code, &adp->f.fid, treq, AFS_STATS_FS_RPCIDX_REMOVEDIR,
+                SHARED_LOCK, NULL));
+
+       if (code) {
+           if (tdc) {
+               ReleaseSharedLock(&tdc->lock);
+               afs_PutDCache(tdc);
+           }
+
+           if (code < 0) {
+               ObtainWriteLock(&afs_xcbhash, 491);
+               afs_DequeueCallback(adp);
+               adp->f.states &= ~CStatd;
+               ReleaseWriteLock(&afs_xcbhash);
+               osi_dnlc_purgedp(adp);
+           }
+           ReleaseWriteLock(&adp->lock);
+           goto done;
+       }
+
+       /* here if rpc worked; update the in-core link count */
+       adp->f.m.LinkCount = OutDirStatus.LinkCount;
+
+    } else {
+       /* Disconnected. */
+
+       if (!tdc) {
+           ReleaseWriteLock(&adp->lock);
+           /* printf("afs_rmdir: No local dcache!\n"); */
+           code = ENETDOWN;
+           goto done;
+       }
+       
+       if (!tvc) {
+           /* Find the vcache. */
+           struct VenusFid tfid;
+
+           tfid.Cell = adp->f.fid.Cell;
+           tfid.Fid.Volume = adp->f.fid.Fid.Volume;
+           code = afs_dir_Lookup(tdc, aname, &tfid.Fid);
+
+           ObtainSharedLock(&afs_xvcache, 764);
+           tvc = afs_FindVCache(&tfid, 0, 1 /* do xstats */ );
+           ReleaseSharedLock(&afs_xvcache);
+           
+           if (!tvc) {
+               /* printf("afs_rmdir: Can't find dir's vcache!\n"); */
+               ReleaseSharedLock(&tdc->lock);
+               afs_PutDCache(tdc);     /* drop ref count */
+               ReleaseWriteLock(&adp->lock);
+               code = ENETDOWN;
+               goto done;
+           }
        }
-       else code = -1;
-    } while
-      (afs_Analyze(tc, code, &adp->fid, &treq,
-                  AFS_STATS_FS_RPCIDX_REMOVEDIR, SHARED_LOCK, NULL));
 
-    if (code) {
-       if (tdc) {
+       if (tvc->f.m.LinkCount > 2) {
+           /* This dir contains more than . and .., thus it can't be
+            * deleted.
+            */
            ReleaseSharedLock(&tdc->lock);
            afs_PutDCache(tdc);
+           afs_PutVCache(tvc);
+           ReleaseWriteLock(&adp->lock);
+           code = ENOTEMPTY;
+           goto done;
        }
-       if (code < 0) {
-         ObtainWriteLock(&afs_xcbhash, 491);
-         afs_DequeueCallback(adp);
-         adp->states &= ~CStatd;
-         ReleaseWriteLock(&afs_xcbhash);
-         osi_dnlc_purgedp(adp);
+
+       /* Make a shadow copy of the parent dir (if not done already).
+        * 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->f.shadow.vnode && !(adp->f.ddirty_flags & VDisconCreate)) {
+           afs_MakeShadowDir(adp, tdc);
        }
-       ReleaseWriteLock(&adp->lock);
-       goto done;
-    }
-    /* here if rpc worked; update the in-core link count */
-    adp->m.LinkCount = OutDirStatus.LinkCount;
-    if (tdc) UpgradeSToWLock(&tdc->lock, 634);
-    if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
+
+       adp->f.m.LinkCount--;
+    }                          /* if (!AFS_IS_DISCON_RW) */
+
+    if (tdc)
+       UpgradeSToWLock(&tdc->lock, 634);
+    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
        /* we can do it locally */
-       code = afs_dir_Delete(&tdc->f.inode, aname);
-       if (code) { 
+       code = afs_dir_Delete(tdc, aname);
+       if (code) {
            ZapDCE(tdc);        /* surprise error -- invalid value */
-           DZap(&tdc->f.inode);
+           DZap(tdc);
        }
     }
     if (tdc) {
@@ -297,16 +453,23 @@ afs_rmdir(adp, aname, acred)
        afs_PutDCache(tdc);     /* drop ref count */
     }
 
+    if (tvc)
+       osi_dnlc_purgedp(tvc);  /* get rid of any entries for this directory */
+    else
+       osi_dnlc_remove(adp, aname, 0);
 
     if (tvc) {
-       osi_dnlc_purgedp (tvc);  /* get rid of any entries for this directory */
-       afs_symhint_inval(tvc);
-    } else
-       osi_dnlc_remove (adp, aname, 0);
-
-    if (tvc) {
-       ObtainWriteLock(&tvc->lock,155);
-       tvc->states &= ~CUnique;                /* For the dfs xlator */
+       ObtainWriteLock(&tvc->lock, 155);
+       tvc->f.states &= ~CUnique;      /* For the dfs xlator */
+       if (AFS_IS_DISCON_RW) {
+           if (tvc->f.ddirty_flags & VDisconCreate) {
+               /* If we we were created whilst disconnected, removal doesn't
+                * need to get logged. Just go away gracefully */
+               afs_DisconRemoveDirty(tvc);
+           } else {
+               afs_DisconAddDirty(tvc, VDisconRemove, 1);
+           }
+       }
        ReleaseWriteLock(&tvc->lock);
        afs_PutVCache(tvc);
     }
@@ -314,13 +477,11 @@ afs_rmdir(adp, aname, acred)
     /* don't worry about link count since dirs can not be hardlinked */
     code = 0;
 
-done:
+  done:
+    AFS_DISCON_UNLOCK();
     afs_PutFakeStat(&fakestate);
-    code = afs_CheckCode(code, &treq, 27); 
-done2:
-#ifdef AFS_OSF_ENV
-    afs_PutVCache(adp);
-    afs_PutVCache(ndp->ni_vp);
-#endif /* AFS_OSF_ENV */
+    code = afs_CheckCode(code, treq, 27);
+    afs_DestroyReq(treq);
+  done2:
     return code;
 }