From nobody@FreeBSD.org  Mon Aug 31 01:19:42 2009
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 4D362106566B
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 31 Aug 2009 01:19:42 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 3C1488FC12
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 31 Aug 2009 01:19:42 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n7V1JgA6057240
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 31 Aug 2009 01:19:42 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id n7V1Jfr0057239;
	Mon, 31 Aug 2009 01:19:41 GMT
	(envelope-from nobody)
Message-Id: <200908310119.n7V1Jfr0057239@www.freebsd.org>
Date: Mon, 31 Aug 2009 01:19:41 GMT
From: Bruce Cran <bruce@cran.org.uk>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [tmpfs] 'panic: Assertion pages > 0 failed' when running regression/tmpfs
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         138367
>Category:       kern
>Synopsis:       [tmpfs] [panic] 'panic: Assertion pages > 0 failed' when running regression/tmpfs
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Aug 31 01:20:04 UTC 2009
>Closed-Date:    Tue Feb 07 18:09:40 UTC 2012
>Last-Modified:  Tue Feb 07 18:09:40 UTC 2012
>Originator:     Bruce Cran
>Release:        8.0-BETA3
>Organization:
>Environment:
FreeBSD gluon.draftnet 8.0-BETA3 FreeBSD 8.0-BETA3 #0: Sat Aug 22 01:01:34 BST 2009     brucec@gluon.draftnet:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
When running 'make regress' in tools/regression/tmpfs the following panic occurs:

panic: Assertion pages > 0 failed at /usr/src/sys/modules/tmpfs/../../fs/tmpfs/tmpfs_vfsops.c:246

(kgdb) bt
#0  doadump () at pcpu.h:246
#1  0xc08801de in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:416
#2  0xc08804b2 in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:579
#3  0xc4de9385 in tmpfs_mount (mp=0xc4966000) at /usr/src/sys/modules/tmpfs/../../fs/tmpfs/tmpfs_vfsops.c:246
#4  0xc09097c2 in vfs_donmount (td=0xc497b000, fsflags=0, fsoptions=0xc4c4f100) at /usr/src/sys/kern/vfs_mount.c:984
#5  0xc090aec5 in nmount (td=0xc497b000, uap=0xe6b60cf8) at /usr/src/sys/kern/vfs_mount.c:420
#6  0xc0bb0143 in syscall (frame=0xe6b60d38) at /usr/src/sys/i386/i386/trap.c:1071
#7  0xc0b929b0 in Xint0x80_syscall () at /usr/src/sys/i386/i386/exception.s:261
#8  0x00000033 in ?? ()
Previous frame inner to this frame (corrupt stack?)

>How-To-Repeat:
run 'make regress' in /usr/src/tools/regression/tmpfs
>Fix:


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-fs 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Aug 31 03:59:14 UTC 2009 
Responsible-Changed-Why:  
Over to maintainer(s). 

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

From: Gleb Kurtsou <gleb.kurtsou@gmail.com>
To: bug-followup@FreeBSD.org, bruce@cran.org.uk
Cc:  
Subject: Re: kern/138367: [tmpfs] [panic] 'panic: Assertion pages > 0
 failed' when running regression/tmpfs
