xref: /openbmc/linux/fs/overlayfs/inode.c (revision e9be9d5e76e34872f0c37d72e25bc27fe9e2c54c)
1*e9be9d5eSMiklos Szeredi /*
2*e9be9d5eSMiklos Szeredi  *
3*e9be9d5eSMiklos Szeredi  * Copyright (C) 2011 Novell Inc.
4*e9be9d5eSMiklos Szeredi  *
5*e9be9d5eSMiklos Szeredi  * This program is free software; you can redistribute it and/or modify it
6*e9be9d5eSMiklos Szeredi  * under the terms of the GNU General Public License version 2 as published by
7*e9be9d5eSMiklos Szeredi  * the Free Software Foundation.
8*e9be9d5eSMiklos Szeredi  */
9*e9be9d5eSMiklos Szeredi 
10*e9be9d5eSMiklos Szeredi #include <linux/fs.h>
11*e9be9d5eSMiklos Szeredi #include <linux/slab.h>
12*e9be9d5eSMiklos Szeredi #include <linux/xattr.h>
13*e9be9d5eSMiklos Szeredi #include "overlayfs.h"
14*e9be9d5eSMiklos Szeredi 
15*e9be9d5eSMiklos Szeredi static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr,
16*e9be9d5eSMiklos Szeredi 			    bool no_data)
17*e9be9d5eSMiklos Szeredi {
18*e9be9d5eSMiklos Szeredi 	int err;
19*e9be9d5eSMiklos Szeredi 	struct dentry *parent;
20*e9be9d5eSMiklos Szeredi 	struct kstat stat;
21*e9be9d5eSMiklos Szeredi 	struct path lowerpath;
22*e9be9d5eSMiklos Szeredi 
23*e9be9d5eSMiklos Szeredi 	parent = dget_parent(dentry);
24*e9be9d5eSMiklos Szeredi 	err = ovl_copy_up(parent);
25*e9be9d5eSMiklos Szeredi 	if (err)
26*e9be9d5eSMiklos Szeredi 		goto out_dput_parent;
27*e9be9d5eSMiklos Szeredi 
28*e9be9d5eSMiklos Szeredi 	ovl_path_lower(dentry, &lowerpath);
29*e9be9d5eSMiklos Szeredi 	err = vfs_getattr(&lowerpath, &stat);
30*e9be9d5eSMiklos Szeredi 	if (err)
31*e9be9d5eSMiklos Szeredi 		goto out_dput_parent;
32*e9be9d5eSMiklos Szeredi 
33*e9be9d5eSMiklos Szeredi 	if (no_data)
34*e9be9d5eSMiklos Szeredi 		stat.size = 0;
35*e9be9d5eSMiklos Szeredi 
36*e9be9d5eSMiklos Szeredi 	err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat, attr);
37*e9be9d5eSMiklos Szeredi 
38*e9be9d5eSMiklos Szeredi out_dput_parent:
39*e9be9d5eSMiklos Szeredi 	dput(parent);
40*e9be9d5eSMiklos Szeredi 	return err;
41*e9be9d5eSMiklos Szeredi }
42*e9be9d5eSMiklos Szeredi 
43*e9be9d5eSMiklos Szeredi int ovl_setattr(struct dentry *dentry, struct iattr *attr)
44*e9be9d5eSMiklos Szeredi {
45*e9be9d5eSMiklos Szeredi 	int err;
46*e9be9d5eSMiklos Szeredi 	struct dentry *upperdentry;
47*e9be9d5eSMiklos Szeredi 
48*e9be9d5eSMiklos Szeredi 	err = ovl_want_write(dentry);
49*e9be9d5eSMiklos Szeredi 	if (err)
50*e9be9d5eSMiklos Szeredi 		goto out;
51*e9be9d5eSMiklos Szeredi 
52*e9be9d5eSMiklos Szeredi 	upperdentry = ovl_dentry_upper(dentry);
53*e9be9d5eSMiklos Szeredi 	if (upperdentry) {
54*e9be9d5eSMiklos Szeredi 		mutex_lock(&upperdentry->d_inode->i_mutex);
55*e9be9d5eSMiklos Szeredi 		err = notify_change(upperdentry, attr, NULL);
56*e9be9d5eSMiklos Szeredi 		mutex_unlock(&upperdentry->d_inode->i_mutex);
57*e9be9d5eSMiklos Szeredi 	} else {
58*e9be9d5eSMiklos Szeredi 		err = ovl_copy_up_last(dentry, attr, false);
59*e9be9d5eSMiklos Szeredi 	}
60*e9be9d5eSMiklos Szeredi 	ovl_drop_write(dentry);
61*e9be9d5eSMiklos Szeredi out:
62*e9be9d5eSMiklos Szeredi 	return err;
63*e9be9d5eSMiklos Szeredi }
64*e9be9d5eSMiklos Szeredi 
65*e9be9d5eSMiklos Szeredi static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
66*e9be9d5eSMiklos Szeredi 			 struct kstat *stat)
67*e9be9d5eSMiklos Szeredi {
68*e9be9d5eSMiklos Szeredi 	struct path realpath;
69*e9be9d5eSMiklos Szeredi 
70*e9be9d5eSMiklos Szeredi 	ovl_path_real(dentry, &realpath);
71*e9be9d5eSMiklos Szeredi 	return vfs_getattr(&realpath, stat);
72*e9be9d5eSMiklos Szeredi }
73*e9be9d5eSMiklos Szeredi 
74*e9be9d5eSMiklos Szeredi int ovl_permission(struct inode *inode, int mask)
75*e9be9d5eSMiklos Szeredi {
76*e9be9d5eSMiklos Szeredi 	struct ovl_entry *oe;
77*e9be9d5eSMiklos Szeredi 	struct dentry *alias = NULL;
78*e9be9d5eSMiklos Szeredi 	struct inode *realinode;
79*e9be9d5eSMiklos Szeredi 	struct dentry *realdentry;
80*e9be9d5eSMiklos Szeredi 	bool is_upper;
81*e9be9d5eSMiklos Szeredi 	int err;
82*e9be9d5eSMiklos Szeredi 
83*e9be9d5eSMiklos Szeredi 	if (S_ISDIR(inode->i_mode)) {
84*e9be9d5eSMiklos Szeredi 		oe = inode->i_private;
85*e9be9d5eSMiklos Szeredi 	} else if (mask & MAY_NOT_BLOCK) {
86*e9be9d5eSMiklos Szeredi 		return -ECHILD;
87*e9be9d5eSMiklos Szeredi 	} else {
88*e9be9d5eSMiklos Szeredi 		/*
89*e9be9d5eSMiklos Szeredi 		 * For non-directories find an alias and get the info
90*e9be9d5eSMiklos Szeredi 		 * from there.
91*e9be9d5eSMiklos Szeredi 		 */
92*e9be9d5eSMiklos Szeredi 		alias = d_find_any_alias(inode);
93*e9be9d5eSMiklos Szeredi 		if (WARN_ON(!alias))
94*e9be9d5eSMiklos Szeredi 			return -ENOENT;
95*e9be9d5eSMiklos Szeredi 
96*e9be9d5eSMiklos Szeredi 		oe = alias->d_fsdata;
97*e9be9d5eSMiklos Szeredi 	}
98*e9be9d5eSMiklos Szeredi 
99*e9be9d5eSMiklos Szeredi 	realdentry = ovl_entry_real(oe, &is_upper);
100*e9be9d5eSMiklos Szeredi 
101*e9be9d5eSMiklos Szeredi 	/* Careful in RCU walk mode */
102*e9be9d5eSMiklos Szeredi 	realinode = ACCESS_ONCE(realdentry->d_inode);
103*e9be9d5eSMiklos Szeredi 	if (!realinode) {
104*e9be9d5eSMiklos Szeredi 		WARN_ON(!(mask & MAY_NOT_BLOCK));
105*e9be9d5eSMiklos Szeredi 		err = -ENOENT;
106*e9be9d5eSMiklos Szeredi 		goto out_dput;
107*e9be9d5eSMiklos Szeredi 	}
108*e9be9d5eSMiklos Szeredi 
109*e9be9d5eSMiklos Szeredi 	if (mask & MAY_WRITE) {
110*e9be9d5eSMiklos Szeredi 		umode_t mode = realinode->i_mode;
111*e9be9d5eSMiklos Szeredi 
112*e9be9d5eSMiklos Szeredi 		/*
113*e9be9d5eSMiklos Szeredi 		 * Writes will always be redirected to upper layer, so
114*e9be9d5eSMiklos Szeredi 		 * ignore lower layer being read-only.
115*e9be9d5eSMiklos Szeredi 		 *
116*e9be9d5eSMiklos Szeredi 		 * If the overlay itself is read-only then proceed
117*e9be9d5eSMiklos Szeredi 		 * with the permission check, don't return EROFS.
118*e9be9d5eSMiklos Szeredi 		 * This will only happen if this is the lower layer of
119*e9be9d5eSMiklos Szeredi 		 * another overlayfs.
120*e9be9d5eSMiklos Szeredi 		 *
121*e9be9d5eSMiklos Szeredi 		 * If upper fs becomes read-only after the overlay was
122*e9be9d5eSMiklos Szeredi 		 * constructed return EROFS to prevent modification of
123*e9be9d5eSMiklos Szeredi 		 * upper layer.
124*e9be9d5eSMiklos Szeredi 		 */
125*e9be9d5eSMiklos Szeredi 		err = -EROFS;
126*e9be9d5eSMiklos Szeredi 		if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) &&
127*e9be9d5eSMiklos Szeredi 		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
128*e9be9d5eSMiklos Szeredi 			goto out_dput;
129*e9be9d5eSMiklos Szeredi 	}
130*e9be9d5eSMiklos Szeredi 
131*e9be9d5eSMiklos Szeredi 	err = __inode_permission(realinode, mask);
132*e9be9d5eSMiklos Szeredi out_dput:
133*e9be9d5eSMiklos Szeredi 	dput(alias);
134*e9be9d5eSMiklos Szeredi 	return err;
135*e9be9d5eSMiklos Szeredi }
136*e9be9d5eSMiklos Szeredi 
137*e9be9d5eSMiklos Szeredi 
138*e9be9d5eSMiklos Szeredi struct ovl_link_data {
139*e9be9d5eSMiklos Szeredi 	struct dentry *realdentry;
140*e9be9d5eSMiklos Szeredi 	void *cookie;
141*e9be9d5eSMiklos Szeredi };
142*e9be9d5eSMiklos Szeredi 
143*e9be9d5eSMiklos Szeredi static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
144*e9be9d5eSMiklos Szeredi {
145*e9be9d5eSMiklos Szeredi 	void *ret;
146*e9be9d5eSMiklos Szeredi 	struct dentry *realdentry;
147*e9be9d5eSMiklos Szeredi 	struct inode *realinode;
148*e9be9d5eSMiklos Szeredi 
149*e9be9d5eSMiklos Szeredi 	realdentry = ovl_dentry_real(dentry);
150*e9be9d5eSMiklos Szeredi 	realinode = realdentry->d_inode;
151*e9be9d5eSMiklos Szeredi 
152*e9be9d5eSMiklos Szeredi 	if (WARN_ON(!realinode->i_op->follow_link))
153*e9be9d5eSMiklos Szeredi 		return ERR_PTR(-EPERM);
154*e9be9d5eSMiklos Szeredi 
155*e9be9d5eSMiklos Szeredi 	ret = realinode->i_op->follow_link(realdentry, nd);
156*e9be9d5eSMiklos Szeredi 	if (IS_ERR(ret))
157*e9be9d5eSMiklos Szeredi 		return ret;
158*e9be9d5eSMiklos Szeredi 
159*e9be9d5eSMiklos Szeredi 	if (realinode->i_op->put_link) {
160*e9be9d5eSMiklos Szeredi 		struct ovl_link_data *data;
161*e9be9d5eSMiklos Szeredi 
162*e9be9d5eSMiklos Szeredi 		data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
163*e9be9d5eSMiklos Szeredi 		if (!data) {
164*e9be9d5eSMiklos Szeredi 			realinode->i_op->put_link(realdentry, nd, ret);
165*e9be9d5eSMiklos Szeredi 			return ERR_PTR(-ENOMEM);
166*e9be9d5eSMiklos Szeredi 		}
167*e9be9d5eSMiklos Szeredi 		data->realdentry = realdentry;
168*e9be9d5eSMiklos Szeredi 		data->cookie = ret;
169*e9be9d5eSMiklos Szeredi 
170*e9be9d5eSMiklos Szeredi 		return data;
171*e9be9d5eSMiklos Szeredi 	} else {
172*e9be9d5eSMiklos Szeredi 		return NULL;
173*e9be9d5eSMiklos Szeredi 	}
174*e9be9d5eSMiklos Szeredi }
175*e9be9d5eSMiklos Szeredi 
176*e9be9d5eSMiklos Szeredi static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
177*e9be9d5eSMiklos Szeredi {
178*e9be9d5eSMiklos Szeredi 	struct inode *realinode;
179*e9be9d5eSMiklos Szeredi 	struct ovl_link_data *data = c;
180*e9be9d5eSMiklos Szeredi 
181*e9be9d5eSMiklos Szeredi 	if (!data)
182*e9be9d5eSMiklos Szeredi 		return;
183*e9be9d5eSMiklos Szeredi 
184*e9be9d5eSMiklos Szeredi 	realinode = data->realdentry->d_inode;
185*e9be9d5eSMiklos Szeredi 	realinode->i_op->put_link(data->realdentry, nd, data->cookie);
186*e9be9d5eSMiklos Szeredi 	kfree(data);
187*e9be9d5eSMiklos Szeredi }
188*e9be9d5eSMiklos Szeredi 
189*e9be9d5eSMiklos Szeredi static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
190*e9be9d5eSMiklos Szeredi {
191*e9be9d5eSMiklos Szeredi 	struct path realpath;
192*e9be9d5eSMiklos Szeredi 	struct inode *realinode;
193*e9be9d5eSMiklos Szeredi 
194*e9be9d5eSMiklos Szeredi 	ovl_path_real(dentry, &realpath);
195*e9be9d5eSMiklos Szeredi 	realinode = realpath.dentry->d_inode;
196*e9be9d5eSMiklos Szeredi 
197*e9be9d5eSMiklos Szeredi 	if (!realinode->i_op->readlink)
198*e9be9d5eSMiklos Szeredi 		return -EINVAL;
199*e9be9d5eSMiklos Szeredi 
200*e9be9d5eSMiklos Szeredi 	touch_atime(&realpath);
201*e9be9d5eSMiklos Szeredi 
202*e9be9d5eSMiklos Szeredi 	return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
203*e9be9d5eSMiklos Szeredi }
204*e9be9d5eSMiklos Szeredi 
205*e9be9d5eSMiklos Szeredi 
206*e9be9d5eSMiklos Szeredi static bool ovl_is_private_xattr(const char *name)
207*e9be9d5eSMiklos Szeredi {
208*e9be9d5eSMiklos Szeredi 	return strncmp(name, "trusted.overlay.", 14) == 0;
209*e9be9d5eSMiklos Szeredi }
210*e9be9d5eSMiklos Szeredi 
211*e9be9d5eSMiklos Szeredi int ovl_setxattr(struct dentry *dentry, const char *name,
212*e9be9d5eSMiklos Szeredi 		 const void *value, size_t size, int flags)
213*e9be9d5eSMiklos Szeredi {
214*e9be9d5eSMiklos Szeredi 	int err;
215*e9be9d5eSMiklos Szeredi 	struct dentry *upperdentry;
216*e9be9d5eSMiklos Szeredi 
217*e9be9d5eSMiklos Szeredi 	err = ovl_want_write(dentry);
218*e9be9d5eSMiklos Szeredi 	if (err)
219*e9be9d5eSMiklos Szeredi 		goto out;
220*e9be9d5eSMiklos Szeredi 
221*e9be9d5eSMiklos Szeredi 	err = -EPERM;
222*e9be9d5eSMiklos Szeredi 	if (ovl_is_private_xattr(name))
223*e9be9d5eSMiklos Szeredi 		goto out_drop_write;
224*e9be9d5eSMiklos Szeredi 
225*e9be9d5eSMiklos Szeredi 	err = ovl_copy_up(dentry);
226*e9be9d5eSMiklos Szeredi 	if (err)
227*e9be9d5eSMiklos Szeredi 		goto out_drop_write;
228*e9be9d5eSMiklos Szeredi 
229*e9be9d5eSMiklos Szeredi 	upperdentry = ovl_dentry_upper(dentry);
230*e9be9d5eSMiklos Szeredi 	err = vfs_setxattr(upperdentry, name, value, size, flags);
231*e9be9d5eSMiklos Szeredi 
232*e9be9d5eSMiklos Szeredi out_drop_write:
233*e9be9d5eSMiklos Szeredi 	ovl_drop_write(dentry);
234*e9be9d5eSMiklos Szeredi out:
235*e9be9d5eSMiklos Szeredi 	return err;
236*e9be9d5eSMiklos Szeredi }
237*e9be9d5eSMiklos Szeredi 
238*e9be9d5eSMiklos Szeredi ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
239*e9be9d5eSMiklos Szeredi 		     void *value, size_t size)
240*e9be9d5eSMiklos Szeredi {
241*e9be9d5eSMiklos Szeredi 	if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
242*e9be9d5eSMiklos Szeredi 	    ovl_is_private_xattr(name))
243*e9be9d5eSMiklos Szeredi 		return -ENODATA;
244*e9be9d5eSMiklos Szeredi 
245*e9be9d5eSMiklos Szeredi 	return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
246*e9be9d5eSMiklos Szeredi }
247*e9be9d5eSMiklos Szeredi 
248*e9be9d5eSMiklos Szeredi ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
249*e9be9d5eSMiklos Szeredi {
250*e9be9d5eSMiklos Szeredi 	ssize_t res;
251*e9be9d5eSMiklos Szeredi 	int off;
252*e9be9d5eSMiklos Szeredi 
253*e9be9d5eSMiklos Szeredi 	res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
254*e9be9d5eSMiklos Szeredi 	if (res <= 0 || size == 0)
255*e9be9d5eSMiklos Szeredi 		return res;
256*e9be9d5eSMiklos Szeredi 
257*e9be9d5eSMiklos Szeredi 	if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
258*e9be9d5eSMiklos Szeredi 		return res;
259*e9be9d5eSMiklos Szeredi 
260*e9be9d5eSMiklos Szeredi 	/* filter out private xattrs */
261*e9be9d5eSMiklos Szeredi 	for (off = 0; off < res;) {
262*e9be9d5eSMiklos Szeredi 		char *s = list + off;
263*e9be9d5eSMiklos Szeredi 		size_t slen = strlen(s) + 1;
264*e9be9d5eSMiklos Szeredi 
265*e9be9d5eSMiklos Szeredi 		BUG_ON(off + slen > res);
266*e9be9d5eSMiklos Szeredi 
267*e9be9d5eSMiklos Szeredi 		if (ovl_is_private_xattr(s)) {
268*e9be9d5eSMiklos Szeredi 			res -= slen;
269*e9be9d5eSMiklos Szeredi 			memmove(s, s + slen, res - off);
270*e9be9d5eSMiklos Szeredi 		} else {
271*e9be9d5eSMiklos Szeredi 			off += slen;
272*e9be9d5eSMiklos Szeredi 		}
273*e9be9d5eSMiklos Szeredi 	}
274*e9be9d5eSMiklos Szeredi 
275*e9be9d5eSMiklos Szeredi 	return res;
276*e9be9d5eSMiklos Szeredi }
277*e9be9d5eSMiklos Szeredi 
278*e9be9d5eSMiklos Szeredi int ovl_removexattr(struct dentry *dentry, const char *name)
279*e9be9d5eSMiklos Szeredi {
280*e9be9d5eSMiklos Szeredi 	int err;
281*e9be9d5eSMiklos Szeredi 	struct path realpath;
282*e9be9d5eSMiklos Szeredi 	enum ovl_path_type type;
283*e9be9d5eSMiklos Szeredi 
284*e9be9d5eSMiklos Szeredi 	err = ovl_want_write(dentry);
285*e9be9d5eSMiklos Szeredi 	if (err)
286*e9be9d5eSMiklos Szeredi 		goto out;
287*e9be9d5eSMiklos Szeredi 
288*e9be9d5eSMiklos Szeredi 	if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
289*e9be9d5eSMiklos Szeredi 	    ovl_is_private_xattr(name))
290*e9be9d5eSMiklos Szeredi 		goto out_drop_write;
291*e9be9d5eSMiklos Szeredi 
292*e9be9d5eSMiklos Szeredi 	type = ovl_path_real(dentry, &realpath);
293*e9be9d5eSMiklos Szeredi 	if (type == OVL_PATH_LOWER) {
294*e9be9d5eSMiklos Szeredi 		err = vfs_getxattr(realpath.dentry, name, NULL, 0);
295*e9be9d5eSMiklos Szeredi 		if (err < 0)
296*e9be9d5eSMiklos Szeredi 			goto out_drop_write;
297*e9be9d5eSMiklos Szeredi 
298*e9be9d5eSMiklos Szeredi 		err = ovl_copy_up(dentry);
299*e9be9d5eSMiklos Szeredi 		if (err)
300*e9be9d5eSMiklos Szeredi 			goto out_drop_write;
301*e9be9d5eSMiklos Szeredi 
302*e9be9d5eSMiklos Szeredi 		ovl_path_upper(dentry, &realpath);
303*e9be9d5eSMiklos Szeredi 	}
304*e9be9d5eSMiklos Szeredi 
305*e9be9d5eSMiklos Szeredi 	err = vfs_removexattr(realpath.dentry, name);
306*e9be9d5eSMiklos Szeredi out_drop_write:
307*e9be9d5eSMiklos Szeredi 	ovl_drop_write(dentry);
308*e9be9d5eSMiklos Szeredi out:
309*e9be9d5eSMiklos Szeredi 	return err;
310*e9be9d5eSMiklos Szeredi }
311*e9be9d5eSMiklos Szeredi 
312*e9be9d5eSMiklos Szeredi static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
313*e9be9d5eSMiklos Szeredi 				  struct dentry *realdentry)
314*e9be9d5eSMiklos Szeredi {
315*e9be9d5eSMiklos Szeredi 	if (type != OVL_PATH_LOWER)
316*e9be9d5eSMiklos Szeredi 		return false;
317*e9be9d5eSMiklos Szeredi 
318*e9be9d5eSMiklos Szeredi 	if (special_file(realdentry->d_inode->i_mode))
319*e9be9d5eSMiklos Szeredi 		return false;
320*e9be9d5eSMiklos Szeredi 
321*e9be9d5eSMiklos Szeredi 	if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC))
322*e9be9d5eSMiklos Szeredi 		return false;
323*e9be9d5eSMiklos Szeredi 
324*e9be9d5eSMiklos Szeredi 	return true;
325*e9be9d5eSMiklos Szeredi }
326*e9be9d5eSMiklos Szeredi 
327*e9be9d5eSMiklos Szeredi static int ovl_dentry_open(struct dentry *dentry, struct file *file,
328*e9be9d5eSMiklos Szeredi 		    const struct cred *cred)
329*e9be9d5eSMiklos Szeredi {
330*e9be9d5eSMiklos Szeredi 	int err;
331*e9be9d5eSMiklos Szeredi 	struct path realpath;
332*e9be9d5eSMiklos Szeredi 	enum ovl_path_type type;
333*e9be9d5eSMiklos Szeredi 	bool want_write = false;
334*e9be9d5eSMiklos Szeredi 
335*e9be9d5eSMiklos Szeredi 	type = ovl_path_real(dentry, &realpath);
336*e9be9d5eSMiklos Szeredi 	if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) {
337*e9be9d5eSMiklos Szeredi 		want_write = true;
338*e9be9d5eSMiklos Szeredi 		err = ovl_want_write(dentry);
339*e9be9d5eSMiklos Szeredi 		if (err)
340*e9be9d5eSMiklos Szeredi 			goto out;
341*e9be9d5eSMiklos Szeredi 
342*e9be9d5eSMiklos Szeredi 		if (file->f_flags & O_TRUNC)
343*e9be9d5eSMiklos Szeredi 			err = ovl_copy_up_last(dentry, NULL, true);
344*e9be9d5eSMiklos Szeredi 		else
345*e9be9d5eSMiklos Szeredi 			err = ovl_copy_up(dentry);
346*e9be9d5eSMiklos Szeredi 		if (err)
347*e9be9d5eSMiklos Szeredi 			goto out_drop_write;
348*e9be9d5eSMiklos Szeredi 
349*e9be9d5eSMiklos Szeredi 		ovl_path_upper(dentry, &realpath);
350*e9be9d5eSMiklos Szeredi 	}
351*e9be9d5eSMiklos Szeredi 
352*e9be9d5eSMiklos Szeredi 	err = vfs_open(&realpath, file, cred);
353*e9be9d5eSMiklos Szeredi out_drop_write:
354*e9be9d5eSMiklos Szeredi 	if (want_write)
355*e9be9d5eSMiklos Szeredi 		ovl_drop_write(dentry);
356*e9be9d5eSMiklos Szeredi out:
357*e9be9d5eSMiklos Szeredi 	return err;
358*e9be9d5eSMiklos Szeredi }
359*e9be9d5eSMiklos Szeredi 
360*e9be9d5eSMiklos Szeredi static const struct inode_operations ovl_file_inode_operations = {
361*e9be9d5eSMiklos Szeredi 	.setattr	= ovl_setattr,
362*e9be9d5eSMiklos Szeredi 	.permission	= ovl_permission,
363*e9be9d5eSMiklos Szeredi 	.getattr	= ovl_getattr,
364*e9be9d5eSMiklos Szeredi 	.setxattr	= ovl_setxattr,
365*e9be9d5eSMiklos Szeredi 	.getxattr	= ovl_getxattr,
366*e9be9d5eSMiklos Szeredi 	.listxattr	= ovl_listxattr,
367*e9be9d5eSMiklos Szeredi 	.removexattr	= ovl_removexattr,
368*e9be9d5eSMiklos Szeredi 	.dentry_open	= ovl_dentry_open,
369*e9be9d5eSMiklos Szeredi };
370*e9be9d5eSMiklos Szeredi 
371*e9be9d5eSMiklos Szeredi static const struct inode_operations ovl_symlink_inode_operations = {
372*e9be9d5eSMiklos Szeredi 	.setattr	= ovl_setattr,
373*e9be9d5eSMiklos Szeredi 	.follow_link	= ovl_follow_link,
374*e9be9d5eSMiklos Szeredi 	.put_link	= ovl_put_link,
375*e9be9d5eSMiklos Szeredi 	.readlink	= ovl_readlink,
376*e9be9d5eSMiklos Szeredi 	.getattr	= ovl_getattr,
377*e9be9d5eSMiklos Szeredi 	.setxattr	= ovl_setxattr,
378*e9be9d5eSMiklos Szeredi 	.getxattr	= ovl_getxattr,
379*e9be9d5eSMiklos Szeredi 	.listxattr	= ovl_listxattr,
380*e9be9d5eSMiklos Szeredi 	.removexattr	= ovl_removexattr,
381*e9be9d5eSMiklos Szeredi };
382*e9be9d5eSMiklos Szeredi 
383*e9be9d5eSMiklos Szeredi struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
384*e9be9d5eSMiklos Szeredi 			    struct ovl_entry *oe)
385*e9be9d5eSMiklos Szeredi {
386*e9be9d5eSMiklos Szeredi 	struct inode *inode;
387*e9be9d5eSMiklos Szeredi 
388*e9be9d5eSMiklos Szeredi 	inode = new_inode(sb);
389*e9be9d5eSMiklos Szeredi 	if (!inode)
390*e9be9d5eSMiklos Szeredi 		return NULL;
391*e9be9d5eSMiklos Szeredi 
392*e9be9d5eSMiklos Szeredi 	mode &= S_IFMT;
393*e9be9d5eSMiklos Szeredi 
394*e9be9d5eSMiklos Szeredi 	inode->i_ino = get_next_ino();
395*e9be9d5eSMiklos Szeredi 	inode->i_mode = mode;
396*e9be9d5eSMiklos Szeredi 	inode->i_flags |= S_NOATIME | S_NOCMTIME;
397*e9be9d5eSMiklos Szeredi 
398*e9be9d5eSMiklos Szeredi 	switch (mode) {
399*e9be9d5eSMiklos Szeredi 	case S_IFDIR:
400*e9be9d5eSMiklos Szeredi 		inode->i_private = oe;
401*e9be9d5eSMiklos Szeredi 		inode->i_op = &ovl_dir_inode_operations;
402*e9be9d5eSMiklos Szeredi 		inode->i_fop = &ovl_dir_operations;
403*e9be9d5eSMiklos Szeredi 		break;
404*e9be9d5eSMiklos Szeredi 
405*e9be9d5eSMiklos Szeredi 	case S_IFLNK:
406*e9be9d5eSMiklos Szeredi 		inode->i_op = &ovl_symlink_inode_operations;
407*e9be9d5eSMiklos Szeredi 		break;
408*e9be9d5eSMiklos Szeredi 
409*e9be9d5eSMiklos Szeredi 	case S_IFREG:
410*e9be9d5eSMiklos Szeredi 	case S_IFSOCK:
411*e9be9d5eSMiklos Szeredi 	case S_IFBLK:
412*e9be9d5eSMiklos Szeredi 	case S_IFCHR:
413*e9be9d5eSMiklos Szeredi 	case S_IFIFO:
414*e9be9d5eSMiklos Szeredi 		inode->i_op = &ovl_file_inode_operations;
415*e9be9d5eSMiklos Szeredi 		break;
416*e9be9d5eSMiklos Szeredi 
417*e9be9d5eSMiklos Szeredi 	default:
418*e9be9d5eSMiklos Szeredi 		WARN(1, "illegal file type: %i\n", mode);
419*e9be9d5eSMiklos Szeredi 		iput(inode);
420*e9be9d5eSMiklos Szeredi 		inode = NULL;
421*e9be9d5eSMiklos Szeredi 	}
422*e9be9d5eSMiklos Szeredi 
423*e9be9d5eSMiklos Szeredi 	return inode;
424*e9be9d5eSMiklos Szeredi 
425*e9be9d5eSMiklos Szeredi }
426