Windows: IsSpaceAvail lock order violation
authorJeffrey Altman <jaltman@your-file-system.com>
Sun, 10 Mar 2013 14:49:42 +0000 (10:49 -0400)
committerJeffrey Altman <jaltman@your-file-system.com>
Mon, 11 Mar 2013 14:05:23 +0000 (07:05 -0700)
cm_IsSpaceAvailable() obtains the cm_scache.rw lock of the volume
root directory.  Therefore it is a lock order violation to call the
function while any other cm_scache.rw lock is held belonging to an
object in the same volume.   vnode 1 is always less than any other
vnode value.

Change-Id: Id34591b6ccec8d7e8e0fe48e3357c991cd99acfb
Reviewed-on: http://gerrit.openafs.org/9552
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>

src/WINNT/afsd/cm_vnodeops.c

index 5122894..963140e 100644 (file)
@@ -2828,6 +2828,7 @@ long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
 {
     long code;
     int shrinking;
+    int available;
 
     /* start by locking out buffer creation */
     lock_ObtainWrite(&scp->bufCreateLock);
@@ -2899,9 +2900,19 @@ long cm_SetLength(cm_scache_t *scp, osi_hyper_t *sizep, cm_user_t *userp,
         scp->mask |= CM_SCACHEMASK_LENGTH;
     }
     else if (LargeIntegerGreaterThan(*sizep, scp->length)) {
-        /* really extending the file */
-        /* Check to see if we have sufficient quota */
-        if (cm_IsSpaceAvailable(&scp->fid, sizep, userp, reqp)) {
+        /*
+         * Really extending the file so must check to see if we
+         * have sufficient quota.  cm_IsSpaceAvailable() obtains
+         * the cm_scache.rw lock on the volume root directory.
+         * vnode 1 < scp->fid.vnode therefore calling cm_IsSpaceAvailable
+         * while holding scp->rw is a lock order violation.
+         * Dropping it is ok because we are holding scp->bufCreateLock
+         * which prevents the size of the file from changing.
+         */
+        lock_ReleaseWrite(&scp->rw);
+        available = cm_IsSpaceAvailable(&scp->fid, sizep, userp, reqp);
+        lock_ObtainWrite(&scp->rw);
+        if (available) {
             scp->length = *sizep;
             scp->mask |= CM_SCACHEMASK_LENGTH;
         } else {