diff --git a/fs/attr.c b/fs/attr.c
index 4daf6ac6de6d..d13ef3f8eac0 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -378,7 +378,7 @@ int notify_mapped_change(struct user_namespace *user_ns, struct dentry *dentry,
 		return error;
 
 	if (inode->i_op->setattr)
-		error = inode->i_op->setattr(dentry, attr);
+		error = iop_setattr(inode, user_ns, dentry, attr);
 	else
 		error = simple_setattr(dentry, attr);
 
diff --git a/fs/namei.c b/fs/namei.c
index 76c9637eccb9..d6dbfab126d7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -407,7 +407,7 @@ static inline int do_inode_permission(struct user_namespace *user_ns, struct ino
 {
 	if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
 		if (likely(inode->i_op->permission))
-			return inode->i_op->permission(inode, mask);
+			return iop_permission(inode, user_ns, inode, mask);
 
 		/* This gets set once for the inode lifetime */
 		spin_lock(&inode->i_lock);
@@ -2872,7 +2872,7 @@ int vfs_mapped_create(struct user_namespace *user_ns, struct inode *dir,
 	error = security_inode_create(dir, dentry, mode);
 	if (error)
 		return error;
-	error = dir->i_op->create(dir, dentry, mode, want_excl);
+	error = iop_create(dir, user_ns, dir, dentry, mode, want_excl);
 	if (!error)
 		fsnotify_create(dir, dentry);
 	return error;
@@ -3175,14 +3175,18 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
 
 	/* Negative dentry, just create the file */
 	if (!dentry->d_inode && (open_flag & O_CREAT)) {
+		struct user_namespace *user_ns;
+
 		file->f_mode |= FMODE_CREATED;
 		audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE);
 		if (!dir_inode->i_op->create) {
 			error = -EACCES;
 			goto out_dput;
 		}
-		error = dir_inode->i_op->create(dir_inode, dentry, mode,
-						open_flag & O_EXCL);
+
+		user_ns = mnt_user_ns(nd->path.mnt);
+		error = iop_create(dir_inode, user_ns, dir_inode, dentry, mode,
+				   open_flag & O_EXCL);
 		if (error)
 			goto out_dput;
 	}
@@ -3363,7 +3367,7 @@ struct dentry *vfs_mapped_tmpfile(struct user_namespace *user_ns,
 	child = d_alloc(dentry, &slash_name);
 	if (unlikely(!child))
 		goto out_err;
-	error = dir->i_op->tmpfile(dir, child, mode);
+	error = iop_tmpfile(dir, user_ns, dir, child, mode);
 	if (error)
 		goto out_err;
 	error = -ENOENT;
@@ -3640,7 +3644,7 @@ int vfs_mapped_mknod(struct user_namespace *user_ns, struct inode *dir,
 	if (error)
 		return error;
 
-	error = dir->i_op->mknod(dir, dentry, mode, dev);
+	error = iop_mknod(dir, user_ns, dir, dentry, mode, dev);
 	if (!error)
 		fsnotify_create(dir, dentry);
 	return error;
@@ -3750,7 +3754,7 @@ int vfs_mapped_mkdir(struct user_namespace *user_ns, struct inode *dir,
 	if (max_links && dir->i_nlink >= max_links)
 		return -EMLINK;
 
-	error = dir->i_op->mkdir(dir, dentry, mode);
+	error = iop_mkdir(dir, user_ns, dir, dentry, mode);
 	if (!error)
 		fsnotify_mkdir(dir, dentry);
 	return error;
@@ -4089,7 +4093,7 @@ int vfs_mapped_symlink(struct user_namespace *user_ns, struct inode *dir,
 	if (error)
 		return error;
 
-	error = dir->i_op->symlink(dir, dentry, oldname);
+	error = iop_symlink(dir, user_ns, dir, dentry, oldname);
 	if (!error)
 		fsnotify_create(dir, dentry);
 	return error;
@@ -4435,8 +4439,8 @@ int vfs_mapped_rename(struct renamedata *rd)
 		if (error)
 			goto out;
 	}
-	error = old_dir->i_op->rename(old_dir, old_dentry,
-				       new_dir, new_dentry, flags);
+	error = iop_rename(old_dir, rd->new_user_ns, old_dir, old_dentry,
+			   new_dir, new_dentry, flags);
 	if (error)
 		goto out;
 
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 665eb7921e1c..b8e204ac2caa 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -578,7 +578,7 @@ posix_mapped_acl_chmod(struct user_namespace *user_ns, struct inode *inode, umod
 	ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
 	if (ret)
 		return ret;
-	ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS);
+	ret = iop_set_acl(inode, user_ns, inode, acl, ACL_TYPE_ACCESS);
 	posix_acl_release(acl);
 	return ret;
 }
@@ -925,7 +925,7 @@ set_posix_mapped_acl(struct user_namespace *user_ns, struct inode *inode,
 		if (ret)
 			return ret;
 	}
-	return inode->i_op->set_acl(inode, acl, type);
+	return iop_set_acl(inode, user_ns, inode, acl, type);
 }
 
 int
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bfcfa3d7374f..cb01141d726a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1978,8 +1978,137 @@ struct inode_operations {
 			   umode_t create_mode);
 	int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 	int (*set_acl)(struct inode *, struct posix_acl *, int);
+#ifdef CONFIG_IDMAP_MOUNTS
+	int (*permission_mapped) (struct user_namespace *, struct inode *, int);
+	int (*create_mapped) (struct user_namespace *, struct inode *,
+			      struct dentry *, umode_t, bool);
+	int (*mknod_mapped) (struct user_namespace *, struct inode *,
+			     struct dentry *, umode_t, dev_t);
+	int (*mkdir_mapped) (struct user_namespace *, struct inode *,
+			     struct dentry *, umode_t);
+	int (*tmpfile_mapped) (struct user_namespace *, struct inode *,
+			       struct dentry *, umode_t);
+	int (*symlink_mapped) (struct user_namespace *, struct inode *,
+			       struct dentry *, const char *);
+	int (*rename_mapped) (struct user_namespace *, struct inode *,
+			      struct dentry *, struct inode *, struct dentry *,
+			      unsigned int);
+	int (*setattr_mapped) (struct user_namespace *, struct dentry *,
+			       struct iattr *);
+	int (*set_acl_mapped)(struct user_namespace *, struct inode *,
+			      struct posix_acl *, int);
+#endif
 } ____cacheline_aligned;
 
+static inline int iop_permission(struct inode *caller,
+				 struct user_namespace *user_ns,
+				 struct inode *inode, int mask)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->permission_mapped)
+		return caller->i_op->permission_mapped(user_ns, inode, mask);
+#endif
+	return caller->i_op->permission(inode, mask);
+}
+
+static inline int iop_create(struct inode *caller,
+			     struct user_namespace *user_ns,
+			     struct inode *inode, struct dentry *dentry,
+			     umode_t mode, bool excl)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->create_mapped)
+		return caller->i_op->create_mapped(user_ns, inode, dentry,
+						    mode, excl);
+#endif
+	return caller->i_op->create(inode, dentry, mode, excl);
+}
+
+static inline int iop_mknod(struct inode *caller,
+			    struct user_namespace *user_ns, struct inode *inode,
+			    struct dentry *dentry, umode_t mode, dev_t dev)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->mknod_mapped)
+		return caller->i_op->mknod_mapped(user_ns, inode, dentry, mode, dev);
+#endif
+	return caller->i_op->mknod(inode, dentry, mode, dev);
+}
+
+static inline int iop_mkdir(struct inode *caller,
+			    struct user_namespace *user_ns, struct inode *inode,
+			    struct dentry *dentry, umode_t mode)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->mkdir_mapped)
+		return caller->i_op->mkdir_mapped(user_ns, inode, dentry, mode);
+#endif
+	return caller->i_op->mkdir(inode, dentry, mode);
+}
+
+static inline int iop_tmpfile(struct inode *caller,
+			      struct user_namespace *user_ns,
+			      struct inode *inode, struct dentry *dentry,
+			      umode_t mode)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->tmpfile_mapped)
+		return caller->i_op->tmpfile_mapped(user_ns, inode, dentry, mode);
+#endif
+	return caller->i_op->tmpfile(inode, dentry, mode);
+}
+
+static inline int iop_symlink(struct inode *caller,
+			      struct user_namespace *user_ns,
+			      struct inode *inode, struct dentry *dentry,
+			      const char *name)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->symlink_mapped)
+		return caller->i_op->symlink_mapped(user_ns, inode, dentry, name);
+#endif
+	return caller->i_op->symlink(inode, dentry, name);
+}
+
+static inline int iop_rename(struct inode *caller,
+			     struct user_namespace *user_ns,
+			     struct inode *old_inode, struct dentry *old_dentry,
+			     struct inode *new_inode, struct dentry *new_dentry,
+			     unsigned int flags)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->rename_mapped)
+		return caller->i_op->rename_mapped(user_ns, old_inode,
+						   old_dentry, new_inode,
+						   new_dentry, flags);
+#endif
+	return caller->i_op->rename(old_inode, old_dentry, new_inode,
+				    new_dentry, flags);
+}
+
+static inline int iop_setattr(struct inode *caller,
+			      struct user_namespace *user_ns,
+			      struct dentry *dentry, struct iattr *attr)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->setattr_mapped)
+		return caller->i_op->setattr_mapped(user_ns, dentry, attr);
+#endif
+	return caller->i_op->setattr(dentry, attr);
+}
+
+static inline int iop_set_acl(struct inode *caller,
+			      struct user_namespace *user_ns,
+			      struct inode *inode, struct posix_acl *acl,
+			      int type)
+{
+#ifdef CONFIG_IDMAP_MOUNTS
+	if (caller->i_op->set_acl_mapped)
+		return caller->i_op->set_acl_mapped(user_ns, inode, acl, type);
+#endif
+	return caller->i_op->set_acl(inode, acl, type);
+}
+
 static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio,
 				     struct iov_iter *iter)
 {
