linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* more integrity cleanups v3
@ 2024-07-02 15:10 Christoph Hellwig
  2024-07-02 15:10 ` [PATCH 1/6] block: split integrity support out of bio.h Christoph Hellwig
                   ` (7 more replies)
  0 siblings, 8 replies; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

Hi Jens and Martin,

this series has more cleanups to the block layer integrity code.
It splits the bio integrity APIs into their own header as they are
only used by very few source files, cleans up their stubs a little
bit, and then in the last patch change when the bio_integrity_payload
is freed when it is not owned by the block layer.  This avoids having
to know the submitter in the core code and will simplify adding other
consuer of the API like file systems or the io_uring non-passthrough
PI support.

This series is based on the block for-next branch as there are
conflicting changes in 6.10-rc but not in the for-6.11/block branch.

Changes since v2:
 - stop calling bio_uninit in bio_endio
 - fix a commit message typo

Changes since v1:
 - rebased to for-next

Diffstat:
 block/bio-integrity.c         |   87 ++++++++---------------
 block/bio.c                   |   16 +++-
 block/blk-map.c               |    3 
 block/blk.h                   |   14 +++
 block/bounce.c                |    2 
 drivers/md/dm.c               |    1 
 drivers/nvme/host/ioctl.c     |   16 +---
 drivers/scsi/sd.c             |    3 
 include/linux/bio-integrity.h |  152 ++++++++++++++++++++++++++++++++++++++++
 include/linux/bio.h           |  156 ------------------------------------------
 include/linux/blk-integrity.h |    1 
 11 files changed, 222 insertions(+), 229 deletions(-)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/6] block: split integrity support out of bio.h
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
@ 2024-07-02 15:10 ` Christoph Hellwig
  2024-07-03  9:28   ` Johannes Thumshirn
  2024-07-02 15:10 ` [PATCH 2/6] block: also return bio_integrity_payload * from stubs Christoph Hellwig
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

Split struct bio_integrity_payload and the related prototypes out of
bio.h into a separate bio-integrity.h header so that it is only pulled
in by the few places that need it.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>
---
 block/bio.c                   |   2 +-
 block/blk.h                   |   1 +
 block/bounce.c                |   2 +-
 drivers/md/dm.c               |   1 +
 drivers/nvme/host/ioctl.c     |   1 +
 drivers/scsi/sd.c             |   3 +-
 include/linux/bio-integrity.h | 153 +++++++++++++++++++++++++++++++++
 include/linux/bio.h           | 156 ----------------------------------
 include/linux/blk-integrity.h |   1 +
 9 files changed, 161 insertions(+), 159 deletions(-)
 create mode 100644 include/linux/bio-integrity.h

diff --git a/block/bio.c b/block/bio.c
index e9e809a63c5975..4ca3f31ce45fb5 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -4,7 +4,7 @@
  */
 #include <linux/mm.h>
 #include <linux/swap.h>
-#include <linux/bio.h>
+#include <linux/bio-integrity.h>
 #include <linux/blkdev.h>
 #include <linux/uio.h>
 #include <linux/iocontext.h>
diff --git a/block/blk.h b/block/blk.h
index 47dadd2439b1ca..401e604f35d2cf 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -2,6 +2,7 @@
 #ifndef BLK_INTERNAL_H
 #define BLK_INTERNAL_H
 
+#include <linux/bio-integrity.h>
 #include <linux/blk-crypto.h>
 #include <linux/memblock.h>	/* for max_pfn/max_low_pfn */
 #include <linux/sched/sysctl.h>
diff --git a/block/bounce.c b/block/bounce.c
index d6a5219f29dd53..0d898cd5ec497f 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -10,7 +10,7 @@
 #include <linux/export.h>
 #include <linux/swap.h>
 #include <linux/gfp.h>
-#include <linux/bio.h>
+#include <linux/bio-integrity.h>
 #include <linux/pagemap.h>
 #include <linux/mempool.h>
 #include <linux/blkdev.h>
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 7d107ae06e1ae1..92d6eeb0a59327 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -11,6 +11,7 @@
 #include "dm-uevent.h"
 #include "dm-ima.h"
 
+#include <linux/bio-integrity.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index 8b69427a44762a..fb46f55f8b2894 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2011-2014, Intel Corporation.
  * Copyright (c) 2017-2021 Christoph Hellwig.
  */
+#include <linux/bio-integrity.h>
 #include <linux/ptrace.h>	/* for force_successful_syscall_return */
 #include <linux/nvme_ioctl.h>
 #include <linux/io_uring/cmd.h>
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 933074f8af4e96..f0f4fd7f20024a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -33,11 +33,12 @@
  *	than the level indicated above to trigger output.	
  */
 
+#include <linux/bio-integrity.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/bio.h>
+#include <linux/bio-integrity.h>
 #include <linux/hdreg.h>
 #include <linux/errno.h>
 #include <linux/idr.h>
diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
new file mode 100644
index 00000000000000..70ef19a0dc7e8b
--- /dev/null
+++ b/include/linux/bio-integrity.h
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_BIO_INTEGRITY_H
+#define _LINUX_BIO_INTEGRITY_H
+
+#include <linux/bio.h>
+
+enum bip_flags {
+	BIP_BLOCK_INTEGRITY	= 1 << 0, /* block layer owns integrity data */
+	BIP_MAPPED_INTEGRITY	= 1 << 1, /* ref tag has been remapped */
+	BIP_CTRL_NOCHECK	= 1 << 2, /* disable HBA integrity checking */
+	BIP_DISK_NOCHECK	= 1 << 3, /* disable disk integrity checking */
+	BIP_IP_CHECKSUM		= 1 << 4, /* IP checksum */
+	BIP_INTEGRITY_USER	= 1 << 5, /* Integrity payload is user address */
+	BIP_COPY_USER		= 1 << 6, /* Kernel bounce buffer in use */
+};
+
+struct bio_integrity_payload {
+	struct bio		*bip_bio;	/* parent bio */
+
+	struct bvec_iter	bip_iter;
+
+	unsigned short		bip_vcnt;	/* # of integrity bio_vecs */
+	unsigned short		bip_max_vcnt;	/* integrity bio_vec slots */
+	unsigned short		bip_flags;	/* control flags */
+
+	struct bvec_iter	bio_iter;	/* for rewinding parent bio */
+
+	struct work_struct	bip_work;	/* I/O completion */
+
+	struct bio_vec		*bip_vec;
+	struct bio_vec		bip_inline_vecs[];/* embedded bvec array */
+};
+
+#ifdef CONFIG_BLK_DEV_INTEGRITY
+
+#define bip_for_each_vec(bvl, bip, iter)				\
+	for_each_bvec(bvl, (bip)->bip_vec, iter, (bip)->bip_iter)
+
+#define bio_for_each_integrity_vec(_bvl, _bio, _iter)			\
+	for_each_bio(_bio)						\
+		bip_for_each_vec(_bvl, _bio->bi_integrity, _iter)
+
+static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
+{
+	if (bio->bi_opf & REQ_INTEGRITY)
+		return bio->bi_integrity;
+
+	return NULL;
+}
+
+static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
+{
+	struct bio_integrity_payload *bip = bio_integrity(bio);
+
+	if (bip)
+		return bip->bip_flags & flag;
+
+	return false;
+}
+
+static inline sector_t bip_get_seed(struct bio_integrity_payload *bip)
+{
+	return bip->bip_iter.bi_sector;
+}
+
+static inline void bip_set_seed(struct bio_integrity_payload *bip,
+				sector_t seed)
+{
+	bip->bip_iter.bi_sector = seed;
+}
+
+struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp,
+		unsigned int nr);
+int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len,
+		unsigned int offset);
+int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len, u32 seed);
+void bio_integrity_unmap_free_user(struct bio *bio);
+bool bio_integrity_prep(struct bio *bio);
+void bio_integrity_advance(struct bio *bio, unsigned int bytes_done);
+void bio_integrity_trim(struct bio *bio);
+int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask);
+int bioset_integrity_create(struct bio_set *bs, int pool_size);
+void bioset_integrity_free(struct bio_set *bs);
+void bio_integrity_init(void);
+
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+
+static inline void *bio_integrity(struct bio *bio)
+{
+	return NULL;
+}
+
+static inline int bioset_integrity_create(struct bio_set *bs, int pool_size)
+{
+	return 0;
+}
+
+static inline void bioset_integrity_free(struct bio_set *bs)
+{
+}
+
+static inline int bio_integrity_map_user(struct bio *bio, void __user *ubuf,
+					 ssize_t len, u32 seed)
+{
+	return -EINVAL;
+}
+
+static inline void bio_integrity_unmap_free_user(struct bio *bio)
+{
+}
+
+static inline bool bio_integrity_prep(struct bio *bio)
+{
+	return true;
+}
+
+static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
+		gfp_t gfp_mask)
+{
+	return 0;
+}
+
+static inline void bio_integrity_advance(struct bio *bio,
+		unsigned int bytes_done)
+{
+}
+
+static inline void bio_integrity_trim(struct bio *bio)
+{
+}
+
+static inline void bio_integrity_init(void)
+{
+}
+
+static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
+{
+	return false;
+}
+
+static inline void *bio_integrity_alloc(struct bio *bio, gfp_t gfp,
+		unsigned int nr)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int bio_integrity_add_page(struct bio *bio, struct page *page,
+					unsigned int len, unsigned int offset)
+{
+	return 0;
+}
+#endif /* CONFIG_BLK_DEV_INTEGRITY */
+#endif /* _LINUX_BIO_INTEGRITY_H */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 818e9361294781..a46e2047bea4d2 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -321,69 +321,6 @@ static inline void bio_next_folio(struct folio_iter *fi, struct bio *bio)
 #define bio_for_each_folio_all(fi, bio)				\
 	for (bio_first_folio(&fi, bio, 0); fi.folio; bio_next_folio(&fi, bio))
 
-enum bip_flags {
-	BIP_BLOCK_INTEGRITY	= 1 << 0, /* block layer owns integrity data */
-	BIP_MAPPED_INTEGRITY	= 1 << 1, /* ref tag has been remapped */
-	BIP_CTRL_NOCHECK	= 1 << 2, /* disable HBA integrity checking */
-	BIP_DISK_NOCHECK	= 1 << 3, /* disable disk integrity checking */
-	BIP_IP_CHECKSUM		= 1 << 4, /* IP checksum */
-	BIP_INTEGRITY_USER	= 1 << 5, /* Integrity payload is user address */
-	BIP_COPY_USER		= 1 << 6, /* Kernel bounce buffer in use */
-};
-
-/*
- * bio integrity payload
- */
-struct bio_integrity_payload {
-	struct bio		*bip_bio;	/* parent bio */
-
-	struct bvec_iter	bip_iter;
-
-	unsigned short		bip_vcnt;	/* # of integrity bio_vecs */
-	unsigned short		bip_max_vcnt;	/* integrity bio_vec slots */
-	unsigned short		bip_flags;	/* control flags */
-
-	struct bvec_iter	bio_iter;	/* for rewinding parent bio */
-
-	struct work_struct	bip_work;	/* I/O completion */
-
-	struct bio_vec		*bip_vec;
-	struct bio_vec		bip_inline_vecs[];/* embedded bvec array */
-};
-
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-
-static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
-{
-	if (bio->bi_opf & REQ_INTEGRITY)
-		return bio->bi_integrity;
-
-	return NULL;
-}
-
-static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
-{
-	struct bio_integrity_payload *bip = bio_integrity(bio);
-
-	if (bip)
-		return bip->bip_flags & flag;
-
-	return false;
-}
-
-static inline sector_t bip_get_seed(struct bio_integrity_payload *bip)
-{
-	return bip->bip_iter.bi_sector;
-}
-
-static inline void bip_set_seed(struct bio_integrity_payload *bip,
-				sector_t seed)
-{
-	bip->bip_iter.bi_sector = seed;
-}
-
-#endif /* CONFIG_BLK_DEV_INTEGRITY */
-
 void bio_trim(struct bio *bio, sector_t offset, sector_t size);
 extern struct bio *bio_split(struct bio *bio, int sectors,
 			     gfp_t gfp, struct bio_set *bs);
@@ -721,99 +658,6 @@ static inline bool bioset_initialized(struct bio_set *bs)
 	return bs->bio_slab != NULL;
 }
 
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-
-#define bip_for_each_vec(bvl, bip, iter)				\
-	for_each_bvec(bvl, (bip)->bip_vec, iter, (bip)->bip_iter)
-
-#define bio_for_each_integrity_vec(_bvl, _bio, _iter)			\
-	for_each_bio(_bio)						\
-		bip_for_each_vec(_bvl, _bio->bi_integrity, _iter)
-
-int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len, u32 seed);
-void bio_integrity_unmap_free_user(struct bio *bio);
-extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int);
-extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int);
-extern bool bio_integrity_prep(struct bio *);
-extern void bio_integrity_advance(struct bio *, unsigned int);
-extern void bio_integrity_trim(struct bio *);
-extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t);
-extern int bioset_integrity_create(struct bio_set *, int);
-extern void bioset_integrity_free(struct bio_set *);
-extern void bio_integrity_init(void);
-
-#else /* CONFIG_BLK_DEV_INTEGRITY */
-
-static inline void *bio_integrity(struct bio *bio)
-{
-	return NULL;
-}
-
-static inline int bioset_integrity_create(struct bio_set *bs, int pool_size)
-{
-	return 0;
-}
-
-static inline void bioset_integrity_free (struct bio_set *bs)
-{
-	return;
-}
-
-static inline bool bio_integrity_prep(struct bio *bio)
-{
-	return true;
-}
-
-static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
-				      gfp_t gfp_mask)
-{
-	return 0;
-}
-
-static inline void bio_integrity_advance(struct bio *bio,
-					 unsigned int bytes_done)
-{
-	return;
-}
-
-static inline void bio_integrity_trim(struct bio *bio)
-{
-	return;
-}
-
-static inline void bio_integrity_init(void)
-{
-	return;
-}
-
-static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
-{
-	return false;
-}
-
-static inline void *bio_integrity_alloc(struct bio * bio, gfp_t gfp,
-								unsigned int nr)
-{
-	return ERR_PTR(-EINVAL);
-}
-
-static inline int bio_integrity_add_page(struct bio *bio, struct page *page,
-					unsigned int len, unsigned int offset)
-{
-	return 0;
-}
-
-static inline int bio_integrity_map_user(struct bio *bio, void __user *ubuf,
-					 ssize_t len, u32 seed)
-{
-	return -EINVAL;
-}
-static inline void bio_integrity_unmap_free_user(struct bio *bio)
-{
-}
-
-#endif /* CONFIG_BLK_DEV_INTEGRITY */
-
 /*
  * Mark a bio as polled. Note that for async polled IO, the caller must
  * expect -EWOULDBLOCK if we cannot allocate a request (or other resources).
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index 804f856ed3e571..de98049b7ded91 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -3,6 +3,7 @@
 #define _LINUX_BLK_INTEGRITY_H
 
 #include <linux/blk-mq.h>
+#include <linux/bio-integrity.h>
 
 struct request;
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/6] block: also return bio_integrity_payload * from stubs
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
  2024-07-02 15:10 ` [PATCH 1/6] block: split integrity support out of bio.h Christoph Hellwig
