Re: [PATCH RFC 3/3] mnt_idmapping: inline all low-level helpers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 16 Apr 2025 at 06:17, Christian Brauner <brauner@xxxxxxxxxx> wrote:
>
> Let's inline all low-level helpers and use likely()/unlikely() to help
> the compiler along.

Hmm. This looks like it might be a mistake - code generation will
probably not be great, because you still end up calling a real
function for some of the cases (ie from_kuid() in the actual real
translation case), so all the register allocation etc issues with
having a function call largely do remain.

Yes, it inlines things into generic_permission(), and that will avoid
the function call overhead for the common case (good), but it also
does make for bigger code generation. And it doesn't actually *change*
the code - it ends up doing all the same accesses, just the
instruction flow is slightly different.

So I think you'd actually be better off with *just* the IOP_USERNS
patch, and only inlining *that* fast-path case, and keep the other
cases out-of-line.

IOW - instead of only checking IOP_USERNS only in i_user_ns() and
making it return 'init_user_ns' without doing the pointer following, I
think you should make just our *existing* inlined i_uid_into_vfsuid()
helper be the minimal inlined wrapper around just the IOP_USERNS
logic.

Because right now the problem with i_uid_into_vfsuid() is two-fold

 - it does that pointer chasing by calling i_user_ns(inode)

 - it then calls make_vfsuid() which does lots of pointless extra work
in the common case

and I think both should be fixed.

Btw, make_vfsuid() itself is kind of odd. It does:

        if (idmap == &nop_mnt_idmap)
                return VFSUIDT_INIT(kuid);
        if (idmap == &invalid_mnt_idmap)
                return INVALID_VFSUID;
        if (initial_idmapping(fs_userns))
                uid = __kuid_val(kuid);
        else
                uid = from_kuid(fs_userns, kuid);
        if (uid == (uid_t)-1)
                return INVALID_VFSUID;
        return VFSUIDT_INIT_RAW(map_id_down(&idmap->uid_map, uid));

and honestly, that looks just horrendous for the actual simple cases.
I think it's a historical accident, but the

                return VFSUIDT_INIT(kuid);

and the

                uid = __kuid_val(kuid);
        ....
        return VFSUIDT_INIT_RAW(map_id_down(&idmap->uid_map, uid));

things are actually the same exact "no mapping" code for the case we
care about most. We shouldn't even do that

        if (uid == (uid_t)-1)
                return INVALID_VFSUID;

case at all for that case, because the no-mapping situation is that
INVALID_VFSUID *is* (uid_t)-1, so all of this is entirely pointless.

So I think the inlined fast-case should be that

        if (idmap == &nop_mnt_idmap || initial_idmapping(fs_userns))
                return VFSUIDT_INIT(kuid);

code, and then the 'initial_idmapping()' thing should check the
IOP_USERNS bit explicitly, and never use the i_user_ns() helper at all
etc.

That case should then be "likely()", and the rest can remain out-of-line.

IOW: instead of inlining all the helpers, just make the *one* helper
that we already have (and is already a trivial inline function) be
much more targeted, and make that fast-case much more explicit.

Hmm?

                   Linus




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux