windows-multi-fix-20061002
authorJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 3 Oct 2006 04:22:37 +0000 (04:22 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 3 Oct 2006 04:22:37 +0000 (04:22 +0000)
Fix the following problems:

it is possible for a file to be created, buffers to become dirty from
writes, the file to be deleted, the stat cache entry to be reused, and
the dirty buffers to remain dirty until the end of time.

stat cache entry starvation can occur because of large numbers of dirty
buffers which take too long to be written to the file server.  The
thread that writes dirty buffers in background writes/checks a small
number of buffers, SQRT(buf-count), and then sleeps for 5 seconds.
Writing all of the dirty buffers via this algorithm produces untimely
results.

threads can end up waiting for a callback on the same stat cache entry
even though there are no threads actually attempting to perform the
FetchStatus.

And:

Fix prototypes

Optimize cm_GetNewSCache to reuse scache entries for deleted files
and entries not in the hashtable before allocating a new one.  This
keeps the entries in the hashtable to a minimum and thereby improving
performance for all other operations which must lookup a scache entry
by FID.

Add support for Sequential and Random Access flags

16 files changed:
src/WINNT/afsd/cm_access.c
src/WINNT/afsd/cm_buf.c
src/WINNT/afsd/cm_buf.h
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_daemon.c
src/WINNT/afsd/cm_daemon.h
src/WINNT/afsd/cm_dcache.c
src/WINNT/afsd/cm_dcache.h
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/rawops.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb.h
src/WINNT/afsd/smb3.c

index 8e13434..9b1d0b0 100644 (file)
@@ -114,7 +114,7 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
 {
     long code;
     cm_fid_t tfid;
-    cm_scache_t *aclScp;
+    cm_scache_t *aclScp = NULL;
     int got_cb = 0;
 
     /* pretty easy: just force a pass through the fetch status code */
@@ -143,13 +143,17 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
         code = cm_GetSCache(&tfid, &aclScp, userp, reqp);
         if (code) {
             lock_ObtainMutex(&scp->mx);
-            return code;
+           goto _done;
         }       
                 
         osi_Log2(afsd_logp, "GetAccess parent scp %x user %x", aclScp, userp);
         lock_ObtainMutex(&aclScp->mx);
-
-       code = cm_GetCallback(aclScp, userp, reqp, 1);
+       code = cm_SyncOp(aclScp, NULL, userp, reqp, 0,
+                     CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+       if (!code) {
+           code = cm_GetCallback(aclScp, userp, reqp, 1);
+           cm_SyncOpDone(aclScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+       }
         lock_ReleaseMutex(&aclScp->mx);
         cm_ReleaseSCache(aclScp);
         lock_ObtainMutex(&scp->mx);
@@ -157,5 +161,9 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
        code = cm_GetCallback(scp, userp, reqp, 1);
     }
 
+  _done:
+    if (got_cb)
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     return code;
 }
index 768aef5..460bf84 100644 (file)
@@ -106,7 +106,12 @@ void buf_ReleaseLocked(cm_buf_t *bp)
 {
     /* ensure that we're in the LRU queue if our ref count is 0 */
     osi_assert(bp->magic == CM_BUF_MAGIC);
+#ifdef DEBUG
+    if (bp->refCount == 0)
+       DebugBreak();
+#else
     osi_assert(bp->refCount > 0);
+#endif
     if (--bp->refCount == 0) {
         if (!(bp->flags & CM_BUF_INLRU)) {
             osi_QAdd((osi_queue_t **) &cm_data.buf_freeListp, &bp->q);
@@ -132,23 +137,28 @@ void buf_IncrSyncer(long parm)
 {
     cm_buf_t *bp;                      /* buffer we're hacking on; held */
     long i;                            /* counter */
-    long nAtOnce;                      /* how many to do at once */
+    long wasDirty;
     cm_req_t req;
 
     lock_ObtainWrite(&buf_globalLock);
     bp = cm_data.buf_allp;
     buf_HoldLocked(bp);
     lock_ReleaseWrite(&buf_globalLock);
-    nAtOnce = (long)sqrt((double)cm_data.buf_nbuffers);
+    wasDirty = 0;
+
     while (buf_ShutdownFlag == 0) {
-        i = SleepEx(5000, 1);
-        if (i != 0) continue;
-            
+        if (!wasDirty) {
+            i = SleepEx(5000, 1);
+            if (i != 0) continue;
+       }
+
         if (buf_ShutdownFlag == 1)
             return;
 
+       wasDirty = 0;
+
         /* now go through our percentage of the buffers */
-        for (i=0; i<nAtOnce; i++) {
+        for (i=0; i<cm_data.buf_nbuffers; i++) {
             /* don't want its identity changing while we're
              * messing with it, so must do all of this with
              * bp held.
@@ -159,8 +169,10 @@ void buf_IncrSyncer(long parm)
              * a log page at any given instant.
              */
             cm_InitReq(&req);
+#ifdef NO_BKG_RETRIES
             req.flags |= CM_REQ_NORETRY;
-            buf_CleanAsync(bp, &req);
+#endif
+           wasDirty |= buf_CleanAsync(bp, &req);
 
             /* now advance to the next buffer; the allp chain never changes,
              * and so can be followed even when holding no locks.
@@ -432,9 +444,9 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
         if ( bp->flags & CM_BUF_WAITING ) {
             bp->waitCount++;
             bp->waitRequests++;
-            osi_Log1(afsd_logp, "buf_WaitIO CM_BUF_WAITING already set for 0x%p", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING already set for 0x%p", bp);
         } else {
-            osi_Log1(afsd_logp, "buf_WaitIO CM_BUF_WAITING set for 0x%p", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING set for 0x%p", bp);
             bp->flags |= CM_BUF_WAITING;
             bp->waitCount = bp->waitRequests = 1;
         }
@@ -443,10 +455,10 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
        smb_UpdateServerPriority();
 
         lock_ObtainMutex(&bp->mx);
-        osi_Log1(afsd_logp, "buf_WaitIO conflict wait done for 0x%p", bp);
+        osi_Log1(buf_logp, "buf_WaitIO conflict wait done for 0x%p", bp);
         bp->waitCount--;
         if (bp->waitCount == 0) {
-            osi_Log1(afsd_logp, "buf_WaitIO CM_BUF_WAITING reset for 0x%p", bp);
+            osi_Log1(buf_logp, "buf_WaitIO CM_BUF_WAITING reset for 0x%p", bp);
             bp->flags &= ~CM_BUF_WAITING;
             bp->waitRequests = 0;
         }
@@ -457,7 +469,7 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
         if ( scp ) {
             lock_ObtainMutex(&scp->mx);
             if (scp->flags & CM_SCACHEFLAG_WAITING) {
-                osi_Log1(afsd_logp, "buf_WaitIO waking scp 0x%p", scp);
+                osi_Log1(buf_logp, "buf_WaitIO waking scp 0x%p", scp);
                 osi_Wakeup((LONG_PTR)&scp->flags);
             }
            lock_ReleaseMutex(&scp->mx);
@@ -468,10 +480,10 @@ void buf_WaitIO(cm_scache_t * scp, cm_buf_t *bp)
      * the I/O to complete.  Do so.
      */
     if (bp->flags & CM_BUF_WAITING) {
-        osi_Log1(afsd_logp, "buf_WaitIO Waking bp 0x%p", bp);
+        osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%p", bp);
         osi_Wakeup((LONG_PTR) bp);
     }
-    osi_Log1(afsd_logp, "WaitIO finished wait for bp 0x%p", bp);
+    osi_Log1(buf_logp, "WaitIO finished wait for bp 0x%p", bp);
 }
 
 /* find a buffer, if any, for a particular file ID and offset.  Assumes
@@ -516,25 +528,36 @@ cm_buf_t *buf_Find(struct cm_scache *scp, osi_hyper_t *offsetp)
  * Makes sure that there's only one person writing this block
  * at any given time, and also ensures that the log is forced sufficiently far,
  * if this buffer contains logged data.
+ *
+ * Returns one if the buffer was dirty.
  */
-void buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
+long buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
 {
     long code = 0;
+    long isdirty = 0;
 
     osi_assert(bp->magic == CM_BUF_MAGIC);
 
     while ((bp->flags & CM_BUF_DIRTY) == CM_BUF_DIRTY) {
+       isdirty = 1;
         lock_ReleaseMutex(&bp->mx);
 
-       osi_Log1(afsd_logp, "buf_CleanAsyncLocked starts I/O on 0x%p", bp);
+       osi_Log1(buf_logp, "buf_CleanAsyncLocked starts I/O on 0x%p", bp);
         code = (*cm_buf_opsp->Writep)(&bp->fid, &bp->offset,
                                        cm_data.buf_blockSize, 0, bp->userp,
                                        reqp);
-       osi_Log2(afsd_logp, "buf_CleanAsyncLocked I/O on 0x%p, done=%d", bp, code);
+       osi_Log2(buf_logp, "buf_CleanAsyncLocked I/O on 0x%p, done=%d", bp, code);
                 
         lock_ObtainMutex(&bp->mx);
-        if (code) 
-            break;
+       /* if the Write routine returns No Such File, clear the dirty flag 
+        * because we aren't going to be able to write this data to the file
+        * server.
+        */
+       if (code == CM_ERROR_NOSUCHFILE){
+           bp->flags &= ~CM_BUF_DIRTY;
+           bp->flags |= CM_BUF_ERROR;
+           bp->error = CM_ERROR_NOSUCHFILE;
+       }
 
 #ifdef DISKCACHE95
         /* Disk cache support */
@@ -553,6 +576,7 @@ void buf_CleanAsyncLocked(cm_buf_t *bp, cm_req_t *reqp)
         osi_Log1(buf_logp, "buf_WaitIO Waking bp 0x%p", bp);
         osi_Wakeup((LONG_PTR) bp);
     }
+    return isdirty;
 }
 
 /* Called with a zero-ref count buffer and with the buf_globalLock write locked.
@@ -753,6 +777,9 @@ long buf_GetNewLocked(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bu
             if (scp) {
                 bp->flags |= CM_BUF_INHASH;
                 bp->fid = scp->fid;
+#ifdef DEBUG
+               bp->scp = scp;
+#endif
                 bp->offset = *offsetp;
                 i = BUF_HASH(&scp->fid, offsetp);
                 bp->hashp = cm_data.buf_hashTablepp[i];
@@ -884,16 +911,17 @@ long buf_Get(struct cm_scache *scp, osi_hyper_t *offsetp, cm_buf_t **bufpp)
         if (bp) {
             /* lock it and break out */
             lock_ObtainMutex(&bp->mx);
-            break;
 
 #ifdef DISKCACHE95
             /* touch disk chunk to update LRU info */
             diskcache_Touch(bp->dcp);
 #endif /* DISKCACHE95 */
+            break;
         }
 
         /* otherwise, we have to create a page */
         code = buf_GetNewLocked(scp, &pageOffset, &bp);
+       /* bp->mx is now held */
 
         /* check if the buffer was created in a race condition branch.
          * If so, go around so we can hold a reference to it. 
@@ -1026,13 +1054,16 @@ long buf_CountFreeList(void)
 }
 
 /* clean a buffer synchronously */
-void buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp)
+long buf_CleanAsync(cm_buf_t *bp, cm_req_t *reqp)
 {
+    long code;
     osi_assert(bp->magic == CM_BUF_MAGIC);
 
     lock_ObtainMutex(&bp->mx);
-    buf_CleanAsyncLocked(bp, reqp);
+    code = buf_CleanAsyncLocked(bp, reqp);
     lock_ReleaseMutex(&bp->mx);
+
+    return code;
 }       
 
 /* wait for a buffer's cleaning to finish */
@@ -1101,8 +1132,8 @@ long buf_CleanAndReset(void)
 
                 /* now no locks are held; clean buffer and go on */
                 cm_InitReq(&req);
-                buf_CleanAsync(bp, &req);
-                buf_CleanWait(NULL, bp);
+               buf_CleanAsync(bp, &req);
+               buf_CleanWait(NULL, bp);
 
                 /* relock and release buffer */
                 lock_ObtainWrite(&buf_globalLock);
@@ -1261,6 +1292,10 @@ long buf_Truncate(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
             }
         }
                
+       cm_SyncOpDone( scp, bufp, 
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+                      | CM_SCACHESYNC_SETSIZE | CM_SCACHESYNC_BUFLOCKED);
+
         lock_ReleaseMutex(&scp->mx);
         lock_ReleaseMutex(&bufp->mx);
     
@@ -1382,8 +1417,8 @@ long buf_CleanVnode(struct cm_scache *scp, cm_user_t *userp, cm_req_t *reqp)
                 bp->userp = userp;
                 lock_ReleaseMutex(&bp->mx);
             }   
-            buf_CleanAsync(bp, reqp);
-            buf_CleanWait(scp, bp);
+            code = buf_CleanAsync(bp, reqp);
+           buf_CleanWait(scp, bp);
             lock_ObtainMutex(&bp->mx);
             if (bp->flags & CM_BUF_ERROR) {
                 if (code == 0 || code == -1) 
@@ -1509,3 +1544,43 @@ void buf_ForceTrace(BOOL flush)
         FlushFileBuffers(handle);
     CloseHandle(handle);
 }
+
+long buf_DirtyBuffersExist(cm_fid_t *fidp)
+{
+    cm_buf_t *bp;
+    afs_uint32 bcount = 0;
+
+    for (bp = cm_data.buf_allp; bp; bp=bp->allp, bcount++) {
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY))
+           return 1;
+    }
+    return 0;
+}
+
+long buf_CleanDirtyBuffers(cm_scache_t *scp)
+{
+    cm_buf_t *bp;
+    afs_uint32 bcount = 0;
+    cm_fid_t * fidp = &scp->fid;
+
+    for (bp = cm_data.buf_allp; bp; bp=bp->allp, bcount++) {
+       if (!cm_FidCmp(fidp, &bp->fid) && (bp->flags & CM_BUF_DIRTY)) {
+               buf_Hold(bp);
+           lock_ObtainMutex(&bp->mx);
+           bp->cmFlags &= ~CM_BUF_CMSTORING;
+           bp->flags &= ~CM_BUF_DIRTY;
+           bp->flags |= CM_BUF_ERROR;
+           bp->error = VNOVNODE;
+           bp->dataVersion = -1; /* bad */
+           bp->dirtyCounter++;
+           if (bp->flags & CM_BUF_WAITING) {
+               osi_Log2(buf_logp, "BUF CleanDirtyBuffers Waking [scp 0x%x] bp 0x%x", scp, bp);
+               osi_Wakeup((long) &bp);
+           }
+           lock_ReleaseMutex(&bp->mx);
+           buf_Release(bp);
+       }
+    }
+    return 0;
+}
+
index 22c2278..99357aa 100644 (file)
@@ -80,6 +80,10 @@ typedef struct cm_buf {
 #endif /* notdef */
     osi_hyper_t offset;                /* offset */
     cm_fid_t fid;              /* file ID */
+#ifdef DEBUG
+    cm_scache_t *scp;          /* for debugging, the scache object belonging to */
+                                /* the fid at the time of fid assignment. */
+#endif
     long flags;                        /* flags we're using */
     long size;                 /* size in bytes of this buffer */
     char *datap;               /* data in this buffer */
@@ -111,7 +115,7 @@ typedef struct cm_softRef {
     long counter;              /* counter of changes to identity */
 } cm_softRef_t;
 
-#define CM_BUF_READING 1       /* now reading buffer to the disk */
+#define CM_BUF_READING 1       /* now reading buffer from the disk */
 #define CM_BUF_WRITING 2       /* now writing buffer to the disk */
 #define CM_BUF_INHASH  4       /* in the hash table */
 #define CM_BUF_DIRTY           8       /* buffer is dirty */
@@ -160,9 +164,9 @@ extern long buf_Get(struct cm_scache *, osi_hyper_t *, cm_buf_t **);
 
 extern long buf_GetNew(struct cm_scache *, osi_hyper_t *, cm_buf_t **);
 
-extern void buf_CleanAsyncLocked(cm_buf_t *, cm_req_t *);
+extern long buf_CleanAsyncLocked(cm_buf_t *, cm_req_t *);
 
-extern void buf_CleanAsync(cm_buf_t *, cm_req_t *);
+extern long buf_CleanAsync(cm_buf_t *, cm_req_t *);
 
 extern void buf_CleanWait(cm_scache_t *, cm_buf_t *);
 
@@ -197,6 +201,10 @@ extern long buf_ValidateBuffers(void);
 
 extern void buf_ForceTrace(BOOL flush);
 
+extern long buf_DirtyBuffersExist(cm_fid_t * fidp);
+
+extern long buf_CleanDirtyBuffers(cm_scache_t *scp);
+
 /* error codes */
 #define CM_BUF_EXISTS  1       /* buffer exists, and shouldn't */
 #endif /*  _BUF_H__ENV_ */
index df53cfd..5ead137 100644 (file)
@@ -1680,9 +1680,16 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
         /* turn off mustCall, since it has now forced us past the check above */
         mustCall = 0;
 
+#if 0
+       /* 20060929 jaltman - We are being called from within cm_SyncOp.
+        * if we call cm_SyncOp again and another thread has attempted
+        * to obtain current status CM_SCACHEFLAG_WAITING will be set
+        * and we will deadlock.  
+        */
         /* otherwise, we have to make an RPC to get the status */
         sflags = CM_SCACHESYNC_FETCHSTATUS | CM_SCACHESYNC_GETCALLBACK;
         cm_SyncOp(scp, NULL, userp, reqp, 0, sflags);
+#endif /* deadlock */
         cm_StartCallbackGrantingCall(scp, &cbr);
         sfid = scp->fid;
         lock_ReleaseMutex(&scp->mx);
@@ -1717,7 +1724,10 @@ long cm_GetCallback(cm_scache_t *scp, struct cm_user *userp,
         } else {
             cm_EndCallbackGrantingCall(NULL, &cbr, NULL, 0);
         }
+#if 0
+       /* 20060929 jaltman - don't deadlock */
         cm_SyncOpDone(scp, NULL, sflags);
+#endif
 
         /* now check to see if we got an error */
         if (code) {
index c923daf..5b1fe41 100644 (file)
@@ -94,7 +94,7 @@ void cm_BkgDaemon(long parm)
     lock_ReleaseWrite(&cm_daemonLock);
 }
 
-void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, long p1, long p2, long p3, long p4,
+void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
        cm_user_t *userp)
 {
     cm_bkgRequest_t *rp;
index a5c25a6..5e614ca 100644 (file)
@@ -24,21 +24,21 @@ void cm_DaemonShutdown(void);
 
 void cm_InitDaemon(int nDaemons);
 
-typedef void (cm_bkgProc_t)(cm_scache_t *scp, long p1, long p2, long p3,
-       long p4, struct cm_user *up);
+typedef void (cm_bkgProc_t)(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3,
+       afs_uint32 p4, struct cm_user *up);
 
 typedef struct cm_bkgRequest {
        osi_queue_t q;
        cm_bkgProc_t *procp;
         cm_scache_t *scp;
-        long p1;
-        long p2;
-        long p3;
-        long p4;
+        afs_uint32 p1;
+        afs_uint32 p2;
+        afs_uint32 p3;
+        afs_uint32 p4;
         struct cm_user *userp;
 } cm_bkgRequest_t;
 
-extern void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, long p1,
-       long p2, long p3, long p4, cm_user_t *userp);
+extern void cm_QueueBKGRequest(cm_scache_t *scp, cm_bkgProc_t *procp, afs_uint32 p1,
+       afs_uint32 p2, afs_uint32 p3, afs_uint32 p4, cm_user_t *userp);
 
 #endif /*  __CM_DAEMON_H_ENV_ */
index 5e00319..89c5721 100644 (file)
@@ -81,12 +81,18 @@ long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
      * buffer, although more likely it will just return a new, empty, buffer.
      */
     scp = cm_FindSCache(fidp);
-    if (scp == NULL)
+    if (scp == NULL) {
         return CM_ERROR_NOSUCHFILE;    /* shouldn't happen */
+    }
 
     cm_AFSFidFromFid(&tfid, fidp);
 
     lock_ObtainMutex(&scp->mx);
+    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+       lock_ReleaseMutex(&scp->mx);
+        cm_ReleaseSCache(scp);
+       return CM_ERROR_NOSUCHFILE;
+    }
 
     code = cm_SetupStoreBIOD(scp, offsetp, length, &biod, userp, reqp);
     if (code) {
@@ -450,6 +456,8 @@ long cm_BufUnstabilize(void *parmp, cm_user_t *userp)
         
     scp = parmp;
         
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_SETSIZE);
+
     lock_ReleaseMutex(&scp->mx);
         
     /* always succeeds */
@@ -559,6 +567,7 @@ long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
                  && bp->dataVersion != scp->dataVersion)
                 stop = 1;
             buf_Release(bp);
