xref: /openbmc/linux/fs/overlayfs/namei.c (revision 4c7d0c9c)
1bbb1e54dSMiklos Szeredi /*
2bbb1e54dSMiklos Szeredi  * Copyright (C) 2011 Novell Inc.
3bbb1e54dSMiklos Szeredi  * Copyright (C) 2016 Red Hat, Inc.
4bbb1e54dSMiklos Szeredi  *
5bbb1e54dSMiklos Szeredi  * This program is free software; you can redistribute it and/or modify it
6bbb1e54dSMiklos Szeredi  * under the terms of the GNU General Public License version 2 as published by
7bbb1e54dSMiklos Szeredi  * the Free Software Foundation.
8bbb1e54dSMiklos Szeredi  */
9bbb1e54dSMiklos Szeredi 
10bbb1e54dSMiklos Szeredi #include <linux/fs.h>
11bbb1e54dSMiklos Szeredi #include <linux/namei.h>
12bbb1e54dSMiklos Szeredi #include <linux/xattr.h>
1302b69b28SMiklos Szeredi #include <linux/ratelimit.h>
14bbb1e54dSMiklos Szeredi #include "overlayfs.h"
15bbb1e54dSMiklos Szeredi #include "ovl_entry.h"
16bbb1e54dSMiklos Szeredi 
17e28edc46SMiklos Szeredi struct ovl_lookup_data {
18e28edc46SMiklos Szeredi 	struct qstr name;
19e28edc46SMiklos Szeredi 	bool is_dir;
20e28edc46SMiklos Szeredi 	bool opaque;
21e28edc46SMiklos Szeredi 	bool stop;
22e28edc46SMiklos Szeredi 	bool last;
2302b69b28SMiklos Szeredi 	char *redirect;
24e28edc46SMiklos Szeredi };
25bbb1e54dSMiklos Szeredi 
2602b69b28SMiklos Szeredi static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
2702b69b28SMiklos Szeredi 			      size_t prelen, const char *post)
2802b69b28SMiklos Szeredi {
2902b69b28SMiklos Szeredi 	int res;
3002b69b28SMiklos Szeredi 	char *s, *next, *buf = NULL;
3102b69b28SMiklos Szeredi 
3202b69b28SMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0);
3302b69b28SMiklos Szeredi 	if (res < 0) {
3402b69b28SMiklos Szeredi 		if (res == -ENODATA || res == -EOPNOTSUPP)
3502b69b28SMiklos Szeredi 			return 0;
3602b69b28SMiklos Szeredi 		goto fail;
3702b69b28SMiklos Szeredi 	}
3802b69b28SMiklos Szeredi 	buf = kzalloc(prelen + res + strlen(post) + 1, GFP_TEMPORARY);
3902b69b28SMiklos Szeredi 	if (!buf)
4002b69b28SMiklos Szeredi 		return -ENOMEM;
4102b69b28SMiklos Szeredi 
4202b69b28SMiklos Szeredi 	if (res == 0)
4302b69b28SMiklos Szeredi 		goto invalid;
4402b69b28SMiklos Szeredi 
4502b69b28SMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res);
4602b69b28SMiklos Szeredi 	if (res < 0)
4702b69b28SMiklos Szeredi 		goto fail;
4802b69b28SMiklos Szeredi 	if (res == 0)
4902b69b28SMiklos Szeredi 		goto invalid;
5002b69b28SMiklos Szeredi 	if (buf[0] == '/') {
5102b69b28SMiklos Szeredi 		for (s = buf; *s++ == '/'; s = next) {
5202b69b28SMiklos Szeredi 			next = strchrnul(s, '/');
5302b69b28SMiklos Szeredi 			if (s == next)
5402b69b28SMiklos Szeredi 				goto invalid;
5502b69b28SMiklos Szeredi 		}
5602b69b28SMiklos Szeredi 	} else {
5702b69b28SMiklos Szeredi 		if (strchr(buf, '/') != NULL)
5802b69b28SMiklos Szeredi 			goto invalid;
5902b69b28SMiklos Szeredi 
6002b69b28SMiklos Szeredi 		memmove(buf + prelen, buf, res);
6102b69b28SMiklos Szeredi 		memcpy(buf, d->name.name, prelen);
6202b69b28SMiklos Szeredi 	}
6302b69b28SMiklos Szeredi 
6402b69b28SMiklos Szeredi 	strcat(buf, post);
6502b69b28SMiklos Szeredi 	kfree(d->redirect);
6602b69b28SMiklos Szeredi 	d->redirect = buf;
6702b69b28SMiklos Szeredi 	d->name.name = d->redirect;
6802b69b28SMiklos Szeredi 	d->name.len = strlen(d->redirect);
6902b69b28SMiklos Szeredi 
7002b69b28SMiklos Szeredi 	return 0;
7102b69b28SMiklos Szeredi 
7202b69b28SMiklos Szeredi err_free:
7302b69b28SMiklos Szeredi 	kfree(buf);
7402b69b28SMiklos Szeredi 	return 0;
7502b69b28SMiklos Szeredi fail:
7602b69b28SMiklos Szeredi 	pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res);
7702b69b28SMiklos Szeredi 	goto err_free;
7802b69b28SMiklos Szeredi invalid:
7902b69b28SMiklos Szeredi 	pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf);
8002b69b28SMiklos Szeredi 	goto err_free;
8102b69b28SMiklos Szeredi }
8202b69b28SMiklos Szeredi 
83bbb1e54dSMiklos Szeredi static bool ovl_is_opaquedir(struct dentry *dentry)
84bbb1e54dSMiklos Szeredi {
85bbb1e54dSMiklos Szeredi 	int res;
86bbb1e54dSMiklos Szeredi 	char val;
87bbb1e54dSMiklos Szeredi 
88bbb1e54dSMiklos Szeredi 	if (!d_is_dir(dentry))
89bbb1e54dSMiklos Szeredi 		return false;
90bbb1e54dSMiklos Szeredi 
91bbb1e54dSMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
92bbb1e54dSMiklos Szeredi 	if (res == 1 && val == 'y')
93bbb1e54dSMiklos Szeredi 		return true;
94bbb1e54dSMiklos Szeredi 
95bbb1e54dSMiklos Szeredi 	return false;
96bbb1e54dSMiklos Szeredi }
97bbb1e54dSMiklos Szeredi 
98e28edc46SMiklos Szeredi static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
99e28edc46SMiklos Szeredi 			     const char *name, unsigned int namelen,
10002b69b28SMiklos Szeredi 			     size_t prelen, const char *post,
101e28edc46SMiklos Szeredi 			     struct dentry **ret)
102e28edc46SMiklos Szeredi {
103e28edc46SMiklos Szeredi 	struct dentry *this;
104e28edc46SMiklos Szeredi 	int err;
105e28edc46SMiklos Szeredi 
106e28edc46SMiklos Szeredi 	this = lookup_one_len_unlocked(name, base, namelen);
107e28edc46SMiklos Szeredi 	if (IS_ERR(this)) {
108e28edc46SMiklos Szeredi 		err = PTR_ERR(this);
109e28edc46SMiklos Szeredi 		this = NULL;
110e28edc46SMiklos Szeredi 		if (err == -ENOENT || err == -ENAMETOOLONG)
111e28edc46SMiklos Szeredi 			goto out;
112e28edc46SMiklos Szeredi 		goto out_err;
113e28edc46SMiklos Szeredi 	}
114e28edc46SMiklos Szeredi 	if (!this->d_inode)
115e28edc46SMiklos Szeredi 		goto put_and_out;
116e28edc46SMiklos Szeredi 
117e28edc46SMiklos Szeredi 	if (ovl_dentry_weird(this)) {
118e28edc46SMiklos Szeredi 		/* Don't support traversing automounts and other weirdness */
119e28edc46SMiklos Szeredi 		err = -EREMOTE;
120e28edc46SMiklos Szeredi 		goto out_err;
121e28edc46SMiklos Szeredi 	}
122e28edc46SMiklos Szeredi 	if (ovl_is_whiteout(this)) {
123e28edc46SMiklos Szeredi 		d->stop = d->opaque = true;
124e28edc46SMiklos Szeredi 		goto put_and_out;
125e28edc46SMiklos Szeredi 	}
126e28edc46SMiklos Szeredi 	if (!d_can_lookup(this)) {
127e28edc46SMiklos Szeredi 		d->stop = true;
128e28edc46SMiklos Szeredi 		if (d->is_dir)
129e28edc46SMiklos Szeredi 			goto put_and_out;
130e28edc46SMiklos Szeredi 		goto out;
131e28edc46SMiklos Szeredi 	}
132e28edc46SMiklos Szeredi 	d->is_dir = true;
133e28edc46SMiklos Szeredi 	if (!d->last && ovl_is_opaquedir(this)) {
134e28edc46SMiklos Szeredi 		d->stop = d->opaque = true;
135e28edc46SMiklos Szeredi 		goto out;
136e28edc46SMiklos Szeredi 	}
13702b69b28SMiklos Szeredi 	err = ovl_check_redirect(this, d, prelen, post);
13802b69b28SMiklos Szeredi 	if (err)
13902b69b28SMiklos Szeredi 		goto out_err;
140e28edc46SMiklos Szeredi out:
141e28edc46SMiklos Szeredi 	*ret = this;
142e28edc46SMiklos Szeredi 	return 0;
143e28edc46SMiklos Szeredi 
144e28edc46SMiklos Szeredi put_and_out:
145e28edc46SMiklos Szeredi 	dput(this);
146e28edc46SMiklos Szeredi 	this = NULL;
147e28edc46SMiklos Szeredi 	goto out;
148e28edc46SMiklos Szeredi 
149e28edc46SMiklos Szeredi out_err:
150e28edc46SMiklos Szeredi 	dput(this);
151e28edc46SMiklos Szeredi 	return err;
152e28edc46SMiklos Szeredi }
153e28edc46SMiklos Szeredi 
154e28edc46SMiklos Szeredi static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
155e28edc46SMiklos Szeredi 			    struct dentry **ret)
156e28edc46SMiklos Szeredi {
1574c7d0c9cSAmir Goldstein 	/* Counting down from the end, since the prefix can change */
1584c7d0c9cSAmir Goldstein 	size_t rem = d->name.len - 1;
15902b69b28SMiklos Szeredi 	struct dentry *dentry = NULL;
16002b69b28SMiklos Szeredi 	int err;
16102b69b28SMiklos Szeredi 
1624c7d0c9cSAmir Goldstein 	if (d->name.name[0] != '/')
16302b69b28SMiklos Szeredi 		return ovl_lookup_single(base, d, d->name.name, d->name.len,
16402b69b28SMiklos Szeredi 					 0, "", ret);
16502b69b28SMiklos Szeredi 
1664c7d0c9cSAmir Goldstein 	while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
1674c7d0c9cSAmir Goldstein 		const char *s = d->name.name + d->name.len - rem;
16802b69b28SMiklos Szeredi 		const char *next = strchrnul(s, '/');
1694c7d0c9cSAmir Goldstein 		size_t thislen = next - s;
1704c7d0c9cSAmir Goldstein 		bool end = !next[0];
17102b69b28SMiklos Szeredi 
1724c7d0c9cSAmir Goldstein 		/* Verify we did not go off the rails */
1734c7d0c9cSAmir Goldstein 		if (WARN_ON(s[-1] != '/'))
17402b69b28SMiklos Szeredi 			return -EIO;
17502b69b28SMiklos Szeredi 
1764c7d0c9cSAmir Goldstein 		err = ovl_lookup_single(base, d, s, thislen,
1774c7d0c9cSAmir Goldstein 					d->name.len - rem, next, &base);
17802b69b28SMiklos Szeredi 		dput(dentry);
17902b69b28SMiklos Szeredi 		if (err)
18002b69b28SMiklos Szeredi 			return err;
18102b69b28SMiklos Szeredi 		dentry = base;
1824c7d0c9cSAmir Goldstein 		if (end)
1834c7d0c9cSAmir Goldstein 			break;
1844c7d0c9cSAmir Goldstein 
1854c7d0c9cSAmir Goldstein 		rem -= thislen + 1;
1864c7d0c9cSAmir Goldstein 
1874c7d0c9cSAmir Goldstein 		if (WARN_ON(rem >= d->name.len))
1884c7d0c9cSAmir Goldstein 			return -EIO;
18902b69b28SMiklos Szeredi 	}
19002b69b28SMiklos Szeredi 	*ret = dentry;
19102b69b28SMiklos Szeredi 	return 0;
192e28edc46SMiklos Szeredi }
193e28edc46SMiklos Szeredi 
194bbb1e54dSMiklos Szeredi /*
195bbb1e54dSMiklos Szeredi  * Returns next layer in stack starting from top.
196bbb1e54dSMiklos Szeredi  * Returns -1 if this is the last layer.
197bbb1e54dSMiklos Szeredi  */
198bbb1e54dSMiklos Szeredi int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
199bbb1e54dSMiklos Szeredi {
200bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe = dentry->d_fsdata;
201bbb1e54dSMiklos Szeredi 
202bbb1e54dSMiklos Szeredi 	BUG_ON(idx < 0);
203bbb1e54dSMiklos Szeredi 	if (idx == 0) {
204bbb1e54dSMiklos Szeredi 		ovl_path_upper(dentry, path);
205bbb1e54dSMiklos Szeredi 		if (path->dentry)
206bbb1e54dSMiklos Szeredi 			return oe->numlower ? 1 : -1;
207bbb1e54dSMiklos Szeredi 		idx++;
208bbb1e54dSMiklos Szeredi 	}
209bbb1e54dSMiklos Szeredi 	BUG_ON(idx > oe->numlower);
210bbb1e54dSMiklos Szeredi 	*path = oe->lowerstack[idx - 1];
211bbb1e54dSMiklos Szeredi 
212bbb1e54dSMiklos Szeredi 	return (idx < oe->numlower) ? idx + 1 : -1;
213bbb1e54dSMiklos Szeredi }
214bbb1e54dSMiklos Szeredi 
215bbb1e54dSMiklos Szeredi struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
216bbb1e54dSMiklos Szeredi 			  unsigned int flags)
217bbb1e54dSMiklos Szeredi {
218bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe;
219bbb1e54dSMiklos Szeredi 	const struct cred *old_cred;
2206b2d5fe4SMiklos Szeredi 	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
221bbb1e54dSMiklos Szeredi 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
222bbb1e54dSMiklos Szeredi 	struct path *stack = NULL;
223bbb1e54dSMiklos Szeredi 	struct dentry *upperdir, *upperdentry = NULL;
224bbb1e54dSMiklos Szeredi 	unsigned int ctr = 0;
225bbb1e54dSMiklos Szeredi 	struct inode *inode = NULL;
226bbb1e54dSMiklos Szeredi 	bool upperopaque = false;
22702b69b28SMiklos Szeredi 	char *upperredirect = NULL;
228bbb1e54dSMiklos Szeredi 	struct dentry *this;
229bbb1e54dSMiklos Szeredi 	unsigned int i;
230bbb1e54dSMiklos Szeredi 	int err;
231e28edc46SMiklos Szeredi 	struct ovl_lookup_data d = {
232e28edc46SMiklos Szeredi 		.name = dentry->d_name,
233e28edc46SMiklos Szeredi 		.is_dir = false,
234e28edc46SMiklos Szeredi 		.opaque = false,
235e28edc46SMiklos Szeredi 		.stop = false,
236e28edc46SMiklos Szeredi 		.last = !poe->numlower,
23702b69b28SMiklos Szeredi 		.redirect = NULL,
238e28edc46SMiklos Szeredi 	};
239bbb1e54dSMiklos Szeredi 
2406b2d5fe4SMiklos Szeredi 	if (dentry->d_name.len > ofs->namelen)
2416b2d5fe4SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
2426b2d5fe4SMiklos Szeredi 
243bbb1e54dSMiklos Szeredi 	old_cred = ovl_override_creds(dentry->d_sb);
244bbb1e54dSMiklos Szeredi 	upperdir = ovl_upperdentry_dereference(poe);
245bbb1e54dSMiklos Szeredi 	if (upperdir) {
246e28edc46SMiklos Szeredi 		err = ovl_lookup_layer(upperdir, &d, &upperdentry);
247e28edc46SMiklos Szeredi 		if (err)
248bbb1e54dSMiklos Szeredi 			goto out;
249bbb1e54dSMiklos Szeredi 
250e28edc46SMiklos Szeredi 		if (upperdentry && unlikely(ovl_dentry_remote(upperdentry))) {
251e28edc46SMiklos Szeredi 			dput(upperdentry);
252bbb1e54dSMiklos Szeredi 			err = -EREMOTE;
253bbb1e54dSMiklos Szeredi 			goto out;
254bbb1e54dSMiklos Szeredi 		}
25502b69b28SMiklos Szeredi 
25602b69b28SMiklos Szeredi 		if (d.redirect) {
25702b69b28SMiklos Szeredi 			upperredirect = kstrdup(d.redirect, GFP_KERNEL);
25802b69b28SMiklos Szeredi 			if (!upperredirect)
25902b69b28SMiklos Szeredi 				goto out_put_upper;
26002b69b28SMiklos Szeredi 			if (d.redirect[0] == '/')
26102b69b28SMiklos Szeredi 				poe = dentry->d_sb->s_root->d_fsdata;
26202b69b28SMiklos Szeredi 		}
263e28edc46SMiklos Szeredi 		upperopaque = d.opaque;
264bbb1e54dSMiklos Szeredi 	}
265bbb1e54dSMiklos Szeredi 
266e28edc46SMiklos Szeredi 	if (!d.stop && poe->numlower) {
267bbb1e54dSMiklos Szeredi 		err = -ENOMEM;
26802b69b28SMiklos Szeredi 		stack = kcalloc(ofs->numlower, sizeof(struct path),
269e28edc46SMiklos Szeredi 				GFP_TEMPORARY);
270bbb1e54dSMiklos Szeredi 		if (!stack)
271bbb1e54dSMiklos Szeredi 			goto out_put_upper;
272bbb1e54dSMiklos Szeredi 	}
273bbb1e54dSMiklos Szeredi 
274e28edc46SMiklos Szeredi 	for (i = 0; !d.stop && i < poe->numlower; i++) {
275bbb1e54dSMiklos Szeredi 		struct path lowerpath = poe->lowerstack[i];
276bbb1e54dSMiklos Szeredi 
277e28edc46SMiklos Szeredi 		d.last = i == poe->numlower - 1;
278e28edc46SMiklos Szeredi 		err = ovl_lookup_layer(lowerpath.dentry, &d, &this);
279e28edc46SMiklos Szeredi 		if (err)
280bbb1e54dSMiklos Szeredi 			goto out_put;
2816b2d5fe4SMiklos Szeredi 
282bbb1e54dSMiklos Szeredi 		if (!this)
283bbb1e54dSMiklos Szeredi 			continue;
284bbb1e54dSMiklos Szeredi 
285bbb1e54dSMiklos Szeredi 		stack[ctr].dentry = this;
286bbb1e54dSMiklos Szeredi 		stack[ctr].mnt = lowerpath.mnt;
287bbb1e54dSMiklos Szeredi 		ctr++;
28802b69b28SMiklos Szeredi 
28902b69b28SMiklos Szeredi 		if (d.stop)
29002b69b28SMiklos Szeredi 			break;
29102b69b28SMiklos Szeredi 
29202b69b28SMiklos Szeredi 		if (d.redirect &&
29302b69b28SMiklos Szeredi 		    d.redirect[0] == '/' &&
29402b69b28SMiklos Szeredi 		    poe != dentry->d_sb->s_root->d_fsdata) {
29502b69b28SMiklos Szeredi 			poe = dentry->d_sb->s_root->d_fsdata;
29602b69b28SMiklos Szeredi 
29702b69b28SMiklos Szeredi 			/* Find the current layer on the root dentry */
29802b69b28SMiklos Szeredi 			for (i = 0; i < poe->numlower; i++)
29902b69b28SMiklos Szeredi 				if (poe->lowerstack[i].mnt == lowerpath.mnt)
30002b69b28SMiklos Szeredi 					break;
30102b69b28SMiklos Szeredi 			if (WARN_ON(i == poe->numlower))
30202b69b28SMiklos Szeredi 				break;
30302b69b28SMiklos Szeredi 		}
304bbb1e54dSMiklos Szeredi 	}
305bbb1e54dSMiklos Szeredi 
306bbb1e54dSMiklos Szeredi 	oe = ovl_alloc_entry(ctr);
307bbb1e54dSMiklos Szeredi 	err = -ENOMEM;
308bbb1e54dSMiklos Szeredi 	if (!oe)
309bbb1e54dSMiklos Szeredi 		goto out_put;
310bbb1e54dSMiklos Szeredi 
311bbb1e54dSMiklos Szeredi 	if (upperdentry || ctr) {
312bbb1e54dSMiklos Szeredi 		struct dentry *realdentry;
313bbb1e54dSMiklos Szeredi 		struct inode *realinode;
314bbb1e54dSMiklos Szeredi 
315bbb1e54dSMiklos Szeredi 		realdentry = upperdentry ? upperdentry : stack[0].dentry;
316bbb1e54dSMiklos Szeredi 		realinode = d_inode(realdentry);
317bbb1e54dSMiklos Szeredi 
318bbb1e54dSMiklos Szeredi 		err = -ENOMEM;
319bbb1e54dSMiklos Szeredi 		if (upperdentry && !d_is_dir(upperdentry)) {
320bbb1e54dSMiklos Szeredi 			inode = ovl_get_inode(dentry->d_sb, realinode);
321bbb1e54dSMiklos Szeredi 		} else {
322bbb1e54dSMiklos Szeredi 			inode = ovl_new_inode(dentry->d_sb, realinode->i_mode,
323bbb1e54dSMiklos Szeredi 					      realinode->i_rdev);
324bbb1e54dSMiklos Szeredi 			if (inode)
325bbb1e54dSMiklos Szeredi 				ovl_inode_init(inode, realinode, !!upperdentry);
326bbb1e54dSMiklos Szeredi 		}
327bbb1e54dSMiklos Szeredi 		if (!inode)
328bbb1e54dSMiklos Szeredi 			goto out_free_oe;
329bbb1e54dSMiklos Szeredi 		ovl_copyattr(realdentry->d_inode, inode);
330bbb1e54dSMiklos Szeredi 	}
331bbb1e54dSMiklos Szeredi 
332bbb1e54dSMiklos Szeredi 	revert_creds(old_cred);
333bbb1e54dSMiklos Szeredi 	oe->opaque = upperopaque;
33402b69b28SMiklos Szeredi 	oe->redirect = upperredirect;
335bbb1e54dSMiklos Szeredi 	oe->__upperdentry = upperdentry;
336bbb1e54dSMiklos Szeredi 	memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
337bbb1e54dSMiklos Szeredi 	kfree(stack);
33802b69b28SMiklos Szeredi 	kfree(d.redirect);
339bbb1e54dSMiklos Szeredi 	dentry->d_fsdata = oe;
340bbb1e54dSMiklos Szeredi 	d_add(dentry, inode);
341bbb1e54dSMiklos Szeredi 
342bbb1e54dSMiklos Szeredi 	return NULL;
343bbb1e54dSMiklos Szeredi 
344bbb1e54dSMiklos Szeredi out_free_oe:
345bbb1e54dSMiklos Szeredi 	kfree(oe);
346bbb1e54dSMiklos Szeredi out_put:
347bbb1e54dSMiklos Szeredi 	for (i = 0; i < ctr; i++)
348bbb1e54dSMiklos Szeredi 		dput(stack[i].dentry);
349bbb1e54dSMiklos Szeredi 	kfree(stack);
350bbb1e54dSMiklos Szeredi out_put_upper:
351bbb1e54dSMiklos Szeredi 	dput(upperdentry);
35202b69b28SMiklos Szeredi 	kfree(upperredirect);
353bbb1e54dSMiklos Szeredi out:
35402b69b28SMiklos Szeredi 	kfree(d.redirect);
355bbb1e54dSMiklos Szeredi 	revert_creds(old_cred);
356bbb1e54dSMiklos Szeredi 	return ERR_PTR(err);
357bbb1e54dSMiklos Szeredi }
358bbb1e54dSMiklos Szeredi 
359bbb1e54dSMiklos Szeredi bool ovl_lower_positive(struct dentry *dentry)
360bbb1e54dSMiklos Szeredi {
361bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe = dentry->d_fsdata;
362bbb1e54dSMiklos Szeredi 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
363bbb1e54dSMiklos Szeredi 	const struct qstr *name = &dentry->d_name;
364bbb1e54dSMiklos Szeredi 	unsigned int i;
365bbb1e54dSMiklos Szeredi 	bool positive = false;
366bbb1e54dSMiklos Szeredi 	bool done = false;
367bbb1e54dSMiklos Szeredi 
368bbb1e54dSMiklos Szeredi 	/*
369bbb1e54dSMiklos Szeredi 	 * If dentry is negative, then lower is positive iff this is a
370bbb1e54dSMiklos Szeredi 	 * whiteout.
371bbb1e54dSMiklos Szeredi 	 */
372bbb1e54dSMiklos Szeredi 	if (!dentry->d_inode)
373bbb1e54dSMiklos Szeredi 		return oe->opaque;
374bbb1e54dSMiklos Szeredi 
375bbb1e54dSMiklos Szeredi 	/* Negative upper -> positive lower */
376bbb1e54dSMiklos Szeredi 	if (!oe->__upperdentry)
377bbb1e54dSMiklos Szeredi 		return true;
378bbb1e54dSMiklos Szeredi 
379bbb1e54dSMiklos Szeredi 	/* Positive upper -> have to look up lower to see whether it exists */
380bbb1e54dSMiklos Szeredi 	for (i = 0; !done && !positive && i < poe->numlower; i++) {
381bbb1e54dSMiklos Szeredi 		struct dentry *this;
382bbb1e54dSMiklos Szeredi 		struct dentry *lowerdir = poe->lowerstack[i].dentry;
383bbb1e54dSMiklos Szeredi 
384bbb1e54dSMiklos Szeredi 		this = lookup_one_len_unlocked(name->name, lowerdir,
385bbb1e54dSMiklos Szeredi 					       name->len);
386bbb1e54dSMiklos Szeredi 		if (IS_ERR(this)) {
387bbb1e54dSMiklos Szeredi 			switch (PTR_ERR(this)) {
388bbb1e54dSMiklos Szeredi 			case -ENOENT:
389bbb1e54dSMiklos Szeredi 			case -ENAMETOOLONG:
390bbb1e54dSMiklos Szeredi 				break;
391bbb1e54dSMiklos Szeredi 
392bbb1e54dSMiklos Szeredi 			default:
393bbb1e54dSMiklos Szeredi 				/*
394bbb1e54dSMiklos Szeredi 				 * Assume something is there, we just couldn't
395bbb1e54dSMiklos Szeredi 				 * access it.
396bbb1e54dSMiklos Szeredi 				 */
397bbb1e54dSMiklos Szeredi 				positive = true;
398bbb1e54dSMiklos Szeredi 				break;
399bbb1e54dSMiklos Szeredi 			}
400bbb1e54dSMiklos Szeredi 		} else {
401bbb1e54dSMiklos Szeredi 			if (this->d_inode) {
402bbb1e54dSMiklos Szeredi 				positive = !ovl_is_whiteout(this);
403bbb1e54dSMiklos Szeredi 				done = true;
404bbb1e54dSMiklos Szeredi 			}
405bbb1e54dSMiklos Szeredi 			dput(this);
406bbb1e54dSMiklos Szeredi 		}
407bbb1e54dSMiklos Szeredi 	}
408bbb1e54dSMiklos Szeredi 
409bbb1e54dSMiklos Szeredi 	return positive;
410bbb1e54dSMiklos Szeredi }
411