xref: /openbmc/linux/fs/overlayfs/inode.c (revision ca4c8a3a)
1e9be9d5eSMiklos Szeredi /*
2e9be9d5eSMiklos Szeredi  *
3e9be9d5eSMiklos Szeredi  * Copyright (C) 2011 Novell Inc.
4e9be9d5eSMiklos Szeredi  *
5e9be9d5eSMiklos Szeredi  * This program is free software; you can redistribute it and/or modify it
6e9be9d5eSMiklos Szeredi  * under the terms of the GNU General Public License version 2 as published by
7e9be9d5eSMiklos Szeredi  * the Free Software Foundation.
8e9be9d5eSMiklos Szeredi  */
9e9be9d5eSMiklos Szeredi 
10e9be9d5eSMiklos Szeredi #include <linux/fs.h>
11e9be9d5eSMiklos Szeredi #include <linux/slab.h>
12e9be9d5eSMiklos Szeredi #include <linux/xattr.h>
135201dc44SMiklos Szeredi #include <linux/posix_acl.h>
14e9be9d5eSMiklos Szeredi #include "overlayfs.h"
15e9be9d5eSMiklos Szeredi 
160f7ff2daSAl Viro static int ovl_copy_up_truncate(struct dentry *dentry)
17e9be9d5eSMiklos Szeredi {
18e9be9d5eSMiklos Szeredi 	int err;
19e9be9d5eSMiklos Szeredi 	struct dentry *parent;
20e9be9d5eSMiklos Szeredi 	struct kstat stat;
21e9be9d5eSMiklos Szeredi 	struct path lowerpath;
228eac98b8SVivek Goyal 	const struct cred *old_cred;
23e9be9d5eSMiklos Szeredi 
24e9be9d5eSMiklos Szeredi 	parent = dget_parent(dentry);
25e9be9d5eSMiklos Szeredi 	err = ovl_copy_up(parent);
26e9be9d5eSMiklos Szeredi 	if (err)
27e9be9d5eSMiklos Szeredi 		goto out_dput_parent;
28e9be9d5eSMiklos Szeredi 
29e9be9d5eSMiklos Szeredi 	ovl_path_lower(dentry, &lowerpath);
30e9be9d5eSMiklos Szeredi 
318eac98b8SVivek Goyal 	old_cred = ovl_override_creds(dentry->d_sb);
328eac98b8SVivek Goyal 	err = vfs_getattr(&lowerpath, &stat);
338eac98b8SVivek Goyal 	if (!err) {
34e9be9d5eSMiklos Szeredi 		stat.size = 0;
350f7ff2daSAl Viro 		err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
368eac98b8SVivek Goyal 	}
378eac98b8SVivek Goyal 	revert_creds(old_cred);
38e9be9d5eSMiklos Szeredi 
39e9be9d5eSMiklos Szeredi out_dput_parent:
40e9be9d5eSMiklos Szeredi 	dput(parent);
41e9be9d5eSMiklos Szeredi 	return err;
42e9be9d5eSMiklos Szeredi }
43e9be9d5eSMiklos Szeredi 
44e9be9d5eSMiklos Szeredi int ovl_setattr(struct dentry *dentry, struct iattr *attr)
45e9be9d5eSMiklos Szeredi {
46e9be9d5eSMiklos Szeredi 	int err;
47e9be9d5eSMiklos Szeredi 	struct dentry *upperdentry;
481175b6b8SVivek Goyal 	const struct cred *old_cred;
49e9be9d5eSMiklos Szeredi 
50cf9a6784SMiklos Szeredi 	/*
51cf9a6784SMiklos Szeredi 	 * Check for permissions before trying to copy-up.  This is redundant
52cf9a6784SMiklos Szeredi 	 * since it will be rechecked later by ->setattr() on upper dentry.  But
53cf9a6784SMiklos Szeredi 	 * without this, copy-up can be triggered by just about anybody.
54cf9a6784SMiklos Szeredi 	 *
55cf9a6784SMiklos Szeredi 	 * We don't initialize inode->size, which just means that
56cf9a6784SMiklos Szeredi 	 * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
57cf9a6784SMiklos Szeredi 	 * check for a swapfile (which this won't be anyway).
58cf9a6784SMiklos Szeredi 	 */
5931051c85SJan Kara 	err = setattr_prepare(dentry, attr);
60cf9a6784SMiklos Szeredi 	if (err)
61cf9a6784SMiklos Szeredi 		return err;
62cf9a6784SMiklos Szeredi 
63e9be9d5eSMiklos Szeredi 	err = ovl_want_write(dentry);
64e9be9d5eSMiklos Szeredi 	if (err)
65e9be9d5eSMiklos Szeredi 		goto out;
66e9be9d5eSMiklos Szeredi 
67acff81ecSMiklos Szeredi 	err = ovl_copy_up(dentry);
68acff81ecSMiklos Szeredi 	if (!err) {
69e9be9d5eSMiklos Szeredi 		upperdentry = ovl_dentry_upper(dentry);
70acff81ecSMiklos Szeredi 
71b99c2d91SMiklos Szeredi 		if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
72b99c2d91SMiklos Szeredi 			attr->ia_valid &= ~ATTR_MODE;
73b99c2d91SMiklos Szeredi 
745955102cSAl Viro 		inode_lock(upperdentry->d_inode);
751175b6b8SVivek Goyal 		old_cred = ovl_override_creds(dentry->d_sb);
76e9be9d5eSMiklos Szeredi 		err = notify_change(upperdentry, attr, NULL);
771175b6b8SVivek Goyal 		revert_creds(old_cred);
78b81de061SKonstantin Khlebnikov 		if (!err)
79b81de061SKonstantin Khlebnikov 			ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
805955102cSAl Viro 		inode_unlock(upperdentry->d_inode);
81e9be9d5eSMiklos Szeredi 	}
82e9be9d5eSMiklos Szeredi 	ovl_drop_write(dentry);
83e9be9d5eSMiklos Szeredi out:
84e9be9d5eSMiklos Szeredi 	return err;
85e9be9d5eSMiklos Szeredi }
86e9be9d5eSMiklos Szeredi 
87e9be9d5eSMiklos Szeredi static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
88e9be9d5eSMiklos Szeredi 			 struct kstat *stat)
89e9be9d5eSMiklos Szeredi {
90e9be9d5eSMiklos Szeredi 	struct path realpath;
911175b6b8SVivek Goyal 	const struct cred *old_cred;
921175b6b8SVivek Goyal 	int err;
93e9be9d5eSMiklos Szeredi 
94e9be9d5eSMiklos Szeredi 	ovl_path_real(dentry, &realpath);
951175b6b8SVivek Goyal 	old_cred = ovl_override_creds(dentry->d_sb);
961175b6b8SVivek Goyal 	err = vfs_getattr(&realpath, stat);
971175b6b8SVivek Goyal 	revert_creds(old_cred);
981175b6b8SVivek Goyal 	return err;
99e9be9d5eSMiklos Szeredi }
100e9be9d5eSMiklos Szeredi 
101e9be9d5eSMiklos Szeredi int ovl_permission(struct inode *inode, int mask)
102e9be9d5eSMiklos Szeredi {
103e9be9d5eSMiklos Szeredi 	bool is_upper;
10439b681f8SMiklos Szeredi 	struct inode *realinode = ovl_inode_real(inode, &is_upper);
105c0ca3d70SVivek Goyal 	const struct cred *old_cred;
106e9be9d5eSMiklos Szeredi 	int err;
107e9be9d5eSMiklos Szeredi 
108e9be9d5eSMiklos Szeredi 	/* Careful in RCU walk mode */
109e9be9d5eSMiklos Szeredi 	if (!realinode) {
110e9be9d5eSMiklos Szeredi 		WARN_ON(!(mask & MAY_NOT_BLOCK));
111a999d7e1SMiklos Szeredi 		return -ECHILD;
112e9be9d5eSMiklos Szeredi 	}
113e9be9d5eSMiklos Szeredi 
114c0ca3d70SVivek Goyal 	/*
115c0ca3d70SVivek Goyal 	 * Check overlay inode with the creds of task and underlying inode
116c0ca3d70SVivek Goyal 	 * with creds of mounter
117c0ca3d70SVivek Goyal 	 */
118c0ca3d70SVivek Goyal 	err = generic_permission(inode, mask);
119c0ca3d70SVivek Goyal 	if (err)
120c0ca3d70SVivek Goyal 		return err;
121c0ca3d70SVivek Goyal 
122c0ca3d70SVivek Goyal 	old_cred = ovl_override_creds(inode->i_sb);
123500cac3cSVivek Goyal 	if (!is_upper && !special_file(realinode->i_mode) && mask & MAY_WRITE) {
124754f8cb7SVivek Goyal 		mask &= ~(MAY_WRITE | MAY_APPEND);
125500cac3cSVivek Goyal 		/* Make sure mounter can read file for copy up later */
126500cac3cSVivek Goyal 		mask |= MAY_READ;
127500cac3cSVivek Goyal 	}
1289c630ebeSMiklos Szeredi 	err = inode_permission(realinode, mask);
129c0ca3d70SVivek Goyal 	revert_creds(old_cred);
130c0ca3d70SVivek Goyal 
131c0ca3d70SVivek Goyal 	return err;
132e9be9d5eSMiklos Szeredi }
133e9be9d5eSMiklos Szeredi 
1346b255391SAl Viro static const char *ovl_get_link(struct dentry *dentry,
135fceef393SAl Viro 				struct inode *inode,
136fceef393SAl Viro 				struct delayed_call *done)
137e9be9d5eSMiklos Szeredi {
1381175b6b8SVivek Goyal 	const struct cred *old_cred;
1391175b6b8SVivek Goyal 	const char *p;
140e9be9d5eSMiklos Szeredi 
1416b255391SAl Viro 	if (!dentry)
1426b255391SAl Viro 		return ERR_PTR(-ECHILD);
1436b255391SAl Viro 
1441175b6b8SVivek Goyal 	old_cred = ovl_override_creds(dentry->d_sb);
1457764235bSMiklos Szeredi 	p = vfs_get_link(ovl_dentry_real(dentry), done);
1461175b6b8SVivek Goyal 	revert_creds(old_cred);
1471175b6b8SVivek Goyal 	return p;
148e9be9d5eSMiklos Szeredi }
149e9be9d5eSMiklos Szeredi 
1500956254aSMiklos Szeredi bool ovl_is_private_xattr(const char *name)
151e9be9d5eSMiklos Szeredi {
152fe2b7595SAndreas Gruenbacher 	return strncmp(name, OVL_XATTR_PREFIX,
153fe2b7595SAndreas Gruenbacher 		       sizeof(OVL_XATTR_PREFIX) - 1) == 0;
154e9be9d5eSMiklos Szeredi }
155e9be9d5eSMiklos Szeredi 
1560e585cccSAndreas Gruenbacher int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
1573767e255SAl Viro 		  size_t size, int flags)
158e9be9d5eSMiklos Szeredi {
159e9be9d5eSMiklos Szeredi 	int err;
1600e585cccSAndreas Gruenbacher 	struct path realpath;
1610e585cccSAndreas Gruenbacher 	enum ovl_path_type type = ovl_path_real(dentry, &realpath);
1621175b6b8SVivek Goyal 	const struct cred *old_cred;
163e9be9d5eSMiklos Szeredi 
164e9be9d5eSMiklos Szeredi 	err = ovl_want_write(dentry);
165e9be9d5eSMiklos Szeredi 	if (err)
166e9be9d5eSMiklos Szeredi 		goto out;
167e9be9d5eSMiklos Szeredi 
1680e585cccSAndreas Gruenbacher 	if (!value && !OVL_TYPE_UPPER(type)) {
1690e585cccSAndreas Gruenbacher 		err = vfs_getxattr(realpath.dentry, name, NULL, 0);
1700e585cccSAndreas Gruenbacher 		if (err < 0)
1710e585cccSAndreas Gruenbacher 			goto out_drop_write;
1720e585cccSAndreas Gruenbacher 	}
1730e585cccSAndreas Gruenbacher 
174e9be9d5eSMiklos Szeredi 	err = ovl_copy_up(dentry);
175e9be9d5eSMiklos Szeredi 	if (err)
176e9be9d5eSMiklos Szeredi 		goto out_drop_write;
177e9be9d5eSMiklos Szeredi 
1780e585cccSAndreas Gruenbacher 	if (!OVL_TYPE_UPPER(type))
1790e585cccSAndreas Gruenbacher 		ovl_path_upper(dentry, &realpath);
1800e585cccSAndreas Gruenbacher 
1811175b6b8SVivek Goyal 	old_cred = ovl_override_creds(dentry->d_sb);
1820e585cccSAndreas Gruenbacher 	if (value)
1830e585cccSAndreas Gruenbacher 		err = vfs_setxattr(realpath.dentry, name, value, size, flags);
1840e585cccSAndreas Gruenbacher 	else {
1850e585cccSAndreas Gruenbacher 		WARN_ON(flags != XATTR_REPLACE);
1860e585cccSAndreas Gruenbacher 		err = vfs_removexattr(realpath.dentry, name);
1870e585cccSAndreas Gruenbacher 	}
1881175b6b8SVivek Goyal 	revert_creds(old_cred);
189e9be9d5eSMiklos Szeredi 
190e9be9d5eSMiklos Szeredi out_drop_write:
191e9be9d5eSMiklos Szeredi 	ovl_drop_write(dentry);
192e9be9d5eSMiklos Szeredi out:
193e9be9d5eSMiklos Szeredi 	return err;
194e9be9d5eSMiklos Szeredi }
195e9be9d5eSMiklos Szeredi 
1960eb45fc3SAndreas Gruenbacher int ovl_xattr_get(struct dentry *dentry, const char *name,
1970eb45fc3SAndreas Gruenbacher 		  void *value, size_t size)
198e9be9d5eSMiklos Szeredi {
199b581755bSMiklos Szeredi 	struct dentry *realdentry = ovl_dentry_real(dentry);
2001175b6b8SVivek Goyal 	ssize_t res;
2011175b6b8SVivek Goyal 	const struct cred *old_cred;
20252148463SMiklos Szeredi 
2031175b6b8SVivek Goyal 	old_cred = ovl_override_creds(dentry->d_sb);
2041175b6b8SVivek Goyal 	res = vfs_getxattr(realdentry, name, value, size);
2051175b6b8SVivek Goyal 	revert_creds(old_cred);
2061175b6b8SVivek Goyal 	return res;
207e9be9d5eSMiklos Szeredi }
208e9be9d5eSMiklos Szeredi 
209e9be9d5eSMiklos Szeredi ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
210e9be9d5eSMiklos Szeredi {
211b581755bSMiklos Szeredi 	struct dentry *realdentry = ovl_dentry_real(dentry);
212e9be9d5eSMiklos Szeredi 	ssize_t res;
2137cb35119SMiklos Szeredi 	size_t len;
2147cb35119SMiklos Szeredi 	char *s;
2151175b6b8SVivek Goyal 	const struct cred *old_cred;
216e9be9d5eSMiklos Szeredi 
2171175b6b8SVivek Goyal 	old_cred = ovl_override_creds(dentry->d_sb);
218b581755bSMiklos Szeredi 	res = vfs_listxattr(realdentry, list, size);
2191175b6b8SVivek Goyal 	revert_creds(old_cred);
220e9be9d5eSMiklos Szeredi 	if (res <= 0 || size == 0)
221e9be9d5eSMiklos Szeredi 		return res;
222e9be9d5eSMiklos Szeredi 
223e9be9d5eSMiklos Szeredi 	/* filter out private xattrs */
2247cb35119SMiklos Szeredi 	for (s = list, len = res; len;) {
2257cb35119SMiklos Szeredi 		size_t slen = strnlen(s, len) + 1;
226e9be9d5eSMiklos Szeredi 
2277cb35119SMiklos Szeredi 		/* underlying fs providing us with an broken xattr list? */
2287cb35119SMiklos Szeredi 		if (WARN_ON(slen > len))
2297cb35119SMiklos Szeredi 			return -EIO;
230e9be9d5eSMiklos Szeredi 
2317cb35119SMiklos Szeredi 		len -= slen;
232e9be9d5eSMiklos Szeredi 		if (ovl_is_private_xattr(s)) {
233e9be9d5eSMiklos Szeredi 			res -= slen;
2347cb35119SMiklos Szeredi 			memmove(s, s + slen, len);
235e9be9d5eSMiklos Szeredi 		} else {
2367cb35119SMiklos Szeredi 			s += slen;
237e9be9d5eSMiklos Szeredi 		}
238e9be9d5eSMiklos Szeredi 	}
239e9be9d5eSMiklos Szeredi 
240e9be9d5eSMiklos Szeredi 	return res;
241e9be9d5eSMiklos Szeredi }
242e9be9d5eSMiklos Szeredi 
24339a25b2bSVivek Goyal struct posix_acl *ovl_get_acl(struct inode *inode, int type)
24439a25b2bSVivek Goyal {
24539b681f8SMiklos Szeredi 	struct inode *realinode = ovl_inode_real(inode, NULL);
2461175b6b8SVivek Goyal 	const struct cred *old_cred;
2471175b6b8SVivek Goyal 	struct posix_acl *acl;
24839a25b2bSVivek Goyal 
2495201dc44SMiklos Szeredi 	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
25039a25b2bSVivek Goyal 		return NULL;
25139a25b2bSVivek Goyal 
2521175b6b8SVivek Goyal 	old_cred = ovl_override_creds(inode->i_sb);
2535201dc44SMiklos Szeredi 	acl = get_acl(realinode, type);
2541175b6b8SVivek Goyal 	revert_creds(old_cred);
2551175b6b8SVivek Goyal 
2561175b6b8SVivek Goyal 	return acl;
25739a25b2bSVivek Goyal }
25839a25b2bSVivek Goyal 
259e9be9d5eSMiklos Szeredi static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
260e9be9d5eSMiklos Szeredi 				  struct dentry *realdentry)
261e9be9d5eSMiklos Szeredi {
2621afaba1eSMiklos Szeredi 	if (OVL_TYPE_UPPER(type))
263e9be9d5eSMiklos Szeredi 		return false;
264e9be9d5eSMiklos Szeredi 
265e9be9d5eSMiklos Szeredi 	if (special_file(realdentry->d_inode->i_mode))
266e9be9d5eSMiklos Szeredi 		return false;
267e9be9d5eSMiklos Szeredi 
268e9be9d5eSMiklos Szeredi 	if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC))
269e9be9d5eSMiklos Szeredi 		return false;
270e9be9d5eSMiklos Szeredi 
271e9be9d5eSMiklos Szeredi 	return true;
272e9be9d5eSMiklos Szeredi }
273e9be9d5eSMiklos Szeredi 
2742d902671SMiklos Szeredi int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
275e9be9d5eSMiklos Szeredi {
2762d902671SMiklos Szeredi 	int err = 0;
277e9be9d5eSMiklos Szeredi 	struct path realpath;
278e9be9d5eSMiklos Szeredi 	enum ovl_path_type type;
279e9be9d5eSMiklos Szeredi 
280e9be9d5eSMiklos Szeredi 	type = ovl_path_real(dentry, &realpath);
2814bacc9c9SDavid Howells 	if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
282e9be9d5eSMiklos Szeredi 		err = ovl_want_write(dentry);
2832d902671SMiklos Szeredi 		if (!err) {
2844bacc9c9SDavid Howells 			if (file_flags & O_TRUNC)
2850f7ff2daSAl Viro 				err = ovl_copy_up_truncate(dentry);
286e9be9d5eSMiklos Szeredi 			else
287e9be9d5eSMiklos Szeredi 				err = ovl_copy_up(dentry);
288f25801eeSDavid Howells 			ovl_drop_write(dentry);
2892d902671SMiklos Szeredi 		}
290e9be9d5eSMiklos Szeredi 	}
291e9be9d5eSMiklos Szeredi 
2922d902671SMiklos Szeredi 	return err;
293e9be9d5eSMiklos Szeredi }
294e9be9d5eSMiklos Szeredi 
295d719e8f2SMiklos Szeredi int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
296d719e8f2SMiklos Szeredi {
297d719e8f2SMiklos Szeredi 	struct dentry *alias;
298d719e8f2SMiklos Szeredi 	struct path upperpath;
299d719e8f2SMiklos Szeredi 
300d719e8f2SMiklos Szeredi 	if (!(flags & S_ATIME))
301d719e8f2SMiklos Szeredi 		return 0;
302d719e8f2SMiklos Szeredi 
303d719e8f2SMiklos Szeredi 	alias = d_find_any_alias(inode);
304d719e8f2SMiklos Szeredi 	if (!alias)
305d719e8f2SMiklos Szeredi 		return 0;
306d719e8f2SMiklos Szeredi 
307d719e8f2SMiklos Szeredi 	ovl_path_upper(alias, &upperpath);
308d719e8f2SMiklos Szeredi 	if (upperpath.dentry) {
309d719e8f2SMiklos Szeredi 		touch_atime(&upperpath);
310d719e8f2SMiklos Szeredi 		inode->i_atime = d_inode(upperpath.dentry)->i_atime;
311d719e8f2SMiklos Szeredi 	}
312d719e8f2SMiklos Szeredi 
313d719e8f2SMiklos Szeredi 	dput(alias);
314d719e8f2SMiklos Szeredi 
315d719e8f2SMiklos Szeredi 	return 0;
316d719e8f2SMiklos Szeredi }
317d719e8f2SMiklos Szeredi 
318e9be9d5eSMiklos Szeredi static const struct inode_operations ovl_file_inode_operations = {
319e9be9d5eSMiklos Szeredi 	.setattr	= ovl_setattr,
320e9be9d5eSMiklos Szeredi 	.permission	= ovl_permission,
321e9be9d5eSMiklos Szeredi 	.getattr	= ovl_getattr,
322e9be9d5eSMiklos Szeredi 	.listxattr	= ovl_listxattr,
32339a25b2bSVivek Goyal 	.get_acl	= ovl_get_acl,
324d719e8f2SMiklos Szeredi 	.update_time	= ovl_update_time,
325e9be9d5eSMiklos Szeredi };
326e9be9d5eSMiklos Szeredi 
327e9be9d5eSMiklos Szeredi static const struct inode_operations ovl_symlink_inode_operations = {
328e9be9d5eSMiklos Szeredi 	.setattr	= ovl_setattr,
3296b255391SAl Viro 	.get_link	= ovl_get_link,
33078a3fa4fSMiklos Szeredi 	.readlink	= generic_readlink,
331e9be9d5eSMiklos Szeredi 	.getattr	= ovl_getattr,
332e9be9d5eSMiklos Szeredi 	.listxattr	= ovl_listxattr,
333d719e8f2SMiklos Szeredi 	.update_time	= ovl_update_time,
334e9be9d5eSMiklos Szeredi };
335e9be9d5eSMiklos Szeredi 
336ca4c8a3aSMiklos Szeredi static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev)
337e9be9d5eSMiklos Szeredi {
338e9be9d5eSMiklos Szeredi 	inode->i_ino = get_next_ino();
339e9be9d5eSMiklos Szeredi 	inode->i_mode = mode;
340d719e8f2SMiklos Szeredi 	inode->i_flags |= S_NOCMTIME;
3412a3a2a3fSMiklos Szeredi #ifdef CONFIG_FS_POSIX_ACL
3422a3a2a3fSMiklos Szeredi 	inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;
3432a3a2a3fSMiklos Szeredi #endif
344e9be9d5eSMiklos Szeredi 
345ca4c8a3aSMiklos Szeredi 	switch (mode & S_IFMT) {
346ca4c8a3aSMiklos Szeredi 	case S_IFREG:
347ca4c8a3aSMiklos Szeredi 		inode->i_op = &ovl_file_inode_operations;
348ca4c8a3aSMiklos Szeredi 		break;
349ca4c8a3aSMiklos Szeredi 
350e9be9d5eSMiklos Szeredi 	case S_IFDIR:
351e9be9d5eSMiklos Szeredi 		inode->i_op = &ovl_dir_inode_operations;
352e9be9d5eSMiklos Szeredi 		inode->i_fop = &ovl_dir_operations;
353e9be9d5eSMiklos Szeredi 		break;
354e9be9d5eSMiklos Szeredi 
355e9be9d5eSMiklos Szeredi 	case S_IFLNK:
356e9be9d5eSMiklos Szeredi 		inode->i_op = &ovl_symlink_inode_operations;
357e9be9d5eSMiklos Szeredi 		break;
358e9be9d5eSMiklos Szeredi 
35951f7e52dSMiklos Szeredi 	default:
360e9be9d5eSMiklos Szeredi 		inode->i_op = &ovl_file_inode_operations;
361ca4c8a3aSMiklos Szeredi 		init_special_inode(inode, mode, rdev);
362e9be9d5eSMiklos Szeredi 		break;
36351f7e52dSMiklos Szeredi 	}
36451f7e52dSMiklos Szeredi }
365e9be9d5eSMiklos Szeredi 
366ca4c8a3aSMiklos Szeredi struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev)
36751f7e52dSMiklos Szeredi {
36851f7e52dSMiklos Szeredi 	struct inode *inode;
36951f7e52dSMiklos Szeredi 
37051f7e52dSMiklos Szeredi 	inode = new_inode(sb);
37151f7e52dSMiklos Szeredi 	if (inode)
372ca4c8a3aSMiklos Szeredi 		ovl_fill_inode(inode, mode, rdev);
37351f7e52dSMiklos Szeredi 
37451f7e52dSMiklos Szeredi 	return inode;
37551f7e52dSMiklos Szeredi }
37651f7e52dSMiklos Szeredi 
37751f7e52dSMiklos Szeredi static int ovl_inode_test(struct inode *inode, void *data)
37851f7e52dSMiklos Szeredi {
37951f7e52dSMiklos Szeredi 	return ovl_inode_real(inode, NULL) == data;
38051f7e52dSMiklos Szeredi }
38151f7e52dSMiklos Szeredi 
38251f7e52dSMiklos Szeredi static int ovl_inode_set(struct inode *inode, void *data)
38351f7e52dSMiklos Szeredi {
38451f7e52dSMiklos Szeredi 	inode->i_private = (void *) (((unsigned long) data) | OVL_ISUPPER_MASK);
38551f7e52dSMiklos Szeredi 	return 0;
38651f7e52dSMiklos Szeredi }
38751f7e52dSMiklos Szeredi 
38851f7e52dSMiklos Szeredi struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode)
38951f7e52dSMiklos Szeredi 
39051f7e52dSMiklos Szeredi {
39151f7e52dSMiklos Szeredi 	struct inode *inode;
39251f7e52dSMiklos Szeredi 
39351f7e52dSMiklos Szeredi 	inode = iget5_locked(sb, (unsigned long) realinode,
39451f7e52dSMiklos Szeredi 			     ovl_inode_test, ovl_inode_set, realinode);
39551f7e52dSMiklos Szeredi 	if (inode && inode->i_state & I_NEW) {
396ca4c8a3aSMiklos Szeredi 		ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
39751f7e52dSMiklos Szeredi 		set_nlink(inode, realinode->i_nlink);
39851f7e52dSMiklos Szeredi 		unlock_new_inode(inode);
399e9be9d5eSMiklos Szeredi 	}
400e9be9d5eSMiklos Szeredi 
401e9be9d5eSMiklos Szeredi 	return inode;
402e9be9d5eSMiklos Szeredi }
403