commit:     3e6246f9ed7137b506f6af180d0207633e1f0902
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Sat Jul  2 16:10:50 2022 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Sat Jul  2 16:10:50 2022 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=3e6246f9

Linux patch 5.15.52

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README              |    4 +
 1051_linux-5.15.52.patch | 1619 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1623 insertions(+)

diff --git a/0000_README b/0000_README
index 55250c51..587226ce 100644
--- a/0000_README
+++ b/0000_README
@@ -247,6 +247,10 @@ Patch:  1050_linux-5.15.51.patch
 From:   http://www.kernel.org
 Desc:   Linux 5.15.51
 
+Patch:  1051_linux-5.15.52.patch
+From:   http://www.kernel.org
+Desc:   Linux 5.15.52
+
 Patch:  1500_XATTR_USER_PREFIX.patch
 From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
 Desc:   Support for namespace user.pax.* on tmpfs.

diff --git a/1051_linux-5.15.52.patch b/1051_linux-5.15.52.patch
new file mode 100644
index 00000000..80ecbea8
--- /dev/null
+++ b/1051_linux-5.15.52.patch
@@ -0,0 +1,1619 @@
+diff --git a/Documentation/filesystems/idmappings.rst 
b/Documentation/filesystems/idmappings.rst
+index 1229a75ec75dd..7a879ec3b6bf0 100644
+--- a/Documentation/filesystems/idmappings.rst
++++ b/Documentation/filesystems/idmappings.rst
+@@ -952,75 +952,3 @@ The raw userspace id that is put on disk is ``u1000`` so 
when the user takes
+ their home directory back to their home computer where they are assigned
+ ``u1000`` using the initial idmapping and mount the filesystem with the 
initial
+ idmapping they will see all those files owned by ``u1000``.
+-
+-Shortcircuting
+---------------
+-
+-Currently, the implementation of idmapped mounts enforces that the filesystem
+-is mounted with the initial idmapping. The reason is simply that none of the
+-filesystems that we targeted were mountable with a non-initial idmapping. But
+-that might change soon enough. As we've seen above, thanks to the properties 
of
+-idmappings the translation works for both filesystems mounted with the initial
+-idmapping and filesystem with non-initial idmappings.
+-
+-Based on this current restriction to filesystem mounted with the initial
+-idmapping two noticeable shortcuts have been taken:
+-
+-1. We always stash a reference to the initial user namespace in ``struct
+-   vfsmount``. Idmapped mounts are thus mounts that have a non-initial user
+-   namespace attached to them.
+-
+-   In order to support idmapped mounts this needs to be changed. Instead of
+-   stashing the initial user namespace the user namespace the filesystem was
+-   mounted with must be stashed. An idmapped mount is then any mount that has
+-   a different user namespace attached then the filesystem was mounted with.
+-   This has no user-visible consequences.
+-
+-2. The translation algorithms in ``mapped_fs*id()`` and ``i_*id_into_mnt()``
+-   are simplified.
+-
+-   Let's consider ``mapped_fs*id()`` first. This function translates the
+-   caller's kernel id into a kernel id in the filesystem's idmapping via
+-   a mount's idmapping. The full algorithm is::
+-
+-    mapped_fsuid(kid):
+-      /* Map the kernel id up into a userspace id in the mount's idmapping. */
+-      from_kuid(mount-idmapping, kid) = uid
+-
+-      /* Map the userspace id down into a kernel id in the filesystem's 
idmapping. */
+-      make_kuid(filesystem-idmapping, uid) = kuid
+-
+-   We know that the filesystem is always mounted with the initial idmapping as
+-   we enforce this in ``mount_setattr()``. So this can be shortened to::
+-
+-    mapped_fsuid(kid):
+-      /* Map the kernel id up into a userspace id in the mount's idmapping. */
+-      from_kuid(mount-idmapping, kid) = uid
+-
+-      /* Map the userspace id down into a kernel id in the filesystem's 
idmapping. */
+-      KUIDT_INIT(uid) = kuid
+-
+-   Similarly, for ``i_*id_into_mnt()`` which translated the filesystem's 
kernel
+-   id into a mount's kernel id::
+-
+-    i_uid_into_mnt(kid):
+-      /* Map the kernel id up into a userspace id in the filesystem's 
idmapping. */
+-      from_kuid(filesystem-idmapping, kid) = uid
+-
+-      /* Map the userspace id down into a kernel id in the mounts's 
idmapping. */
+-      make_kuid(mount-idmapping, uid) = kuid
+-
+-   Again, we know that the filesystem is always mounted with the initial
+-   idmapping as we enforce this in ``mount_setattr()``. So this can be
+-   shortened to::
+-
+-    i_uid_into_mnt(kid):
+-      /* Map the kernel id up into a userspace id in the filesystem's 
idmapping. */
+-      __kuid_val(kid) = uid
+-
+-      /* Map the userspace id down into a kernel id in the mounts's 
idmapping. */
+-      make_kuid(mount-idmapping, uid) = kuid
+-
+-Handling filesystems mounted with non-initial idmappings requires that the
+-translation functions be converted to their full form. They can still be
+-shortcircuited on non-idmapped mounts. This has no user-visible consequences.
+diff --git a/Makefile b/Makefile
+index b3bc9d907bed3..777e0a0eeccd1 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 15
+-SUBLEVEL = 51
++SUBLEVEL = 52
+ EXTRAVERSION =
+ NAME = Trick or Treat
+ 
+diff --git a/arch/powerpc/include/asm/ftrace.h 
b/arch/powerpc/include/asm/ftrace.h
+index debe8c4f70626..02d32d6422cd8 100644
+--- a/arch/powerpc/include/asm/ftrace.h
++++ b/arch/powerpc/include/asm/ftrace.h
+@@ -96,7 +96,7 @@ static inline bool arch_syscall_match_sym_name(const char 
*sym, const char *name
+ #endif /* PPC64_ELF_ABI_v1 */
+ #endif /* CONFIG_FTRACE_SYSCALLS */
+ 
+-#ifdef CONFIG_PPC64
++#if defined(CONFIG_PPC64) && defined(CONFIG_FUNCTION_TRACER)
+ #include <asm/paca.h>
+ 
+ static inline void this_cpu_disable_ftrace(void)
+@@ -120,11 +120,13 @@ static inline u8 this_cpu_get_ftrace_enabled(void)
+       return get_paca()->ftrace_enabled;
+ }
+ 
++void ftrace_free_init_tramp(void);
+ #else /* CONFIG_PPC64 */
+ static inline void this_cpu_disable_ftrace(void) { }
+ static inline void this_cpu_enable_ftrace(void) { }
+ static inline void this_cpu_set_ftrace_enabled(u8 ftrace_enabled) { }
+ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; }
++static inline void ftrace_free_init_tramp(void) { }
+ #endif /* CONFIG_PPC64 */
+ #endif /* !__ASSEMBLY__ */
+ 
+diff --git a/arch/powerpc/kernel/trace/ftrace.c 
b/arch/powerpc/kernel/trace/ftrace.c
+index d89c5df4f2062..660040c2d7b54 100644
+--- a/arch/powerpc/kernel/trace/ftrace.c
++++ b/arch/powerpc/kernel/trace/ftrace.c
+@@ -336,9 +336,7 @@ static int setup_mcount_compiler_tramp(unsigned long tramp)
+ 
+       /* Is this a known long jump tramp? */
+       for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
+-              if (!ftrace_tramps[i])
+-                      break;
+-              else if (ftrace_tramps[i] == tramp)
++              if (ftrace_tramps[i] == tramp)
+                       return 0;
+ 
+       /* Is this a known plt tramp? */
+@@ -881,6 +879,17 @@ void arch_ftrace_update_code(int command)
+ 
+ extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];
+ 
++void ftrace_free_init_tramp(void)
++{
++      int i;
++
++      for (i = 0; i < NUM_FTRACE_TRAMPS && ftrace_tramps[i]; i++)
++              if (ftrace_tramps[i] == (unsigned long)ftrace_tramp_init) {
++                      ftrace_tramps[i] = 0;
++                      return;
++              }
++}
++
+ int __init ftrace_dyn_arch_init(void)
+ {
+       int i;
+diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
+index 05b9c3f31456c..543a044560e93 100644
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -22,6 +22,7 @@
+ #include <asm/kasan.h>
+ #include <asm/svm.h>
+ #include <asm/mmzone.h>
++#include <asm/ftrace.h>
+ 
+ #include <mm/mmu_decl.h>
+ 
+@@ -314,6 +315,7 @@ void free_initmem(void)
+       mark_initmem_nx();
+       init_mem_is_free = true;
+       free_initmem_default(POISON_FREE_INITMEM);
++      ftrace_free_init_tramp();
+ }
+ 
+ /*
+diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
+index 9e3af56747e8f..eba6485a59a39 100644
+--- a/arch/x86/kernel/kvm.c
++++ b/arch/x86/kernel/kvm.c
+@@ -948,7 +948,7 @@ asm(
+ "movq __per_cpu_offset(,%rdi,8), %rax;"
+ "cmpb $0, " __stringify(KVM_STEAL_TIME_preempted) "+steal_time(%rax);"
+ "setne        %al;"
+-"ret;"
++ASM_RET
+ ".size __raw_callee_save___kvm_vcpu_is_preempted, 
.-__raw_callee_save___kvm_vcpu_is_preempted;"
+ ".popsection");
+ 
+diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
+index 7b6f8bfef9270..98daa9d200f79 100644
+--- a/drivers/md/bcache/btree.c
++++ b/drivers/md/bcache/btree.c
+@@ -2017,6 +2017,7 @@ int bch_btree_check(struct cache_set *c)
+       if (c->root->level == 0)
+               return 0;
+ 
++      memset(&check_state, 0, sizeof(struct btree_check_state));
+       check_state.c = c;
+       check_state.total_threads = bch_btree_chkthread_nr();
+       check_state.key_idx = 0;
+diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
+index 9699ce076b775..96a07839864b6 100644
+--- a/drivers/md/bcache/writeback.c
++++ b/drivers/md/bcache/writeback.c
+@@ -947,6 +947,7 @@ void bch_sectors_dirty_init(struct bcache_device *d)
+               return;
+       }
+ 
++      memset(&state, 0, sizeof(struct bch_dirty_init_state));
+       state.c = c;
+       state.d = d;
+       state.total_threads = bch_btre_dirty_init_thread_nr();
+diff --git a/drivers/net/ethernet/mscc/ocelot.c 
b/drivers/net/ethernet/mscc/ocelot.c
+index a59300d9e0000..96b1e394a397f 100644
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -2206,11 +2206,15 @@ int ocelot_init(struct ocelot *ocelot)
+       ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
+                      ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
+                      ANA_PGID_PGID, PGID_MC);
++      ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
++                     ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
++                     ANA_PGID_PGID, PGID_MCIPV4);
++      ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
++                     ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
++                     ANA_PGID_PGID, PGID_MCIPV6);
+       ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
+                      ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)),
+                      ANA_PGID_PGID, PGID_BC);
+-      ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4);
+-      ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6);
+ 
+       /* Allow manual injection via DEVCPU_QS registers, and byte swap these
+        * registers endianness.
+diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c 
b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+index f405f42d1c1b0..897da3ed2f029 100644
+--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
++++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+@@ -304,7 +304,8 @@ static void rtw8821c_set_channel_rf(struct rtw_dev 
*rtwdev, u8 channel, u8 bw)
+       if (channel <= 14) {
+               if (rtwdev->efuse.rfe_option == 0)
+                       rtw8821c_switch_rf_set(rtwdev, SWITCH_TO_WLG);
+-              else if (rtwdev->efuse.rfe_option == 2)
++              else if (rtwdev->efuse.rfe_option == 2 ||
++                       rtwdev->efuse.rfe_option == 4)
+                       rtw8821c_switch_rf_set(rtwdev, SWITCH_TO_BTG);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTDBG, BIT(6), 0x1);
+               rtw_write_rf(rtwdev, RF_PATH_A, 0x64, 0xf, 0xf);
+@@ -777,6 +778,15 @@ static void rtw8821c_coex_cfg_ant_switch(struct rtw_dev 
*rtwdev, u8 ctrl_type,
+       if (switch_status == coex_dm->cur_switch_status)
+               return;
+ 
++      if (coex_rfe->wlg_at_btg) {
++              ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;
++
++              if (coex_rfe->ant_switch_polarity)
++                      pos_type = COEX_SWITCH_TO_WLA;
++              else
++                      pos_type = COEX_SWITCH_TO_WLG_BT;
++      }
++
+       coex_dm->cur_switch_status = switch_status;
+ 
+       if (coex_rfe->ant_switch_diversity &&
+@@ -1502,6 +1512,8 @@ static const struct rtw_intf_phy_para_table 
phy_para_table_8821c = {
+ static const struct rtw_rfe_def rtw8821c_rfe_defs[] = {
+       [0] = RTW_DEF_RFE(8821c, 0, 0),
+       [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
++      [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
++      [6] = RTW_DEF_RFE(8821c, 0, 0),
+ };
+ 
+ static struct rtw_hw_reg rtw8821c_dig[] = {
+diff --git a/fs/attr.c b/fs/attr.c
+index 66899b6e9bd86..dbe996b0dedfc 100644
+--- a/fs/attr.c
++++ b/fs/attr.c
+@@ -61,9 +61,15 @@ static bool chgrp_ok(struct user_namespace *mnt_userns,
+                    const struct inode *inode, kgid_t gid)
+ {
+       kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
+-      if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)) &&
+-          (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
+-              return true;
++      if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode))) {
++              kgid_t mapped_gid;
++
++              if (gid_eq(gid, inode->i_gid))
++                      return true;
++              mapped_gid = mapped_kgid_fs(mnt_userns, i_user_ns(inode), gid);
++              if (in_group_p(mapped_gid))
++                      return true;
++      }
+       if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
+               return true;
+       if (gid_eq(kgid, INVALID_GID) &&
+@@ -123,12 +129,20 @@ int setattr_prepare(struct user_namespace *mnt_userns, 
struct dentry *dentry,
+ 
+       /* Make sure a caller can chmod. */
+       if (ia_valid & ATTR_MODE) {
++              kgid_t mapped_gid;
++
+               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);
++              else
++                      mapped_gid = i_gid_into_mnt(mnt_userns, inode);
++
+               /* Also check the setgid bit! */
+-               if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
+-                                i_gid_into_mnt(mnt_userns, inode)) &&
+-                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
++              if (!in_group_p(mapped_gid) &&
++                  !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
+                       attr->ia_mode &= ~S_ISGID;
+       }
+ 
+diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c
+index d463d89f5db8c..146291be62637 100644
+--- a/fs/cachefiles/bind.c
++++ b/fs/cachefiles/bind.c
+@@ -117,7 +117,7 @@ static int cachefiles_daemon_add_cache(struct 
cachefiles_cache *cache)
+       root = path.dentry;
+ 
+       ret = -EINVAL;
+-      if (mnt_user_ns(path.mnt) != &init_user_ns) {
++      if (is_idmapped_mnt(path.mnt)) {
+               pr_warn("File cache on idmapped mounts not supported");
+               goto error_unsupported;
+       }
+diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
+index d66bbd2df191e..2dd23a82e0de5 100644
+--- a/fs/ecryptfs/main.c
++++ b/fs/ecryptfs/main.c
+@@ -537,7 +537,7 @@ static struct dentry *ecryptfs_mount(struct 
file_system_type *fs_type, int flags
+               goto out_free;
+       }
+ 
+-      if (mnt_user_ns(path.mnt) != &init_user_ns) {
++      if (is_idmapped_mnt(path.mnt)) {
+               rc = -EINVAL;
+               printk(KERN_ERR "Mounting on idmapped mounts currently 
disallowed\n");
+               goto out_free;
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index be21765753533..a8470a98f84d8 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -2932,15 +2932,24 @@ static int io_prep_rw(struct io_kiocb *req, const 
struct io_uring_sqe *sqe,
+               kiocb->ki_complete = io_complete_rw;
+       }
+ 
++      /* used for fixed read/write too - just read unconditionally */
++      req->buf_index = READ_ONCE(sqe->buf_index);
++      req->imu = NULL;
++
+       if (req->opcode == IORING_OP_READ_FIXED ||
+           req->opcode == IORING_OP_WRITE_FIXED) {
+-              req->imu = NULL;
++              struct io_ring_ctx *ctx = req->ctx;
++              u16 index;
++
++              if (unlikely(req->buf_index >= ctx->nr_user_bufs))
++                      return -EFAULT;
++              index = array_index_nospec(req->buf_index, ctx->nr_user_bufs);
++              req->imu = ctx->user_bufs[index];
+               io_req_set_rsrc_node(req);
+       }
+ 
+       req->rw.addr = READ_ONCE(sqe->addr);
+       req->rw.len = READ_ONCE(sqe->len);
+-      req->buf_index = READ_ONCE(sqe->buf_index);
+       return 0;
+ }
+ 
+@@ -3066,18 +3075,9 @@ static int __io_import_fixed(struct io_kiocb *req, int 
rw, struct iov_iter *iter
+ 
+ static int io_import_fixed(struct io_kiocb *req, int rw, struct iov_iter 
*iter)
+ {
+-      struct io_ring_ctx *ctx = req->ctx;
+-      struct io_mapped_ubuf *imu = req->imu;
+-      u16 index, buf_index = req->buf_index;
+-
+-      if (likely(!imu)) {
+-              if (unlikely(buf_index >= ctx->nr_user_bufs))
+-                      return -EFAULT;
+-              index = array_index_nospec(buf_index, ctx->nr_user_bufs);
+-              imu = READ_ONCE(ctx->user_bufs[index]);
+-              req->imu = imu;
+-      }
+-      return __io_import_fixed(req, rw, iter, imu);
++      if (WARN_ON_ONCE(!req->imu))
++              return -EFAULT;
++      return __io_import_fixed(req, rw, iter, req->imu);
+ }
+ 
+ static void io_ring_submit_unlock(struct io_ring_ctx *ctx, bool needs_lock)
+diff --git a/fs/ksmbd/smbacl.c b/fs/ksmbd/smbacl.c
+index 7e57ffdb4ce39..38f23bf981ac9 100644
+--- a/fs/ksmbd/smbacl.c
++++ b/fs/ksmbd/smbacl.c
+@@ -9,6 +9,7 @@
+ #include <linux/fs.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
++#include <linux/mnt_idmapping.h>
+ 
+ #include "smbacl.h"
+ #include "smb_common.h"
+@@ -274,14 +275,7 @@ static int sid_to_id(struct user_namespace *user_ns,
+               uid_t id;
+ 
+               id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
+-              /*
+-               * Translate raw sid into kuid in the server's user
+-               * namespace.
+-               */
+-              uid = make_kuid(&init_user_ns, id);
+-
+-              /* If this is an idmapped mount, apply the idmapping. */
+-              uid = kuid_from_mnt(user_ns, uid);
++              uid = mapped_kuid_user(user_ns, &init_user_ns, KUIDT_INIT(id));
+               if (uid_valid(uid)) {
+                       fattr->cf_uid = uid;
+                       rc = 0;
+@@ -291,14 +285,7 @@ static int sid_to_id(struct user_namespace *user_ns,
+               gid_t id;
+ 
+               id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
+-              /*
+-               * Translate raw sid into kgid in the server's user
+-               * namespace.
+-               */
+-              gid = make_kgid(&init_user_ns, id);
+-
+-              /* If this is an idmapped mount, apply the idmapping. */
+-              gid = kgid_from_mnt(user_ns, gid);
++              gid = mapped_kgid_user(user_ns, &init_user_ns, KGIDT_INIT(id));
+               if (gid_valid(gid)) {
+                       fattr->cf_gid = gid;
+                       rc = 0;
+diff --git a/fs/ksmbd/smbacl.h b/fs/ksmbd/smbacl.h
+index 73e08cad412bd..811af33094291 100644
+--- a/fs/ksmbd/smbacl.h
++++ b/fs/ksmbd/smbacl.h
+@@ -11,6 +11,7 @@
+ #include <linux/fs.h>
+ #include <linux/namei.h>
+ #include <linux/posix_acl.h>
++#include <linux/mnt_idmapping.h>
+ 
+ #include "mgmt/tree_connect.h"
+ 
+@@ -216,7 +217,7 @@ static inline uid_t posix_acl_uid_translate(struct 
user_namespace *mnt_userns,
+       kuid_t kuid;
+ 
+       /* If this is an idmapped mount, apply the idmapping. */
+-      kuid = kuid_into_mnt(mnt_userns, pace->e_uid);
++      kuid = mapped_kuid_fs(mnt_userns, &init_user_ns, pace->e_uid);
+ 
+       /* Translate the kuid into a userspace id ksmbd would see. */
+       return from_kuid(&init_user_ns, kuid);
+@@ -228,7 +229,7 @@ static inline gid_t posix_acl_gid_translate(struct 
user_namespace *mnt_userns,
+       kgid_t kgid;
+ 
+       /* If this is an idmapped mount, apply the idmapping. */
+-      kgid = kgid_into_mnt(mnt_userns, pace->e_gid);
++      kgid = mapped_kgid_fs(mnt_userns, &init_user_ns, pace->e_gid);
+ 
+       /* Translate the kgid into a userspace id ksmbd would see. */
+       return from_kgid(&init_user_ns, kgid);
+diff --git a/fs/namespace.c b/fs/namespace.c
+index b696543adab84..dc31ad6b370f3 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -31,6 +31,7 @@
+ #include <uapi/linux/mount.h>
+ #include <linux/fs_context.h>
+ #include <linux/shmem_fs.h>
++#include <linux/mnt_idmapping.h>
+ 
+ #include "pnode.h"
+ #include "internal.h"
+@@ -561,7 +562,7 @@ static void free_vfsmnt(struct mount *mnt)
+       struct user_namespace *mnt_userns;
+ 
+       mnt_userns = mnt_user_ns(&mnt->mnt);
+-      if (mnt_userns != &init_user_ns)
++      if (!initial_idmapping(mnt_userns))
+               put_user_ns(mnt_userns);
+       kfree_const(mnt->mnt_devname);
+ #ifdef CONFIG_SMP
+@@ -965,6 +966,7 @@ static struct mount *skip_mnt_tree(struct mount *p)
+ struct vfsmount *vfs_create_mount(struct fs_context *fc)
+ {
+       struct mount *mnt;
++      struct user_namespace *fs_userns;
+ 
+       if (!fc->root)
+               return ERR_PTR(-EINVAL);
+@@ -982,6 +984,10 @@ struct vfsmount *vfs_create_mount(struct fs_context *fc)
+       mnt->mnt_mountpoint     = mnt->mnt.mnt_root;
+       mnt->mnt_parent         = mnt;
+ 
++      fs_userns = mnt->mnt.mnt_sb->s_user_ns;
++      if (!initial_idmapping(fs_userns))
++              mnt->mnt.mnt_userns = get_user_ns(fs_userns);
++
+       lock_mount_hash();
+       list_add_tail(&mnt->mnt_instance, &mnt->mnt.mnt_sb->s_mounts);
+       unlock_mount_hash();
+@@ -1072,7 +1078,7 @@ static struct mount *clone_mnt(struct mount *old, struct 
dentry *root,
+ 
+       atomic_inc(&sb->s_active);
+       mnt->mnt.mnt_userns = mnt_user_ns(&old->mnt);
+-      if (mnt->mnt.mnt_userns != &init_user_ns)
++      if (!initial_idmapping(mnt->mnt.mnt_userns))
+               mnt->mnt.mnt_userns = get_user_ns(mnt->mnt.mnt_userns);
+       mnt->mnt.mnt_sb = sb;
+       mnt->mnt.mnt_root = dget(root);
+@@ -3927,28 +3933,32 @@ static unsigned int recalc_flags(struct mount_kattr 
*kattr, struct mount *mnt)
+ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
+ {
+       struct vfsmount *m = &mnt->mnt;
++      struct user_namespace *fs_userns = m->mnt_sb->s_user_ns;
+ 
+       if (!kattr->mnt_userns)
+               return 0;
+ 
++      /*
++       * Creating an idmapped mount with the filesystem wide idmapping
++       * doesn't make sense so block that. We don't allow mushy semantics.
++       */
++      if (kattr->mnt_userns == fs_userns)
++              return -EINVAL;
++
+       /*
+        * Once a mount has been idmapped we don't allow it to change its
+        * mapping. It makes things simpler and callers can just create
+        * another bind-mount they can idmap if they want to.
+        */
+-      if (mnt_user_ns(m) != &init_user_ns)
++      if (is_idmapped_mnt(m))
+               return -EPERM;
+ 
+       /* The underlying filesystem doesn't support idmapped mounts yet. */
+       if (!(m->mnt_sb->s_type->fs_flags & FS_ALLOW_IDMAP))
+               return -EINVAL;
+ 
+-      /* Don't yet support filesystem mountable in user namespaces. */
+-      if (m->mnt_sb->s_user_ns != &init_user_ns)
+-              return -EINVAL;
+-
+       /* We're not controlling the superblock. */
+-      if (!capable(CAP_SYS_ADMIN))
++      if (!ns_capable(fs_userns, CAP_SYS_ADMIN))
+               return -EPERM;
+ 
+       /* Mount has already been visible in the filesystem hierarchy. */
+@@ -4002,14 +4012,27 @@ out:
+ 
+ static void do_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
+ {
+-      struct user_namespace *mnt_userns;
++      struct user_namespace *mnt_userns, *old_mnt_userns;
+ 
+       if (!kattr->mnt_userns)
+               return;
+ 
++      /*
++       * We're the only ones able to change the mount's idmapping. So
++       * mnt->mnt.mnt_userns is stable and we can retrieve it directly.
++       */
++      old_mnt_userns = mnt->mnt.mnt_userns;
++
+       mnt_userns = get_user_ns(kattr->mnt_userns);
+       /* Pairs with smp_load_acquire() in mnt_user_ns(). */
+       smp_store_release(&mnt->mnt.mnt_userns, mnt_userns);
++
++      /*
++       * If this is an idmapped filesystem drop the reference we've taken
++       * in vfs_create_mount() before.
++       */
++      if (!initial_idmapping(old_mnt_userns))
++              put_user_ns(old_mnt_userns);
+ }
+ 
+ static void mount_setattr_commit(struct mount_kattr *kattr,
+@@ -4133,13 +4156,15 @@ static int build_mount_idmapped(const struct 
mount_attr *attr, size_t usize,
+       }
+ 
+       /*
+-       * The init_user_ns is used to indicate that a vfsmount is not idmapped.
+-       * This is simpler than just having to treat NULL as unmapped. Users
+-       * wanting to idmap a mount to init_user_ns can just use a namespace
+-       * with an identity mapping.
++       * The initial idmapping cannot be used to create an idmapped
++       * mount. We use the initial idmapping as an indicator of a mount
++       * that is not idmapped. It can simply be passed into helpers that
++       * are aware of idmapped mounts as a convenient shortcut. A user
++       * can just create a dedicated identity mapping to achieve the same
++       * result.
+        */
+       mnt_userns = container_of(ns, struct user_namespace, ns);
+-      if (mnt_userns == &init_user_ns) {
++      if (initial_idmapping(mnt_userns)) {
+               err = -EPERM;
+               goto out_fput;
+       }
+diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
+index 9421dae227374..668c7527b17e8 100644
+--- a/fs/nfsd/export.c
++++ b/fs/nfsd/export.c
+@@ -427,7 +427,7 @@ static int check_export(struct path *path, int *flags, 
unsigned char *uuid)
+               return -EINVAL;
+       }
+ 
+-      if (mnt_user_ns(path->mnt) != &init_user_ns) {
++      if (is_idmapped_mnt(path->mnt)) {
+               dprintk("exp_export: export of idmapped mounts not yet 
supported.\n");
+               return -EINVAL;
+       }
+diff --git a/fs/open.c b/fs/open.c
+index e0df1536eb69f..1ba1d2ab2ef0b 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -32,6 +32,7 @@
+ #include <linux/ima.h>
+ #include <linux/dnotify.h>
+ #include <linux/compat.h>
++#include <linux/mnt_idmapping.h>
+ 
+ #include "internal.h"
+ 
+@@ -640,7 +641,7 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, 
umode_t, mode)
+ 
+ int chown_common(const struct path *path, uid_t user, gid_t group)
+ {
+-      struct user_namespace *mnt_userns;
++      struct user_namespace *mnt_userns, *fs_userns;
+       struct inode *inode = path->dentry->d_inode;
+       struct inode *delegated_inode = NULL;
+       int error;
+@@ -652,8 +653,9 @@ int chown_common(const struct path *path, uid_t user, 
gid_t group)
+       gid = make_kgid(current_user_ns(), group);
+ 
+       mnt_userns = mnt_user_ns(path->mnt);
+-      uid = kuid_from_mnt(mnt_userns, uid);
+-      gid = kgid_from_mnt(mnt_userns, gid);
++      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;
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index 265181c110ae2..7bb0a47cb6156 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -873,7 +873,7 @@ static int ovl_mount_dir_noesc(const char *name, struct 
path *path)
+               pr_err("filesystem on '%s' not supported\n", name);
+               goto out_put;
+       }
+-      if (mnt_user_ns(path->mnt) != &init_user_ns) {
++      if (is_idmapped_mnt(path->mnt)) {
+               pr_err("idmapped layers are currently not supported\n");
+               goto out_put;
+       }
+diff --git a/fs/posix_acl.c b/fs/posix_acl.c
+index f5c25f580dd92..ceb1e3b868577 100644
+--- a/fs/posix_acl.c
++++ b/fs/posix_acl.c
+@@ -23,6 +23,7 @@
+ #include <linux/export.h>
+ #include <linux/user_namespace.h>
+ #include <linux/namei.h>
++#include <linux/mnt_idmapping.h>
+ 
+ static struct posix_acl **acl_by_type(struct inode *inode, int type)
+ {
+@@ -375,7 +376,9 @@ posix_acl_permission(struct user_namespace *mnt_userns, 
struct inode *inode,
+                                         goto check_perm;
+                                 break;
+                         case ACL_USER:
+-                              uid = kuid_into_mnt(mnt_userns, pa->e_uid);
++                              uid = mapped_kuid_fs(mnt_userns,
++                                                   i_user_ns(inode),
++                                                   pa->e_uid);
+                               if (uid_eq(uid, current_fsuid()))
+                                         goto mask;
+                               break;
+@@ -388,7 +391,9 @@ posix_acl_permission(struct user_namespace *mnt_userns, 
struct inode *inode,
+                                 }
+                               break;
+                         case ACL_GROUP:
+-                              gid = kgid_into_mnt(mnt_userns, pa->e_gid);
++                              gid = mapped_kgid_fs(mnt_userns,
++                                                   i_user_ns(inode),
++                                                   pa->e_gid);
+                               if (in_group_p(gid)) {
+                                       found = 1;
+                                       if ((pa->e_perm & want) == want)
+@@ -735,17 +740,17 @@ static void posix_acl_fix_xattr_userns(
+               case ACL_USER:
+                       uid = make_kuid(from, le32_to_cpu(entry->e_id));
+                       if (from_user)
+-                              uid = kuid_from_mnt(mnt_userns, uid);
++                              uid = mapped_kuid_user(mnt_userns, 
&init_user_ns, uid);
+                       else
+-                              uid = kuid_into_mnt(mnt_userns, uid);
++                              uid = mapped_kuid_fs(mnt_userns, &init_user_ns, 
uid);
+                       entry->e_id = cpu_to_le32(from_kuid(to, uid));
+                       break;
+               case ACL_GROUP:
+                       gid = make_kgid(from, le32_to_cpu(entry->e_id));
+                       if (from_user)
+-                              gid = kgid_from_mnt(mnt_userns, gid);
++                              gid = mapped_kgid_user(mnt_userns, 
&init_user_ns, gid);
+                       else
+-                              gid = kgid_into_mnt(mnt_userns, gid);
++                              gid = mapped_kgid_fs(mnt_userns, &init_user_ns, 
gid);
+                       entry->e_id = cpu_to_le32(from_kgid(to, gid));
+                       break;
+               default:
+@@ -755,9 +760,14 @@ static void posix_acl_fix_xattr_userns(
+ }
+ 
+ void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
++                                 struct inode *inode,
+                                  void *value, size_t size)
+ {
+       struct user_namespace *user_ns = current_user_ns();
++
++      /* Leave ids untouched on non-idmapped mounts. */
++      if (no_idmapping(mnt_userns, i_user_ns(inode)))
++              mnt_userns = &init_user_ns;
+       if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
+               return;
+       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, mnt_userns, value,
+@@ -765,9 +775,14 @@ void posix_acl_fix_xattr_from_user(struct user_namespace 
*mnt_userns,
+ }
+ 
+ void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
++                               struct inode *inode,
+                                void *value, size_t size)
+ {
+       struct user_namespace *user_ns = current_user_ns();
++
++      /* Leave ids untouched on non-idmapped mounts. */
++      if (no_idmapping(mnt_userns, i_user_ns(inode)))
++              mnt_userns = &init_user_ns;
+       if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
+               return;
+       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, mnt_userns, value,
+diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
+index 392ef5162655b..49650e54d2f88 100644
+--- a/fs/proc_namespace.c
++++ b/fs/proc_namespace.c
+@@ -80,7 +80,7 @@ static void show_mnt_opts(struct seq_file *m, struct 
vfsmount *mnt)
+                       seq_puts(m, fs_infop->str);
+       }
+ 
+-      if (mnt_user_ns(mnt) != &init_user_ns)
++      if (is_idmapped_mnt(mnt))
+               seq_puts(m, ",idmapped");
+ }
+ 
+diff --git a/fs/xattr.c b/fs/xattr.c
+index 5c8c5175b385c..998045165916e 100644
+--- a/fs/xattr.c
++++ b/fs/xattr.c
+@@ -569,7 +569,8 @@ setxattr(struct user_namespace *mnt_userns, struct dentry 
*d,
+               }
+               if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+                   (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+-                      posix_acl_fix_xattr_from_user(mnt_userns, kvalue, size);
++                      posix_acl_fix_xattr_from_user(mnt_userns, d_inode(d),
++                                                    kvalue, size);
+       }
+ 
+       error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
+@@ -667,7 +668,8 @@ getxattr(struct user_namespace *mnt_userns, struct dentry 
*d,
+       if (error > 0) {
+               if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+                   (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+-                      posix_acl_fix_xattr_to_user(mnt_userns, kvalue, error);
++                      posix_acl_fix_xattr_to_user(mnt_userns, d_inode(d),
++                                                  kvalue, error);
+               if (size && copy_to_user(value, kvalue, error))
+                       error = -EFAULT;
+       } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
+diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
+index fbc9d816882ce..23523b802539e 100644
+--- a/fs/xfs/libxfs/xfs_attr.c
++++ b/fs/xfs/libxfs/xfs_attr.c
+@@ -1077,21 +1077,18 @@ xfs_attr_node_hasname(
+ 
+       state = xfs_da_state_alloc(args);
+       if (statep != NULL)
+-              *statep = NULL;
++              *statep = state;
+ 
+       /*
+        * Search to see if name exists, and get back a pointer to it.
+        */
+       error = xfs_da3_node_lookup_int(state, &retval);
+-      if (error) {
+-              xfs_da_state_free(state);
+-              return error;
+-      }
++      if (error)
++              retval = error;
+ 
+-      if (statep != NULL)
+-              *statep = state;
+-      else
++      if (!statep)
+               xfs_da_state_free(state);
++
+       return retval;
+ }
+ 
+@@ -1112,7 +1109,7 @@ xfs_attr_node_addname_find_attr(
+        */
+       retval = xfs_attr_node_hasname(args, &dac->da_state);
+       if (retval != -ENOATTR && retval != -EEXIST)
+-              return retval;
++              goto error;
+ 
+       if (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
+               goto error;
+@@ -1337,7 +1334,7 @@ int xfs_attr_node_removename_setup(
+ 
+       error = xfs_attr_node_hasname(args, state);
+       if (error != -EEXIST)
+-              return error;
++              goto out;
+       error = 0;
+ 
+       ASSERT((*state)->path.blk[(*state)->path.active - 1].bp != NULL);
+diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
+index 34fc6148032a3..c8c15c3c31471 100644
+--- a/fs/xfs/xfs_aops.c
++++ b/fs/xfs/xfs_aops.c
+@@ -82,6 +82,7 @@ xfs_end_ioend(
+       struct iomap_ioend      *ioend)
+ {
+       struct xfs_inode        *ip = XFS_I(ioend->io_inode);
++      struct xfs_mount        *mp = ip->i_mount;
+       xfs_off_t               offset = ioend->io_offset;
+       size_t                  size = ioend->io_size;
+       unsigned int            nofs_flag;
+@@ -97,18 +98,26 @@ xfs_end_ioend(
+       /*
+        * Just clean up the in-memory structures if the fs has been shut down.
+        */
+-      if (xfs_is_shutdown(ip->i_mount)) {
++      if (xfs_is_shutdown(mp)) {
+               error = -EIO;
+               goto done;
+       }
+ 
+       /*
+-       * Clean up any COW blocks on an I/O error.
++       * Clean up all COW blocks and underlying data fork delalloc blocks on
++       * I/O error. The delalloc punch is required because this ioend was
++       * mapped to blocks in the COW fork and the associated pages are no
++       * longer dirty. If we don't remove delalloc blocks here, they become
++       * stale and can corrupt free space accounting on unmount.
+        */
+       error = blk_status_to_errno(ioend->io_bio->bi_status);
+       if (unlikely(error)) {
+-              if (ioend->io_flags & IOMAP_F_SHARED)
++              if (ioend->io_flags & IOMAP_F_SHARED) {
+                       xfs_reflink_cancel_cow_range(ip, offset, size, true);
++                      xfs_bmap_punch_delalloc_range(ip,
++                                                    XFS_B_TO_FSBT(mp, offset),
++                                                    XFS_B_TO_FSB(mp, size));
++              }
+               goto done;
+       }
+ 
+diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
+index a476c7ef5d533..991fbf1eb5640 100644
+--- a/fs/xfs/xfs_buf_item_recover.c
++++ b/fs/xfs/xfs_buf_item_recover.c
+@@ -816,7 +816,7 @@ xlog_recover_get_buf_lsn(
+       }
+ 
+       if (lsn != (xfs_lsn_t)-1) {
+-              if (!uuid_equal(&mp->m_sb.sb_uuid, uuid))
++              if (!uuid_equal(&mp->m_sb.sb_meta_uuid, uuid))
+                       goto recover_immediately;
+               return lsn;
+       }
+diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
+index 3f8a0713573ad..a4b8caa2c601d 100644
+--- a/fs/xfs/xfs_extfree_item.c
++++ b/fs/xfs/xfs_extfree_item.c
+@@ -482,7 +482,7 @@ xfs_extent_free_finish_item(
+                       free->xefi_startblock,
+                       free->xefi_blockcount,
+                       &free->xefi_oinfo, free->xefi_skip_discard);
+-      kmem_free(free);
++      kmem_cache_free(xfs_bmap_free_item_zone, free);
+       return error;
+ }
+ 
+@@ -502,7 +502,7 @@ xfs_extent_free_cancel_item(
+       struct xfs_extent_free_item     *free;
+ 
+       free = container_of(item, struct xfs_extent_free_item, xefi_list);
+-      kmem_free(free);
++      kmem_cache_free(xfs_bmap_free_item_zone, free);
+ }
+ 
+ const struct xfs_defer_op_type xfs_extent_free_defer_type = {
+@@ -564,7 +564,7 @@ xfs_agfl_free_finish_item(
+       extp->ext_len = free->xefi_blockcount;
+       efdp->efd_next_extent++;
+ 
+-      kmem_free(free);
++      kmem_cache_free(xfs_bmap_free_item_zone, free);
+       return error;
+ }
+ 
+diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
+index a4f6f034fb813..2477e301fa828 100644
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -994,8 +994,8 @@ xfs_create(
+       /*
+        * Make sure that we have allocated dquot(s) on disk.
+        */
+-      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns),
+-                      mapped_fsgid(mnt_userns), prid,
++      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns),
++                      mapped_fsgid(mnt_userns, &init_user_ns), prid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                       &udqp, &gdqp, &pdqp);
+       if (error)
+@@ -1148,8 +1148,8 @@ xfs_create_tmpfile(
+       /*
+        * Make sure that we have allocated dquot(s) on disk.
+        */
+-      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns),
+-                      mapped_fsgid(mnt_userns), prid,
++      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns),
++                      mapped_fsgid(mnt_userns, &init_user_ns), prid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                       &udqp, &gdqp, &pdqp);
+       if (error)
+diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
+index c174262a074e3..09a8fba84ff99 100644
+--- a/fs/xfs/xfs_linux.h
++++ b/fs/xfs/xfs_linux.h
+@@ -61,6 +61,7 @@ typedef __u32                        xfs_nlink_t;
+ #include <linux/ratelimit.h>
+ #include <linux/rhashtable.h>
+ #include <linux/xattr.h>
++#include <linux/mnt_idmapping.h>
+ 
+ #include <asm/page.h>
+ #include <asm/div64.h>
+diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
+index 6c93c8ada6f35..b59cc9c0961ce 100644
+--- a/fs/xfs/xfs_log_cil.c
++++ b/fs/xfs/xfs_log_cil.c
+@@ -1442,9 +1442,9 @@ out_shutdown:
+  */
+ bool
+ xfs_log_item_in_current_chkpt(
+-      struct xfs_log_item *lip)
++      struct xfs_log_item     *lip)
+ {
+-      struct xfs_cil_ctx *ctx = lip->li_mountp->m_log->l_cilp->xc_ctx;
++      struct xfs_cil          *cil = lip->li_mountp->m_log->l_cilp;
+ 
+       if (list_empty(&lip->li_cil))
+               return false;
+@@ -1454,7 +1454,7 @@ xfs_log_item_in_current_chkpt(
+        * first checkpoint it is written to. Hence if it is different to the
+        * current sequence, we're in a new checkpoint.
+        */
+-      return lip->li_seq == ctx->sequence;
++      return lip->li_seq == READ_ONCE(cil->xc_current_sequence);
+ }
+ 
+ /*
+diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
+index 170fee98c45c7..e8d19916ba99d 100644
+--- a/fs/xfs/xfs_super.c
++++ b/fs/xfs/xfs_super.c
+@@ -1768,7 +1768,15 @@ static int
+ xfs_remount_ro(
+       struct xfs_mount        *mp)
+ {
+-      int error;
++      struct xfs_icwalk       icw = {
++              .icw_flags      = XFS_ICWALK_FLAG_SYNC,
++      };
++      int                     error;
++
++      /* Flush all the dirty data to disk. */
++      error = sync_filesystem(mp->m_super);
++      if (error)
++              return error;
+ 
+       /*
+        * Cancel background eofb scanning so it cannot race with the final
+@@ -1776,8 +1784,13 @@ xfs_remount_ro(
+        */
+       xfs_blockgc_stop(mp);
+ 
+-      /* Get rid of any leftover CoW reservations... */
+-      error = xfs_blockgc_free_space(mp, NULL);
++      /*
++       * Clear out all remaining COW staging extents and speculative post-EOF
++       * preallocations so that we don't leave inodes requiring inactivation
++       * cleanups during reclaim on a read-only mount.  We must process every
++       * cached inode, so this requires a synchronous cache scan.
++       */
++      error = xfs_blockgc_free_space(mp, &icw);
+       if (error) {
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+               return error;
+@@ -1843,8 +1856,6 @@ xfs_fs_reconfigure(
+       if (error)
+               return error;
+ 
+-      sync_filesystem(mp->m_super);
+-
+       /* inode32 -> inode64 */
+       if (xfs_has_small_inums(mp) && !xfs_has_small_inums(new_mp)) {
+               mp->m_features &= ~XFS_FEAT_SMALL_INUMS;
+diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
+index fc2c6a4046471..a31d2e5d03214 100644
+--- a/fs/xfs/xfs_symlink.c
++++ b/fs/xfs/xfs_symlink.c
+@@ -184,8 +184,8 @@ xfs_symlink(
+       /*
+        * Make sure that we have allocated dquot(s) on disk.
+        */
+-      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns),
+-                      mapped_fsgid(mnt_userns), prid,
++      error = xfs_qm_vop_dqalloc(dp, mapped_fsuid(mnt_userns, &init_user_ns),
++                      mapped_fsgid(mnt_userns, &init_user_ns), prid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                       &udqp, &gdqp, &pdqp);
+       if (error)
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 56eba723477e3..76162f0466705 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -41,6 +41,7 @@
+ #include <linux/stddef.h>
+ #include <linux/mount.h>
+ #include <linux/cred.h>
++#include <linux/mnt_idmapping.h>
+ 
+ #include <asm/byteorder.h>
+ #include <uapi/linux/fs.h>
+@@ -1601,6 +1602,11 @@ struct super_block {
+       struct list_head        s_inodes_wb;    /* writeback inodes */
+ } __randomize_layout;
+ 
++static inline struct user_namespace *i_user_ns(const struct inode *inode)
++{
++      return inode->i_sb->s_user_ns;
++}
++
+ /* Helper functions so that in most cases filesystems will
+  * not need to deal directly with kuid_t and kgid_t and can
+  * instead deal with the raw numeric values that are stored
+@@ -1608,50 +1614,22 @@ struct super_block {
+  */
+ static inline uid_t i_uid_read(const struct inode *inode)
+ {
+-      return from_kuid(inode->i_sb->s_user_ns, inode->i_uid);
++      return from_kuid(i_user_ns(inode), inode->i_uid);
+ }
+ 
+ static inline gid_t i_gid_read(const struct inode *inode)
+ {
+-      return from_kgid(inode->i_sb->s_user_ns, inode->i_gid);
++      return from_kgid(i_user_ns(inode), inode->i_gid);
+ }
+ 
+ static inline void i_uid_write(struct inode *inode, uid_t uid)
+ {
+-      inode->i_uid = make_kuid(inode->i_sb->s_user_ns, uid);
++      inode->i_uid = make_kuid(i_user_ns(inode), uid);
+ }
+ 
+ static inline void i_gid_write(struct inode *inode, gid_t gid)
+ {
+-      inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid);
+-}
+-
+-/**
+- * kuid_into_mnt - map a kuid down into a mnt_userns
+- * @mnt_userns: user namespace of the relevant mount
+- * @kuid: kuid to be mapped
+- *
+- * Return: @kuid mapped according to @mnt_userns.
+- * If @kuid has no mapping INVALID_UID is returned.
+- */
+-static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns,
+-                                 kuid_t kuid)
+-{
+-      return make_kuid(mnt_userns, __kuid_val(kuid));
+-}
+-
+-/**
+- * kgid_into_mnt - map a kgid down into a mnt_userns
+- * @mnt_userns: user namespace of the relevant mount
+- * @kgid: kgid to be mapped
+- *
+- * Return: @kgid mapped according to @mnt_userns.
+- * If @kgid has no mapping INVALID_GID is returned.
+- */
+-static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns,
+-                                 kgid_t kgid)
+-{
+-      return make_kgid(mnt_userns, __kgid_val(kgid));
++      inode->i_gid = make_kgid(i_user_ns(inode), gid);
+ }
+ 
+ /**
+@@ -1665,7 +1643,7 @@ static inline kgid_t kgid_into_mnt(struct user_namespace 
*mnt_userns,
+ static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns,
+                                   const struct inode *inode)
+ {
+-      return kuid_into_mnt(mnt_userns, inode->i_uid);
++      return mapped_kuid_fs(mnt_userns, i_user_ns(inode), inode->i_uid);
+ }
+ 
+ /**
+@@ -1679,69 +1657,7 @@ static inline kuid_t i_uid_into_mnt(struct 
user_namespace *mnt_userns,
+ static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns,
+                                   const struct inode *inode)
+ {
+-      return kgid_into_mnt(mnt_userns, inode->i_gid);
+-}
+-
+-/**
+- * kuid_from_mnt - map a kuid up into a mnt_userns
+- * @mnt_userns: user namespace of the relevant mount
+- * @kuid: kuid to be mapped
+- *
+- * Return: @kuid mapped up according to @mnt_userns.
+- * If @kuid has no mapping INVALID_UID is returned.
+- */
+-static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns,
+-                                 kuid_t kuid)
+-{
+-      return KUIDT_INIT(from_kuid(mnt_userns, kuid));
+-}
+-
+-/**
+- * kgid_from_mnt - map a kgid up into a mnt_userns
+- * @mnt_userns: user namespace of the relevant mount
+- * @kgid: kgid to be mapped
+- *
+- * Return: @kgid mapped up according to @mnt_userns.
+- * If @kgid has no mapping INVALID_GID is returned.
+- */
+-static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns,
+-                                 kgid_t kgid)
+-{
+-      return KGIDT_INIT(from_kgid(mnt_userns, kgid));
+-}
+-
+-/**
+- * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns
+- * @mnt_userns: user namespace of the relevant mount
+- *
+- * Use this helper to initialize a new vfs or filesystem object based on
+- * the caller's fsuid. A common example is initializing the i_uid field of
+- * a newly allocated inode triggered by a creation event such as mkdir or
+- * O_CREAT. Other examples include the allocation of quotas for a specific
+- * user.
+- *
+- * Return: the caller's current fsuid mapped up according to @mnt_userns.
+- */
+-static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns)
+-{
+-      return kuid_from_mnt(mnt_userns, current_fsuid());
+-}
+-
+-/**
+- * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns
+- * @mnt_userns: user namespace of the relevant mount
+- *
+- * Use this helper to initialize a new vfs or filesystem object based on
+- * the caller's fsgid. A common example is initializing the i_gid field of
+- * a newly allocated inode triggered by a creation event such as mkdir or
+- * O_CREAT. Other examples include the allocation of quotas for a specific
+- * user.
+- *
+- * Return: the caller's current fsgid mapped up according to @mnt_userns.
+- */
+-static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns)
+-{
+-      return kgid_from_mnt(mnt_userns, current_fsgid());
++      return mapped_kgid_fs(mnt_userns, i_user_ns(inode), inode->i_gid);
+ }
+ 
+ /**
+@@ -1755,7 +1671,7 @@ static inline kgid_t mapped_fsgid(struct user_namespace 
*mnt_userns)
+ static inline void inode_fsuid_set(struct inode *inode,
+                                  struct user_namespace *mnt_userns)
+ {
+-      inode->i_uid = mapped_fsuid(mnt_userns);
++      inode->i_uid = mapped_fsuid(mnt_userns, i_user_ns(inode));
+ }
+ 
+ /**
+@@ -1769,7 +1685,7 @@ static inline void inode_fsuid_set(struct inode *inode,
+ static inline void inode_fsgid_set(struct inode *inode,
+                                  struct user_namespace *mnt_userns)
+ {
+-      inode->i_gid = mapped_fsgid(mnt_userns);
++      inode->i_gid = mapped_fsgid(mnt_userns, i_user_ns(inode));
+ }
+ 
+ /**
+@@ -1786,10 +1702,18 @@ static inline void inode_fsgid_set(struct inode *inode,
+ static inline bool fsuidgid_has_mapping(struct super_block *sb,
+                                       struct user_namespace *mnt_userns)
+ {
+-      struct user_namespace *s_user_ns = sb->s_user_ns;
++      struct user_namespace *fs_userns = sb->s_user_ns;
++      kuid_t kuid;
++      kgid_t kgid;
+ 
+-      return kuid_has_mapping(s_user_ns, mapped_fsuid(mnt_userns)) &&
+-             kgid_has_mapping(s_user_ns, mapped_fsgid(mnt_userns));
++      kuid = mapped_fsuid(mnt_userns, fs_userns);
++      if (!uid_valid(kuid))
++              return false;
++      kgid = mapped_fsgid(mnt_userns, fs_userns);
++      if (!gid_valid(kgid))
++              return false;
++      return kuid_has_mapping(fs_userns, kuid) &&
++             kgid_has_mapping(fs_userns, kgid);
+ }
+ 
+ extern struct timespec64 current_time(struct inode *inode);
+@@ -2726,6 +2650,21 @@ static inline struct user_namespace 
*file_mnt_user_ns(struct file *file)
+ {
+       return mnt_user_ns(file->f_path.mnt);
+ }
++
++/**
++ * is_idmapped_mnt - check whether a mount is mapped
++ * @mnt: the mount to check
++ *
++ * If @mnt has an idmapping attached different from the
++ * filesystem's idmapping then @mnt is mapped.
++ *
++ * Return: true if mount is mapped, false if not.
++ */
++static inline bool is_idmapped_mnt(const struct vfsmount *mnt)
++{
++      return mnt_user_ns(mnt) != mnt->mnt_sb->s_user_ns;
++}
++
+ extern long vfs_truncate(const struct path *, loff_t);
+ int do_truncate(struct user_namespace *, struct dentry *, loff_t start,
+               unsigned int time_attrs, struct file *filp);
+diff --git a/include/linux/mnt_idmapping.h b/include/linux/mnt_idmapping.h
+new file mode 100644
+index 0000000000000..ee5a217de2a88
+--- /dev/null
++++ b/include/linux/mnt_idmapping.h
+@@ -0,0 +1,234 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef _LINUX_MNT_IDMAPPING_H
++#define _LINUX_MNT_IDMAPPING_H
++
++#include <linux/types.h>
++#include <linux/uidgid.h>
++
++struct user_namespace;
++/*
++ * Carries the initial idmapping of 0:0:4294967295 which is an identity
++ * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is
++ * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...].
++ */
++extern struct user_namespace init_user_ns;
++
++/**
++ * initial_idmapping - check whether this is the initial mapping
++ * @ns: idmapping to check
++ *
++ * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1,
++ * [...], 1000 to 1000 [...].
++ *
++ * Return: true if this is the initial mapping, false if not.
++ */
++static inline bool initial_idmapping(const struct user_namespace *ns)
++{
++      return ns == &init_user_ns;
++}
++
++/**
++ * no_idmapping - check whether we can skip remapping a kuid/gid
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ *
++ * This function can be used to check whether a remapping between two
++ * idmappings is required.
++ * An idmapped mount is a mount that has an idmapping attached to it that
++ * is different from the filsystem's idmapping and the initial idmapping.
++ * If the initial mapping is used or the idmapping of the mount and the
++ * filesystem are identical no remapping is required.
++ *
++ * Return: true if remapping can be skipped, false if not.
++ */
++static inline bool no_idmapping(const struct user_namespace *mnt_userns,
++                              const struct user_namespace *fs_userns)
++{
++      return initial_idmapping(mnt_userns) || mnt_userns == fs_userns;
++}
++
++/**
++ * mapped_kuid_fs - map a filesystem kuid into a mnt_userns
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ * @kuid : kuid to be mapped
++ *
++ * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this
++ * function when preparing a @kuid to be reported to userspace.
++ *
++ * If no_idmapping() determines that this is not an idmapped mount we can
++ * simply return @kuid unchanged.
++ * If initial_idmapping() tells us that the filesystem is not mounted with an
++ * idmapping we know the value of @kuid won't change when calling
++ * from_kuid() so we can simply retrieve the value via __kuid_val()
++ * directly.
++ *
++ * Return: @kuid mapped according to @mnt_userns.
++ * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
++ * returned.
++ */
++static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
++                                  struct user_namespace *fs_userns,
++                                  kuid_t kuid)
++{
++      uid_t uid;
++
++      if (no_idmapping(mnt_userns, fs_userns))
++              return kuid;
++      if (initial_idmapping(fs_userns))
++              uid = __kuid_val(kuid);
++      else
++              uid = from_kuid(fs_userns, kuid);
++      if (uid == (uid_t)-1)
++              return INVALID_UID;
++      return make_kuid(mnt_userns, uid);
++}
++
++/**
++ * mapped_kgid_fs - map a filesystem kgid into a mnt_userns
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ * @kgid : kgid to be mapped
++ *
++ * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this
++ * function when preparing a @kgid to be reported to userspace.
++ *
++ * If no_idmapping() determines that this is not an idmapped mount we can
++ * simply return @kgid unchanged.
++ * If initial_idmapping() tells us that the filesystem is not mounted with an
++ * idmapping we know the value of @kgid won't change when calling
++ * from_kgid() so we can simply retrieve the value via __kgid_val()
++ * directly.
++ *
++ * Return: @kgid mapped according to @mnt_userns.
++ * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
++ * returned.
++ */
++static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
++                                  struct user_namespace *fs_userns,
++                                  kgid_t kgid)
++{
++      gid_t gid;
++
++      if (no_idmapping(mnt_userns, fs_userns))
++              return kgid;
++      if (initial_idmapping(fs_userns))
++              gid = __kgid_val(kgid);
++      else
++              gid = from_kgid(fs_userns, kgid);
++      if (gid == (gid_t)-1)
++              return INVALID_GID;
++      return make_kgid(mnt_userns, gid);
++}
++
++/**
++ * mapped_kuid_user - map a user kuid into a mnt_userns
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ * @kuid : kuid to be mapped
++ *
++ * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this
++ * function when preparing a @kuid to be written to disk or inode.
++ *
++ * If no_idmapping() determines that this is not an idmapped mount we can
++ * simply return @kuid unchanged.
++ * If initial_idmapping() tells us that the filesystem is not mounted with an
++ * idmapping we know the value of @kuid won't change when calling
++ * make_kuid() so we can simply retrieve the value via KUIDT_INIT()
++ * directly.
++ *
++ * Return: @kuid mapped according to @mnt_userns.
++ * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
++ * returned.
++ */
++static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns,
++                                    struct user_namespace *fs_userns,
++                                    kuid_t kuid)
++{
++      uid_t uid;
++
++      if (no_idmapping(mnt_userns, fs_userns))
++              return kuid;
++      uid = from_kuid(mnt_userns, kuid);
++      if (uid == (uid_t)-1)
++              return INVALID_UID;
++      if (initial_idmapping(fs_userns))
++              return KUIDT_INIT(uid);
++      return make_kuid(fs_userns, uid);
++}
++
++/**
++ * mapped_kgid_user - map a user kgid into a mnt_userns
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ * @kgid : kgid to be mapped
++ *
++ * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this
++ * function when preparing a @kgid to be written to disk or inode.
++ *
++ * If no_idmapping() determines that this is not an idmapped mount we can
++ * simply return @kgid unchanged.
++ * If initial_idmapping() tells us that the filesystem is not mounted with an
++ * idmapping we know the value of @kgid won't change when calling
++ * make_kgid() so we can simply retrieve the value via KGIDT_INIT()
++ * directly.
++ *
++ * Return: @kgid mapped according to @mnt_userns.
++ * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
++ * returned.
++ */
++static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
++                                    struct user_namespace *fs_userns,
++                                    kgid_t kgid)
++{
++      gid_t gid;
++
++      if (no_idmapping(mnt_userns, fs_userns))
++              return kgid;
++      gid = from_kgid(mnt_userns, kgid);
++      if (gid == (gid_t)-1)
++              return INVALID_GID;
++      if (initial_idmapping(fs_userns))
++              return KGIDT_INIT(gid);
++      return make_kgid(fs_userns, gid);
++}
++
++/**
++ * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ *
++ * Use this helper to initialize a new vfs or filesystem object based on
++ * the caller's fsuid. A common example is initializing the i_uid field of
++ * a newly allocated inode triggered by a creation event such as mkdir or
++ * O_CREAT. Other examples include the allocation of quotas for a specific
++ * user.
++ *
++ * Return: the caller's current fsuid mapped up according to @mnt_userns.
++ */
++static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns,
++                                struct user_namespace *fs_userns)
++{
++      return mapped_kuid_user(mnt_userns, fs_userns, current_fsuid());
++}
++
++/**
++ * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns
++ * @mnt_userns: the mount's idmapping
++ * @fs_userns: the filesystem's idmapping
++ *
++ * Use this helper to initialize a new vfs or filesystem object based on
++ * the caller's fsgid. A common example is initializing the i_gid field of
++ * a newly allocated inode triggered by a creation event such as mkdir or
++ * O_CREAT. Other examples include the allocation of quotas for a specific
++ * user.
++ *
++ * Return: the caller's current fsgid mapped up according to @mnt_userns.
++ */
++static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns,
++                                struct user_namespace *fs_userns)
++{
++      return mapped_kgid_user(mnt_userns, fs_userns, current_fsgid());
++}
++
++#endif /* _LINUX_MNT_IDMAPPING_H */
+diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h
+index 060e8d2031814..1766e1de69560 100644
+--- a/include/linux/posix_acl_xattr.h
++++ b/include/linux/posix_acl_xattr.h
+@@ -34,15 +34,19 @@ posix_acl_xattr_count(size_t size)
+ 
+ #ifdef CONFIG_FS_POSIX_ACL
+ void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
++                                 struct inode *inode,
+                                  void *value, size_t size);
+ void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
++                                 struct inode *inode,
+                                void *value, size_t size);
+ #else
+ static inline void posix_acl_fix_xattr_from_user(struct user_namespace 
*mnt_userns,
++                                               struct inode *inode,
+                                                void *value, size_t size)
+ {
+ }
+ static inline void posix_acl_fix_xattr_to_user(struct user_namespace 
*mnt_userns,
++                                             struct inode *inode,
+                                              void *value, size_t size)
+ {
+ }
+diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
+index 19e6b861de97b..9c6f661fb4362 100644
+--- a/kernel/time/tick-sched.c
++++ b/kernel/time/tick-sched.c
+@@ -509,7 +509,6 @@ void __init tick_nohz_full_setup(cpumask_var_t cpumask)
+       cpumask_copy(tick_nohz_full_mask, cpumask);
+       tick_nohz_full_running = true;
+ }
+-EXPORT_SYMBOL_GPL(tick_nohz_full_setup);
+ 
+ static int tick_nohz_cpu_down(unsigned int cpu)
+ {
+diff --git a/security/commoncap.c b/security/commoncap.c
+index 3f810d37b71bd..5fc8986c3c77c 100644
+--- a/security/commoncap.c
++++ b/security/commoncap.c
+@@ -24,6 +24,7 @@
+ #include <linux/user_namespace.h>
+ #include <linux/binfmts.h>
+ #include <linux/personality.h>
++#include <linux/mnt_idmapping.h>
+ 
+ /*
+  * If a non-root user executes a setuid-root binary in
+@@ -418,7 +419,7 @@ int cap_inode_getsecurity(struct user_namespace 
*mnt_userns,
+       kroot = make_kuid(fs_ns, root);
+ 
+       /* If this is an idmapped mount shift the kuid. */
+-      kroot = kuid_into_mnt(mnt_userns, kroot);
++      kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot);
+ 
+       /* If the root kuid maps to a valid uid in current ns, then return
+        * this as a nscap. */
+@@ -488,6 +489,7 @@ out_free:
+  * @size:     size of @ivalue
+  * @task_ns:  user namespace of the caller
+  * @mnt_userns:       user namespace of the mount the inode was found from
++ * @fs_userns:        user namespace of the filesystem
+  *
+  * If the inode has been found through an idmapped mount the user namespace of
+  * the vfsmount must be passed through @mnt_userns. This function will then
+@@ -497,7 +499,8 @@ out_free:
+  */
+ static kuid_t rootid_from_xattr(const void *value, size_t size,
+                               struct user_namespace *task_ns,
+-                              struct user_namespace *mnt_userns)
++                              struct user_namespace *mnt_userns,
++                              struct user_namespace *fs_userns)
+ {
+       const struct vfs_ns_cap_data *nscap = value;
+       kuid_t rootkid;
+@@ -507,7 +510,7 @@ static kuid_t rootid_from_xattr(const void *value, size_t 
size,
+               rootid = le32_to_cpu(nscap->rootid);
+ 
+       rootkid = make_kuid(task_ns, rootid);
+-      return kuid_from_mnt(mnt_userns, rootkid);
++      return mapped_kuid_user(mnt_userns, fs_userns, rootkid);
+ }
+ 
+ static bool validheader(size_t size, const struct vfs_cap_data *cap)
+@@ -553,12 +556,12 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, 
struct dentry *dentry,
+               return -EINVAL;
+       if (!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_SETFCAP))
+               return -EPERM;
+-      if (size == XATTR_CAPS_SZ_2 && (mnt_userns == &init_user_ns))
++      if (size == XATTR_CAPS_SZ_2 && (mnt_userns == fs_ns))
+               if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP))
+                       /* user is privileged, just write the v2 */
+                       return size;
+ 
+-      rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns);
++      rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns);
+       if (!uid_valid(rootid))
+               return -EINVAL;
+ 
+@@ -699,7 +702,7 @@ int get_vfs_caps_from_disk(struct user_namespace 
*mnt_userns,
+       /* Limit the caps to the mounter of the filesystem
+        * or the more limited uid specified in the xattr.
+        */
+-      rootkuid = kuid_into_mnt(mnt_userns, rootkuid);
++      rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid);
+       if (!rootid_owns_currentns(rootkuid))
+               return -ENODATA;
+ 

Reply via email to