Date: Sat, 3 Oct 2009 12:21:08 +0300

 --7AUc2qLy4jB3hD7Z
 Content-Type: text/plain; charset=utf-8
 Content-Disposition: inline
 
 I wasn't able to trigger it on amd64, but there were several integer
 overflow bugs.
 
 Besides there was inconsistency in setting max values. Max pages was set
 to SIZE_MAX (if no value provided by user), but max file size depended
 on available swap/memory at the moment of mounting filesystem. I've set
 max file size to 4GB (of memory limit set by user). It can be changed to
 uint64_t max, but using 4GB seems to be sufficient limit to prevent
 resource exhaustion.
 
 Would you try this patch, I have no i386 system running to test it.
 
 
 --7AUc2qLy4jB3hD7Z
 Content-Type: text/plain; charset=utf-8
 Content-Disposition: attachment; filename="tmpfs-intoverflow.patch.txt"
 
 diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h
 index ffd705f..42a0e5d 100644
 --- a/sys/fs/tmpfs/tmpfs.h
 +++ b/sys/fs/tmpfs/tmpfs.h
 @@ -470,6 +470,11 @@ int	tmpfs_truncate(struct vnode *, off_t);
  #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE)
  
  /*
 + * Set maximum file size to 4 GB.
 + */
 +#define TMPFS_MAXFILESIZE UINT_MAX
 +
 +/*
   * Returns information about the number of available memory pages,
   * including physical and virtual ones.
   *
 diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c
 index f0ae6be..cdefaba 100644
 --- a/sys/fs/tmpfs/tmpfs_vfsops.c
 +++ b/sys/fs/tmpfs/tmpfs_vfsops.c
 @@ -82,57 +82,6 @@ static const char *tmpfs_opts[] = {
  };
  
  /* --------------------------------------------------------------------- */
 -
 -#define SWI_MAXMIB	3
 -
 -static u_int
 -get_swpgtotal(void)
 -{
 -	struct xswdev xsd;
 -	char *sname = "vm.swap_info";
 -	int soid[SWI_MAXMIB], oid[2];
 -	u_int unswdev, total, dmmax, nswapdev;
 -	size_t mibi, len;
 -
 -	total = 0;
 -
 -	len = sizeof(dmmax);
 -	if (kernel_sysctlbyname(curthread, "vm.dmmax", &dmmax, &len,
 -				NULL, 0, NULL, 0) != 0)
 -		return total;
 -
 -	len = sizeof(nswapdev);
 -	if (kernel_sysctlbyname(curthread, "vm.nswapdev",
 -				&nswapdev, &len,
 -				NULL, 0, NULL, 0) != 0)
 -		return total;
 -
 -	mibi = (SWI_MAXMIB - 1) * sizeof(int);
 -	oid[0] = 0;
 -	oid[1] = 3;
 -
 -	if (kernel_sysctl(curthread, oid, 2,
 -			soid, &mibi, (void *)sname, strlen(sname),
 -			NULL, 0) != 0)
 -		return total;
 -
 -	mibi = (SWI_MAXMIB - 1);
 -	for (unswdev = 0; unswdev < nswapdev; ++unswdev) {
 -		soid[mibi] = unswdev;
 -		len = sizeof(struct xswdev);
 -		if (kernel_sysctl(curthread,
 -				soid, mibi + 1, &xsd, &len, NULL, 0,
 -				NULL, 0) != 0)
 -			return total;
 -		if (len == sizeof(struct xswdev))
 -			total += (xsd.xsw_nblks - dmmax);
 -	}
 -
 -	/* Not Reached */
 -	return total;
 -}
 -
 -/* --------------------------------------------------------------------- */
  static int
  tmpfs_node_ctor(void *mem, int size, void *arg, int flags)
  {
 @@ -186,7 +135,7 @@ tmpfs_mount(struct mount *mp)
  	int error;
  	/* Size counters. */
  	ino_t	nodes_max;
 -	size_t	size_max;
 +	off_t	size_max;
  
  	/* Root node attributes. */
  	uid_t	root_uid;
 @@ -230,8 +179,7 @@ tmpfs_mount(struct mount *mp)
  
  	/* Do not allow mounts if we do not have enough memory to preserve
  	 * the minimum reserved pages. */
 -	mem_size = cnt.v_free_count + cnt.v_inactive_count + get_swpgtotal();
 -	mem_size -= mem_size > cnt.v_wire_count ? cnt.v_wire_count : mem_size;
 +	mem_size = tmpfs_mem_info();
  	if (mem_size < TMPFS_PAGES_RESERVED)
  		return ENOSPC;
  
 @@ -239,14 +187,17 @@ tmpfs_mount(struct mount *mp)
  	 * allowed to use, based on the maximum size the user passed in
  	 * the mount structure.  A value of zero is treated as if the
  	 * maximum available space was requested. */
 -	if (size_max < PAGE_SIZE || size_max >= SIZE_MAX)
 -		pages = SIZE_MAX;
 +	/* XXX Choose maximum values to prevent integer overflow */
 +	if (size_max < PAGE_SIZE || size_max > SSIZE_MAX - PAGE_SIZE)
 +		pages = SSIZE_MAX - PAGE_SIZE;
  	else
  		pages = howmany(size_max, PAGE_SIZE);
  	MPASS(pages > 0);
  
 +	CTASSERT(sizeof(ino_t) == sizeof(uint32_t));
 +	/* Set maximum node number to 2GB to prevent integer overflow. */
  	if (nodes_max <= 3)
 -		nodes = 3 + pages * PAGE_SIZE / 1024;
 +		nodes = qmin(pages + 3, INT_MAX);
  	else
  		nodes = nodes_max;
  	MPASS(nodes >= 3);
 @@ -258,7 +209,11 @@ tmpfs_mount(struct mount *mp)
  	mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF);
  	tmp->tm_nodes_max = nodes;
  	tmp->tm_nodes_inuse = 0;
 -	tmp->tm_maxfilesize = (u_int64_t)(cnt.v_page_count + get_swpgtotal()) * PAGE_SIZE;
 +	if ((u_int64_t)pages < (OFF_MAX >> PAGE_SHIFT))
 +		tmp->tm_maxfilesize = qmin((u_int64_t)(pages) * PAGE_SIZE,
 +		    TMPFS_MAXFILESIZE);
 +	else
 +		tmp->tm_maxfilesize = TMPFS_MAXFILESIZE;
  	LIST_INIT(&tmp->tm_nodes_used);
  
  	tmp->tm_pages_max = pages;
 
 --7AUc2qLy4jB3hD7Z--
