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

Commit 3e01cee3 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

ovl: check whiteout on lowest layer as well



Not checking whiteouts on lowest layer was an optimization (there's nothing
to white out there), but it could result in inconsitent behavior when a
layer previously used as upper/middle is later used as lowest. 

Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 3d3c6b89
Loading
Loading
Loading
Loading
+40 −39
Original line number Original line Diff line number Diff line
@@ -80,14 +80,17 @@ static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root,
	return NULL;
	return NULL;
}
}


static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len,
static struct ovl_cache_entry *ovl_cache_entry_new(struct dentry *dir,
						   const char *name, int len,
						   u64 ino, unsigned int d_type)
						   u64 ino, unsigned int d_type)
{
{
	struct ovl_cache_entry *p;
	struct ovl_cache_entry *p;
	size_t size = offsetof(struct ovl_cache_entry, name[len + 1]);
	size_t size = offsetof(struct ovl_cache_entry, name[len + 1]);


	p = kmalloc(size, GFP_KERNEL);
	p = kmalloc(size, GFP_KERNEL);
	if (p) {
	if (!p)
		return NULL;

	memcpy(p->name, name, len);
	memcpy(p->name, name, len);
	p->name[len] = '\0';
	p->name[len] = '\0';
	p->len = len;
	p->len = len;
@@ -95,8 +98,32 @@ static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len,
	p->ino = ino;
	p->ino = ino;
	p->is_whiteout = false;
	p->is_whiteout = false;
	p->is_cursor = false;
	p->is_cursor = false;

	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 NULL;
		}
		}


		/*
		 * 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, dir, len);
		if (!IS_ERR(dentry)) {
			p->is_whiteout = ovl_is_whiteout(dentry);
			dput(dentry);
		}
		revert_creds(old_cred);
		put_cred(override_cred);
	}
	return p;
	return p;
}
}


@@ -123,36 +150,10 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
			return 0;
			return 0;
	}
	}


	p = ovl_cache_entry_new(name, len, ino, d_type);
	p = ovl_cache_entry_new(rdd->dir, name, len, ino, d_type);
	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);
@@ -170,7 +171,7 @@ static int ovl_fill_lower(struct ovl_readdir_data *rdd,
	if (p) {
	if (p) {
		list_move_tail(&p->l_node, &rdd->middle);
		list_move_tail(&p->l_node, &rdd->middle);
	} else {
	} else {
		p = ovl_cache_entry_new(name, namelen, ino, d_type);
		p = ovl_cache_entry_new(rdd->dir, name, namelen, ino, d_type);
		if (p == NULL)
		if (p == NULL)
			rdd->err = -ENOMEM;
			rdd->err = -ENOMEM;
		else
		else
@@ -229,6 +230,7 @@ static inline int ovl_dir_read(struct path *realpath,
	if (IS_ERR(realfile))
	if (IS_ERR(realfile))
		return PTR_ERR(realfile);
		return PTR_ERR(realfile);


	rdd->dir = realpath->dentry;
	rdd->ctx.pos = 0;
	rdd->ctx.pos = 0;
	do {
	do {
		rdd->count = 0;
		rdd->count = 0;
@@ -274,7 +276,6 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
		next = ovl_path_next(idx, dentry, &realpath);
		next = ovl_path_next(idx, dentry, &realpath);


		if (next != -1) {
		if (next != -1) {
			rdd.dir = realpath.dentry;
			err = ovl_dir_read(&realpath, &rdd);
			err = ovl_dir_read(&realpath, &rdd);
			if (err)
			if (err)
				break;
				break;
+10 −17
Original line number Original line Diff line number Diff line
@@ -350,16 +350,12 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
		if (IS_ERR(this))
		if (IS_ERR(this))
			goto out;
			goto out;


		/*
		if (this) {
		 * If this is not the lowermost layer, check whiteout and opaque
		 * directory.
		 */
		if (poe->numlower && this) {
			if (ovl_is_whiteout(this)) {
			if (ovl_is_whiteout(this)) {
				dput(this);
				dput(this);
				this = NULL;
				this = NULL;
				upperopaque = true;
				upperopaque = true;
			} else if (ovl_is_opaquedir(this)) {
			} else if (poe->numlower && ovl_is_opaquedir(this)) {
				upperopaque = true;
				upperopaque = true;
			}
			}
		}
		}
@@ -384,19 +380,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
			goto out_put;
			goto out_put;
		if (!this)
		if (!this)
			continue;
			continue;

		/*
		 * If this is not the lowermost layer, check whiteout and opaque
		 * directory.
		 */
		if (i < poe->numlower - 1) {
		if (ovl_is_whiteout(this)) {
		if (ovl_is_whiteout(this)) {
			dput(this);
			dput(this);
			break;
			break;
			} else if (ovl_is_opaquedir(this)) {
				opaque = true;
			}
		}
		}
		/*
		 * Only makes sense to check opaque dir if this is not the
		 * lowermost layer.
		 */
		if (i < poe->numlower - 1 && ovl_is_opaquedir(this))
			opaque = true;
		/*
		/*
		 * If this is a non-directory then stop here.
		 * If this is a non-directory then stop here.
		 *
		 *