afs: Avoid unnecessary panic in ShakeLooseVCaches
authorAndrew Deason <adeason@sinenomine.net>
Fri, 28 Dec 2012 21:39:15 +0000 (16:39 -0500)
committerDerrick Brashear <shadow@your-file-system.com>
Mon, 31 Dec 2012 14:54:59 +0000 (06:54 -0800)
afs_vcount can change as we traverse the loop. If we successfully
evict something from the cache, afs_vcount goes down, but our loop
variable 'i' stays incremented. For example, if afs_vcount was 100 at
the start of the loop and we kicked out 50 things, by the time we
traverse the entire VLRU, we could have iterated over the loop 100
times, but afs_vcount would still be just at 50.

So, remember what afs_vcount was at the start of the loop, and use
that for our loop limit. Note that vcaches cannot be added to the VLRU
during the execution of this loop, since we're just kicking stuff out.
And nobody else can modify the VLRU but us, since we're holding
afs_xvcache, and if we drop afs_xvcache, we restart the whole eviction
process.

The bug here was introduced by commit bc6dd950, but usually did not
affect Linux until commit 696db866.

FIXES 131553

Change-Id: If30026b5b2101559e704d0e1961effe14beb915f
Reviewed-on: http://gerrit.openafs.org/8849
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Chas Williams - CONTRACTOR <chas@cmf.nrl.navy.mil>
Reviewed-by: Derrick Brashear <shadow@your-file-system.com>

src/afs/afs_vcache.c

index 21c49f8..c79309b 100644 (file)
@@ -707,18 +707,20 @@ afs_ShakeLooseVCaches(afs_int32 anumber)
     struct vcache *tvc;
     struct afs_q *tq, *uq;
     int fv_slept, defersleep = 0;
+    int limit;
     afs_int32 target = anumber;
 
     loop = 0;
 
  retry:
     i = 0;
+    limit = afs_vcount;
     for (tq = VLRU.prev; tq != &VLRU && anumber > 0; tq = uq) {
        tvc = QTOV(tq);
        uq = QPrev(tq);
        if (tvc->f.states & CVFlushed) {
            refpanic("CVFlushed on VLRU");
-       } else if (i++ > afs_vcount) {
+       } else if (i++ > limit) {
            refpanic("Found too many AFS vnodes on VLRU (VLRU cycle?)");
        } else if (QNext(uq) != tq) {
            refpanic("VLRU inconsistent");