[CRIU] [PATCH 14/15] bfd: Implement buffered writes

Pavel Emelyanov xemul at parallels.com
Mon Sep 29 03:59:08 PDT 2014


On 09/29/2014 02:36 PM, Andrew Vagin wrote:
> On Mon, Sep 29, 2014 at 12:50:29PM +0400, Pavel Emelyanov wrote:
>> Dump times (top-5) look like
>>
>> Before patch:
>> 	writev:     1595  0.048337 (15.1%)
>> 	openat:     1326  0.041976 (13.1%)
>> 	 close:     1434  0.034661 (10.8%)
>> 	  read:      988  0.028760 (9.0%)
>> 	 wait4:      170  0.028271 (8.8%)
>>
>> After patch:
>> 	openat:     1326  0.040010 (16.4%)
>> 	 close:     1434  0.030039 (12.3%)
>> 	  read:      988  0.025827 (10.6%)
>> 	 wait4:      170  0.025549 (10.5%)
>> 	ptrace:      834  0.021624 (8.9%)
>>
>> So write-s go away from top list (turn into 8th position).
>>
>> Funny thing is that all object writes get merged with the
>> magic writes, so the total amount of write()-s (not writev-s)
>> in the strace remain intact :)
>>
>> Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
>> ---
>>  bfd.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>>  1 file changed, 70 insertions(+), 3 deletions(-)
>>
>> diff --git a/bfd.c b/bfd.c
>> index 2572679..0bc9a64 100644
>> --- a/bfd.c
>> +++ b/bfd.c
>> @@ -84,10 +84,22 @@ int bfdopen(struct bfd *f)
>>  	return 0;
>>  }
>>  
>> +static int bflush(struct bfd *bfd);
>> +
>>  void bclose(struct bfd *f)
>>  {
>> -	if (bfd_buffered(f))
>> +	if (bfd_buffered(f)) {
>> +		if (bflush(f) < 0)
>> +			/*
>> +			 * FIXME -- propagate error up. It's
>> +			 * hardly possible by returning and
>> +			 * checking it, but setting a static
>> +			 * flag, failing further bfdopen-s and
>> +			 * checking one at the end would work.
>> +			 */
>> +			pr_err("Error flushing image\n");
>>  		buf_put(&f->b);
>> +	}
> 
> Nobody reads logs if the exit code is zero. I would prefer to return
> error from here and check it.

Nobody checks errors from closing the images :)
I've already written how to handle such errors.

>>  	close(f->fd);
>>  }
>>  
>> @@ -178,14 +190,69 @@ again:
>>  	goto again;
>>  }
>>  
>> +static int bflush(struct bfd *bfd)
>> +{
>> +	struct xbuf *b = &bfd->b;
>> +	int ret;
>> +
>> +	if (!b->sz)
>> +		return 0;
>> +
>> +	ret = write(bfd->fd, b->data, b->sz);
>> +	if (ret != b->sz)
> 
> Can we print error here?

Sure.

>> +		return -1;
>> +
>> +	b->sz = 0;
>> +	return 0;
>> +}
>> +
>> +static int __bwrite(struct bfd *bfd, const void *buf, int size)
>> +{
>> +	struct xbuf *b = &bfd->b;
>> +
>> +	if (b->sz + size > BUFSIZE) {
>> +		int ret;
>> +		ret = bflush(bfd);
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>> +
>> +	if (size > BUFSIZE)
>> +		return write(bfd->fd, buf, size);
> 
> Looks like you want to say that a caller whould get a proper errno and
> print errors.

The only existing user -- pb_write|read -- does.

>> +
>> +	memcpy(b->data + b->sz, buf, size);
>> +	b->sz += size;
>> +	return size;
>> +}
>> +
>>  int bwrite(struct bfd *bfd, const void *buf, int size)
>>  {
>> -	return write(bfd->fd, buf, size);
>> +	if (!bfd_buffered(bfd))
>> +		return write(bfd->fd, buf, size);
>> +
>> +	return __bwrite(bfd, buf, size);
>>  }
>>  
>>  int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt)
>>  {
>> -	return writev(bfd->fd, iov, cnt);
>> +	int i, written = 0;
>> +
>> +	if (!bfd_buffered(bfd))
>> +		return writev(bfd->fd, iov, cnt);
>> +
>> +	for (i = 0; i < cnt; i++) {
>> +		int ret;
>> +
>> +		ret = __bwrite(bfd, (const void *)iov[i].iov_base, iov[i].iov_len);
>> +		if (ret < 0)
>> +			return ret;
> 
> 		written += ret;
> 
>> +		if (ret < iov[i].iov_len)
>> +			break;
>> +
>> +		written += ret;
> 
> It should be moved upper.

Yup.

>> +	}
>> +
>> +	return written;
>>  }
>>  
>>  int bread(struct bfd *bfd, void *buf, int size)
>> -- 
>> 1.8.4.2
>>
>>
>> _______________________________________________
>> CRIU mailing list
>> CRIU at openvz.org
>> https://lists.openvz.org/mailman/listinfo/criu
> .
> 



More information about the CRIU mailing list