Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Nov 2018 00:36:35 +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: r341005 - head/sys/cam
Message-ID:  <201811270036.wAR0aZZB035842@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: imp
Date: Tue Nov 27 00:36:35 2018
New Revision: 341005
URL: https://svnweb.freebsd.org/changeset/base/341005

Log:
  NVME trim clocking
  
  Add the ability to set two goals for trims in the I/O scheduler. The
  first goal is the number of BIO_DELETEs to accumulate
  (kern.cam.XX.U.trim_goal). When non-zero, this many trims will be
  accumulated before we start to transfer them to lower layers. This is
  useful for devices that like to get lots of trims all at once in one
  transaction (not all devices are like this, and some vary by workload).
  
  The second is a number of ticks to defer trims. If you've set a trim
  goal, then kern.cam.XX.U.trim_ticks controls how long the system will
  defer those trims before timing out and sending them anyway. It has no
  effect when trim_goal is 0.
  
  In any event, a BIO_FLUSH will cause all the TRIMs to be released to
  the periph drivers. This may be a minor overloading of what BIO_FLUSH
  is supposed to mean, but it's useful to preserve other ordering
  semantics that users of BIO_FLUSH reply on.
  
  Sponsored by: Netflix, Inc

Modified:
  head/sys/cam/cam_iosched.c
  head/sys/cam/cam_iosched.h