@ 2024-07-02 15:10 ` Christoph Hellwig
  2024-07-03  9:29   ` Johannes Thumshirn
  2024-07-02 15:10 ` [PATCH 3/6] block: don't call bio_uninit from bio_endio Christoph Hellwig
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

struct bio_integrity_payload is defined unconditionally. No need to
return void * from bio_integrity() and bio_integrity_alloc().

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
---
 include/linux/bio-integrity.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
index 70ef19a0dc7e8b..cac24dac06fff0 100644
--- a/include/linux/bio-integrity.h
+++ b/include/linux/bio-integrity.h
@@ -85,7 +85,7 @@ void bio_integrity_init(void);
 
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 
-static inline void *bio_integrity(struct bio *bio)
+static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
 {
 	return NULL;
 }
@@ -138,8 +138,8 @@ static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
 	return false;
 }
 
-static inline void *bio_integrity_alloc(struct bio *bio, gfp_t gfp,
-		unsigned int nr)
+static inline struct bio_integrity_payload *
+bio_integrity_alloc(struct bio *bio, gfp_t gfp, unsigned int nr)
 {
 	return ERR_PTR(-EINVAL);
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 3/6] block: don't call bio_uninit from bio_endio
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
  2024-07-02 15:10 ` [PATCH 1/6] block: split integrity support out of bio.h Christoph Hellwig
  2024-07-02 15:10 ` [PATCH 2/6] block: also return bio_integrity_payload * from stubs Christoph Hellwig
@ 2024-07-02 15:10 ` Christoph Hellwig
  2024-07-03  9:50   ` Johannes Thumshirn
  2024-07-02 15:10 ` [PATCH 4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user Christoph Hellwig
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

Commit b222dd2fdd53 ("block: call bio_uninit in bio_endio") added a call
to bio_uninit in bio_endio to work around callers that use bio_init but
fail to call bio_uninit after they are done to release the resources.
While this is an abuse of the bio_init API we still have quite a few of
those left.  But this early uninit causes a problem for integrity data,
as at least some users need the bio_integrity_payload.  Right now the
only one is the NVMe passthrough which archives this by adding a special
case to skip the freeing if the BIP_INTEGRITY_USER flag is set.

Sort this out by only putting bi_blkg in bio_endio as that is the cause
of the actual leaks - the few users of the crypto context and integrity
data all properly call bio_uninit, usually through bio_put for
dynamically allocated bios.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/bio.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index 4ca3f31ce45fb5..68ce75fd9b7c89 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1630,8 +1630,18 @@ void bio_endio(struct bio *bio)
 		goto again;
 	}
 
