From gibbs@ns1.scsiguy.com  Sun Aug  6 02:17:40 2006
Return-Path: <gibbs@ns1.scsiguy.com>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 9408916A4DA
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  6 Aug 2006 02:17:40 +0000 (UTC)
	(envelope-from gibbs@ns1.scsiguy.com)
Received: from ns1.scsiguy.com (ns1.scsiguy.com [70.89.174.89])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 4941D43D46
	for <FreeBSD-gnats-submit@freebsd.org>; Sun,  6 Aug 2006 02:17:40 +0000 (GMT)
	(envelope-from gibbs@ns1.scsiguy.com)
Received: from ns1.scsiguy.com (gibbs@localhost [127.0.0.1])
	by ns1.scsiguy.com (8.13.6/8.13.6) with ESMTP id k762HdEQ023159
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO)
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 5 Aug 2006 20:17:39 -0600 (MDT)
	(envelope-from gibbs@ns1.scsiguy.com)
Received: (from gibbs@localhost)
	by ns1.scsiguy.com (8.13.6/8.13.6/Submit) id k762Hcqs023158;
	Sat, 5 Aug 2006 20:17:38 -0600 (MDT)
	(envelope-from gibbs)
Message-Id: <200608060217.k762Hcqs023158@ns1.scsiguy.com>
Date: Sat, 5 Aug 2006 20:17:38 -0600 (MDT)
From: "Justin T. Gibbs" <gibbs@scsiguy.com>
Reply-To: "Justin T. Gibbs" <gibbs@scsiguy.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: linprocfs disallows non-zero file offsets for maps files
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         101453
>Category:       kern
>Synopsis:       [linux] [patch] linprocfs disallows non-zero file offsets for maps files
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kib
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Aug 06 02:20:14 GMT 2006
>Closed-Date:    Mon Oct 13 13:05:44 UTC 2008
>Last-Modified:  Mon Oct 13 13:05:44 UTC 2008
>Originator:     Justin T. Gibbs
>Release:        FreeBSD 6.1-STABLE i386
>Organization:
>Environment:
System: FreeBSD aslan.scsiguy.com 6.1-STABLE FreeBSD 6.1-STABLE #4: Sat May 6 17:23:37 MDT 2006 gibbs@aslan.scsiguy.com:/usr/obj/usr/src/sys/ASLAN i386

>Description:
	While trying to run Matlab R2006a under linux emulation, its
	embedded JVM complained of being unable to locate the position
	of thread stacks.  The JRE uses the linux procfs filesystem's
	"maps" file to determine this information.  Using ktrace I
	determined that the JRE was reading the maps file in 4k chunks,
	but that the output for the matlab process was much larger than
	this and was being truncated.  The attached patch allows the
	maps file to be read in chunks rather than all at once.  After
	applying this patch, the ktrace output indicated that all data
	was read correctly and the JVM error dissappeared.  Unfortunately,
	Matlab still hangs when attempting to launch its java based GUI.
	I'm still investigating that issue, but currently believe that
	the root cause for that is elsewhere in our compatibility framework.

>How-To-Repeat:
	Attempt to read the maps file in linprocfs in multiple chunks.
	
>Fix:
Index: linprocfs.c
===================================================================
RCS file: /usr/cvs/src/sys/compat/linprocfs/linprocfs.c,v
retrieving revision 1.89.2.3
diff -u -r1.89.2.3 linprocfs.c
--- linprocfs.c	3 Jul 2006 06:38:53 -0000	1.89.2.3
+++ linprocfs.c	26 Jul 2006 02:35:11 -0000
@@ -851,12 +851,14 @@
 	vm_object_t obj, tobj, lobj;
 	vm_ooffset_t off = 0;
 	char *name = "", *freename = NULL;
+	char *bufptr;
 	size_t len;
 	ino_t ino;
 	int ref_count, shadow_count, flags;
 	int error;
 	struct vnode *vp;
 	struct vattr vat;
+	off_t cur_offset;
 	
 	PROC_LOCK(p);
 	error = p_candebug(td, p);
@@ -867,10 +869,8 @@
 	if (uio->uio_rw != UIO_READ)
 		return (EOPNOTSUPP);
 	
-	if (uio->uio_offset != 0)
-		return (0);
-	
 	error = 0;
