diff --git a/fs/namespace.c b/fs/namespace.c
index 940ecfc..de02b39 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1652,6 +1652,22 @@ SYSCALL_DEFINE1(oldumount, char __user *, name)
 
 #endif
 
+/* Returns true if the VFS should shift inode's UID */
+static bool vfs_mount_shift_i_uid(struct mnt_namespace *ns,
+				  const struct inode *inode)
+{
+	return (ns->flags & CLONE_MNTNS_SHIFT_UIDGID) &&
+		(inode->i_sb->s_iflags & SB_I_VFS_SHIFT_UIDS);
+}
+
+/* Returns true if the VFS should shift inode's GID */
+static bool vfs_mount_shift_i_gid(struct mnt_namespace *ns,
+				  const struct inode *inode)
+{
+	return (ns->flags & CLONE_MNTNS_SHIFT_UIDGID) &&
+		(inode->i_sb->s_iflags & SB_I_VFS_SHIFT_GIDS);
+}
+
 static bool is_mnt_ns_file(struct dentry *dentry)
 {
 	/* Is this a proxy for a mount namespace? */
@@ -1664,6 +1680,52 @@ struct mnt_namespace *to_mnt_ns(struct ns_common *ns)
 	return container_of(ns, struct mnt_namespace, ns);
 }
 
+/*
+ * Returns the virtual UID view of the inode's uid
+ * If UID shifts are enabled on the mount namespace and the filesystem,
+ * the VFS will return the shifted UID according to the rules of the
+ * user namespace of the containing mount namespace. If no shift is
+ * performed, inode->i_uid is returned.
+ */
+kuid_t vfs_shift_i_uid_to_virtual(const struct inode *inode)
+{
+	kuid_t i_uid = inode->i_uid;
+	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
+
+	/* Nothing to do */
+	if (!vfs_mount_shift_i_uid(ns, inode))
+		return i_uid;
+
+	/* If there is no mapping construct one in the current mountns */
+	if (!kuid_has_mapping(ns->user_ns, i_uid))
+		return make_kuid(ns->user_ns, i_uid.val);
+
+	return i_uid;
+}
+
+/*
+ * Returns the virtual GID view of the inode's gid
+ * If GID shifts are enabled on the mount namespace and the filesystem,
+ * the VFS will return the shifted GID according to the rules of the
+ * user namespace of the containing mount namespace. If no shift is
+ * performed, inode->i_gid is returned.
+ */
+kgid_t vfs_shift_i_gid_to_virtual(const struct inode *inode)
+{
+	kgid_t i_gid = inode->i_gid;
+	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
+
+	/* Nothing to do */
+	if (!vfs_mount_shift_i_gid(ns, inode))
+		return i_gid;
+
+	/* If there is no mapping construct one in the current mountns */
+	if (!kgid_has_mapping(ns->user_ns, i_gid))
+		return make_kgid(ns->user_ns, i_gid.val);
+
+	return i_gid;
+}
+
 static bool mnt_ns_loop(struct dentry *dentry)
 {
 	/* Could bind mounting the mount namespace inode cause a
diff --git a/fs/stat.c b/fs/stat.c
index bc045c7..d00622b 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -24,8 +24,8 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
 	stat->ino = inode->i_ino;
 	stat->mode = inode->i_mode;
 	stat->nlink = inode->i_nlink;
-	stat->uid = inode->i_uid;
-	stat->gid = inode->i_gid;
+	stat->uid = vfs_shift_i_uid_to_virtual(inode);
+	stat->gid = vfs_shift_i_gid_to_virtual(inode);
 	stat->rdev = inode->i_rdev;
 	stat->size = i_size_read(inode);
 	stat->atime = inode->i_atime;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 70e61b5..a9efc5a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1298,6 +1298,8 @@ struct mm_struct;
 /* sb->s_iflags */
 #define SB_I_CGROUPWB	0x00000001	/* cgroup-aware writeback enabled */
 #define SB_I_NOEXEC	0x00000002	/* Ignore executables on this fs */
+#define SB_I_VFS_SHIFT_UIDS	0X00000004	/* FS allows VFS to do UID shifts */
+#define SB_I_VFS_SHIFT_GIDS	0X00000008	/* FS allows VFS to do GID shifts */
 
 /* Possible states of 'frozen' field */
 enum {
@@ -1563,6 +1565,15 @@ extern int vfs_whiteout(struct inode *, struct dentry *);
  */
 extern void inode_init_owner(struct inode *inode, const struct inode *dir,
 			umode_t mode);
+
+/*
+ * VFS helpers to shift inodes's uid/gid and passed values to either virtual
+ * or on-disk view. The shift is done according to rules of the user namespace
+ * of the containing mount namespace.
+ */
+extern kuid_t vfs_shift_i_uid_to_virtual(const struct inode *inode);
+extern kgid_t vfs_shift_i_gid_to_virtual(const struct inode *inode);
+
 /*
  * VFS FS_IOC_FIEMAP helper definitions.
  */