+           bp = NULL;
         }
         else 
             stop = 1;
@@ -592,15 +601,23 @@ long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
     return code;
 }
 
-void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
+void cm_BkgStore(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
                  cm_user_t *userp)
 {
     osi_hyper_t toffset;
     long length;
     cm_req_t req;
+    long code;
+
+    if (scp->flags & CM_SCACHEFLAG_DELETED) {
+       osi_Log4(afsd_logp, "Skipping BKG store - Deleted scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, p2, p1, p3);
+       return;
+    }
 
     cm_InitReq(&req);
+#ifdef NO_BKG_RETRIES
     req.flags |= CM_REQ_NORETRY;
+#endif
 
     toffset.LowPart = p1;
     toffset.HighPart = p2;
@@ -608,7 +625,7 @@ void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
 
     osi_Log4(afsd_logp, "Starting BKG store scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, p2, p1, p3);
 
-    cm_BufWrite(&scp->fid, &toffset, length, /* flags */ 0, userp, &req);
+    code = cm_BufWrite(&scp->fid, &toffset, length, /* flags */ 0, userp, &req);
 
     lock_ObtainMutex(&scp->mx);
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
@@ -753,7 +770,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
     lock_ObtainMutex(&scp->mx);
 
     bufp = NULL;
-    for (temp = 0; temp < inSize; temp += cm_data.buf_blockSize, bufp = NULL) {
+    for (temp = 0; temp < inSize; temp += cm_data.buf_blockSize) {
         thyper.HighPart = 0;
         thyper.LowPart = temp;
         tbase = LargeIntegerAdd(*inOffsetp, thyper);
@@ -789,6 +806,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             cm_SyncOpDone(scp, bufp, flags);
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
         }       
     }
 
@@ -814,6 +832,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
     biop->length = cm_data.buf_blockSize;
     firstModOffset = bufp->offset;
     biop->offset = firstModOffset;
+    bufp = NULL;       /* this buffer and reference added to the queue */
 
     /* compute the window surrounding *inOffsetp of size cm_chunkSize */
     scanStart = *inOffsetp;
@@ -844,6 +863,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         lock_ObtainMutex(&scp->mx);
         if (code == 0) {
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
                 
@@ -851,6 +871,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         if (code) {
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
                 
@@ -859,6 +880,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             cm_SyncOpDone(scp, bufp, flags);
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
 
@@ -875,6 +897,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         osi_QAddT((osi_queue_t **) &biop->bufListp,
                   (osi_queue_t **) &biop->bufListEndp,
                   &qdp->q);
+       bufp = NULL;            /* added to the queue */
 
         /* update biod info describing the transfer */
         biop->offset = LargeIntegerSubtract(biop->offset, thyper);
@@ -900,6 +923,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         lock_ObtainMutex(&scp->mx);
         if (code == 0) {
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
 
@@ -907,6 +931,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         if (code) {
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
                 
@@ -915,6 +940,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
             cm_SyncOpDone(scp, bufp, flags);
             lock_ReleaseMutex(&bufp->mx);
             buf_Release(bufp);
+           bufp = NULL;
             break;
         }
 
@@ -931,6 +957,7 @@ long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
         osi_QAddH((osi_queue_t **) &biop->bufListp,
                   (osi_queue_t **) &biop->bufListEndp,
                   &qdp->q);
+       bufp = NULL;
 
         /* update biod info describing the transfer */
         biop->length += cm_data.buf_blockSize;
@@ -1224,6 +1251,7 @@ void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore)
         lock_ReleaseMutex(&scp->mx);
         lock_ReleaseMutex(&bufp->mx);
         buf_Release(bufp);
+       bufp = NULL;
     }
 
     /* clean things out */
@@ -1409,7 +1437,7 @@ long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
                     nbytes_hi = ntohl(nbytes_hi);
                 } else {
                     nbytes_hi = 0;
-                                       code = callp->error;
+                   code = callp->error;
                     rx_EndCall(callp, code);
                     callp = NULL;
                 }
index 9951334..1969cfc 100644 (file)
@@ -42,10 +42,10 @@ extern void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore);
 extern long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp,
        long inSize, cm_bulkIO_t *biop, cm_user_t *userp, cm_req_t *reqp);
 
-extern void cm_BkgPrefetch(cm_scache_t *scp, long p1, long p2, long p3, long p4,
+extern void cm_BkgPrefetch(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
        struct cm_user *userp);
 
-extern void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
+extern void cm_BkgStore(cm_scache_t *scp, afs_uint32 p1, afs_uint32 p2, afs_uint32 p3, afs_uint32 p4,
        struct cm_user *userp);
 
 extern void cm_ConsiderPrefetch(cm_scache_t *scp, osi_hyper_t *offsetp,
index e552564..dd27ea0 100644 (file)
@@ -987,7 +987,7 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
         
     /* if something went wrong, bail out now */
     if (code) {
-        goto done;
+        goto done2;
     }
         
     lock_ObtainMutex(&scp->mx);
@@ -996,7 +996,7 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (code) {     
         lock_ReleaseMutex(&scp->mx);
         cm_ReleaseSCache(scp);
-        goto done;
+        goto done2;
     }
 
     /* now check that this is a real mount point */
@@ -1004,7 +1004,7 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
         lock_ReleaseMutex(&scp->mx);
         cm_ReleaseSCache(scp);
         code = CM_ERROR_INVAL;
-        goto done;
+        goto done1;
     }
 
     /* time to make the RPC, so drop the lock */
@@ -1018,7 +1018,10 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
                           FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, cp, NULL, TRUE);
 
-  done:
+  done1:
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+  done2:
     cm_ReleaseSCache(dscp);
     return code;
 }
@@ -1841,7 +1844,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
         
     /* if something went wrong, bail out now */
     if (code) {
-        goto done;
+        goto done2;
     }
         
     lock_ObtainMutex(&scp->mx);
@@ -1850,7 +1853,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     if (code) {     
         lock_ReleaseMutex(&scp->mx);
         cm_ReleaseSCache(scp);
-        goto done;
+        goto done2;
     }
        
     /* now check that this is a real symlink */
@@ -1860,7 +1863,7 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
         lock_ReleaseMutex(&scp->mx);
         cm_ReleaseSCache(scp);
         code = CM_ERROR_INVAL;
-        goto done;
+        goto done1;
     }
        
     /* time to make the RPC, so drop the lock */
@@ -1875,7 +1878,10 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
                           | FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, cp, NULL, TRUE);
 
-  done:
+  done1:
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+  done2:
     cm_ReleaseSCache(dscp);
     return code;
 }
index 9d1de18..fa42707 100644 (file)
@@ -84,6 +84,8 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                lock_ObtainMutex(&bufp->mx);
                bufp->cmFlags &= ~CM_BUF_CMSTORING;
                bufp->flags &= ~CM_BUF_DIRTY;
+               bufp->flags |= CM_BUF_ERROR;
+               bufp->error = VNOVNODE;
                bufp->dataVersion = -1; /* bad */
                bufp->dirtyCounter++;
                if (bufp->flags & CM_BUF_WAITING) {
@@ -102,6 +104,8 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                lock_ObtainMutex(&bufp->mx);
                bufp->cmFlags &= ~CM_BUF_CMFETCHING;
                bufp->flags &= ~CM_BUF_DIRTY;
+               bufp->flags |= CM_BUF_ERROR;
+               bufp->error = VNOVNODE;
                bufp->dataVersion = -1; /* bad */
                bufp->dirtyCounter++;
                if (bufp->flags & CM_BUF_WAITING) {
@@ -112,6 +116,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
                buf_Release(bufp);
            }
         }
+       buf_CleanDirtyBuffers(scp); 
     } else {
        /* look for things that shouldn't still be set */
        osi_assert(scp->bufWritesp == NULL);
@@ -121,6 +126,7 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
     /* invalidate so next merge works fine;
      * also initialize some flags */
     scp->flags &= ~(CM_SCACHEFLAG_STATD
+                    | CM_SCACHEFLAG_DELETED
                     | CM_SCACHEFLAG_RO
                     | CM_SCACHEFLAG_PURERO
                     | CM_SCACHEFLAG_OVERQUOTA
@@ -183,34 +189,86 @@ long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
 cm_scache_t *cm_GetNewSCache(void)
 {
     cm_scache_t *scp;
+    int retry = 0;
 
-  start:
-    if (cm_data.currentSCaches >= cm_data.maxSCaches) {
-        for (scp = cm_data.scacheLRULastp;
-              scp;
-              scp = (cm_scache_t *) osi_QPrev(&scp->q)) {
-            if (scp->refCount == 0) 
-                break;
-        }
-                
-        if (scp) {
-            osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
-
-           if (!cm_RecycleSCache(scp, 0)) {
-           
+    /* first pass - look for deleted objects */
+    for ( scp = cm_data.scacheLRULastp;
+         scp;
+         scp = (cm_scache_t *) osi_QPrev(&scp->q)) 
+    {
+       osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
+
+       if (scp->refCount == 0) {
+           if (scp->flags & CM_SCACHEFLAG_DELETED) {
+               osi_Log1(afsd_logp, "GetNewSCache attempting to recycle deleted scp 0x%x", scp);
+               if (!cm_RecycleSCache(scp, CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS)) {
+
+                   /* we found an entry, so return it */
+                   /* now remove from the LRU queue and put it back at the
+                    * head of the LRU queue.
+                    */
+                   cm_AdjustLRU(scp);
+
+                   /* and we're done */
+                   return scp;
+               } 
+               osi_Log1(afsd_logp, "GetNewSCache recycled failed scp 0x%x", scp);
+           } else if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
                /* we found an entry, so return it */
                /* now remove from the LRU queue and put it back at the
-                * head of the LRU queue.
-                */
+               * head of the LRU queue.
+               */
                cm_AdjustLRU(scp);
 
                /* and we're done */
                return scp;
+           }
+       }       
+    }  
+    osi_Log0(afsd_logp, "GetNewSCache no deleted or recycled entries available for reuse");
+
+    if (cm_data.currentSCaches >= cm_data.maxSCaches) {
+       /* There were no deleted scache objects that we could use.  Try to find
+        * one that simply hasn't been used in a while.
+        */
+       while (1) {
+           for ( scp = cm_data.scacheLRULastp;
+                 scp;
+                 scp = (cm_scache_t *) osi_QPrev(&scp->q)) 
+           {
+               /* It is possible for the refCount to be zero and for there still
+                * to be outstanding dirty buffers.  If there are dirty buffers,
+                * we must not recycle the scp. */
+               if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
+                   if (!buf_DirtyBuffersExist(&scp->fid)) {
+                       if (!cm_RecycleSCache(scp, 0)) {
+                           /* we found an entry, so return it */
+                           /* now remove from the LRU queue and put it back at the
+                            * head of the LRU queue.
+                            */
+                           cm_AdjustLRU(scp);
+
+                           /* and we're done */
+                           return scp;
+                       }
+                   } else {
+                       osi_Log1(afsd_logp,"GetNewSCache dirty buffers exist scp 0x%x", scp);
+                   }
+               }       
+           }
+           osi_Log1(afsd_logp, "GetNewSCache all scache entries in use (retry = %d)", retry);
+           
+           /* If get here it means that every scache is either in use or has dirty buffers.
+            * We used to panic.  Now we will give up our lock and wait.
+            */
+           if (++retry < 10) {
+               lock_ReleaseWrite(&cm_scacheLock);
+               Sleep(1000);
+               lock_ObtainWrite(&cm_scacheLock);
            } else {
-               /* We don't like this entry, choose another one. */
-               goto start;
+               return NULL;
            }
-        }
+       } /* forever */
     }
         
     /* if we get here, we should allocate a new scache entry.  We either are below
@@ -443,8 +501,13 @@ cm_scache_t *cm_FindSCache(cm_fid_t *fidp)
     cm_scache_t *scp;
 
     hash = CM_SCACHE_HASH(fidp);
-        
-    osi_assert(fidp->cell != 0);
+
+    if (fidp->cell == 0) {
+#ifdef DEBUG
+       DebugBreak();
+#endif
+       return NULL;
+    }
 
     lock_ObtainWrite(&cm_scacheLock);
     for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
@@ -529,7 +592,12 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
             mp = "";
         }
         scp = cm_GetNewSCache();
-         
+       if (scp == NULL) {
+           osi_Log0(afsd_logp,"cm_getSCache unable to obtain *new* scache entry");
+            lock_ReleaseWrite(&cm_scacheLock);
+           return CM_ERROR_WOULDBLOCK;
+       }
+
        lock_ObtainMutex(&scp->mx);
         scp->fid = *fidp;
         scp->volp = cm_data.rootSCachep->volp;
@@ -602,6 +670,12 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
         
     /* now, if we don't have the fid, recycle something */
     scp = cm_GetNewSCache();
+    if (scp == NULL) {
+       osi_Log0(afsd_logp,"cm_getSCache unable to obtain *new* scache entry");
+       lock_ReleaseWrite(&cm_scacheLock);
+       return CM_ERROR_WOULDBLOCK;
+    }
+
     osi_assert(!(scp->flags & CM_SCACHEFLAG_INHASH));
     lock_ObtainMutex(&scp->mx);
     scp->fid = *fidp;
@@ -898,7 +972,7 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
         // yj: modified this so that callback only checked if we're
         // not checking something on /afs
         /* fix the conditional to match the one in cm_HaveCallback */
-        if (  (flags & CM_SCACHESYNC_NEEDCALLBACK)
+        if ((flags & CM_SCACHESYNC_NEEDCALLBACK)
 #ifdef AFS_FREELANCE_CLIENT
              && (!cm_freelanceEnabled || 
                   !(scp->fid.vnode==0x1 && scp->fid.unique==0x1) ||
@@ -912,7 +986,7 @@ long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *req
                           scp);
                 if (bufLocked) 
                    lock_ReleaseMutex(&bufp->mx);
-                code = cm_GetCallback(scp, userp, reqp, 0);
+                code = cm_GetCallback(scp, userp, reqp, (flags & CM_SCACHESYNC_FORCECB)?1:0);
                 if (bufLocked) {
                     lock_ReleaseMutex(&scp->mx);
                     lock_ObtainMutex(&bufp->mx);
@@ -1086,12 +1160,16 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags)
            osi_QDFree(qdp);
        }
         if (bufp) {
+           int release = 0;
+           if (bufp->cmFlags & CM_BUF_CMFETCHING)
+               release = 1;
             bufp->cmFlags &= ~(CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED);
             if (bufp->flags & CM_BUF_WAITING) {
                 osi_Log2(afsd_logp, "CM SyncOpDone Waking [scp 0x%p] bufp 0x%p", scp, bufp);
                 osi_Wakeup((LONG_PTR) &bufp);
             }
-            buf_Release(bufp);
+           if (release)
+               buf_Release(bufp);
         }
     }
 
@@ -1108,12 +1186,16 @@ void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags)
            osi_QDFree(qdp);
        }
         if (bufp) {
+           int release = 0;
+           if (bufp->cmFlags & CM_BUF_CMSTORING)
+               release = 1;
             bufp->cmFlags &= ~CM_BUF_CMSTORING;
             if (bufp->flags & CM_BUF_WAITING) {
                 osi_Log2(afsd_logp, "CM SyncOpDone Waking [scp 0x%p] bufp 0x%p", scp, bufp);
                 osi_Wakeup((LONG_PTR) &bufp);
             }
-            buf_Release(bufp);
+           if (release)
+               buf_Release(bufp);
         }
     }
 
index 7cb07bc..724a62d 100644 (file)
@@ -276,6 +276,8 @@ typedef struct cm_scache {
 #define CM_SCACHESYNC_BUFLOCKED                0x80000 /* the buffer is locked */
 #define CM_SCACHESYNC_NOWAIT           0x100000/* don't wait for the state,
                                                 * just fail */
+#define CM_SCACHESYNC_FORCECB          0x200000/* when calling cm_GetCallback()
+                                                 * set the force flag */
 
 /* flags for cm_RecycleSCache  */
 #define CM_SCACHE_RECYCLEFLAG_DESTROY_BUFFERS  0x1
index ee8127c..afcc46f 100644 (file)
@@ -450,8 +450,8 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
     /* First check permissions */
     lock_ObtainMutex(&dscp->mx);
     code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_DELETE,
-                      CM_SCACHESYNC_GETSTATUS
-                      | CM_SCACHESYNC_NEEDCALLBACK);
+                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
+    cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     lock_ReleaseMutex(&dscp->mx);
     if (code)
         return code;
@@ -487,6 +487,7 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
         lock_ReleaseMutex(&scp->mx);
         lock_ObtainMutex(&bufferp->mx);
         lock_ObtainMutex(&scp->mx);
+       cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
         if (code)
             break;
     }