-	/* release cgroup info */
-	bio_uninit(bio);
+#ifdef CONFIG_BLK_CGROUP
+	/*
+	 * Release cgroup info.  We shouldn't have to do this here, but quite
+	 * a few callers of bio_init fail to call bio_uninit, so we cover up
+	 * for that here at least for now.
+	 */
+	if (bio->bi_blkg) {
+		blkg_put(bio->bi_blkg);
+		bio->bi_blkg = NULL;
+	}
+#endif
+
 	if (bio->bi_end_io)
 		bio->bi_end_io(bio);
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
                   ` (2 preceding siblings ...)
  2024-07-02 15:10 ` [PATCH 3/6] block: don't call bio_uninit from bio_endio Christoph Hellwig
@ 2024-07-02 15:10 ` Christoph Hellwig
  2024-07-03  9:32   ` Johannes Thumshirn
  2024-07-02 15:10 ` [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion Christoph Hellwig
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

blk_rq_unmap_user always unmaps user space pass-through request.  If such
a request has integrity data attached it must come from a user mapping
as well.  Call bio_integrity_unmap_free_user from blk_rq_unmap_user
and remove the nvme_unmap_bio wrapper in the nvme driver.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
---
 block/bio-integrity.c     |  1 -
 block/blk-map.c           |  3 +++
 drivers/nvme/host/ioctl.c | 15 ++++-----------
 3 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index c4aed1dfa497a3..c8757d47e0ef62 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -174,7 +174,6 @@ void bio_integrity_unmap_free_user(struct bio *bio)
 	bio->bi_integrity = NULL;
 	bio->bi_opf &= ~REQ_INTEGRITY;
 }
-EXPORT_SYMBOL(bio_integrity_unmap_free_user);
 
 /**
  * bio_integrity_add_page - Attach integrity metadata
diff --git a/block/blk-map.c b/block/blk-map.c
index bce144091128f6..df5f82d114720f 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -757,6 +757,9 @@ int blk_rq_unmap_user(struct bio *bio)
 			bio_release_pages(bio, bio_data_dir(bio) == READ);
 		}
 
+		if (bio_integrity(bio))
+			bio_integrity_unmap_free_user(bio);
+
 		next_bio = bio;
 		bio = bio->bi_next;
 		blk_mq_map_bio_put(next_bio);
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index fb46f55f8b2894..f1d58e70933f54 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -112,13 +112,6 @@ static struct request *nvme_alloc_user_request(struct request_queue *q,
 	return req;
 }
 
-static void nvme_unmap_bio(struct bio *bio)
-{
-	if (bio_integrity(bio))
-		bio_integrity_unmap_free_user(bio);
-	blk_rq_unmap_user(bio);
-}
-
 static int nvme_map_user_request(struct request *req, u64 ubuffer,
 		unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
 		u32 meta_seed, struct io_uring_cmd *ioucmd, unsigned int flags)
@@ -165,7 +158,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
 
 out_unmap:
 	if (bio)
-		nvme_unmap_bio(bio);
+		blk_rq_unmap_user(bio);
 out:
 	blk_mq_free_request(req);
 	return ret;
@@ -203,7 +196,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
 	if (result)
 		*result = le64_to_cpu(nvme_req(req)->result.u64);
 	if (bio)
-		nvme_unmap_bio(bio);
+		blk_rq_unmap_user(bio);
 	blk_mq_free_request(req);
 
 	if (effects)
@@ -414,7 +407,7 @@ static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd,
 	struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd);
 
 	if (pdu->bio)
-		nvme_unmap_bio(pdu->bio);
+		blk_rq_unmap_user(pdu->bio);
 	io_uring_cmd_done(ioucmd, pdu->status, pdu->result, issue_flags);
 }
 
@@ -440,7 +433,7 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
 	 */
 	if (blk_rq_is_poll(req)) {
 		if (pdu->bio)
-			nvme_unmap_bio(pdu->bio);
+			blk_rq_unmap_user(pdu->bio);
 		io_uring_cmd_iopoll_done(ioucmd, pdu->result, pdu->status);
 	} else {
 		io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
                   ` (3 preceding siblings ...)
  2024-07-02 15:10 ` [PATCH 4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user Christoph Hellwig
@ 2024-07-02 15:10 ` Christoph Hellwig
  2024-07-03  9:33   ` Johannes Thumshirn
  2024-07-03 12:19   ` Kanchan Joshi
  2024-07-02 15:10 ` [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user Christoph Hellwig
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

Currently __bio_integrity_endio frees the integrity payload unless it is
explicitly marked as user-mapped.  This means in-kernel callers that
allocate their own integrity payload never get to see it on I/O
completion.  The current two users don't need it as they just pre-mapped
PI tuples received over the network, but this limits uses of integrity
data lot.

Change bio_integrity_endio to call __bio_integrity_endio for block layer
generated integrity data only, and leave freeing of submitter
allocated integrity data to bio_uninit which also gets called from
the final bio_put.  This requires that unmapping user mapped or copied
integrity data is now always done by the caller, and the special
BIP_INTEGRITY_USER flag can go away.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/bio-integrity.c         | 57 ++++++++++++++---------------------
 block/blk.h                   | 13 ++++++--
 include/linux/bio-integrity.h |  3 +-
 3 files changed, 34 insertions(+), 39 deletions(-)

diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index c8757d47e0ef62..4aa836d603fb23 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -22,9 +22,17 @@ void blk_flush_integrity(void)
 	flush_workqueue(kintegrityd_wq);
 }
 
-static void __bio_integrity_free(struct bio_set *bs,
-				 struct bio_integrity_payload *bip)
+/**
+ * bio_integrity_free - Free bio integrity payload
+ * @bio:	bio containing bip to be freed
+ *
+ * Description: Free the integrity portion of a bio.
+ */
+void bio_integrity_free(struct bio *bio)
 {
+	struct bio_integrity_payload *bip = bio_integrity(bio);
+	struct bio_set *bs = bio->bi_pool;
+
 	if (bs && mempool_initialized(&bs->bio_integrity_pool)) {
 		if (bip->bip_vec)
 			bvec_free(&bs->bvec_integrity_pool, bip->bip_vec,
@@ -33,6 +41,8 @@ static void __bio_integrity_free(struct bio_set *bs,
 	} else {
 		kfree(bip);
 	}
+	bio->bi_integrity = NULL;
+	bio->bi_opf &= ~REQ_INTEGRITY;
 }
 
 /**
@@ -86,7 +96,10 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
 
 	return bip;
 err:
-	__bio_integrity_free(bs, bip);
+	if (bs && mempool_initialized(&bs->bio_integrity_pool))
+		mempool_free(bip, &bs->bio_integrity_pool);
+	else
+		kfree(bip);
 	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(bio_integrity_alloc);
@@ -132,28 +145,6 @@ static void bio_integrity_unmap_user(struct bio_integrity_payload *bip)
 	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt, dirty);
 }
 
-/**
- * bio_integrity_free - Free bio integrity payload
- * @bio:	bio containing bip to be freed
- *
- * Description: Used to free the integrity portion of a bio. Usually
- * called from bio_free().
- */
-void bio_integrity_free(struct bio *bio)
-{
-	struct bio_integrity_payload *bip = bio_integrity(bio);
-	struct bio_set *bs = bio->bi_pool;
-
-	if (bip->bip_flags & BIP_INTEGRITY_USER)
-		return;
-	if (bip->bip_flags & BIP_BLOCK_INTEGRITY)
-		kfree(bvec_virt(bip->bip_vec));
-
-	__bio_integrity_free(bs, bip);
-	bio->bi_integrity = NULL;
-	bio->bi_opf &= ~REQ_INTEGRITY;
-}
-
 /**
  * bio_integrity_unmap_free_user - Unmap and free bio user integrity payload
  * @bio:	bio containing bip to be unmapped and freed
@@ -165,14 +156,9 @@ void bio_integrity_free(struct bio *bio)
 void bio_integrity_unmap_free_user(struct bio *bio)
 {
 	struct bio_integrity_payload *bip = bio_integrity(bio);
-	struct bio_set *bs = bio->bi_pool;
 
-	if (WARN_ON_ONCE(!(bip->bip_flags & BIP_INTEGRITY_USER)))
-		return;
 	bio_integrity_unmap_user(bip);
-	__bio_integrity_free(bs, bip);
-	bio->bi_integrity = NULL;
-	bio->bi_opf &= ~REQ_INTEGRITY;
+	bio_integrity_free(bio);
 }
 
 /**
@@ -273,7 +259,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec,
 		goto free_bip;
 	}
 
-	bip->bip_flags |= BIP_INTEGRITY_USER | BIP_COPY_USER;
+	bip->bip_flags |= BIP_COPY_USER;
 	bip->bip_iter.bi_sector = seed;
 	bip->bip_vcnt = nr_vecs;
 	return 0;
@@ -294,7 +280,6 @@ static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec,
 		return PTR_ERR(bip);
 
 	memcpy(bip->bip_vec, bvec, nr_vecs * sizeof(*bvec));
-	bip->bip_flags |= BIP_INTEGRITY_USER;
 	bip->bip_iter.bi_sector = seed;
 	bip->bip_iter.bi_size = len;
 	bip->bip_vcnt = nr_vecs;
@@ -502,6 +487,8 @@ static void bio_integrity_verify_fn(struct work_struct *work)
 	struct bio *bio = bip->bip_bio;
 
 	blk_integrity_verify(bio);
+
+	kfree(bvec_virt(bip->bip_vec));
 	bio_integrity_free(bio);
 	bio_endio(bio);
 }
@@ -522,13 +509,13 @@ bool __bio_integrity_endio(struct bio *bio)
 	struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
 	struct bio_integrity_payload *bip = bio_integrity(bio);
 
-	if (bio_op(bio) == REQ_OP_READ && !bio->bi_status &&
-	    (bip->bip_flags & BIP_BLOCK_INTEGRITY) && bi->csum_type) {
+	if (bio_op(bio) == REQ_OP_READ && !bio->bi_status && bi->csum_type) {
 		INIT_WORK(&bip->bip_work, bio_integrity_verify_fn);
 		queue_work(kintegrityd_wq, &bip->bip_work);
 		return false;
 	}
 
+	kfree(bvec_virt(bip->bip_vec));
 	bio_integrity_free(bio);
 	return true;
 }
diff --git a/block/blk.h b/block/blk.h
index 401e604f35d2cf..2233dc8d36b82a 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -202,11 +202,20 @@ static inline unsigned int blk_queue_get_max_sectors(struct request *rq)
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
 void blk_flush_integrity(void);
-bool __bio_integrity_endio(struct bio *);
 void bio_integrity_free(struct bio *bio);
+
+/*
+ * Integrity payloads can either be owned by the submitter, in which case
+ * bio_uninit will free them, or owned and generated by the block layer,
+ * in which case we'll verify them here (for reads) and free them before
+ * the bio is handed back to the submitted.
+ */
+bool __bio_integrity_endio(struct bio *bio);
 static inline bool bio_integrity_endio(struct bio *bio)
 {
-	if (bio_integrity(bio))
+	struct bio_integrity_payload *bip = bio_integrity(bio);
+
+	if (bip && (bip->bip_flags & BIP_BLOCK_INTEGRITY))
 		return __bio_integrity_endio(bio);
 	return true;
 }
diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
index cac24dac06fff0..3823d9be0d0790 100644
--- a/include/linux/bio-integrity.h
+++ b/include/linux/bio-integrity.h
@@ -10,8 +10,7 @@ enum bip_flags {
 	BIP_CTRL_NOCHECK	= 1 << 2, /* disable HBA integrity checking */
 	BIP_DISK_NOCHECK	= 1 << 3, /* disable disk integrity checking */
 	BIP_IP_CHECKSUM		= 1 << 4, /* IP checksum */
-	BIP_INTEGRITY_USER	= 1 << 5, /* Integrity payload is user address */
-	BIP_COPY_USER		= 1 << 6, /* Kernel bounce buffer in use */
+	BIP_COPY_USER		= 1 << 5, /* Kernel bounce buffer in use */
 };
 
 struct bio_integrity_payload {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
                   ` (4 preceding siblings ...)
  2024-07-02 15:10 ` [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion Christoph Hellwig
@ 2024-07-02 15:10 ` Christoph Hellwig
  2024-07-03  9:33   ` Johannes Thumshirn
  2024-07-03 12:21   ` Kanchan Joshi
  2024-07-03  2:18 ` more integrity cleanups v3 Martin K. Petersen
  2024-07-03 16:21 ` Jens Axboe
  7 siblings, 2 replies; 18+ messages in thread
