Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 3 Oct 2009 09:30:03 GMT
From:      Gleb Kurtsou <gleb.kurtsou@gmail.com>
To:        freebsd-fs@FreeBSD.org
Subject:   Re: kern/138367: [tmpfs] [panic] 'panic: Assertion pages > 0 failed' when running regression/tmpfs
Message-ID:  <200910030930.n939U3kc077250@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/138367; it has been noted by GNATS.

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--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910030930.n939U3kc077250>