Introduce a new lookup flag LOOKUP_DONTCACHE_NEGATIVE to skip caching negative dentry in lookup. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx> --- fs/namei.c | 14 ++++++++++---- include/linux/namei.h | 9 +++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index a320371899cf..a258f0a1d5d6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1532,6 +1532,9 @@ static struct dentry *__lookup_slow(const struct qstr *name, if (unlikely(old)) { dput(dentry); dentry = old; + } else if ((flags & LOOKUP_DONTCACHE_NEGATIVE) && + d_is_negative(dentry)) { + d_drop(dentry); } } return dentry; @@ -2554,6 +2557,7 @@ EXPORT_SYMBOL(lookup_one_len); * @name: pathname component to lookup * @base: base directory to lookup from * @len: maximum length @len should be interpreted to + * @flags: lookup flags * * Note that this routine is purely a helper for filesystem usage and should * not be called by generic code. @@ -2562,7 +2566,8 @@ EXPORT_SYMBOL(lookup_one_len); * i_mutex held, and will take the i_mutex itself if necessary. */ struct dentry *lookup_one_len_unlocked(const char *name, - struct dentry *base, int len) + struct dentry *base, int len, + unsigned int flags) { struct qstr this; int err; @@ -2574,7 +2579,7 @@ struct dentry *lookup_one_len_unlocked(const char *name, ret = lookup_dcache(&this, base, 0); if (!ret) - ret = lookup_slow(&this, base, 0); + ret = lookup_slow(&this, base, flags); return ret; } EXPORT_SYMBOL(lookup_one_len_unlocked); @@ -2588,9 +2593,10 @@ EXPORT_SYMBOL(lookup_one_len_unlocked); * this one avoids such problems. */ struct dentry *lookup_positive_unlocked(const char *name, - struct dentry *base, int len) + struct dentry *base, int len, + unsigned int flags) { - struct dentry *ret = lookup_one_len_unlocked(name, base, len); + struct dentry *ret = lookup_one_len_unlocked(name, base, len, flags); if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) { dput(ret); ret = ERR_PTR(-ENOENT); diff --git a/include/linux/namei.h b/include/linux/namei.h index a4bb992623c4..1d43fc481e47 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -49,6 +49,9 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; /* LOOKUP_* flags which do scope-related checks based on the dirfd. */ #define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT) +/* Hint: don't cache negative. */ +#define LOOKUP_DONTCACHE_NEGATIVE 0x200000 + extern int path_pts(struct path *path); extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); @@ -68,8 +71,10 @@ extern struct dentry *kern_path_locked(const char *, struct path *); extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int); extern struct dentry *lookup_one_len(const char *, struct dentry *, int); -extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int); -extern struct dentry *lookup_positive_unlocked(const char *, struct dentry *, int); +extern struct dentry *lookup_one_len_unlocked(const char *name, + struct dentry *base, int len, unsigned int flags); +extern struct dentry *lookup_positive_unlocked(const char *name, + struct dentry *base, int len, unsigned int flags); extern int follow_down_one(struct path *); extern int follow_down(struct path *); -- 2.20.1