Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+28 −49
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ struct ovl_readdir_data {
	struct rb_root root;
	struct list_head *list;
	struct list_head middle;
	struct dentry *dir;
	int count;
	int err;
};
@@ -126,6 +127,32 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
	if (p == NULL)
		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);
	rb_link_node(&p->node, parent, newp);
	rb_insert_color(&p->node, &rdd->root);
@@ -231,49 +258,6 @@ static void ovl_dir_reset(struct file *file)
		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)
{
	int err;
@@ -290,15 +274,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
	ovl_path_upper(dentry, &upperpath);

	if (upperpath.dentry) {
		rdd.dir = upperpath.dentry;
		err = ovl_dir_read(&upperpath, &rdd);
		if (err)
			goto out;

		if (lowerpath.dentry) {
			err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
			if (err)
				goto out;
		}
	}
	if (lowerpath.dentry) {
		/*