From owner-freebsd-fs@FreeBSD.ORG Sat Oct 3 09:30:04 2009 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E38EF1065670 for ; Sat, 3 Oct 2009 09:30:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id D1B908FC18 for ; Sat, 3 Oct 2009 09:30:03 +0000 (UTC) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id n939U3WE077254 for ; Sat, 3 Oct 2009 09:30:03 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n939U3kc077250; Sat, 3 Oct 2009 09:30:03 GMT (envelope-from gnats) Date: Sat, 3 Oct 2009 09:30:03 GMT Message-Id: <200910030930.n939U3kc077250@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Gleb Kurtsou Cc: Subject: Re: kern/138367: [tmpfs] [panic] 'panic: Assertion pages > 0 failed' when running regression/tmpfs X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Gleb Kurtsou List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 03 Oct 2009 09:30:04 -0000 The following reply was made to PR kern/138367; it has been noted by GNATS. From: Gleb Kurtsou 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--