summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--0000_README4
-rw-r--r--1006_linux-5.18.7.patch779
2 files changed, 783 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 84b72755..17ef0755 100644
--- a/0000_README
+++ b/0000_README
@@ -67,6 +67,10 @@ Patch: 1005_linux-5.18.6.patch
From: http://www.kernel.org
Desc: Linux 5.18.6
+Patch: 1006_linux-5.18.7.patch
+From: http://www.kernel.org
+Desc: Linux 5.18.7
+
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/1006_linux-5.18.7.patch b/1006_linux-5.18.7.patch
new file mode 100644
index 00000000..ec6938d8
--- /dev/null
+++ b/1006_linux-5.18.7.patch
@@ -0,0 +1,779 @@
+diff --git a/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml b/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml
+index 80914b93638e4..24c5e38584528 100644
+--- a/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml
++++ b/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml
+@@ -24,15 +24,29 @@ properties:
+ reg:
+ maxItems: 1
+
++ clocks:
++ maxItems: 1
++ description:
++ The SFP clock. Typically, this is the platform clock divided by 4.
++
++ clock-names:
++ const: sfp
++
+ required:
+ - compatible
+ - reg
++ - clock-names
++ - clocks
+
+ unevaluatedProperties: false
+
+ examples:
+ - |
++ #include <dt-bindings/clock/fsl,qoriq-clockgen.h>
+ efuse@1e80000 {
+ compatible = "fsl,ls1028a-sfp";
+ reg = <0x1e80000 0x8000>;
++ clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
++ QORIQ_CLK_PLL_DIV(4)>;
++ clock-names = "sfp";
+ };
+diff --git a/Makefile b/Makefile
+index 27850d452d652..61d63068553c8 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 18
+-SUBLEVEL = 6
++SUBLEVEL = 7
+ EXTRAVERSION =
+ NAME = Superb Owl
+
+diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
+index 697df02362af1..4909dcd762e8c 100644
+--- a/arch/s390/mm/pgtable.c
++++ b/arch/s390/mm/pgtable.c
+@@ -748,7 +748,7 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+ pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT;
+ ptev = pte_val(*ptep);
+ if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE))
+- page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1);
++ page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 0);
+ pgste_set_unlock(ptep, pgste);
+ preempt_enable();
+ }
+diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
+index 34c9dbb6a47d6..686a9d75a0e41 100644
+--- a/arch/x86/boot/boot.h
++++ b/arch/x86/boot/boot.h
+@@ -110,66 +110,78 @@ typedef unsigned int addr_t;
+
+ static inline u8 rdfs8(addr_t addr)
+ {
++ u8 *ptr = (u8 *)absolute_pointer(addr);
+ u8 v;
+- asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
++ asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*ptr));
+ return v;
+ }
+ static inline u16 rdfs16(addr_t addr)
+ {
++ u16 *ptr = (u16 *)absolute_pointer(addr);
+ u16 v;
+- asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
++ asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*ptr));
+ return v;
+ }
+ static inline u32 rdfs32(addr_t addr)
+ {
++ u32 *ptr = (u32 *)absolute_pointer(addr);
+ u32 v;
+- asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
++ asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*ptr));
+ return v;
+ }
+
+ static inline void wrfs8(u8 v, addr_t addr)
+ {
+- asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "qi" (v));
++ u8 *ptr = (u8 *)absolute_pointer(addr);
++ asm volatile("movb %1,%%fs:%0" : "+m" (*ptr) : "qi" (v));
+ }
+ static inline void wrfs16(u16 v, addr_t addr)
+ {
+- asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "ri" (v));
++ u16 *ptr = (u16 *)absolute_pointer(addr);
++ asm volatile("movw %1,%%fs:%0" : "+m" (*ptr) : "ri" (v));
+ }
+ static inline void wrfs32(u32 v, addr_t addr)
+ {
+- asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "ri" (v));
++ u32 *ptr = (u32 *)absolute_pointer(addr);
++ asm volatile("movl %1,%%fs:%0" : "+m" (*ptr) : "ri" (v));
+ }
+
+ static inline u8 rdgs8(addr_t addr)
+ {
++ u8 *ptr = (u8 *)absolute_pointer(addr);
+ u8 v;
+- asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
++ asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*ptr));
+ return v;
+ }
+ static inline u16 rdgs16(addr_t addr)
+ {
++ u16 *ptr = (u16 *)absolute_pointer(addr);
+ u16 v;
+- asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
++ asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*ptr));
+ return v;
+ }
+ static inline u32 rdgs32(addr_t addr)
+ {
++ u32 *ptr = (u32 *)absolute_pointer(addr);
+ u32 v;
+- asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
++ asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*ptr));
+ return v;
+ }
+
+ static inline void wrgs8(u8 v, addr_t addr)
+ {
+- asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "qi" (v));
++ u8 *ptr = (u8 *)absolute_pointer(addr);
++ asm volatile("movb %1,%%gs:%0" : "+m" (*ptr) : "qi" (v));
+ }
+ static inline void wrgs16(u16 v, addr_t addr)
+ {
+- asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "ri" (v));
++ u16 *ptr = (u16 *)absolute_pointer(addr);
++ asm volatile("movw %1,%%gs:%0" : "+m" (*ptr) : "ri" (v));
+ }
+ static inline void wrgs32(u32 v, addr_t addr)
+ {
+- asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "ri" (v));
++ u32 *ptr = (u32 *)absolute_pointer(addr);
++ asm volatile("movl %1,%%gs:%0" : "+m" (*ptr) : "ri" (v));
+ }
+
+ /* Note: these only return true/false, not a signed return value! */
+diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
+index e3add857c2c9d..c421af5a3cdce 100644
+--- a/arch/x86/boot/main.c
++++ b/arch/x86/boot/main.c
+@@ -33,7 +33,7 @@ static void copy_boot_params(void)
+ u16 cl_offset;
+ };
+ const struct old_cmdline * const oldcmd =
+- (const struct old_cmdline *)OLD_CL_ADDRESS;
++ absolute_pointer(OLD_CL_ADDRESS);
+
+ BUILD_BUG_ON(sizeof(boot_params) != 4096);
+ memcpy(&boot_params.hdr, &hdr, sizeof(hdr));
+diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c
+index b04a6a7bf5669..435dc00d04e5d 100644
+--- a/drivers/net/ethernet/sun/cassini.c
++++ b/drivers/net/ethernet/sun/cassini.c
+@@ -1313,7 +1313,7 @@ static void cas_init_rx_dma(struct cas *cp)
+ writel(val, cp->regs + REG_RX_PAGE_SIZE);
+
+ /* enable the header parser if desired */
+- if (CAS_HP_FIRMWARE == cas_prog_null)
++ if (&CAS_HP_FIRMWARE[0] == &cas_prog_null[0])
+ return;
+
+ val = CAS_BASE(HP_CFG_NUM_CPU, CAS_NCPUS > 63 ? 0 : CAS_NCPUS);
+@@ -3780,7 +3780,7 @@ static void cas_reset(struct cas *cp, int blkflag)
+
+ /* program header parser */
+ if ((cp->cas_flags & CAS_FLAG_TARGET_ABORT) ||
+- (CAS_HP_ALT_FIRMWARE == cas_prog_null)) {
++ (&CAS_HP_ALT_FIRMWARE[0] == &cas_prog_null[0])) {
+ cas_load_firmware(cp, CAS_HP_FIRMWARE);
+ } else {
+ cas_load_firmware(cp, CAS_HP_ALT_FIRMWARE);
+diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
+index 51fe51bb05041..15e6a6aded319 100644
+--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
+@@ -2386,10 +2386,7 @@ void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel)
+ rtl_dbg(rtlpriv, COMP_SCAN, DBG_LOUD,
+ "Just Read IQK Matrix reg for channel:%d....\n",
+ channel);
+- if ((rtlphy->iqk_matrix[indexforchannel].
+- value[0] != NULL)
+- /*&&(regea4 != 0) */)
+- _rtl92d_phy_patha_fill_iqk_matrix(hw, true,
++ _rtl92d_phy_patha_fill_iqk_matrix(hw, true,
+ rtlphy->iqk_matrix[
+ indexforchannel].value, 0,
+ (rtlphy->iqk_matrix[
+diff --git a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
+index c6b032f95d2e4..4627847c6daab 100644
+--- a/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
++++ b/drivers/net/wwan/iosm/iosm_ipc_protocol_ops.c
+@@ -372,8 +372,6 @@ bool ipc_protocol_dl_td_prepare(struct iosm_protocol *ipc_protocol,
+ struct sk_buff *ipc_protocol_dl_td_process(struct iosm_protocol *ipc_protocol,
+ struct ipc_pipe *pipe)
+ {
+- u32 tail =
+- le32_to_cpu(ipc_protocol->p_ap_shm->tail_array[pipe->pipe_nr]);
+ struct ipc_protocol_td *p_td;
+ struct sk_buff *skb;
+
+@@ -403,14 +401,6 @@ struct sk_buff *ipc_protocol_dl_td_process(struct iosm_protocol *ipc_protocol,
+ goto ret;
+ }
+
+- if (!IPC_CB(skb)) {
+- dev_err(ipc_protocol->dev, "pipe# %d, tail: %d skb_cb is NULL",
+- pipe->pipe_nr, tail);
+- ipc_pcie_kfree_skb(ipc_protocol->pcie, skb);
+- skb = NULL;
+- goto ret;
+- }
+-
+ if (p_td->buffer.address != IPC_CB(skb)->mapping) {
+ dev_err(ipc_protocol->dev, "invalid buf=%llx or skb=%p",
+ (unsigned long long)p_td->buffer.address, skb->data);
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index 3d123ca028c97..68aab48838e41 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -1647,7 +1647,7 @@ static inline void io_req_track_inflight(struct io_kiocb *req)
+ {
+ if (!(req->flags & REQ_F_INFLIGHT)) {
+ req->flags |= REQ_F_INFLIGHT;
+- atomic_inc(&current->io_uring->inflight_tracked);
++ atomic_inc(&req->task->io_uring->inflight_tracked);
+ }
+ }
+
+diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
+index 985e995d2a398..4f897e1095470 100644
+--- a/fs/notify/fanotify/fanotify.c
++++ b/fs/notify/fanotify/fanotify.c
+@@ -319,12 +319,8 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
+ return 0;
+ }
+
+- fsnotify_foreach_iter_type(type) {
+- if (!fsnotify_iter_should_report_type(iter_info, type))
+- continue;
+- mark = iter_info->marks[type];
+-
+- /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */
++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
++ /* Apply ignore mask regardless of mark's ISDIR flag */
+ marks_ignored_mask |= mark->ignored_mask;
+
+ /*
+@@ -334,14 +330,6 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
+ if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
+ continue;
+
+- /*
+- * If the event is on a child and this mark is on a parent not
+- * watching children, don't send it!
+- */
+- if (type == FSNOTIFY_ITER_TYPE_PARENT &&
+- !(mark->mask & FS_EVENT_ON_CHILD))
+- continue;
+-
+ marks_mask |= mark->mask;
+
+ /* Record the mark types of this group that matched the event */
+@@ -849,16 +837,14 @@ out:
+ */
+ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
+ {
++ struct fsnotify_mark *mark;
+ int type;
+ __kernel_fsid_t fsid = {};
+
+- fsnotify_foreach_iter_type(type) {
++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
+ struct fsnotify_mark_connector *conn;
+
+- if (!fsnotify_iter_should_report_type(iter_info, type))
+- continue;
+-
+- conn = READ_ONCE(iter_info->marks[type]->connector);
++ conn = READ_ONCE(mark->connector);
+ /* Mark is just getting destroyed or created? */
+ if (!conn)
+ continue;
+diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
+index 70a8516b78bc5..6d63423cd4928 100644
+--- a/fs/notify/fsnotify.c
++++ b/fs/notify/fsnotify.c
+@@ -290,22 +290,15 @@ static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask,
+ }
+
+ if (parent_mark) {
+- /*
+- * parent_mark indicates that the parent inode is watching
+- * children and interested in this event, which is an event
+- * possible on child. But is *this mark* watching children and
+- * interested in this event?
+- */
+- if (parent_mark->mask & FS_EVENT_ON_CHILD) {
+- ret = fsnotify_handle_inode_event(group, parent_mark, mask,
+- data, data_type, dir, name, 0);
+- if (ret)
+- return ret;
+- }
+- if (!inode_mark)
+- return 0;
++ ret = fsnotify_handle_inode_event(group, parent_mark, mask,
++ data, data_type, dir, name, 0);
++ if (ret)
++ return ret;
+ }
+
++ if (!inode_mark)
++ return 0;
++
+ if (mask & FS_EVENT_ON_CHILD) {
+ /*
+ * Some events can be sent on both parent dir and child marks
+@@ -335,31 +328,23 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
+ struct fsnotify_mark *mark;
+ int type;
+
+- if (WARN_ON(!iter_info->report_mask))
++ if (!iter_info->report_mask)
+ return 0;
+
+ /* clear ignored on inode modification */
+ if (mask & FS_MODIFY) {
+- fsnotify_foreach_iter_type(type) {
+- if (!fsnotify_iter_should_report_type(iter_info, type))
+- continue;
+- mark = iter_info->marks[type];
+- if (mark &&
+- !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
++ if (!(mark->flags &
++ FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
+ mark->ignored_mask = 0;
+ }
+ }
+
+- fsnotify_foreach_iter_type(type) {
+- if (!fsnotify_iter_should_report_type(iter_info, type))
+- continue;
+- mark = iter_info->marks[type];
+- /* does the object mark tell us to do something? */
+- if (mark) {
+- group = mark->group;
+- marks_mask |= mark->mask;
+- marks_ignored_mask |= mark->ignored_mask;
+- }
++ /* Are any of the group marks interested in this event? */
++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
++ group = mark->group;
++ marks_mask |= mark->mask;
++ marks_ignored_mask |= mark->ignored_mask;
+ }
+
+ pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n",
+@@ -403,11 +388,11 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
+
+ /*
+ * iter_info is a multi head priority queue of marks.
+- * Pick a subset of marks from queue heads, all with the
+- * same group and set the report_mask for selected subset.
+- * Returns the report_mask of the selected subset.
++ * Pick a subset of marks from queue heads, all with the same group
++ * and set the report_mask to a subset of the selected marks.
++ * Returns false if there are no more groups to iterate.
+ */
+-static unsigned int fsnotify_iter_select_report_types(
++static bool fsnotify_iter_select_report_types(
+ struct fsnotify_iter_info *iter_info)
+ {
+ struct fsnotify_group *max_prio_group = NULL;
+@@ -423,30 +408,48 @@ static unsigned int fsnotify_iter_select_report_types(
+ }
+
+ if (!max_prio_group)
+- return 0;
++ return false;
+
+ /* Set the report mask for marks from same group as max prio group */
++ iter_info->current_group = max_prio_group;
+ iter_info->report_mask = 0;
+ fsnotify_foreach_iter_type(type) {
+ mark = iter_info->marks[type];
+- if (mark &&
+- fsnotify_compare_groups(max_prio_group, mark->group) == 0)
++ if (mark && mark->group == iter_info->current_group) {
++ /*
++ * FSNOTIFY_ITER_TYPE_PARENT indicates that this inode
++ * is watching children and interested in this event,
++ * which is an event possible on child.
++ * But is *this mark* watching children?
++ */
++ if (type == FSNOTIFY_ITER_TYPE_PARENT &&
++ !(mark->mask & FS_EVENT_ON_CHILD))
++ continue;
++
+ fsnotify_iter_set_report_type(iter_info, type);
++ }
+ }
+
+- return iter_info->report_mask;
++ return true;
+ }
+
+ /*
+- * Pop from iter_info multi head queue, the marks that were iterated in the
++ * Pop from iter_info multi head queue, the marks that belong to the group of
+ * current iteration step.
+ */
+ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
+ {
++ struct fsnotify_mark *mark;
+ int type;
+
++ /*
++ * We cannot use fsnotify_foreach_iter_mark_type() here because we
++ * may need to advance a mark of type X that belongs to current_group
++ * but was not selected for reporting.
++ */
+ fsnotify_foreach_iter_type(type) {
+- if (fsnotify_iter_should_report_type(iter_info, type))
++ mark = iter_info->marks[type];
++ if (mark && mark->group == iter_info->current_group)
+ iter_info->marks[type] =
+ fsnotify_next_mark(iter_info->marks[type]);
+ }
+diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
+index 1c2ece9611287..15a4c7c07a3bf 100644
+--- a/fs/zonefs/super.c
++++ b/fs/zonefs/super.c
+@@ -72,15 +72,51 @@ static inline void zonefs_i_size_write(struct inode *inode, loff_t isize)
+ zi->i_flags &= ~ZONEFS_ZONE_OPEN;
+ }
+
+-static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+- unsigned int flags, struct iomap *iomap,
+- struct iomap *srcmap)
++static int zonefs_read_iomap_begin(struct inode *inode, loff_t offset,
++ loff_t length, unsigned int flags,
++ struct iomap *iomap, struct iomap *srcmap)
+ {
+ struct zonefs_inode_info *zi = ZONEFS_I(inode);
+ struct super_block *sb = inode->i_sb;
+ loff_t isize;
+
+- /* All I/Os should always be within the file maximum size */
++ /*
++ * All blocks are always mapped below EOF. If reading past EOF,
++ * act as if there is a hole up to the file maximum size.
++ */
++ mutex_lock(&zi->i_truncate_mutex);
++ iomap->bdev = inode->i_sb->s_bdev;
++ iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
++ isize = i_size_read(inode);
++ if (iomap->offset >= isize) {
++ iomap->type = IOMAP_HOLE;
++ iomap->addr = IOMAP_NULL_ADDR;
++ iomap->length = length;
++ } else {
++ iomap->type = IOMAP_MAPPED;
++ iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
++ iomap->length = isize - iomap->offset;
++ }
++ mutex_unlock(&zi->i_truncate_mutex);
++
++ trace_zonefs_iomap_begin(inode, iomap);
++
++ return 0;
++}
++
++static const struct iomap_ops zonefs_read_iomap_ops = {
++ .iomap_begin = zonefs_read_iomap_begin,
++};
++
++static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
++ loff_t length, unsigned int flags,
++ struct iomap *iomap, struct iomap *srcmap)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct super_block *sb = inode->i_sb;
++ loff_t isize;
++
++ /* All write I/Os should always be within the file maximum size */
+ if (WARN_ON_ONCE(offset + length > zi->i_max_size))
+ return -EIO;
+
+@@ -90,7 +126,7 @@ static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+ * operation.
+ */
+ if (WARN_ON_ONCE(zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
+- (flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)))
++ !(flags & IOMAP_DIRECT)))
+ return -EIO;
+
+ /*
+@@ -99,47 +135,44 @@ static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+ * write pointer) and unwriten beyond.
+ */
+ mutex_lock(&zi->i_truncate_mutex);
++ iomap->bdev = inode->i_sb->s_bdev;
++ iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
++ iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
+ isize = i_size_read(inode);
+- if (offset >= isize)
++ if (iomap->offset >= isize) {
+ iomap->type = IOMAP_UNWRITTEN;
+- else
++ iomap->length = zi->i_max_size - iomap->offset;
++ } else {
+ iomap->type = IOMAP_MAPPED;
+- if (flags & IOMAP_WRITE)
+- length = zi->i_max_size - offset;
+- else
+- length = min(length, isize - offset);
++ iomap->length = isize - iomap->offset;
++ }
+ mutex_unlock(&zi->i_truncate_mutex);
+
+- iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
+- iomap->length = ALIGN(offset + length, sb->s_blocksize) - iomap->offset;
+- iomap->bdev = inode->i_sb->s_bdev;
+- iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
+-
+ trace_zonefs_iomap_begin(inode, iomap);
+
+ return 0;
+ }
+
+-static const struct iomap_ops zonefs_iomap_ops = {
+- .iomap_begin = zonefs_iomap_begin,
++static const struct iomap_ops zonefs_write_iomap_ops = {
++ .iomap_begin = zonefs_write_iomap_begin,
+ };
+
+ static int zonefs_readpage(struct file *unused, struct page *page)
+ {
+- return iomap_readpage(page, &zonefs_iomap_ops);
++ return iomap_readpage(page, &zonefs_read_iomap_ops);
+ }
+
+ static void zonefs_readahead(struct readahead_control *rac)
+ {
+- iomap_readahead(rac, &zonefs_iomap_ops);
++ iomap_readahead(rac, &zonefs_read_iomap_ops);
+ }
+
+ /*
+ * Map blocks for page writeback. This is used only on conventional zone files,
+ * which implies that the page range can only be within the fixed inode size.
+ */
+-static int zonefs_map_blocks(struct iomap_writepage_ctx *wpc,
+- struct inode *inode, loff_t offset)
++static int zonefs_write_map_blocks(struct iomap_writepage_ctx *wpc,
++ struct inode *inode, loff_t offset)
+ {
+ struct zonefs_inode_info *zi = ZONEFS_I(inode);
+
+@@ -153,12 +186,12 @@ static int zonefs_map_blocks(struct iomap_writepage_ctx *wpc,
+ offset < wpc->iomap.offset + wpc->iomap.length)
+ return 0;
+
+- return zonefs_iomap_begin(inode, offset, zi->i_max_size - offset,
+- IOMAP_WRITE, &wpc->iomap, NULL);
++ return zonefs_write_iomap_begin(inode, offset, zi->i_max_size - offset,
++ IOMAP_WRITE, &wpc->iomap, NULL);
+ }
+
+ static const struct iomap_writeback_ops zonefs_writeback_ops = {
+- .map_blocks = zonefs_map_blocks,
++ .map_blocks = zonefs_write_map_blocks,
+ };
+
+ static int zonefs_writepage(struct page *page, struct writeback_control *wbc)
+@@ -188,7 +221,8 @@ static int zonefs_swap_activate(struct swap_info_struct *sis,
+ return -EINVAL;
+ }
+
+- return iomap_swapfile_activate(sis, swap_file, span, &zonefs_iomap_ops);
++ return iomap_swapfile_activate(sis, swap_file, span,
++ &zonefs_read_iomap_ops);
+ }
+
+ static const struct address_space_operations zonefs_file_aops = {
+@@ -607,7 +641,7 @@ static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf)
+
+ /* Serialize against truncates */
+ filemap_invalidate_lock_shared(inode->i_mapping);
+- ret = iomap_page_mkwrite(vmf, &zonefs_iomap_ops);
++ ret = iomap_page_mkwrite(vmf, &zonefs_write_iomap_ops);
+ filemap_invalidate_unlock_shared(inode->i_mapping);
+
+ sb_end_pagefault(inode->i_sb);
+@@ -860,7 +894,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
+ if (append)
+ ret = zonefs_file_dio_append(iocb, from);
+ else
+- ret = iomap_dio_rw(iocb, from, &zonefs_iomap_ops,
++ ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
+ &zonefs_write_dio_ops, 0, 0);
+ if (zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
+ (ret > 0 || ret == -EIOCBQUEUED)) {
+@@ -902,7 +936,7 @@ static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
+ if (ret <= 0)
+ goto inode_unlock;
+
+- ret = iomap_file_buffered_write(iocb, from, &zonefs_iomap_ops);
++ ret = iomap_file_buffered_write(iocb, from, &zonefs_write_iomap_ops);
+ if (ret > 0)
+ iocb->ki_pos += ret;
+ else if (ret == -EIO)
+@@ -995,7 +1029,7 @@ static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+ goto inode_unlock;
+ }
+ file_accessed(iocb->ki_filp);
+- ret = iomap_dio_rw(iocb, to, &zonefs_iomap_ops,
++ ret = iomap_dio_rw(iocb, to, &zonefs_read_iomap_ops,
+ &zonefs_read_dio_ops, 0, 0);
+ } else {
+ ret = generic_file_read_iter(iocb, to);
+diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
+index 0805b74cae441..beb9c99fea07d 100644
+--- a/include/linux/fsnotify_backend.h
++++ b/include/linux/fsnotify_backend.h
+@@ -370,6 +370,7 @@ static inline bool fsnotify_valid_obj_type(unsigned int obj_type)
+
+ struct fsnotify_iter_info {
+ struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT];
++ struct fsnotify_group *current_group;
+ unsigned int report_mask;
+ int srcu_idx;
+ };
+@@ -386,20 +387,31 @@ static inline void fsnotify_iter_set_report_type(
+ iter_info->report_mask |= (1U << iter_type);
+ }
+
+-static inline void fsnotify_iter_set_report_type_mark(
+- struct fsnotify_iter_info *iter_info, int iter_type,
+- struct fsnotify_mark *mark)
++static inline struct fsnotify_mark *fsnotify_iter_mark(
++ struct fsnotify_iter_info *iter_info, int iter_type)
+ {
+- iter_info->marks[iter_type] = mark;
+- iter_info->report_mask |= (1U << iter_type);
++ if (fsnotify_iter_should_report_type(iter_info, iter_type))
++ return iter_info->marks[iter_type];
++ return NULL;
++}
++
++static inline int fsnotify_iter_step(struct fsnotify_iter_info *iter, int type,
++ struct fsnotify_mark **markp)
++{
++ while (type < FSNOTIFY_ITER_TYPE_COUNT) {
++ *markp = fsnotify_iter_mark(iter, type);
++ if (*markp)
++ break;
++ type++;
++ }
++ return type;
+ }
+
+ #define FSNOTIFY_ITER_FUNCS(name, NAME) \
+ static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \
+ struct fsnotify_iter_info *iter_info) \
+ { \
+- return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \
+- iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \
++ return fsnotify_iter_mark(iter_info, FSNOTIFY_ITER_TYPE_##NAME); \
+ }
+
+ FSNOTIFY_ITER_FUNCS(inode, INODE)
+@@ -409,6 +421,11 @@ FSNOTIFY_ITER_FUNCS(sb, SB)
+
+ #define fsnotify_foreach_iter_type(type) \
+ for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++)
++#define fsnotify_foreach_iter_mark_type(iter, mark, type) \
++ for (type = 0; \
++ type = fsnotify_iter_step(iter, type, &mark), \
++ type < FSNOTIFY_ITER_TYPE_COUNT; \
++ type++)
+
+ /*
+ * fsnotify_connp_t is what we embed in objects which connector can be attached
+diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
+index 0918a39279f6c..feef799884d1f 100644
+--- a/kernel/bpf/btf.c
++++ b/kernel/bpf/btf.c
+@@ -5769,6 +5769,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
+ struct bpf_reg_state *regs,
+ bool ptr_to_mem_ok)
+ {
++ enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
+ struct bpf_verifier_log *log = &env->log;
+ u32 i, nargs, ref_id, ref_obj_id = 0;
+ bool is_kfunc = btf_is_kernel(btf);
+@@ -5834,8 +5835,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
+ if (ret < 0)
+ return ret;
+
+- if (btf_get_prog_ctx_type(log, btf, t,
+- env->prog->type, i)) {
++ if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
+ /* If function expects ctx type in BTF check that caller
+ * is passing PTR_TO_CTX.
+ */
+diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
+index d9aad15e0d242..02bb8cbf91949 100644
+--- a/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
++++ b/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c
+@@ -395,6 +395,18 @@ static void test_func_map_prog_compatibility(void)
+ "./test_attach_probe.o");
+ }
+
++static void test_func_replace_global_func(void)
++{
++ const char *prog_name[] = {
++ "freplace/test_pkt_access",
++ };
++
++ test_fexit_bpf2bpf_common("./freplace_global_func.o",
++ "./test_pkt_access.o",
++ ARRAY_SIZE(prog_name),
++ prog_name, false, NULL);
++}
++
+ /* NOTE: affect other tests, must run in serial mode */
+ void serial_test_fexit_bpf2bpf(void)
+ {
+@@ -416,4 +428,6 @@ void serial_test_fexit_bpf2bpf(void)
+ test_func_replace_multi();
+ if (test__start_subtest("fmod_ret_freplace"))
+ test_fmod_ret_freplace();
++ if (test__start_subtest("func_replace_global_func"))
++ test_func_replace_global_func();
+ }
+diff --git a/tools/testing/selftests/bpf/progs/freplace_global_func.c b/tools/testing/selftests/bpf/progs/freplace_global_func.c
+new file mode 100644
+index 0000000000000..96cb61a6ce87a
+--- /dev/null
++++ b/tools/testing/selftests/bpf/progs/freplace_global_func.c
+@@ -0,0 +1,18 @@
++// SPDX-License-Identifier: GPL-2.0
++#include <linux/bpf.h>
++#include <bpf/bpf_helpers.h>
++
++__noinline
++int test_ctx_global_func(struct __sk_buff *skb)
++{
++ volatile int retval = 1;
++ return retval;
++}
++
++SEC("freplace/test_pkt_access")
++int new_test_pkt_access(struct __sk_buff *skb)
++{
++ return test_ctx_global_func(skb);
++}
++
++char _license[] SEC("license") = "GPL";