+	cur_offset = 0;
 	if (map != &curthread->td_proc->p_vmspace->vm_map)
 		vm_map_lock_read(map);
         for (entry = map->header.next;
@@ -924,12 +924,35 @@
 		if (freename)
 			free(freename, M_TEMP);
 		len = strlen(mebuffer);
+		bufptr = mebuffer;
+		if (cur_offset < uio->uio_offset) {
+			off_t delta;
+
+			/*
+			 * Discard data until we get to the
+			 * desired offset in the data.
+			 */
+			delta = uio->uio_offset - cur_offset;
+			if (delta >= len) {
+				cur_offset += len;
+				continue;
+			}
+			bufptr += delta;
+			len -= delta;
+		}
+	
 		if (len > uio->uio_resid)
 			len = uio->uio_resid; /*
 					       * XXX We should probably return
 					       * EFBIG here, as in procfs.
 					       */
-		error = uiomove(mebuffer, len, uio);
+		error = uiomove(bufptr, len, uio);
+		/*
+		 * Once we start outputing data, there is no need to
+		 * look for where the data will start, so keep
+		 * cur_offset in sync with the offset in the uio struct.
+		 */
+		cur_offset = uio->uio_offset;
 		if (error)
 			break;
 	}
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-i386->freebsd-emulation 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Sat Oct 21 17:35:55 UTC 2006 
Responsible-Changed-Why:  
Over to mailing list for review. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=101453 
Responsible-Changed-From-To: freebsd-emulation->des 
Responsible-Changed-By: netchild 
Responsible-Changed-When: Wed Aug 29 10:53:18 UTC 2007 
Responsible-Changed-Why:  
Hand over to des, it's his territorry and he agreed (implicit) to take it. 

Notified by:	rdivacky 

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

