diff --git a/config/kernel-rq-for-each_segment.m4 b/config/kernel-rq-for-each_segment.m4 index 449168d088..84ce7d1ec0 100644 --- a/config/kernel-rq-for-each_segment.m4 +++ b/config/kernel-rq-for-each_segment.m4 @@ -1,10 +1,13 @@ dnl # dnl # 2.6.x API change dnl # +dnl # 3.14 API change +dnl # AC_DEFUN([ZFS_AC_KERNEL_RQ_FOR_EACH_SEGMENT], [ - AC_MSG_CHECKING([whether rq_for_each_segment() is available]) tmp_flags="$EXTRA_KCFLAGS" EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}" + + AC_MSG_CHECKING([whether rq_for_each_segment() wants bio_vec *]) ZFS_LINUX_TRY_COMPILE([ #include ],[ @@ -16,8 +19,29 @@ AC_DEFUN([ZFS_AC_KERNEL_RQ_FOR_EACH_SEGMENT], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_RQ_FOR_EACH_SEGMENT, 1, [rq_for_each_segment() is available]) + AC_DEFINE(HAVE_RQ_FOR_EACH_SEGMENT_BVP, 1, + [rq_for_each_segment() wants bio_vec *]) ],[ AC_MSG_RESULT(no) ]) + + AC_MSG_CHECKING([whether rq_for_each_segment() wants bio_vec]) + ZFS_LINUX_TRY_COMPILE([ + #include + ],[ + struct bio_vec bv; + struct req_iterator iter; + struct request *req = NULL; + rq_for_each_segment(bv, req, iter) { } + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RQ_FOR_EACH_SEGMENT, 1, + [rq_for_each_segment() is available]) + AC_DEFINE(HAVE_RQ_FOR_EACH_SEGMENT_BV, 1, + [rq_for_each_segment() wants bio_vec]) + ],[ + AC_MSG_RESULT(no) + ]) + EXTRA_KCFLAGS="$tmp_flags" ]) diff --git a/include/linux/blkdev_compat.h b/include/linux/blkdev_compat.h index be22ae700f..8566033fcf 100644 --- a/include/linux/blkdev_compat.h +++ b/include/linux/blkdev_compat.h @@ -284,8 +284,32 @@ struct req_iterator { #define rq_for_each_segment(bvl, _rq, _iter) \ __rq_for_each_bio(_iter.bio, _rq) \ bio_for_each_segment(bvl, _iter.bio, _iter.i) + +#define HAVE_RQ_FOR_EACH_SEGMENT_BVP 1 #endif /* HAVE_RQ_FOR_EACH_SEGMENT */ +/* + * 3.14 API change + * rq_for_each_segment changed from taking bio_vec * to taking bio_vec. + * We provide rq_for_each_segment4 which takes both. + * You should not modify the fields in @bv and @bvp. + * + * Note: the if-else is just to inject the assignment before the loop body. + */ +#ifdef HAVE_RQ_FOR_EACH_SEGMENT_BVP +#define rq_for_each_segment4(bv, bvp, rq, iter) \ + rq_for_each_segment(bvp, rq, iter) \ + if ((bv = *bvp), 0) \ + ; \ + else +#else +#define rq_for_each_segment4(bv, bvp, rq, iter) \ + rq_for_each_segment(bv, rq, iter) \ + if ((bvp = &bv), 0) \ + ; \ + else +#endif + #ifdef HAVE_BIO_BVEC_ITER #define BIO_BI_SECTOR(bio) (bio)->bi_iter.bi_sector #define BIO_BI_SIZE(bio) (bio)->bi_iter.bi_size diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 5d9337f65b..edad9b4969 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -1011,13 +1011,13 @@ xuio_stat_wbuf_nocopy() static int dmu_req_copy(void *arg_buf, int size, struct request *req, size_t req_offset) { - struct bio_vec *bv; + struct bio_vec bv, *bvp; struct req_iterator iter; char *bv_buf; int tocpy, bv_len, bv_offset; int offset = 0; - rq_for_each_segment(bv, req, iter) { + rq_for_each_segment4(bv, bvp, req, iter) { /* * Fully consumed the passed arg_buf. We use goto here because * rq_for_each_segment is a double loop @@ -1027,19 +1027,19 @@ dmu_req_copy(void *arg_buf, int size, struct request *req, size_t req_offset) goto out; /* Skip already copied bv */ - if (req_offset >= bv->bv_len) { - req_offset -= bv->bv_len; + if (req_offset >= bv.bv_len) { + req_offset -= bv.bv_len; continue; } - bv_len = bv->bv_len - req_offset; - bv_offset = bv->bv_offset + req_offset; + bv_len = bv.bv_len - req_offset; + bv_offset = bv.bv_offset + req_offset; req_offset = 0; tocpy = MIN(bv_len, size - offset); ASSERT3S(tocpy, >=, 0); - bv_buf = page_address(bv->bv_page) + bv_offset; + bv_buf = page_address(bv.bv_page) + bv_offset; ASSERT3P(bv_buf, !=, NULL); if (rq_data_dir(req) == WRITE)