kern/138367: [tmpfs] [panic] 'panic: Assertion pages > 0
failed' when running regression/tmpfs
Gleb Kurtsou
gleb.kurtsou at gmail.com
Sat Oct 3 09:30:04 UTC 2009
The following reply was made to PR kern/138367; it has been noted by GNATS.
From: Gleb Kurtsou <gleb.kurtsou at gmail.com>
To: bug-followup at FreeBSD.org, bruce at 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--
More information about the freebsd-fs
mailing list