From: Christoph Hellwig @ 2024-07-02 15:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block

Now that the integrity payload is always freed in bio_uninit, don't
bother freeing it a little earlier in bio_integrity_unmap_free_user.
With that the separate bio_integrity_unmap_free_user can go away by
just passing the bio to bio_integrity_unmap_user.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/bio-integrity.c         | 31 +++++++++++--------------------
 block/blk-map.c               |  2 +-
 include/linux/bio-integrity.h |  4 ++--
 3 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 4aa836d603fb23..4b5c604585561e 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -131,34 +131,25 @@ static void bio_integrity_uncopy_user(struct bio_integrity_payload *bip)
 	bio_integrity_unpin_bvec(copy, nr_vecs, true);
 }
 
-static void bio_integrity_unmap_user(struct bio_integrity_payload *bip)
+/**
+ * bio_integrity_unmap_user - Unmap user integrity payload
+ * @bio:	bio containing bip to be unmapped
+ *
+ * Unmap the user mapped integrity portion of a bio.
+ */
+void bio_integrity_unmap_user(struct bio *bio)
 {
-	bool dirty = bio_data_dir(bip->bip_bio) == READ;
+	struct bio_integrity_payload *bip = bio_integrity(bio);
 
 	if (bip->bip_flags & BIP_COPY_USER) {
-		if (dirty)
+		if (bio_data_dir(bio) == READ)
 			bio_integrity_uncopy_user(bip);
 		kfree(bvec_virt(bip->bip_vec));
 		return;
 	}
 
-	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt, dirty);
-}
-
-/**
- * bio_integrity_unmap_free_user - Unmap and free bio user integrity payload
- * @bio:	bio containing bip to be unmapped and freed
- *
- * Description: Used to unmap and free the user mapped integrity portion of a
- * bio. Submitter attaching the user integrity buffer is responsible for
- * unmapping and freeing it during completion.
- */
-void bio_integrity_unmap_free_user(struct bio *bio)
-{
-	struct bio_integrity_payload *bip = bio_integrity(bio);
-
-	bio_integrity_unmap_user(bip);
-	bio_integrity_free(bio);
+	bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt,
+			bio_data_dir(bio) == READ);
 }
 
 /**
diff --git a/block/blk-map.c b/block/blk-map.c
index df5f82d114720f..0e1167b239342f 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -758,7 +758,7 @@ int blk_rq_unmap_user(struct bio *bio)
 		}
 
 		if (bio_integrity(bio))
-			bio_integrity_unmap_free_user(bio);
+			bio_integrity_unmap_user(bio);
 
 		next_bio = bio;
 		bio = bio->bi_next;
diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
index 3823d9be0d0790..dd831c269e9948 100644
--- a/include/linux/bio-integrity.h
+++ b/include/linux/bio-integrity.h
@@ -73,7 +73,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp,
 int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len,
 		unsigned int offset);
 int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t len, u32 seed);
-void bio_integrity_unmap_free_user(struct bio *bio);
+void bio_integrity_unmap_user(struct bio *bio);
 bool bio_integrity_prep(struct bio *bio);
 void bio_integrity_advance(struct bio *bio, unsigned int bytes_done);
 void bio_integrity_trim(struct bio *bio);
@@ -104,7 +104,7 @@ static inline int bio_integrity_map_user(struct bio *bio, void __user *ubuf,
 	return -EINVAL;
 }
 
-static inline void bio_integrity_unmap_free_user(struct bio *bio)
+static inline void bio_integrity_unmap_user(struct bio *bio)
 {
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: more integrity cleanups v3
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
                   ` (5 preceding siblings ...)
  2024-07-02 15:10 ` [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user Christoph Hellwig
@ 2024-07-03  2:18 ` Martin K. Petersen
  2024-07-03 16:21 ` Jens Axboe
  7 siblings, 0 replies; 18+ messages in thread
From: Martin K. Petersen @ 2024-07-03  2:18 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Jens Axboe, Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block


Christoph,

> this series has more cleanups to the block layer integrity code. It
> splits the bio integrity APIs into their own header as they are only
> used by very few source files, cleans up their stubs a little bit, and
> then in the last patch change when the bio_integrity_payload is freed
> when it is not owned by the block layer. This avoids having to know
> the submitter in the core code and will simplify adding other consuer
> of the API like file systems or the io_uring non-passthrough PI
> support.

Looks good to me and is more in line with how this originally worked.

Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/6] block: split integrity support out of bio.h
  2024-07-02 15:10 ` [PATCH 1/6] block: split integrity support out of bio.h Christoph Hellwig
@ 2024-07-03  9:28   ` Johannes Thumshirn
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Thumshirn @ 2024-07-03  9:28 UTC (permalink / raw)
  To: hch, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/6] block: also return bio_integrity_payload * from stubs
  2024-07-02 15:10 ` [PATCH 2/6] block: also return bio_integrity_payload * from stubs Christoph Hellwig
@ 2024-07-03  9:29   ` Johannes Thumshirn
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Thumshirn @ 2024-07-03  9:29 UTC (permalink / raw)
  To: hch, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user
  2024-07-02 15:10 ` [PATCH 4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user Christoph Hellwig
@ 2024-07-03  9:32   ` Johannes Thumshirn
  0 siblings, 0 replies; 18+ messages in thread
From: Johannes Thumshirn @ 2024-07-03  9:32 UTC (permalink / raw)
  To: hch, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion
  2024-07-02 15:10 ` [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion Christoph Hellwig
@ 2024-07-03  9:33   ` Johannes Thumshirn
  2024-07-03 12:19   ` Kanchan Joshi
  1 sibling, 0 replies; 18+ messages in thread
From: Johannes Thumshirn @ 2024-07-03  9:33 UTC (permalink / raw)
  To: hch, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user
  2024-07-02 15:10 ` [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user Christoph Hellwig
@ 2024-07-03  9:33   ` Johannes Thumshirn
  2024-07-03 12:21   ` Kanchan Joshi
  1 sibling, 0 replies; 18+ messages in thread
From: Johannes Thumshirn @ 2024-07-03  9:33 UTC (permalink / raw)
  To: hch, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 3/6] block: don't call bio_uninit from bio_endio
  2024-07-02 15:10 ` [PATCH 3/6] block: don't call bio_uninit from bio_endio Christoph Hellwig
@ 2024-07-03  9:50   ` Johannes Thumshirn
  2024-07-04  7:23     ` hch
  0 siblings, 1 reply; 18+ messages in thread
From: Johannes Thumshirn @ 2024-07-03  9:50 UTC (permalink / raw)
  To: hch, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

On 02.07.24 17:11, Christoph Hellwig wrote:
> Commit b222dd2fdd53 ("block: call bio_uninit in bio_endio") added a call
> to bio_uninit in bio_endio to work around callers that use bio_init but
> fail to call bio_uninit after they are done to release the resources.
> While this is an abuse of the bio_init API we still have quite a few of
> those left.  But this early uninit causes a problem for integrity data,
> as at least some users need the bio_integrity_payload.  Right now the
> only one is the NVMe passthrough which archives this by adding a special
> case to skip the freeing if the BIP_INTEGRITY_USER flag is set.
> 
> Sort this out by only putting bi_blkg in bio_endio as that is the cause
> of the actual leaks - the few users of the crypto context and integrity
> data all properly call bio_uninit, usually through bio_put for
> dynamically allocated bios.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>   block/bio.c | 14 ++++++++++++--
>   1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/block/bio.c b/block/bio.c
> index 4ca3f31ce45fb5..68ce75fd9b7c89 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -1630,8 +1630,18 @@ void bio_endio(struct bio *bio)
>   		goto again;
>   	}
>   
> -	/* release cgroup info */
> -	bio_uninit(bio);
> +#ifdef CONFIG_BLK_CGROUP
> +	/*
> +	 * Release cgroup info.  We shouldn't have to do this here, but quite
> +	 * a few callers of bio_init fail to call bio_uninit, so we cover up
> +	 * for that here at least for now.
> +	 */
> +	if (bio->bi_blkg) {
> +		blkg_put(bio->bi_blkg);
> +		bio->bi_blkg = NULL;
> +	}
> +#endif
> +
>   	if (bio->bi_end_io)
>   		bio->bi_end_io(bio);
>   }

