]> www.infradead.org Git - users/hch/misc.git/commitdiff
fs: hpfs: Avoid multiple -Wflex-array-member-not-at-end warnings
authorGustavo A. R. Silva <gustavoars@kernel.org>
Mon, 11 Aug 2025 13:00:12 +0000 (22:00 +0900)
committerMikulas Patocka <mpatocka@redhat.com>
Mon, 8 Sep 2025 14:28:38 +0000 (16:28 +0200)
-Wflex-array-member-not-at-end was introduced in GCC-14, and we are
getting ready to enable it, globally.

So, in order to avoid ending up with a flexible-array member in the
middle of other structs, we use the `struct_group_tagged()` helper
to create a new tagged `struct bplus_header_fixed`. This structure
groups together all the members of the flexible `struct bplus_header`
except the flexible array.

As a result, the array is effectively separated from the rest of the
members without modifying the memory layout of the flexible structure.
We then change the type of the middle struct member currently causing
trouble from `struct bplus_header` to `struct bplus_header_fixed`.

We also want to ensure that when new members need to be added to the
flexible structure, they are always included within the newly created
tagged struct. For this, we use `static_assert()`. This ensures that the
memory layout for both the flexible structure and the new tagged struct
is the same after any changes.

This approach avoids having to implement `struct bplus_header_fixed`
as a completely separate structure, thus preventing having to maintain
two independent but basically identical structures, closing the door
to potential bugs in the future.

We also use `container_of()` (via a wrapper) whenever we need to retrieve
a pointer to the flexible structure, through which we can access the
flexible-array member, if necessary.

So, with these changes, fix 26 of the following type of warnings:
fs/hpfs/hpfs.h:456:23: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
fs/hpfs/hpfs.h:498:23: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
fs/hpfs/anode.c
fs/hpfs/ea.c
fs/hpfs/file.c
fs/hpfs/hpfs.h
fs/hpfs/map.c

index c14c9a035ee0c0bea94d8b441a4fb0e6934d19d6..a4f5321eafaee9f57e13261a225acb8cfa29b076 100644 (file)
@@ -27,7 +27,7 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
                                a = le32_to_cpu(btree->u.internal[i].down);
                                brelse(bh);
                                if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
-                               btree = &anode->btree;
+                               btree = GET_BTREE_PTR(&anode->btree);
                                goto go_down;
                        }
                hpfs_error(s, "sector %08x not found in internal anode %08x", sec, a);
@@ -69,12 +69,13 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
        int n;
        unsigned fs;
        int c1, c2 = 0;
+
        if (fnod) {
                if (!(fnode = hpfs_map_fnode(s, node, &bh))) return -1;
-               btree = &fnode->btree;
+               btree = GET_BTREE_PTR(&fnode->btree);
        } else {
                if (!(anode = hpfs_map_anode(s, node, &bh))) return -1;
-               btree = &anode->btree;
+               btree = GET_BTREE_PTR(&anode->btree);
        }
        a = node;
        go_down:
@@ -91,7 +92,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                if (hpfs_sb(s)->sb_chk)
                        if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1;
                if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
-               btree = &anode->btree;
+               btree = GET_BTREE_PTR(&anode->btree);
                goto go_down;
        }
        if (n >= 0) {
@@ -151,7 +152,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                }
                brelse(bh);
                bh = bh1;
-               btree = &anode->btree;
+               btree = GET_BTREE_PTR(&anode->btree);
        }
        btree->n_free_nodes--; n = btree->n_used_nodes++;
        le16_add_cpu(&btree->first_free, 12);
@@ -168,10 +169,10 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                        if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1;
                if (up != node || !fnod) {
                        if (!(anode = hpfs_map_anode(s, up, &bh))) return -1;
-                       btree = &anode->btree;
+                       btree = GET_BTREE_PTR(&anode->btree);
                } else {
                        if (!(fnode = hpfs_map_fnode(s, up, &bh))) return -1;
-                       btree = &fnode->btree;
+                       btree = GET_BTREE_PTR(&fnode->btree);
                }
                if (btree->n_free_nodes) {
                        btree->n_free_nodes--; n = btree->n_used_nodes++;
@@ -206,8 +207,8 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                        anode->btree.n_used_nodes = 1;
                        anode->btree.n_free_nodes = 59;
                        anode->btree.first_free = cpu_to_le16(16);
-                       anode->btree.u.internal[0].down = cpu_to_le32(a);
-                       anode->btree.u.internal[0].file_secno = cpu_to_le32(-1);
+                       GET_BTREE_PTR(&anode->btree)->u.internal[0].down = cpu_to_le32(a);
+                       GET_BTREE_PTR(&anode->btree)->u.internal[0].file_secno = cpu_to_le32(-1);
                        mark_buffer_dirty(bh);
                        brelse(bh);
                        if ((anode = hpfs_map_anode(s, a, &bh))) {
@@ -229,20 +230,20 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
                        brelse(bh2);
                        return -1;
                }
-               btree = &anode->btree;
+               btree = GET_BTREE_PTR(&anode->btree);
        } else {
                if (!(fnode = hpfs_map_fnode(s, node, &bh))) {
                        brelse(bh2);
                        return -1;
                }
-               btree = &fnode->btree;
+               btree = GET_BTREE_PTR(&fnode->btree);
        }
        ranode->up = cpu_to_le32(node);
        memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free));
        if (fnod)
                ranode->btree.flags |= BP_fnode_parent;
-       ranode->btree.n_free_nodes = (bp_internal(&ranode->btree) ? 60 : 40) - ranode->btree.n_used_nodes;
-       if (bp_internal(&ranode->btree)) for (n = 0; n < ranode->btree.n_used_nodes; n++) {
+       GET_BTREE_PTR(&ranode->btree)->n_free_nodes = (bp_internal(GET_BTREE_PTR(&ranode->btree)) ? 60 : 40) - GET_BTREE_PTR(&ranode->btree)->n_used_nodes;
+       if (bp_internal(GET_BTREE_PTR(&ranode->btree))) for (n = 0; n < GET_BTREE_PTR(&ranode->btree)->n_used_nodes; n++) {
                struct anode *unode;
                if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) {
                        unode->up = cpu_to_le32(ra);
@@ -291,7 +292,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
                        if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1"))
                                return;
                if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
-               btree1 = &anode->btree;
+               btree1 = GET_BTREE_PTR(&anode->btree);
                level++;
                pos = 0;
        }
@@ -307,7 +308,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
        ano = le32_to_cpu(anode->up);
        if (--level) {
                if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
-               btree1 = &anode->btree;
+               btree1 = GET_BTREE_PTR(&anode->btree);
        } else btree1 = btree;
        for (i = 0; i < btree1->n_used_nodes; i++) {
                if (le32_to_cpu(btree1->u.internal[i].down) == oano) {
@@ -332,7 +333,7 @@ static secno anode_lookup(struct super_block *s, anode_secno a, unsigned sec)
        struct anode *anode;
        struct buffer_head *bh;
        if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
-       return hpfs_bplus_lookup(s, NULL, &anode->btree, sec, bh);
+       return hpfs_bplus_lookup(s, NULL, GET_BTREE_PTR(&anode->btree), sec, bh);
 }
 
 int hpfs_ea_read(struct super_block *s, secno a, int ano, unsigned pos,
@@ -388,7 +389,7 @@ void hpfs_ea_remove(struct super_block *s, secno a, int ano, unsigned len)
        struct buffer_head *bh;
        if (ano) {
                if (!(anode = hpfs_map_anode(s, a, &bh))) return;
-               hpfs_remove_btree(s, &anode->btree);
+               hpfs_remove_btree(s, GET_BTREE_PTR(&anode->btree));
                brelse(bh);
                hpfs_free_sectors(s, a, 1);
        } else hpfs_free_sectors(s, a, (len + 511) >> 9);
@@ -407,10 +408,10 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
        int c1, c2 = 0;
        if (fno) {
                if (!(fnode = hpfs_map_fnode(s, f, &bh))) return;
-               btree = &fnode->btree;
+               btree = GET_BTREE_PTR(&fnode->btree);
        } else {
                if (!(anode = hpfs_map_anode(s, f, &bh))) return;
-               btree = &anode->btree;
+               btree = GET_BTREE_PTR(&anode->btree);
        }
        if (!secs) {
                hpfs_remove_btree(s, btree);
@@ -448,7 +449,7 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
                        if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree"))
                                return;
                if (!(anode = hpfs_map_anode(s, node, &bh))) return;
-               btree = &anode->btree;
+               btree = GET_BTREE_PTR(&anode->btree);
        }       
        nodes = btree->n_used_nodes + btree->n_free_nodes;
        for (i = 0; i < btree->n_used_nodes; i++)
@@ -485,7 +486,7 @@ void hpfs_remove_fnode(struct super_block *s, fnode_secno fno)
        struct extended_attribute *ea;
        struct extended_attribute *ea_end;
        if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return;
-       if (!fnode_is_dir(fnode)) hpfs_remove_btree(s, &fnode->btree);
+       if (!fnode_is_dir(fnode)) hpfs_remove_btree(s, GET_BTREE_PTR(&fnode->btree));
        else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno));
        ea_end = fnode_end_ea(fnode);
        for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
index 102ba18e561f6fbce6bcbeda94acd62a1300e211..2149d3ca530b6f635ff884988383bdde21be5e7a 100644 (file)
@@ -41,7 +41,7 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len)
                struct buffer_head *bh;
                struct anode *anode;
                if ((anode = hpfs_map_anode(s, a, &bh))) {
-                       hpfs_remove_btree(s, &anode->btree);
+                       hpfs_remove_btree(s, GET_BTREE_PTR(&anode->btree));
                        brelse(bh);
                        hpfs_free_sectors(s, a, 1);
                }
index 263b5bbe1849555263143894214c5388e2ca7539..29e876705369ba7e9c8dd61b6490f74877d9f30d 100644 (file)
@@ -51,7 +51,9 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno, unsigned *n_sec
                return hpfs_inode->i_disk_sec + n;
        }
        if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
-       disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh);
+       disk_secno = hpfs_bplus_lookup(inode->i_sb, inode,
+                                      GET_BTREE_PTR(&fnode->btree),
+                                      file_secno, bh);
        if (disk_secno == -1) return 0;
        if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0;
        n = file_secno - hpfs_inode->i_file_sec;
index 281dec8f636b326796edda49857cd33c82dd24fb..353f73c914d9d52be85a5166382505f5add96e75 100644 (file)
@@ -394,27 +394,45 @@ enum {
        BP_binary_search = 0x40,
        BP_internal = 0x80
 };
+
+/**
+ * GET_BTREE_PTR() - Get a pointer to struct bplus_header
+ *
+ * Wrapper around container_of() to retrieve a pointer to struct
+ * bplus_header from a pointer to struct bplus_header_fixed.
+ *
+ * @ptr: Pointer to struct bplus_header_fixed.
+ *
+ */
+#define GET_BTREE_PTR(ptr) \
+       container_of(ptr, struct bplus_header, __hdr)
+
 struct bplus_header
 {
-  u8 flags;                            /* bit 0 - high bit of first free entry offset
+       /* New members MUST be added within the struct_group() macro below. */
+       struct_group_tagged(bplus_header_fixed, __hdr,
+               u8 flags;               /* bit 0 - high bit of first free entry offset
                                           bit 5 - we're pointed to by an fnode,
                                           the data btree or some ea or the
                                           main ea bootage pointer ea_secno
                                           bit 6 - suggest binary search (unused)
                                           bit 7 - 1 -> (internal) tree of anodes
                                                   0 -> (leaf) list of extents */
-  u8 fill[3];
-  u8 n_free_nodes;                     /* free nodes in following array */
-  u8 n_used_nodes;                     /* used nodes in following array */
-  __le16 first_free;                   /* offset from start of header to
+               u8 fill[3];
+               u8 n_free_nodes;        /* free nodes in following array */
+               u8 n_used_nodes;        /* used nodes in following array */
+               __le16 first_free;      /* offset from start of header to
                                           first free node in array */
-  union {
-       /* (internal) 2-word entries giving subtree pointers */
-       DECLARE_FLEX_ARRAY(struct bplus_internal_node, internal);
-       /* (external) 3-word entries giving sector runs */
-       DECLARE_FLEX_ARRAY(struct bplus_leaf_node, external);
-  } u;
+       );
+       union {
+               /* (internal) 2-word entries giving subtree pointers */
+               DECLARE_FLEX_ARRAY(struct bplus_internal_node, internal);
+               /* (external) 3-word entries giving sector runs */
+               DECLARE_FLEX_ARRAY(struct bplus_leaf_node, external);
+       } u;
 };
+static_assert(offsetof(struct bplus_header, u.internal) == sizeof(struct bplus_header_fixed),
+             "struct member likely outside of struct_group_tagged()");
 
 static inline bool bp_internal(struct bplus_header *bp)
 {
@@ -453,7 +471,7 @@ struct fnode
   __le16 flags;                                /* bit 1 set -> ea_secno is an anode */
                                        /* bit 8 set -> directory.  first & only extent
                                           points to dnode. */
-  struct bplus_header btree;           /* b+ tree, 8 extents or 12 subtrees */
+  struct bplus_header_fixed btree;     /* b+ tree, 8 extents or 12 subtrees */
   union {
     struct bplus_leaf_node external[8];
     struct bplus_internal_node internal[12];
@@ -495,7 +513,7 @@ struct anode
   __le32 self;                         /* pointer to this anode */
   __le32 up;                           /* parent anode or fnode */
 
-  struct bplus_header btree;           /* b+tree, 40 extents or 60 subtrees */
+  struct bplus_header_fixed btree;     /* b+tree, 40 extents or 60 subtrees */
   union {
     struct bplus_leaf_node external[40];
     struct bplus_internal_node internal[60];
index ecd9fccd166316b10f54f2919cee01762b0cfbfd..be73233502f8151ab40315a3475eee1d672952af 100644 (file)
@@ -178,14 +178,14 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea
                        }
                        if (!fnode_is_dir(fnode)) {
                                if ((unsigned)fnode->btree.n_used_nodes + (unsigned)fnode->btree.n_free_nodes !=
-                                   (bp_internal(&fnode->btree) ? 12 : 8)) {
+                                   (bp_internal(GET_BTREE_PTR(&fnode->btree)) ? 12 : 8)) {
                                        hpfs_error(s,
                                           "bad number of nodes in fnode %08lx",
                                            (unsigned long)ino);
                                        goto bail;
                                }
                                if (le16_to_cpu(fnode->btree.first_free) !=
-                                   8 + fnode->btree.n_used_nodes * (bp_internal(&fnode->btree) ? 8 : 12)) {
+                                   8 + fnode->btree.n_used_nodes * (bp_internal(GET_BTREE_PTR(&fnode->btree)) ? 8 : 12)) {
                                        hpfs_error(s,
                                            "bad first_free pointer in fnode %08lx",
                                            (unsigned long)ino);
@@ -233,12 +233,12 @@ struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buff
                                goto bail;
                        }
                        if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes !=
-                           (bp_internal(&anode->btree) ? 60 : 40)) {
+                           (bp_internal(GET_BTREE_PTR(&anode->btree)) ? 60 : 40)) {
                                hpfs_error(s, "bad number of nodes in anode %08x", ano);
                                goto bail;
                        }
                        if (le16_to_cpu(anode->btree.first_free) !=
-                           8 + anode->btree.n_used_nodes * (bp_internal(&anode->btree) ? 8 : 12)) {
+                           8 + anode->btree.n_used_nodes * (bp_internal(GET_BTREE_PTR(&anode->btree)) ? 8 : 12)) {
                                hpfs_error(s, "bad first_free pointer in anode %08x", ano);
                                goto bail;
                        }