Commit 49c21e1c authored by Miklos Szeredi's avatar Miklos Szeredi

ovl: check whiteout while reading directory

Don't make a separate pass for checking whiteouts, since we can do it while
reading the upper directory.

This will make it easier to handle multiple layers.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent b2776bf7
...@@ -40,6 +40,7 @@ struct ovl_readdir_data { ...@@ -40,6 +40,7 @@ struct ovl_readdir_data {
struct rb_root root; struct rb_root root;
struct list_head *list; struct list_head *list;
struct list_head middle; struct list_head middle;
struct dentry *dir;
int count; int count;
int err; int err;
}; };
...@@ -126,6 +127,32 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd, ...@@ -126,6 +127,32 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
if (p == NULL) if (p == NULL)
return -ENOMEM; return -ENOMEM;
if (d_type == DT_CHR) {
struct dentry *dentry;
const struct cred *old_cred;
struct cred *override_cred;
override_cred = prepare_creds();
if (!override_cred) {
kfree(p);
return -ENOMEM;
}
/*
* CAP_DAC_OVERRIDE for lookup
*/
cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
old_cred = override_creds(override_cred);
dentry = lookup_one_len(name, rdd->dir, len);
if (!IS_ERR(dentry)) {
p->is_whiteout = ovl_is_whiteout(dentry);
dput(dentry);
}
revert_creds(old_cred);
put_cred(override_cred);
}
list_add_tail(&p->l_node, rdd->list); list_add_tail(&p->l_node, rdd->list);
rb_link_node(&p->node, parent, newp); rb_link_node(&p->node, parent, newp);
rb_insert_color(&p->node, &rdd->root); rb_insert_color(&p->node, &rdd->root);
...@@ -231,49 +258,6 @@ static void ovl_dir_reset(struct file *file) ...@@ -231,49 +258,6 @@ static void ovl_dir_reset(struct file *file)
od->is_real = false; od->is_real = false;
} }
static int ovl_dir_mark_whiteouts(struct dentry *dir,
struct ovl_readdir_data *rdd)
{
struct ovl_cache_entry *p;
struct dentry *dentry;
const struct cred *old_cred;
struct cred *override_cred;
override_cred = prepare_creds();
if (!override_cred) {
ovl_cache_free(rdd->list);
return -ENOMEM;
}
/*
* CAP_DAC_OVERRIDE for lookup
*/
cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
old_cred = override_creds(override_cred);
mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry(p, rdd->list, l_node) {
if (p->is_cursor)
continue;
if (p->type != DT_CHR)
continue;
dentry = lookup_one_len(p->name, dir, p->len);
if (IS_ERR(dentry))
continue;
p->is_whiteout = ovl_is_whiteout(dentry);
dput(dentry);
}
mutex_unlock(&dir->d_inode->i_mutex);
revert_creds(old_cred);
put_cred(override_cred);
return 0;
}
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
{ {
int err; int err;
...@@ -290,15 +274,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) ...@@ -290,15 +274,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
ovl_path_upper(dentry, &upperpath); ovl_path_upper(dentry, &upperpath);
if (upperpath.dentry) { if (upperpath.dentry) {
rdd.dir = upperpath.dentry;
err = ovl_dir_read(&upperpath, &rdd); err = ovl_dir_read(&upperpath, &rdd);
if (err) if (err)
goto out; goto out;
if (lowerpath.dentry) {
err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
if (err)
goto out;
}
} }
if (lowerpath.dentry) { if (lowerpath.dentry) {
/* /*
......
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