]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
DEVEL15-windows-local-dir-updates-20080916
authorAsanka Herath <asanka@secure-endpoints.com>
Tue, 16 Sep 2008 12:47:47 +0000 (12:47 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 16 Sep 2008 12:47:47 +0000 (12:47 +0000)
LICENSE MIT

When a local directory update occurs to the directory pages stored
in the dcache, there is no guarrantee that the same modifications
will be made to the cached pages as are being made by the file server.
In the situation that one or more of the cached pages are recycled,
it is not permissible to obtain the missing pages from the file server
without first invalidating the rest of the cached pages.  This is
necessary to prevent mixing of incompatible data representations.

Define a new flag CM_SCACHEFLAG_LOCAL which is used to indicate that
dcache entries were locally modified even though they are not dirty.

As the previous code could have corrupted the contents of the dcache,
bump CM_CONFIG_DATA_VERSION in order to force the rebuilding of the
cache.

Add error CM_ERROR_NOTINCACHE to indicate that a requested directory
page is not present in the cache and will not be created on the fly.

Prefetch all dcache entries for directories and ensure that a consistent
set is being used.

(cherry picked from commit 1f686941197c32734acd2531a911b8e5e43cc94e)

src/WINNT/afsd/cm.h
src/WINNT/afsd/cm_dir.c
src/WINNT/afsd/cm_memmap.h
src/WINNT/afsd/cm_scache.c
src/WINNT/afsd/cm_scache.h

index 3e246fbd41cb927741403cb0feda1e89340b9998..5abf1d6aa9efe17e4d7731541a16ce0847fd9f8d 100644 (file)
@@ -99,6 +99,7 @@
 #define CM_ERROR_RANGE_NOT_LOCKED       (CM_ERROR_BASE+57)
 #define CM_ERROR_NOSUCHDEVICE           (CM_ERROR_BASE+58)
 #define CM_ERROR_LOCK_NOT_GRANTED       (CM_ERROR_BASE+59)
+#define CM_ERROR_NOTINCACHE             (CM_ERROR_BASE+60)
 
 /* Used by cm_FollowMountPoint and cm_FindVolumeByName */
 /* And as an index in cm_volume_t */
index d6f34395dc7999166fabc11845c40bf8f8508e8b..edc4fc58f1b3aa99bce09d84db13c57b2f60a5a3 100644 (file)
@@ -98,7 +98,7 @@ static int
 cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * buffer, int flags);
 
 static long
-cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked);
+cm_DirCheckStatus(cm_dirOp_t * op, int locked);
 
 static long
 cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified);
@@ -116,6 +116,8 @@ cm_DirAddPage(cm_dirOp_t * op, int pageno);
 static long
 cm_DirFreeBlobs(cm_dirOp_t * op, int firstblob, int nblobs);
 
+static long
+cm_DirPrefetchBuffers(cm_dirOp_t * op);
 
 /* compute how many 32 byte entries an AFS 3 dir requires for storing
  * the specified name.
@@ -393,6 +395,9 @@ cm_DirFindBlobs(cm_dirOp_t * op, int nblobs)
                 dhpModified = TRUE;
            }
 
+            /* the create flag is not set for the GetPage call below
+               since the page should have been added if necessary
+               above. */
             code = cm_DirGetPage(op, i, &pagebuf, &pp);
             if (code) {
                 cm_DirReleasePage(op, &dhpbuf, dhpModified);
@@ -603,6 +608,14 @@ cm_DirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
     code = cm_DirFindItem(op, entry,
                           &itembuf, &firstitem,
                           &pibuf, &previtem);
+
+    if (code == CM_ERROR_NOTINCACHE) {
+        code = cm_DirPrefetchBuffers(op);
+        if (code == 0)
+            code = cm_DirFindItem(op, entry, &itembuf, &firstitem,
+                                  &pibuf, &previtem);
+    }
+
     if (code != 0) {
         dir_lookup_misses++;
         code = ENOENT;
@@ -1121,7 +1134,7 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
 }
 
 /* Check if it is safe for us to perform local directory updates.
-   Called with scp->rw unlocked. */
+   Called with op->scp->rw unlocked. */
 int
 cm_CheckDirOpForSingleChange(cm_dirOp_t * op)
 {
@@ -1194,6 +1207,7 @@ cm_EndDirOp(cm_dirOp_t * op)
          * and update the dataVersion for each. */
         lock_ObtainWrite(&op->scp->rw);
         code = buf_ForceDataVersion(op->scp, op->dataVersion, op->newDataVersion);
+        op->scp->flags |= CM_SCACHEFLAG_LOCAL;
         lock_ReleaseWrite(&op->scp->rw);
     }
 
@@ -1270,11 +1284,7 @@ cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * bufferp)
                          (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
                          CM_SCACHESYNC_BUFLOCKED);
 
