aboutsummaryrefslogtreecommitdiff
path: root/module/os/linux/zfs/vdev_disk.c
diff options
context:
space:
mode:
authorBrian Behlendorf <behlendorf1@llnl.gov>2022-05-27 20:28:51 +0000
committerBrian Behlendorf <behlendorf1@llnl.gov>2022-05-31 19:04:03 +0000
commit5f264996f4dc2d5279afe96698688a20c281c473 (patch)
tree16cd400e9067a58219f0bf46e85a393438eb4082 /module/os/linux/zfs/vdev_disk.c
parent152d6fda54e61042a70059c95c44b364aea0bbd8 (diff)
downloadsrc-5f264996f4dc2d5279afe96698688a20c281c473.tar.gz
src-5f264996f4dc2d5279afe96698688a20c281c473.zip
Diffstat (limited to 'module/os/linux/zfs/vdev_disk.c')
-rw-r--r--module/os/linux/zfs/vdev_disk.c53
1 files changed, 39 insertions, 14 deletions
diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
index 235cd1691c14..cf2d7386b952 100644
--- a/module/os/linux/zfs/vdev_disk.c
+++ b/module/os/linux/zfs/vdev_disk.c
@@ -460,6 +460,13 @@ vdev_submit_bio_impl(struct bio *bio)
#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)
/*
@@ -556,6 +563,7 @@ bio_set_dev(struct bio *bio, struct block_device *bdev)
bio->bi_bdev = bdev;
}
#endif /* HAVE_BIO_SET_DEV */
+#endif /* !HAVE_BIO_ALLOC_4ARG */
static inline void
vdev_submit_bio(struct bio *bio)
@@ -566,10 +574,36 @@ 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)
@@ -581,6 +615,7 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio,
int bio_count = 16;
int error = 0;
struct blk_plug plug;
+ unsigned short nr_vecs;
/*
* Accessing outside the block device is never allowed.
@@ -632,15 +667,8 @@ retry:
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));
@@ -649,7 +677,6 @@ retry:
/* 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;
@@ -713,14 +740,12 @@ vdev_disk_io_flush(struct block_device *bdev, zio_t *zio)
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);