* performed on the raw inode simply passs init_user_ns.
  */
 static bool chown_ok(struct user_namespace *mnt_userns,
-                    const struct inode *inode,
-                    kuid_t uid)
+                    const struct inode *inode, vfsuid_t ia_vfsuid)
 {
-       kuid_t kuid = i_uid_into_mnt(mnt_userns, inode);
-       if (uid_eq(current_fsuid(), kuid) && uid_eq(uid, inode->i_uid))
+       vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+       if (vfsuid_eq_kuid(vfsuid, current_fsuid()) &&
+           vfsuid_eq(ia_vfsuid, vfsuid))
                return true;
        if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
                return true;
-       if (uid_eq(kuid, INVALID_UID) &&
+       if (!vfsuid_valid(vfsuid) &&
            ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
                return true;
        return false;
  * performed on the raw inode simply passs init_user_ns.
  */
 static bool chgrp_ok(struct user_namespace *mnt_userns,
-                    const struct inode *inode, kgid_t gid)
+                    const struct inode *inode, vfsgid_t ia_vfsgid)
 {
-       kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
-       if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode))) {
-               kgid_t mapped_gid;
-
-               if (gid_eq(gid, inode->i_gid))
+       vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+       vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+       if (vfsuid_eq_kuid(vfsuid, current_fsuid())) {
+               if (vfsgid_eq(ia_vfsgid, vfsgid))
                        return true;
-               mapped_gid = mapped_kgid_fs(mnt_userns, i_user_ns(inode), gid);
-               if (in_group_p(mapped_gid))
+               if (vfsgid_in_group_p(ia_vfsgid))
                        return true;
        }
        if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
                return true;
-       if (gid_eq(kgid, INVALID_GID) &&
+       if (!vfsgid_valid(vfsgid) &&
            ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
                return true;
        return false;
                goto kill_priv;
 
        /* Make sure a caller can chown. */
-       if ((ia_valid & ATTR_UID) && !chown_ok(mnt_userns, inode, attr->ia_uid))
+       if ((ia_valid & ATTR_UID) &&
+           !chown_ok(mnt_userns, inode, attr->ia_vfsuid))
                return -EPERM;
 
        /* Make sure caller can chgrp. */
-       if ((ia_valid & ATTR_GID) && !chgrp_ok(mnt_userns, inode, attr->ia_gid))
+       if ((ia_valid & ATTR_GID) &&
+           !chgrp_ok(mnt_userns, inode, attr->ia_vfsgid))
                return -EPERM;
 
        /* Make sure a caller can chmod. */
        if (ia_valid & ATTR_MODE) {
-               kgid_t mapped_gid;
+               vfsgid_t vfsgid;
 
                if (!inode_owner_or_capable(mnt_userns, inode))
                        return -EPERM;
 
                if (ia_valid & ATTR_GID)
-                       mapped_gid = mapped_kgid_fs(mnt_userns,
-                                               i_user_ns(inode), attr->ia_gid);
+                       vfsgid = attr->ia_vfsgid;
                else
-                       mapped_gid = i_gid_into_mnt(mnt_userns, inode);
+                       vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
 
                /* Also check the setgid bit! */
-               if (!in_group_p(mapped_gid) &&
+               if (!vfsgid_in_group_p(vfsgid) &&
                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                        attr->ia_mode &= ~S_ISGID;
        }
  * setattr_copy must be called with i_mutex held.
  *
  * setattr_copy updates the inode's metadata with that specified
- * in attr on idmapped mounts. If file ownership is changed setattr_copy
- * doesn't map ia_uid and ia_gid. It will asssume the caller has already
- * provided the intended values. Necessary permission checks to determine
+ * in attr on idmapped mounts. Necessary permission checks to determine
  * whether or not the S_ISGID property needs to be removed are performed with
  * the correct idmapped mount permission helpers.
  * Noticeably missing is inode size update, which is more complex
 {
        unsigned int ia_valid = attr->ia_valid;
 
-       i_uid_update(&init_user_ns, attr, inode);
-       i_gid_update(&init_user_ns, attr, inode);
+       i_uid_update(mnt_userns, attr, inode);
+       i_gid_update(mnt_userns, attr, inode);
        if (ia_valid & ATTR_ATIME)
                inode->i_atime = attr->ia_atime;
        if (ia_valid & ATTR_MTIME)
                inode->i_ctime = attr->ia_ctime;
        if (ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
-               kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
-               if (!in_group_p(kgid) &&
+               vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
+               if (!vfsgid_in_group_p(vfsgid) &&
                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                        mode &= ~S_ISGID;
                inode->i_mode = mode;
  * retry.  Because breaking a delegation may take a long time, the
  * caller should drop the i_mutex before doing so.
  *
- * If file ownership is changed notify_change() doesn't map ia_uid and
- * ia_gid. It will asssume the caller has already provided the intended values.
- *
  * Alternatively, a caller may pass NULL for delegated_inode.  This may
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.  Also, passing NULL is fine for callers holding
         * namespace of the superblock.
         */
        if (ia_valid & ATTR_UID &&
-           !kuid_has_mapping(inode->i_sb->s_user_ns, attr->ia_uid))
+           !vfsuid_has_fsmapping(mnt_userns, inode->i_sb->s_user_ns,
+                                 attr->ia_vfsuid))
                return -EOVERFLOW;
        if (ia_valid & ATTR_GID &&
-           !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid))
+           !vfsgid_has_fsmapping(mnt_userns, inode->i_sb->s_user_ns,
+                                 attr->ia_vfsgid))
                return -EOVERFLOW;
 
        /* Don't allow modifications of files with invalid uids or
         * gids unless those uids & gids are being made valid.
         */
        if (!(ia_valid & ATTR_UID) &&
-           !uid_valid(i_uid_into_mnt(mnt_userns, inode)))
+           !vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)))
                return -EOVERFLOW;
        if (!(ia_valid & ATTR_GID) &&
-           !gid_valid(i_gid_into_mnt(mnt_userns, inode)))
+           !vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
                return -EOVERFLOW;
 
-       error = security_inode_setattr(&init_user_ns, dentry, attr);
+       error = security_inode_setattr(mnt_userns, dentry, attr);
        if (error)
                return error;
        error = try_break_deleg(inode, delegated_inode);
 
        if (error)
                return error;
 
-       if (is_quota_modification(&init_user_ns, inode, iattr)) {
+       if (is_quota_modification(mnt_userns, inode, iattr)) {
                error = dquot_initialize(inode);
                if (error)
                        return error;
        }
-       if (i_uid_needs_update(&init_user_ns, iattr, inode) ||
-           i_gid_needs_update(&init_user_ns, iattr, inode)) {
-               error = dquot_transfer(&init_user_ns, inode, iattr);
+       if (i_uid_needs_update(mnt_userns, iattr, inode) ||
+           i_gid_needs_update(mnt_userns, iattr, inode)) {
+               error = dquot_transfer(mnt_userns, inode, iattr);
                if (error)
                        return error;
        }
 
        if (error)
                return error;
 
-       if (is_quota_modification(&init_user_ns, inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                error = dquot_initialize(inode);
                if (error)
                        return error;
        }
 
-       if (i_uid_needs_update(&init_user_ns, attr, inode) ||
-           i_gid_needs_update(&init_user_ns, attr, inode)) {
+       if (i_uid_needs_update(mnt_userns, attr, inode) ||
+           i_gid_needs_update(mnt_userns, attr, inode)) {
                handle_t *handle;
 
                /* (user+group)*(old+new) structure, inode write (sb,
                 * counts xattr inode references.
                 */
                down_read(&EXT4_I(inode)->xattr_sem);
-               error = dquot_transfer(&init_user_ns, inode, attr);
+               error = dquot_transfer(mnt_userns, inode, attr);
                up_read(&EXT4_I(inode)->xattr_sem);
 
                if (error) {
                }
                /* Update corresponding info in inode so that everything is in
                 * one transaction */
-               i_uid_update(&init_user_ns, attr, inode);
-               i_gid_update(&init_user_ns, attr, inode);
+               i_uid_update(mnt_userns, attr, inode);
+               i_gid_update(mnt_userns, attr, inode);
                error = ext4_mark_inode_dirty(handle, inode);
                ext4_journal_stop(handle);
                if (unlikely(error)) {
 
 {
        unsigned int ia_valid = attr->ia_valid;
 
-       i_uid_update(&init_user_ns, attr, inode);
-       i_gid_update(&init_user_ns, attr, inode);
+       i_uid_update(mnt_userns, attr, inode);
+       i_gid_update(mnt_userns, attr, inode);
        if (ia_valid & ATTR_ATIME)
                inode->i_atime = attr->ia_atime;
        if (ia_valid & ATTR_MTIME)
        if (err)
                return err;
 
-       if (is_quota_modification(&init_user_ns, inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                err = f2fs_dquot_initialize(inode);
                if (err)
                        return err;
        }
-       if (i_uid_needs_update(&init_user_ns, attr, inode) ||
-           i_gid_needs_update(&init_user_ns, attr, inode)) {
+       if (i_uid_needs_update(mnt_userns, attr, inode) ||
+           i_gid_needs_update(mnt_userns, attr, inode)) {
                f2fs_lock_op(F2FS_I_SB(inode));
-               err = dquot_transfer(&init_user_ns, inode, attr);
+               err = dquot_transfer(mnt_userns, inode, attr);
                if (err) {
                        set_sbi_flag(F2FS_I_SB(inode),
                                        SBI_QUOTA_NEED_REPAIR);
                 * update uid/gid under lock_op(), so that dquot and inode can
                 * be updated atomically.
                 */
-               i_uid_update(&init_user_ns, attr, inode);
-               i_gid_update(&init_user_ns, attr, inode);
+               i_uid_update(mnt_userns, attr, inode);
+               i_gid_update(mnt_userns, attr, inode);
                f2fs_mark_inode_dirty_sync(inode, true);
                f2fs_unlock_op(F2FS_I_SB(inode));
        }
 
 
        memset(&attr, 0, sizeof(attr));
 
-       attr.ia_uid = make_kuid(inode->i_sb->s_user_ns, i_uid);
-       attr.ia_gid = make_kgid(inode->i_sb->s_user_ns, i_gid);
+       attr.ia_vfsuid = VFSUIDT_INIT(make_kuid(inode->i_sb->s_user_ns, i_uid));
+       attr.ia_vfsgid = VFSGIDT_INIT(make_kgid(inode->i_sb->s_user_ns, i_gid));
 
-       if (!uid_eq(attr.ia_uid, inode->i_uid))
+       if (!vfsuid_eq(attr.ia_vfsuid, i_uid_into_vfsuid(&init_user_ns, inode)))
                attr.ia_valid |= ATTR_UID;
-       if (!gid_eq(attr.ia_gid, inode->i_gid))
+       if (!vfsgid_eq(attr.ia_vfsgid, i_gid_into_vfsgid(&init_user_ns, inode)))
                attr.ia_valid |= ATTR_GID;
 
        if (!attr.ia_valid)
 
         * out the RO attribute for checking by the security
         * module, just because it maps to a file mode.
         */
-       err = security_inode_setattr(&init_user_ns,
+       err = security_inode_setattr(file_mnt_user_ns(file),
                                     file->f_path.dentry, &ia);
        if (err)
                goto out_unlock_inode;
        }
 
        if (((attr->ia_valid & ATTR_UID) &&
-            (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
+            (!uid_eq(from_vfsuid(mnt_userns, i_user_ns(inode), attr->ia_vfsuid),
+                     sbi->options.fs_uid))) ||
            ((attr->ia_valid & ATTR_GID) &&
-            (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
+            (!gid_eq(from_vfsgid(mnt_userns, i_user_ns(inode), attr->ia_vfsgid),
+                     sbi->options.fs_gid))) ||
            ((attr->ia_valid & ATTR_MODE) &&
             (attr->ia_mode & ~FAT_VALID_MODE)))
                error = -EPERM;
 
        if (rc)
                return rc;
 
-       if (is_quota_modification(&init_user_ns, inode, iattr)) {
+       if (is_quota_modification(mnt_userns, inode, iattr)) {
                rc = dquot_initialize(inode);
                if (rc)
                        return rc;
        }
        if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
            (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
-               rc = dquot_transfer(&init_user_ns, inode, iattr);
+               rc = dquot_transfer(mnt_userns, inode, iattr);
                if (rc)
                        return rc;
        }
 
        if (status)
                return status;
 
-       if (is_quota_modification(&init_user_ns, inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                status = dquot_initialize(inode);
                if (status)
                        return status;
 
        return do_fchmodat(AT_FDCWD, filename, mode);
 }
 
+/**
+ * setattr_vfsuid - check and set ia_fsuid attribute
+ * @kuid: new inode owner
+ *
+ * Check whether @kuid is valid and if so generate and set vfsuid_t in
+ * ia_vfsuid.
+ *
+ * Return: true if @kuid is valid, false if not.
+ */
+static inline bool setattr_vfsuid(struct iattr *attr, kuid_t kuid)
+{
+       if (!uid_valid(kuid))
+               return false;
+       attr->ia_valid |= ATTR_UID;
+       attr->ia_vfsuid = VFSUIDT_INIT(kuid);
+       return true;
+}
+
+/**
+ * setattr_vfsgid - check and set ia_fsgid attribute
+ * @kgid: new inode owner
+ *
+ * Check whether @kgid is valid and if so generate and set vfsgid_t in
+ * ia_vfsgid.
+ *
+ * Return: true if @kgid is valid, false if not.
+ */
+static inline bool setattr_vfsgid(struct iattr *attr, kgid_t kgid)
+{
+       if (!gid_valid(kgid))
+               return false;
+       attr->ia_valid |= ATTR_GID;
+       attr->ia_vfsgid = VFSGIDT_INIT(kgid);
+       return true;
+}
+
 int chown_common(const struct path *path, uid_t user, gid_t group)
 {
        struct user_namespace *mnt_userns, *fs_userns;
 
        mnt_userns = mnt_user_ns(path->mnt);
        fs_userns = i_user_ns(inode);
-       uid = mapped_kuid_user(mnt_userns, fs_userns, uid);
-       gid = mapped_kgid_user(mnt_userns, fs_userns, gid);
 
 retry_deleg:
        newattrs.ia_valid =  ATTR_CTIME;
-       if (user != (uid_t) -1) {
-               if (!uid_valid(uid))
-                       return -EINVAL;
-               newattrs.ia_valid |= ATTR_UID;
-               newattrs.ia_uid = uid;
-       }
-       if (group != (gid_t) -1) {
-               if (!gid_valid(gid))
-                       return -EINVAL;
-               newattrs.ia_valid |= ATTR_GID;
-               newattrs.ia_gid = gid;
-       }
+       if ((user != (uid_t)-1) && !setattr_vfsuid(&newattrs, uid))
+               return -EINVAL;
+       if ((group != (gid_t)-1) && !setattr_vfsgid(&newattrs, gid))
+               return -EINVAL;
        if (!S_ISDIR(inode->i_mode))
                newattrs.ia_valid |=
                        ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
        inode_lock(inode);
-       error = security_path_chown(path, uid, gid);
+       /* Continue to send actual fs values, not the mount values. */
+       error = security_path_chown(
+               path,
+               from_vfsuid(mnt_userns, fs_userns, newattrs.ia_vfsuid),
+               from_vfsgid(mnt_userns, fs_userns, newattrs.ia_vfsgid));
        if (!error)
                error = notify_change(mnt_userns, path->dentry, &newattrs,
                                      &delegated_inode);
 
        if (!err) {
                struct iattr attr = {
                        .ia_valid = ATTR_UID | ATTR_GID,
-                       .ia_uid = stat->uid,
-                       .ia_gid = stat->gid,
+                       .ia_vfsuid = VFSUIDT_INIT(stat->uid),
+                       .ia_vfsgid = VFSGIDT_INIT(stat->gid),
                };
                err = ovl_do_notify_change(ofs, upperdentry, &attr);
        }
 
                                       struct dentry *upperdentry,
                                       struct iattr *attr)
 {
-       struct user_namespace *upper_mnt_userns = ovl_upper_mnt_userns(ofs);
-       struct user_namespace *fs_userns = i_user_ns(d_inode(upperdentry));
-
-       if (attr->ia_valid & ATTR_UID)
-               attr->ia_uid = mapped_kuid_user(upper_mnt_userns,
-                                               fs_userns, attr->ia_uid);
-       if (attr->ia_valid & ATTR_GID)
-               attr->ia_gid = mapped_kgid_user(upper_mnt_userns,
-                                               fs_userns, attr->ia_gid);
-
-       return notify_change(upper_mnt_userns, upperdentry, attr, NULL);
+       return notify_change(ovl_upper_mnt_userns(ofs), upperdentry, attr, NULL);
 }
 
 static inline int ovl_do_rmdir(struct ovl_fs *ofs,
 
        if (!dquot_active(inode))
                return 0;
 
-       if (i_uid_needs_update(&init_user_ns, iattr, inode)) {
-               dquot = dqget(sb, make_kqid_uid(iattr->ia_uid));
+       if (i_uid_needs_update(mnt_userns, iattr, inode)) {
+               kuid_t kuid = from_vfsuid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsuid);
+
+               dquot = dqget(sb, make_kqid_uid(kuid));
                if (IS_ERR(dquot)) {
                        if (PTR_ERR(dquot) != -ESRCH) {
                                ret = PTR_ERR(dquot);
                }
                transfer_to[USRQUOTA] = dquot;
        }
-       if (i_gid_needs_update(&init_user_ns, iattr, inode)) {
-               dquot = dqget(sb, make_kqid_gid(iattr->ia_gid));
+       if (i_gid_needs_update(mnt_userns, iattr, inode)) {
+               kgid_t kgid = from_vfsgid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsgid);
+
+               dquot = dqget(sb, make_kqid_gid(kgid));
                if (IS_ERR(dquot)) {
                        if (PTR_ERR(dquot) != -ESRCH) {
                                ret = PTR_ERR(dquot);
 
        /* must be turned off for recursive notify_change calls */
        ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
 
-       if (is_quota_modification(&init_user_ns, inode, attr)) {
+       if (is_quota_modification(mnt_userns, inode, attr)) {
                error = dquot_initialize(inode);
                if (error)
                        return error;
                reiserfs_write_unlock(inode->i_sb);
                if (error)
                        goto out;
-               error = dquot_transfer(&init_user_ns, inode, attr);
+               error = dquot_transfer(mnt_userns, inode, attr);
                reiserfs_write_lock(inode->i_sb);
                if (error) {
                        journal_end(&th);
 
                uint    qflags = 0;
 
                if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) {
-                       uid = iattr->ia_uid;
+                       uid = from_vfsuid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsuid);
                        qflags |= XFS_QMOPT_UQUOTA;
                } else {
                        uid = inode->i_uid;
                }
                if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) {
-                       gid = iattr->ia_gid;
+                       gid = from_vfsgid(mnt_userns, i_user_ns(inode),
+                                         iattr->ia_vfsgid);
                        qflags |= XFS_QMOPT_GQUOTA;
                }  else {
                        gid = inode->i_gid;
         * also.
         */
        if (XFS_IS_UQUOTA_ON(mp) &&
-           i_uid_needs_update(&init_user_ns, iattr, inode)) {
+           i_uid_needs_update(mnt_userns, iattr, inode)) {
                ASSERT(udqp);
                old_udqp = xfs_qm_vop_chown(tp, ip, &ip->i_udquot, udqp);
        }
        if (XFS_IS_GQUOTA_ON(mp) &&
-           i_gid_needs_update(&init_user_ns, iattr, inode)) {
+           i_gid_needs_update(mnt_userns, iattr, inode)) {
                ASSERT(xfs_has_pquotino(mp) || !XFS_IS_PQUOTA_ON(mp));
                ASSERT(gdqp);
                old_gdqp = xfs_qm_vop_chown(tp, ip, &ip->i_gdquot, gdqp);
 
             !uid_eq(iattr->ia_uid, inode->i_uid)) ||
            ((iattr->ia_valid & ATTR_GID) &&
             !gid_eq(iattr->ia_gid, inode->i_gid))) {
-               ret = dquot_transfer(&init_user_ns, inode, iattr);
+               ret = dquot_transfer(mnt_userns, inode, iattr);
                if (ret)
                        return ret;
        }
 
         * are a dedicated type requiring the filesystem to use the dedicated
         * helpers. Other filesystem can continue to use ia_{g,u}id until they
         * have been ported.
+        *
+        * They always contain the same value. In other words FS_ALLOW_IDMAP
+        * pass down the same value on idmapped mounts as they would on regular
+        * mounts.
         */
        union {
                kuid_t          ia_uid;
 
                                         struct inode *inode, struct iattr *ia)
 {
        return ((ia->ia_valid & ATTR_SIZE) ||
-               i_uid_needs_update(&init_user_ns, ia, inode) ||
-               i_gid_needs_update(&init_user_ns, ia, inode));
+               i_uid_needs_update(mnt_userns, ia, inode) ||
+               i_gid_needs_update(mnt_userns, ia, inode));
 }
 
 #if defined(CONFIG_QUOTA)
 
        struct inode *inode = d_backing_inode(dentry);
        unsigned int ia_valid = attr->ia_valid;
 
-       if (!i_uid_needs_update(&init_user_ns, attr, inode) &&
-           !i_gid_needs_update(&init_user_ns, attr, inode) &&
+       if (!i_uid_needs_update(mnt_userns, attr, inode) &&
+           !i_gid_needs_update(mnt_userns, attr, inode) &&
            (!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode))
                return 0;