diff mbox series

[1/8,next] block: blk_types.h: Use struct_group_tagged() in flex struct bio

Message ID ccf673b997e771430b7570fb8a6dfc11d07a2bde.1739957534.git.gustavoars@kernel.org (mailing list archive)
State New
Headers show
Series Avoid a couple hundred -Wflex-array-member-not-at-end warnings | expand

Commit Message

Gustavo A. R. Silva Feb. 24, 2025, 9:55 a.m. UTC
Use the `struct_group_tagged()` helper to create a new tagged
`struct bio_hdr`. This structure groups together all the members of
the flexible `struct bio` except the flexible array `bi_inline_vecs`.
As a result, the array is effectively separated from the rest of the
members without modifying the memory layout of the flexible structure.

This new tagged struct will be used to fix problematic declarations
of middle-flex-arrays in composite structs, like these[1][2][3], for
instance.

[1] https://git.kernel.org/linus/a7e8997ae18c42d3
[2] https://git.kernel.org/linus/c1ddb29709e675ea
[3] https://git.kernel.org/linus/57be3d3562ca4aa6

Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
 include/linux/blk_types.h | 84 ++++++++++++++++++++-------------------
 1 file changed, 44 insertions(+), 40 deletions(-)

Comments

Christoph Hellwig Feb. 24, 2025, 4:39 p.m. UTC | #1
On Mon, Feb 24, 2025 at 08:25:08PM +1030, Gustavo A. R. Silva wrote:
> Use the `struct_group_tagged()` helper to create a new tagged
> `struct bio_hdr`. This structure groups together all the members of
> the flexible `struct bio` except the flexible array `bi_inline_vecs`.
> As a result, the array is effectively separated from the rest of the
> members without modifying the memory layout of the flexible structure.
> 
> This new tagged struct will be used to fix problematic declarations
> of middle-flex-arrays in composite structs, like these[1][2][3], for
> instance.

Well, I guess this goes with the context-less nvme patch.  I think
you're much better off just removing the bi_inline_vecs array entirely,
and just add a new structure for bio + inline vecs for the few callers
that dynamically allocate the bio and actually have inline vecs.

Similar to what I did here for the bio integrity payload:

https://lore.kernel.org/linux-block/20250131122436.1317268-4-hch@lst.de/
diff mbox series

Patch

diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index dce7615c35e7..9182750457a8 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -212,62 +212,65 @@  typedef unsigned int blk_qc_t;
  * stacking drivers)
  */
 struct bio {
-	struct bio		*bi_next;	/* request queue link */
-	struct block_device	*bi_bdev;
-	blk_opf_t		bi_opf;		/* bottom bits REQ_OP, top bits
-						 * req_flags.
-						 */
-	unsigned short		bi_flags;	/* BIO_* below */
-	unsigned short		bi_ioprio;
-	enum rw_hint		bi_write_hint;
-	blk_status_t		bi_status;
-	atomic_t		__bi_remaining;
-
-	struct bvec_iter	bi_iter;
-
-	union {
-		/* for polled bios: */
-		blk_qc_t		bi_cookie;
-		/* for plugged zoned writes only: */
-		unsigned int		__bi_nr_segments;
-	};
-	bio_end_io_t		*bi_end_io;
-	void			*bi_private;
+	/* New members MUST be added within the struct_group() macro below. */
+	struct_group_tagged(bio_hdr, __hdr,
+		struct bio		*bi_next;	/* request queue link */
+		struct block_device	*bi_bdev;
+		blk_opf_t		bi_opf;		/* bottom bits REQ_OP, top bits
+							 * req_flags.
+							 */
+		unsigned short		bi_flags;	/* BIO_* below */
+		unsigned short		bi_ioprio;
+		enum rw_hint		bi_write_hint;
+		blk_status_t		bi_status;
+		atomic_t		__bi_remaining;
+
+		struct bvec_iter	bi_iter;
+
+		union {
+			/* for polled bios: */
+			blk_qc_t		bi_cookie;
+			/* for plugged zoned writes only: */
+			unsigned int		__bi_nr_segments;
+		};
+		bio_end_io_t		*bi_end_io;
+		void			*bi_private;
 #ifdef CONFIG_BLK_CGROUP
-	/*
-	 * Represents the association of the css and request_queue for the bio.
-	 * If a bio goes direct to device, it will not have a blkg as it will
-	 * not have a request_queue associated with it.  The reference is put
-	 * on release of the bio.
-	 */
-	struct blkcg_gq		*bi_blkg;
-	struct bio_issue	bi_issue;
+		/*
+		 * Represents the association of the css and request_queue for the bio.
+		 * If a bio goes direct to device, it will not have a blkg as it will
+		 * not have a request_queue associated with it.  The reference is put
+		 * on release of the bio.
+		 */
+		struct blkcg_gq		*bi_blkg;
+		struct bio_issue	bi_issue;
 #ifdef CONFIG_BLK_CGROUP_IOCOST
-	u64			bi_iocost_cost;
+		u64			bi_iocost_cost;
 #endif
 #endif
 
 #ifdef CONFIG_BLK_INLINE_ENCRYPTION
-	struct bio_crypt_ctx	*bi_crypt_context;
+		struct bio_crypt_ctx	*bi_crypt_context;
 #endif
 
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
-	struct bio_integrity_payload *bi_integrity; /* data integrity */
+		struct bio_integrity_payload *bi_integrity; /* data integrity */
 #endif
 
-	unsigned short		bi_vcnt;	/* how many bio_vec's */
+		unsigned short		bi_vcnt;	/* how many bio_vec's */
 
-	/*
-	 * Everything starting with bi_max_vecs will be preserved by bio_reset()
-	 */
+		/*
+		 * Everything starting with bi_max_vecs will be preserved by bio_reset()
+		 */
 
-	unsigned short		bi_max_vecs;	/* max bvl_vecs we can hold */
+		unsigned short		bi_max_vecs;	/* max bvl_vecs we can hold */
 
-	atomic_t		__bi_cnt;	/* pin count */
+		atomic_t		__bi_cnt;	/* pin count */
 
-	struct bio_vec		*bi_io_vec;	/* the actual vec list */
+		struct bio_vec		*bi_io_vec;	/* the actual vec list */
 
-	struct bio_set		*bi_pool;
+		struct bio_set		*bi_pool;
+	);
 
 	/*
 	 * We can inline a number of vecs at the end of the bio, to avoid
@@ -276,6 +279,8 @@  struct bio {
 	 */
 	struct bio_vec		bi_inline_vecs[];
 };
+static_assert(offsetof(struct bio, bi_inline_vecs) == sizeof(struct bio_hdr),
+	      "struct member likely outside of struct_group_tagged()");
 
 #define BIO_RESET_BYTES		offsetof(struct bio, bi_max_vecs)
 #define BIO_MAX_SECTORS		(UINT_MAX >> SECTOR_SHIFT)