From: dchagin@FreeBSD.org
To: bug-followup@FreeBSD.org, gibbs@scsiguy.com
Cc: freebsd-emulation@FreeBSD.org
Subject: Re: kern/101453: [linux] [patch] linprocfs disallows
Date: Wed, 1 Oct 2008 21:31:38 +0400 (MSD)

 >   Unformatted:
 >   The original implementation of this routine should have placed its
 >   output into the sbuf provided as an argument. The following untested
 >   patch from des@FreeBSD.org converts the code to make use of the sbuf.
 >   Once the sbuf is properly filled, pseudofs should take care of handling
 >   any offset into the fd.
 >   Index: sys/compat/linprocfs/linprocfs.c
 >   ===================================================================
 
 more comments:
 glibc pthread_getattr_np() uses /proc/self/maps for thread stack address &&
 size calculation. Linux applications which uses NPTL cannot work without
 this patch. I have a little corrected a patch and have tested it with
 linux-flashplugin9. It works fine. It would be excellent to commit it and
 make MFC to RELENG_7 before 7.1R! Many our users waits it.
 
 Fix:
 diff --git a/src/sys/compat/linprocfs/linprocfs.c b/src/sys/compat/linprocfs/linprocfs.c
 index dd4bf77..715146a 100644
 --- a/src/sys/compat/linprocfs/linprocfs.c
 +++ b/src/sys/compat/linprocfs/linprocfs.c
 @@ -872,14 +872,12 @@ linprocfs_doprocenviron(PFS_FILL_ARGS)
  static int
  linprocfs_doprocmaps(PFS_FILL_ARGS)
  {
 -	char mebuffer[512];
  	vm_map_t map = &p->p_vmspace->vm_map;
  	vm_map_entry_t entry, tmp_entry;
  	vm_object_t obj, tobj, lobj;
  	vm_offset_t saved_end;
  	vm_ooffset_t off = 0;
  	char *name = "", *freename = NULL;
 -	size_t len;
  	ino_t ino;
  	unsigned int last_timestamp;
  	int ref_count, shadow_count, flags;
 @@ -897,13 +895,9 @@ linprocfs_doprocmaps(PFS_FILL_ARGS)
  	if (uio->uio_rw != UIO_READ)
  		return (EOPNOTSUPP);
  
 -	if (uio->uio_offset != 0)
 -		return (0);
 -
  	error = 0;
  	vm_map_lock_read(map);
 -	for (entry = map->header.next;
 -	    ((uio->uio_resid > 0) && (entry != &map->header));
 +	for (entry = map->header.next; entry != &map->header;
  	    entry = entry->next) {
  		name = "";
  		freename = NULL;
 @@ -952,7 +946,7 @@ linprocfs_doprocmaps(PFS_FILL_ARGS)
  		 * format:
  		 *  start, end, access, offset, major, minor, inode, name.
  		 */
 -		snprintf(mebuffer, sizeof mebuffer,
 +		error = sbuf_printf(sb,
  		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
  		    (u_long)entry->start, (u_long)entry->end,
  		    (entry->protection & VM_PROT_READ)?"r":"-",
 @@ -968,18 +962,11 @@ linprocfs_doprocmaps(PFS_FILL_ARGS)
  		    );
  		if (freename)
  			free(freename, M_TEMP);
 -		len = strlen(mebuffer);
 -		if (len > uio->uio_resid)
 -			len = uio->uio_resid; /*
 -					       * XXX We should probably return
 -					       * EFBIG here, as in procfs.
 -					       */
  		last_timestamp = map->timestamp;
  		vm_map_unlock_read(map);
 -		error = uiomove(mebuffer, len, uio);
 +		if (error == -1)
 +			return (0);
  		vm_map_lock_read(map);
 -		if (error)
 -			break;
  		if (last_timestamp + 1 != map->timestamp) {
  			/*
  			 * Look again for the entry because the map was
 
 --
 chd,
 Have fun!
Responsible-Changed-From-To: des->kib 
Responsible-Changed-By: kib 
Responsible-Changed-When: Sat Oct 4 13:51:10 UTC 2008 
Responsible-Changed-Why:  
Take. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/101453: commit references a PR
Date: Sat,  4 Oct 2008 14:08:37 +0000 (UTC)

 kib         2008-10-04 14:08:16 UTC
 
   FreeBSD src repository
 
   Modified files:
     sys/compat/linprocfs linprocfs.c 
     sys/fs/procfs        procfs_map.c 
   Log:
   SVN rev 183600 on 2008-10-04 14:08:16Z by kib
   
   Change the linprocfs <pid>/maps and procfs <pid>/map handlers to use
   sbuf instead of doing uiomove. This allows for reads from non-zero
   offsets to work.
   
   Patch is forward-ported des@' one, and was adopted to current code
   by dchagin@ and me.
   
   Reviewed by:    des (linprocfs part)
   PR:     kern/101453
   MFC after:      1 week
   
   Revision  Changes    Path
   1.125     +5 -29     src/sys/compat/linprocfs/linprocfs.c
   1.42      +7 -29     src/sys/fs/procfs/procfs_map.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: kib 
State-Changed-When: Mon Oct 13 13:05:20 UTC 2008 
State-Changed-Why:  
patch committed to head and stable/7. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=101453 
>Unformatted:
The original implementation of this routine should have placed its
output into the sbuf provided as an argument.  The following untested
patch from des@FreeBSD.org converts the code to make use of the sbuf.
Once the sbuf is properly filled, pseudofs should take care of handling
any offset into the fd.

Index: sys/compat/linprocfs/linprocfs.c
===================================================================
RCS file: /home/ncvs/src/sys/compat/linprocfs/linprocfs.c,v
retrieving revision 1.97
diff -u -r1.97 linprocfs.c
--- sys/compat/linprocfs/linprocfs.c	8 Aug 2006 12:29:26 -0000	1.97
+++ sys/compat/linprocfs/linprocfs.c	18 Aug 2006 15:33:06 -0000
@@ -791,13 +791,11 @@
 static int
 linprocfs_doprocmaps(PFS_FILL_ARGS)
 {
-	char mebuffer[512];
 	vm_map_t map = &p->p_vmspace->vm_map;
 	vm_map_entry_t entry;
 	vm_object_t obj, tobj, lobj;
 	vm_ooffset_t off = 0;
 	char *name = "", *freename = NULL;
-	size_t len;
 	ino_t ino;
 	int ref_count, shadow_count, flags;
 	int error;
@@ -820,9 +818,7 @@
 	error = 0;
 	if (map != &curthread->td_proc->p_vmspace->vm_map)
 		vm_map_lock_read(map);
-        for (entry = map->header.next;
-	    ((uio->uio_resid > 0) && (entry != &map->header));
-	    entry = entry->next) {
+        for (entry = map->header.next; entry != &map->header; entry = entry->next) {
 		name = "";
 		freename = NULL;
 		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
@@ -864,7 +860,7 @@
 	     	 * format:
 		 *  start, end, access, offset, major, minor, inode, name.
 		 */
-		snprintf(mebuffer, sizeof mebuffer,
+		sbuf_printf(sb,
 		    "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
 		    (u_long)entry->start, (u_long)entry->end,
 		    (entry->protection & VM_PROT_READ)?"r":"-",
@@ -880,15 +876,6 @@
 		    );
 		if (freename)
 			free(freename, M_TEMP);
-		len = strlen(mebuffer);
-		if (len > uio->uio_resid)
-			len = uio->uio_resid; /*
-					       * XXX We should probably return
-					       * EFBIG here, as in procfs.
-					       */
-		error = uiomove(mebuffer, len, uio);
-		if (error)
-			break;
 	}
 	if (map != &curthread->td_proc->p_vmspace->vm_map)
 		vm_map_unlock_read(map);