@@ -693,6 +694,7 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
                     lock_ReleaseMutex(&scp->mx);
                     break;
                 }
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ | CM_SCACHESYNC_BUFLOCKED);
                                 
                 if (cm_HaveBuffer(scp, bufferp, 1)) {
                     lock_ReleaseMutex(&scp->mx);
@@ -911,6 +913,8 @@ long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
         if (code) {
             goto done;
         }
+       cm_SyncOpDone(scp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
 
         if (cm_HaveBuffer(scp, bufp, 0)) 
             break;
@@ -1185,6 +1189,7 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
         cm_ReleaseSCache(tscp);
         return code;
     }
+    cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     /* tscp is now locked */
 
     if (!(flags & CM_FLAG_NOMOUNTCHASE)
@@ -1383,6 +1388,8 @@ long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
                 buf_Release(bufp);
                 return code;
             }
+           cm_SyncOpDone(linkScp, bufp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
             if (cm_HaveBuffer(linkScp, bufp, 0)) 
                 break;
 
@@ -1636,6 +1643,8 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                     }
                     break;
                 }
+               cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
                 if (tscp->fileType == CM_SCACHETYPE_SYMLINK) {
                     /* this is a symlink; assemble a new buffer */
                     lock_ReleaseMutex(&tscp->mx);
@@ -2105,7 +2114,8 @@ long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) 
         goto done;
