Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Feb 2018 05:43:55 +0000 (UTC)
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329815 - in head/sys/cam: . ata nvme scsi
Message-ID:  <201802220543.w1M5ht9k068959@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: imp
Date: Thu Feb 22 05:43:55 2018
New Revision: 329815
URL: https://svnweb.freebsd.org/changeset/base/329815

Log:
  Introduce capacity flags for periphs
  
  Introduce flags word to describe the capacities of the peripheral.
  First bit will describe if the periph driver allows multiple
  outstanding TRIMS to be active in a device.
  
  Modify the I/O scheduler so that the nda driver can queue trims
  for a while after the first one arrives. We'll queue until we see
  a I/O scheduler tick, then we'll schedule as many TRIMs as allowed
  by other factors (currently this is slocts in the NVMe controller).
  This mariginally helps the read latency issues we see with reads,
  but sets the stage for the nda driver to do TRIM collapsing like the
  da and ada drivers do today.
  
  Sponsored by: Netflix

Modified:
  head/sys/cam/ata/ata_da.c
  head/sys/cam/cam_iosched.c
  head/sys/cam/cam_iosched.h
  head/sys/cam/nvme/nvme_da.c
  head/sys/cam/scsi/scsi_da.c

Modified: head/sys/cam/ata/ata_da.c
==============================================================================
--- head/sys/cam/ata/ata_da.c	Thu Feb 22 05:43:50 2018	(r329814)
+++ head/sys/cam/ata/ata_da.c	Thu Feb 22 05:43:55 2018	(r329815)
@@ -1705,7 +1705,7 @@ adaregister(struct cam_periph *periph, void *arg)
 	announce_buf = softc->announce_temp;
 	bzero(announce_buf, ADA_ANNOUNCETMP_SZ);
 
-	if (cam_iosched_init(&softc->cam_iosched, periph) != 0) {
+	if (cam_iosched_init(&softc->cam_iosched, periph, 0) != 0) {
 		printf("adaregister: Unable to probe new device. "
 		       "Unable to allocate iosched memory\n");
 		free(softc, M_DEVBUF);

Modified: head/sys/cam/cam_iosched.c
==============================================================================
--- head/sys/cam/cam_iosched.c	Thu Feb 22 05:43:50 2018	(r329814)
+++ head/sys/cam/cam_iosched.c	Thu Feb 22 05:43:55 2018	(r329815)
@@ -68,6 +68,8 @@ static MALLOC_DEFINE(M_CAMSCHED, "CAM I/O Scheduler",
 #define CAM_IOSCHED_FLAG_CALLOUT_ACTIVE (1ul << 1)
 			/* Timer has just ticked */
 #define CAM_IOSCHED_FLAG_TICK		(1ul << 2)
+			/* When set, defer trims until after next tick */
+#define CAM_IOSCHED_FLAG_TRIM_QONLY	(1ul << 4)
 
 			/* Periph drivers set these flags to indicate work */
 #define CAM_IOSCHED_FLAG_WORK_FLAGS	((0xffffu) << 16)
@@ -290,6 +292,7 @@ struct cam_iosched_softc {
 	struct bio_queue_head trim_queue;
 				/* scheduler flags < 16, user flags >= 16 */
 	uint32_t	flags;
+	u_int		caps;
 	int		sort_io_queue;
 #ifdef CAM_IOSCHED_DYNAMIC
 	int		read_bias;		/* Read bias setting */
@@ -1064,12 +1067,16 @@ cam_iosched_cl_sysctl_fini(struct control_loop *clp)
  * sizeof struct cam_iosched_softc.
  */
 int
-cam_iosched_init(struct cam_iosched_softc **iscp, struct cam_periph *periph)
+cam_iosched_init(struct cam_iosched_softc **iscp, struct cam_periph *periph,
+	u_int caps)
 {
 
 	*iscp = malloc(sizeof(**iscp), M_CAMSCHED, M_NOWAIT | M_ZERO);
 	if (*iscp == NULL)
 		return ENOMEM;
+	(*iscp)->caps = caps;
+	if (caps & CAM_IOSCHED_CAP_TRIM_CLOCKED)
+		(*iscp)->flags |= CAM_IOSCHED_FLAG_TRIM_QONLY;
 #ifdef CAM_IOSCHED_DYNAMIC
 	if (iosched_debug)
 		printf("CAM IOSCHEDULER Allocating entry at %p\n", *iscp);
@@ -1196,7 +1203,7 @@ cam_iosched_flush(struct cam_iosched_softc *isc, struc
 
 #ifdef CAM_IOSCHED_DYNAMIC
 static struct bio *
-cam_iosched_get_write(struct cam_iosched_softc *isc)
+cam_iosched_get_write(struct cam_iosched_softc *isc, bool wastick)
 {
 	struct bio *bp;
 
@@ -1305,13 +1312,45 @@ cam_iosched_next_trim(struct cam_iosched_softc *isc)
  *
  * Assumes we're called with the periph lock held.
  */
-struct bio *
-cam_iosched_get_trim(struct cam_iosched_softc *isc)
+static struct bio *
+cam_iosched_get_trim(struct cam_iosched_softc *isc, bool wastick)
 {
 
-	if (!cam_iosched_has_more_trim(isc))
+	/*
+	 * If there's no trims, return NULL. If we're clocking out the
+	 * trims rather than doing thins right away, this is where we
+	 * set the queue only bit. This causes us to ignore them until
+	 * the next clock tick. If we can't get a trim, and we're clocking
+	 * them out, if the queue is empty or if we're rate limited,
+	 * then set QONLY so we stop processing trims until the next
+	 * tick.
+	 */
+	if (!cam_iosched_has_more_trim(isc)) {
+		if ((isc->caps & CAM_IOSCHED_CAP_TRIM_CLOCKED) &&
+		    (bioq_first(&isc->trim_queue) == NULL ||
+#ifdef CAM_IOSCHED_DYNAMIC
+		     (isc->trim_stats.state_flags & IOP_RATE_LIMITED)
+#else
+		     false
+#endif
+		    ))
+			isc->flags |= CAM_IOSCHED_FLAG_TRIM_QONLY;
 		return NULL;
+	}
 
+	/*
+	 * If we just ticked, and we have trims, then turn off
+	 * the queue only flag.
+	 */
+	if (wastick)
+		isc->flags &= ~CAM_IOSCHED_FLAG_TRIM_QONLY;
+
+	/*
+	 * If QONLY is set, no trims are eligble just now.
+	 */
+	if (isc->flags & CAM_IOSCHED_FLAG_TRIM_QONLY)
+		return NULL;
+
 	return cam_iosched_next_trim(isc);
 }
 
@@ -1327,17 +1366,17 @@ cam_iosched_next_bio(struct cam_iosched_softc *isc)
 	struct bio *bp;
 	bool wastick;
 	
-	wastick = !!(isc->flags & CAM_IOSCHED_FLAGS_TICK);
-	isc->flags &= ~CAM_IOSCHED_FLAGS_TICK;
+	wastick = !!(isc->flags & CAM_IOSCHED_FLAG_TICK);
+	isc->flags &= ~CAM_IOSCHED_FLAG_TICK;
 
 	/*
 	 * See if we have a trim that can be scheduled. We can only send one
-	 * at a time down, so this takes that into account.
-	 *
-	 * XXX newer TRIM commands are queueable. Revisit this when we
-	 * implement them.
+	 * at a time down, so this takes that into account for those devices
+	 * that can only do one. In addition, some devices queue up a bunch
+	 * of TRIMs before sending them down as a batch.
 	 */
-	if ((bp = cam_iosched_get_trim(isc)) != NULL)
+	if ((isc->flags & CAM_IOSCHED_FLAG_TRIM_QONLY) == 0 &&
+	    (bp = cam_iosched_get_trim(isc, wastick)) != NULL)
 		return bp;
 
 #ifdef CAM_IOSCHED_DYNAMIC
@@ -1346,7 +1385,7 @@ cam_iosched_next_bio(struct cam_iosched_softc *isc)
 	 * and if so, those are next.
 	 */
 	if (do_dynamic_iosched) {
-		if ((bp = cam_iosched_get_write(isc)) != NULL)
+		if ((bp = cam_iosched_get_write(isc, was_tick)) != NULL)
 			return bp;
 	}
 #endif

Modified: head/sys/cam/cam_iosched.h
==============================================================================
--- head/sys/cam/cam_iosched.h	Thu Feb 22 05:43:50 2018	(r329814)
+++ head/sys/cam/cam_iosched.h	Thu Feb 22 05:43:55 2018	(r329815)
@@ -81,11 +81,12 @@ cam_iosched_sbintime_t(uintptr_t delta)
 	return (sbintime_t)((uint64_t)delta << CAM_IOSCHED_TIME_SHIFT);
 }
 
-int cam_iosched_init(struct cam_iosched_softc **, struct cam_periph *periph);
+#define CAM_IOSCHED_CAP_TRIM_CLOCKED	0x1
+
+int cam_iosched_init(struct cam_iosched_softc **, struct cam_periph *periph, u_int caps);
 void cam_iosched_fini(struct cam_iosched_softc *);
 void cam_iosched_sysctl_init(struct cam_iosched_softc *, struct sysctl_ctx_list *, struct sysctl_oid *);
 struct bio *cam_iosched_next_trim(struct cam_iosched_softc *isc);
-struct bio *cam_iosched_get_trim(struct cam_iosched_softc *isc);
 struct bio *cam_iosched_next_bio(struct cam_iosched_softc *isc);
 void cam_iosched_queue_work(struct cam_iosched_softc *isc, struct bio *bp);
 void cam_iosched_flush(struct cam_iosched_softc *isc, struct devstat *stp, int err);

Modified: head/sys/cam/nvme/nvme_da.c
==============================================================================
--- head/sys/cam/nvme/nvme_da.c	Thu Feb 22 05:43:50 2018	(r329814)
+++ head/sys/cam/nvme/nvme_da.c	Thu Feb 22 05:43:55 2018	(r329815)
@@ -691,7 +691,8 @@ ndaregister(struct cam_periph *periph, void *arg)
 		return(CAM_REQ_CMP_ERR);
 	}
 
-	if (cam_iosched_init(&softc->cam_iosched, periph) != 0) {
+	if (cam_iosched_init(&softc->cam_iosched, periph,
+		CAM_IOSCHED_CAP_TRIM_CLOCKED) != 0) {
 		printf("ndaregister: Unable to probe new device. "
 		       "Unable to allocate iosched memory\n");
 		return(CAM_REQ_CMP_ERR);

Modified: head/sys/cam/scsi/scsi_da.c
==============================================================================
--- head/sys/cam/scsi/scsi_da.c	Thu Feb 22 05:43:50 2018	(r329814)
+++ head/sys/cam/scsi/scsi_da.c	Thu Feb 22 05:43:55 2018	(r329815)
@@ -2572,7 +2572,7 @@ daregister(struct cam_periph *periph, void *arg)
 		return(CAM_REQ_CMP_ERR);
 	}
 
-	if (cam_iosched_init(&softc->cam_iosched, periph) != 0) {
+	if (cam_iosched_init(&softc->cam_iosched, periph, 0) != 0) {
 		printf("daregister: Unable to probe new device. "
 		       "Unable to allocate iosched memory\n");
 		free(softc, M_DEVBUF);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802220543.w1M5ht9k068959>