diff options
| -rw-r--r-- | sys/amd64/conf/GENERIC | 2 | ||||
| -rw-r--r-- | sys/amd64/conf/GENERIC-NODEBUG | 2 | ||||
| -rw-r--r-- | sys/cam/cam_ccb.h | 6 | ||||
| -rw-r--r-- | sys/cam/cam_periph.c | 5 | ||||
| -rw-r--r-- | sys/cam/cam_xpt.c | 17 | ||||
| -rw-r--r-- | sys/cam/scsi/scsi_da.c | 15 | ||||
| -rw-r--r-- | sys/conf/options | 2 | ||||
| -rw-r--r-- | sys/dev/mps/mps_sas.c | 9 | ||||
| -rw-r--r-- | sys/geom/geom_dev.c | 1 | ||||
| -rw-r--r-- | sys/geom/geom_disk.c | 2 | ||||
| -rw-r--r-- | sys/geom/geom_io.c | 12 | ||||
| -rw-r--r-- | sys/geom/geom_subr.c | 4 | ||||
| -rw-r--r-- | sys/geom/geom_vfs.c | 4 | ||||
| -rw-r--r-- | sys/geom/part/g_part.c | 2 | ||||
| -rw-r--r-- | sys/kern/vfs_bio.c | 31 | ||||
| -rw-r--r-- | sys/kern/vfs_cluster.c | 1 | ||||
| -rw-r--r-- | sys/sys/bio.h | 20 | ||||
| -rw-r--r-- | sys/sys/buf.h | 20 | ||||
| -rw-r--r-- | sys/vm/vm_pager.c | 2 |
19 files changed, 157 insertions, 0 deletions
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index d727d5349f00..bbb2beca5413 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -83,7 +83,9 @@ options RCTL # Resource limits options KDB # Enable kernel debugger support. options KDB_TRACE # Print a stack trace for a panic. # For full debugger support use (turn off in stable branch): +options BUF_TRACKING # Track buffer history options DDB # Support DDB. +options FULL_BUF_TRACKING # Track more buffer history options GDB # Support remote GDB. options DEADLKRES # Enable the deadlock resolver options INVARIANTS # Enable calls of extra sanity checking diff --git a/sys/amd64/conf/GENERIC-NODEBUG b/sys/amd64/conf/GENERIC-NODEBUG index be8e6af34382..6d4e4b05206f 100644 --- a/sys/amd64/conf/GENERIC-NODEBUG +++ b/sys/amd64/conf/GENERIC-NODEBUG @@ -34,5 +34,7 @@ nooptions INVARIANTS nooptions INVARIANT_SUPPORT nooptions WITNESS nooptions WITNESS_SKIPSPIN +nooptions BUF_TRACKING nooptions DEADLKRES +nooptions FULL_BUF_TRACKING diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h index 9ec266e84cc1..b638ab1dba9f 100644 --- a/sys/cam/cam_ccb.h +++ b/sys/cam/cam_ccb.h @@ -744,6 +744,9 @@ struct ccb_scsiio { #define CAM_TAG_ACTION_NONE 0x00 u_int tag_id; /* tag id from initator (target mode) */ u_int init_id; /* initiator id of who selected */ +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + struct bio *bio; /* Associated bio */ +#endif }; static __inline uint8_t * @@ -1335,6 +1338,9 @@ cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries, csio->sense_len = sense_len; csio->cdb_len = cdb_len; csio->tag_action = tag_action; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + csio->bio = NULL; +#endif } static __inline void diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index 942a6c30376f..ae4134504b9c 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -1427,6 +1427,11 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig, union ccb *orig_ccb = ccb; int error, recoveryccb; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + if (ccb->ccb_h.func_code == XPT_SCSI_IO && ccb->csio.bio != NULL) + biotrack(ccb->csio.bio, __func__); +#endif + periph = xpt_path_periph(ccb->ccb_h.path); recoveryccb = (ccb->ccb_h.cbfcnp == camperiphdone); if ((periph->flags & CAM_PERIPH_RECOVERY_INPROG) && !recoveryccb) { diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index cfca7807c781..34018052ed60 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/bio.h> #include <sys/bus.h> #include <sys/systm.h> #include <sys/types.h> @@ -4471,6 +4472,12 @@ xpt_done(union ccb *done_ccb) struct cam_doneq *queue; int run, hash; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + if (done_ccb->ccb_h.func_code == XPT_SCSI_IO && + done_ccb->csio.bio != NULL) + biotrack(done_ccb->csio.bio, __func__); +#endif + CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done: func= %#x %s status %#x\n", done_ccb->ccb_h.func_code, @@ -5189,6 +5196,16 @@ xpt_done_process(struct ccb_hdr *ccb_h) struct cam_devq *devq; struct mtx *mtx = NULL; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + struct ccb_scsiio *csio; + + if (ccb_h->func_code == XPT_SCSI_IO) { + csio = &((union ccb *)ccb_h)->csio; + if (csio->bio != NULL) + biotrack(csio->bio, __func__); + } +#endif + if (ccb_h->flags & CAM_HIGH_POWER) { struct highpowerlist *hphead; struct cam_ed *device; diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 977ac8d6252b..16d8ef7b07ca 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -2949,6 +2949,8 @@ more: void *data_ptr; int rw_op; + biotrack(bp, __func__); + if (bp->bio_cmd == BIO_WRITE) { softc->flags |= DA_FLAG_DIRTY; rw_op = SCSI_RW_WRITE; @@ -2976,6 +2978,9 @@ more: /*dxfer_len*/ bp->bio_bcount, /*sense_len*/SSD_FULL_SIZE, da_default_timeout * 1000); +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + start_ccb->csio.bio = bp; +#endif break; } case BIO_FLUSH: @@ -4008,6 +4013,10 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone\n")); csio = &done_ccb->csio; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + if (csio->bio != NULL) + biotrack(csio->bio, __func__); +#endif state = csio->ccb_h.ccb_state & DA_CCB_TYPE_MASK; switch (state) { case DA_CCB_BUFFER_IO: @@ -4106,6 +4115,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) } } + biotrack(bp, __func__); LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); if (LIST_EMPTY(&softc->pending_ccbs)) softc->flags |= DA_FLAG_WAS_OTAG; @@ -5219,6 +5229,11 @@ daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) struct cam_periph *periph; int error, error_code, sense_key, asc, ascq; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + if (ccb->csio.bio != NULL) + biotrack(ccb->csio.bio, __func__); +#endif + periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct da_softc *)periph->softc; diff --git a/sys/conf/options b/sys/conf/options index 9004832b1b36..79f71a8e487c 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -50,12 +50,14 @@ TWA_FLASH_FIRMWARE opt_twa.h # Debugging options. ALT_BREAK_TO_DEBUGGER opt_kdb.h BREAK_TO_DEBUGGER opt_kdb.h +BUF_TRACKING opt_global.h DDB DDB_BUFR_SIZE opt_ddb.h DDB_CAPTURE_DEFAULTBUFSIZE opt_ddb.h DDB_CAPTURE_MAXBUFSIZE opt_ddb.h DDB_CTF opt_ddb.h DDB_NUMSYM opt_ddb.h +FULL_BUF_TRACKING opt_global.h GDB KDB opt_global.h KDB_TRACE opt_kdb.h diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c index 2f23612204f3..2ff4389a1a25 100644 --- a/sys/dev/mps/mps_sas.c +++ b/sys/dev/mps/mps_sas.c @@ -1872,6 +1872,10 @@ mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb) } } +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + if (csio->bio != NULL) + biotrack(csio->bio, __func__); +#endif callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, mpssas_scsiio_timeout, cm, 0); @@ -2125,6 +2129,11 @@ mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm) TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED); +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + if (ccb->csio.bio != NULL) + biotrack(ccb->csio.bio, __func__); +#endif + if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) { TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); if (cm->cm_reply != NULL) diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c index d74b92e59776..3ccbd583fa2d 100644 --- a/sys/geom/geom_dev.c +++ b/sys/geom/geom_dev.c @@ -668,6 +668,7 @@ g_dev_strategy(struct bio *bp) sc = cp->private; KASSERT(cp->acr || cp->acw, ("Consumer with zero access count in g_dev_strategy")); + biotrack(bp, __func__); #ifdef INVARIANTS if ((bp->bio_offset % cp->provider->sectorsize) != 0 || (bp->bio_bcount % cp->provider->sectorsize) != 0) { diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index 8c3ec6452cb3..dbaa6b524db3 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -421,6 +421,8 @@ g_disk_start(struct bio *bp) int error; off_t off; + biotrack(bp, __func__); + sc = bp->bio_to->private; if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) { g_io_deliver(bp, ENXIO); diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index dbb346842df7..e192f67d94d4 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -223,6 +223,9 @@ g_clone_bio(struct bio *bp) /* Inherit classification info from the parent */ bp2->bio_classifier1 = bp->bio_classifier1; bp2->bio_classifier2 = bp->bio_classifier2; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + bp2->bio_track_bp = bp->bio_track_bp; +#endif bp->bio_children++; } #ifdef KTR @@ -362,6 +365,8 @@ g_io_check(struct bio *bp) off_t excess; int error; + biotrack(bp, __func__); + cp = bp->bio_from; pp = bp->bio_to; @@ -503,6 +508,8 @@ g_run_classifiers(struct bio *bp) struct g_classifier_hook *hook; int classified = 0; + biotrack(bp, __func__); + TAILQ_FOREACH(hook, &g_classifier_tailq, link) classified |= hook->func(hook->arg, bp); @@ -518,6 +525,8 @@ g_io_request(struct bio *bp, struct g_consumer *cp) int direct, error, first; uint8_t cmd; + biotrack(bp, __func__); + KASSERT(cp != NULL, ("NULL cp in g_io_request")); KASSERT(bp != NULL, ("NULL bp in g_io_request")); pp = cp->provider; @@ -644,6 +653,8 @@ g_io_deliver(struct bio *bp, int error) struct mtx *mtxp; int direct, first; + biotrack(bp, __func__); + KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); pp = bp->bio_to; KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); @@ -835,6 +846,7 @@ g_io_schedule_down(struct thread *tp __unused) } CTR0(KTR_GEOM, "g_down has work to do"); g_bioq_unlock(&g_bio_run_down); + biotrack(bp, __func__); if (pace != 0) { /* * There has been at least one memory allocation diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index d0df840945c4..33416063eec6 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -1531,6 +1531,10 @@ DB_SHOW_COMMAND(bio, db_show_bio) db_printf(" caller2: %p\n", bp->bio_caller2); db_printf(" bio_from: %p\n", bp->bio_from); db_printf(" bio_to: %p\n", bp->bio_to); + +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + db_printf(" bio_track_bp: %p\n", bp->bio_track_bp); +#endif } } diff --git a/sys/geom/geom_vfs.c b/sys/geom/geom_vfs.c index eda4b75b0891..c59cc6a569e2 100644 --- a/sys/geom/geom_vfs.c +++ b/sys/geom/geom_vfs.c @@ -192,6 +192,10 @@ g_vfs_strategy(struct bufobj *bo, struct buf *bp) } bip->bio_done = g_vfs_done; bip->bio_caller2 = bp; +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + buf_track(bp, __func__); + bip->bio_track_bp = bp; +#endif g_io_request(bip, cp); } diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index a7513980e3ba..4f52398ca0b9 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -2154,6 +2154,8 @@ g_part_start(struct bio *bp) struct g_provider *pp; char buf[64]; + biotrack(bp, __func__); + pp = bp->bio_to; gp = pp->geom; table = gp->softc; diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 51e9cf2f738e..b19e4d73b0db 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1952,6 +1952,7 @@ bufwrite(struct buf *bp) if (oldflags & B_ASYNC) BUF_KERNPROC(bp); bp->b_iooffset = dbtob(bp->b_blkno); + buf_track(bp, __func__); bstrategy(bp); if ((oldflags & B_ASYNC) == 0) { @@ -2078,6 +2079,8 @@ bdwrite(struct buf *bp) VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL); } + buf_track(bp, __func__); + /* * Set the *dirty* buffer range based upon the VM system dirty * pages. @@ -2386,6 +2389,8 @@ brelse(struct buf *bp) brelvp(bp); } + buf_track(bp, __func__); + /* buffers with no memory */ if (bp->b_bufsize == 0) { buf_free(bp); @@ -2470,6 +2475,7 @@ bqrelse(struct buf *bp) binsfree(bp, qindex); out: + buf_track(bp, __func__); /* unlock */ BUF_UNLOCK(bp); if (qindex == QUEUE_CLEAN) @@ -3716,6 +3722,7 @@ loop: CTR4(KTR_BUF, "getblk(%p, %ld, %d) = %p", vp, (long)blkno, size, bp); BUF_ASSERT_HELD(bp); end: + buf_track(bp, __func__); KASSERT(bp->b_bufobj == bo, ("bp %p wrong b_bufobj %p should be %p", bp, bp->b_bufobj, bo)); return (bp); @@ -3892,6 +3899,7 @@ biodone(struct bio *bp) void (*done)(struct bio *); vm_offset_t start, end; + biotrack(bp, __func__); if ((bp->bio_flags & BIO_TRANSIENT_MAPPING) != 0) { bp->bio_flags &= ~BIO_TRANSIENT_MAPPING; bp->bio_flags |= BIO_UNMAPPED; @@ -3948,6 +3956,15 @@ biofinish(struct bio *bp, struct devstat *stat, int error) biodone(bp); } +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) +void +biotrack_buf(struct bio *bp, const char *location) +{ + + buf_track(bp->bio_track_bp, location); +} +#endif + /* * bufwait: * @@ -3998,6 +4015,7 @@ bufdone(struct buf *bp) struct bufobj *dropobj; void (*biodone)(struct buf *); + buf_track(bp, __func__); CTR3(KTR_BUF, "bufdone(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); dropobj = NULL; @@ -4801,6 +4819,9 @@ DB_SHOW_COMMAND(buffer, db_show_buffer) { /* get args */ struct buf *bp = (struct buf *)addr; +#ifdef FULL_BUF_TRACKING + uint32_t i, j; +#endif if (!have_addr) { db_printf("usage: show buffer <addr>\n"); @@ -4837,6 +4858,16 @@ DB_SHOW_COMMAND(buffer, db_show_buffer) } db_printf("\n"); } +#if defined(FULL_BUF_TRACKING) + db_printf("b_io_tracking: b_io_tcnt = %u\n", bp->b_io_tcnt); + + i = bp->b_io_tcnt % BUF_TRACKING_SIZE; + for (j = 1; j <= BUF_TRACKING_SIZE; j++) + db_printf(" %2u: %s\n", j, + bp->b_io_tracking[BUF_TRACKING_ENTRY(i - j)]); +#elif defined(BUF_TRACKING) + db_printf("b_io_tracking: %s\n", bp->b_io_tracking); +#endif db_printf(" "); BUF_LOCKPRINTINFO(bp); } diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c index 018be4860005..532261e8625f 100644 --- a/sys/kern/vfs_cluster.c +++ b/sys/kern/vfs_cluster.c @@ -1008,6 +1008,7 @@ cluster_wbuild(struct vnode *vp, long size, daddr_t start_lbn, int len, reassignbuf(tbp); /* put on clean list */ bufobj_wref(tbp->b_bufobj); BUF_KERNPROC(tbp); + buf_track(tbp, __func__); TAILQ_INSERT_TAIL(&bp->b_cluster.cluster_head, tbp, b_cluster.cluster_entry); } diff --git a/sys/sys/bio.h b/sys/sys/bio.h index 8821fef59bb3..9c669537e7ed 100644 --- a/sys/sys/bio.h +++ b/sys/sys/bio.h @@ -121,6 +121,9 @@ struct bio { void *_bio_caller2; uint8_t _bio_cflags; #endif +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) + struct buf *bio_track_bp; /* Parent buf for tracking */ +#endif /* XXX: these go away when bio chaining is introduced */ daddr_t bio_pblkno; /* physical block number */ @@ -142,6 +145,23 @@ void biodone(struct bio *bp); void biofinish(struct bio *bp, struct devstat *stat, int error); int biowait(struct bio *bp, const char *wchan); +#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) +void biotrack_buf(struct bio *bp, const char *location); + +static __inline void +biotrack(struct bio *bp, const char *location) +{ + + if (bp->bio_track_bp != NULL) + biotrack_buf(bp, location); +} +#else +static __inline void +biotrack(struct bio *bp __unused, const char *location __unused) +{ +} +#endif + void bioq_disksort(struct bio_queue_head *ap, struct bio *bp); struct bio *bioq_first(struct bio_queue_head *head); struct bio *bioq_takefirst(struct bio_queue_head *head); diff --git a/sys/sys/buf.h b/sys/sys/buf.h index 034671e794d1..f1d08d728bf8 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -140,6 +140,15 @@ struct buf { void *b_fsprivate1; void *b_fsprivate2; void *b_fsprivate3; + +#if defined(FULL_BUF_TRACKING) +#define BUF_TRACKING_SIZE 32 +#define BUF_TRACKING_ENTRY(x) ((x) & (BUF_TRACKING_SIZE - 1)) + const char *b_io_tracking[BUF_TRACKING_SIZE]; + uint32_t b_io_tcnt; +#elif defined(BUF_TRACKING) + const char *b_io_tracking; +#endif }; #define b_object b_bufobj->bo_object @@ -429,6 +438,17 @@ buf_countdeps(struct buf *bp, int i) return (0); } +static __inline void +buf_track(struct buf *bp, const char *location) +{ + +#if defined(FULL_BUF_TRACKING) + bp->b_io_tracking[BUF_TRACKING_ENTRY(bp->b_io_tcnt++)] = location; +#elif defined(BUF_TRACKING) + bp->b_io_tracking = location; +#endif +} + #endif /* _KERNEL */ /* diff --git a/sys/vm/vm_pager.c b/sys/vm/vm_pager.c index fccd1c8b8c96..87557aef472b 100644 --- a/sys/vm/vm_pager.c +++ b/sys/vm/vm_pager.c @@ -376,6 +376,7 @@ initpbuf(struct buf *bp) bp->b_iodone = NULL; bp->b_error = 0; BUF_LOCK(bp, LK_EXCLUSIVE, NULL); + buf_track(bp, __func__); } /* @@ -473,6 +474,7 @@ relpbuf(struct buf *bp, int *pfreecnt) KASSERT(bp->b_vp == NULL, ("relpbuf with vp")); KASSERT(bp->b_bufobj == NULL, ("relpbuf with bufobj")); + buf_track(bp, __func__); BUF_UNLOCK(bp); mtx_lock(&pbuf_mtx); |