-        
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     if (scp->fileType != CM_SCACHETYPE_FILE) {
         code = CM_ERROR_ISDIR;
         goto done;
@@ -2164,6 +2174,10 @@ long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
     /* done successfully */
     code = 0;
 
+    cm_SyncOpDone(scp, NULL, 
+                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS
+                  | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_SETSIZE);
+
   done:
     lock_ReleaseMutex(&scp->mx);
     lock_ReleaseWrite(&scp->bufCreateLock);
@@ -2176,7 +2190,6 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
                 cm_req_t *reqp)
 {
     long code;
-    int flags;
     AFSFetchStatus afsOutStatus;
     AFSVolSync volSync;
     cm_conn_t *connp;
@@ -2188,8 +2201,6 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
     if (attrp->mask & CM_ATTRMASK_LENGTH)
         return cm_SetLength(scp, &attrp->length, userp, reqp);
 
-    flags = CM_SCACHESYNC_STORESTATUS;
-
     lock_ObtainMutex(&scp->mx);
     /* otherwise, we have to make an RPC to get the status */
     code = cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STORESTATUS);
@@ -3511,6 +3522,8 @@ long cm_LockCheckPerms(cm_scache_t * scp,
            osi_Log0(afsd_logp, "cm_LockCheckPerms user is creator but has no INSERT bits for scp");
     }
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     osi_Log1(afsd_logp, "cm_LockCheckPerms returning code %d", code);
 
     return code;
index bf19b02..800e811 100644 (file)
@@ -41,6 +41,8 @@ long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
     if (code) 
         goto done;
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
 
@@ -98,6 +100,8 @@ long ReadData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
                 if (code) 
                     goto done;
 
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
 
                 /* otherwise, load the buffer and try again */
@@ -177,6 +181,8 @@ long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
     if (code) 
         goto done;
     
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
+
 #if 0
     /* make sure we have a writable FD */
     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
@@ -260,7 +266,12 @@ long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
                                   | CM_SCACHESYNC_BUFLOCKED);
                 if (code) 
                     goto done;
-                                
+                       
+               cm_SyncOpDone(scp, bufferp, 
+                              CM_SCACHESYNC_NEEDCALLBACK 
+                              | CM_SCACHESYNC_WRITE 
+                              | CM_SCACHESYNC_BUFLOCKED);
+
                 /* If we're overwriting the entire buffer, or
                  * if we're writing at or past EOF, mark the
                  * buffer as current so we don't call
@@ -358,8 +369,9 @@ long WriteData(cm_scache_t *scp, osi_hyper_t offset, long count, char *op,
         lock_ReleaseMutex(&scp->mx);
         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
-    }       
+    }   
 
+    /* cm_SyncOpDone is called when cm_BkgStore completes */
     return code;
 }
 
