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 */ 59cf9a6784SMiklos Szeredi err = inode_change_ok(dentry->d_inode, 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 6703bea604SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 6803bea604SMiklos Szeredi struct inode *realinode = d_inode(ovl_dentry_real(dentry)); 6903bea604SMiklos Szeredi 7003bea604SMiklos Szeredi err = -ETXTBSY; 7103bea604SMiklos Szeredi if (atomic_read(&realinode->i_writecount) < 0) 7203bea604SMiklos Szeredi goto out_drop_write; 7303bea604SMiklos Szeredi } 7403bea604SMiklos Szeredi 75acff81ecSMiklos Szeredi err = ovl_copy_up(dentry); 76acff81ecSMiklos Szeredi if (!err) { 7703bea604SMiklos Szeredi struct inode *winode = NULL; 7803bea604SMiklos Szeredi 79e9be9d5eSMiklos Szeredi upperdentry = ovl_dentry_upper(dentry); 80acff81ecSMiklos Szeredi 8103bea604SMiklos Szeredi if (attr->ia_valid & ATTR_SIZE) { 8203bea604SMiklos Szeredi winode = d_inode(upperdentry); 8303bea604SMiklos Szeredi err = get_write_access(winode); 8403bea604SMiklos Szeredi if (err) 8503bea604SMiklos Szeredi goto out_drop_write; 8603bea604SMiklos Szeredi } 8703bea604SMiklos Szeredi 88b99c2d91SMiklos Szeredi if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 89b99c2d91SMiklos Szeredi attr->ia_valid &= ~ATTR_MODE; 90b99c2d91SMiklos Szeredi 915955102cSAl Viro inode_lock(upperdentry->d_inode); 921175b6b8SVivek Goyal old_cred = ovl_override_creds(dentry->d_sb); 93e9be9d5eSMiklos Szeredi err = notify_change(upperdentry, attr, NULL); 941175b6b8SVivek Goyal revert_creds(old_cred); 95b81de061SKonstantin Khlebnikov if (!err) 96b81de061SKonstantin Khlebnikov ovl_copyattr(upperdentry->d_inode, dentry->d_inode); 975955102cSAl Viro inode_unlock(upperdentry->d_inode); 9803bea604SMiklos Szeredi 9903bea604SMiklos Szeredi if (winode) 10003bea604SMiklos Szeredi put_write_access(winode); 101e9be9d5eSMiklos Szeredi } 10203bea604SMiklos Szeredi out_drop_write: 103e9be9d5eSMiklos Szeredi ovl_drop_write(dentry); 104e9be9d5eSMiklos Szeredi out: 105e9be9d5eSMiklos Szeredi return err; 106e9be9d5eSMiklos Szeredi } 107e9be9d5eSMiklos Szeredi 108e9be9d5eSMiklos Szeredi static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, 109e9be9d5eSMiklos Szeredi struct kstat *stat) 110e9be9d5eSMiklos Szeredi { 111e9be9d5eSMiklos Szeredi struct path realpath; 1121175b6b8SVivek Goyal const struct cred *old_cred; 1131175b6b8SVivek Goyal int err; 114e9be9d5eSMiklos Szeredi 115e9be9d5eSMiklos Szeredi ovl_path_real(dentry, &realpath); 1161175b6b8SVivek Goyal old_cred = ovl_override_creds(dentry->d_sb); 1171175b6b8SVivek Goyal err = vfs_getattr(&realpath, stat); 1181175b6b8SVivek Goyal revert_creds(old_cred); 1191175b6b8SVivek Goyal return err; 120e9be9d5eSMiklos Szeredi } 121e9be9d5eSMiklos Szeredi 122e9be9d5eSMiklos Szeredi int ovl_permission(struct inode *inode, int mask) 123e9be9d5eSMiklos Szeredi { 124e9be9d5eSMiklos Szeredi bool is_upper; 12539b681f8SMiklos Szeredi struct inode *realinode = ovl_inode_real(inode, &is_upper); 126c0ca3d70SVivek Goyal const struct cred *old_cred; 127e9be9d5eSMiklos Szeredi int err; 128e9be9d5eSMiklos Szeredi 129e9be9d5eSMiklos Szeredi /* Careful in RCU walk mode */ 130e9be9d5eSMiklos Szeredi if (!realinode) { 131e9be9d5eSMiklos Szeredi WARN_ON(!(mask & MAY_NOT_BLOCK)); 132a999d7e1SMiklos Szeredi return -ECHILD; 133e9be9d5eSMiklos Szeredi } 134e9be9d5eSMiklos Szeredi 135c0ca3d70SVivek Goyal /* 136c0ca3d70SVivek Goyal * Check overlay inode with the creds of task and underlying inode 137c0ca3d70SVivek Goyal * with creds of mounter 138c0ca3d70SVivek Goyal */ 139c0ca3d70SVivek Goyal err = generic_permission(inode, mask); 140c0ca3d70SVivek Goyal if (err) 141c0ca3d70SVivek Goyal return err; 142c0ca3d70SVivek Goyal 143c0ca3d70SVivek Goyal old_cred = ovl_override_creds(inode->i_sb); 144500cac3cSVivek Goyal if (!is_upper && !special_file(realinode->i_mode) && mask & MAY_WRITE) { 145754f8cb7SVivek Goyal mask &= ~(MAY_WRITE | MAY_APPEND); 146500cac3cSVivek Goyal /* Make sure mounter can read file for copy up later */ 147500cac3cSVivek Goyal mask |= MAY_READ; 148500cac3cSVivek Goyal } 1499c630ebeSMiklos Szeredi err = inode_permission(realinode, mask); 150c0ca3d70SVivek Goyal revert_creds(old_cred); 151c0ca3d70SVivek Goyal 152c0ca3d70SVivek Goyal return err; 153e9be9d5eSMiklos Szeredi } 154e9be9d5eSMiklos Szeredi 1556b255391SAl Viro static const char *ovl_get_link(struct dentry *dentry, 156fceef393SAl Viro struct inode *inode, 157fceef393SAl Viro struct delayed_call *done) 158e9be9d5eSMiklos Szeredi { 1591175b6b8SVivek Goyal const struct cred *old_cred; 1601175b6b8SVivek Goyal const char *p; 161e9be9d5eSMiklos Szeredi 1626b255391SAl Viro if (!dentry) 1636b255391SAl Viro return ERR_PTR(-ECHILD); 1646b255391SAl Viro 1651175b6b8SVivek Goyal old_cred = ovl_override_creds(dentry->d_sb); 166*7764235bSMiklos Szeredi p = vfs_get_link(ovl_dentry_real(dentry), done); 1671175b6b8SVivek Goyal revert_creds(old_cred); 1681175b6b8SVivek Goyal return p; 169e9be9d5eSMiklos Szeredi } 170e9be9d5eSMiklos Szeredi 1710956254aSMiklos Szeredi bool ovl_is_private_xattr(const char *name) 172e9be9d5eSMiklos Szeredi { 173fe2b7595SAndreas Gruenbacher return strncmp(name, OVL_XATTR_PREFIX, 174fe2b7595SAndreas Gruenbacher sizeof(OVL_XATTR_PREFIX) - 1) == 0; 175e9be9d5eSMiklos Szeredi } 176e9be9d5eSMiklos Szeredi 1770e585cccSAndreas Gruenbacher int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, 1783767e255SAl Viro size_t size, int flags) 179e9be9d5eSMiklos Szeredi { 180e9be9d5eSMiklos Szeredi int err; 1810e585cccSAndreas Gruenbacher struct path realpath; 1820e585cccSAndreas Gruenbacher enum ovl_path_type type = ovl_path_real(dentry, &realpath); 1831175b6b8SVivek Goyal const struct cred *old_cred; 184e9be9d5eSMiklos Szeredi 185e9be9d5eSMiklos Szeredi err = ovl_want_write(dentry); 186e9be9d5eSMiklos Szeredi if (err) 187e9be9d5eSMiklos Szeredi goto out; 188e9be9d5eSMiklos Szeredi 1890e585cccSAndreas Gruenbacher if (!value && !OVL_TYPE_UPPER(type)) { 1900e585cccSAndreas Gruenbacher err = vfs_getxattr(realpath.dentry, name, NULL, 0); 1910e585cccSAndreas Gruenbacher if (err < 0) 1920e585cccSAndreas Gruenbacher goto out_drop_write; 1930e585cccSAndreas Gruenbacher } 1940e585cccSAndreas Gruenbacher 195e9be9d5eSMiklos Szeredi err = ovl_copy_up(dentry); 196e9be9d5eSMiklos Szeredi if (err) 197e9be9d5eSMiklos Szeredi goto out_drop_write; 198e9be9d5eSMiklos Szeredi 1990e585cccSAndreas Gruenbacher if (!OVL_TYPE_UPPER(type)) 2000e585cccSAndreas Gruenbacher ovl_path_upper(dentry, &realpath); 2010e585cccSAndreas Gruenbacher 2021175b6b8SVivek Goyal old_cred = ovl_override_creds(dentry->d_sb); 2030e585cccSAndreas Gruenbacher if (value) 2040e585cccSAndreas Gruenbacher err = vfs_setxattr(realpath.dentry, name, value, size, flags); 2050e585cccSAndreas Gruenbacher else { 2060e585cccSAndreas Gruenbacher WARN_ON(flags != XATTR_REPLACE); 2070e585cccSAndreas Gruenbacher err = vfs_removexattr(realpath.dentry, name); 2080e585cccSAndreas Gruenbacher } 2091175b6b8SVivek Goyal revert_creds(old_cred); 210e9be9d5eSMiklos Szeredi 211e9be9d5eSMiklos Szeredi out_drop_write: 212e9be9d5eSMiklos Szeredi ovl_drop_write(dentry); 213e9be9d5eSMiklos Szeredi out: 214e9be9d5eSMiklos Szeredi return err; 215e9be9d5eSMiklos Szeredi } 216e9be9d5eSMiklos Szeredi 2170eb45fc3SAndreas Gruenbacher int ovl_xattr_get(struct dentry *dentry, const char *name, 2180eb45fc3SAndreas Gruenbacher void *value, size_t size) 219e9be9d5eSMiklos Szeredi { 220b581755bSMiklos Szeredi struct dentry *realdentry = ovl_dentry_real(dentry); 2211175b6b8SVivek Goyal ssize_t res; 2221175b6b8SVivek Goyal const struct cred *old_cred; 22352148463SMiklos Szeredi 2241175b6b8SVivek Goyal old_cred = ovl_override_creds(dentry->d_sb); 2251175b6b8SVivek Goyal res = vfs_getxattr(realdentry, name, value, size); 2261175b6b8SVivek Goyal revert_creds(old_cred); 2271175b6b8SVivek Goyal return res; 228e9be9d5eSMiklos Szeredi } 229e9be9d5eSMiklos Szeredi 230e9be9d5eSMiklos Szeredi ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) 231e9be9d5eSMiklos Szeredi { 232b581755bSMiklos Szeredi struct dentry *realdentry = ovl_dentry_real(dentry); 233e9be9d5eSMiklos Szeredi ssize_t res; 2347cb35119SMiklos Szeredi size_t len; 2357cb35119SMiklos Szeredi char *s; 2361175b6b8SVivek Goyal const struct cred *old_cred; 237e9be9d5eSMiklos Szeredi 2381175b6b8SVivek Goyal old_cred = ovl_override_creds(dentry->d_sb); 239b581755bSMiklos Szeredi res = vfs_listxattr(realdentry, list, size); 2401175b6b8SVivek Goyal revert_creds(old_cred); 241e9be9d5eSMiklos Szeredi if (res <= 0 || size == 0) 242e9be9d5eSMiklos Szeredi return res; 243e9be9d5eSMiklos Szeredi 244e9be9d5eSMiklos Szeredi /* filter out private xattrs */ 2457cb35119SMiklos Szeredi for (s = list, len = res; len;) { 2467cb35119SMiklos Szeredi size_t slen = strnlen(s, len) + 1; 247e9be9d5eSMiklos Szeredi 2487cb35119SMiklos Szeredi /* underlying fs providing us with an broken xattr list? */ 2497cb35119SMiklos Szeredi if (WARN_ON(slen > len)) 2507cb35119SMiklos Szeredi return -EIO; 251e9be9d5eSMiklos Szeredi 2527cb35119SMiklos Szeredi len -= slen; 253e9be9d5eSMiklos Szeredi if (ovl_is_private_xattr(s)) { 254e9be9d5eSMiklos Szeredi res -= slen; 2557cb35119SMiklos Szeredi memmove(s, s + slen, len); 256e9be9d5eSMiklos Szeredi } else { 2577cb35119SMiklos Szeredi s += slen; 258e9be9d5eSMiklos Szeredi } 259e9be9d5eSMiklos Szeredi } 260e9be9d5eSMiklos Szeredi 261e9be9d5eSMiklos Szeredi return res; 262e9be9d5eSMiklos Szeredi } 263e9be9d5eSMiklos Szeredi 26439a25b2bSVivek Goyal struct posix_acl *ovl_get_acl(struct inode *inode, int type) 26539a25b2bSVivek Goyal { 26639b681f8SMiklos Szeredi struct inode *realinode = ovl_inode_real(inode, NULL); 2671175b6b8SVivek Goyal const struct cred *old_cred; 2681175b6b8SVivek Goyal struct posix_acl *acl; 26939a25b2bSVivek Goyal 2705201dc44SMiklos Szeredi if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode)) 27139a25b2bSVivek Goyal return NULL; 27239a25b2bSVivek Goyal 27339a25b2bSVivek Goyal if (!realinode->i_op->get_acl) 27439a25b2bSVivek Goyal return NULL; 27539a25b2bSVivek Goyal 2761175b6b8SVivek Goyal old_cred = ovl_override_creds(inode->i_sb); 2775201dc44SMiklos Szeredi acl = get_acl(realinode, type); 2781175b6b8SVivek Goyal revert_creds(old_cred); 2791175b6b8SVivek Goyal 2801175b6b8SVivek Goyal return acl; 28139a25b2bSVivek Goyal } 28239a25b2bSVivek Goyal 283e9be9d5eSMiklos Szeredi static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, 284e9be9d5eSMiklos Szeredi struct dentry *realdentry) 285e9be9d5eSMiklos Szeredi { 2861afaba1eSMiklos Szeredi if (OVL_TYPE_UPPER(type)) 287e9be9d5eSMiklos Szeredi return false; 288e9be9d5eSMiklos Szeredi 289e9be9d5eSMiklos Szeredi if (special_file(realdentry->d_inode->i_mode)) 290e9be9d5eSMiklos Szeredi return false; 291e9be9d5eSMiklos Szeredi 292e9be9d5eSMiklos Szeredi if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC)) 293e9be9d5eSMiklos Szeredi return false; 294e9be9d5eSMiklos Szeredi 295e9be9d5eSMiklos Szeredi return true; 296e9be9d5eSMiklos Szeredi } 297e9be9d5eSMiklos Szeredi 2982d902671SMiklos Szeredi int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags) 299e9be9d5eSMiklos Szeredi { 3002d902671SMiklos Szeredi int err = 0; 301e9be9d5eSMiklos Szeredi struct path realpath; 302e9be9d5eSMiklos Szeredi enum ovl_path_type type; 303e9be9d5eSMiklos Szeredi 304e9be9d5eSMiklos Szeredi type = ovl_path_real(dentry, &realpath); 3054bacc9c9SDavid Howells if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { 306e9be9d5eSMiklos Szeredi err = ovl_want_write(dentry); 3072d902671SMiklos Szeredi if (!err) { 3084bacc9c9SDavid Howells if (file_flags & O_TRUNC) 3090f7ff2daSAl Viro err = ovl_copy_up_truncate(dentry); 310e9be9d5eSMiklos Szeredi else 311e9be9d5eSMiklos Szeredi err = ovl_copy_up(dentry); 312f25801eeSDavid Howells ovl_drop_write(dentry); 3132d902671SMiklos Szeredi } 314e9be9d5eSMiklos Szeredi } 315e9be9d5eSMiklos Szeredi 3162d902671SMiklos Szeredi return err; 317e9be9d5eSMiklos Szeredi } 318e9be9d5eSMiklos Szeredi 319d719e8f2SMiklos Szeredi int ovl_update_time(struct inode *inode, struct timespec *ts, int flags) 320d719e8f2SMiklos Szeredi { 321d719e8f2SMiklos Szeredi struct dentry *alias; 322d719e8f2SMiklos Szeredi struct path upperpath; 323d719e8f2SMiklos Szeredi 324d719e8f2SMiklos Szeredi if (!(flags & S_ATIME)) 325d719e8f2SMiklos Szeredi return 0; 326d719e8f2SMiklos Szeredi 327d719e8f2SMiklos Szeredi alias = d_find_any_alias(inode); 328d719e8f2SMiklos Szeredi if (!alias) 329d719e8f2SMiklos Szeredi return 0; 330d719e8f2SMiklos Szeredi 331d719e8f2SMiklos Szeredi ovl_path_upper(alias, &upperpath); 332d719e8f2SMiklos Szeredi if (upperpath.dentry) { 333d719e8f2SMiklos Szeredi touch_atime(&upperpath); 334d719e8f2SMiklos Szeredi inode->i_atime = d_inode(upperpath.dentry)->i_atime; 335d719e8f2SMiklos Szeredi } 336d719e8f2SMiklos Szeredi 337d719e8f2SMiklos Szeredi dput(alias); 338d719e8f2SMiklos Szeredi 339d719e8f2SMiklos Szeredi return 0; 340d719e8f2SMiklos Szeredi } 341d719e8f2SMiklos Szeredi 342e9be9d5eSMiklos Szeredi static const struct inode_operations ovl_file_inode_operations = { 343e9be9d5eSMiklos Szeredi .setattr = ovl_setattr, 344e9be9d5eSMiklos Szeredi .permission = ovl_permission, 345e9be9d5eSMiklos Szeredi .getattr = ovl_getattr, 346d837a49bSMiklos Szeredi .setxattr = generic_setxattr, 3470eb45fc3SAndreas Gruenbacher .getxattr = generic_getxattr, 348e9be9d5eSMiklos Szeredi .listxattr = ovl_listxattr, 3490e585cccSAndreas Gruenbacher .removexattr = generic_removexattr, 35039a25b2bSVivek Goyal .get_acl = ovl_get_acl, 351d719e8f2SMiklos Szeredi .update_time = ovl_update_time, 352e9be9d5eSMiklos Szeredi }; 353e9be9d5eSMiklos Szeredi 354e9be9d5eSMiklos Szeredi static const struct inode_operations ovl_symlink_inode_operations = { 355e9be9d5eSMiklos Szeredi .setattr = ovl_setattr, 3566b255391SAl Viro .get_link = ovl_get_link, 35778a3fa4fSMiklos Szeredi .readlink = generic_readlink, 358e9be9d5eSMiklos Szeredi .getattr = ovl_getattr, 359d837a49bSMiklos Szeredi .setxattr = generic_setxattr, 3600eb45fc3SAndreas Gruenbacher .getxattr = generic_getxattr, 361e9be9d5eSMiklos Szeredi .listxattr = ovl_listxattr, 3620e585cccSAndreas Gruenbacher .removexattr = generic_removexattr, 363d719e8f2SMiklos Szeredi .update_time = ovl_update_time, 364e9be9d5eSMiklos Szeredi }; 365e9be9d5eSMiklos Szeredi 36651f7e52dSMiklos Szeredi static void ovl_fill_inode(struct inode *inode, umode_t mode) 367e9be9d5eSMiklos Szeredi { 368e9be9d5eSMiklos Szeredi inode->i_ino = get_next_ino(); 369e9be9d5eSMiklos Szeredi inode->i_mode = mode; 370d719e8f2SMiklos Szeredi inode->i_flags |= S_NOCMTIME; 3712a3a2a3fSMiklos Szeredi #ifdef CONFIG_FS_POSIX_ACL 3722a3a2a3fSMiklos Szeredi inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE; 3732a3a2a3fSMiklos Szeredi #endif 374e9be9d5eSMiklos Szeredi 37507a2daabSVivek Goyal mode &= S_IFMT; 376e9be9d5eSMiklos Szeredi switch (mode) { 377e9be9d5eSMiklos Szeredi case S_IFDIR: 378e9be9d5eSMiklos Szeredi inode->i_op = &ovl_dir_inode_operations; 379e9be9d5eSMiklos Szeredi inode->i_fop = &ovl_dir_operations; 380e9be9d5eSMiklos Szeredi break; 381e9be9d5eSMiklos Szeredi 382e9be9d5eSMiklos Szeredi case S_IFLNK: 383e9be9d5eSMiklos Szeredi inode->i_op = &ovl_symlink_inode_operations; 384e9be9d5eSMiklos Szeredi break; 385e9be9d5eSMiklos Szeredi 38651f7e52dSMiklos Szeredi default: 38751f7e52dSMiklos Szeredi WARN(1, "illegal file type: %i\n", mode); 38851f7e52dSMiklos Szeredi /* Fall through */ 38951f7e52dSMiklos Szeredi 390e9be9d5eSMiklos Szeredi case S_IFREG: 391e9be9d5eSMiklos Szeredi case S_IFSOCK: 392e9be9d5eSMiklos Szeredi case S_IFBLK: 393e9be9d5eSMiklos Szeredi case S_IFCHR: 394e9be9d5eSMiklos Szeredi case S_IFIFO: 395e9be9d5eSMiklos Szeredi inode->i_op = &ovl_file_inode_operations; 396e9be9d5eSMiklos Szeredi break; 39751f7e52dSMiklos Szeredi } 39851f7e52dSMiklos Szeredi } 399e9be9d5eSMiklos Szeredi 40051f7e52dSMiklos Szeredi struct inode *ovl_new_inode(struct super_block *sb, umode_t mode) 40151f7e52dSMiklos Szeredi { 40251f7e52dSMiklos Szeredi struct inode *inode; 40351f7e52dSMiklos Szeredi 40451f7e52dSMiklos Szeredi inode = new_inode(sb); 40551f7e52dSMiklos Szeredi if (inode) 40651f7e52dSMiklos Szeredi ovl_fill_inode(inode, mode); 40751f7e52dSMiklos Szeredi 40851f7e52dSMiklos Szeredi return inode; 40951f7e52dSMiklos Szeredi } 41051f7e52dSMiklos Szeredi 41151f7e52dSMiklos Szeredi static int ovl_inode_test(struct inode *inode, void *data) 41251f7e52dSMiklos Szeredi { 41351f7e52dSMiklos Szeredi return ovl_inode_real(inode, NULL) == data; 41451f7e52dSMiklos Szeredi } 41551f7e52dSMiklos Szeredi 41651f7e52dSMiklos Szeredi static int ovl_inode_set(struct inode *inode, void *data) 41751f7e52dSMiklos Szeredi { 41851f7e52dSMiklos Szeredi inode->i_private = (void *) (((unsigned long) data) | OVL_ISUPPER_MASK); 41951f7e52dSMiklos Szeredi return 0; 42051f7e52dSMiklos Szeredi } 42151f7e52dSMiklos Szeredi 42251f7e52dSMiklos Szeredi struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode) 42351f7e52dSMiklos Szeredi 42451f7e52dSMiklos Szeredi { 42551f7e52dSMiklos Szeredi struct inode *inode; 42651f7e52dSMiklos Szeredi 42751f7e52dSMiklos Szeredi inode = iget5_locked(sb, (unsigned long) realinode, 42851f7e52dSMiklos Szeredi ovl_inode_test, ovl_inode_set, realinode); 42951f7e52dSMiklos Szeredi if (inode && inode->i_state & I_NEW) { 43051f7e52dSMiklos Szeredi ovl_fill_inode(inode, realinode->i_mode); 43151f7e52dSMiklos Szeredi set_nlink(inode, realinode->i_nlink); 43251f7e52dSMiklos Szeredi unlock_new_inode(inode); 433e9be9d5eSMiklos Szeredi } 434e9be9d5eSMiklos Szeredi 435e9be9d5eSMiklos Szeredi return inode; 436e9be9d5eSMiklos Szeredi } 437