Commit 1434a65e authored by Chengguang Xu's avatar Chengguang Xu Committed by Miklos Szeredi

ovl: drop negative dentry in upper layer

Negative dentries of upper layer are useless after construction of
overlayfs' own dentry and may keep in the memory long time even after
unmount of overlayfs instance. This patch tries to drop unnecessary
negative dentry of upper layer to effectively reclaim memory.
Signed-off-by: default avatarChengguang Xu <cgxu519@mykernel.net>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 05acefb4
...@@ -191,16 +191,36 @@ static bool ovl_is_opaquedir(struct dentry *dentry) ...@@ -191,16 +191,36 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE); return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE);
} }
static struct dentry *ovl_lookup_positive_unlocked(const char *name,
struct dentry *base, int len,
bool drop_negative)
{
struct dentry *ret = lookup_one_len_unlocked(name, base, len);
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
if (drop_negative && ret->d_lockref.count == 1) {
spin_lock(&ret->d_lock);
/* Recheck condition under lock */
if (d_is_negative(ret) && ret->d_lockref.count == 1)
__d_drop(ret);
spin_unlock(&ret->d_lock);
}
dput(ret);
ret = ERR_PTR(-ENOENT);
}
return ret;
}
static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
const char *name, unsigned int namelen, const char *name, unsigned int namelen,
size_t prelen, const char *post, size_t prelen, const char *post,
struct dentry **ret) struct dentry **ret, bool drop_negative)
{ {
struct dentry *this; struct dentry *this;
int err; int err;
bool last_element = !post[0]; bool last_element = !post[0];
this = lookup_positive_unlocked(name, base, namelen); this = ovl_lookup_positive_unlocked(name, base, namelen, drop_negative);
if (IS_ERR(this)) { if (IS_ERR(this)) {
err = PTR_ERR(this); err = PTR_ERR(this);
this = NULL; this = NULL;
...@@ -276,7 +296,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, ...@@ -276,7 +296,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
} }
static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
struct dentry **ret) struct dentry **ret, bool drop_negative)
{ {
/* Counting down from the end, since the prefix can change */ /* Counting down from the end, since the prefix can change */
size_t rem = d->name.len - 1; size_t rem = d->name.len - 1;
...@@ -285,7 +305,7 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, ...@@ -285,7 +305,7 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
if (d->name.name[0] != '/') if (d->name.name[0] != '/')
return ovl_lookup_single(base, d, d->name.name, d->name.len, return ovl_lookup_single(base, d, d->name.name, d->name.len,
0, "", ret); 0, "", ret, drop_negative);
while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) { while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
const char *s = d->name.name + d->name.len - rem; const char *s = d->name.name + d->name.len - rem;
...@@ -298,7 +318,8 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, ...@@ -298,7 +318,8 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
return -EIO; return -EIO;
err = ovl_lookup_single(base, d, s, thislen, err = ovl_lookup_single(base, d, s, thislen,
d->name.len - rem, next, &base); d->name.len - rem, next, &base,
drop_negative);
dput(dentry); dput(dentry);
if (err) if (err)
return err; return err;
...@@ -830,7 +851,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -830,7 +851,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
old_cred = ovl_override_creds(dentry->d_sb); old_cred = ovl_override_creds(dentry->d_sb);
upperdir = ovl_dentry_upper(dentry->d_parent); upperdir = ovl_dentry_upper(dentry->d_parent);
if (upperdir) { if (upperdir) {
err = ovl_lookup_layer(upperdir, &d, &upperdentry); err = ovl_lookup_layer(upperdir, &d, &upperdentry, true);
if (err) if (err)
goto out; goto out;
...@@ -888,7 +909,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -888,7 +909,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
else else
d.last = lower.layer->idx == roe->numlower; d.last = lower.layer->idx == roe->numlower;
err = ovl_lookup_layer(lower.dentry, &d, &this); err = ovl_lookup_layer(lower.dentry, &d, &this, false);
if (err) if (err)
goto out_put; goto out_put;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment