[lttng-dev] [PATCH lttng-tools] Fix mmap write() for large subbuffers and handle EINTR

David Goulet dgoulet at efficios.com
Fri Jul 6 09:51:57 EDT 2012


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512



Mathieu Desnoyers:
> With large subbuffer (packet) size, if write() returns before
> copying the entire packet for mmap buffers, the consumerd restarts
> the write infinitely, which is not good at all.
> 
> This affects both lttng-ust (in default mmap mode) and lttng-kernel
> (but only for mmap buffers, which is not the default).
> 
> This issue would show up with large subbuffer size.
> 
> We need to handle this case, as well as EINTR errors (which need to
> restart write).
> 
> Also fixing the return value of mmap read functions, which were
> returning the amount of data written by the last invocation of
> write() rather than the total number of bytes written. splice use
> had the same issue.
> 
> Also now consider a write() that returns more bytes than requested
> as an error.
> 
> Moreover, assigning error = ret after failed splice and write was
> a mistake: error is holding the actual error value. ret just holds
> -1.
> 
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers at efficios.com> 
> --- diff --git a/src/common/kernel-consumer/kernel-consumer.c
> b/src/common/kernel-consumer/kernel-consumer.c index
> bbc31f8..739e06d 100644 ---
> a/src/common/kernel-consumer/kernel-consumer.c +++
> b/src/common/kernel-consumer/kernel-consumer.c @@ -49,7 +49,7 @@
> ssize_t lttng_kconsumer_on_read_subbuffer_mmap( struct
> lttng_consumer_stream *stream, unsigned long len) { unsigned long
> mmap_offset; -	ssize_t ret = 0; +	ssize_t ret = 0, written = 0; 
> off_t orig_offset = stream->out_fd_offset; int fd =
> stream->wait_fd; int outfd = stream->out_fd; @@ -59,30 +59,40 @@
> ssize_t lttng_kconsumer_on_read_subbuffer_mmap( if (ret != 0) { 
> errno = -ret; perror("kernctl_get_mmap_read_offset"); +		written =
> ret; goto end; }
> 
> while (len > 0) { ret = write(outfd, stream->mmap_base +
> mmap_offset, len); -		if (ret >= len) { -			len = 0; -		} else if
> (ret < 0) { -			errno = -ret; +		if (ret <= 0) { +			if (errno ==
> EINTR) { +				/* restart the interrupted system call */ +
> continue; +			} else { +				perror("Error in file write"); +				if
> (written == 0) { +					written = ret; +				} +				goto end; +			}

Hmmm, write() of 0 _may_ be an error or not. Here it seems we are
simply considering it an error and ending the loop.

Idem for ust-consumer.c

Small note while you are at it, can you use PERROR instead of perror()
:). Here for you Mathieu :D

:%s/perror/PERROR/g

The rest seems very good on my side. Just tell me if you want me to
integrate it in master and stable.

Cheers!
David

> +		} else if (ret > len) { perror("Error in file write"); +
> written += ret; goto end; +		} else { +			len -= ret; +
> mmap_offset += ret; } /* This won't block, but will start writeout
> asynchronously */ lttng_sync_file_range(outfd,
> stream->out_fd_offset, ret, SYNC_FILE_RANGE_WRITE); 
> stream->out_fd_offset += ret; +		written += ret; } - 
> lttng_consumer_sync_trace_file(stream, orig_offset); - -	goto end; 
> - end: -	return ret; +	return written; }
> 
> /* @@ -94,7 +104,7 @@ ssize_t
> lttng_kconsumer_on_read_subbuffer_splice( struct
> lttng_consumer_local_data *ctx, struct lttng_consumer_stream
> *stream, unsigned long len) { -	ssize_t ret = 0; +	ssize_t ret = 0,
> written = 0; loff_t offset = 0; off_t orig_offset =
> stream->out_fd_offset; int fd = stream->wait_fd; @@ -107,8 +117,11
> @@ ssize_t lttng_kconsumer_on_read_subbuffer_splice( SPLICE_F_MOVE
> | SPLICE_F_MORE); DBG("splice chan to pipe ret %zd", ret); if (ret
> < 0) { -			errno = -ret; perror("Error in relay splice"); +			if
> (written == 0) { +				written = ret; +			} +			ret = errno; goto
> splice_error; }
> 
> @@ -116,8 +129,18 @@ ssize_t
> lttng_kconsumer_on_read_subbuffer_splice( SPLICE_F_MOVE |
> SPLICE_F_MORE); DBG("splice pipe to file %zd", ret); if (ret < 0)
> { -			errno = -ret; perror("Error in file splice"); +			if (written
> == 0) { +				written = ret; +			} +			ret = errno; +			goto
> splice_error; +		} +		if (ret > len) { +			errno = EINVAL; +
> perror("Wrote more data than requested"); +			written += ret; +
> ret = errno; goto splice_error; } len -= ret; @@ -125,6 +148,7 @@
> ssize_t lttng_kconsumer_on_read_subbuffer_splice( 
> lttng_sync_file_range(outfd, stream->out_fd_offset, ret, 
> SYNC_FILE_RANGE_WRITE); stream->out_fd_offset += ret; +		written +=
> ret; } lttng_consumer_sync_trace_file(stream, orig_offset);
> 
> @@ -132,7 +156,7 @@ ssize_t
> lttng_kconsumer_on_read_subbuffer_splice(
> 
> splice_error: /* send the appropriate error description to sessiond
> */ -	switch(ret) { +	switch (ret) { case EBADF: 
> lttng_consumer_send_error(ctx, CONSUMERD_SPLICE_EBADF); break; @@
> -148,7 +172,7 @@ splice_error: }
> 
> end: -	return ret; +	return written; }
> 
> /* @@ -351,13 +375,14 @@ ssize_t
> lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream
> *stream,
> 
> /* splice the subbuffer to the tracefile */ ret =
> lttng_consumer_on_read_subbuffer_splice(ctx, stream, len); -			if
> (ret < 0) { +			if (ret != len) { /* * display the error but
> continue processing to try * to release the subbuffer */ ERR("Error
> splicing to tracefile"); } + break; case LTTNG_EVENT_MMAP: /* read
> the used subbuffer size */ @@ -369,7 +394,7 @@ ssize_t
> lttng_kconsumer_read_subbuffer(struct lttng_consumer_stream
> *stream, } /* write the subbuffer to the tracefile */ ret =
> lttng_consumer_on_read_subbuffer_mmap(ctx, stream, len); -			if
> (ret < 0) { +			if (ret != len) { /* * display the error but
> continue processing to try * to release the subbuffer diff --git
> a/src/common/ust-consumer/ust-consumer.c
> b/src/common/ust-consumer/ust-consumer.c index 2b55fd4..a29eb58
> 100644 --- a/src/common/ust-consumer/ust-consumer.c +++
> b/src/common/ust-consumer/ust-consumer.c @@ -49,7 +49,7 @@ ssize_t
> lttng_ustconsumer_on_read_subbuffer_mmap( struct
> lttng_consumer_stream *stream, unsigned long len) { unsigned long
> mmap_offset; -	long ret = 0; +	long ret = 0, written = 0; off_t
> orig_offset = stream->out_fd_offset; int outfd = stream->out_fd;
> 
> @@ -59,29 +59,39 @@ ssize_t
> lttng_ustconsumer_on_read_subbuffer_mmap( if (ret != 0) { errno =
> -ret; PERROR("ustctl_get_mmap_read_offset"); +		written = ret; goto
> end; } while (len > 0) { ret = write(outfd, stream->mmap_base +
> mmap_offset, len); -		if (ret >= len) { -			len = 0; -		} else if
> (ret < 0) { -			errno = -ret; -			PERROR("Error in file write"); +
> if (ret <= 0) { +			if (errno == EINTR) { +				/* restart the
> interrupted system call */ +				continue; +			} else { +
> perror("Error in file write"); +				if (written == 0) { +
> written = ret; +				} +				goto end; +			} +		} else if (ret > len)
> { +			perror("Error in file write"); +			written += ret; goto end; 
> +		} else { +			len -= ret; +			mmap_offset += ret; } /* This won't
> block, but will start writeout asynchronously */ 
> lttng_sync_file_range(outfd, stream->out_fd_offset, ret, 
> SYNC_FILE_RANGE_WRITE); stream->out_fd_offset += ret; +		written +=
> ret; } - lttng_consumer_sync_trace_file(stream, orig_offset); - -
> goto end; - end: -	return ret; +	return written; }
> 
> /* @@ -384,7 +394,7 @@ int lttng_ustconsumer_read_subbuffer(struct
> lttng_consumer_stream *stream, assert(err == 0); /* write the
> subbuffer to the tracefile */ ret =
> lttng_consumer_on_read_subbuffer_mmap(ctx, stream, len); -	if (ret
> < 0) { +	if (ret != len) { /* * display the error but continue
> processing to try * to release the subbuffer
-----BEGIN PGP SIGNATURE-----

iQEcBAEBCgAGBQJP9u16AAoJEELoaioR9I02NQQH/014q8Mz0+aNb14fWJf7UtCI
6R2pNLDGNsDEeyqxbHUu2iBVrnncVTbxp19/vZOtGZ7Gm0s4irHca63uZ24ad9pQ
gj4Dl2mmv5VVJOV+23LPlvdFb0LzaV6HbZV4II8E+PBrQ563SElDOF1HvfGUKqIb
uwwuZoUU2z6dQaK5fmgOU1nXLZjVUqVNq1me2dRAN/k25flTDw0iDnwxvLk12yE4
kjSSwAvsLWap5P2ElY/Oes1r/8eZUmmjKF6B1RnQ+ImbSRY16tKy3UaqzYfHb0ku
S/lKP74ya3q13OuJapVWRWmHS/8bQ4OWYNyZScGN1/kJIDCySdoeBJbNLoYJ8g4=
=MjwS
-----END PGP SIGNATURE-----



More information about the lttng-dev mailing list