From nobody@FreeBSD.org  Tue Aug 20 04:31:14 2013
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTP id B856A993
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 20 Aug 2013 04:31:14 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from oldred.freebsd.org (oldred.freebsd.org [8.8.178.121])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by mx1.freebsd.org (Postfix) with ESMTPS id A552A2E02
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 20 Aug 2013 04:31:14 +0000 (UTC)
Received: from oldred.freebsd.org ([127.0.1.6])
	by oldred.freebsd.org (8.14.5/8.14.7) with ESMTP id r7K4VExG003739
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 20 Aug 2013 04:31:14 GMT
	(envelope-from nobody@oldred.freebsd.org)
Received: (from nobody@localhost)
	by oldred.freebsd.org (8.14.5/8.14.5/Submit) id r7K4VECF003700;
	Tue, 20 Aug 2013 04:31:14 GMT
	(envelope-from nobody)
Message-Id: <201308200431.r7K4VECF003700@oldred.freebsd.org>
Date: Tue, 20 Aug 2013 04:31:14 GMT
From: Vitja Makarov <vitja.makarov@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: socket timeout rounding issue
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         181416
>Category:       kern
>Synopsis:       [libc] socket timeout rounding issue
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jhb
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 20 04:40:00 UTC 2013
>Closed-Date:    Wed Nov 13 17:24:29 UTC 2013
>Last-Modified:  Wed Nov 13 17:24:29 UTC 2013
>Originator:     Vitja Makarov
>Release:        9.1-RELEASE
>Organization:
Rambler
>Environment:
FreeBSD dbg 9.1-RELEASE FreeBSD 9.1-RELEASE #5: Tue Aug 20 08:14:54 MSK 2013     root@dbg:/usr/obj/nfs/usr/src/sys/MYKERNEL  i386

>Description:
Recently I was playing with small socket timeouts. setsockopt(2)
SO_RCVTIMEO and found a problem with it: if timeout is small enough
read(2) may return before timeout is actually expired.

I was unable to reproduce this on linux box.

I found that kernel uses a timer with 1/HZ precision so it converts
time in microseconds to ticks that's ok linux does it as well. The
problem is in details: freebsd uses floor() approach while linux uses
ceil():

from FreeBSD's sys/kern/uipc_socket.c:
val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick;
if (val == 0 && tv.tv_usec != 0)
     val = 1; /* at least one tick if tv > 0 */

from Linux's net/core/sock.c:
*timeo_p = tv.tv_sec*HZ + (tv.tv_usec+(1000000/HZ-1))/(1000000/HZ);

So, for instance, we have a freebsd system running with kern.hz set to
100 and set receive timeout to 25ms that is converted to 2 ticks which
is 20ms. In my test program read(2) returns with EAGAIN set in
0.019ms.

>How-To-Repeat:

>Fix:


>Release-Note:
>Audit-Trail:

From: Bruce Evans <brde@optusnet.com.au>
To: Vitja Makarov <vitja.makarov@gmail.com>
Cc: freebsd-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org
Subject: Re: kern/181416: socket timeout rounding issue
Date: Tue, 20 Aug 2013 20:11:37 +1000 (EST)

 On Tue, 20 Aug 2013, Vitja Makarov wrote:
 
 >> Description:
 > I found that kernel uses a timer with 1/HZ precision so it converts
 > time in microseconds to ticks that's ok linux does it as well. The
 > problem is in details: freebsd uses floor() approach while linux uses
 > ceil():
 >
 > from FreeBSD's sys/kern/uipc_socket.c:
 > val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick;
 
 This is actually an off-by-2 error in most case.  ceil() isn't high enough
 either, since for example with hz = 100 and tv = 25 msec, the ceil() of 3
 ticks is 2 full ticks plus a fractional tick which may be 1 nsec long.  At
 least with old timeout code.
 
 > if (val == 0 && tv.tv_usec != 0)
 >     val = 1; /* at least one tick if tv > 0 */
 
 This does the ceil() in the special case where tv < 1 tick.  This is a
 waste of timeout, at least with old timeout code, since callout_reset()
 used to add 1.  This seems to have been lost, breaking old callers that
 depended on it.  Current timeout code tries to be more accurute, but that
 means that it less accurate if the caller is broken and rounds down.
 Maybe your bug can only be seen with the increased accuracy.
 
 tvtohz() should always be used to convert timevals to ticks.  It rounds
 up and adds 1, and handles overflow.  The conversion in uipc_socket.c
 isn't even short.  It takes 15 lines for its own overflow handling.  It
 seems to check the SHRT_MAX limit twice.
 
 If uipc_socket.c called tvtohz(), then it would still have to check
 that the result fits in a short.  Its error handling when it doesn't
 fit seems wrong.  EDOM is documented as a domain error for math
 software.  setsockopt() isn't math software, and EDOM isn't a documented
 errno for it.  EINVAL and EOVERFLOW are more usual kernel errors for
 unrepresentable values.
 
 Grepping for ' / tick' in /sys shows no other home made tvtohz()'s.
 
 > from Linux's net/core/sock.c:
 > *timeo_p = tv.tv_sec*HZ + (tv.tv_usec+(1000000/HZ-1))/(1000000/HZ);
 
 The conversion is much simpler when HZ is hard-coded.  Linux has some
 bounds checking before this, but the error handling in at least
 Linux-2.6.10 is to ignore invalid tv's and return success without
 changing the timeout.
 
 > So, for instance, we have a freebsd system running with kern.hz set to
 > 100 and set receive timeout to 25ms that is converted to 2 ticks which
 > is 20ms. In my test program read(2) returns with EAGAIN set in
 > 0.019ms.
 
 Bruce
State-Changed-From-To: open->patched 
State-Changed-By: jhb 
State-Changed-When: Thu Aug 29 15:59:23 UTC 2013 
State-Changed-Why:  
Fix committed to HEAD. 


Responsible-Changed-From-To: freebsd-bugs->jhb 
Responsible-Changed-By: jhb 
Responsible-Changed-When: Thu Aug 29 15:59:23 UTC 2013 
Responsible-Changed-Why:  
Fix committed to HEAD. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=181416 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/181416: commit references a PR
Date: Thu, 29 Aug 2013 15:59:14 +0000 (UTC)

 Author: jhb
 Date: Thu Aug 29 15:59:05 2013
 New Revision: 255030
 URL: http://svnweb.freebsd.org/changeset/base/255030
 
 Log:
   Don't return an error for socket timeouts that are too large.  Just
   cap them to INT_MAX ticks instead.
   
   PR:		kern/181416 (r254699 really)
   Requested by:	bde
   MFC after:	2 weeks
 
 Modified:
   head/sys/kern/uipc_socket.c
 
 Modified: head/sys/kern/uipc_socket.c
 ==============================================================================
 --- head/sys/kern/uipc_socket.c	Thu Aug 29 15:58:20 2013	(r255029)
 +++ head/sys/kern/uipc_socket.c	Thu Aug 29 15:59:05 2013	(r255030)
 @@ -2698,17 +2698,12 @@ sosetopt(struct socket *so, struct socko
  				    sizeof tv);
  			if (error)
  				goto bad;
 -
 -			if (tv.tv_sec < 0 || tv.tv_sec > INT_MAX / hz ||
 -			    tv.tv_usec < 0 || tv.tv_usec >= 1000000) {
 +			if (tv.tv_sec < 0 || tv.tv_usec < 0 ||
 +			    tv.tv_usec >= 1000000) {
  				error = EDOM;
  				goto bad;
  			}
  			val = tvtohz(&tv);
 -			if (val == INT_MAX) {
 -				error = EDOM;
 -				goto bad;
 -			}
  
  			switch (sopt->sopt_name) {
  			case SO_SNDTIMEO:
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/181416: commit references a PR
Date: Wed, 13 Nov 2013 17:08:45 +0000 (UTC)

 Author: jhb
 Date: Wed Nov 13 17:08:37 2013
 New Revision: 258099
 URL: http://svnweb.freebsd.org/changeset/base/258099
 
 Log:
   MFC 254699,255030:
   Use tvtohz() to convert a socket buffer timeout to a tick value rather
   than using a home-rolled version.  The home-rolled version could result
   in shorter-than-requested sleeps.
   
   PR:		kern/181416
 
 Modified:
   stable/9/sys/kern/uipc_socket.c
 Directory Properties:
   stable/9/sys/   (props changed)
 
 Modified: stable/9/sys/kern/uipc_socket.c
 ==============================================================================
 --- stable/9/sys/kern/uipc_socket.c	Wed Nov 13 17:06:26 2013	(r258098)
 +++ stable/9/sys/kern/uipc_socket.c	Wed Nov 13 17:08:37 2013	(r258099)
 @@ -2654,22 +2654,12 @@ sosetopt(struct socket *so, struct socko
  				    sizeof tv);
  			if (error)
  				goto bad;
 -
 -			/* assert(hz > 0); */
 -			if (tv.tv_sec < 0 || tv.tv_sec > INT_MAX / hz ||
 -			    tv.tv_usec < 0 || tv.tv_usec >= 1000000) {
 -				error = EDOM;
 -				goto bad;
 -			}
 -			/* assert(tick > 0); */
 -			/* assert(ULONG_MAX - INT_MAX >= 1000000); */
 -			val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick;
 -			if (val > INT_MAX) {
 +			if (tv.tv_sec < 0 || tv.tv_usec < 0 ||
 +			    tv.tv_usec >= 1000000) {
  				error = EDOM;
  				goto bad;
  			}
 -			if (val == 0 && tv.tv_usec != 0)
 -				val = 1;
 +			val = tvtohz(&tv);
  
  			switch (sopt->sopt_name) {
  			case SO_SNDTIMEO:
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/181416: commit references a PR
Date: Wed, 13 Nov 2013 17:10:26 +0000 (UTC)

 Author: jhb
 Date: Wed Nov 13 17:10:18 2013
 New Revision: 258100
 URL: http://svnweb.freebsd.org/changeset/base/258100
 
 Log:
   MFC 254699,255030:
   Use tvtohz() to convert a socket buffer timeout to a tick value rather
   than using a home-rolled version.  The home-rolled version could result
   in shorter-than-requested sleeps.
   
   PR:		kern/181416
 
 Modified:
   stable/8/sys/kern/uipc_socket.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/kern/   (props changed)
 
 Modified: stable/8/sys/kern/uipc_socket.c
 ==============================================================================
 --- stable/8/sys/kern/uipc_socket.c	Wed Nov 13 17:08:37 2013	(r258099)
 +++ stable/8/sys/kern/uipc_socket.c	Wed Nov 13 17:10:18 2013	(r258100)
 @@ -2570,22 +2570,12 @@ sosetopt(struct socket *so, struct socko
  				    sizeof tv);
  			if (error)
  				goto bad;
 -
 -			/* assert(hz > 0); */
 -			if (tv.tv_sec < 0 || tv.tv_sec > INT_MAX / hz ||
 -			    tv.tv_usec < 0 || tv.tv_usec >= 1000000) {
 -				error = EDOM;
 -				goto bad;
 -			}
 -			/* assert(tick > 0); */
 -			/* assert(ULONG_MAX - INT_MAX >= 1000000); */
 -			val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick;
 -			if (val > INT_MAX) {
 +			if (tv.tv_sec < 0 || tv.tv_usec < 0 ||
 +			    tv.tv_usec >= 1000000) {
  				error = EDOM;
  				goto bad;
  			}
 -			if (val == 0 && tv.tv_usec != 0)
 -				val = 1;
 +			val = tvtohz(&tv);
  
  			switch (sopt->sopt_name) {
  			case SO_SNDTIMEO:
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jhb 
State-Changed-When: Wed Nov 13 17:22:04 UTC 2013 
State-Changed-Why:  
Fix merged to 8 and 9. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=181416 
>Unformatted:
