diff --git a/config/kernel-bio-end-io-t-args.m4 b/config/kernel-bio-end-io-t-args.m4 index c8c520f1ba82..3c420cc0c305 100644 --- a/config/kernel-bio-end-io-t-args.m4 +++ b/config/kernel-bio-end-io-t-args.m4 @@ -22,3 +22,25 @@ AC_DEFUN([ZFS_AC_KERNEL_BIO_END_IO_T_ARGS], [ AC_MSG_RESULT(no) ]) ]) + +dnl # +dnl # 4.13 API change +dnl # The bio->bi_error field was replaced with bio->bi_status which is an +dnl # enum which describes all possible error types. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_BIO_BI_STATUS], [ + AC_MSG_CHECKING([whether bio->bi_status exists]) + ZFS_LINUX_TRY_COMPILE([ + #include + ],[ + struct bio bio __attribute__ ((unused)); + blk_status_t status __attribute__ ((unused)) = BLK_STS_OK; + + bio.bi_status = status; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BIO_BI_STATUS, 1, [bio->bi_status exists]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 324ab816f6a6..e92a659879b4 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -30,6 +30,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [ ZFS_AC_KERNEL_REQ_OP_FLUSH ZFS_AC_KERNEL_BIO_BI_OPF ZFS_AC_KERNEL_BIO_END_IO_T_ARGS + ZFS_AC_KERNEL_BIO_BI_STATUS ZFS_AC_KERNEL_BIO_RW_BARRIER ZFS_AC_KERNEL_BIO_RW_DISCARD ZFS_AC_KERNEL_BLK_QUEUE_BDI diff --git a/include/linux/blkdev_compat.h b/include/linux/blkdev_compat.h index 822e964a7137..428664a0b6b3 100644 --- a/include/linux/blkdev_compat.h +++ b/include/linux/blkdev_compat.h @@ -221,14 +221,104 @@ bio_set_flags_failfast(struct block_device *bdev, int *flags) #define DISK_NAME_LEN 32 #endif /* DISK_NAME_LEN */ +#ifdef HAVE_BIO_BI_STATUS +static inline int +bi_status_to_errno(blk_status_t status) +{ + switch (status) { + case BLK_STS_OK: + return (0); + case BLK_STS_NOTSUPP: + return (EOPNOTSUPP); + case BLK_STS_TIMEOUT: + return (ETIMEDOUT); + case BLK_STS_NOSPC: + return (ENOSPC); + case BLK_STS_TRANSPORT: + return (ENOLINK); + case BLK_STS_TARGET: + return (EREMOTEIO); + case BLK_STS_NEXUS: + return (EBADE); + case BLK_STS_MEDIUM: + return (ENODATA); + case BLK_STS_PROTECTION: + return (EILSEQ); + case BLK_STS_RESOURCE: + return (ENOMEM); + case BLK_STS_AGAIN: + return (EAGAIN); + case BLK_STS_IOERR: + return (EIO); + default: + return (EIO); + } +} + +static inline blk_status_t +errno_to_bi_status(int error) +{ + switch (error) { + case 0: + return (BLK_STS_OK); + case EOPNOTSUPP: + return (BLK_STS_NOTSUPP); + case ETIMEDOUT: + return (BLK_STS_TIMEOUT); + case ENOSPC: + return (BLK_STS_NOSPC); + case ENOLINK: + return (BLK_STS_TRANSPORT); + case EREMOTEIO: + return (BLK_STS_TARGET); + case EBADE: + return (BLK_STS_NEXUS); + case ENODATA: + return (BLK_STS_MEDIUM); + case EILSEQ: + return (BLK_STS_PROTECTION); + case ENOMEM: + return (BLK_STS_RESOURCE); + case EAGAIN: + return (BLK_STS_AGAIN); + case EIO: + return (BLK_STS_IOERR); + default: + return (BLK_STS_IOERR); + } +} +#endif /* HAVE_BIO_BI_STATUS */ + /* * 4.3 API change * The bio_endio() prototype changed slightly. These are helper * macro's to ensure the prototype and invocation are handled. */ #ifdef HAVE_1ARG_BIO_END_IO_T +#ifdef HAVE_BIO_BI_STATUS +#define BIO_END_IO_ERROR(bio) bi_status_to_errno(bio->bi_status) #define BIO_END_IO_PROTO(fn, x, z) static void fn(struct bio *x) -#define BIO_END_IO(bio, error) bio->bi_error = error; bio_endio(bio); +#define BIO_END_IO(bio, error) bio_set_bi_status(bio, error) +static inline void +bio_set_bi_status(struct bio *bio, int error) +{ + ASSERT3S(error, <=, 0); + bio->bi_status = errno_to_bi_status(-error); + bio_endio(bio); +} +#else +#define BIO_END_IO_ERROR(bio) (-(bio->bi_error)) +#define BIO_END_IO_PROTO(fn, x, z) static void fn(struct bio *x) +#define BIO_END_IO(bio, error) bio_set_bi_error(bio, error) +static inline void +bio_set_bi_error(struct bio *bio, int error) +{ + ASSERT3S(error, <=, 0); + bio->bi_error = error; + bio_endio(bio); +} +#endif /* HAVE_BIO_BI_STATUS */ + #else #define BIO_END_IO_PROTO(fn, x, z) static void fn(struct bio *x, int z) #define BIO_END_IO(bio, error) bio_endio(bio, error); diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c index 3fdf5642b104..f87f7913eacc 100644 --- a/module/zfs/vdev_disk.c +++ b/module/zfs/vdev_disk.c @@ -427,7 +427,7 @@ BIO_END_IO_PROTO(vdev_disk_physio_completion, bio, error) if (dr->dr_error == 0) { #ifdef HAVE_1ARG_BIO_END_IO_T - dr->dr_error = -(bio->bi_error); + dr->dr_error = BIO_END_IO_ERROR(bio); #else if (error) dr->dr_error = -(error); @@ -618,15 +618,16 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio, return (error); } -BIO_END_IO_PROTO(vdev_disk_io_flush_completion, bio, rc) +BIO_END_IO_PROTO(vdev_disk_io_flush_completion, bio, error) { zio_t *zio = bio->bi_private; #ifdef HAVE_1ARG_BIO_END_IO_T - int rc = bio->bi_error; + zio->io_error = BIO_END_IO_ERROR(bio); +#else + zio->io_error = -error; #endif - zio->io_error = -rc; - if (rc && (rc == -EOPNOTSUPP)) + if (zio->io_error && (zio->io_error == EOPNOTSUPP)) zio->io_vd->vdev_nowritecache = B_TRUE; bio_put(bio);