Skip to content

Commit 7a97f21

Browse files
committed
vdev_disk: add BIO filling debug option
Set zfs_vdev_disk_debug_bio_fill=1. If the kernel rejects an IO, OpenZFS will log some stuff describing how the IO was constructed, which hopefully will help us understand what happened. Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
1 parent 9c56b8e commit 7a97f21

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

module/os/linux/zfs/vdev_disk.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ typedef struct vdev_disk {
8484
*/
8585
uint_t zfs_vdev_disk_max_segs = 0;
8686

87+
/*
88+
* BIO fill debugging. 0 disables it (default). If enabled, the BIO fill layout
89+
* is record if as its filled. If set to 1, layout is logged to the kernel log
90+
* on error. If 2, layout is logged for all IOs.
91+
*/
92+
uint_t zfs_vdev_disk_debug_bio_fill = 0;
93+
94+
#define DEBUG_BIO_FILL_ALLOC_SIZE (256)
95+
8796
/*
8897
* Unique identifier for the exclusive vdev holder.
8998
*/
@@ -689,6 +698,11 @@ typedef struct {
689698

690699
struct bio *vbio_bio; /* pointer to the current bio */
691700
int vbio_flags; /* bio flags */
701+
702+
/* debugging info, when zfs_vdev_disk_debug_bio_fill > 0 */
703+
char *vbio_debug;
704+
size_t vbio_debug_size;
705+
size_t vbio_debug_pos;
692706
} vbio_t;
693707

694708
static vbio_t *
@@ -706,9 +720,56 @@ vbio_alloc(zio_t *zio, struct block_device *bdev, int flags)
706720
vbio->vbio_bio = NULL;
707721
vbio->vbio_flags = flags;
708722

723+
if (zfs_vdev_disk_debug_bio_fill > 0) {
724+
vbio->vbio_debug =
725+
kmem_alloc(DEBUG_BIO_FILL_ALLOC_SIZE, KM_SLEEP);
726+
vbio->vbio_debug_size = DEBUG_BIO_FILL_ALLOC_SIZE;
727+
vbio->vbio_debug_pos = 0;
728+
}
729+
709730
return (vbio);
710731
}
711732

733+
static inline void
734+
vbio_debug_append(vbio_t *vbio, char c)
735+
{
736+
if (vbio->vbio_debug == NULL)
737+
return;
738+
739+
vbio->vbio_debug[vbio->vbio_debug_pos++] = c;
740+
741+
if (vbio->vbio_debug_pos < vbio->vbio_debug_size)
742+
return;
743+
744+
size_t new_size = vbio->vbio_debug_size * 2;
745+
char *new = kmem_alloc(new_size, KM_SLEEP);
746+
memcpy(new, vbio->vbio_debug, vbio->vbio_debug_size);
747+
kmem_free(vbio->vbio_debug, vbio->vbio_debug_size);
748+
vbio->vbio_debug = new;
749+
vbio->vbio_debug_size = new_size;
750+
}
751+
752+
static inline void
753+
vbio_debug_append_size(vbio_t *vbio, size_t ssize)
754+
{
755+
const uint_t nlb = (ssize / ((~vbio->vbio_lbs_mask)+1));
756+
const char cnlb = (nlb < 10) ? (nlb + 0x30) : (nlb + (0x97-10));
757+
vbio_debug_append(vbio, cnlb);
758+
759+
}
760+
761+
static void
762+
vbio_debug_log(vbio_t *vbio)
763+
{
764+
printk(KERN_INFO "vbio debug: vd=%llu ms=%x mb=%x bs=%x "
765+
"ty=%u sz=%llx bt=%c %.*s\n", vbio->vbio_zio->io_vd->vdev_id,
766+
vbio->vbio_max_segs, vbio->vbio_max_bytes, (~vbio->vbio_lbs_mask)+1,
767+
vbio->vbio_zio->io_type, vbio->vbio_zio->io_size,
768+
abd_is_linear(vbio->vbio_zio->io_abd) ? 'L' :
769+
abd_is_gang(vbio->vbio_zio->io_abd) ? 'G' : 'S',
770+
(int)vbio->vbio_debug_pos, vbio->vbio_debug);
771+
}
772+
712773
BIO_END_IO_PROTO(vbio_completion, bio, error);
713774