State-Changed-From-To: open->feedback 
State-Changed-By: jh 
State-Changed-When: Sat Jan 16 10:31:57 UTC 2010 
State-Changed-Why:  
The reported panic should not occur after r201773. Can you confirm? 


Responsible-Changed-From-To: freebsd-fs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Sat Jan 16 10:31:57 UTC 2010 
Responsible-Changed-Why:  
I'll try to look at the other issues raised by Gleb Kurtsou. 

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

From: Bruce Cran <bruce@cran.org.uk>
To: bug-followup@FreeBSD.org, bruce@cran.org.uk
Cc:  
Subject: Re: kern/138367: [tmpfs] [panic] 'panic: Assertion pages &gt; 0
 failed' when running regression/tmpfs
Date: Sat, 16 Jan 2010 11:37:17 +0000

 Sorry for the delay in replying. I only managed to cause the panic
 once, and was unable to reproduce the crash when I tried again later.
 
 -- 
 Bruce Cran

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/138367: commit references a PR
Date: Wed, 20 Jan 2010 16:56:36 +0000 (UTC)

 Author: jh
 Date: Wed Jan 20 16:56:20 2010
 New Revision: 202708
 URL: http://svn.freebsd.org/changeset/base/202708
 
 Log:
   - Change the type of nodes_max to u_int and use "%u" format string to
     convert its value. [1]
   - Set default tm_nodes_max to min(pages + 3, UINT32_MAX). It's more
     reasonable than the old four nodes per page (with page size 4096) because
     non-empty regular files always use at least one page. This fixes possible
     overflow in the calculation. [2]
   - Don't allow more than tm_nodes_max nodes allocated in tmpfs_alloc_node().
   
   PR:		kern/138367
   Suggested by:	bde [1], Gleb Kurtsou [2]
   Approved by:	trasz (mentor)
 
 Modified:
   head/sys/fs/tmpfs/tmpfs_subr.c
   head/sys/fs/tmpfs/tmpfs_vfsops.c
 
 Modified: head/sys/fs/tmpfs/tmpfs_subr.c
 ==============================================================================
 --- head/sys/fs/tmpfs/tmpfs_subr.c	Wed Jan 20 16:50:13 2010	(r202707)
 +++ head/sys/fs/tmpfs/tmpfs_subr.c	Wed Jan 20 16:56:20 2010	(r202708)
 @@ -93,7 +93,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
  	MPASS(IFF(type == VLNK, target != NULL));
  	MPASS(IFF(type == VBLK || type == VCHR, rdev != VNOVAL));
  
 -	if (tmp->tm_nodes_inuse > tmp->tm_nodes_max)
 +	if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max)
  		return (ENOSPC);
  
  	nnode = (struct tmpfs_node *)uma_zalloc_arg(
 
 Modified: head/sys/fs/tmpfs/tmpfs_vfsops.c
 ==============================================================================
 --- head/sys/fs/tmpfs/tmpfs_vfsops.c	Wed Jan 20 16:50:13 2010	(r202707)
 +++ head/sys/fs/tmpfs/tmpfs_vfsops.c	Wed Jan 20 16:56:20 2010	(r202708)
 @@ -182,10 +182,10 @@ tmpfs_mount(struct mount *mp)
  	struct tmpfs_mount *tmp;
  	struct tmpfs_node *root;
  	size_t pages, mem_size;
 -	ino_t nodes;
 +	uint32_t nodes;
  	int error;
  	/* Size counters. */
 -	ino_t nodes_max;
 +	u_int nodes_max;
  	u_quad_t size_max;
  
  	/* Root node attributes. */
 @@ -223,7 +223,7 @@ tmpfs_mount(struct mount *mp)
  	if (mp->mnt_cred->cr_ruid != 0 ||
  	    vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) != 1)
  		root_mode = va.va_mode;
 -	if (vfs_scanopt(mp->mnt_optnew, "inodes", "%d", &nodes_max) != 1)
 +	if (vfs_scanopt(mp->mnt_optnew, "inodes", "%u", &nodes_max) != 1)
  		nodes_max = 0;
  	if (vfs_scanopt(mp->mnt_optnew, "size", "%qu", &size_max) != 1)
  		size_max = 0;
 @@ -245,9 +245,12 @@ tmpfs_mount(struct mount *mp)
  		pages = howmany(size_max, PAGE_SIZE);
  	MPASS(pages > 0);
  
 -	if (nodes_max <= 3)
 -		nodes = 3 + pages * PAGE_SIZE / 1024;
 -	else
 +	if (nodes_max <= 3) {
 +		if (pages > UINT32_MAX - 3)
 +			nodes = UINT32_MAX;
 +		else
 +			nodes = pages + 3;
 +	} else
  		nodes = nodes_max;
  	MPASS(nodes >= 3);
  
 _______________________________________________
 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: feedback->patched 
