svn commit: r296156 - head/bin/dd

Edward Tomasz Napierala trasz at FreeBSD.org
Sun Feb 28 10:27:14 UTC 2016


Author: trasz
Date: Sun Feb 28 10:27:12 2016
New Revision: 296156
URL: https://svnweb.freebsd.org/changeset/base/296156

Log:
  Add speed limit to dd(1). This is useful for testing RCTL disk io limits
  (when they actually get committed, that is), and might also come in handy
  in other situations.
  
  Reviewed by:	wblock@ (man page)
  MFC after:	1 month
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/bin/dd/args.c
  head/bin/dd/dd.1
  head/bin/dd/dd.c
  head/bin/dd/extern.h
  head/bin/dd/misc.c

Modified: head/bin/dd/args.c
==============================================================================
--- head/bin/dd/args.c	Sun Feb 28 09:35:37 2016	(r296155)
+++ head/bin/dd/args.c	Sun Feb 28 10:27:12 2016	(r296156)
@@ -66,6 +66,7 @@ static void	f_obs(char *);
 static void	f_of(char *);
 static void	f_seek(char *);
 static void	f_skip(char *);
+static void	f_speed(char *);
 static void	f_status(char *);
 static uintmax_t get_num(const char *);
 static off_t	get_off_t(const char *);
@@ -89,6 +90,7 @@ static const struct arg {
 	{ "oseek",	f_seek,		C_SEEK,	 C_SEEK },
 	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
 	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
+	{ "speed",	f_speed,	0,	 0 },
 	{ "status",	f_status,	C_STATUS,C_STATUS },
 };
 
@@ -295,6 +297,13 @@ f_skip(char *arg)
 }
 
 static void
+f_speed(char *arg)
+{
+
+	speed = get_num(arg);
+}
+
+static void
 f_status(char *arg)
 {
 

Modified: head/bin/dd/dd.1
==============================================================================
--- head/bin/dd/dd.1	Sun Feb 28 09:35:37 2016	(r296155)
+++ head/bin/dd/dd.1	Sun Feb 28 10:27:12 2016	(r296156)
@@ -32,7 +32,7 @@
 .\"     @(#)dd.1	8.2 (Berkeley) 1/13/94
 .\" $FreeBSD$
 .\"
-.Dd February 4, 2016
+.Dd February 28, 2016
 .Dt DD 1
 .Os
 .Sh NAME
@@ -156,6 +156,10 @@ Otherwise, input data is read and discar
 For pipes, the correct number of bytes is read.
 For all other devices, the correct number of blocks is read without
 distinguishing between a partial or complete block being read.
+.It Cm speed Ns = Ns Ar n
+Limit the copying speed to
+.Ar n
+bytes per second.
 .It Cm status Ns = Ns Ar value
 Where
 .Cm value
@@ -325,7 +329,7 @@ appended.
 .El
 .El
 .Pp
-Where sizes are specified, a decimal, octal, or hexadecimal number of
+Where sizes or speed are specified, a decimal, octal, or hexadecimal number of
 bytes is expected.
 If the number ends with a
 .Dq Li b ,

Modified: head/bin/dd/dd.c
==============================================================================
--- head/bin/dd/dd.c	Sun Feb 28 09:35:37 2016	(r296155)
+++ head/bin/dd/dd.c	Sun Feb 28 10:27:12 2016	(r296156)
@@ -82,6 +82,7 @@ size_t	cbsz;			/* conversion block size 
 uintmax_t files_cnt = 1;	/* # of files to copy */
 const	u_char *ctab;		/* conversion table */
 char	fill_char;		/* Character to fill with if defined */
+size_t	speed = 0;		/* maximum speed, in bytes per second */
 volatile sig_atomic_t need_summary;
 
 int
@@ -276,6 +277,29 @@ getfdtype(IO *io)
 		io->flags |= ISSEEK;
 }
 
+/*
+ * Limit the speed by adding a delay before every block read.
+ * The delay (t_usleep) is equal to the time computed from block
+ * size and the specified speed limit (t_target) minus the time
+ * spent on actual read and write operations (t_io).
+ */
+static void
+speed_limit(void)
+{
+	static double t_prev, t_usleep;
+	double t_now, t_io, t_target;
+
+	t_now = secs_elapsed();
+	t_io = t_now - t_prev - t_usleep;
+	t_target = (double)in.dbsz / (double)speed;
+	t_usleep = t_target - t_io;
+	if (t_usleep > 0)
+		usleep(t_usleep * 1000000);
+	else
+		t_usleep = 0;
+	t_prev = t_now;
+}
+
 static void
 dd_in(void)
 {
@@ -293,6 +317,9 @@ dd_in(void)
 			break;
 		}
 
+		if (speed > 0)
+			speed_limit();
+
 		/*
 		 * Zero the buffer first if sync; if doing block operations,
 		 * use spaces.

Modified: head/bin/dd/extern.h
==============================================================================
--- head/bin/dd/extern.h	Sun Feb 28 09:35:37 2016	(r296155)
+++ head/bin/dd/extern.h	Sun Feb 28 10:27:12 2016	(r296156)
@@ -42,6 +42,7 @@ void def_close(void);
 void jcl(char **);
 void pos_in(void);
 void pos_out(void);
+double secs_elapsed(void);
 void summary(void);
 void siginfo_handler(int);
 void terminate(int);
@@ -54,6 +55,7 @@ extern void (*cfunc)(void);
 extern uintmax_t cpy_cnt;
 extern size_t cbsz;
 extern u_int ddflags;
+extern size_t speed;
 extern uintmax_t files_cnt;
 extern const u_char *ctab;
 extern const u_char a2e_32V[], a2e_POSIX[];

Modified: head/bin/dd/misc.c
==============================================================================
--- head/bin/dd/misc.c	Sun Feb 28 09:35:37 2016	(r296155)
+++ head/bin/dd/misc.c	Sun Feb 28 10:27:12 2016	(r296156)
@@ -54,15 +54,12 @@ __FBSDID("$FreeBSD$");
 #include "dd.h"
 #include "extern.h"
 
-void
-summary(void)
+double
+secs_elapsed(void)
 {
 	struct timespec end, ts_res;
 	double secs, res;
 
-	if (ddflags & C_NOINFO)
-		return;
-
 	if (clock_gettime(CLOCK_MONOTONIC, &end))
 		err(1, "clock_gettime");
 	if (clock_getres(CLOCK_MONOTONIC, &ts_res))
@@ -72,6 +69,20 @@ summary(void)
 	res = ts_res.tv_sec + ts_res.tv_nsec * 1e-9;
 	if (secs < res)
 		secs = res;
+
+	return (secs);
+}
+
+void
+summary(void)
+{
+	double secs;
+
+	if (ddflags & C_NOINFO)
+		return;
+
+	secs = secs_elapsed();
+
 	(void)fprintf(stderr,
 	    "%ju+%ju records in\n%ju+%ju records out\n",
 	    st.in_full, st.in_part, st.out_full, st.out_part);


More information about the svn-src-all mailing list