__bio_clone_fast should also clone integrity and crypto data, as a clone
without those is incomplete. Right now the only caller that can actually
support crypto and integrity data (dm) does it manually for the one
callchain that supports these, but we better do it properly in the core.
Note that all callers except for the above mentioned one also don't need
to handle failure at all, given that the integrity and crypto clones are
based on mempool allocations that won't fail for sleeping allocations.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Link: https://lore.kernel.org/r/20220202160109.108149-11-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
return 0;
}
-EXPORT_SYMBOL(bio_integrity_clone);
int bioset_integrity_create(struct bio_set *bs, int pool_size)
{
* __bio_clone_fast - clone a bio that shares the original bio's biovec
* @bio: destination bio
* @bio_src: bio to clone
+ * @gfp: allocation flags
*
* Clone a &bio. Caller will own the returned bio, but not
* the actual data it points to. Reference count of returned
*
* Caller must ensure that @bio_src is not freed before @bio.
*/
-void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
+int __bio_clone_fast(struct bio *bio, struct bio *bio_src, gfp_t gfp)
{
WARN_ON_ONCE(bio->bi_pool && bio->bi_max_vecs);
bio_clone_blkg_association(bio, bio_src);
blkcg_bio_issue_init(bio);
+
+ if (bio_crypt_clone(bio, bio_src, gfp) < 0)
+ return -ENOMEM;
+ if (bio_integrity(bio_src) &&
+ bio_integrity_clone(bio, bio_src, gfp) < 0)
+ return -ENOMEM;
+ return 0;
}
EXPORT_SYMBOL(__bio_clone_fast);
if (!b)
return NULL;
- __bio_clone_fast(b, bio);
-
- if (bio_crypt_clone(b, bio, gfp_mask) < 0)
- goto err_put;
-
- if (bio_integrity(bio) &&
- bio_integrity_clone(b, bio, gfp_mask) < 0)
- goto err_put;
+ if (__bio_clone_fast(b, bio, gfp_mask < 0)) {
+ bio_put(b);
+ return NULL;
+ }
return b;
-
-err_put:
- bio_put(b);
- return NULL;
}
EXPORT_SYMBOL(bio_clone_fast);
*dst->bi_crypt_context = *src->bi_crypt_context;
return 0;
}
-EXPORT_SYMBOL_GPL(__bio_crypt_clone);
/* Increments @dun by @inc, treating @dun as a multi-limb integer. */
void bio_crypt_dun_increment(u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
struct bio *bio = &s->bio.bio;
bio_init(bio, NULL, NULL, 0, 0);
- __bio_clone_fast(bio, orig_bio);
+ __bio_clone_fast(bio, orig_bio, GFP_NOIO);
/*
* bi_end_io can be set separately somewhere else, e.g. the
* variants in,
tio = clone_to_tio(clone);
tio->inside_dm_io = false;
}
- __bio_clone_fast(&tio->clone, ci->bio);
+
+ if (__bio_clone_fast(&tio->clone, ci->bio, gfp_mask) < 0) {
+ if (ci->io->tio.io)
+ bio_put(&tio->clone);
+ return NULL;
+ }
tio->magic = DM_TIO_MAGIC;
tio->io = ci->io;
sector_t sector, unsigned *len)
{
struct bio *bio = ci->bio, *clone;
- int r;
clone = alloc_tio(ci, ti, 0, len, GFP_NOIO);
-
- r = bio_crypt_clone(clone, bio, GFP_NOIO);
- if (r < 0)
- goto free_tio;
-
- if (bio_integrity(bio)) {
- struct dm_target_io *tio = clone_to_tio(clone);
-
- if (unlikely(!dm_target_has_integrity(tio->ti->type) &&
- !dm_target_passes_integrity(tio->ti->type))) {
- DMWARN("%s: the target %s doesn't support integrity data.",
- dm_device_name(tio->io->md),
- tio->ti->type->name);
- r = -EIO;
- goto free_tio;
- }
-
- r = bio_integrity_clone(clone, bio, GFP_NOIO);
- if (r < 0)
- goto free_tio;
- }
-
bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector));
clone->bi_iter.bi_size = to_bytes(*len);
__map_bio(clone);
return 0;
-free_tio:
- free_tio(clone);
- return r;
}
static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
multipath = conf->multipaths + mp_bh->path;
bio_init(&mp_bh->bio, NULL, NULL, 0, 0);
- __bio_clone_fast(&mp_bh->bio, bio);
+ __bio_clone_fast(&mp_bh->bio, bio, GFP_NOIO);
mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset;
bio_set_dev(&mp_bh->bio, multipath->rdev->bdev);
struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned short nr_iovecs);
extern void bio_put(struct bio *);
-extern void __bio_clone_fast(struct bio *, struct bio *);
+int __bio_clone_fast(struct bio *bio, struct bio *bio_src, gfp_t gfp);
extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *);
extern struct bio_set fs_bio_set;