]> git.proxmox.com Git - mirror_zfs.git/commitdiff
vdev_disk: disable flushes if device does not support it
authorRob N <robn@despairlabs.com>
Thu, 2 May 2024 22:18:35 +0000 (08:18 +1000)
committerGitHub <noreply@github.com>
Thu, 2 May 2024 22:18:35 +0000 (15:18 -0700)
If the underlying device doesn't have a write-back cache, the kernel
will just return a successful response. This doesn't hurt anything, but
it's extra work on the IO taskqs that are unnecessary. So, detect this
when we open the device for the first time.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #16148

include/os/linux/kernel/linux/blkdev_compat.h
module/os/linux/zfs/vdev_disk.c

index b0f398354e4f5ed7f0a25e7466fda9dd227f9df1..658f546213dea5d54925a25b3a415b2a1710ad7d 100644 (file)
@@ -94,6 +94,33 @@ blk_queue_set_write_cache(struct request_queue *q, bool wc, bool fua)
 #endif
 }
 
+/*
+ * Detect if a device has a write cache. Used to set the intial value for the
+ * vdev nowritecache flag.
+ *
+ * 4.10: QUEUE_FLAG_WC added. Initialised by the driver, but can be changed
+ *       later by the operator. If not set, kernel will return flush requests
+ *       immediately without doing anything.
+ * 6.6: QUEUE_FLAG_HW_WC added. Initialised by the driver, can't be changed.
+ *      Only controls if the operator is allowed to change _WC. Initial version
+ *      buggy; aliased to QUEUE_FLAG_FUA, so unuseable.
+ * 6.6.10, 6.7: QUEUE_FLAG_HW_WC fixed.
+ *
+ * Older than 4.10 we just assume write cache, and let the normal flush fail
+ * detection apply.
+ */
+static inline boolean_t
+zfs_bdev_has_write_cache(struct block_device *bdev)
+{
+#if defined(QUEUE_FLAG_HW_WC) && QUEUE_FLAG_HW_WC != QUEUE_FLAG_FUA
+       return (test_bit(QUEUE_FLAG_HW_WC, &bdev_get_queue(bdev)->queue_flags));
+#elif defined(QUEUE_FLAG_WC)
+       return (test_bit(QUEUE_FLAG_WC, &bdev_get_queue(bdev)->queue_flags));
+#else
+       return (B_TRUE);
+#endif
+}
+
 static inline void
 blk_queue_set_read_ahead(struct request_queue *q, unsigned long ra_pages)
 {
index 2cea61a6294cf0860b20aad8faef7687173d8dee..463c5f705102956ab6a8357e60fdd80f797e65e3 100644 (file)
@@ -429,8 +429,11 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
        /*  Determine the logical block size */
        int logical_block_size = bdev_logical_block_size(bdev);
 
-       /* Clear the nowritecache bit, causes vdev_reopen() to try again. */
-       v->vdev_nowritecache = B_FALSE;
+       /*
+        * If the device has a write cache, clear the nowritecache flag,
+        * so that we start issuing flush requests again.
+        */
+       v->vdev_nowritecache = !zfs_bdev_has_write_cache(bdev);
 
        /* Set when device reports it supports TRIM. */
        v->vdev_has_trim = bdev_discard_supported(bdev);