-        if (code == 0) {
-            if (bufferp->dataVersion == CM_BUF_VERSION_BAD) {
-                /* This is a new buffer */
-                bufferp->dataVersion = op->dataVersion;
-            } else if (bufferp->dataVersion != op->dataVersion) {
+        if (code == 0 && bufferp->dataVersion != op->dataVersion) {
                 osi_Log2(afsd_logp,
                          "cm_DirOpAddBuffer: buffer data version mismatch. buf dv = %d. needs %d", 
                          bufferp->dataVersion, op->dataVersion);
@@ -1284,8 +1294,7 @@ cm_DirOpAddBuffer(cm_dirOp_t * op, cm_buf_t * bufferp)
                               (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ) |
                               CM_SCACHESYNC_BUFLOCKED);
 
-                code = CM_ERROR_INVAL;
-            }
+            code = CM_ERROR_NOTINCACHE;
         }
 
         lock_ReleaseWrite(&op->scp->rw);
@@ -1447,15 +1456,15 @@ cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * bufferp, int flags)
      scp->rw may be released
  */
 static long
-cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked)
+cm_DirCheckStatus(cm_dirOp_t * op, int scp_locked)
 {
     long code;
 
-    if (!locked)
+    if (!scp_locked)
         lock_ObtainWrite(&op->scp->rw);
     code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (!locked)
+    if (!scp_locked)
         lock_ReleaseWrite(&op->scp->rw);
 
     osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x",
@@ -1464,6 +1473,92 @@ cm_DirCheckStatus(cm_dirOp_t * op, afs_uint32 locked)
     return code;
 }
 
+/* Attempt to prefetch all the buffers for this operation.
+
+   Called with scp->rw unlocked
+ */
+static long
+cm_DirPrefetchBuffers(cm_dirOp_t * op)
+{
+    long code = 0;
+    osi_hyper_t offset;
+    cm_buf_t *bufferp = NULL;
+
+    osi_Log1(afsd_logp, "cm_DirPrefetchBuffers for op 0x%p", op);
+
+    /* prefetching is only done on read operations where we don't
+       expect the data version to change. */
+    if (op->dataVersion != op->newDataVersion) {
+        osi_Log0(afsd_logp, "Skipping prefetch for write operation.");
+        return CM_ERROR_INVAL;
+    }
+
+    lock_ObtainWrite(&op->scp->rw);
+
+    /* When we are prefetching a file, we first flush out any of its
+       contents just to make sure that we don't end up with buffers
+       that was locally modified. */
+
+    if (op->scp->flags & CM_SCACHEFLAG_LOCAL) {
+        lock_ReleaseWrite(&op->scp->rw);
+        code = cm_FlushFile(op->scp, op->userp, &op->req);
+        if (code != 0)
+            return code;
+        lock_ObtainWrite(&op->scp->rw);
+    }
+
+    offset = ConvertLongToLargeInteger(0);
+    while (LargeIntegerLessThan(offset, op->scp->length)) {
+        osi_Log2(afsd_logp, "Trying prefetch for offset %08x:%08x",
+                 offset.HighPart, offset.LowPart);
+        lock_ReleaseWrite(&op->scp->rw);
+
+        code = buf_Get(op->scp, &offset, &bufferp);
+
+        lock_ObtainWrite(&op->scp->rw);
+
+        if (code)
+            break;
+
+        while (1) {
+
+            code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP,
+                             CM_SCACHESYNC_NEEDCALLBACK |
+                             (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ));
+
+            if (code)
+                break;
+
+            cm_SyncOpDone(op->scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK |
+                          (op->lockType == CM_DIRLOCK_WRITE ? CM_SCACHESYNC_WRITE : CM_SCACHESYNC_READ));
+
+            if (cm_HaveBuffer(op->scp, bufferp, 0))
+                break;
+
+            code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req);
+            if (code)
+                break;
+        }
+
+        if (code)
+            break;
+
+        if (bufferp) {
+            buf_Release(bufferp);
+            bufferp = NULL;
+        }
+
+        offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(cm_data.buf_blockSize));
+    }
+
+ done:
+    lock_ReleaseWrite(&op->scp->rw);
+
+    osi_Log1(afsd_logp, "cm_DirPrefetchBuffers returning code 0x%x", code);
+
+    return code;
+}
+
 /* Release a directory buffer that was obtained via a call to
    cm_DirGetPage() or any other function that returns a locked, held,
    directory page buffer.
@@ -1503,6 +1598,9 @@ cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified)
    released and a new buffer returned that contains the requested
    page.
 
+   If the specified page exists beyond the EOF for the scp, a new
+   buffer will be allocated only if create is set to TRUE.
+
    Note: If a buffer is specified on entry via bufferpp, it is assumed
    that the buffer is unmodified.  If the buffer is modified, it
    should be released via cm_DirReleasePage().
@@ -1583,50 +1681,6 @@ cm_DirGetPage(cm_dirOp_t * op,
             bufferp = NULL;
             goto _exit;
         }
-
-#if 0
-        /* The code below is for making sure the buffer contains
-           current data.  This is a bad idea, since the whole point of
-           doing directory updates locally is to avoid fetching all
-           the data from the server. */
-        while (1) {
-            lock_ObtainWrite(&op->scp->rw);
-            code = cm_SyncOp(op->scp, bufferp, op->userp, &op->req, PRSFS_LOOKUP,
-                             CM_SCACHESYNC_NEEDCALLBACK |
-                             CM_SCACHESYNC_READ |
-                             CM_SCACHESYNC_BUFLOCKED);
-
-            if (code) {
-                lock_ReleaseWrite(&op->scp->rw);
-                break;
-            }
-
-            cm_SyncOpDone(op->scp, bufferp,
-                          CM_SCACHESYNC_NEEDCALLBACK |
-                          CM_SCACHESYNC_READ |
-                          CM_SCACHESYNC_BUFLOCKED);
-
-            if (cm_HaveBuffer(op->scp, bufferp, 1)) {
-                lock_ReleaseWrite(&op->scp->rw);
-                break;
-            }
-
-            lock_ReleaseMutex(&bufferp->mx);
-            code = cm_GetBuffer(op->scp, bufferp, NULL, op->userp, &op->req);
-            lock_ReleaseWrite(&op->scp->rw);
-            lock_ObtainMutex(&bufferp->mx);
-
-            if (code)
-                break;
-        }
-
-        if (code) {
-            cm_DirOpDelBuffer(op, bufferp, 0);
-            buf_Release(bufferp);
-            bufferp = NULL;
-            goto _exit;
-        }
-#endif
     }
 
  _has_buffer:
index c94cda2c21d9a5f9790e19d85dd2becc513a5a35..6588928b2538b11c4edc64f9e775b708c079f9ed 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef CM_MEMMAP_H
 #define CM_MEMMAP_H 1
 
-#define CM_CONFIG_DATA_VERSION  4
+#define CM_CONFIG_DATA_VERSION  5
 #define CM_CONFIG_DATA_MAGIC            ('A' | 'F'<<8 | 'S'<<16 | CM_CONFIG_DATA_VERSION<<24)
 
 typedef struct cm_config_data {
index b3944a56d77575e3445d842bb7ef276acd15a80a..257d0f7b6da133fbdd8897b119bd01bf43f26a35 100644 (file)
@@ -1754,7 +1754,7 @@ void cm_DiscardSCache(cm_scache_t *scp)
        scp->cbServerp = NULL;
     }
     scp->cbExpires = 0;
-    scp->flags &= ~CM_SCACHEFLAG_CALLBACK;
+    scp->flags &= ~(CM_SCACHEFLAG_CALLBACK | CM_SCACHEFLAG_LOCAL);
     cm_dnlcPurgedp(scp);
     cm_dnlcPurgevp(scp);
     cm_FreeAllACLEnts(scp);
index 72f99741bd5dfbfd4cd7a49be48579210109d1b8..1a6d6c2938c282ae9a05ed094d9b7f674fe03896 100644 (file)
@@ -261,6 +261,7 @@ typedef struct cm_scache {
 
 #define CM_SCACHEFLAG_EACCESS           0x200000 /* Bulk Stat returned EACCES */
 #define CM_SCACHEFLAG_SMB_FID          0x400000
+#define CM_SCACHEFLAG_LOCAL             0x800000 /* Locally modified */
 
 /* sync flags for calls to the server.  The CM_SCACHEFLAG_FETCHING,
  * CM_SCACHEFLAG_STORING and CM_SCACHEFLAG_SIZESTORING flags correspond to the