mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
ceph: do not cache negative dentries for snapped directories
When a LOOKUP/LOOKUPSNAP in a snapped directory returns ENOENT without a trace, ceph_finish_lookup() creates a negative dentry via d_add(dentry, NULL). For live directories this is fine — the dentry naturally expires. But for snapped directories, ceph_d_revalidate() unconditionally trusts all cached dentries (valid = 1), so a negative dentry created by a transient error persists forever, hiding entries that genuinely exist in the snapshot. Only cache negative dentries for live (non-snapshotted) parent directories. For snapped parents, skip the negative dentry so that VFS retries the lookup on the next access. Since the conditions that trigger a negative dentry (MDS transient error, local ENOENT shortcut, or MDS null dentry lease) are all rare in snapped directories, the performance impact of this change is negligible. Link: https://tracker.ceph.com/issues/78529 Reported-by: Andras Pataki <apataki@flatironinstitute.org> Signed-off-by: Xiubo Li <xiubo.li@clyso.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
@@ -774,8 +774,13 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
|
||||
d_drop(dentry);
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
if (d_unhashed(dentry))
|
||||
d_add(dentry, NULL);
|
||||
if (d_unhashed(dentry)) {
|
||||
struct inode *parent =
|
||||
d_inode(dentry->d_parent);
|
||||
if (!parent ||
|
||||
ceph_snap(parent) == CEPH_NOSNAP)
|
||||
d_add(dentry, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,6 +845,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
||||
dentry->d_name.len) &&
|
||||
!is_root_ceph_dentry(dir, dentry) &&
|
||||
ceph_test_mount_opt(fsc, DCACHE) &&
|
||||
ceph_snap(dir) == CEPH_NOSNAP &&
|
||||
__ceph_dir_is_complete(ci) &&
|
||||
__ceph_caps_issued_mask_metric(ci, CEPH_CAP_FILE_SHARED, 1)) {
|
||||
__ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD);
|
||||
|
||||
@@ -1814,7 +1814,8 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
|
||||
ceph_dir_clear_ordered(dir);
|
||||
d_delete(dn);
|
||||
} else if (have_lease) {
|
||||
if (d_unhashed(dn))
|
||||
if (d_unhashed(dn) &&
|
||||
ceph_snap(dir) == CEPH_NOSNAP)
|
||||
d_add(dn, NULL);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user