Modified: head/sys/cam/cam_iosched.c
==============================================================================
--- head/sys/cam/cam_iosched.c	Mon Nov 26 23:09:45 2018	(r341004)
+++ head/sys/cam/cam_iosched.c	Tue Nov 27 00:36:35 2018	(r341005)
@@ -277,6 +277,10 @@ struct cam_iosched_softc {
 				/* scheduler flags < 16, user flags >= 16 */
 	uint32_t	flags;
 	int		sort_io_queue;
+	int		trim_goal;		/* # of trims to queue before sending */
+	int		trim_ticks;		/* Max ticks to hold trims */
+	int		last_trim_tick;		/* Last 'tick' time ld a trim */
+	int		queued_trims;		/* Number of trims in the queue */
 #ifdef CAM_IOSCHED_DYNAMIC
 	int		read_bias;		/* Read bias setting */
 	int		current_read_bias;	/* Current read bias state */
@@ -751,6 +755,22 @@ cam_iosched_has_io(struct cam_iosched_softc *isc)
 static inline bool
 cam_iosched_has_more_trim(struct cam_iosched_softc *isc)
 {
+
+	/*
+	 * If we've set a trim_goal, then if we exceed that allow trims
+	 * to be passed back to the driver. If we've also set a tick timeout
+	 * allow trims back to the driver. Otherwise, don't allow trims yet.
+	 */
+	if (isc->trim_goal > 0) {
+		if (isc->queued_trims >= isc->trim_goal)
+			return true;
+		if (isc->queued_trims > 0 &&
+		    isc->trim_ticks > 0 &&
+		    ticks - isc->last_trim_tick > isc->trim_ticks)
+			return true;
+		return false;
+	}
+
 	return !(isc->flags & CAM_IOSCHED_FLAG_TRIM_ACTIVE) &&
 	    bioq_first(&isc->trim_queue);
 }
@@ -1131,14 +1151,21 @@ cam_iosched_fini(struct cam_iosched_softc *isc)
 void cam_iosched_sysctl_init(struct cam_iosched_softc *isc,
     struct sysctl_ctx_list *ctx, struct sysctl_oid *node)
 {
-#ifdef CAM_IOSCHED_DYNAMIC
 	struct sysctl_oid_list *n;
-#endif
 
-	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(node),
+	n = SYSCTL_CHILDREN(node);
+	SYSCTL_ADD_INT(ctx, n,
 		OID_AUTO, "sort_io_queue", CTLFLAG_RW | CTLFLAG_MPSAFE,
 		&isc->sort_io_queue, 0,
 		"Sort IO queue to try and optimise disk access patterns");
+	SYSCTL_ADD_INT(ctx, n,
+	    OID_AUTO, "trim_goal", CTLFLAG_RW,
+	    &isc->trim_goal, 0,
+	    "Number of trims to try to accumulate before sending to hardware");
+	SYSCTL_ADD_INT(ctx, n,
+	    OID_AUTO, "trim_ticks", CTLFLAG_RW,
+	    &isc->trim_goal, 0,
+	    "IO Schedul qaunta to hold back trims for when accumulating");
 
 #ifdef CAM_IOSCHED_DYNAMIC
 	if (!do_dynamic_iosched)
@@ -1193,6 +1220,41 @@ cam_iosched_set_latfcn(struct cam_iosched_softc *isc,
 }
 
 /*
+ * Client drivers can set two parameters. "goal" is the number of BIO_DELETEs
+ * that will be queued up before iosched will "release" the trims to the client
+ * driver to wo with what they will (usually combine as many as possible). If we
+ * don't get this many, after trim_ticks we'll submit the I/O anyway with
+ * whatever we have.  We do need an I/O of some kind of to clock the deferred
+ * trims out to disk. Since we will eventually get a write for the super block
+ * or something before we shutdown, the trims will complete. To be safe, when a
+ * BIO_FLUSH is presented to the iosched work queue, we set the ticks time far
+ * enough in the past so we'll present the BIO_DELETEs to the client driver.
+ * There might be a race if no BIO_DELETESs were queued, a BIO_FLUSH comes in
+ * and then a BIO_DELETE is sent down. No know client does this, and there's
+ * already a race between an ordered BIO_FLUSH and any BIO_DELETEs in flight,
+ * but no client depends on the ordering being honored.
+ *
+ * XXX I'm not sure what the interaction between UFS direct BIOs and the BUF
+ * flushing on shutdown. I think there's bufs that would be dependent on the BIO
+ * finishing to write out at least metadata, so we'll be fine. To be safe, keep
+ * the number of ticks low (less than maybe 10s) to avoid shutdown races.
+ */
+
+void
+cam_iosched_set_trim_goal(struct cam_iosched_softc *isc, int goal)
+{
+
+	isc->trim_goal = goal;
+}
+
+void
+cam_iosched_set_trim_ticks(struct cam_iosched_softc *isc, int trim_ticks)
+{
+
+	isc->trim_ticks = trim_ticks;
+}
+
+/*
  * Flush outstanding I/O. Consumers of this library don't know all the
  * queues we may keep, so this allows all I/O to be flushed in one
  * convenient call.
@@ -1281,6 +1343,9 @@ void
 cam_iosched_put_back_trim(struct cam_iosched_softc *isc, struct bio *bp)
 {
 	bioq_insert_head(&isc->trim_queue, bp);
+	if (isc->queued_trims == 0)
+		isc->last_trim_tick = ticks;
+	isc->queued_trims++;
 #ifdef CAM_IOSCHED_DYNAMIC
 	isc->trim_stats.queued++;
 	isc->trim_stats.total--;		/* since we put it back, don't double count */
@@ -1304,6 +1369,8 @@ cam_iosched_next_trim(struct cam_iosched_softc *isc)
 	if (bp == NULL)
 		return NULL;
 	bioq_remove(&isc->trim_queue, bp);
+	isc->queued_trims--;
+	isc->last_trim_tick = ticks;	/* Reset the tick timer when we take trims */
 #ifdef CAM_IOSCHED_DYNAMIC
 	isc->trim_stats.queued--;
 	isc->trim_stats.total++;
@@ -1430,12 +1497,22 @@ cam_iosched_queue_work(struct cam_iosched_softc *isc, 
 {
 
 	/*
-	 * Put all trims on the trim queue sorted, since we know
-	 * that the collapsing code requires this. Otherwise put
-	 * the work on the bio queue.
+	 * If we get a BIO_FLUSH, and we're doing delayed BIO_DELETEs then we
+	 * set the last tick time to one less than the current ticks minus the
+	 * delay to force the BIO_DELETEs to be presented to the client driver.
 	 */
+	if (bp->bio_cmd == BIO_FLUSH && isc->trim_ticks > 0)
+		isc->last_trim_tick = ticks - isc->trim_ticks - 1;
+
+	/*
+	 * Put all trims on the trim queue. Otherwise put the work on the bio
+	 * queue.
+	 */
 	if (bp->bio_cmd == BIO_DELETE) {
 		bioq_insert_tail(&isc->trim_queue, bp);
+		if (isc->queued_trims == 0)
+			isc->last_trim_tick = ticks;
+		isc->queued_trims++;
 #ifdef CAM_IOSCHED_DYNAMIC
 		isc->trim_stats.in++;
 		isc->trim_stats.queued++;

Modified: head/sys/cam/cam_iosched.h
==============================================================================
--- head/sys/cam/cam_iosched.h	Mon Nov 26 23:09:45 2018	(r341004)
+++ head/sys/cam/cam_iosched.h	Tue Nov 27 00:36:35 2018	(r341005)
@@ -101,6 +101,7 @@ void cam_iosched_clr_work_flags(struct cam_iosched_sof
 void cam_iosched_trim_done(struct cam_iosched_softc *isc);
 int cam_iosched_bio_complete(struct cam_iosched_softc *isc, struct bio *bp, union ccb *done_ccb);
 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);
 #endif
 #endif



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