diff --git a/include/linux/blkdev_compat.h b/include/linux/blkdev_compat.h index 748963be81..ec301ee9b5 100644 --- a/include/linux/blkdev_compat.h +++ b/include/linux/blkdev_compat.h @@ -332,15 +332,30 @@ bio_set_flags_failfast(struct block_device *bdev, int *flags) #endif /* - * 2.6.32 API change - * Use the normal I/O patch for discards. + * 2.6.28 - 2.6.35 API, + * BIO_RW_DISCARD + * + * 2.6.36 - 4.7 API, + * REQ_DISCARD + * + * 4.8 - 4.x API, + * REQ_OP_DISCARD + * + * In all cases the normal I/O path is used for discards. The only + * difference is how the kernel tags individual I/Os as discards. */ #ifdef QUEUE_FLAG_DISCARD -#ifdef HAVE_BIO_RW_DISCARD -#define VDEV_REQ_DISCARD (1 << BIO_RW_DISCARD) +static inline boolean_t +bio_is_discard(struct bio *bio) +{ +#if defined(HAVE_BIO_RW_DISCARD) + return (bio->bi_rw & (1 << BIO_RW_DISCARD)); +#elif defined(REQ_DISCARD) + return (bio->bi_rw & REQ_DISCARD); #else -#define VDEV_REQ_DISCARD REQ_DISCARD + return (bio_op(bio) == REQ_OP_DISCARD); #endif +} #else #error "Allowing the build will cause discard requests to become writes " "potentially triggering the DMU_MAX_ACCESS assertion. Please file a " diff --git a/include/sys/vdev_disk.h b/include/sys/vdev_disk.h index d5a1889d2a..cf8028d2ac 100644 --- a/include/sys/vdev_disk.h +++ b/include/sys/vdev_disk.h @@ -38,7 +38,7 @@ typedef struct vdev_disk { } vdev_disk_t; extern int vdev_disk_physio(struct block_device *, caddr_t, - size_t, uint64_t, int); + size_t, uint64_t, int, int); extern int vdev_disk_read_rootlabel(char *, char *, nvlist_t **); #endif /* _KERNEL */ diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c index 7c515def07..2f06e721be 100644 --- a/module/zfs/vdev_disk.c +++ b/module/zfs/vdev_disk.c @@ -494,41 +494,45 @@ bio_map(struct bio *bio, void *bio_ptr, unsigned int bio_size) return (bio_size); } +#ifndef bio_set_op_attrs +#define bio_set_op_attrs(bio, rw, flags) \ + do { (bio)->bi_rw |= (rw)|(flags); } while (0) +#endif + static inline void -vdev_submit_bio_impl(int rw, struct bio *bio) +vdev_submit_bio_impl(struct bio *bio) { #ifdef HAVE_1ARG_SUBMIT_BIO - bio->bi_rw |= rw; submit_bio(bio); #else - submit_bio(rw, bio); + submit_bio(0, bio); #endif } static inline void -vdev_submit_bio(int rw, struct bio *bio) +vdev_submit_bio(struct bio *bio) { #ifdef HAVE_CURRENT_BIO_TAIL struct bio **bio_tail = current->bio_tail; current->bio_tail = NULL; - vdev_submit_bio_impl(rw, bio); + vdev_submit_bio_impl(bio); current->bio_tail = bio_tail; #else struct bio_list *bio_list = current->bio_list; current->bio_list = NULL; - vdev_submit_bio_impl(rw, bio); + vdev_submit_bio_impl(bio); current->bio_list = bio_list; #endif } static int __vdev_disk_physio(struct block_device *bdev, zio_t *zio, caddr_t kbuf_ptr, - size_t kbuf_size, uint64_t kbuf_offset, int flags, int wait) + size_t kbuf_size, uint64_t kbuf_offset, int rw, int flags, int wait) { dio_request_t *dr; caddr_t bio_ptr; uint64_t bio_offset; - int rw, bio_size, bio_count = 16; + int bio_size, bio_count = 16; int i = 0, error = 0; ASSERT3U(kbuf_offset + kbuf_size, <=, bdev->bd_inode->i_size); @@ -541,7 +545,6 @@ retry: if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) bio_set_flags_failfast(bdev, &flags); - rw = flags; dr->dr_zio = zio; dr->dr_wait = wait; @@ -585,9 +588,9 @@ retry: dr->dr_bio[i]->bi_bdev = bdev; BIO_BI_SECTOR(dr->dr_bio[i]) = bio_offset >> 9; - dr->dr_bio[i]->bi_rw = rw; dr->dr_bio[i]->bi_end_io = vdev_disk_physio_completion; dr->dr_bio[i]->bi_private = dr; + bio_set_op_attrs(dr->dr_bio[i], rw, flags); /* Remaining size is returned to become the new size */ bio_size = bio_map(dr->dr_bio[i], bio_ptr, bio_size); @@ -605,7 +608,7 @@ retry: /* Submit all bio's associated with this dio */ for (i = 0; i < dr->dr_bio_count; i++) if (dr->dr_bio[i]) - vdev_submit_bio(rw, dr->dr_bio[i]); + vdev_submit_bio(dr->dr_bio[i]); /* * On synchronous blocking requests we wait for all bio the completion @@ -628,10 +631,11 @@ retry: int vdev_disk_physio(struct block_device *bdev, caddr_t kbuf, - size_t size, uint64_t offset, int flags) + size_t size, uint64_t offset, int rw, int flags) { bio_set_flags_failfast(bdev, &flags); - return (__vdev_disk_physio(bdev, NULL, kbuf, size, offset, flags, 1)); + return (__vdev_disk_physio(bdev, NULL, kbuf, size, offset, rw, flags, + 1)); } BIO_END_IO_PROTO(vdev_disk_io_flush_completion, bio, rc) @@ -672,7 +676,8 @@ vdev_disk_io_flush(struct block_device *bdev, zio_t *zio) bio->bi_private = zio; bio->bi_bdev = bdev; zio->io_delay = jiffies_64; - vdev_submit_bio(VDEV_WRITE_FLUSH_FUA, bio); + bio_set_op_attrs(bio, 0, VDEV_WRITE_FLUSH_FUA); + vdev_submit_bio(bio); invalidate_bdev(bdev); return (0); @@ -684,7 +689,7 @@ vdev_disk_io_start(zio_t *zio) vdev_t *v = zio->io_vd; vdev_disk_t *vd = v->vdev_tsd; zio_priority_t pri = zio->io_priority; - int flags, error; + int rw, flags, error; switch (zio->io_type) { case ZIO_TYPE_IOCTL: @@ -723,17 +728,19 @@ vdev_disk_io_start(zio_t *zio) zio_execute(zio); return; case ZIO_TYPE_WRITE: + rw = WRITE; if ((pri == ZIO_PRIORITY_SYNC_WRITE) && (v->vdev_nonrot)) flags = WRITE_SYNC; else - flags = WRITE; + flags = 0; break; case ZIO_TYPE_READ: + rw = READ; if ((pri == ZIO_PRIORITY_SYNC_READ) && (v->vdev_nonrot)) flags = READ_SYNC; else - flags = READ; + flags = 0; break; default: @@ -743,7 +750,7 @@ vdev_disk_io_start(zio_t *zio) } error = __vdev_disk_physio(vd->vd_bdev, zio, zio->io_data, - zio->io_size, zio->io_offset, flags, 0); + zio->io_size, zio->io_offset, rw, flags, 0); if (error) { zio->io_error = error; zio_interrupt(zio); @@ -844,7 +851,8 @@ vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config) /* read vdev label */ offset = vdev_label_offset(size, i, 0); if (vdev_disk_physio(bdev, (caddr_t)label, - VDEV_SKIP_SIZE + VDEV_PHYS_SIZE, offset, READ_SYNC) != 0) + VDEV_SKIP_SIZE + VDEV_PHYS_SIZE, offset, READ, + REQ_SYNC) != 0) continue; if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 8fa3e738cf..3c2a196d62 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -766,7 +766,7 @@ zvol_request(struct request_queue *q, struct bio *bio) goto out2; } - if (bio->bi_rw & VDEV_REQ_DISCARD) { + if (bio_is_discard(bio)) { error = zvol_discard(bio); goto out2; }