mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
bio_integrity_alloc_buf usage of GFP_ flags is messed up. For one it
mixes GFP_NOFS and GFP_NOIO for neighbouring allocations, but it also
makes the allocations fail more often than needed. That code was copied
from bio_alloc_bioset which needs to do that so that it can punt to the
rescuer workqueue, but none of that is needed for the integrity
allocations that either sits in the file system or at the very bottom
of the I/O stack. Failing early means we'll do a fully waiting
allocation from the mempool ->alloc callback which is usually much
larger than required.
Fix this by passing a gfp_t so that the file system path can pass
GFP_NOFS and the auto-integrity code can pass GFP_NOIO, and don't
modify the allocation type except for disabling warnings.
Fixes: ec7f31b2a2 ("block: make bio auto-integrity deadlock safe")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Link: https://patch.msgid.link/20260624080014.1998650-2-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
155 lines
4.2 KiB
C
155 lines
4.2 KiB
C
/* 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_DISK_NOCHECK = 1 << 2, /* disable disk integrity checking */
|
|
BIP_IP_CHECKSUM = 1 << 3, /* IP checksum */
|
|
BIP_COPY_USER = 1 << 4, /* Kernel bounce buffer in use */
|
|
BIP_CHECK_GUARD = 1 << 5, /* guard check */
|
|
BIP_CHECK_REFTAG = 1 << 6, /* reftag check */
|
|
BIP_CHECK_APPTAG = 1 << 7, /* apptag check */
|
|
|
|
BIP_MEMPOOL = 1 << 15, /* buffer backed by mempool */
|
|
};
|
|
|
|
struct bio_integrity_payload {
|
|
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 */
|
|
u16 app_tag; /* application tag value */
|
|
|
|
struct bio_vec *bip_vec;
|
|
};
|
|
|
|
#define BIP_CLONE_FLAGS (BIP_MAPPED_INTEGRITY | BIP_IP_CHECKSUM | \
|
|
BIP_CHECK_GUARD | BIP_CHECK_REFTAG | BIP_CHECK_APPTAG)
|
|
|
|
#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;
|
|
}
|
|
|
|
void bio_integrity_init(struct bio *bio, struct bio_integrity_payload *bip,
|
|
struct bio_vec *bvecs, unsigned int nr_vecs);
|
|
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, struct iov_iter *iter);
|
|
int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta);
|
|
void bio_integrity_unmap_user(struct bio *bio);
|
|
void bio_integrity_prep(struct bio *bio, unsigned int action);
|
|
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);
|
|
|
|
#else /* CONFIG_BLK_DEV_INTEGRITY */
|
|
|
|
static inline struct bio_integrity_payload *bio_integrity(struct bio *bio)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline void bio_integrity_unmap_user(struct bio *bio)
|
|
{
|
|
}
|
|
|
|
static inline void bio_integrity_prep(struct bio *bio, unsigned int action)
|
|
{
|
|
}
|
|
|
|
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 bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline struct bio_integrity_payload *
|
|
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 */
|
|
|
|
void bio_integrity_alloc_buf(struct bio *bio, gfp_t gfp, bool zero_buffer);
|
|
void bio_integrity_free_buf(struct bio_integrity_payload *bip);
|
|
void bio_integrity_setup_default(struct bio *bio);
|
|
|
|
unsigned int fs_bio_integrity_alloc(struct bio *bio);
|
|
void fs_bio_integrity_free(struct bio *bio);
|
|
void fs_bio_integrity_generate(struct bio *bio);
|
|
int fs_bio_integrity_verify(struct bio *bio, sector_t sector,
|
|
unsigned int size);
|
|
|
|
#endif /* _LINUX_BIO_INTEGRITY_H */
|