aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/conf/GENERIC2
-rw-r--r--sys/amd64/conf/GENERIC-NODEBUG2
-rw-r--r--sys/cam/cam_ccb.h6
-rw-r--r--sys/cam/cam_periph.c5
-rw-r--r--sys/cam/cam_xpt.c17
-rw-r--r--sys/cam/scsi/scsi_da.c15
-rw-r--r--sys/conf/options2
-rw-r--r--sys/dev/mps/mps_sas.c9
-rw-r--r--sys/geom/geom_dev.c1
-rw-r--r--sys/geom/geom_disk.c2
-rw-r--r--sys/geom/geom_io.c12
-rw-r--r--sys/geom/geom_subr.c4
-rw-r--r--sys/geom/geom_vfs.c4
-rw-r--r--sys/geom/part/g_part.c2
-rw-r--r--sys/kern/vfs_bio.c31
-rw-r--r--sys/kern/vfs_cluster.c1
-rw-r--r--sys/sys/bio.h20
-rw-r--r--sys/sys/buf.h20
-rw-r--r--sys/vm/vm_pager.c2
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);