Allows concurrent dcache_put() calls
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 22 Jul 2014 04:49:56 +0000 (21:49 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 22 Jul 2014 04:49:56 +0000 (21:49 -0700)
Two openers could fail to find a dentry in the dcache, then get the
dentry from the FS, and then both try to insert into the dcache.  The
second one would find a non-NEGATIVE item present.  This is fine, it's
just not something dcache_put was built for at the time, hence the
assert.

kern/src/vfs.c

index 358010e..1a999d9 100644 (file)
@@ -812,8 +812,10 @@ void dcache_put(struct super_block *sb, struct dentry *key_val)
        int retval;
        spin_lock(&sb->s_dcache_lock);
        old = hashtable_remove(sb->s_dcache, key_val);
-       if (old) {
-               assert(old->d_flags & DENTRY_NEGATIVE);
+       /* if it is old and non-negative, our caller lost a race with someone else
+        * adding the dentry.  but since we yanked it out, like a bunch of idiots,
+        * we still have to put it back.  should be fairly rare. */
+       if (old && (old->d_flags & DENTRY_NEGATIVE)) {
                /* This is possible, but rare for now (about to be put on the LRU) */
                assert(!(old->d_flags & DENTRY_USED));
                assert(!kref_refcnt(&old->d_kref));