* Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
From: Lorenzo Stoakes @ 2026-02-09 14:02 UTC (permalink / raw)
To: Pedro Falcato
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <mflwgdnyipdf4reufmbx7qarjcgouct5coe2bllticrabcu6rt@vf3bvmpunimw>
On Fri, Feb 06, 2026 at 05:14:10PM +0000, Pedro Falcato wrote:
> On Thu, Jan 22, 2026 at 04:06:12PM +0000, Lorenzo Stoakes wrote:
> > This patch introduces the mk_vma_flags() macro helper to allow easy
> > manipulation of VMA flags utilising the new bitmap representation
> > implemented of VMA flags defined by the vma_flags_t type.
> >
> > It is a variadic macro which provides a bitwise-or'd representation of all
> > of each individual VMA flag specified.
> >
> > Note that, while we maintain VM_xxx flags for backwards compatibility until
> > the conversion is complete, we define VMA flags of type vma_flag_t using
> > VMA_xxx_BIT to avoid confusing the two.
> >
> > This helper macro therefore can be used thusly:
> >
> > vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
> >
> > We allow for up to 5 flags to specified at a time which should accommodate
> > all current kernel uses of combined VMA flags.
> >
>
> How do you allow up to 5 flags? I don't see any such limitation in the code?
Yeah oops :) This is from a previous implementation.
Andrew could you drop this paragraph? Thanks!
>
> > Testing has demonstrated that the compiler optimises this code such that it
> > generates the same assembly utilising this macro as it does if the flags
> > were specified manually, for instance:
> >
> > vma_flags_t get_flags(void)
> > {
> > return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> > }
> >
> > Generates the same code as:
> >
> > vma_flags_t get_flags(void)
> > {
> > vma_flags_t flags;
> >
> > vma_flags_clear_all(&flags);
> > vma_flag_set(&flags, VMA_READ_BIT);
> > vma_flag_set(&flags, VMA_WRITE_BIT);
> > vma_flag_set(&flags, VMA_EXEC_BIT);
> >
> > return flags;
> > }
> >
> > And:
> >
> > vma_flags_t get_flags(void)
> > {
> > vma_flags_t flags;
> > unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
> >
> > *bitmap = 1UL << (__force int)VMA_READ_BIT;
> > *bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
> > *bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
> >
> > return flags;
> > }
> >
> > That is:
> >
> > get_flags:
> > movl $7, %eax
> > ret
> >
> > Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Thanks!
>
> --
> Pedro
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
From: Lorenzo Stoakes @ 2026-02-09 14:04 UTC (permalink / raw)
To: Pedro Falcato
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <vrbggto75ugvpa5wtugmayr7yops6cnvygit42f2md646y6qnx@3vzc7taleijw>
On Fri, Feb 06, 2026 at 05:35:49PM +0000, Pedro Falcato wrote:
> On Thu, Jan 22, 2026 at 04:06:14PM +0000, Lorenzo Stoakes wrote:
> > Now we have the mk_vma_flags() macro helper which permits easy
> > specification of any number of VMA flags, add helper functions which
> > operate with vma_flags_t parameters.
> >
> > This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
> > vma_flags_clear[_mask]() respectively testing, setting and clearing flags
> > with the _mask variants accepting vma_flag_t parameters, and the non-mask
> > variants implemented as macros which accept a list of flags.
> >
> > This allows us to trivially test/set/clear aggregate VMA flag values as
> > necessary, for instance:
> >
> > if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
> > goto readwrite;
>
> I'm not a huge fan of the _test ambiguity here, but more words makes it uglier :/
> I think I can live with it though.
Yeah, as discussed on IRC it's a bit of a trade off here unfortunately.
I don't love having the _BIT stuff there but is necessary for now I feel until
VM_xxx flags are finally fully deprecated.
>
> >
> > vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
> >
> > vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
> >
>
> The variadic-ness here is very nice though.
Thanks!
>
> > We also add a function for testing that ALL flags are set for convenience,
> > e.g.:
> >
> > if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
> > /* Both READ and MAYREAD flags set */
> > ...
> > }
> >
> > The compiler generates optimal assembly for each such that they behave as
> > if the caller were setting the bitmap flags manually.
> >
> > This is important for e.g. drivers which manipulate flag values rather than
> > a VMA's specific flag values.
> >
> > We also add helpers for testing, setting and clearing flags for VMA's and
> > VMA descriptors to reduce boilerplate.
> >
> > Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
> >
> > Finally, update the userland VMA tests to add the helpers there so they can
> > be utilised as part of userland testing.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Thanks (also for other tags :P)
>
> --
> Pedro
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH] xfrm: kill xfrm_dev_{state,policy}_flush_secctx_check()
From: Tetsuo Handa @ 2026-02-09 14:26 UTC (permalink / raw)
To: Steffen Klassert, Paul Moore, SELinux, linux-security-module
Cc: Herbert Xu, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Network Development
In-Reply-To: <aYnDWbxo-jAzR4ca@secunet.com>
On 2026/02/09 20:22, Steffen Klassert wrote:
> On Mon, Feb 09, 2026 at 07:02:47PM +0900, Tetsuo Handa wrote:
>> On 2026/02/09 18:25, Steffen Klassert wrote:
>>> The problem is that, with adding IPsec offloads to netdevices, security
>>> critical resources came into the netdevices. Someone who has no
>>> capabilities to delete xfrm states or xfrm policies should not be able
>>> to unregister the netdevice if xfrm states or xfrm policies are
>>> offloaded. Unfortunately, unregistering can't be canceled at this stage
>>> anymore. So I think we need some netdevice unregistration hook for
>>> the LSM subsystem so it can check for xfrm states or xfrm policies
>>> and refuse the unregistration before we actually start to remove
>>> the device.
>>
>> Unfortunately, unregistering is not always triggered by a user's request. ;-)
>
> As far as I remember, a security context is not always tied to a
> user request. It can also be attached to system tasks or objects.
That is not what I wanted to say. There are at least three routes (listed below)
that can trigger xfrm_dev_unregister() path. You could insert LSM hooks into the
netlink_sendmsg() route and the del_device_store() route, but the cleanup_net()
route is a result of tear-down action which is too late to insert LSM hooks.
The NETDEV_UNREGISTER path can be triggered by just doing "unshare -n ip addr show"
(i.e. implicit cleanup of a network namespace due to termination of init process in
that namespace). We are not allowed to reject the cleanup_net() route.
----------
xfrm_dev_state_flush_secctx_check: LSM policy is rejecting this operation.
CPU: 0 UID: 0 PID: 16195 Comm: syz.3.3878 Tainted: G L syzkaller #0 PREEMPT(full)
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
xfrm_dev_state_flush_secctx_check net/xfrm/xfrm_state.c:900 [inline]
xfrm_dev_state_flush+0x5fa/0x740 net/xfrm/xfrm_state.c:971
xfrm_dev_unregister net/xfrm/xfrm_device.c:549 [inline]
xfrm_dev_event+0x1bc/0x3f0 net/xfrm/xfrm_device.c:570
notifier_call_chain+0x1be/0x400 kernel/notifier.c:85
call_netdevice_notifiers_extack net/core/dev.c:2281 [inline]
call_netdevice_notifiers net/core/dev.c:2295 [inline]
netdev_wait_allrefs_any net/core/dev.c:11589 [inline]
netdev_run_todo+0x778/0x1130 net/core/dev.c:11710
nsim_destroy+0x3ae/0x680 drivers/net/netdevsim/netdev.c:1190
__nsim_dev_port_del+0x14d/0x1b0 drivers/net/netdevsim/dev.c:1529
nsim_dev_port_del_all drivers/net/netdevsim/dev.c:1541 [inline]
nsim_dev_reload_destroy+0x288/0x490 drivers/net/netdevsim/dev.c:1765
nsim_dev_reload_down+0x8a/0xc0 drivers/net/netdevsim/dev.c:1039
devlink_reload+0x1d1/0x8e0 net/devlink/dev.c:461
devlink_nl_reload_doit+0xaaa/0xc80 net/devlink/dev.c:584
genl_family_rcv_msg_doit+0x22a/0x330 net/netlink/genetlink.c:1115
genl_family_rcv_msg net/netlink/genetlink.c:1195 [inline]
genl_rcv_msg+0x61c/0x7a0 net/netlink/genetlink.c:1210
netlink_rcv_skb+0x232/0x4b0 net/netlink/af_netlink.c:2550
genl_rcv+0x28/0x40 net/netlink/genetlink.c:1219
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x80f/0x9b0 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec+0x18f/0x1d0 net/socket.c:737
__sock_sendmsg net/socket.c:752 [inline]
____sys_sendmsg+0x589/0x8c0 net/socket.c:2610
___sys_sendmsg+0x2a5/0x360 net/socket.c:2664
__sys_sendmsg net/socket.c:2696 [inline]
__do_sys_sendmsg net/socket.c:2701 [inline]
__se_sys_sendmsg net/socket.c:2699 [inline]
__x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2699
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7feb10f9aeb9
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007feb11efc028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007feb11215fa0 RCX: 00007feb10f9aeb9
RDX: 0000000006048800 RSI: 0000200000000080 RDI: 0000000000000005
RBP: 00007feb11008c1f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007feb11216038 R14: 00007feb11215fa0 R15: 00007ffdd0b07b18
</TASK>
----------
----------
xfrm_dev_state_flush_secctx_check: LSM policy is rejecting this operation.
CPU: 1 UID: 0 PID: 11340 Comm: kworker/u8:17 Tainted: G L syzkaller #0 PREEMPT(full)
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
Workqueue: netns cleanup_net
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
xfrm_dev_state_flush_secctx_check net/xfrm/xfrm_state.c:900 [inline]
xfrm_dev_state_flush+0x5fa/0x740 net/xfrm/xfrm_state.c:971
xfrm_dev_unregister net/xfrm/xfrm_device.c:549 [inline]
xfrm_dev_event+0x1bc/0x3f0 net/xfrm/xfrm_device.c:570
notifier_call_chain+0x1be/0x400 kernel/notifier.c:85
call_netdevice_notifiers_extack net/core/dev.c:2281 [inline]
call_netdevice_notifiers net/core/dev.c:2295 [inline]
netdev_wait_allrefs_any net/core/dev.c:11589 [inline]
netdev_run_todo+0x778/0x1130 net/core/dev.c:11710
nsim_destroy+0x3ae/0x680 drivers/net/netdevsim/netdev.c:1190
__nsim_dev_port_del+0x14d/0x1b0 drivers/net/netdevsim/dev.c:1529
nsim_dev_port_del_all drivers/net/netdevsim/dev.c:1541 [inline]
nsim_dev_reload_destroy+0x288/0x490 drivers/net/netdevsim/dev.c:1765
nsim_dev_reload_down+0x8a/0xc0 drivers/net/netdevsim/dev.c:1039
devlink_reload+0x1d1/0x8e0 net/devlink/dev.c:461
devlink_pernet_pre_exit+0x1e6/0x3f0 net/devlink/core.c:509
ops_pre_exit_list net/core/net_namespace.c:161 [inline]
ops_undo_list+0x187/0x940 net/core/net_namespace.c:234
cleanup_net+0x4df/0x7b0 net/core/net_namespace.c:696
process_one_work+0x949/0x1650 kernel/workqueue.c:3279
process_scheduled_works kernel/workqueue.c:3362 [inline]
worker_thread+0xb46/0x1140 kernel/workqueue.c:3443
kthread+0x388/0x470 kernel/kthread.c:467
ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
----------
----------
xfrm_dev_state_flush_secctx_check: LSM policy is rejecting this operation.
CPU: 0 UID: 0 PID: 18368 Comm: syz-executor Tainted: G L syzkaller #0 PREEMPT(full)
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
xfrm_dev_state_flush_secctx_check net/xfrm/xfrm_state.c:900 [inline]
xfrm_dev_state_flush+0x5fa/0x740 net/xfrm/xfrm_state.c:971
xfrm_dev_unregister net/xfrm/xfrm_device.c:549 [inline]
xfrm_dev_event+0x1bc/0x3f0 net/xfrm/xfrm_device.c:570
notifier_call_chain+0x1be/0x400 kernel/notifier.c:85
call_netdevice_notifiers_extack net/core/dev.c:2281 [inline]
call_netdevice_notifiers net/core/dev.c:2295 [inline]
netdev_wait_allrefs_any net/core/dev.c:11589 [inline]
netdev_run_todo+0x778/0x1130 net/core/dev.c:11710
nsim_destroy+0x3ae/0x680 drivers/net/netdevsim/netdev.c:1190
__nsim_dev_port_del+0x14d/0x1b0 drivers/net/netdevsim/dev.c:1529
nsim_dev_port_del_all drivers/net/netdevsim/dev.c:1541 [inline]
nsim_dev_reload_destroy+0x288/0x490 drivers/net/netdevsim/dev.c:1765
nsim_drv_remove+0x58/0x170 drivers/net/netdevsim/dev.c:1780
device_remove drivers/base/dd.c:571 [inline]
__device_release_driver drivers/base/dd.c:1284 [inline]
device_release_driver_internal+0x46f/0x860 drivers/base/dd.c:1307
bus_remove_device+0x34d/0x440 drivers/base/bus.c:616
device_del+0x527/0x8f0 drivers/base/core.c:3878
device_unregister+0x21/0xf0 drivers/base/core.c:3919
nsim_bus_dev_del drivers/net/netdevsim/bus.c:491 [inline]
del_device_store+0x2b0/0x370 drivers/net/netdevsim/bus.c:244
kernfs_fop_write_iter+0x3af/0x540 fs/kernfs/file.c:352
new_sync_write fs/read_write.c:595 [inline]
vfs_write+0x61d/0xb90 fs/read_write.c:688
ksys_write+0x150/0x270 fs/read_write.c:740
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fd13375b78e
Code: 08 0f 85 a5 a8 ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 80 00 00 00 00 48 83 ec 08
RSP: 002b:00007ffc52b936a8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000555567157500 RCX: 00007fd13375b78e
RDX: 0000000000000001 RSI: 00007ffc52b93730 RDI: 0000000000000005
RBP: 00007fd133808a88 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000001
R13: 00007ffc52b93730 R14: 00007fd134544620 R15: 0000000000000003
</TASK>
----------
>
>> For example, we don't check permission for unmount when a mount is deleted
>> due to teardown of a mount namespace. I wonder why you want to check permission
>> for unregistering a net_device when triggered by a teardown path.
>
> I just try to find out what's the right thing to do here.
> If a policy goes away, packets that match this policy will
> find another path through the network stack. As best, they
> are dropped somewhere, but they can also leave on some other
> device without encryption. A LSM that implements xfrm hooks
> must be able to check the permission to delete the xfrm policy
> or state.
Do you mean that calling xfrm_dev_down()/xfrm_dev_unregister() might
result in network traffic to be sent in cleartext ?
If yes, we need to consider updating the other patch at
https://lkml.kernel.org/r/20260202123655.GK34749@unreal to replace
the NETDEV_UNREGISTER net_device with the blackhole_netdev. (That is,
xfrm_dev_{state,policy}_flush() does not actually delete a state/policy
but instead updates that state/policy to behave as a blackhole. Then,
we won't need to call LSM hooks because we no longer delete).
Also, we need to consider changing xfrm_dev_down() to no-op, for just doing
e.g. "ip link set ens160 down; ip link set ens160 up" (which triggers
NETDEV_DOWN event and NETDEV_UP event) might result in network traffic
to be sent in cleartext because currently xfrm_dev_down() can delete a
state/policy. Such behavior might not what the administrator is expecting.
>
>>
>>>
>>> The same happened btw. when xfrm was made per network namespace.
>>> Here we just leak the xfrm states and xfrm policies if some
>>> LSM refuses to remove them.
>>>
>>> I guess we need a solution for both cases.
>>
>> Is replacing the NETDEV_UNREGISTER net_device with the blackhole_netdev applicable
>> ( https://elixir.bootlin.com/linux/v6.19-rc5/source/net/xfrm/xfrm_policy.c#L3948 ) ?
>> If no, there is no choice but break SELinux's expectation.
>
> That could be an option to not accidentally send out
> unencrypted packets. But finding the right place for
> these checks would be preferable IMO.
Can we have such giant lock if you found the right place for these checks
( https://lkml.kernel.org/r/f9b88268-03dc-4356-8b31-0bab73cc9b1e@I-love.SAKURA.ne.jp ) ?
^ permalink raw reply
* Re: [PATCH 1/5] export file_close_fd and task_work_add
From: Lorenzo Stoakes @ 2026-02-09 15:21 UTC (permalink / raw)
To: Alice Ryhl
Cc: Greg Kroah-Hartman, Carlos Llamas, Alexander Viro,
Christian Brauner, Jan Kara, Paul Moore, James Morris,
Serge E. Hallyn, Andrew Morton, Dave Chinner, Qi Zheng,
Roman Gushchin, Muchun Song, David Hildenbrand, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
kernel-team, linux-fsdevel, linux-kernel, linux-security-module,
linux-mm, rust-for-linux
In-Reply-To: <aYSfBJA4hR4shPfI@google.com>
On Thu, Feb 05, 2026 at 01:45:40PM +0000, Alice Ryhl wrote:
> On Thu, Feb 05, 2026 at 11:53:19AM +0000, Lorenzo Stoakes wrote:
> > On Thu, Feb 05, 2026 at 11:42:46AM +0000, Alice Ryhl wrote:
> > > On Thu, Feb 05, 2026 at 11:20:33AM +0000, Lorenzo Stoakes wrote:
> > > > On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote:
> > > > > This exports the functionality needed by Binder to close file
> > > > > descriptors.
> > > > >
> > > > > When you send a fd over Binder, what happens is this:
> > > > >
> > > > > 1. The sending process turns the fd into a struct file and stores it in
> > > > > the transaction object.
> > > > > 2. When the receiving process gets the message, the fd is installed as a
> > > > > fd into the current process.
> > > > > 3. When the receiving process is done handling the message, it tells
> > > > > Binder to clean up the transaction. As part of this, fds embedded in
> > > > > the transaction are closed.
> > > > >
> > > > > Note that it was not always implemented like this. Previously the
> > > > > sending process would install the fd directly into the receiving proc in
> > > > > step 1, but as discussed previously [1] this is not ideal and has since
> > > > > been changed so that fd install happens during receive.
> > > > >
> > > > > The functions being exported here are for closing the fd in step 3. They
> > > > > are required because closing a fd from an ioctl is in general not safe.
> > > > > This is to meet the requirements for using fdget(), which is used by the
> > > > > ioctl framework code before calling into the driver's implementation of
> > > > > the ioctl. Binder works around this with this sequence of operations:
> > > > >
> > > > > 1. file_close_fd()
> > > > > 2. get_file()
> > > > > 3. filp_close()
> > > > > 4. task_work_add(current, TWA_RESUME)
> > > > > 5. <binder returns from ioctl>
> > > > > 6. fput()
> > > > >
> > > > > This ensures that when fput() is called in the task work, the fdget()
> > > > > that the ioctl framework code uses has already been fdput(), so if the
> > > > > fd being closed happens to be the same fd, then the fd is not closed
> > > > > in violation of the fdget() rules.
> > > >
> > > > I'm not really familiar with this mechanism but you're already talking about
> > > > this being a workaround so strikes me the correct thing to do is to find a way
> > > > to do this in the kernel sensibly rather than exporting internal implementation
> > > > details and doing it in binder.
> > >
> > > I did previously submit a patch that implemented this logic outside of
> > > Binder, but I was advised to move it into Binder.
> >
> > Right yeah that's just odd to me, we really do not want to be adding internal
> > implementation details to drivers.
> >
> > This is based on bitter experience of bugs being caused by drivers abusing every
> > interface they get, which is basically exactly what always happens, sadly.
> >
> > And out-of-tree is heavily discouraged.
> >
> > Also can we use EXPORT_SYMBOL_FOR_MODULES() for anything we do need to export to
> > make it explicitly only for binder, perhaps?
> >
> > >
> > > But I'm happy to submit a patch to extract this logic into some sort of
> > > close_fd_safe() method that can be called even if said fd is currently
> > > held using fdget().
> >
> > Yup, especially given Christian's view on the kernel task export here I think
> > that's a more sensible approach.
> >
> > But obviously I defer the sensible-ness of this to him as I am but an mm dev :)
>
> Quick sketch of how this would look:
>
> diff --git a/drivers/android/binder.c b/drivers/android/binder.c
> index adde1e40cccd..6fb7175ff69b 100644
> --- a/drivers/android/binder.c
> +++ b/drivers/android/binder.c
> @@ -64,7 +64,6 @@
> #include <linux/spinlock.h>
> #include <linux/ratelimit.h>
> #include <linux/syscalls.h>
> -#include <linux/task_work.h>
> #include <linux/sizes.h>
> #include <linux/ktime.h>
>
> @@ -1962,68 +1961,6 @@ static bool binder_validate_fixup(struct binder_proc *proc,
> return (fixup_offset >= last_min_offset);
> }
>
> -/**
> - * struct binder_task_work_cb - for deferred close
> - *
> - * @twork: callback_head for task work
> - * @file: file to close
> - *
> - * Structure to pass task work to be handled after
> - * returning from binder_ioctl() via task_work_add().
> - */
> -struct binder_task_work_cb {
> - struct callback_head twork;
> - struct file *file;
> -};
> -
> -/**
> - * binder_do_fd_close() - close list of file descriptors
> - * @twork: callback head for task work
> - *
> - * It is not safe to call ksys_close() during the binder_ioctl()
> - * function if there is a chance that binder's own file descriptor
> - * might be closed. This is to meet the requirements for using
> - * fdget() (see comments for __fget_light()). Therefore use
> - * task_work_add() to schedule the close operation once we have
> - * returned from binder_ioctl(). This function is a callback
> - * for that mechanism and does the actual ksys_close() on the
> - * given file descriptor.
> - */
> -static void binder_do_fd_close(struct callback_head *twork)
> -{
> - struct binder_task_work_cb *twcb = container_of(twork,
> - struct binder_task_work_cb, twork);
> -
> - fput(twcb->file);
> - kfree(twcb);
> -}
> -
> -/**
> - * binder_deferred_fd_close() - schedule a close for the given file-descriptor
> - * @fd: file-descriptor to close
> - *
> - * See comments in binder_do_fd_close(). This function is used to schedule
> - * a file-descriptor to be closed after returning from binder_ioctl().
> - */
> -static void binder_deferred_fd_close(int fd)
> -{
> - struct binder_task_work_cb *twcb;
> -
> - twcb = kzalloc(sizeof(*twcb), GFP_KERNEL);
> - if (!twcb)
> - return;
> - init_task_work(&twcb->twork, binder_do_fd_close);
> - twcb->file = file_close_fd(fd);
> - if (twcb->file) {
> - // pin it until binder_do_fd_close(); see comments there
> - get_file(twcb->file);
> - filp_close(twcb->file, current->files);
> - task_work_add(current, &twcb->twork, TWA_RESUME);
> - } else {
> - kfree(twcb);
> - }
> -}
> -
> static void binder_transaction_buffer_release(struct binder_proc *proc,
> struct binder_thread *thread,
> struct binder_buffer *buffer,
> @@ -2183,7 +2120,10 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
> offset, sizeof(fd));
> WARN_ON(err);
> if (!err) {
> - binder_deferred_fd_close(fd);
> + /*
> + * Intentionally ignore EBADF errors here.
> + */
> + close_fd_safe(fd, GFP_KERNEL | __GFP_NOFAIL);
> /*
> * Need to make sure the thread goes
> * back to userspace to complete the
> diff --git a/fs/file.c b/fs/file.c
> index 0a4f3bdb2dec..58e3825e846c 100644
> --- a/fs/file.c
> +++ b/fs/file.c
> @@ -21,6 +21,7 @@
> #include <linux/rcupdate.h>
> #include <linux/close_range.h>
> #include <linux/file_ref.h>
> +#include <linux/task_work.h>
> #include <net/sock.h>
> #include <linux/init_task.h>
>
> @@ -1525,3 +1526,47 @@ int iterate_fd(struct files_struct *files, unsigned n,
> return res;
> }
> EXPORT_SYMBOL(iterate_fd);
> +
> +struct close_fd_safe_task_work {
> + struct callback_head twork;
> + struct file *file;
> +};
> +
> +static void close_fd_safe_callback(struct callback_head *twork)
> +{
> + struct close_fd_safe_task_work *twcb = container_of(twork,
> + struct close_fd_safe_task_work, twork);
> +
> + fput(twcb->file);
> + kfree(twcb);
> +}
> +
> +/**
> + * close_fd_safe - close the given fd
> + * @fd: file descriptor to close
> + * @flags: gfp flags for allocation of task work
> + *
> + * This closes an fd. Unlike close_fd(), this may be used even if the fd is
> + * currently held with fdget().
> + *
> + * Returns: 0 or an error code
> + */
> +int close_fd_safe(unsigned int fd, gfp_t flags)
> +{
> + struct close_fd_safe_task_work *twcb;
> +
> + twcb = kzalloc(sizeof(*twcb), flags);
> + if (!twcb)
> + return -ENOMEM;
> + init_task_work(&twcb->twork, close_fd_safe_callback);
> + twcb->file = file_close_fd(fd);
> + if (!twcb->file) {
> + kfree(twcb);
> + return -EBADF;
> + }
> +
> + get_file(twcb->file);
> + filp_close(twcb->file, current->files);
> + task_work_add(current, &twcb->twork, TWA_RESUME);
> + return 0;
> +}
Would need an EXPORT_SYMBOL_FOR_MODULES(...) here right?
> diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
> index c45306a9f007..1c99a56c0cdf 100644
> --- a/include/linux/fdtable.h
> +++ b/include/linux/fdtable.h
> @@ -111,6 +111,7 @@ int iterate_fd(struct files_struct *, unsigned,
> const void *);
>
> extern int close_fd(unsigned int fd);
> +extern int close_fd_safe(unsigned int fd, gfp_t flags);
One nit, generally well in mm anyway we avoid the 'extern' and remove them as we
go. Not sure about vfs actually though?
> extern struct file *file_close_fd(unsigned int fd);
>
> extern struct kmem_cache *files_cachep;
I mean this is essentially taking what's in binder and making it a general
thing, so needs Christian's input on whether this is sensible I think :)
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH 3/5] mm: export zap_page_range_single and list_lru_add/del
From: Lorenzo Stoakes @ 2026-02-09 15:22 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Alice Ryhl, Greg Kroah-Hartman, Carlos Llamas, Alexander Viro,
Christian Brauner, Jan Kara, Paul Moore, James Morris,
Serge E. Hallyn, Andrew Morton, Dave Chinner, Qi Zheng,
Roman Gushchin, Muchun Song, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, Danilo Krummrich, kernel-team,
linux-fsdevel, linux-kernel, linux-security-module, linux-mm,
rust-for-linux
In-Reply-To: <ba5cb90a-cd4f-496e-a665-cc323ec598ab@kernel.org>
On Thu, Feb 05, 2026 at 01:30:16PM +0100, David Hildenbrand (Arm) wrote:
> On 2/5/26 13:24, Lorenzo Stoakes wrote:
> > On Thu, Feb 05, 2026 at 12:19:22PM +0000, Alice Ryhl wrote:
> > > On Thu, Feb 05, 2026 at 01:13:57PM +0100, David Hildenbrand (arm) wrote:
> > > >
> > > > Could Rust just use zap_vma_ptes() or does it want to zap things in VMAs
> > > > that are not VM_PFNMAP?
> > >
> > > The VMA is VM_MIXEDMAP, not VM_PFNMAP.
> >
> > OK this smells like David's cleanup could extend it to allow for
> > VM_MIXEDMAP :) then we solve the export problem.
>
> My thinking ... and while at it, gonna remove these functions to make them a
> bit more ... consistent in naming.
Sounds good :)
>
> --
> Cheers,
>
> David
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH v3 1/5] lsm: Add hook security_unix_find
From: Paul Moore @ 2026-02-09 17:09 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, Tingmao Wang,
Mickaël Salaün, James Morris, Serge E . Hallyn,
Justin Suess, linux-security-module, Samasth Norway Ananda,
Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
Demi Marie Obenour, Alyssa Ross, Jann Horn, Tahera Fahimi,
Simon Horman, netdev, Alexander Viro, Christian Brauner
In-Reply-To: <aYMenaSmBkAsFowd@google.com>
On Wed, Feb 4, 2026 at 5:25 AM Günther Noack <gnoack@google.com> wrote:
>
> Paul:
>
> You have previously said that you would like hooks to be generic and
> ideally reflect the arguments of the same function that they are
> called from [3].
To clarify, I didn't say that it is generally ideal for the LSM hook
to reflect the arguments of the calling function; while that might be
a good starting point, we have plenty of examples where that is not
desirable. In this particular case I said it seems like it would be a
good idea to pass the "type" and "flags" parameters from the caller to
the LSM hook.
> Q: Would it be acceptable to change the hook arguments, if we can then
> avoid passing additional data between hooks through that side-storage?
If you're passing the sock, I think we can skip passing the type,
however, I could envision someone wanting the path in addition to just
the sock, but let's wait to hear back from the AppArmor folks.
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH] landlock: Add counted_by and fix comment in landlock_ruleset
From: Mickaël Salaün @ 2026-02-09 17:28 UTC (permalink / raw)
To: Tingmao Wang; +Cc: Günther Noack, linux-security-module
In-Reply-To: <20260208235449.1124354-1-m@maowtm.org>
Thanks!
On Sun, Feb 08, 2026 at 11:54:48PM +0000, Tingmao Wang wrote:
> For a domain, this array stores the access masks for each layer (of
> which there are num_layers of them). For an unmerged ruleset, we have
> one "layer", and one element in this array. This annotation serves as
> useful documentation.
>
> This also removes a comment saying that num_layers = 0 for unmerged
> rulesets, which is incorrect (it is 1).
>
> Signed-off-by: Tingmao Wang <m@maowtm.org>
> ---
>
> I'm not sure if I should add a Fixes tag, but if I should had, it would
> be ae271c1b14 ("landlock: Add ruleset and domain management").
>
> security/landlock/ruleset.h | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 9d6dc632684c..7005840ac641 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -168,8 +168,7 @@ struct landlock_ruleset {
> /**
> * @num_layers: Number of layers that are used in this
> * ruleset. This enables to check that all the layers
> - * allow an access request. A value of 0 identifies a
> - * non-merged ruleset (i.e. not a domain).
> + * allow an access request.
> */
> u32 num_layers;
> /**
> @@ -184,7 +183,8 @@ struct landlock_ruleset {
> * layers are set once and never changed for the
> * lifetime of the ruleset.
> */
> - struct access_masks access_masks[];
> + struct access_masks
> + access_masks[] __counted_by(num_layers);
> };
> };
> };
>
> base-commit: f179e1859c711214412876c57f56f9b0cfb13264
> --
> 2.53.0
>
^ permalink raw reply
* Re: [PATCH v4 4/6] landlock/selftests: Test named UNIX domain socket restrictions
From: Mickaël Salaün @ 2026-02-09 17:29 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, Justin Suess, linux-security-module, Tingmao Wang,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi
In-Reply-To: <20260208231017.114343-5-gnoack3000@gmail.com>
On Mon, Feb 09, 2026 at 12:10:14AM +0100, Günther Noack wrote:
> * Exercise the access right for connect() and sendmsg() on named UNIX
> domain sockets, in various combinations of Landlock domains and
> socket types.
> * Extract common helpers from an existing IOCTL test that
> also uses pathname unix(7) sockets.
>
> The tested combinations are the cross product of these sets of fixture
> fields:
>
> * {{.handled=RESOLVE_UNIX},
> {.handled=RESOLVE_UNIX, .allowed=RESOLVE_UNIX}}
> * {{.sock_type=SOCK_STREAM},
> {.sock_type=SOCK_DGRAM},
> {.sock_type=SOCK_DGRAM, .use_sendto=true},
> {.sock_type=SOCK_SEQPACKET}}
> * {{.server_in_same_domain=false},
> {.server_in_same_domain=true}}
It would improve test clarity to follow the same approach as Tingmao to
check the scope, especially to use the scoped_base_variant.h:
https://lore.kernel.org/all/88de5bed60b06ba97088d87803f7bb3dbcc9a808.1767115163.git.m@maowtm.org/
Even if there is no more explicit scoped flag anymore, this test suite
is still relevant.
The fs_test.c part would then mostly check the
LANDLOCK_ACCESS_FS_RESOLVE_UNIX rules/exceptions.
>
> Some additional fixtures exercise scenarios with two nested domains.
>
> Cc: Justin Suess <utilityemal77@gmail.com>
> Cc: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
> tools/testing/selftests/landlock/fs_test.c | 381 ++++++++++++++++++++-
> 1 file changed, 365 insertions(+), 16 deletions(-)
>
> diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
> index b318627e7561..9d3f5dab4567 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -4358,30 +4358,61 @@ TEST_F_FORK(layout1, named_pipe_ioctl)
> ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0));
> }
>
> +/*
> + * set_up_named_unix_server - Create a pathname unix socket
> + *
> + * If the socket type is not SOCK_DGRAM, also invoke listen(2).
> + *
> + * Return: The listening FD - it is the caller responsibility to close it.
> + */
> +static int set_up_named_unix_server(struct __test_metadata *const _metadata,
> + int type, const char *const path)
> +{
> + int fd;
> + struct sockaddr_un addr = {
> + .sun_family = AF_UNIX,
> + };
> +
> + fd = socket(AF_UNIX, type, 0);
> + ASSERT_LE(0, fd);
> +
> + strncpy(addr.sun_path, path, sizeof(addr.sun_path));
> + ASSERT_EQ(0, bind(fd, (struct sockaddr *)&addr, sizeof(addr)));
> +
> + if (type != SOCK_DGRAM)
> + ASSERT_EQ(0, listen(fd, 10 /* qlen */));
> + return fd;
> +}
> +
> +/*
> + * test_connect_named_unix - connect to the given named UNIX socket
> + *
> + * Return: The errno from connect(), or 0
> + */
> +static int test_connect_named_unix(int fd, const char *const path)
> +{
> + struct sockaddr_un addr = {
> + .sun_family = AF_UNIX,
> + };
> + strncpy(addr.sun_path, path, sizeof(addr.sun_path));
> +
> + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
> + return errno;
> + return 0;
> +}
> +
> /* For named UNIX domain sockets, no IOCTL restrictions apply. */
> TEST_F_FORK(layout1, named_unix_domain_socket_ioctl)
> {
> const char *const path = file1_s1d1;
> int srv_fd, cli_fd, ruleset_fd;
> - struct sockaddr_un srv_un = {
> - .sun_family = AF_UNIX,
> - };
> - struct sockaddr_un cli_un = {
> - .sun_family = AF_UNIX,
> - };
> const struct landlock_ruleset_attr attr = {
> .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
> };
>
> /* Sets up a server */
> ASSERT_EQ(0, unlink(path));
> - srv_fd = socket(AF_UNIX, SOCK_STREAM, 0);
> - ASSERT_LE(0, srv_fd);
> -
> - strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path));
> - ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, sizeof(srv_un)));
> -
> - ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */));
> + srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, path);
>
> /* Enables Landlock. */
> ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
> @@ -4393,9 +4424,7 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl)
> cli_fd = socket(AF_UNIX, SOCK_STREAM, 0);
> ASSERT_LE(0, cli_fd);
>
> - strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path));
> - ASSERT_EQ(0,
> - connect(cli_fd, (struct sockaddr *)&cli_un, sizeof(cli_un)));
> + ASSERT_EQ(0, test_connect_named_unix(cli_fd, path));
>
> /* FIONREAD and other IOCTLs should not be forbidden. */
> EXPECT_EQ(0, test_fionread_ioctl(cli_fd));
> @@ -4570,6 +4599,326 @@ TEST_F_FORK(ioctl, handle_file_access_file)
> ASSERT_EQ(0, close(file_fd));
> }
>
> +/* clang-format off */
> +FIXTURE(unix_socket) {};
> +
> +FIXTURE_SETUP(unix_socket) {};
> +
> +FIXTURE_TEARDOWN(unix_socket) {};
> +/* clang-format on */
> +
> +FIXTURE_VARIANT(unix_socket)
> +{
> + const __u64 handled;
> + const __u64 allowed;
> + const __u64 handled2;
> + const __u64 allowed2;
> + const int sock_type;
> + const int expected;
> + const bool use_sendto;
> + const bool server_in_same_domain;
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_handled_not_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_STREAM,
> + .expected = EACCES,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_handled_and_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_STREAM,
> + .expected = 0,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_not_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_DGRAM,
> + .expected = EACCES,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_and_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_DGRAM,
> + .expected = 0,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_not_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_DGRAM,
> + .use_sendto = true,
> + .expected = EACCES,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_and_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_DGRAM,
> + .use_sendto = true,
> + .expected = 0,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_not_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_SEQPACKET,
> + .expected = EACCES,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_and_allowed)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_SEQPACKET,
> + .expected = 0,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_handled_not_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_STREAM,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_handled_and_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_STREAM,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_not_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_DGRAM,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_and_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_DGRAM,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_not_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_DGRAM,
> + .use_sendto = true,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_and_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_DGRAM,
> + .use_sendto = true,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_not_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .sock_type = SOCK_SEQPACKET,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_and_allowed_and_same_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_SEQPACKET,
> + .expected = 0,
> + .server_in_same_domain = true,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_scope_path)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .server_in_same_domain = true,
> + .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_STREAM,
> + .expected = 0,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_path_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .server_in_same_domain = true,
> + .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed2 = 0,
> + .sock_type = SOCK_STREAM,
> + .expected = EACCES,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_scope_scope)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = 0,
> + .server_in_same_domain = true,
> + .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed2 = 0,
> + .sock_type = SOCK_STREAM,
> + .expected = EACCES,
> +};
> +
> +/* clang-format off */
> +FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_path_path)
> +{
> + /* clang-format on */
> + .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .server_in_same_domain = true,
> + .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .allowed2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> + .sock_type = SOCK_STREAM,
> + .expected = 0,
> +};
> +
> +/*
> + * test_sendto_named_unix - sendto to the given named UNIX socket
> + *
> + * sendto() is equivalent to sendmsg() in this respect.
> + *
> + * Return: The errno from sendto(), or 0
> + */
> +static int test_sendto_named_unix(int fd, const char *const path)
> +{
> + static const char buf[] = "dummy";
> + struct sockaddr_un addr = {
> + .sun_family = AF_UNIX,
> + };
> + strncpy(addr.sun_path, path, sizeof(addr.sun_path));
> +
> + if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&addr,
> + sizeof(addr)) == -1)
> + return errno;
> + return 0;
> +}
> +
> +TEST_F_FORK(unix_socket, test)
> +{
> + const char *const path = "sock";
> + int cli_fd, srv_fd, ruleset_fd, res;
> + struct rule rules[] = {
> + {
> + .path = ".",
> + .access = variant->allowed,
> + },
> + {},
> + };
> +
> + /* Sets up a server (in the case where the server is in the parent domain) */
> + if (!variant->server_in_same_domain)
> + srv_fd = set_up_named_unix_server(_metadata, variant->sock_type,
> + path);
> +
> + /* Enables Landlock. */
> + ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
> + ASSERT_LE(0, ruleset_fd);
> + enforce_ruleset(_metadata, ruleset_fd);
> + ASSERT_EQ(0, close(ruleset_fd));
> +
> + /* Sets up a server (in the case where the server is in the same domain) */
> + if (variant->server_in_same_domain)
> + srv_fd = set_up_named_unix_server(_metadata, variant->sock_type,
> + path);
> +
> + if (variant->handled2) {
> + /* Enables Landlock another time, if needed. */
> + rules[0].access = variant->allowed2;
> + ruleset_fd =
> + create_ruleset(_metadata, variant->handled2, rules);
> + ASSERT_LE(0, ruleset_fd);
> + enforce_ruleset(_metadata, ruleset_fd);
> + ASSERT_EQ(0, close(ruleset_fd));
> + }
> +
> + /* Sets up a client connection to it */
> + cli_fd = socket(AF_UNIX, variant->sock_type, 0);
> + ASSERT_LE(0, cli_fd);
> +
> + /* Connecting or sendto to the Unix socket is denied. */
> + if (variant->use_sendto)
> + res = test_sendto_named_unix(cli_fd, path);
> + else
> + res = test_connect_named_unix(cli_fd, path);
> + EXPECT_EQ(variant->expected, res);
> +
> + /* Clean up. */
> + EXPECT_EQ(0, close(cli_fd));
> + EXPECT_EQ(0, close(srv_fd));
> + EXPECT_EQ(0, unlink(path));
> +}
> +
> /* clang-format off */
> FIXTURE(layout1_bind) {};
> /* clang-format on */
> --
> 2.52.0
>
>
^ permalink raw reply
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-02-09 17:28 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, Tingmao Wang, Justin Suess,
Jann Horn, linux-security-module, Samasth Norway Ananda,
Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
Demi Marie Obenour, Alyssa Ross, Tahera Fahimi
In-Reply-To: <aYm1RWtV6Af-zEHf@google.com>
On Mon, Feb 09, 2026 at 11:21:57AM +0100, Günther Noack wrote:
> On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> > +static int hook_unix_find(const struct path *const path, struct sock *other,
> > + int flags)
> > +{
> > + const struct landlock_ruleset *dom_other;
> > + const struct landlock_cred_security *subject;
> > + struct layer_access_masks layer_masks;
> > + struct landlock_request request = {};
> > + static const struct access_masks fs_resolve_unix = {
> > + .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> > + };
> > + int type = other->sk_type;
> > +
> > + /* Lookup for the purpose of saving coredumps is OK. */
> > + if (flags & SOCK_COREDUMP)
> > + return 0;
> > +
> > + /* Only stream, dgram and seqpacket sockets are restricted. */
> > + if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
> > + return 0;
>
> FYI: This is a (highly speculative) safeguard, because these three
> socket types are the only ones that exist in AF_UNIX (compare unix(7),
> 2nd paragraph).
>
> In the (highly unlikely) case that someone adds a fourth AF_UNIX
> socket type, this means that Landlock will start permitting
> connections to these sockets unconditionally.
>
> I am unsure whether the safeguard is useful, or whether we should
> rather group that (highly unlikely) future socket type together with
> the existing ones. *If you have opinions, I'd be interested.*
>
> The fact that these are the only existing AF_UNIX socket types is also
> the reason why it does not matter that we are now (in v4) taking the
> type value from the server-side sk instead of the client socket. The
> check will either way always pass as long as only these three types
> are the only ones.
>
> For now (and probably for another few decades :)), as long as these
> are the only AF_UNIX types, it does not make a difference though
> whether the check is there or not.
You can remove these type checks. We're building Landlock access
control wrt to the (moving) current state of Linux, and the goal is to
cover most/useful access types that currently make sense. Once access
type is implemented, it should handle (by default) future features
related to the kernel object to make sure a sandbox is well covered.
This LANDLOCK_ACCESS_FS_RESOLVE_UNIX right is really about UNIX sockets
that can be resolved through the filesystem, so this should handle
current and potential future UNIX sockets as well.
If a new named UNIX socket type is created, Landlock should handle that
with this access right, unless there is a specific semantic (e.g.
coredump), in which case we'll update the access right, and potentially
add a new one if it makes sense.
I was thinking about calling WARN_ON_ONCE() but this is not worth it.
^ permalink raw reply
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
From: Mickaël Salaün @ 2026-02-09 17:51 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
Tingmao Wang, Justin Suess, linux-security-module,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi, Simon Horman, netdev, Alexander Viro,
Christian Brauner
In-Reply-To: <20260208231017.114343-2-gnoack3000@gmail.com>
On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
> From: Justin Suess <utilityemal77@gmail.com>
>
> Add a LSM hook security_unix_find.
>
> This hook is called to check the path of a named unix socket before a
> connection is initiated. The peer socket may be inspected as well.
>
> Why existing hooks are unsuitable:
>
> Existing socket hooks, security_unix_stream_connect(),
> security_unix_may_send(), and security_socket_connect() don't provide
> TOCTOU-free / namespace independent access to the paths of sockets.
>
> (1) We cannot resolve the path from the struct sockaddr in existing hooks.
> This requires another path lookup. A change in the path between the
> two lookups will cause a TOCTOU bug.
>
> (2) We cannot use the struct path from the listening socket, because it
> may be bound to a path in a different namespace than the caller,
> resulting in a path that cannot be referenced at policy creation time.
>
> Cc: Günther Noack <gnoack3000@gmail.com>
> Cc: Tingmao Wang <m@maowtm.org>
> Signed-off-by: Justin Suess <utilityemal77@gmail.com>
> ---
> include/linux/lsm_hook_defs.h | 5 +++++
> include/linux/security.h | 11 +++++++++++
> net/unix/af_unix.c | 9 +++++++++
> security/security.c | 20 ++++++++++++++++++++
> 4 files changed, 45 insertions(+)
>
> diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
> index 8c42b4bde09c..7a0fd3dbfa29 100644
> --- a/include/linux/lsm_hook_defs.h
> +++ b/include/linux/lsm_hook_defs.h
> @@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
> LSM_HOOK(int, 0, watch_key, struct key *key)
> #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
> + int flags)
> +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
> #ifdef CONFIG_SECURITY_NETWORK
> LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
> struct sock *newsk)
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 83a646d72f6f..99a33d8eb28d 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
> }
> #endif /* CONFIG_SECURITY_NETWORK */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +
> +int security_unix_find(const struct path *path, struct sock *other, int flags);
> +
> +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
> +{
> + return 0;
> +}
> +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
> #ifdef CONFIG_SECURITY_INFINIBAND
> int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
> int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index d0511225799b..db9d279b3883 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -1226,10 +1226,19 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
> if (!S_ISSOCK(inode->i_mode))
> goto path_put;
>
> + err = -ECONNREFUSED;
We don't see it in this patch but err is already set to -ECONNREFUSED.
This line might be confusing, and unrelated to the goal of this patch,
so we should remove it.
> sk = unix_find_socket_byinode(inode);
> if (!sk)
> goto path_put;
>
> + /*
> + * We call the hook because we know that the inode is a socket
> + * and we hold a valid reference to it via the path.
This comment can be alligned with 80 columns.
> + */
> + err = security_unix_find(&path, sk, flags);
This hook makes sense and is quite generic.
> + if (err)
> + goto sock_put;
> +
> err = -EPROTOTYPE;
> if (sk->sk_type == type)
> touch_atime(&path);
> diff --git a/security/security.c b/security/security.c
> index 31a688650601..9e9515955098 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
>
> #endif /* CONFIG_SECURITY_NETWORK */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +/*
This should be a docstring like other hooks: /**
> + * security_unix_find() - Check if a named AF_UNIX socket can connect
> + * @path: path of the socket being connected to
> + * @other: peer sock
> + * @flags: flags associated with the socket
> + *
> + * This hook is called to check permissions before connecting to a named
> + * AF_UNIX socket.
> + *
> + * Return: Returns 0 if permission is granted.
> + */
> +int security_unix_find(const struct path *path, struct sock *other, int flags)
> +{
> + return call_int_hook(unix_find, path, other, flags);
> +}
> +EXPORT_SYMBOL(security_unix_find);
> +
> +#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
> #ifdef CONFIG_SECURITY_INFINIBAND
> /**
> * security_ib_pkey_access() - Check if access to an IB pkey is allowed
> --
> 2.52.0
>
>
^ permalink raw reply
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
From: Mickaël Salaün @ 2026-02-09 18:03 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, Tingmao Wang, Justin Suess,
Jann Horn, linux-security-module, Samasth Norway Ananda,
Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
Demi Marie Obenour, Alyssa Ross, Tahera Fahimi
In-Reply-To: <aYm1RWtV6Af-zEHf@google.com>
On Mon, Feb 09, 2026 at 11:21:57AM +0100, Günther Noack wrote:
> On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> > +static int hook_unix_find(const struct path *const path, struct sock *other,
> > + int flags)
> > +{
> > + const struct landlock_ruleset *dom_other;
> > + const struct landlock_cred_security *subject;
> > + struct layer_access_masks layer_masks;
> > + struct landlock_request request = {};
> > + static const struct access_masks fs_resolve_unix = {
> > + .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> > + };
> > + int type = other->sk_type;
> > +
> > + /* Lookup for the purpose of saving coredumps is OK. */
> > + if (flags & SOCK_COREDUMP)
> > + return 0;
We should test this case too.
tools/testing/selftests/coredump/coredump_socket_* should help.
> > +
> > + /* Only stream, dgram and seqpacket sockets are restricted. */
> > + if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
> > + return 0;
^ permalink raw reply
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
From: Tingmao Wang @ 2026-02-09 18:33 UTC (permalink / raw)
To: Mickaël Salaün, Justin Suess, Günther Noack
Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi, Simon Horman, netdev,
Alexander Viro, Christian Brauner
In-Reply-To: <20260209.yeeh3ieDuz9u@digikod.net>
On 2/9/26 17:51, Mickaël Salaün wrote:
> On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
>> [...]
>> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
>> index d0511225799b..db9d279b3883 100644
>> --- a/net/unix/af_unix.c
>> +++ b/net/unix/af_unix.c
>> @@ -1226,10 +1226,19 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
>> if (!S_ISSOCK(inode->i_mode))
>> goto path_put;
>>
>> + err = -ECONNREFUSED;
>
> We don't see it in this patch but err is already set to -ECONNREFUSED.
> This line might be confusing, and unrelated to the goal of this patch,
> so we should remove it.
I will confess that in a side conversation with Justin previously I
suggested that for blocks like these it might be better to always assign
to err, and let the compiler optimize it away, so that when this block is
moved there is less chances of mistake. (This was relevant in the
previous context where a move of this hook caused err to be reset,
resulting in a NULL deference from syzbot)
But of course if the convention in this file is to not do it, or if I have
missed some reason against doing this, then that's also fine (even though,
IMHO, personally I think this is better).
^ permalink raw reply
* Re: [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t
From: Liam R. Howlett @ 2026-02-09 18:38 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <64fa89f416f22a60ae74cfff8fd565e7677be192.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> We need to pass around these values and access them in a way that sparse
> does not allow, as __private implies noderef, i.e. disallowing dereference
> of the value, which manifests as sparse warnings even when passed around
> benignly.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 4 ++--
> include/linux/mm_types.h | 14 ++++++++------
> 2 files changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index d7ca837dd8a5..776a7e03f88b 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -943,7 +943,7 @@ static inline void vm_flags_reset_once(struct vm_area_struct *vma,
> * system word.
> */
> if (NUM_VMA_FLAG_BITS > BITS_PER_LONG) {
> - unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
> + unsigned long *bitmap = vma->flags.__vma_flags;
>
> bitmap_zero(&bitmap[1], NUM_VMA_FLAG_BITS - BITS_PER_LONG);
> }
> @@ -1006,7 +1006,7 @@ static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
> static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
> vma_flag_t bit)
> {
> - unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
> + unsigned long *bitmap = vma->flags.__vma_flags;
>
> vma_assert_stabilised(vma);
> if (__vma_flag_atomic_valid(vma, bit))
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index e5ee66f84d9a..592ad065fa75 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -866,7 +866,7 @@ struct mmap_action {
> #define NUM_VMA_FLAG_BITS BITS_PER_LONG
> typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> -} __private vma_flags_t;
> +} vma_flags_t;
>
> /*
> * Describes a VMA that is about to be mmap()'ed. Drivers may choose to
> @@ -1056,7 +1056,7 @@ struct vm_area_struct {
> /* Clears all bits in the VMA flags bitmap, non-atomically. */
> static inline void vma_flags_clear_all(vma_flags_t *flags)
> {
> - bitmap_zero(ACCESS_PRIVATE(flags, __vma_flags), NUM_VMA_FLAG_BITS);
> + bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
> }
>
> /*
> @@ -1067,7 +1067,9 @@ static inline void vma_flags_clear_all(vma_flags_t *flags)
> */
> static inline void vma_flags_overwrite_word(vma_flags_t *flags, unsigned long value)
> {
> - *ACCESS_PRIVATE(flags, __vma_flags) = value;
> + unsigned long *bitmap = flags->__vma_flags;
> +
> + bitmap[0] = value;
> }
>
> /*
> @@ -1078,7 +1080,7 @@ static inline void vma_flags_overwrite_word(vma_flags_t *flags, unsigned long va
> */
> static inline void vma_flags_overwrite_word_once(vma_flags_t *flags, unsigned long value)
> {
> - unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
> + unsigned long *bitmap = flags->__vma_flags;
>
> WRITE_ONCE(*bitmap, value);
> }
> @@ -1086,7 +1088,7 @@ static inline void vma_flags_overwrite_word_once(vma_flags_t *flags, unsigned lo
> /* Update the first system word of VMA flags setting bits, non-atomically. */
> static inline void vma_flags_set_word(vma_flags_t *flags, unsigned long value)
> {
> - unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
> + unsigned long *bitmap = flags->__vma_flags;
>
> *bitmap |= value;
> }
> @@ -1094,7 +1096,7 @@ static inline void vma_flags_set_word(vma_flags_t *flags, unsigned long value)
> /* Update the first system word of VMA flags clearing bits, non-atomically. */
> static inline void vma_flags_clear_word(vma_flags_t *flags, unsigned long value)
> {
> - unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
> + unsigned long *bitmap = flags->__vma_flags;
>
> *bitmap &= ~value;
> }
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag()
From: Liam R. Howlett @ 2026-02-09 18:40 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <033dcf12e819dee5064582bced9b12ea346d1607.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> In order to stay consistent between functions which manipulate a vm_flags_t
> argument of the form of vma_flags_...() and those which manipulate a
> VMA (in this case the flags field of a VMA), rename
> vma_flag_[test/set]_atomic() to vma_[test/set]_atomic_flag().
>
> This lays the groundwork for adding VMA flag manipulation functions in a
> subsequent commit.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 13 +++++--------
> mm/khugepaged.c | 2 +-
> mm/madvise.c | 2 +-
> 3 files changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 776a7e03f88b..e0d31238097c 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -987,8 +987,7 @@ static inline void vm_flags_mod(struct vm_area_struct *vma,
> __vm_flags_mod(vma, set, clear);
> }
>
> -static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
> - vma_flag_t bit)
> +static inline bool __vma_atomic_valid_flag(struct vm_area_struct *vma, vma_flag_t bit)
> {
> const vm_flags_t mask = BIT((__force int)bit);
>
> @@ -1003,13 +1002,12 @@ static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
> * Set VMA flag atomically. Requires only VMA/mmap read lock. Only specific
> * valid flags are allowed to do this.
> */
> -static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
> - vma_flag_t bit)
> +static inline void vma_set_atomic_flag(struct vm_area_struct *vma, vma_flag_t bit)
> {
> unsigned long *bitmap = vma->flags.__vma_flags;
>
> vma_assert_stabilised(vma);
> - if (__vma_flag_atomic_valid(vma, bit))
> + if (__vma_atomic_valid_flag(vma, bit))
> set_bit((__force int)bit, bitmap);
> }
>
> @@ -1020,10 +1018,9 @@ static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
> * This is necessarily racey, so callers must ensure that serialisation is
> * achieved through some other means, or that races are permissible.
> */
> -static inline bool vma_flag_test_atomic(struct vm_area_struct *vma,
> - vma_flag_t bit)
> +static inline bool vma_test_atomic_flag(struct vm_area_struct *vma, vma_flag_t bit)
> {
> - if (__vma_flag_atomic_valid(vma, bit))
> + if (__vma_atomic_valid_flag(vma, bit))
> return test_bit((__force int)bit, &vma->vm_flags);
>
> return false;
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index fba6aea5bea6..e76f42243534 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -1741,7 +1741,7 @@ static bool file_backed_vma_is_retractable(struct vm_area_struct *vma)
> * obtained on guard region installation after the flag is set, so this
> * check being performed under this lock excludes races.
> */
> - if (vma_flag_test_atomic(vma, VMA_MAYBE_GUARD_BIT))
> + if (vma_test_atomic_flag(vma, VMA_MAYBE_GUARD_BIT))
> return false;
>
> return true;
> diff --git a/mm/madvise.c b/mm/madvise.c
> index 1f3040688f04..8debb2d434aa 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -1140,7 +1140,7 @@ static long madvise_guard_install(struct madvise_behavior *madv_behavior)
> * acquire an mmap/VMA write lock to read it. All remaining readers may
> * or may not see the flag set, but we don't care.
> */
> - vma_flag_set_atomic(vma, VMA_MAYBE_GUARD_BIT);
> + vma_set_atomic_flag(vma, VMA_MAYBE_GUARD_BIT);
>
> /*
> * If anonymous and we are establishing page tables the VMA ought to
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
From: Liam R. Howlett @ 2026-02-09 18:44 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <fde00df6ff7fb8c4b42cc0defa5a4924c7a1943a.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> This patch introduces the mk_vma_flags() macro helper to allow easy
> manipulation of VMA flags utilising the new bitmap representation
> implemented of VMA flags defined by the vma_flags_t type.
>
> It is a variadic macro which provides a bitwise-or'd representation of all
> of each individual VMA flag specified.
>
> Note that, while we maintain VM_xxx flags for backwards compatibility until
> the conversion is complete, we define VMA flags of type vma_flag_t using
> VMA_xxx_BIT to avoid confusing the two.
>
> This helper macro therefore can be used thusly:
>
> vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
>
> We allow for up to 5 flags to specified at a time which should accommodate
> all current kernel uses of combined VMA flags.
>
> Testing has demonstrated that the compiler optimises this code such that it
> generates the same assembly utilising this macro as it does if the flags
> were specified manually, for instance:
>
> vma_flags_t get_flags(void)
> {
> return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> }
>
> Generates the same code as:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
>
> vma_flags_clear_all(&flags);
> vma_flag_set(&flags, VMA_READ_BIT);
> vma_flag_set(&flags, VMA_WRITE_BIT);
> vma_flag_set(&flags, VMA_EXEC_BIT);
>
> return flags;
> }
>
> And:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
> unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
>
> *bitmap = 1UL << (__force int)VMA_READ_BIT;
> *bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
> *bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
>
> return flags;
> }
>
> That is:
>
> get_flags:
> movl $7, %eax
> ret
>
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Besides the part about 5 arguments that has been discussed,
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 33 +++++++++++++++++++++++++++++++++
> 1 file changed, 33 insertions(+)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index e0d31238097c..32c3b5347dc6 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2,6 +2,7 @@
> #ifndef _LINUX_MM_H
> #define _LINUX_MM_H
>
> +#include <linux/args.h>
> #include <linux/errno.h>
> #include <linux/mmdebug.h>
> #include <linux/gfp.h>
> @@ -1026,6 +1027,38 @@ static inline bool vma_test_atomic_flag(struct vm_area_struct *vma, vma_flag_t b
> return false;
> }
>
> +/* Set an individual VMA flag in flags, non-atomically. */
> +static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> +
> + __set_bit((__force int)bit, bitmap);
> +}
> +
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> +{
> + vma_flags_t flags;
> + int i;
> +
> + vma_flags_clear_all(&flags);
> + for (i = 0; i < count; i++)
> + vma_flag_set(&flags, bits[i]);
> + return flags;
> +}
> +
> +/*
> + * Helper macro which bitwise-or combines the specified input flags into a
> + * vma_flags_t bitmap value. E.g.:
> + *
> + * vma_flags_t flags = mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT,
> + * VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
> + *
> + * The compiler cleverly optimises away all of the work and this ends up being
> + * equivalent to aggregating the values manually.
> + */
> +#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> + (const vma_flag_t []){__VA_ARGS__})
> +
> static inline void vma_set_anonymous(struct vm_area_struct *vma)
> {
> vma->vm_ops = NULL;
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 04/13] tools: bitmap: add missing bitmap_[subset(), andnot()]
From: Liam R. Howlett @ 2026-02-09 18:45 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <0fd0d4ec868297f522003cb4b5898b53b498805b.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> The bitmap_subset() and bitmap_andnot() functions are not present in the
> tools version of include/linux/bitmap.h, so add them as subsequent patches
> implement test code that requires them.
>
> We also add the missing __bitmap_subset() to tools/lib/bitmap.c.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> tools/include/linux/bitmap.h | 22 ++++++++++++++++++++++
> tools/lib/bitmap.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 51 insertions(+)
>
> diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
> index 0d992245c600..250883090a5d 100644
> --- a/tools/include/linux/bitmap.h
> +++ b/tools/include/linux/bitmap.h
> @@ -24,6 +24,10 @@ void __bitmap_set(unsigned long *map, unsigned int start, int len);
> void __bitmap_clear(unsigned long *map, unsigned int start, int len);
> bool __bitmap_intersects(const unsigned long *bitmap1,
> const unsigned long *bitmap2, unsigned int bits);
> +bool __bitmap_subset(const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int nbits);
> +bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int nbits);
>
> #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
> #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
> @@ -81,6 +85,15 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
> __bitmap_or(dst, src1, src2, nbits);
> }
>
> +static __always_inline
> +bool bitmap_andnot(unsigned long *dst, const unsigned long *src1,
> + const unsigned long *src2, unsigned int nbits)
> +{
> + if (small_const_nbits(nbits))
> + return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
> + return __bitmap_andnot(dst, src1, src2, nbits);
> +}
> +
> static inline unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags __maybe_unused)
> {
> return malloc(bitmap_size(nbits));
> @@ -157,6 +170,15 @@ static inline bool bitmap_intersects(const unsigned long *src1,
> return __bitmap_intersects(src1, src2, nbits);
> }
>
> +static __always_inline
> +bool bitmap_subset(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
> +{
> + if (small_const_nbits(nbits))
> + return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
> + else
> + return __bitmap_subset(src1, src2, nbits);
> +}
> +
> static inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
> {
> if (__builtin_constant_p(nbits) && nbits == 1)
> diff --git a/tools/lib/bitmap.c b/tools/lib/bitmap.c
> index 51255c69754d..aa83d22c45e3 100644
> --- a/tools/lib/bitmap.c
> +++ b/tools/lib/bitmap.c
> @@ -140,3 +140,32 @@ void __bitmap_clear(unsigned long *map, unsigned int start, int len)
> *p &= ~mask_to_clear;
> }
> }
> +
> +bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int bits)
> +{
> + unsigned int k;
> + unsigned int lim = bits/BITS_PER_LONG;
> + unsigned long result = 0;
> +
> + for (k = 0; k < lim; k++)
> + result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
> + if (bits % BITS_PER_LONG)
> + result |= (dst[k] = bitmap1[k] & ~bitmap2[k] &
> + BITMAP_LAST_WORD_MASK(bits));
> + return result != 0;
> +}
> +
> +bool __bitmap_subset(const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int bits)
> +{
> + unsigned int k, lim = bits/BITS_PER_LONG;
> + for (k = 0; k < lim; ++k)
> + if (bitmap1[k] & ~bitmap2[k])
> + return false;
> +
> + if (bits % BITS_PER_LONG)
> + if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
> + return false;
> + return true;
> +}
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
From: Liam R. Howlett @ 2026-02-09 18:53 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <885d4897d67a6a57c0b07fa182a7055ad752df11.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> Now we have the mk_vma_flags() macro helper which permits easy
> specification of any number of VMA flags, add helper functions which
> operate with vma_flags_t parameters.
>
> This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
> vma_flags_clear[_mask]() respectively testing, setting and clearing flags
> with the _mask variants accepting vma_flag_t parameters, and the non-mask
> variants implemented as macros which accept a list of flags.
>
> This allows us to trivially test/set/clear aggregate VMA flag values as
> necessary, for instance:
>
> if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
> goto readwrite;
>
> vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
> vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
> We also add a function for testing that ALL flags are set for convenience,
> e.g.:
>
> if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
> /* Both READ and MAYREAD flags set */
> ...
> }
>
> The compiler generates optimal assembly for each such that they behave as
> if the caller were setting the bitmap flags manually.
>
> This is important for e.g. drivers which manipulate flag values rather than
> a VMA's specific flag values.
>
> We also add helpers for testing, setting and clearing flags for VMA's and
> VMA descriptors to reduce boilerplate.
>
> Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
>
> Finally, update the userland VMA tests to add the helpers there so they can
> be utilised as part of userland testing.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 165 +++++++++++++++++++++++++++++++
> include/linux/mm_types.h | 4 +-
> tools/testing/vma/vma_internal.h | 147 +++++++++++++++++++++++----
> 3 files changed, 295 insertions(+), 21 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 32c3b5347dc6..fd93317193e0 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1059,6 +1059,171 @@ static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> #define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> (const vma_flag_t []){__VA_ARGS__})
>
> +/* Test each of to_test flags in flags, non-atomically. */
> +static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Test whether any specified VMA flag is set, e.g.:
> + *
> + * if (vma_flags_test(flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) { ... }
> + */
> +#define vma_flags_test(flags, ...) \
> + vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/* Test that ALL of the to_test flags are set, non-atomically. */
> +static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Test whether ALL specified VMA flags are set, e.g.:
> + *
> + * if (vma_flags_test_all(flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) { ... }
> + */
> +#define vma_flags_test_all(flags, ...) \
> + vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/* Set each of the to_set flags in flags, non-atomically. */
> +static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_set = to_set.__vma_flags;
> +
> + bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Set all specified VMA flags, e.g.:
> + *
> + * vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> + */
> +#define vma_flags_set(flags, ...) \
> + vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/* Clear all of the to-clear flags in flags, non-atomically. */
> +static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
> +
> + bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Clear all specified individual flags, e.g.:
> + *
> + * vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> + */
> +#define vma_flags_clear(flags, ...) \
> + vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/*
> + * Helper to test that ALL specified flags are set in a VMA.
> + *
> + * Note: appropriate locks must be held, this function does not acquire them for
> + * you.
> + */
> +static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_all_mask(&vma->flags, flags);
> +}
> +
> +/*
> + * Helper macro for checking that ALL specified flags are set in a VMA, e.g.:
> + *
> + * if (vma_test_all_flags(vma, VMA_READ_BIT, VMA_MAYREAD_BIT) { ... }
> + */
> +#define vma_test_all_flags(vma, ...) \
> + vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +/*
> + * Helper to set all VMA flags in a VMA.
> + *
> + * Note: appropriate locks must be held, this function does not acquire them for
> + * you.
> + */
> +static inline void vma_set_flags_mask(struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&vma->flags, flags);
> +}
> +
> +/*
> + * Helper macro for specifying VMA flags in a VMA, e.g.:
> + *
> + * vma_set_flags(vma, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
> + * VMA_DONTDUMP_BIT);
> + *
> + * Note: appropriate locks must be held, this function does not acquire them for
> + * you.
> + */
> +#define vma_set_flags(vma, ...) \
> + vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +/* Helper to test all VMA flags in a VMA descriptor. */
> +static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_mask(&desc->vma_flags, flags);
> +}
> +
> +/*
> + * Helper macro for testing VMA flags for an input pointer to a struct
> + * vm_area_desc object describing a proposed VMA, e.g.:
> + *
> + * if (vma_desc_test_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT,
> + * VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)) { ... }
> + */
> +#define vma_desc_test_flags(desc, ...) \
> + vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +/* Helper to set all VMA flags in a VMA descriptor. */
> +static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&desc->vma_flags, flags);
> +}
> +
> +/*
> + * Helper macro for specifying VMA flags for an input pointer to a struct
> + * vm_area_desc object describing a proposed VMA, e.g.:
> + *
> + * vma_desc_set_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
> + * VMA_DONTDUMP_BIT);
> + */
> +#define vma_desc_set_flags(desc, ...) \
> + vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +/* Helper to clear all VMA flags in a VMA descriptor. */
> +static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_clear_mask(&desc->vma_flags, flags);
> +}
> +
> +/*
> + * Helper macro for clearing VMA flags for an input pointer to a struct
> + * vm_area_desc object describing a proposed VMA, e.g.:
> + *
> + * vma_desc_clear_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
> + * VMA_DONTDUMP_BIT);
> + */
> +#define vma_desc_clear_flags(desc, ...) \
> + vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> static inline void vma_set_anonymous(struct vm_area_struct *vma)
> {
> vma->vm_ops = NULL;
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index 592ad065fa75..cdac328b46dc 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -844,7 +844,7 @@ struct mmap_action {
>
> /*
> * If specified, this hook is invoked when an error occurred when
> - * attempting the selection action.
> + * attempting the selected action.
> *
> * The hook can return an error code in order to filter the error, but
> * it is not valid to clear the error here.
> @@ -868,6 +868,8 @@ typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> } vma_flags_t;
>
> +#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
> +
> /*
> * Describes a VMA that is about to be mmap()'ed. Drivers may choose to
> * manipulate mutable fields which will cause those fields to be updated in the
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index ca4eb563b29b..2b01794cbd61 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -21,7 +21,13 @@
>
> #include <stdlib.h>
>
> +#ifdef __CONCAT
> +#undef __CONCAT
> +#endif
> +
> +#include <linux/args.h>
> #include <linux/atomic.h>
> +#include <linux/bitmap.h>
> #include <linux/list.h>
> #include <linux/maple_tree.h>
> #include <linux/mm.h>
> @@ -38,6 +44,8 @@ extern unsigned long dac_mmap_min_addr;
> #define dac_mmap_min_addr 0UL
> #endif
>
> +#define ACCESS_PRIVATE(p, member) ((p)->member)
> +
> #define VM_WARN_ON(_expr) (WARN_ON(_expr))
> #define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
> #define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
> @@ -533,6 +541,8 @@ typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> } __private vma_flags_t;
>
> +#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
> +
> struct mm_struct {
> struct maple_tree mm_mt;
> int map_count; /* number of VMAs */
> @@ -882,6 +892,123 @@ static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
> return __pgprot(vm_flags);
> }
>
> +static inline void vma_flags_clear_all(vma_flags_t *flags)
> +{
> + bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
> +}
> +
> +static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> +
> + __set_bit((__force int)bit, bitmap);
> +}
> +
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> +{
> + vma_flags_t flags;
> + int i;
> +
> + vma_flags_clear_all(&flags);
> + for (i = 0; i < count; i++)
> + vma_flag_set(&flags, bits[i]);
> + return flags;
> +}
> +
> +#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> + (const vma_flag_t []){__VA_ARGS__})
> +
> +static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_test(flags, ...) \
> + vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_test_all(flags, ...) \
> + vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_set = to_set.__vma_flags;
> +
> + bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_set(flags, ...) \
> + vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
> +
> + bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_clear(flags, ...) \
> + vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_all_mask(&vma->flags, flags);
> +}
> +
> +#define vma_test_all_flags(vma, ...) \
> + vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_set_flags_mask(struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&vma->flags, flags);
> +}
> +
> +#define vma_set_flags(vma, ...) \
> + vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_test_flags(desc, ...) \
> + vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_set_flags(desc, ...) \
> + vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_clear_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_clear_flags(desc, ...) \
> + vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> static inline bool is_shared_maywrite(vm_flags_t vm_flags)
> {
> return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> @@ -1540,31 +1667,11 @@ static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
> {
> }
>
> -#define ACCESS_PRIVATE(p, member) ((p)->member)
> -
> -#define bitmap_size(nbits) (ALIGN(nbits, BITS_PER_LONG) / BITS_PER_BYTE)
> -
> -static __always_inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
> -{
> - unsigned int len = bitmap_size(nbits);
> -
> - if (small_const_nbits(nbits))
> - *dst = 0;
> - else
> - memset(dst, 0, len);
> -}
> -
> static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
> {
> return test_bit(flag, ACCESS_PRIVATE(&mm->flags, __mm_flags));
> }
>
> -/* Clears all bits in the VMA flags bitmap, non-atomically. */
> -static inline void vma_flags_clear_all(vma_flags_t *flags)
> -{
> - bitmap_zero(ACCESS_PRIVATE(flags, __vma_flags), NUM_VMA_FLAG_BITS);
> -}
> -
> /*
> * Copy value to the first system word of VMA flags, non-atomically.
> *
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 06/13] mm: update hugetlbfs to use VMA flags on mmap_prepare
From: Liam R. Howlett @ 2026-02-09 19:03 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <9226bec80c9aa3447cc2b83354f733841dba8a50.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> In order to update all mmap_prepare users to utilising the new VMA flags
> type vma_flags_t and associated helper functions, we start by updating
> hugetlbfs which has a lot of additional logic that requires updating to
> make this change.
>
> This is laying the groundwork for eliminating the vm_flags_t from struct
> vm_area_desc and using vma_flags_t only, which further lays the ground for
> removing the deprecated vm_flags_t type altogether.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> fs/hugetlbfs/inode.c | 14 +++++++-------
> include/linux/hugetlb.h | 6 +++---
> include/linux/hugetlb_inline.h | 10 ++++++++++
> ipc/shm.c | 12 +++++++-----
> mm/hugetlb.c | 22 +++++++++++-----------
> mm/memfd.c | 4 ++--
> mm/mmap.c | 2 +-
> 7 files changed, 41 insertions(+), 29 deletions(-)
>
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 3b4c152c5c73..95a5b23b4808 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -109,7 +109,7 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
> loff_t len, vma_len;
> int ret;
> struct hstate *h = hstate_file(file);
> - vm_flags_t vm_flags;
> + vma_flags_t vma_flags;
>
> /*
> * vma address alignment (but not the pgoff alignment) has
> @@ -119,7 +119,7 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
> * way when do_mmap unwinds (may be important on powerpc
> * and ia64).
> */
> - desc->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
> + vma_desc_set_flags(desc, VMA_HUGETLB_BIT, VMA_DONTEXPAND_BIT);
> desc->vm_ops = &hugetlb_vm_ops;
>
> /*
> @@ -148,23 +148,23 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
>
> ret = -ENOMEM;
>
> - vm_flags = desc->vm_flags;
> + vma_flags = desc->vma_flags;
> /*
> * for SHM_HUGETLB, the pages are reserved in the shmget() call so skip
> * reserving here. Note: only for SHM hugetlbfs file, the inode
> * flag S_PRIVATE is set.
> */
> if (inode->i_flags & S_PRIVATE)
> - vm_flags |= VM_NORESERVE;
> + vma_flags_set(&vma_flags, VMA_NORESERVE_BIT);
>
> if (hugetlb_reserve_pages(inode,
> desc->pgoff >> huge_page_order(h),
> len >> huge_page_shift(h), desc,
> - vm_flags) < 0)
> + vma_flags) < 0)
> goto out;
>
> ret = 0;
> - if ((desc->vm_flags & VM_WRITE) && inode->i_size < len)
> + if (vma_desc_test_flags(desc, VMA_WRITE_BIT) && inode->i_size < len)
> i_size_write(inode, len);
> out:
> inode_unlock(inode);
> @@ -1527,7 +1527,7 @@ static int get_hstate_idx(int page_size_log)
> * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
> */
> struct file *hugetlb_file_setup(const char *name, size_t size,
> - vm_flags_t acctflag, int creat_flags,
> + vma_flags_t acctflag, int creat_flags,
> int page_size_log)
> {
> struct inode *inode;
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index 94a03591990c..4e72bf66077e 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -150,7 +150,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
> struct folio **foliop);
> #endif /* CONFIG_USERFAULTFD */
> long hugetlb_reserve_pages(struct inode *inode, long from, long to,
> - struct vm_area_desc *desc, vm_flags_t vm_flags);
> + struct vm_area_desc *desc, vma_flags_t vma_flags);
> long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
> long freed);
> bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list);
> @@ -529,7 +529,7 @@ static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
> }
>
> extern const struct vm_operations_struct hugetlb_vm_ops;
> -struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
> +struct file *hugetlb_file_setup(const char *name, size_t size, vma_flags_t acct,
> int creat_flags, int page_size_log);
>
> static inline bool is_file_hugepages(const struct file *file)
> @@ -545,7 +545,7 @@ static inline struct hstate *hstate_inode(struct inode *i)
>
> #define is_file_hugepages(file) false
> static inline struct file *
> -hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
> +hugetlb_file_setup(const char *name, size_t size, vma_flags_t acctflag,
> int creat_flags, int page_size_log)
> {
> return ERR_PTR(-ENOSYS);
> diff --git a/include/linux/hugetlb_inline.h b/include/linux/hugetlb_inline.h
> index a27aa0162918..593f5d4e108b 100644
> --- a/include/linux/hugetlb_inline.h
> +++ b/include/linux/hugetlb_inline.h
> @@ -11,6 +11,11 @@ static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
> return !!(vm_flags & VM_HUGETLB);
> }
>
> +static inline bool is_vma_hugetlb_flags(const vma_flags_t *flags)
> +{
> + return vma_flags_test(flags, VMA_HUGETLB_BIT);
> +}
> +
> #else
>
> static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
> @@ -18,6 +23,11 @@ static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
> return false;
> }
>
> +static inline bool is_vma_hugetlb_flags(const vma_flags_t *flags)
> +{
> + return false;
> +}
> +
> #endif
>
> static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
> diff --git a/ipc/shm.c b/ipc/shm.c
> index 3db36773dd10..2c7379c4c647 100644
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -707,9 +707,9 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> int error;
> struct shmid_kernel *shp;
> size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
> + const bool has_no_reserve = shmflg & SHM_NORESERVE;
> struct file *file;
> char name[13];
> - vm_flags_t acctflag = 0;
>
> if (size < SHMMIN || size > ns->shm_ctlmax)
> return -EINVAL;
> @@ -738,6 +738,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
>
> sprintf(name, "SYSV%08x", key);
> if (shmflg & SHM_HUGETLB) {
> + vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct hstate *hs;
> size_t hugesize;
>
> @@ -749,17 +750,18 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> hugesize = ALIGN(size, huge_page_size(hs));
>
> /* hugetlb_file_setup applies strict accounting */
> - if (shmflg & SHM_NORESERVE)
> - acctflag = VM_NORESERVE;
> + if (has_no_reserve)
> + vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
> file = hugetlb_file_setup(name, hugesize, acctflag,
> HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
> } else {
> + vm_flags_t acctflag = 0;
> +
> /*
> * Do not allow no accounting for OVERCOMMIT_NEVER, even
> * if it's asked for.
> */
> - if ((shmflg & SHM_NORESERVE) &&
> - sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> + if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> acctflag = VM_NORESERVE;
> file = shmem_kernel_file_setup(name, size, acctflag);
> }
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 4f4494251f5c..e6955061d751 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1193,16 +1193,16 @@ static void set_vma_resv_flags(struct vm_area_struct *vma, unsigned long flags)
>
> static void set_vma_desc_resv_map(struct vm_area_desc *desc, struct resv_map *map)
> {
> - VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
> - VM_WARN_ON_ONCE(desc->vm_flags & VM_MAYSHARE);
> + VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
> + VM_WARN_ON_ONCE(vma_desc_test_flags(desc, VMA_MAYSHARE_BIT));
>
> desc->private_data = map;
> }
>
> static void set_vma_desc_resv_flags(struct vm_area_desc *desc, unsigned long flags)
> {
> - VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
> - VM_WARN_ON_ONCE(desc->vm_flags & VM_MAYSHARE);
> + VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
> + VM_WARN_ON_ONCE(vma_desc_test_flags(desc, VMA_MAYSHARE_BIT));
>
> desc->private_data = (void *)((unsigned long)desc->private_data | flags);
> }
> @@ -1216,7 +1216,7 @@ static int is_vma_resv_set(struct vm_area_struct *vma, unsigned long flag)
>
> static bool is_vma_desc_resv_set(struct vm_area_desc *desc, unsigned long flag)
> {
> - VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
> + VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
>
> return ((unsigned long)desc->private_data) & flag;
> }
> @@ -6564,7 +6564,7 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
> long hugetlb_reserve_pages(struct inode *inode,
> long from, long to,
> struct vm_area_desc *desc,
> - vm_flags_t vm_flags)
> + vma_flags_t vma_flags)
> {
> long chg = -1, add = -1, spool_resv, gbl_resv;
> struct hstate *h = hstate_inode(inode);
> @@ -6585,7 +6585,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> * attempt will be made for VM_NORESERVE to allocate a page
> * without using reserves
> */
> - if (vm_flags & VM_NORESERVE)
> + if (vma_flags_test(&vma_flags, VMA_NORESERVE_BIT))
> return 0;
>
> /*
> @@ -6594,7 +6594,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> * to reserve the full area even if read-only as mprotect() may be
> * called to make the mapping read-write. Assume !desc is a shm mapping
> */
> - if (!desc || desc->vm_flags & VM_MAYSHARE) {
> + if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
> /*
> * resv_map can not be NULL as hugetlb_reserve_pages is only
> * called for inodes for which resv_maps were created (see
> @@ -6628,7 +6628,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> if (err < 0)
> goto out_err;
>
> - if (desc && !(desc->vm_flags & VM_MAYSHARE) && h_cg) {
> + if (desc && !vma_desc_test_flags(desc, VMA_MAYSHARE_BIT) && h_cg) {
> /* For private mappings, the hugetlb_cgroup uncharge info hangs
> * of the resv_map.
> */
> @@ -6665,7 +6665,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> * consumed reservations are stored in the map. Hence, nothing
> * else has to be done for private mappings here
> */
> - if (!desc || desc->vm_flags & VM_MAYSHARE) {
> + if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
> add = region_add(resv_map, from, to, regions_needed, h, h_cg);
>
> if (unlikely(add < 0)) {
> @@ -6729,7 +6729,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> hugetlb_cgroup_uncharge_cgroup_rsvd(hstate_index(h),
> chg * pages_per_huge_page(h), h_cg);
> out_err:
> - if (!desc || desc->vm_flags & VM_MAYSHARE)
> + if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT))
> /* Only call region_abort if the region_chg succeeded but the
> * region_add failed or didn't run.
> */
> diff --git a/mm/memfd.c b/mm/memfd.c
> index ab5312aff14b..5f95f639550c 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -87,7 +87,7 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
> gfp_mask &= ~(__GFP_HIGHMEM | __GFP_MOVABLE);
> idx >>= huge_page_order(h);
>
> - nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, 0);
> + nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, EMPTY_VMA_FLAGS);
> if (nr_resv < 0)
> return ERR_PTR(nr_resv);
>
> @@ -464,7 +464,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> int err = 0;
>
> if (flags & MFD_HUGETLB) {
> - file = hugetlb_file_setup(name, 0, VM_NORESERVE,
> + file = hugetlb_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT),
> HUGETLB_ANONHUGE_INODE,
> (flags >> MFD_HUGE_SHIFT) &
> MFD_HUGE_MASK);
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 8771b276d63d..038ff5f09df0 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -594,7 +594,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
> * taken when vm_ops->mmap() is called
> */
> file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
> - VM_NORESERVE,
> + mk_vma_flags(VMA_NORESERVE_BIT),
> HUGETLB_ANONHUGE_INODE,
> (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
> if (IS_ERR(file))
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 07/13] mm: update secretmem to use VMA flags on mmap_prepare
From: Liam R. Howlett @ 2026-02-09 19:06 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <a243a09b0a5d0581e963d696de1735f61f5b2075.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> This patch updates secretmem to use the new vma_flags_t type which will
> soon supersede vm_flags_t altogether.
>
> In order to make this change we also have to update mlock_future_ok(), we
> replace the vm_flags_t parameter with a simple boolean is_vma_locked one,
> which also simplifies the invocation here.
>
> This is laying the groundwork for eliminating the vm_flags_t in
> vm_area_desc and more broadly throughout the kernel.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
With the type fix for brk - I assume sparse would have detected this as
well.
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> mm/internal.h | 2 +-
> mm/mmap.c | 8 ++++----
> mm/mremap.c | 2 +-
> mm/secretmem.c | 7 +++----
> mm/vma.c | 2 +-
> 5 files changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/mm/internal.h b/mm/internal.h
> index ef71a1d9991f..d67e8bb75734 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -1046,7 +1046,7 @@ extern long populate_vma_page_range(struct vm_area_struct *vma,
> unsigned long start, unsigned long end, int *locked);
> extern long faultin_page_range(struct mm_struct *mm, unsigned long start,
> unsigned long end, bool write, int *locked);
> -bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
> +bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
> unsigned long bytes);
>
> /*
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 038ff5f09df0..354479c95896 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -225,12 +225,12 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
> return hint;
> }
>
> -bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
> - unsigned long bytes)
> +bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
> + unsigned long bytes)
> {
> unsigned long locked_pages, limit_pages;
>
> - if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
> + if (!is_vma_locked || capable(CAP_IPC_LOCK))
> return true;
>
> locked_pages = bytes >> PAGE_SHIFT;
> @@ -416,7 +416,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
> if (!can_do_mlock())
> return -EPERM;
>
> - if (!mlock_future_ok(mm, vm_flags, len))
> + if (!mlock_future_ok(mm, vm_flags & VM_LOCKED, len))
> return -EAGAIN;
>
> if (file) {
> diff --git a/mm/mremap.c b/mm/mremap.c
> index 8391ae17de64..2be876a70cc0 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -1740,7 +1740,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
> if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
> return -EFAULT;
>
> - if (!mlock_future_ok(mm, vma->vm_flags, vrm->delta))
> + if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, vrm->delta))
> return -EAGAIN;
>
> if (!may_expand_vm(mm, vma->vm_flags, vrm->delta >> PAGE_SHIFT))
> diff --git a/mm/secretmem.c b/mm/secretmem.c
> index edf111e0a1bb..11a779c812a7 100644
> --- a/mm/secretmem.c
> +++ b/mm/secretmem.c
> @@ -122,13 +122,12 @@ static int secretmem_mmap_prepare(struct vm_area_desc *desc)
> {
> const unsigned long len = vma_desc_size(desc);
>
> - if ((desc->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
> + if (!vma_desc_test_flags(desc, VMA_SHARED_BIT, VMA_MAYSHARE_BIT))
> return -EINVAL;
>
> - if (!mlock_future_ok(desc->mm, desc->vm_flags | VM_LOCKED, len))
> + vma_desc_set_flags(desc, VMA_LOCKED_BIT, VMA_DONTDUMP_BIT);
> + if (!mlock_future_ok(desc->mm, /*is_vma_locked=*/ true, len))
> return -EAGAIN;
> -
> - desc->vm_flags |= VM_LOCKED | VM_DONTDUMP;
> desc->vm_ops = &secretmem_vm_ops;
>
> return 0;
> diff --git a/mm/vma.c b/mm/vma.c
> index f352d5c72212..39dcd9ddd4ba 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -3053,7 +3053,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
> return -ENOMEM;
>
> /* mlock limit tests */
> - if (!mlock_future_ok(mm, vma->vm_flags, grow << PAGE_SHIFT))
> + if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, grow << PAGE_SHIFT))
> return -ENOMEM;
>
> /* Check to ensure the stack will not grow into a hugetlb-only region */
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
From: Liam R. Howlett @ 2026-02-09 19:13 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <736febd280eb484d79cef5cf55b8a6f79ad832d2.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> shmem file setup functions to operate in terms of vma_flags_t rather than
> vm_flags_t.
>
> This patch makes this change and updates all callers to use the new
> functions.
>
> No functional changes intended.
A few nits, but
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> drivers/gpu/drm/drm_gem.c | 5 +-
> drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> fs/xfs/scrub/xfile.c | 3 +-
> fs/xfs/xfs_buf_mem.c | 2 +-
> include/linux/shmem_fs.h | 8 ++-
> ipc/shm.c | 6 +--
> mm/memfd.c | 2 +-
> mm/memfd_luo.c | 2 +-
> mm/shmem.c | 59 +++++++++++++----------
> security/keys/big_key.c | 2 +-
> 16 files changed, 57 insertions(+), 49 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
> index 9322a9287dc7..0bc36957979d 100644
> --- a/arch/x86/kernel/cpu/sgx/ioctl.c
> +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
> @@ -83,7 +83,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
> encl_size = secs->size + PAGE_SIZE;
>
> backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
> - VM_NORESERVE);
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(backing)) {
> ret = PTR_ERR(backing);
> goto err_out_shrink;
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index e4df43427394..be4dca2bc34e 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -130,14 +130,15 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev,
> struct vfsmount *gemfs)
> {
> struct file *filp;
> + const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
>
> drm_gem_private_object_init(dev, obj, size);
>
> if (gemfs)
> filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
> - VM_NORESERVE);
> + flags);
> else
> - filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
> + filp = shmem_file_setup("drm mm object", size, flags);
>
> if (IS_ERR(filp))
> return PTR_ERR(filp);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> index 26dda55a07ff..fe1843497b27 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> @@ -496,7 +496,7 @@ static int __create_shmem(struct drm_i915_private *i915,
> struct drm_gem_object *obj,
> resource_size_t size)
> {
> - unsigned long flags = VM_NORESERVE;
> + const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
> struct file *filp;
>
> drm_gem_private_object_init(&i915->drm, obj, size);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> index f65fe86c02b5..7b1a7d01db2b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -200,7 +200,8 @@ static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
> struct address_space *mapping;
> gfp_t mask;
>
> - filp = shmem_file_setup("i915-shmem-tt", size, VM_NORESERVE);
> + filp = shmem_file_setup("i915-shmem-tt", size,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(filp))
> return PTR_ERR(filp);
>
> diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c b/drivers/gpu/drm/i915/gt/shmem_utils.c
> index 365c4b8b04f4..5f37c699a320 100644
> --- a/drivers/gpu/drm/i915/gt/shmem_utils.c
> +++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
> @@ -19,7 +19,8 @@ struct file *shmem_create_from_data(const char *name, void *data, size_t len)
> struct file *file;
> int err;
>
> - file = shmem_file_setup(name, PAGE_ALIGN(len), VM_NORESERVE);
> + file = shmem_file_setup(name, PAGE_ALIGN(len),
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(file))
> return file;
>
> diff --git a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> index 61ec6f580b62..bd5f7d0b9b62 100644
> --- a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> +++ b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> @@ -143,7 +143,7 @@ static void ttm_tt_fini_shmem(struct kunit *test)
> err = ttm_tt_init(tt, bo, 0, caching, 0);
> KUNIT_ASSERT_EQ(test, err, 0);
>
> - shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
> + shmem = shmem_file_setup("ttm swap", BO_SIZE, EMPTY_VMA_FLAGS);
> tt->swap_storage = shmem;
>
> ttm_tt_fini(tt);
> diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
> index 32530c75f038..6bd4c123d94c 100644
> --- a/drivers/gpu/drm/ttm/ttm_backup.c
> +++ b/drivers/gpu/drm/ttm/ttm_backup.c
> @@ -178,5 +178,6 @@ EXPORT_SYMBOL_GPL(ttm_backup_bytes_avail);
> */
> struct file *ttm_backup_shmem_create(loff_t size)
> {
> - return shmem_file_setup("ttm shmem backup", size, 0);
> + return shmem_file_setup("ttm shmem backup", size,
> + EMPTY_VMA_FLAGS);
> }
> diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
> index 611d20ab966d..f73a5ce87645 100644
> --- a/drivers/gpu/drm/ttm/ttm_tt.c
> +++ b/drivers/gpu/drm/ttm/ttm_tt.c
> @@ -330,7 +330,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
> struct page *to_page;
> int i, ret;
>
> - swap_storage = shmem_file_setup("ttm swap", size, 0);
> + swap_storage = shmem_file_setup("ttm swap", size, EMPTY_VMA_FLAGS);
> if (IS_ERR(swap_storage)) {
> pr_err("Failed allocating swap storage\n");
> return PTR_ERR(swap_storage);
> diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
> index c753c79df203..fe0584a39f16 100644
> --- a/fs/xfs/scrub/xfile.c
> +++ b/fs/xfs/scrub/xfile.c
> @@ -61,7 +61,8 @@ xfile_create(
> if (!xf)
> return -ENOMEM;
>
> - xf->file = shmem_kernel_file_setup(description, isize, VM_NORESERVE);
> + xf->file = shmem_kernel_file_setup(description, isize,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(xf->file)) {
> error = PTR_ERR(xf->file);
> goto out_xfile;
> diff --git a/fs/xfs/xfs_buf_mem.c b/fs/xfs/xfs_buf_mem.c
> index dcbfa274e06d..fd6f0a5bc0ea 100644
> --- a/fs/xfs/xfs_buf_mem.c
> +++ b/fs/xfs/xfs_buf_mem.c
> @@ -62,7 +62,7 @@ xmbuf_alloc(
> if (!btp)
> return -ENOMEM;
>
> - file = shmem_kernel_file_setup(descr, 0, 0);
> + file = shmem_kernel_file_setup(descr, 0, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> error = PTR_ERR(file);
> goto out_free_btp;
> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> index e2069b3179c4..a8273b32e041 100644
> --- a/include/linux/shmem_fs.h
> +++ b/include/linux/shmem_fs.h
> @@ -102,12 +102,10 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
> extern const struct fs_parameter_spec shmem_fs_parameters[];
> extern void shmem_init(void);
> extern int shmem_init_fs_context(struct fs_context *fc);
> -extern struct file *shmem_file_setup(const char *name,
> - loff_t size, unsigned long flags);
> -extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> - unsigned long flags);
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags);
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size, vma_flags_t vma_flags);
> extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt,
> - const char *name, loff_t size, unsigned long flags);
> + const char *name, loff_t size, vma_flags_t flags);
> int shmem_zero_setup(struct vm_area_struct *vma);
> int shmem_zero_setup_desc(struct vm_area_desc *desc);
> extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
> diff --git a/ipc/shm.c b/ipc/shm.c
> index 2c7379c4c647..e8c7d1924c50 100644
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -708,6 +708,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> struct shmid_kernel *shp;
> size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
> const bool has_no_reserve = shmflg & SHM_NORESERVE;
> + vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct file *file;
> char name[13];
>
> @@ -738,7 +739,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
>
> sprintf(name, "SYSV%08x", key);
> if (shmflg & SHM_HUGETLB) {
> - vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct hstate *hs;
> size_t hugesize;
>
> @@ -755,14 +755,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> file = hugetlb_file_setup(name, hugesize, acctflag,
> HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
> } else {
> - vm_flags_t acctflag = 0;
> -
> /*
> * Do not allow no accounting for OVERCOMMIT_NEVER, even
> * if it's asked for.
> */
> if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> - acctflag = VM_NORESERVE;
> + vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
> file = shmem_kernel_file_setup(name, size, acctflag);
> }
> error = PTR_ERR(file);
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 5f95f639550c..f3a8950850a2 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -469,7 +469,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> (flags >> MFD_HUGE_SHIFT) &
> MFD_HUGE_MASK);
> } else {
> - file = shmem_file_setup(name, 0, VM_NORESERVE);
> + file = shmem_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT));
> }
> if (IS_ERR(file))
> return file;
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> index 4f6ba63b4310..a2629dcfd0f1 100644
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -443,7 +443,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
> if (!ser)
> return -EINVAL;
>
> - file = shmem_file_setup("", 0, VM_NORESERVE);
> + file = shmem_file_setup("", 0, mk_vma_flags(VMA_NORESERVE_BIT));
>
> if (IS_ERR(file)) {
> pr_err("failed to setup file: %pe\n", file);
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 0adde3f4df27..97a8f55c7296 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3057,9 +3057,9 @@ static struct offset_ctx *shmem_get_offset_ctx(struct inode *inode)
> }
>
> static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> - struct super_block *sb,
> - struct inode *dir, umode_t mode,
> - dev_t dev, unsigned long flags)
> + struct super_block *sb,
> + struct inode *dir, umode_t mode,
> + dev_t dev, vma_flags_t flags)
Using two tabs here would have been less ugly, and below too.
> {
> struct inode *inode;
> struct shmem_inode_info *info;
> @@ -3087,7 +3087,8 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> spin_lock_init(&info->lock);
> atomic_set(&info->stop_eviction, 0);
> info->seals = F_SEAL_SEAL;
> - info->flags = (flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
> + info->flags = vma_flags_test(&flags, VMA_NORESERVE_BIT)
> + ? SHMEM_F_NORESERVE : 0;
> info->i_crtime = inode_get_mtime(inode);
> info->fsflags = (dir == NULL) ? 0 :
> SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
> @@ -3140,7 +3141,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> #ifdef CONFIG_TMPFS_QUOTA
> static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
A variable named flags is often incorrectly passed along as the wrong
flags, so I try to avoid it.
> {
> int err;
> struct inode *inode;
> @@ -3166,9 +3167,9 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> return ERR_PTR(err);
> }
> #else
> -static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> +static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> return __shmem_get_inode(idmap, sb, dir, mode, dev, flags);
> }
> @@ -3875,7 +3876,8 @@ shmem_mknod(struct mnt_idmap *idmap, struct inode *dir,
> if (!generic_ci_validate_strict_name(dir, &dentry->d_name))
> return -EINVAL;
>
> - inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev, VM_NORESERVE);
> + inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode))
> return PTR_ERR(inode);
>
> @@ -3910,7 +3912,8 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
> struct inode *inode;
> int error;
>
> - inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0, VM_NORESERVE);
> + inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode)) {
> error = PTR_ERR(inode);
> goto err_out;
> @@ -4107,7 +4110,7 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir,
> return -ENAMETOOLONG;
>
> inode = shmem_get_inode(idmap, dir->i_sb, dir, S_IFLNK | 0777, 0,
> - VM_NORESERVE);
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode))
> return PTR_ERR(inode);
>
> @@ -5108,7 +5111,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
> #endif /* CONFIG_TMPFS_QUOTA */
>
> inode = shmem_get_inode(&nop_mnt_idmap, sb, NULL,
> - S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
> + S_IFDIR | sbinfo->mode, 0,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode)) {
> error = PTR_ERR(inode);
> goto failed;
> @@ -5808,7 +5812,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
>
> static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> struct inode *inode = ramfs_get_inode(sb, dir, mode, dev);
> return inode ? inode : ERR_PTR(-ENOSPC);
> @@ -5819,10 +5823,11 @@ static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> /* common code */
>
> static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long vm_flags,
> + loff_t size, vma_flags_t flags,
> unsigned int i_flags)
> {
> - unsigned long flags = (vm_flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
> + const unsigned long shmem_flags =
> + vma_flags_test(&flags, VMA_NORESERVE_BIT) ? SHMEM_F_NORESERVE : 0;
> struct inode *inode;
> struct file *res;
>
> @@ -5835,13 +5840,13 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> if (is_idmapped_mnt(mnt))
> return ERR_PTR(-EINVAL);
>
> - if (shmem_acct_size(flags, size))
> + if (shmem_acct_size(shmem_flags, size))
> return ERR_PTR(-ENOMEM);
>
> inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,
> - S_IFREG | S_IRWXUGO, 0, vm_flags);
> + S_IFREG | S_IRWXUGO, 0, flags);
> if (IS_ERR(inode)) {
> - shmem_unacct_size(flags, size);
> + shmem_unacct_size(shmem_flags, size);
> return ERR_CAST(inode);
> }
> inode->i_flags |= i_flags;
> @@ -5864,9 +5869,10 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> * checks are provided at the key or shm level rather than the inode.
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> -struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> + vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE);
> }
> @@ -5878,7 +5884,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
> * @size: size to be set for the file
> * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> */
> -struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, 0);
> }
> @@ -5889,16 +5895,17 @@ EXPORT_SYMBOL_GPL(shmem_file_setup);
> * @mnt: the tmpfs mount where the file will be created
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long flags)
> + loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(mnt, name, size, flags, 0);
> }
> EXPORT_SYMBOL_GPL(shmem_file_setup_with_mnt);
>
> -static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, vm_flags_t vm_flags)
> +static struct file *__shmem_zero_setup(unsigned long start, unsigned long end,
> + vma_flags_t flags)
> {
> loff_t size = end - start;
>
> @@ -5908,7 +5915,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> * accessible to the user through its mapping, use S_PRIVATE flag to
> * bypass file security, in the same way as shmem_kernel_file_setup().
> */
> - return shmem_kernel_file_setup("dev/zero", size, vm_flags);
> + return shmem_kernel_file_setup("dev/zero", size, flags);
> }
>
> /**
> @@ -5918,7 +5925,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> */
> int shmem_zero_setup(struct vm_area_struct *vma)
> {
> - struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->vm_flags);
> + struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> @@ -5939,7 +5946,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
> */
> int shmem_zero_setup_desc(struct vm_area_desc *desc)
> {
> - struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vm_flags);
> + struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vma_flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> diff --git a/security/keys/big_key.c b/security/keys/big_key.c
> index d46862ab90d6..268f702df380 100644
> --- a/security/keys/big_key.c
> +++ b/security/keys/big_key.c
> @@ -103,7 +103,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
> 0, enckey);
>
> /* save aligned data to file */
> - file = shmem_kernel_file_setup("", enclen, 0);
> + file = shmem_kernel_file_setup("", enclen, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> ret = PTR_ERR(file);
> goto err_enckey;
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
From: Liam R. Howlett @ 2026-02-09 19:27 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Pedro Falcato, Jarkko Sakkinen, Dave Hansen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
H . Peter Anvin, Arnd Bergmann, Greg Kroah-Hartman, Dan Williams,
Vishal Verma, Dave Jiang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig,
Huang Rui, Matthew Auld, Matthew Brost, Alexander Viro,
Christian Brauner, Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu,
Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Hugh Dickins,
Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts, Dev Jain,
Barry Song, Lance Yang, Jann Horn, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <d55a0ba8-46a3-49d4-ba76-aa9658e1e8be@lucifer.local>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260206 20:01]:
> On Fri, Feb 06, 2026 at 11:31:53AM -0800, Andrew Morton wrote:
> > On Fri, 6 Feb 2026 17:46:36 +0000 Pedro Falcato <pfalcato@suse.de> wrote:
> >
> > > > -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> > > > +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> > > > + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
> > >
> > > as a sidenote, these flags are no longer constant expressions and thus
> > >
> > > static vma_flags_t flags = VMA_REMAP_FLAGS;
>
> I mean this would be a code smell anyway :) but point taken.
>
> > >
> > > can't compile.
> >
> > Yup, that isn't nice. An all-caps thing with no () is a compile-time
> > constant.
>
> There is precedence for this, e.g. TASK_SIZE_MAX and other arch defines like
> that:
>
> error: initializer element is not a compile-time constant
> 3309 | static unsigned long task_max = TASK_SIZE_MAX;
> | ^~~~~~~~~~~~~
>
> And this will almost certainly (and certainly in everything I tested) become a
> compile-time constant via the optimiser so to all intents and purposes it _is_
> essentially compile-time.
>
> But the point of doing it this way is to maintain, as much as possible,
> one-to-one translation between the previous approach and the new with as little
> noise/friction as possible.
>
> Making this a function makes things really horrible honestly.
>
> Because vma_remap_flags() suddenly because a vague thing - I'd assume this was a
> function doing something. So now do we call it get_vma_remap_flags()? Suddenly
> something nice-ish like:
>
> if (vma_flags_test(flags, VMA_REMAP_FLAGS)) {
> ...
> }
>
> Become:
>
> if (vma_flags_test(flags, get_vma_remap_flags())) {
> ...
> }
>
> And now it's SUPER ambiguous as to what you're doing there. I'd assume right
> away that get_vma_remap_flags() was going off and doing something or referencing
> a static variable or something.
>
> Given the compile will treat the former _exactly_ as if it were a compile-time
> constant it's just adding unnecessary ambiguity.
>
> So is it something we can live with?
How many of these are there going to be? Could we do something like:
static inline remap_vma_flags_test(..) {
return vma_flags_test_all(vma_flags, ...);
}
if (remap_vma_flags_test(vma_flags)) {
...
}
^ permalink raw reply
* Re: [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only
From: Liam R. Howlett @ 2026-02-09 19:32 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <fd2a2938b246b4505321954062b1caba7acfc77a.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> Now we have eliminated all uses of vm_area_desc->vm_flags, eliminate this
> field, and have mmap_prepare users utilise the vma_flags_t
> vm_area_desc->vma_flags field only.
>
> As part of this change we alter is_shared_maywrite() to accept a
> vma_flags_t parameter, and introduce is_shared_maywrite_vm_flags() for use
> with legacy vm_flags_t flags.
>
> We also update struct mmap_state to add a union between vma_flags and
> vm_flags temporarily until the mmap logic is also converted to using
> vma_flags_t.
>
> Also update the VMA userland tests to reflect this change.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 9 +++++++--
> include/linux/mm_types.h | 5 +----
> mm/filemap.c | 2 +-
> mm/util.c | 2 +-
> mm/vma.c | 11 +++++++----
> mm/vma.h | 3 +--
> tools/testing/vma/vma_internal.h | 9 +++++++--
> 7 files changed, 25 insertions(+), 16 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index e31f72a021ef..37e215de3343 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1290,15 +1290,20 @@ static inline bool vma_is_accessible(const struct vm_area_struct *vma)
> return vma->vm_flags & VM_ACCESS_FLAGS;
> }
>
> -static inline bool is_shared_maywrite(vm_flags_t vm_flags)
> +static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
> {
> return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> (VM_SHARED | VM_MAYWRITE);
> }
>
> +static inline bool is_shared_maywrite(const vma_flags_t *flags)
> +{
> + return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
> +}
> +
Confusing git diff here, but looks okay.
> static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma)
> {
> - return is_shared_maywrite(vma->vm_flags);
> + return is_shared_maywrite(&vma->flags);
> }
>
> static inline
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index cdac328b46dc..6d98ff6bc2e5 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -887,10 +887,7 @@ struct vm_area_desc {
> /* Mutable fields. Populated with initial state. */
> pgoff_t pgoff;
> struct file *vm_file;
> - union {
> - vm_flags_t vm_flags;
> - vma_flags_t vma_flags;
> - };
> + vma_flags_t vma_flags;
> pgprot_t page_prot;
>
> /* Write-only fields. */
> diff --git a/mm/filemap.c b/mm/filemap.c
> index ebd75684cb0a..6cd7974d4ada 100644
> --- a/mm/filemap.c
> +++ b/mm/filemap.c
> @@ -4012,7 +4012,7 @@ int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
>
> int generic_file_readonly_mmap_prepare(struct vm_area_desc *desc)
> {
> - if (is_shared_maywrite(desc->vm_flags))
> + if (is_shared_maywrite(&desc->vma_flags))
> return -EINVAL;
> return generic_file_mmap_prepare(desc);
> }
> diff --git a/mm/util.c b/mm/util.c
> index 97cae40c0209..b05ab6f97e11 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -1154,7 +1154,7 @@ int __compat_vma_mmap(const struct file_operations *f_op,
>
> .pgoff = vma->vm_pgoff,
> .vm_file = vma->vm_file,
> - .vm_flags = vma->vm_flags,
> + .vma_flags = vma->flags,
> .page_prot = vma->vm_page_prot,
>
> .action.type = MMAP_NOTHING, /* Default */
> diff --git a/mm/vma.c b/mm/vma.c
> index 39dcd9ddd4ba..be64f781a3aa 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -15,7 +15,10 @@ struct mmap_state {
> unsigned long end;
> pgoff_t pgoff;
> unsigned long pglen;
> - vm_flags_t vm_flags;
> + union {
> + vm_flags_t vm_flags;
> + vma_flags_t vma_flags;
> + };
> struct file *file;
> pgprot_t page_prot;
>
> @@ -2369,7 +2372,7 @@ static void set_desc_from_map(struct vm_area_desc *desc,
>
> desc->pgoff = map->pgoff;
> desc->vm_file = map->file;
> - desc->vm_flags = map->vm_flags;
> + desc->vma_flags = map->vma_flags;
> desc->page_prot = map->page_prot;
> }
>
> @@ -2650,7 +2653,7 @@ static int call_mmap_prepare(struct mmap_state *map,
> map->file_doesnt_need_get = true;
> map->file = desc->vm_file;
> }
> - map->vm_flags = desc->vm_flags;
> + map->vma_flags = desc->vma_flags;
> map->page_prot = desc->page_prot;
> /* User-defined fields. */
> map->vm_ops = desc->vm_ops;
> @@ -2823,7 +2826,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
> return -EINVAL;
>
> /* Map writable and ensure this isn't a sealed memfd. */
> - if (file && is_shared_maywrite(vm_flags)) {
> + if (file && is_shared_maywrite_vm_flags(vm_flags)) {
> int error = mapping_map_writable(file->f_mapping);
>
> if (error)
> diff --git a/mm/vma.h b/mm/vma.h
> index bb7fa5d2bde2..062672df8a65 100644
> --- a/mm/vma.h
> +++ b/mm/vma.h
> @@ -286,8 +286,7 @@ static inline void set_vma_from_desc(struct vm_area_struct *vma,
> vma->vm_pgoff = desc->pgoff;
> if (desc->vm_file != vma->vm_file)
> vma_set_file(vma, desc->vm_file);
> - if (desc->vm_flags != vma->vm_flags)
> - vm_flags_set(vma, desc->vm_flags);
> + vma->flags = desc->vma_flags;
> vma->vm_page_prot = desc->page_prot;
>
> /* User-defined fields. */
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index 2b01794cbd61..2743f12ecf32 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -1009,15 +1009,20 @@ static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> #define vma_desc_clear_flags(desc, ...) \
> vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
>
> -static inline bool is_shared_maywrite(vm_flags_t vm_flags)
> +static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
> {
> return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> (VM_SHARED | VM_MAYWRITE);
> }
>
> +static inline bool is_shared_maywrite(const vma_flags_t *flags)
> +{
> + return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
> +}
> +
> static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
> {
> - return is_shared_maywrite(vma->vm_flags);
> + return is_shared_maywrite(&vma->flags);
> }
>
> static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
From: Tingmao Wang @ 2026-02-09 19:53 UTC (permalink / raw)
To: Mickaël Salaün, Justin Suess, Günther Noack
Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi, Simon Horman, netdev,
Alexander Viro, Christian Brauner
In-Reply-To: <a0ae82d6-8c9f-4b6d-9f7b-a6d38efbf80f@maowtm.org>
On 2/9/26 18:33, Tingmao Wang wrote:
> On 2/9/26 17:51, Mickaël Salaün wrote:
>> On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
>>> [...]
>>> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
>>> index d0511225799b..db9d279b3883 100644
>>> --- a/net/unix/af_unix.c
>>> +++ b/net/unix/af_unix.c
>>> @@ -1226,10 +1226,19 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
>>> if (!S_ISSOCK(inode->i_mode))
>>> goto path_put;
>>>
>>> + err = -ECONNREFUSED;
>>
>> We don't see it in this patch but err is already set to -ECONNREFUSED.
>> This line might be confusing, and unrelated to the goal of this patch,
>> so we should remove it.
>
> I will confess that in a side conversation with Justin previously I
> suggested that for blocks like these it might be better to always assign
> to err, and let the compiler optimize it away, so that when this block is
> moved there is less chances of mistake. (This was relevant in the
> previous context where a move of this hook caused err to be reset,
> resulting in a NULL deference from syzbot)
>
> But of course if the convention in this file is to not do it, or if I have
> missed some reason against doing this, then that's also fine (even though,
> IMHO, personally I think this is better).
>
Actually, looking at this more carefully, Mickaël is right that this
single line addition doesn't have anything to do with the patch itself
(unlike in the diff in the other thread [1] where it is part of a moved
block), so I guess it makes sense to not add this in this patch.
Apologies for any conversation derailment caused here :)
[1]: https://lore.kernel.org/all/e6b6b069-384c-4c45-a56b-fa54b26bc72a@maowtm.org/
^ permalink raw reply
* Re: [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files
From: Liam R. Howlett @ 2026-02-09 19:58 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <a0455ccfe4fdcd1c962c64f76304f612e5662a4e.1769097829.git.lorenzo.stoakes@oracle.com>
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> So far the userland VMA tests have been established as a rough expression
> of what's been possible.
>
> qAdapt it into a more usable form by separating out tests and shared helper
^^^^ Typo
> functions.
>
> Since we test functions that are declared statically in mm/vma.c, we make
> use of the trick of #include'ing kernel C files directly.
>
> In order for the tests to continue to function, we must therefore also
> this way into the tests/ directory.
>
> We try to keep as much shared logic actually modularised into a separate
> compilation unit in shared.c, however the merge_existing() and attach_vma()
> helpers rely on statically declared mm/vma.c functions so these must be
> declared in main.c.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Besides that typo, it looks good.
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> tools/testing/vma/Makefile | 4 +-
> tools/testing/vma/main.c | 55 ++++
> tools/testing/vma/shared.c | 131 ++++++++
> tools/testing/vma/shared.h | 114 +++++++
> tools/testing/vma/{vma.c => tests/merge.c} | 332 +--------------------
> tools/testing/vma/tests/mmap.c | 57 ++++
> tools/testing/vma/tests/vma.c | 39 +++
> tools/testing/vma/vma_internal.h | 9 -
> 8 files changed, 406 insertions(+), 335 deletions(-)
> create mode 100644 tools/testing/vma/main.c
> create mode 100644 tools/testing/vma/shared.c
> create mode 100644 tools/testing/vma/shared.h
> rename tools/testing/vma/{vma.c => tests/merge.c} (82%)
> create mode 100644 tools/testing/vma/tests/mmap.c
> create mode 100644 tools/testing/vma/tests/vma.c
>
> diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> index 66f3831a668f..94133d9d3955 100644
> --- a/tools/testing/vma/Makefile
> +++ b/tools/testing/vma/Makefile
> @@ -6,10 +6,10 @@ default: vma
>
> include ../shared/shared.mk
>
> -OFILES = $(SHARED_OFILES) vma.o maple-shim.o
> +OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> TARGETS = vma
>
> -vma.o: vma.c vma_internal.h ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> +main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
>
> vma: $(OFILES)
> $(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
> diff --git a/tools/testing/vma/main.c b/tools/testing/vma/main.c
> new file mode 100644
> index 000000000000..49b09e97a51f
> --- /dev/null
> +++ b/tools/testing/vma/main.c
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include "shared.h"
> +/*
> + * Directly import the VMA implementation here. Our vma_internal.h wrapper
> + * provides userland-equivalent functionality for everything vma.c uses.
> + */
> +#include "../../../mm/vma_init.c"
> +#include "../../../mm/vma_exec.c"
> +#include "../../../mm/vma.c"
> +
> +/* Tests are included directly so they can test static functions in mm/vma.c. */
> +#include "tests/merge.c"
> +#include "tests/mmap.c"
> +#include "tests/vma.c"
> +
> +/* Helper functions which utilise static kernel functions. */
> +
> +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> +{
> + struct vm_area_struct *vma;
> +
> + vma = vma_merge_existing_range(vmg);
> + if (vma)
> + vma_assert_attached(vma);
> + return vma;
> +}
> +
> +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> +{
> + int res;
> +
> + res = vma_link(mm, vma);
> + if (!res)
> + vma_assert_attached(vma);
> + return res;
> +}
> +
> +/* Main test running which invokes tests/ *.c runners. */
> +int main(void)
> +{
> + int num_tests = 0, num_fail = 0;
> +
> + maple_tree_init();
> + vma_state_init();
> +
> + run_merge_tests(&num_tests, &num_fail);
> + run_mmap_tests(&num_tests, &num_fail);
> + run_vma_tests(&num_tests, &num_fail);
> +
> + printf("%d tests run, %d passed, %d failed.\n",
> + num_tests, num_tests - num_fail, num_fail);
> +
> + return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c
> new file mode 100644
> index 000000000000..bda578cc3304
> --- /dev/null
> +++ b/tools/testing/vma/shared.c
> @@ -0,0 +1,131 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include "shared.h"
> +
> +
> +bool fail_prealloc;
> +unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> +unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> +unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> +
> +const struct vm_operations_struct vma_dummy_vm_ops;
> +struct anon_vma dummy_anon_vma;
> +struct task_struct __current;
> +
> +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags)
> +{
> + struct vm_area_struct *vma = vm_area_alloc(mm);
> +
> + if (vma == NULL)
> + return NULL;
> +
> + vma->vm_start = start;
> + vma->vm_end = end;
> + vma->vm_pgoff = pgoff;
> + vm_flags_reset(vma, vm_flags);
> + vma_assert_detached(vma);
> +
> + return vma;
> +}
> +
> +void detach_free_vma(struct vm_area_struct *vma)
> +{
> + vma_mark_detached(vma);
> + vm_area_free(vma);
> +}
> +
> +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags)
> +{
> + struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> +
> + if (vma == NULL)
> + return NULL;
> +
> + if (attach_vma(mm, vma)) {
> + detach_free_vma(vma);
> + return NULL;
> + }
> +
> + /*
> + * Reset this counter which we use to track whether writes have
> + * begun. Linking to the tree will have caused this to be incremented,
> + * which means we will get a false positive otherwise.
> + */
> + vma->vm_lock_seq = UINT_MAX;
> +
> + return vma;
> +}
> +
> +void reset_dummy_anon_vma(void)
> +{
> + dummy_anon_vma.was_cloned = false;
> + dummy_anon_vma.was_unlinked = false;
> +}
> +
> +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> +{
> + struct vm_area_struct *vma;
> + int count = 0;
> +
> + fail_prealloc = false;
> + reset_dummy_anon_vma();
> +
> + vma_iter_set(vmi, 0);
> + for_each_vma(*vmi, vma) {
> + detach_free_vma(vma);
> + count++;
> + }
> +
> + mtree_destroy(&mm->mm_mt);
> + mm->map_count = 0;
> + return count;
> +}
> +
> +bool vma_write_started(struct vm_area_struct *vma)
> +{
> + int seq = vma->vm_lock_seq;
> +
> + /* We reset after each check. */
> + vma->vm_lock_seq = UINT_MAX;
> +
> + /* The vma_start_write() stub simply increments this value. */
> + return seq > -1;
> +}
> +
> +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc, struct anon_vma *anon_vma)
> +{
> + vma->anon_vma = anon_vma;
> + INIT_LIST_HEAD(&vma->anon_vma_chain);
> + list_add(&avc->same_vma, &vma->anon_vma_chain);
> + avc->anon_vma = vma->anon_vma;
> +}
> +
> +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc)
> +{
> + __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> +}
> +
> +struct task_struct *get_current(void)
> +{
> + return &__current;
> +}
> +
> +unsigned long rlimit(unsigned int limit)
> +{
> + return (unsigned long)-1;
> +}
> +
> +void vma_set_range(struct vm_area_struct *vma,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff)
> +{
> + vma->vm_start = start;
> + vma->vm_end = end;
> + vma->vm_pgoff = pgoff;
> +}
> diff --git a/tools/testing/vma/shared.h b/tools/testing/vma/shared.h
> new file mode 100644
> index 000000000000..6c64211cfa22
> --- /dev/null
> +++ b/tools/testing/vma/shared.h
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#pragma once
> +
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include "generated/bit-length.h"
> +#include "maple-shared.h"
> +#include "vma_internal.h"
> +#include "../../../mm/vma.h"
> +
> +/* Simple test runner. Assumes local num_[fail, tests] counters. */
> +#define TEST(name) \
> + do { \
> + (*num_tests)++; \
> + if (!test_##name()) { \
> + (*num_fail)++; \
> + fprintf(stderr, "Test " #name " FAILED\n"); \
> + } \
> + } while (0)
> +
> +#define ASSERT_TRUE(_expr) \
> + do { \
> + if (!(_expr)) { \
> + fprintf(stderr, \
> + "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> + __FILE__, __LINE__, __FUNCTION__, #_expr); \
> + return false; \
> + } \
> + } while (0)
> +
> +#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> +#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> +#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> +
> +#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> +
> +extern bool fail_prealloc;
> +
> +/* Override vma_iter_prealloc() so we can choose to fail it. */
> +#define vma_iter_prealloc(vmi, vma) \
> + (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> +
> +#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> +
> +extern unsigned long mmap_min_addr;
> +extern unsigned long dac_mmap_min_addr;
> +extern unsigned long stack_guard_gap;
> +
> +extern const struct vm_operations_struct vma_dummy_vm_ops;
> +extern struct anon_vma dummy_anon_vma;
> +extern struct task_struct __current;
> +
> +/*
> + * Helper function which provides a wrapper around a merge existing VMA
> + * operation.
> + *
> + * Declared in main.c as uses static VMA function.
> + */
> +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg);
> +
> +/*
> + * Helper function to allocate a VMA and link it to the tree.
> + *
> + * Declared in main.c as uses static VMA function.
> + */
> +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma);
> +
> +/* Helper function providing a dummy vm_ops->close() method.*/
> +static inline void dummy_close(struct vm_area_struct *)
> +{
> +}
> +
> +/* Helper function to simply allocate a VMA. */
> +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags);
> +
> +/* Helper function to detach and free a VMA. */
> +void detach_free_vma(struct vm_area_struct *vma);
> +
> +/* Helper function to allocate a VMA and link it to the tree. */
> +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags);
> +
> +/*
> + * Helper function to reset the dummy anon_vma to indicate it has not been
> + * duplicated.
> + */
> +void reset_dummy_anon_vma(void);
> +
> +/*
> + * Helper function to remove all VMAs and destroy the maple tree associated with
> + * a virtual address space. Returns a count of VMAs in the tree.
> + */
> +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi);
> +
> +/* Helper function to determine if VMA has had vma_start_write() performed. */
> +bool vma_write_started(struct vm_area_struct *vma);
> +
> +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc, struct anon_vma *anon_vma);
> +
> +/* Provide a simple dummy VMA/anon_vma dummy setup for testing. */
> +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc);
> +
> +/* Helper function to specify a VMA's range. */
> +void vma_set_range(struct vm_area_struct *vma,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff);
> diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/tests/merge.c
> similarity index 82%
> rename from tools/testing/vma/vma.c
> rename to tools/testing/vma/tests/merge.c
> index 93d21bc7e112..3708dc6945b0 100644
> --- a/tools/testing/vma/vma.c
> +++ b/tools/testing/vma/tests/merge.c
> @@ -1,132 +1,5 @@
> // SPDX-License-Identifier: GPL-2.0-or-later
>
> -#include <stdbool.h>
> -#include <stdio.h>
> -#include <stdlib.h>
> -
> -#include "generated/bit-length.h"
> -
> -#include "maple-shared.h"
> -#include "vma_internal.h"
> -
> -/* Include so header guard set. */
> -#include "../../../mm/vma.h"
> -
> -static bool fail_prealloc;
> -
> -/* Then override vma_iter_prealloc() so we can choose to fail it. */
> -#define vma_iter_prealloc(vmi, vma) \
> - (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> -
> -#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> -
> -unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> -unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> -unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> -
> -/*
> - * Directly import the VMA implementation here. Our vma_internal.h wrapper
> - * provides userland-equivalent functionality for everything vma.c uses.
> - */
> -#include "../../../mm/vma_init.c"
> -#include "../../../mm/vma_exec.c"
> -#include "../../../mm/vma.c"
> -
> -const struct vm_operations_struct vma_dummy_vm_ops;
> -static struct anon_vma dummy_anon_vma;
> -
> -#define ASSERT_TRUE(_expr) \
> - do { \
> - if (!(_expr)) { \
> - fprintf(stderr, \
> - "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> - __FILE__, __LINE__, __FUNCTION__, #_expr); \
> - return false; \
> - } \
> - } while (0)
> -#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> -#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> -#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> -
> -#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> -
> -static struct task_struct __current;
> -
> -struct task_struct *get_current(void)
> -{
> - return &__current;
> -}
> -
> -unsigned long rlimit(unsigned int limit)
> -{
> - return (unsigned long)-1;
> -}
> -
> -/* Helper function to simply allocate a VMA. */
> -static struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> - unsigned long start,
> - unsigned long end,
> - pgoff_t pgoff,
> - vm_flags_t vm_flags)
> -{
> - struct vm_area_struct *vma = vm_area_alloc(mm);
> -
> - if (vma == NULL)
> - return NULL;
> -
> - vma->vm_start = start;
> - vma->vm_end = end;
> - vma->vm_pgoff = pgoff;
> - vm_flags_reset(vma, vm_flags);
> - vma_assert_detached(vma);
> -
> - return vma;
> -}
> -
> -/* Helper function to allocate a VMA and link it to the tree. */
> -static int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> -{
> - int res;
> -
> - res = vma_link(mm, vma);
> - if (!res)
> - vma_assert_attached(vma);
> - return res;
> -}
> -
> -static void detach_free_vma(struct vm_area_struct *vma)
> -{
> - vma_mark_detached(vma);
> - vm_area_free(vma);
> -}
> -
> -/* Helper function to allocate a VMA and link it to the tree. */
> -static struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> - unsigned long start,
> - unsigned long end,
> - pgoff_t pgoff,
> - vm_flags_t vm_flags)
> -{
> - struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> -
> - if (vma == NULL)
> - return NULL;
> -
> - if (attach_vma(mm, vma)) {
> - detach_free_vma(vma);
> - return NULL;
> - }
> -
> - /*
> - * Reset this counter which we use to track whether writes have
> - * begun. Linking to the tree will have caused this to be incremented,
> - * which means we will get a false positive otherwise.
> - */
> - vma->vm_lock_seq = UINT_MAX;
> -
> - return vma;
> -}
> -
> /* Helper function which provides a wrapper around a merge new VMA operation. */
> static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> {
> @@ -146,20 +19,6 @@ static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> return vma;
> }
>
> -/*
> - * Helper function which provides a wrapper around a merge existing VMA
> - * operation.
> - */
> -static struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> -{
> - struct vm_area_struct *vma;
> -
> - vma = vma_merge_existing_range(vmg);
> - if (vma)
> - vma_assert_attached(vma);
> - return vma;
> -}
> -
> /*
> * Helper function which provides a wrapper around the expansion of an existing
> * VMA.
> @@ -173,8 +32,8 @@ static int expand_existing(struct vma_merge_struct *vmg)
> * Helper function to reset merge state the associated VMA iterator to a
> * specified new range.
> */
> -static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> - unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> +void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> {
> vma_iter_set(vmg->vmi, start);
>
> @@ -197,8 +56,8 @@ static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
>
> /* Helper function to set both the VMG range and its anon_vma. */
> static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long start,
> - unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> - struct anon_vma *anon_vma)
> + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> + struct anon_vma *anon_vma)
> {
> vmg_set_range(vmg, start, end, pgoff, vm_flags);
> vmg->anon_vma = anon_vma;
> @@ -211,10 +70,9 @@ static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long s
> * VMA, link it to the maple tree and return it.
> */
> static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> - struct vma_merge_struct *vmg,
> - unsigned long start, unsigned long end,
> - pgoff_t pgoff, vm_flags_t vm_flags,
> - bool *was_merged)
> + struct vma_merge_struct *vmg, unsigned long start,
> + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> + bool *was_merged)
> {
> struct vm_area_struct *merged;
>
> @@ -234,72 +92,6 @@ static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> return alloc_and_link_vma(mm, start, end, pgoff, vm_flags);
> }
>
> -/*
> - * Helper function to reset the dummy anon_vma to indicate it has not been
> - * duplicated.
> - */
> -static void reset_dummy_anon_vma(void)
> -{
> - dummy_anon_vma.was_cloned = false;
> - dummy_anon_vma.was_unlinked = false;
> -}
> -
> -/*
> - * Helper function to remove all VMAs and destroy the maple tree associated with
> - * a virtual address space. Returns a count of VMAs in the tree.
> - */
> -static int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> -{
> - struct vm_area_struct *vma;
> - int count = 0;
> -
> - fail_prealloc = false;
> - reset_dummy_anon_vma();
> -
> - vma_iter_set(vmi, 0);
> - for_each_vma(*vmi, vma) {
> - detach_free_vma(vma);
> - count++;
> - }
> -
> - mtree_destroy(&mm->mm_mt);
> - mm->map_count = 0;
> - return count;
> -}
> -
> -/* Helper function to determine if VMA has had vma_start_write() performed. */
> -static bool vma_write_started(struct vm_area_struct *vma)
> -{
> - int seq = vma->vm_lock_seq;
> -
> - /* We reset after each check. */
> - vma->vm_lock_seq = UINT_MAX;
> -
> - /* The vma_start_write() stub simply increments this value. */
> - return seq > -1;
> -}
> -
> -/* Helper function providing a dummy vm_ops->close() method.*/
> -static void dummy_close(struct vm_area_struct *)
> -{
> -}
> -
> -static void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> - struct anon_vma_chain *avc,
> - struct anon_vma *anon_vma)
> -{
> - vma->anon_vma = anon_vma;
> - INIT_LIST_HEAD(&vma->anon_vma_chain);
> - list_add(&avc->same_vma, &vma->anon_vma_chain);
> - avc->anon_vma = vma->anon_vma;
> -}
> -
> -static void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> - struct anon_vma_chain *avc)
> -{
> - __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> -}
> -
> static bool test_simple_merge(void)
> {
> struct vm_area_struct *vma;
> @@ -1616,39 +1408,6 @@ static bool test_merge_extend(void)
> return true;
> }
>
> -static bool test_copy_vma(void)
> -{
> - vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> - struct mm_struct mm = {};
> - bool need_locks = false;
> - VMA_ITERATOR(vmi, &mm, 0);
> - struct vm_area_struct *vma, *vma_new, *vma_next;
> -
> - /* Move backwards and do not merge. */
> -
> - vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> - vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> - ASSERT_NE(vma_new, vma);
> - ASSERT_EQ(vma_new->vm_start, 0);
> - ASSERT_EQ(vma_new->vm_end, 0x2000);
> - ASSERT_EQ(vma_new->vm_pgoff, 0);
> - vma_assert_attached(vma_new);
> -
> - cleanup_mm(&mm, &vmi);
> -
> - /* Move a VMA into position next to another and merge the two. */
> -
> - vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> - vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> - vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> - vma_assert_attached(vma_new);
> -
> - ASSERT_EQ(vma_new, vma_next);
> -
> - cleanup_mm(&mm, &vmi);
> - return true;
> -}
> -
> static bool test_expand_only_mode(void)
> {
> vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> @@ -1689,73 +1448,8 @@ static bool test_expand_only_mode(void)
> return true;
> }
>
> -static bool test_mmap_region_basic(void)
> -{
> - struct mm_struct mm = {};
> - unsigned long addr;
> - struct vm_area_struct *vma;
> - VMA_ITERATOR(vmi, &mm, 0);
> -
> - current->mm = &mm;
> -
> - /* Map at 0x300000, length 0x3000. */
> - addr = __mmap_region(NULL, 0x300000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x300, NULL);
> - ASSERT_EQ(addr, 0x300000);
> -
> - /* Map at 0x250000, length 0x3000. */
> - addr = __mmap_region(NULL, 0x250000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x250, NULL);
> - ASSERT_EQ(addr, 0x250000);
> -
> - /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> - addr = __mmap_region(NULL, 0x303000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x303, NULL);
> - ASSERT_EQ(addr, 0x303000);
> -
> - /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> - addr = __mmap_region(NULL, 0x24d000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x24d, NULL);
> - ASSERT_EQ(addr, 0x24d000);
> -
> - ASSERT_EQ(mm.map_count, 2);
> -
> - for_each_vma(vmi, vma) {
> - if (vma->vm_start == 0x300000) {
> - ASSERT_EQ(vma->vm_end, 0x306000);
> - ASSERT_EQ(vma->vm_pgoff, 0x300);
> - } else if (vma->vm_start == 0x24d000) {
> - ASSERT_EQ(vma->vm_end, 0x253000);
> - ASSERT_EQ(vma->vm_pgoff, 0x24d);
> - } else {
> - ASSERT_FALSE(true);
> - }
> - }
> -
> - cleanup_mm(&mm, &vmi);
> - return true;
> -}
> -
> -int main(void)
> +static void run_merge_tests(int *num_tests, int *num_fail)
> {
> - int num_tests = 0, num_fail = 0;
> -
> - maple_tree_init();
> - vma_state_init();
> -
> -#define TEST(name) \
> - do { \
> - num_tests++; \
> - if (!test_##name()) { \
> - num_fail++; \
> - fprintf(stderr, "Test " #name " FAILED\n"); \
> - } \
> - } while (0)
> -
> /* Very simple tests to kick the tyres. */
> TEST(simple_merge);
> TEST(simple_modify);
> @@ -1771,15 +1465,5 @@ int main(void)
> TEST(dup_anon_vma);
> TEST(vmi_prealloc_fail);
> TEST(merge_extend);
> - TEST(copy_vma);
> TEST(expand_only_mode);
> -
> - TEST(mmap_region_basic);
> -
> -#undef TEST
> -
> - printf("%d tests run, %d passed, %d failed.\n",
> - num_tests, num_tests - num_fail, num_fail);
> -
> - return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> }
> diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c
> new file mode 100644
> index 000000000000..bded4ecbe5db
> --- /dev/null
> +++ b/tools/testing/vma/tests/mmap.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +static bool test_mmap_region_basic(void)
> +{
> + struct mm_struct mm = {};
> + unsigned long addr;
> + struct vm_area_struct *vma;
> + VMA_ITERATOR(vmi, &mm, 0);
> +
> + current->mm = &mm;
> +
> + /* Map at 0x300000, length 0x3000. */
> + addr = __mmap_region(NULL, 0x300000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x300, NULL);
> + ASSERT_EQ(addr, 0x300000);
> +
> + /* Map at 0x250000, length 0x3000. */
> + addr = __mmap_region(NULL, 0x250000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x250, NULL);
> + ASSERT_EQ(addr, 0x250000);
> +
> + /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> + addr = __mmap_region(NULL, 0x303000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x303, NULL);
> + ASSERT_EQ(addr, 0x303000);
> +
> + /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> + addr = __mmap_region(NULL, 0x24d000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x24d, NULL);
> + ASSERT_EQ(addr, 0x24d000);
> +
> + ASSERT_EQ(mm.map_count, 2);
> +
> + for_each_vma(vmi, vma) {
> + if (vma->vm_start == 0x300000) {
> + ASSERT_EQ(vma->vm_end, 0x306000);
> + ASSERT_EQ(vma->vm_pgoff, 0x300);
> + } else if (vma->vm_start == 0x24d000) {
> + ASSERT_EQ(vma->vm_end, 0x253000);
> + ASSERT_EQ(vma->vm_pgoff, 0x24d);
> + } else {
> + ASSERT_FALSE(true);
> + }
> + }
> +
> + cleanup_mm(&mm, &vmi);
> + return true;
> +}
> +
> +static void run_mmap_tests(int *num_tests, int *num_fail)
> +{
> + TEST(mmap_region_basic);
> +}
> diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
> new file mode 100644
> index 000000000000..6d9775aee243
> --- /dev/null
> +++ b/tools/testing/vma/tests/vma.c
> @@ -0,0 +1,39 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +static bool test_copy_vma(void)
> +{
> + vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> + struct mm_struct mm = {};
> + bool need_locks = false;
> + VMA_ITERATOR(vmi, &mm, 0);
> + struct vm_area_struct *vma, *vma_new, *vma_next;
> +
> + /* Move backwards and do not merge. */
> +
> + vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> + vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> + ASSERT_NE(vma_new, vma);
> + ASSERT_EQ(vma_new->vm_start, 0);
> + ASSERT_EQ(vma_new->vm_end, 0x2000);
> + ASSERT_EQ(vma_new->vm_pgoff, 0);
> + vma_assert_attached(vma_new);
> +
> + cleanup_mm(&mm, &vmi);
> +
> + /* Move a VMA into position next to another and merge the two. */
> +
> + vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> + vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> + vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> + vma_assert_attached(vma_new);
> +
> + ASSERT_EQ(vma_new, vma_next);
> +
> + cleanup_mm(&mm, &vmi);
> + return true;
> +}
> +
> +static void run_vma_tests(int *num_tests, int *num_fail)
> +{
> + TEST(copy_vma);
> +}
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index 2743f12ecf32..b48ebae3927d 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -1127,15 +1127,6 @@ static inline void mapping_allow_writable(struct address_space *mapping)
> atomic_inc(&mapping->i_mmap_writable);
> }
>
> -static inline void vma_set_range(struct vm_area_struct *vma,
> - unsigned long start, unsigned long end,
> - pgoff_t pgoff)
> -{
> - vma->vm_start = start;
> - vma->vm_end = end;
> - vma->vm_pgoff = pgoff;
> -}
> -
> static inline
> struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
> {
> --
> 2.52.0
>
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Mickaël Salaün @ 2026-02-09 20:20 UTC (permalink / raw)
To: Tingmao Wang
Cc: Günther Noack, Günther Noack, Justin Suess, Paul Moore,
John Johansen, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi, Matthieu Buffet, linux-security-module
In-Reply-To: <c33926c5-3c7a-40d8-b910-ac99b43576ff@maowtm.org>
On Sun, Feb 08, 2026 at 08:48:22PM +0000, Tingmao Wang wrote:
> On 2/8/26 20:37, Günther Noack wrote:
> > On Sun, Feb 08, 2026 at 02:57:10AM +0000, Tingmao Wang wrote:
> >> On 2/5/26 10:27, Mickaël Salaün wrote:
> >>> On Thu, Feb 05, 2026 at 09:02:19AM +0100, Günther Noack wrote:
> >>>> [...]
> >>>>
> >>>> The implementation of this approach would be that we would have to
> >>>> join the functionality from the scoped and FS-based patch set, but
> >>>> without introducing the LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET flag in
> >>>> the UAPI.
> >>>
> >>> Right, this looks good to me. We'll need to sync both patch series and
> >>> remove the scope flag from UAPI. I'll let you and Tingmao work together
> >>> for the next series. The "IPC scoping" documentation section should
> >>> mention LANDLOCK_ACCESS_FS_RESOLVE_UNIX even if it's not a scope flag.
> >>
> >> This sounds good to me. I'm not sure how much code we can reuse out of
> >> the existing LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET patchset - but I think
> >> the selftest patches could still largely be useful (after changing e.g.
> >> create_scoped_domain() to use the RESOLVE_UNIX fs access instead of the
> >> scope bit for pathname sockets). The fs-based rules (i.e. "exceptions")
> >> can then be tested separately from the scope tests (and would also check
> >> for things like path being different across mount namespaces etc).
> >>
> >> Günther, feel free to take anything out of the existing scope series, if
> >> you feel it would be useful. Also let me know if you would like me to
> >> help with any part of the RESOLVE_UNIX series if you feel that would be
> >> useful (but you don't have to if not).
> >
> > Thank you, Tingmao!
> >
> > So far, the selftests that I already had in fs_test.c were
> > straightforward to extend so that they cover the new cases. I had a
> > look at your patch set, but found the scoping tests difficult to port
> > to fs_test.c
>
> I was thinking that the tests in scoped_abstract_unix_test.c could be
> extended to test scoping of pathname UNIX sockets as well (otherwise
> wouldn't you have to write another instance of the scoped_domains test
> based on scoped_base_variants.h, whether you put it in fs_test.c or
> somewhere else?)
>
> And if you think that is sensible, then I'm hoping that patch 4,5,6 of the
> series would be mostly useful. But it's up to you :)
I agree that these 3 patches should be integrated (see my other reply on
Günther's v4).
>
> > , but I'll double check that we don't miss anything.
> > Either way, I'll make sure that you'll get appropriate credit for
> > it. :)
>
> Thanks!
>
> Tingmao
>
> > ...
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox