[LTP] [PATCH v2] lib: introduce safe_write() retry

Jan Stancek jstancek@redhat.com
Tue Oct 4 10:31:06 CEST 2022


Turn safe_write() len_strict parameter into 3-way switch, introducing
one additional mode of operation "retry". On short writes, this
resumes write() with remainder of the buffer.

Signed-off-by: Jan Stancek <jstancek@redhat.com>
---
 include/safe_macros_fn.h    | 11 ++++++++--
 lib/safe_macros.c           | 42 ++++++++++++++++++++++++++++---------
 lib/tests/tst_safe_macros.c |  6 +++---
 3 files changed, 44 insertions(+), 15 deletions(-)

I can send follow-up to update all call sites too.

diff --git a/include/safe_macros_fn.h b/include/safe_macros_fn.h
index 3df952811b94..8eb03edd81ba 100644
--- a/include/safe_macros_fn.h
+++ b/include/safe_macros_fn.h
@@ -24,6 +24,13 @@
 #include <unistd.h>
 #include <dirent.h>
 
+/* supported values for safe_write() len_strict parameter */
+enum safe_write_opts {
+        SAFE_WRITE_ANY = 0,	// no length strictness, short writes are ok
+        SAFE_WRITE_ALL = 1,	// strict length, short writes raise TBROK
+        SAFE_WRITE_RETRY = 2,	// retry/resume after short write
+};
+
 char* safe_basename(const char *file, const int lineno,
                     void (*cleanup_fn)(void), char *path);
 
@@ -111,8 +118,8 @@ int safe_symlink(const char *file, const int lineno,
                  const char *newpath);
 
 ssize_t safe_write(const char *file, const int lineno,
-                   void (cleanup_fn)(void), char len_strict, int fildes,
-                   const void *buf, size_t nbyte);
+                   void (cleanup_fn)(void), enum safe_write_opts len_strict,
+                   int fildes, const void *buf, size_t nbyte);
 
 long safe_strtol(const char *file, const int lineno,
                  void (cleanup_fn)(void), char *str, long min, long max);
diff --git a/lib/safe_macros.c b/lib/safe_macros.c
index 16e582bc976b..eac31f4ce3ff 100644
--- a/lib/safe_macros.c
+++ b/lib/safe_macros.c
@@ -524,20 +524,42 @@ int safe_symlink(const char *file, const int lineno,
 }
 
 ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void),
-                   char len_strict, int fildes, const void *buf, size_t nbyte)
+                   enum safe_write_opts len_strict, int fildes, const void *buf,
+                   size_t nbyte)
 {
 	ssize_t rval;
+	const void *wbuf = buf;
+	size_t len = nbyte;
+	int iter = 0;
+
+	do {
+		iter++;
+		rval = write(fildes, wbuf, len);
+		if (rval == -1) {
+			if (len_strict == SAFE_WRITE_RETRY)
+				tst_resm_(file, lineno, TINFO,
+					"write() wrote %zu bytes in %d calls",
+					nbyte-len, iter);
+			tst_brkm_(file, lineno, TBROK | TERRNO,
+				cleanup_fn, "write(%d,%p,%zu) failed",
+				fildes, buf, nbyte);
+		}
 
-	rval = write(fildes, buf, nbyte);
+		if (len_strict == SAFE_WRITE_ANY)
+			return rval;
 
-	if (rval == -1 || (len_strict && (size_t)rval != nbyte)) {
-		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
-			"write(%d,%p,%zu) failed", fildes, buf, nbyte);
-	} else if (rval < 0) {
-		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
-			"Invalid write(%d,%p,%zu) return value %zd", fildes,
-			buf, nbyte, rval);
-	}
+		if (len_strict == SAFE_WRITE_ALL) {
+			if ((size_t)rval != nbyte)
+				tst_brkm_(file, lineno, TBROK | TERRNO,
+					cleanup_fn, "short write(%d,%p,%zu) "
+					"return value %zd",
+					fildes, buf, nbyte, rval);
+			return rval;
+		}
+
+		wbuf += rval;
+		len -= rval;
+	} while (len > 0);
 
 	return rval;
 }
diff --git a/lib/tests/tst_safe_macros.c b/lib/tests/tst_safe_macros.c
index b5809f40d10e..5c427ee16832 100644
--- a/lib/tests/tst_safe_macros.c
+++ b/lib/tests/tst_safe_macros.c
@@ -31,9 +31,9 @@ int main(int argc LTP_ATTRIBUTE_UNUSED, char **argv)
 	printf("buf: %s\n", buf);
 	SAFE_READ(cleanup, 1, fd, buf, 9);
 	printf("buf: %s\n", buf);
-	SAFE_WRITE(cleanup, 0, -1, buf, 9);
-	SAFE_WRITE(NULL, 0, fd, buf, 9);
-	SAFE_WRITE(NULL, 1, fd, buf, 9);
+	SAFE_WRITE(cleanup, SAFE_WRITE_ANY, -1, buf, 9);
+	SAFE_WRITE(NULL, SAFE_WRITE_ANY, fd, buf, 9);
+	SAFE_WRITE(NULL, SAFE_WRITE_ALL, fd, buf, 9);
 	SAFE_PIPE(NULL, fds);
 
 	return 0;
-- 
2.27.0



More information about the ltp mailing list