Fix decoding of preadv syscall in case of short read

* io.c (SYS_FUNC(preadv)): Call tprint_iov_upto instead
of tprint_iov and specify syscall return value as a data size limit.
* NEWS: Mention it.
* tests/preadv.c (main): Add a test case for preadv short read.
diff --git a/NEWS b/NEWS
index 24365b0..c5a4d2e 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,7 @@
   * Fixed decoding of mlock2 syscall on sparc.
   * Fixed decoding of syscalls unknown to the kernel on s390/s390x.
     (addresses Debian bug #485979 and Fedora bug #1298294).
+  * Fixed decoding of preadv syscall in case of short read.
   * Fixed decoding and dumping of readv syscall in case of short read.
   * Fixed dumping of recvmsg and recvmmsg syscalls in case of short read.
   * Fixed decoding of mincore syscall's last argument.
diff --git a/io.c b/io.c
index cda5f92..d8444f3 100644
--- a/io.c
+++ b/io.c
@@ -221,7 +221,8 @@
 		printfd(tcp, tcp->u_arg[0]);
 		tprints(", ");
 	} else {
-		tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
+		tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], 1,
+				tcp->u_rval);
 		tprintf(", %lu, ", tcp->u_arg[2]);
 		print_lld_from_low_high_val(tcp, 3);
 	}
diff --git a/tests/preadv.c b/tests/preadv.c
index 53d7ed6..0fabed2 100644
--- a/tests/preadv.c
+++ b/tests/preadv.c
@@ -92,6 +92,61 @@
 		perror_msg_and_fail("preadv");
 	printf("preadv(0, [], 0, -3) = -1 EINVAL (%m)\n");
 
+	static const char tmp[] = "preadv-tmpfile";
+	int fd = open(tmp, O_RDWR | O_CREAT | O_TRUNC, 0600);
+	if (fd < 0)
+		perror_msg_and_fail("open");
+	if (unlink(tmp))
+		perror_msg_and_fail("unlink");
+
+	static const char w[] = "0123456789abcde";
+	if (write(fd, w, LENGTH_OF(w)) != LENGTH_OF(w))
+		perror_msg_and_fail("write");
+
+	static const char r0_c[] = "01234567";
+	static const char r1_c[] = "89abcde";
+
+	const unsigned int r_len = (LENGTH_OF(w) + 1) / 2;
+	void *r0 = tail_alloc(r_len);
+	const struct iovec r0_iov_[] = {
+		{
+			.iov_base = r0,
+			.iov_len = r_len
+		}
+	};
+	const struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_));
+
+	long rc;
+
+	rc = preadv(fd, r_iov, ARRAY_SIZE(r0_iov_), 0);
+	if (rc != (int) r_len)
+		perror_msg_and_fail("preadv: expected %u, returned %ld",
+				    r_len, rc);
+	printf("preadv(%d, [{\"%s\", %u}], %u, 0) = %u\n",
+	       fd, r0_c, r_len, ARRAY_SIZE(r0_iov_), r_len);
+
+	void *r1 = tail_alloc(r_len);
+	void *r2 = tail_alloc(LENGTH_OF(w));
+	const struct iovec r1_iov_[] = {
+		{
+			.iov_base = r1,
+			.iov_len = r_len
+		},
+		{
+			.iov_base = r2,
+			.iov_len = LENGTH_OF(w)
+		}
+	};
+	r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_));
+
+	rc = preadv(fd, r_iov, ARRAY_SIZE(r1_iov_), r_len);
+	if (rc != (int) LENGTH_OF(w) - r_len)
+		perror_msg_and_fail("preadv: expected %d, returned %ld",
+				    (int) LENGTH_OF(w) - r_len, rc);
+	printf("preadv(%d, [{\"%s\", %u}, {\"\", %u}], %u, %u) = %u\n",
+	       fd, r1_c, r_len, LENGTH_OF(w), ARRAY_SIZE(r1_iov_),
+		r_len, LENGTH_OF(w) - r_len);
+
 	puts("+++ exited with 0 +++");
 	return 0;
 }