714775
static int
@@ -717,6 +778,9 @@ vbio_add_page(vbio_t *vbio, struct page *page, uint_t size, uint_t offset)
717778
struct bio *bio = vbio->vbio_bio;
718779
uint_t ssize;
719780

781+
vbio_debug_append_size(vbio, size);
782+
vbio_debug_append(vbio, '[');
783+
720784
while (size > 0) {
721785
if (bio == NULL) {
722786
/* New BIO, allocate and set up */
@@ -730,10 +794,13 @@ vbio_add_page(vbio_t *vbio, struct page *page, uint_t size, uint_t offset)
730794
WRITE : READ, vbio->vbio_flags);
731795

732796
if (vbio->vbio_bio) {
797+
vbio_debug_append(vbio, '$');
733798
bio_chain(vbio->vbio_bio, bio);
734799
vdev_submit_bio(vbio->vbio_bio);
735800
}
736801
vbio->vbio_bio = bio;
802+
803+
vbio_debug_append(vbio, '^');
737804
}
738805

739806
/*
@@ -748,19 +815,25 @@ vbio_add_page(vbio_t *vbio, struct page *page, uint_t size, uint_t offset)
748815
vbio->vbio_lbs_mask);
749816
if (ssize > 0 &&
750817
bio_add_page(bio, page, ssize, offset) == ssize) {
818+
vbio_debug_append_size(vbio, ssize);
751819
/* Accepted, adjust and load any remaining. */
752820
size -= ssize;
753821
offset += ssize;
754822
continue;
755823
}
756824

825+
vbio_debug_append_size(vbio, ssize);
826+
vbio_debug_append(vbio, '!');
827+
757828
/* No room, set up for a new BIO and loop */
758829
vbio->vbio_offset += BIO_BI_SIZE(bio);
759830

760831
/* Signal new BIO allocation wanted */
761832
bio = NULL;
762833
}
763834

835+
vbio_debug_append(vbio, ']');
836+
764837
return (0);
765838
}
766839

@@ -799,6 +872,7 @@ vbio_submit(vbio_t *vbio, abd_t *abd, uint64_t size)
799872
* called and free the vbio before this task is run again, so we must
800873
* consider it invalid from this point.
801874
*/
875+
vbio_debug_append(vbio, '$');
802876
vdev_submit_bio(vbio->vbio_bio);
803877

804878
blk_finish_plug(&plug);
@@ -830,6 +904,14 @@ BIO_END_IO_PROTO(vbio_completion, bio, error)
830904
/* Return the BIO to the kernel */
831905
bio_put(bio);
832906

907+
/* Emit debug output if wanted */
908+
if (vbio->vbio_debug != NULL) {
909+
if ((zfs_vdev_disk_debug_bio_fill == 1 && zio->io_error != 0) ||
910+
zfs_vdev_disk_debug_bio_fill == 2)
911+
vbio_debug_log(vbio);
912+
kmem_free(vbio->vbio_debug, vbio->vbio_debug_size);
913+
}
914+
833915
/*
834916
* If we copied the ABD before issuing it, clean up and return the copy
835917
* to the ADB, with changes if appropriate.
@@ -1663,3 +1745,6 @@ ZFS_MODULE_PARAM(zfs_vdev_disk, zfs_vdev_disk_, max_segs, UINT, ZMOD_RW,
16631745
ZFS_MODULE_PARAM_CALL(zfs_vdev_disk, zfs_vdev_disk_, classic,
16641746
vdev_disk_param_set_classic, param_get_uint, ZMOD_RD,
16651747
"Use classic BIO submission method");
1748+
1749+
ZFS_MODULE_PARAM(zfs_vdev_disk, zfs_vdev_disk_, debug_bio_fill, UINT, ZMOD_RW,
1750+
"BIO fill debugging: 0 - disable, 1 - errors only, 2 - everything");

0 commit comments

Comments
 (0)