static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) { int err; struct dentry *newdentry; const struct cred *old_cred; struct cred *override_cred; /* FIXME: recheck lower dentry to see if whiteout is really needed */ err = -ENOMEM; override_cred = ovl_prepare_creds(dentry->d_sb); if (!override_cred) goto out; override_cred->fsuid = make_kuid(override_cred->user_ns, 0); if (!uid_valid(override_cred->fsuid)) override_cred->fsuid = GLOBAL_ROOT_UID; override_cred->fsgid = make_kgid(override_cred->user_ns, 0); if (!gid_valid(override_cred->fsgid)) override_cred->fsgid = GLOBAL_ROOT_GID; old_cred = override_creds(override_cred); newdentry = lookup_one_len(dentry->d_name.name, upperdir, dentry->d_name.len); err = PTR_ERR(newdentry); if (IS_ERR(newdentry)) goto out_put_cred; /* Just been removed within the same locked region */ WARN_ON(newdentry->d_inode); err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink); if (err) goto out_dput; ovl_dentry_version_inc(dentry->d_parent); err = ovl_do_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0); if (err) vfs_unlink(upperdir->d_inode, newdentry, NULL); out_dput: dput(newdentry); out_put_cred: revert_creds(old_cred); put_cred(override_cred); out: if (err) { /* * There's no way to recover from failure to whiteout. * What should we do? Log a big fat error and... ? */ pr_err("overlayfs: ERROR - failed to whiteout '%s'\n", dentry->d_name.name); } return err; }
static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) { int err; err = ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0); if (!err) ovl_dentry_set_opaque(dentry); return err; }
static int ovl_set_nlink_common(struct dentry *dentry, struct dentry *realdentry, const char *format) { struct inode *inode = d_inode(dentry); struct inode *realinode = d_inode(realdentry); char buf[13]; int len; len = snprintf(buf, sizeof(buf), format, (int) (inode->i_nlink - realinode->i_nlink)); if (WARN_ON(len >= sizeof(buf))) return -EIO; return ovl_do_setxattr(ovl_dentry_upper(dentry), OVL_XATTR_NLINK, buf, len, 0); }
static int ovl_set_opaque(struct dentry *upperdentry) { return ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0); }
static int ovl_set_opaque(struct dentry *upperdentry) { return ovl_do_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0); }
static int ovl_make_workdir(struct ovl_fs *ofs, struct path *workpath) { struct vfsmount *mnt = ofs->upper_mnt; struct dentry *temp; int fh_type; int err; err = mnt_want_write(mnt); if (err) return err; ofs->workdir = ovl_workdir_create(ofs, OVL_WORKDIR_NAME, false); if (!ofs->workdir) goto out; /* * Upper should support d_type, else whiteouts are visible. Given * workdir and upper are on same fs, we can do iterate_dir() on * workdir. This check requires successful creation of workdir in * previous step. */ err = ovl_check_d_type_supported(workpath); if (err < 0) goto out; /* * We allowed this configuration and don't want to break users over * kernel upgrade. So warn instead of erroring out. */ if (!err) pr_warn("overlayfs: upper fs needs to support d_type.\n"); /* Check if upper/work fs supports O_TMPFILE */ temp = ovl_do_tmpfile(ofs->workdir, S_IFREG | 0); ofs->tmpfile = !IS_ERR(temp); if (ofs->tmpfile) dput(temp); else pr_warn("overlayfs: upper fs does not support tmpfile.\n"); /* * Check if upper/work fs supports trusted.overlay.* xattr */ err = ovl_do_setxattr(ofs->workdir, OVL_XATTR_OPAQUE, "0", 1, 0); if (err) { ofs->noxattr = true; ofs->config.index = false; ofs->config.metacopy = false; pr_warn("overlayfs: upper fs does not support xattr, falling back to index=off and metacopy=off.\n"); err = 0; } else { vfs_removexattr(ofs->workdir, OVL_XATTR_OPAQUE); } /* Check if upper/work fs supports file handles */ fh_type = ovl_can_decode_fh(ofs->workdir->d_sb); if (ofs->config.index && !fh_type) { ofs->config.index = false; pr_warn("overlayfs: upper fs does not support file handles, falling back to index=off.\n"); } /* Check if upper fs has 32bit inode numbers */ if (fh_type != FILEID_INO32_GEN) ofs->xino_bits = 0; /* NFS export of r/w mount depends on index */ if (ofs->config.nfs_export && !ofs->config.index) { pr_warn("overlayfs: NFS export requires \"index=on\", falling back to nfs_export=off.\n"); ofs->config.nfs_export = false; } out: mnt_drop_write(mnt); return err; }