Windows: cm_BPlusDirBuildTree can fail
authorJeffrey Altman <jaltman@secure-endpoints.com>
Sat, 5 Dec 2009 15:53:03 +0000 (10:53 -0500)
committerJeffrey Altman <jaltman|account-1000011@unknown>
Tue, 8 Dec 2009 14:29:40 +0000 (06:29 -0800)
It is possible that cm_BPlusDirBuildTree can fail.  For example,
the server could be marked down after a callback is obtained
but before all of the directory data buffers have been fetched.
cm_BeginDirOp must check for the failure, destroy the tree,
and return the failure code to the caller.  Otherwise, a tree
with no entries may be created and marked with the current
data version.

LICENSE MIT

Change-Id: I26fbfceaf68389a1906797b12721c49172b027ec
Reviewed-on: http://gerrit.openafs.org/893
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>

src/WINNT/afsd/cm_dir.c

index c28edef..ac55aed 100644 (file)
@@ -1068,24 +1068,31 @@ cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
                         lock_ReleaseWrite(&scp->rw);
                         mxheld = 0;
                     }
-                    cm_BPlusDirBuildTree(scp, userp, reqp);
+                    code = cm_BPlusDirBuildTree(scp, userp, reqp);
                     if (!mxheld) {
                         lock_ObtainWrite(&scp->rw);
                         mxheld = 1;
                     }
-                    if (op->dataVersion != scp->dataVersion) {
-                        /* We lost the race, therefore we must update the
-                         * dirop state and retry to build the tree.
-                         */
-                        op->length = scp->length;
-                        op->newLength = op->length;
-                        op->dataVersion = scp->dataVersion;
-                        op->newDataVersion = op->dataVersion;
-                        goto repeat;
+                    if (code) {
+                        bplus_free_tree++;
+                        freeBtree(scp->dirBplus);
+                        scp->dirBplus = NULL;
+                        scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
+                    } else {
+                        if (op->dataVersion != scp->dataVersion) {
+                            /* We lost the race, therefore we must update the
+                             * dirop state and retry to build the tree.
+                            */
+                            op->length = scp->length;
+                            op->newLength = op->length;
+                            op->dataVersion = scp->dataVersion;
+                            op->newDataVersion = op->dataVersion;
+                            goto repeat;
+                        }
+
+                         if (scp->dirBplus)
+                            scp->dirDataVersion = scp->dataVersion;
                     }
-
-                    if (scp->dirBplus)
-                        scp->dirDataVersion = scp->dataVersion;
                 }
             }