int bindex;
struct dentry *lower_dentry;
- BUG_ON(!dentry || dbstart(dentry) < 0);
+ BUG_ON(!dentry);
+ /* cache coherency: check if file was deleted on lower branch */
+ if (dbstart(dentry) < 0)
+ return true;
for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
- /* XXX: what if lower_dentry is NULL? */
- if (lower_dentry && lower_dentry->d_inode)
+ /* unhashed (i.e., unlinked) lower dentries don't count */
+ if (lower_dentry && lower_dentry->d_inode &&
+ !d_deleted(lower_dentry) &&
+ !(lower_dentry->d_flags & DCACHE_NFSFS_RENAMED))
return false;
}
return true;
verify_locked(dentry);
verify_locked(dentry->d_parent);
+ sbgen = atomic_read(&UNIONFS_SB(dentry->d_sb)->generation);
/* if the dentry is unhashed, do NOT revalidate */
if (d_deleted(dentry))
goto out;
if (dentry->d_inode)
positive = 1;
dgen = atomic_read(&UNIONFS_D(dentry)->generation);
- sbgen = atomic_read(&UNIONFS_SB(dentry->d_sb)->generation);
/*
* If we are working on an unconnected dentry, then there is no
* revalidation to be done, because this file does not exist within
/* Free the pointers for our inodes and this dentry. */
bstart = dbstart(dentry);
bend = dbend(dentry);
+
+ /*
+ * mntput unhashed lower dentries, because those files got
+ * deleted or rmdir'ed.
+ */
+ for (bindex = bstart; bindex <= bend; bindex++) {
+ lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+ if (!lower_dentry)
+ continue;
+ if (!d_deleted(lower_dentry) &&
+ !(lower_dentry->d_flags & DCACHE_NFSFS_RENAMED))
+ continue;
+ unionfs_mntput(dentry, bindex);
+ }
+
__dput_lowers(dentry, bstart, bend);
dbstart(dentry) = dbend(dentry) = -1;
iput_lowers_all(dentry->d_inode, true);
}
- result = unionfs_lookup_backend(dentry, &lowernd,
- interpose_flag);
+ if (realloc_dentry_private_data(dentry) != 0) {
+ valid = false;
+ goto out;
+ }
+
+ result = unionfs_lookup_full(dentry, &lowernd, interpose_flag);
if (result) {
if (IS_ERR(result)) {
valid = false;
}
out:
+ if (valid)
+ atomic_set(&UNIONFS_D(dentry)->generation, sbgen);
+
return valid;
}
return true;
}
}
+
+ /*
+ * Last check: if this is a positive dentry, but somehow all lower
+ * dentries are negative or unhashed, then this dentry needs to be
+ * revalidated, because someone probably deleted the objects from
+ * the lower branches directly.
+ */
+ if (is_negative_lower(dentry))
+ return true;
+
return false; /* default: lower is not newer */
}