Can we have sth. like this on top to avoid the duplication?:

diff --git a/block/bio.c b/block/bio.c
index 68ce75fd9b7c..f10c377b6899 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -210,14 +210,21 @@ struct bio_vec *bvec_alloc(mempool_t *pool, 
unsigned short *nr_vecs,
         return mempool_alloc(pool, gfp_mask);
  }

-void bio_uninit(struct bio *bio)
+static void bio_uninit_blkg(struct bio *bio)
  {
  #ifdef CONFIG_BLK_CGROUP
-       if (bio->bi_blkg) {
-               blkg_put(bio->bi_blkg);
-               bio->bi_blkg = NULL;
-       }
+       if (!bio->bi_blkg)
+               return;
+
+       blkg_put(bio->bi_blkg);
+       bio->bi_blkg = NULL;
  #endif
+}
+
+void bio_uninit(struct bio *bio)
+{
+       bio_uninit_blkg(bio);
+
         if (bio_integrity(bio))
                 bio_integrity_free(bio);

@@ -1630,17 +1637,12 @@ void bio_endio(struct bio *bio)
                 goto again;
         }

-#ifdef CONFIG_BLK_CGROUP
         /*
          * Release cgroup info.  We shouldn't have to do this here, but 
quite
          * a few callers of bio_init fail to call bio_uninit, so we 
cover up
          * for that here at least for now.
          */
