Skip to content

Commit

Permalink
vdev_disk: disable flushes if device does not support it
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Rob Norris <[email protected]>
Closes #16148
  • Loading branch information
robn authored May 2, 2024
1 parent 645b833 commit 8f1b7a6
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
27 changes: 27 additions & 0 deletions include/os/linux/kernel/linux/blkdev_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
7 changes: 5 additions & 2 deletions module/os/linux/zfs/vdev_disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 8f1b7a6

Please sign in to comment.