State-Changed-By: jh 
State-Changed-When: Wed Jan 20 18:09:06 UTC 2010 
State-Changed-Why:  
The panic should should be fixed by r201773. I will propose a different 
change for maximum file size. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/138367: commit references a PR
Date: Tue,  8 Mar 2011 17:27:46 +0000 (UTC)

 Author: jh
 Date: Tue Mar  8 17:27:36 2011
 New Revision: 219401
 URL: http://svn.freebsd.org/changeset/base/219401
 
 Log:
   MFC r201773:
   
   - Change the type of size_max to u_quad_t because its value is converted
     with vfs_scanopt(9) using the "%qu" format string.
   - Limit the maximum value of size_max to (SIZE_MAX - PAGE_SIZE) to
     prevent overflow in howmany() macro.
   
   PR:		kern/141194
   
   MFC r202187:
   
   - Fix some style bugs in tmpfs_mount().
   - Remove a stale comment about tmpfs_mem_info() 'total' argument.
   
   MFC r202708:
   
   - Change the type of nodes_max to u_int and use "%u" format string to
     convert its value.
   - Set default tm_nodes_max to min(pages + 3, UINT32_MAX). It's more
     reasonable than the old four nodes per page (with page size 4096) because
     non-empty regular files always use at least one page. This fixes possible
     overflow in the calculation.
   - Don't allow more than tm_nodes_max nodes allocated in tmpfs_alloc_node().
   
   PR:		kern/138367
 
 Modified:
   stable/8/sys/fs/tmpfs/tmpfs.h
   stable/8/sys/fs/tmpfs/tmpfs_subr.c
   stable/8/sys/fs/tmpfs/tmpfs_vfsops.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/fs/tmpfs/tmpfs.h
 ==============================================================================
 --- stable/8/sys/fs/tmpfs/tmpfs.h	Tue Mar  8 17:00:31 2011	(r219400)
 +++ stable/8/sys/fs/tmpfs/tmpfs.h	Tue Mar  8 17:27:36 2011	(r219401)
 @@ -476,10 +476,6 @@ int	tmpfs_truncate(struct vnode *, off_t
   * Returns information about the number of available memory pages,
   * including physical and virtual ones.
   *
 - * If 'total' is TRUE, the value returned is the total amount of memory
 - * pages configured for the system (either in use or free).
 - * If it is FALSE, the value returned is the amount of free memory pages.
 - *
   * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
   * excessive memory usage.
   *
 
 Modified: stable/8/sys/fs/tmpfs/tmpfs_subr.c
 ==============================================================================
 --- stable/8/sys/fs/tmpfs/tmpfs_subr.c	Tue Mar  8 17:00:31 2011	(r219400)
 +++ stable/8/sys/fs/tmpfs/tmpfs_subr.c	Tue Mar  8 17:27:36 2011	(r219401)
 @@ -93,7 +93,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
  	MPASS(IFF(type == VLNK, target != NULL));
  	MPASS(IFF(type == VBLK || type == VCHR, rdev != VNOVAL));
  
 -	if (tmp->tm_nodes_inuse > tmp->tm_nodes_max)
 +	if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max)
  		return (ENOSPC);
  
  	nnode = (struct tmpfs_node *)uma_zalloc_arg(
 
 Modified: stable/8/sys/fs/tmpfs/tmpfs_vfsops.c
 ==============================================================================
 --- stable/8/sys/fs/tmpfs/tmpfs_vfsops.c	Tue Mar  8 17:00:31 2011	(r219400)
 +++ stable/8/sys/fs/tmpfs/tmpfs_vfsops.c	Tue Mar  8 17:27:36 2011	(r219401)
 @@ -182,18 +182,18 @@ tmpfs_mount(struct mount *mp)
  	struct tmpfs_mount *tmp;
  	struct tmpfs_node *root;
  	size_t pages, mem_size;
 -	ino_t nodes;
 +	uint32_t nodes;
  	int error;
  	/* Size counters. */
 -	ino_t	nodes_max;
 -	size_t	size_max;
 +	u_int nodes_max;
 +	u_quad_t size_max;
  
  	/* Root node attributes. */
 -	uid_t	root_uid;
 -	gid_t	root_gid;
 -	mode_t	root_mode;
 +	uid_t root_uid;
 +	gid_t root_gid;
 +	mode_t root_mode;
  
 -	struct vattr	va;
 +	struct vattr va;
  
  	if (vfs_filteropt(mp->mnt_optnew, tmpfs_opts))
  		return (EINVAL);
 @@ -223,7 +223,7 @@ tmpfs_mount(struct mount *mp)
  	if (mp->mnt_cred->cr_ruid != 0 ||
  	    vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) != 1)
  		root_mode = va.va_mode;
 -	if (vfs_scanopt(mp->mnt_optnew, "inodes", "%d", &nodes_max) != 1)
 +	if (vfs_scanopt(mp->mnt_optnew, "inodes", "%u", &nodes_max) != 1)
  		nodes_max = 0;
  	if (vfs_scanopt(mp->mnt_optnew, "size", "%qu", &size_max) != 1)
  		size_max = 0;
 @@ -239,15 +239,18 @@ tmpfs_mount(struct mount *mp)
  	 * allowed to use, based on the maximum size the user passed in
  	 * the mount structure.  A value of zero is treated as if the
  	 * maximum available space was requested. */
 -	if (size_max < PAGE_SIZE || size_max >= SIZE_MAX)
 +	if (size_max < PAGE_SIZE || size_max > SIZE_MAX - PAGE_SIZE)
  		pages = SIZE_MAX;
  	else
  		pages = howmany(size_max, PAGE_SIZE);
  	MPASS(pages > 0);
  
 -	if (nodes_max <= 3)
 -		nodes = 3 + pages * PAGE_SIZE / 1024;
 -	else
 +	if (nodes_max <= 3) {
 +		if (pages > UINT32_MAX - 3)
 +			nodes = UINT32_MAX;
 +		else
 +			nodes = pages + 3;
 +	} else
  		nodes = nodes_max;
  	MPASS(nodes >= 3);
  
 _______________________________________________
 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: jh 
State-Changed-When: Tue Feb 7 18:09:39 UTC 2012 
State-Changed-Why:  
Fixed in head, stable/9 and stable/8. 

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