-       if (bio->bi_blkg) {
-               blkg_put(bio->bi_blkg);
-               bio->bi_blkg = NULL;
-       }
-#endif
+       bio_uninit_blkg(bio);

         if (bio->bi_end_io)
                 bio->bi_end_io(bio);


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion
  2024-07-02 15:10 ` [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion Christoph Hellwig
  2024-07-03  9:33   ` Johannes Thumshirn
@ 2024-07-03 12:19   ` Kanchan Joshi
  1 sibling, 0 replies; 18+ messages in thread
From: Kanchan Joshi @ 2024-07-03 12:19 UTC (permalink / raw)
  To: Christoph Hellwig, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, linux-block

On 7/2/2024 8:40 PM, Christoph Hellwig wrote:
> + * Integrity payloads can either be owned by the submitter, in which case
> + * bio_uninit will free them, or owned and generated by the block layer,
> + * in which case we'll verify them here (for reads) and free them before
> + * the bio is handed back to the submitted.

s/submitted/submitter?

With that
Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user
  2024-07-02 15:10 ` [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user Christoph Hellwig
  2024-07-03  9:33   ` Johannes Thumshirn
@ 2024-07-03 12:21   ` Kanchan Joshi
  1 sibling, 0 replies; 18+ messages in thread
From: Kanchan Joshi @ 2024-07-03 12:21 UTC (permalink / raw)
  To: Christoph Hellwig, Jens Axboe
  Cc: Martin K . Petersen, Anuj Gupta, linux-block

Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: more integrity cleanups v3
  2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
                   ` (6 preceding siblings ...)
  2024-07-03  2:18 ` more integrity cleanups v3 Martin K. Petersen
@ 2024-07-03 16:21 ` Jens Axboe
  7 siblings, 0 replies; 18+ messages in thread
From: Jens Axboe @ 2024-07-03 16:21 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Martin K . Petersen, Anuj Gupta, Kanchan Joshi, linux-block


On Tue, 02 Jul 2024 17:10:18 +0200, Christoph Hellwig wrote:
> this series has more cleanups to the block layer integrity code.
> It splits the bio integrity APIs into their own header as they are
> only used by very few source files, cleans up their stubs a little
> bit, and then in the last patch change when the bio_integrity_payload
> is freed when it is not owned by the block layer.  This avoids having
> to know the submitter in the core code and will simplify adding other
> consuer of the API like file systems or the io_uring non-passthrough
> PI support.
> 
> [...]

Applied, thanks!

[1/6] block: split integrity support out of bio.h
      commit: da042a3655151157c06e71a583e883ab2d86d1ff
[2/6] block: also return bio_integrity_payload * from stubs
      commit: 21671a1ed1ff22e158ebe9d619943f926f03f5cd
[3/6] block: don't call bio_uninit from bio_endio
      commit: bf4c89fc8797f5c0964a0c3d561fbe7e8483b62f
[4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user
      commit: f8924374fd37a8b41d554acd8b7407af7d354c0d
[5/6] block: don't free submitter owned integrity payload on I/O completion
      commit: 85253bac4d02b1f95d6109c221aeccd7a262ec4d
[6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user
      commit: 74cc150282e41c6c0704cd305c9a4392dc64ef4d

Best regards,
-- 
Jens Axboe




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 3/6] block: don't call bio_uninit from bio_endio
  2024-07-03  9:50   ` Johannes Thumshirn
@ 2024-07-04  7:23     ` hch
  0 siblings, 0 replies; 18+ messages in thread
From: hch @ 2024-07-04  7:23 UTC (permalink / raw)
  To: Johannes Thumshirn
  Cc: hch, Jens Axboe, Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
	linux-block@vger.kernel.org

On Wed, Jul 03, 2024 at 09:50:08AM +0000, Johannes Thumshirn wrote:
> Can we have sth. like this on top to avoid the duplication?:

I hope I can just get rid of it over the next merge window or two.
Right now the only two offenders I've found are bcache and bcachefs,
so it might not be that much work.


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2024-07-04  7:23 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-02 15:10 more integrity cleanups v3 Christoph Hellwig
2024-07-02 15:10 ` [PATCH 1/6] block: split integrity support out of bio.h Christoph Hellwig
2024-07-03  9:28   ` Johannes Thumshirn
2024-07-02 15:10 ` [PATCH 2/6] block: also return bio_integrity_payload * from stubs Christoph Hellwig
2024-07-03  9:29   ` Johannes Thumshirn
2024-07-02 15:10 ` [PATCH 3/6] block: don't call bio_uninit from bio_endio Christoph Hellwig
2024-07-03  9:50   ` Johannes Thumshirn
2024-07-04  7:23     ` hch
2024-07-02 15:10 ` [PATCH 4/6] block: call bio_integrity_unmap_free_user from blk_rq_unmap_user Christoph Hellwig
2024-07-03  9:32   ` Johannes Thumshirn
2024-07-02 15:10 ` [PATCH 5/6] block: don't free submitter owned integrity payload on I/O completion Christoph Hellwig
2024-07-03  9:33   ` Johannes Thumshirn
2024-07-03 12:19   ` Kanchan Joshi
2024-07-02 15:10 ` [PATCH 6/6] block: don't free the integrity payload in bio_integrity_unmap_free_user Christoph Hellwig
2024-07-03  9:33   ` Johannes Thumshirn
2024-07-03 12:21   ` Kanchan Joshi
2024-07-03  2:18 ` more integrity cleanups v3 Martin K. Petersen
2024-07-03 16:21 ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).