index fddf723..c1742eb 100644 (file)
@@ -184,7 +184,9 @@ void smb_ResetServerPriority()
 
 void smb_SetRequestStartTime()
 {
-    time_t * tp = malloc(sizeof(time_t));
+    time_t * tp = TlsGetValue(smb_TlsRequestSlot);
+    if (!tp)
+       tp = malloc(sizeof(time_t));
     if (tp) {
        *tp = osi_Time();
 
@@ -1051,7 +1053,16 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
     smb_tid_t *tidp;
 
     lock_ObtainWrite(&smb_rctLock);
+  retry:
     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
+       if (tidp->refCount == 0 && tidp->delete) {
+           tidp->refCount++;
+           lock_ReleaseWrite(&smb_rctLock);
+           smb_ReleaseTID(tidp);
+           lock_ObtainWrite(&smb_rctLock);
+           goto retry;
+       }
+
         if (tid == tidp->tid) {
             tidp->refCount++;
             break;
@@ -1356,6 +1367,13 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
 
   retry:
     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
+       if (fidp->refCount == 0 && fidp->delete) {
+           fidp->refCount++;
+           lock_ReleaseWrite(&smb_rctLock);
+           smb_ReleaseFID(fidp);
+           lock_ObtainWrite(&smb_rctLock);
+           goto retry;
+       }
         if (fid == fidp->fid) {
             if (newFid) {
                 fid++;
@@ -3683,6 +3701,8 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
             continue;
         }
 
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
         attr = smb_Attributes(scp);
         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
@@ -3931,6 +3951,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         return code;
     }
         
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     dirLength = scp->length;
     bufferp = NULL;
     bufferOffset.LowPart = bufferOffset.HighPart = 0;
@@ -4037,6 +4059,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                     break;
                 }
                                 
+               cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
                 if (cm_HaveBuffer(scp, bufferp, 0)) {
                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
                     break;
@@ -4212,7 +4236,10 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 
     /* release the mutex */
     lock_ReleaseMutex(&scp->mx);
-    if (bufferp) buf_Release(bufferp);
+    if (bufferp) {
+       buf_Release(bufferp);
+       bufferp = NULL;
+    }
 
     /* apply and free last set of patches; if not doing a star match, this
      * will be empty, but better safe (and freeing everything) than sorry.
@@ -4317,11 +4344,15 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     lock_ObtainMutex(&newScp->mx);
     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
-    if (code && code != CM_ERROR_NOACCESS) {
-        lock_ReleaseMutex(&newScp->mx);
-        cm_ReleaseSCache(newScp);
-        cm_ReleaseUser(userp);
-        return code;
+    if (code) {
+       if (code != CM_ERROR_NOACCESS) {
+           lock_ReleaseMutex(&newScp->mx);
+           cm_ReleaseSCache(newScp);
+           cm_ReleaseUser(userp);
+           return code;
+       }
+    } else {
+       cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     }
 
     attrs = smb_Attributes(newScp);
@@ -4410,6 +4441,8 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         return code;
     }
 
+    cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     /* Check for RO volume */
     if (newScp->flags & CM_SCACHEFLAG_RO) {
         lock_ReleaseMutex(&newScp->mx);
@@ -4529,9 +4562,10 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
                 code = CM_ERROR_NOSUCHFILE;
             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
                 cm_buf_t *bp = buf_Find(dscp, &hzero);
-                if (bp)
+                if (bp) {
                     buf_Release(bp);
-                else
+                   bp = NULL;
+               } else
                     code = CM_ERROR_NOSUCHFILE;
             }
             cm_ReleaseSCache(dscp);
@@ -4572,6 +4606,8 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         return code;
     }
 
+    cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
 #ifdef undef
     /* use smb_Attributes instead.   Also the fact that a file is 
      * in a readonly volume doesn't mean it shojuld be marked as RO 
@@ -5652,7 +5688,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
 
-        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
 
     post_syncopdone:
 
@@ -5667,16 +5703,22 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
         if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
-            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-                smb_NotifyChange(FILE_ACTION_REMOVED,
-                                 FILE_NOTIFY_CHANGE_DIR_NAME,
-                                 dscp, fullPathp, NULL, TRUE);
+           if (code == 0) {
+               scp->flags |= CM_SCACHEFLAG_DELETED;
+               if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                   smb_NotifyChange(FILE_ACTION_REMOVED,
+                                     FILE_NOTIFY_CHANGE_DIR_NAME,
+                                     dscp, fullPathp, NULL, TRUE);
+           }
         } else {
             code = cm_Unlink(dscp, fullPathp, userp, &req);
-            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-                smb_NotifyChange(FILE_ACTION_REMOVED,
-                                 FILE_NOTIFY_CHANGE_FILE_NAME,
-                                 dscp, fullPathp, NULL, TRUE);
+           if (code == 0) {                            
+               scp->flags |= CM_SCACHEFLAG_DELETED;
+               if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                   smb_NotifyChange(FILE_ACTION_REMOVED,
+                                     FILE_NOTIFY_CHANGE_FILE_NAME,
+                                     dscp, fullPathp, NULL, TRUE);
+           }
         }
         free(fullPathp);
        lock_ObtainMutex(&fidp->mx);
@@ -5760,7 +5802,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     osi_hyper_t bufferOffset;
     long bufIndex, nbytes;
     int chunk;
-    int sequential = 0;
+    int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
     cm_req_t req;
 
     cm_InitReq(&req);
@@ -5778,7 +5820,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
             fidp->prev_chunk = fidp->curr_chunk;
             fidp->curr_chunk = chunk;
         }
-        if (fidp->curr_chunk == fidp->prev_chunk + 1)
+        if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
             sequential = 1;
     }
     lock_ReleaseMutex(&fidp->mx);
@@ -5786,7 +5828,10 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) goto done;
+    if (code) 
+       goto done;
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
@@ -5842,8 +5887,11 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
                                  CM_SCACHESYNC_NEEDCALLBACK |
                                  CM_SCACHESYNC_READ);
-                if (code) goto done;
-                                
+                if (code) 
+                   goto done;
+                    
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
 
                 /* otherwise, load the buffer and try again */
@@ -5879,7 +5927,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
   done:
     lock_ReleaseMutex(&scp->mx);
-    if (bufferp) 
+    if (bufferp)
         buf_Release(bufferp);
 
     if (code == 0 && sequential)
@@ -5945,6 +5993,8 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     if (code) 
         goto done;
         
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
+
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
     minLength = fileLength;
@@ -6022,6 +6072,11 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 if (code) 
                     goto done;
 
+               cm_SyncOpDone(scp, bufferp, 
+                              CM_SCACHESYNC_NEEDCALLBACK 
+                              | CM_SCACHESYNC_WRITE 
+                              | CM_SCACHESYNC_BUFLOCKED);
+
                 /* If we're overwriting the entire buffer, or
                  * if we're writing at or past EOF, mark the
                  * buffer as current so we don't call
@@ -6126,6 +6181,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         lock_ReleaseMutex(&scp->mx);
         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
+       /* cm_SyncOpDone is called at the completion of cm_BkgStore */
     }
 
     cm_ReleaseSCache(scp);
@@ -6940,6 +6996,7 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code == 0) {
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         if (whence == 1) {
             /* offset from current offset */
             new_offset = LargeIntegerAdd(fidp->offset,
index b140539..60cadfe 100644 (file)
@@ -385,6 +385,8 @@ typedef struct smb_fid {
 #define SMB_FID_MTIMESETDONE           0x80    /* have set modtime via Tr2 */
 #define SMB_FID_LOOKSLIKECOPY  (SMB_FID_LENGTHSETDONE | SMB_FID_MTIMESETDONE)
 #define SMB_FID_NTOPEN                 0x100   /* have dscp and pathp */
+#define SMB_FID_SEQUENTIAL             0x200
+#define SMB_FID_RANDOM                 0x400
 
 #define SMB_FID_SHARE_READ              0x1000
 #define SMB_FID_SHARE_WRITE             0x2000
index 01c86e4..74f2860 100644 (file)
@@ -2806,6 +2806,8 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) goto done;
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
@@ -3081,11 +3083,13 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
-       lock_ReleaseMutex(&scp->mx);
         if (code) {
+           lock_ReleaseMutex(&scp->mx);
             goto done;
         }
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+       lock_ReleaseMutex(&scp->mx);
        lock_ObtainMutex(&fidp->mx);
        lock_ObtainMutex(&scp->mx);
 
@@ -3212,6 +3216,8 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     if (code) 
         goto done;
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
      */
@@ -3350,10 +3356,14 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
-       lock_ReleaseMutex(&scp->mx);
-        if (code)
+        if (code) {
+           lock_ReleaseMutex(&scp->mx);
             goto done;
+       }
+
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+       lock_ReleaseMutex(&scp->mx);
        lock_ObtainMutex(&fidp->mx);
        lock_ObtainMutex(&scp->mx);
 
@@ -3710,7 +3720,9 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
             }
             continue;
         }
-                
+        
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
         /* now watch for a symlink */
         code = 0;
         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
@@ -4367,6 +4379,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return code;
     }
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
   startsearch:
     dirLength = scp->length;
     bufferp = NULL;
@@ -4484,7 +4498,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
                     break;
                 }
-                                
+                       
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
                 if (cm_HaveBuffer(scp, bufferp, 0)) {
                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
                     break;
@@ -4750,8 +4766,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     /* release the mutex */
     lock_ReleaseMutex(&scp->mx);
-    if (bufferp) 
+    if (bufferp) {
         buf_Release(bufferp);
+       bufferp = NULL;
+    }
 
     /* apply and free last set of patches; if not doing a star match, this
      * will be empty, but better safe (and freeing everything) than sorry.
@@ -5471,6 +5489,8 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (code) 
        goto done;
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     /* decode times.  We need a search time, but the response to this
      * call provides the date first, not the time, as returned in the
      * searchTime variable.  So we take the high-order bits first.
@@ -6044,6 +6064,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         fidflags |= SMB_FID_OPENWRITE;
     if (createOptions & FILE_DELETE_ON_CLOSE)
         fidflags |= SMB_FID_DELONCLOSE;
+    if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
+       fidflags | SMB_FID_SEQUENTIAL;
+    if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
+       fidflags & SMB_FID_RANDOM;
 
     /* and the share mode */
     if (shareAccess & FILE_SHARE_READ)
@@ -6788,6 +6812,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         fidflags |= SMB_FID_OPENWRITE;
     if (createOptions & FILE_DELETE_ON_CLOSE)
         fidflags |= SMB_FID_DELONCLOSE;
+    if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
+       fidflags | SMB_FID_SEQUENTIAL;
+    if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
+       fidflags & SMB_FID_RANDOM;
 
     /* And the share mode */
     if (shareAccess & FILE_SHARE_READ)