Add max_latency option

If set, fio will exit if it sees a total IO latency that exceeds
this value.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/HOWTO b/HOWTO
index 8eda99d..a7bd1fb 100644
--- a/HOWTO
+++ b/HOWTO
@@ -780,6 +780,9 @@
 		the job to exit. The same format as rate is used for read vs
 		write seperation.
 
+max_latency=int	If set, fio will exit the job if it exceeds this maximum
+		latency. It will exit with an ETIME error.
+
 ratecycle=int	Average bandwidth for 'rate' and 'ratemin' over this number
 		of milliseconds.
 
diff --git a/fio.1 b/fio.1
index bf65551..08d6c0f 100644
--- a/fio.1
+++ b/fio.1
@@ -639,6 +639,10 @@
 Average bandwidth for \fBrate\fR and \fBratemin\fR over this number of
 milliseconds.  Default: 1000ms.
 .TP
+.BI max_latency \fR=\fPint
+If set, fio will exit the job if it exceeds this maximum latency. It will exit
+with an ETIME error.
+.TP
 .BI cpumask \fR=\fPint
 Set CPU affinity for this job. \fIint\fR is a bitmask of allowed CPUs the job
 may run on.  See \fBsched_setaffinity\fR\|(2).
diff --git a/fio.h b/fio.h
index 03e4da1..139b938 100644
--- a/fio.h
+++ b/fio.h
@@ -198,6 +198,8 @@
 	enum fio_memtype mem_type;
 	unsigned int mem_align;
 
+	unsigned int max_latency;
+
 	unsigned int stonewall;
 	unsigned int new_group;
 	unsigned int numjobs;
diff --git a/io_u.c b/io_u.c
index e047677..b049b61 100644
--- a/io_u.c
+++ b/io_u.c
@@ -1325,6 +1325,13 @@
 
 		tusec = utime_since(&io_u->start_time, &icd->time);
 		add_lat_sample(td, idx, tusec, bytes);
+
+		if (td->o.max_latency && tusec > td->o.max_latency) {
+			if (!td->error)
+				log_err("fio: latency of %lu usec exceeds specified max (%u usec)\n", tusec, td->o.max_latency);
+			td_verror(td, ETIME, "max latency exceeded");
+			icd->error = ETIME;
+		}
 	}
 
 	if (!td->o.disable_clat) {
diff --git a/options.c b/options.c
index e0b7fec..380df36 100644
--- a/options.c
+++ b/options.c
@@ -2099,6 +2099,12 @@
 		.parent = "rate",
 	},
 	{
+		.name	= "max_latency",
+		.type	= FIO_OPT_INT,
+		.off1	= td_var_offset(max_latency),
+		.help	= "Maximum tolerated IO latency (usec)",
+	},
+	{
 		.name	= "invalidate",
 		.type	= FIO_OPT_BOOL,
 		.off1	= td_var_offset(invalidate_cache),