]> git.dujemihanovic.xyz Git - linux.git/commitdiff
uidgid: make sure we fit into one cacheline
authorChristian Brauner <brauner@kernel.org>
Tue, 10 Sep 2024 08:16:39 +0000 (10:16 +0200)
committerChristian Brauner <brauner@kernel.org>
Thu, 12 Sep 2024 10:16:09 +0000 (12:16 +0200)
When I expanded uidgid mappings I intended for a struct uid_gid_map to
fit into a single cacheline on x86 as they tend to be pretty
performance sensitive (idmapped mounts etc). But a 4 byte hole was added
that brought it over 64 bytes. Fix that by adding the static extent
array and the extent counter into a substruct. C's type punning for
unions guarantees that we can access ->nr_extents even if the last
written to member wasn't within the same object. This is also what we
rely on in struct_group() and friends. This of course relies on
non-strict aliasing which we don't do.

99) If the member used to read the contents of a union object is not the
    same as the member last used to store a value in the object, the
    appropriate part of the object representation of the value is
    reinterpreted as an object representation in the new type as
    described in 6.2.6 (a process sometimes called "type punning").

Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf
Link: https://lore.kernel.org/r/20240910-work-uid_gid_map-v1-1-e6bc761363ed@kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
include/linux/user_namespace.h
kernel/user.c

index 6030a823561735bf5c8c3329d26023735b63b638..3625096d5f8517b26411c5adebe63aa092cfa3b1 100644 (file)
@@ -21,9 +21,11 @@ struct uid_gid_extent {
 };
 
 struct uid_gid_map { /* 64 bytes -- 1 cache line */
-       u32 nr_extents;
        union {
-               struct uid_gid_extent extent[UID_GID_MAP_MAX_BASE_EXTENTS];
+               struct {
+                       struct uid_gid_extent extent[UID_GID_MAP_MAX_BASE_EXTENTS];
+                       u32 nr_extents;
+               };
                struct {
                        struct uid_gid_extent *forward;
                        struct uid_gid_extent *reverse;
index aa1162deafe49f6dfd7ce9ea33d27fcc0db67add..f46b1d41163b205d21729b482f84154f9d7a5f57 100644 (file)
@@ -36,33 +36,33 @@ EXPORT_SYMBOL_GPL(init_binfmt_misc);
  */
 struct user_namespace init_user_ns = {
        .uid_map = {
-               .nr_extents = 1,
                {
                        .extent[0] = {
                                .first = 0,
                                .lower_first = 0,
                                .count = 4294967295U,
                        },
+                       .nr_extents = 1,
                },
        },
        .gid_map = {
-               .nr_extents = 1,
                {
                        .extent[0] = {
                                .first = 0,
                                .lower_first = 0,
                                .count = 4294967295U,
                        },
+                       .nr_extents = 1,
                },
        },
        .projid_map = {
-               .nr_extents = 1,
                {
                        .extent[0] = {
                                .first = 0,
                                .lower_first = 0,
                                .count = 4294967295U,
                        },
+                       .nr_extents = 1,
                },
        },
        .ns.count = REFCOUNT_INIT(3),