git: 4a3a5de8ace3 - main - nda: Update trim stats with the periph lock held

From: Warner Losh <imp_at_FreeBSD.org>
Date: Tue, 06 Oct 2026 22:58:49 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=4a3a5de8ace3c41da35f0fbac4d2549b868d1091

commit 4a3a5de8ace3c41da35f0fbac4d2549b868d1091
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-10-06 22:45:36 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-10-06 22:46:22 +0000

    nda: Update trim stats with the periph lock held
    
    Separate the updating the stats for the completion from the biodone for
    each one.
    
    Sponsored by:           Netflix
    Reviewed by:            ali_mashtizadeh.com
    Differential Revision:  https://reviews.freebsd.org/D60155
---
 sys/cam/cam_iosched.c  | 22 ++++++++++++++++++++++
 sys/cam/cam_iosched.h  |  2 ++
 sys/cam/nvme/nvme_da.c | 22 ++++------------------
 3 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/sys/cam/cam_iosched.c b/sys/cam/cam_iosched.c
index e807301c6302..822adffc93e5 100644
--- a/sys/cam/cam_iosched.c
+++ b/sys/cam/cam_iosched.c
@@ -1822,6 +1822,28 @@ cam_iosched_bio_update_stats(struct cam_iosched_softc *isc, struct bio *bp,
 	return retval;
 }
 
+/*
+ * Update completion status and statistics for each bio in a queue.
+ * The queue is not modified.
+ */
+void
+cam_iosched_bio_queue_update_stats(struct cam_iosched_softc *isc,
+    struct bio_queue *queue, union ccb *done_ccb, int error)
+{
+	struct bio *bp;
+
+	TAILQ_FOREACH(bp, queue, bio_queue) {
+		bp->bio_error = error;
+		if (error != 0) {
+			bp->bio_flags |= BIO_ERROR;
+			bp->bio_resid = bp->bio_bcount;
+		} else
+			bp->bio_resid = 0;
+		cam_iosched_bio_update_stats(isc, bp, done_ccb);
+		done_ccb = NULL;
+	}
+}
+
 /*
  * Tell the io scheduler that you've pushed a trim down into the sim.
  * This also tells the I/O scheduler not to push any more trims down, so
diff --git a/sys/cam/cam_iosched.h b/sys/cam/cam_iosched.h
index cbe6a20fb871..9fc9d4a91b22 100644
--- a/sys/cam/cam_iosched.h
+++ b/sys/cam/cam_iosched.h
@@ -100,6 +100,8 @@ void cam_iosched_set_work_flags(struct cam_iosched_softc *isc, uint32_t flags);
 void cam_iosched_clr_work_flags(struct cam_iosched_softc *isc, uint32_t flags);
 void cam_iosched_trim_done(struct cam_iosched_softc *isc);
 int cam_iosched_bio_update_stats(struct cam_iosched_softc *isc, struct bio *bp, union ccb *done_ccb);
+void cam_iosched_bio_queue_update_stats(struct cam_iosched_softc *isc,
+    struct bio_queue *queue, union ccb *done_ccb, int error);
 void cam_iosched_set_latfcn(struct cam_iosched_softc *isc, cam_iosched_latfcn_t, void *);
 void cam_iosched_set_trim_goal(struct cam_iosched_softc *isc, int goal);
 void cam_iosched_set_trim_ticks(struct cam_iosched_softc *isc, int ticks);
diff --git a/sys/cam/nvme/nvme_da.c b/sys/cam/nvme/nvme_da.c
index fe5c87c5428a..dc06d2d0d0ab 100644
--- a/sys/cam/nvme/nvme_da.c
+++ b/sys/cam/nvme/nvme_da.c
@@ -1329,8 +1329,8 @@ ndadone(struct cam_periph *periph, union ccb *done_ccb)
 			biodone(bp);
 		} else { /* state == NDA_CCB_TRIM */
 			struct nda_trim_request *trim;
-			struct bio *bp1, *bp2;
-			TAILQ_HEAD(, bio) queue;
+			struct bio *bp2;
+			struct bio_queue queue;
 
 			trim = nvmeio->ccb_trim;
 			TAILQ_INIT(&queue);
@@ -1342,28 +1342,14 @@ ndadone(struct cam_periph *periph, union ccb *done_ccb)
 			 * need to call this here.
 			 * cam_iosched_trim_done(softc->cam_iosched);
 			 */
-			/*
-			 * The the I/O scheduler that we're finishing the I/O
-			 * so we can keep book. The first one we pass in the CCB
-			 * which has the timing information. The rest we pass in NULL
-			 * so we can keep proper counts.
-			 */
-			bp1 = TAILQ_FIRST(&queue);
-			cam_iosched_bio_update_stats(softc->cam_iosched, bp1, done_ccb);
+			cam_iosched_bio_queue_update_stats(softc->cam_iosched,
+			    &queue, done_ccb, error);
 			xpt_release_ccb(done_ccb);
 			softc->outstanding_cmds--;
 			ndaschedule(periph);
 			cam_periph_unlock(periph);
 			while ((bp2 = TAILQ_FIRST(&queue)) != NULL) {
 				TAILQ_REMOVE(&queue, bp2, bio_queue);
-				bp2->bio_error = error;
-				if (error != 0) {
-					bp2->bio_flags |= BIO_ERROR;
-					bp2->bio_resid = bp1->bio_bcount;
-				} else
-					bp2->bio_resid = 0;
-				if (bp1 != bp2)
-					cam_iosched_bio_update_stats(softc->cam_iosched, bp2, NULL);
 				biodone(bp2);
 			}
 		}