[LTP] [PATCH v3] syscalls/sendmmsg: add new test

Steve Muckle smuckle@google.com
Thu Jul 25 01:52:03 CEST 2019


Hi Cyril, thanks for your feedback.

On 7/24/19 6:42 AM, Cyril Hrubis wrote:
>> diff --git a/configure.ac b/configure.ac
>> index 3dcf282e8..5e4e7f1f9 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -82,9 +82,11 @@ AC_CHECK_FUNCS([ \
>>       pwritev \
>>       pwritev2 \
>>       readlinkat \
>> +    recvmmsg \
>>       renameat \
>>       renameat2 \
>>       sched_getcpu \
>> +    sendmmsg \
>>       sigpending \
>>       splice \
>>       stime \
>> @@ -253,6 +255,7 @@ LTP_CHECK_TIME
>>   LTP_CHECK_TIMERFD
>>   test "x$with_tirpc" = xyes && LTP_CHECK_TIRPC
>>   LTP_CHECK_TPACKET_V3
>> +LTP_CHECK_MMSGHDR
> 
> This seems to be already there under the # custom functions comment.

Ah yes looks like this got added while I was sitting on the patch, and I 
failed to notice it when I rebased. Removed.

>> +	addr.sin_family = AF_INET;
>> +	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
>> +	addr.sin_port = htons(port);
> 
> The port returned by TST_GET_UNUSED_PORT() is already in network byte
> order, we found a bug recently where test was failing randomly since if
> we attempt to convert the value we may end up with priviledged port
> number if we are unlucky.

Fixed.

> 
>> +	SAFE_CONNECT(send_sockfd, (struct sockaddr *) &addr, sizeof(addr));
>> +
>> +	memset(msg1, 0, sizeof(msg1));
>> +	msg1[0].iov_base = "one";
>> +	msg1[0].iov_len = 3;
>> +	msg1[1].iov_base = "two";
>> +	msg1[1].iov_len = 3;
>> +
>> +	memset(&msg2, 0, sizeof(msg2));
>> +	msg2.iov_base = "three";
>> +	msg2.iov_len = 5;
>> +
>> +	memset(msg, 0, sizeof(msg));
>> +	msg[0].msg_hdr.msg_iov = msg1;
>> +	msg[0].msg_hdr.msg_iovlen = 2;
>> +
>> +	msg[1].msg_hdr.msg_iov = &msg2;
>> +	msg[1].msg_hdr.msg_iovlen = 1;
>> +
>> +	sem_wait(&send_sem);
>> +
>> +	while (msgs) {
>> +		retval = do_sendmmsg(send_sockfd, msg, msgs, 0);
>> +		if (retval < 0) {
>> +			/*
>> +			 * tst_brk is used here so reader is not left waiting
>> +			 * for data - note timeout for recvmmsg does not work
>> +			 * as one would expect (see man page)
>> +			 */
>> +			tst_brk(TBROK|TTERRNO, "sendmmsg failed");
>> +			goto out;
>> +		}
>> +		msgs -= retval;
> 
> Wouldn't this resend the start of the message again if we got
> interrupted in the middle?

The failure modes aren't clear to me. Based on the man page for sendmmsg 
it sounded like it returns the number of messages successfully sent, and 
I assumed that unsuccessfully sent messages were not partially sent? The 
sendmsg page says that it only sends messages that can fit atomically in 
the underlying protocol.

> I guess that the correct retry would loop over the messages and
> decrement the iov_len and shift the buffers based on the msg_len.
> Something as:
> 
> retry:
> 	retval = do_sendmmsg(send_sockfd, msg, msgs, 0);
> 
> 	for (i = 0; i < retval; i++) {
> 		int transmitted = msg[i].msg_len;
> 		msg[i].msg_len = 0;
> 		for (j = 0; j < msg[i].msg_iovlen; j++) {
> 			int len = msg[i].msg_iov[j].msg_iovlen;
> 
> 			/* whole buffer send */
> 			if (transmitted >= len) {
> 				transmitted -= len;
> 				msg[i].msg_iov[j].msg_iovlen = 0;
> 				continue;
> 			}
> 
> 			msg[i].msg_iov[j].msg_iovlen -= transmitted;
> 			msg[i].msg_iov[j].msg_iov += transmitted;
> 
> 			goto retry;
> 		}
> 	}
> 
> Also I'm pretty sure that we will actually happen to write the whole
> buffer unless we fill up the kernel buffers, which we hardly will with
> a few bytes. So maybe we should just send the message here and check
> that the msg_len are filled correctly in this case.

That works for me, after all if we get unlucky and cannot send the first 
message in the vector, sendmmsg() returns an error and the test will 
fail. So retrying on the second message is a bit inconsistent.

>> +	addr.sin_port = htons(port);
> 
> Here as well, the htons() should be dropped.

Fixed.

thanks,
steve


More information about the ltp mailing list