#define preempt_schedule_notrace(x) preempt_schedule(x)
#endif
+/*
+ * As for the Linux 5.18 kernel bio_alloc() expects a block_device struct
+ * as an argument removing the need to set it with bio_set_dev(). This
+ * removes the need for all of the following compatibility code.
+ */
+#if !defined(HAVE_BIO_ALLOC_4ARG)
+
#ifdef HAVE_BIO_SET_DEV
#if defined(CONFIG_BLK_CGROUP) && defined(HAVE_BIO_SET_DEV_GPL_ONLY)
/*
bio->bi_bdev = bdev;
}
#endif /* HAVE_BIO_SET_DEV */
+#endif /* !HAVE_BIO_ALLOC_4ARG */
static inline void
vdev_submit_bio(struct bio *bio)
current->bio_list = bio_list;
}
+static inline struct bio *
+vdev_bio_alloc(struct block_device *bdev, gfp_t gfp_mask,
+ unsigned short nr_vecs)
+{
+ struct bio *bio;
+
#ifdef HAVE_BIO_ALLOC_4ARG
-#define bio_alloc(gfp_mask, nr_iovecs) bio_alloc(NULL, nr_iovecs, 0, gfp_mask)
+ bio = bio_alloc(bdev, nr_vecs, 0, gfp_mask);
+#else
+ bio = bio_alloc(gfp_mask, nr_vecs);
+ if (likely(bio != NULL))
+ bio_set_dev(bio, bdev);
#endif
+ return (bio);
+}
+
+static inline unsigned int
+vdev_bio_max_segs(zio_t *zio, int bio_size, uint64_t abd_offset)
+{
+ unsigned long nr_segs = abd_nr_pages_off(zio->io_abd,
+ bio_size, abd_offset);
+
+#ifdef HAVE_BIO_MAX_SEGS
+ return (bio_max_segs(nr_segs));
+#else
+ return (MIN(nr_segs, BIO_MAX_PAGES));
+#endif
+}
+
static int
__vdev_disk_physio(struct block_device *bdev, zio_t *zio,
size_t io_size, uint64_t io_offset, int rw, int flags)
int bio_count = 16;
int error = 0;
struct blk_plug plug;
+ unsigned short nr_vecs;
/*
* Accessing outside the block device is never allowed.
goto retry;
}
- /* bio_alloc() with __GFP_WAIT never returns NULL */
-#ifdef HAVE_BIO_MAX_SEGS
- dr->dr_bio[i] = bio_alloc(GFP_NOIO, bio_max_segs(
- abd_nr_pages_off(zio->io_abd, bio_size, abd_offset)));
-#else
- dr->dr_bio[i] = bio_alloc(GFP_NOIO,
- MIN(abd_nr_pages_off(zio->io_abd, bio_size, abd_offset),
- BIO_MAX_PAGES));
-#endif
+ nr_vecs = vdev_bio_max_segs(zio, bio_size, abd_offset);
+ dr->dr_bio[i] = vdev_bio_alloc(bdev, GFP_NOIO, nr_vecs);
if (unlikely(dr->dr_bio[i] == NULL)) {
vdev_disk_dio_free(dr);
return (SET_ERROR(ENOMEM));
/* Matching put called by vdev_disk_physio_completion */
vdev_disk_dio_get(dr);
- bio_set_dev(dr->dr_bio[i], bdev);
BIO_BI_SECTOR(dr->dr_bio[i]) = bio_offset >> 9;
dr->dr_bio[i]->bi_end_io = vdev_disk_physio_completion;
dr->dr_bio[i]->bi_private = dr;
if (!q)
return (SET_ERROR(ENXIO));
- bio = bio_alloc(GFP_NOIO, 0);
- /* bio_alloc() with __GFP_WAIT never returns NULL */
+ bio = vdev_bio_alloc(bdev, GFP_NOIO, 0);
if (unlikely(bio == NULL))
return (SET_ERROR(ENOMEM));
bio->bi_end_io = vdev_disk_io_flush_completion;
bio->bi_private = zio;
- bio_set_dev(bio, bdev);
bio_set_flush(bio);
vdev_submit_bio(bio);
invalidate_bdev(bdev);