Date: Thu, 5 Apr 2012 04:20:14 -0700 From: David Wolfskill <david@catwhisker.org> To: Gleb Kurtsou <gleb.kurtsou@gmail.com> Cc: current@freebsd.org Subject: Re: Using TMPFS for /tmp and /var/run? Message-ID: <20120405112014.GH1420@albert.catwhisker.org> In-Reply-To: <20120405074304.GA1048@reks> References: <20120404095035.GA1929@reks> <20120404133858.GB1420@albert.catwhisker.org> <20120405074304.GA1048@reks>
next in thread | previous in thread | raw e-mail | index | archive | help
--D+WCZLadiceW8Bs8 Content-Type: multipart/mixed; boundary="LWVQOr/QoF/fPPTS" Content-Disposition: inline --LWVQOr/QoF/fPPTS Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Apr 05, 2012 at 10:43:04AM +0300, Gleb Kurtsou wrote: > ... > > Summary: as before, I believe that the patch didn't hurt anything, but > > it also doesn't restrict the usable size of /tmp to the specified size > > (from /etc/fstab): > >=20 >=20 > I've checked on i386 and patch worked as expected, but it required > previous patch. I've combined both patches. Could you try it. To be very clear, I've attached the output from=20 cd /sys && svn diff Peace, david --=20 David H. Wolfskill david@catwhisker.org Depriving a girl or boy of an opportunity for education is evil. See http://www.catwhisker.org/~david/publickey.gpg for my public key. --LWVQOr/QoF/fPPTS Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=diffs Content-Transfer-Encoding: quoted-printable Index: fs/tmpfs/tmpfs.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- fs/tmpfs/tmpfs.h (revision 233868) +++ fs/tmpfs/tmpfs.h (working copy) @@ -337,11 +337,10 @@ * system, set during mount time. This variable must never be * used directly as it may be bigger than the current amount of * free memory; in the extreme case, it will hold the SIZE_MAX - * value. Instead, use the TMPFS_PAGES_MAX macro. */ + * value. */ size_t tm_pages_max; =20 - /* Number of pages in use by the file system. Cannot be bigger - * than the value returned by TMPFS_PAGES_MAX in any case. */ + /* Number of pages in use by the file system. */ size_t tm_pages_used; =20 /* Pointer to the node representing the root directory of this @@ -486,58 +485,32 @@ * Memory management stuff. */ =20 -/* Amount of memory pages to reserve for the system (e.g., to not use by +/* + * Amount of memory pages to reserve for the system (e.g., to not use by * tmpfs). - * XXX: Should this be tunable through sysctl, for instance? */ -#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) + */ +#define TMPFS_PAGES_MINRESERVED (4 * 1024 * 1024 / PAGE_SIZE) =20 /* - * Returns information about the number of available memory pages, - * including physical and virtual ones. - * - * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid - * excessive memory usage. - * + * Number of reserved swap pages should not be lower than + * swap_pager_almost_full high water mark. */ -static __inline size_t -tmpfs_mem_info(void) -{ +#define TMPFS_SWAP_MINRESERVED 1024 =20 - return (swap_pager_avail + cnt.v_free_count + cnt.v_cache_count); -} +size_t tmpfs_mem_avail(void); =20 -/* Returns the maximum size allowed for a tmpfs file system. This macro - * must be used instead of directly retrieving the value from tm_pages_max. - * The reason is that the size of a tmpfs file system is dynamic: it lets - * the user store files as long as there is enough free memory (including - * physical memory and swap space). Therefore, the amount of memory to be - * used is either the limit imposed by the user during mount time or the - * amount of available memory, whichever is lower. To avoid consuming all - * the memory for a given mount point, the system will always reserve a - * minimum of TMPFS_PAGES_RESERVED pages, which is also taken into account - * by this macro (see above). */ static __inline size_t -TMPFS_PAGES_MAX(struct tmpfs_mount *tmp) +tmpfs_pages_used(struct tmpfs_mount *tmp) { - size_t freepages; + const size_t node_size =3D sizeof(struct tmpfs_node) + + sizeof(struct tmpfs_dirent); + size_t meta_pages; =20 - freepages =3D tmpfs_mem_info(); - freepages -=3D freepages < TMPFS_PAGES_RESERVED ? - freepages : TMPFS_PAGES_RESERVED; - - return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used); + meta_pages =3D howmany((uintmax_t)tmp->tm_nodes_inuse * node_size, + PAGE_SIZE); + return (meta_pages + tmp->tm_pages_used); } =20 -/* Returns the available space for the given file system. */ -#define TMPFS_META_PAGES(tmp) (howmany((tmp)->tm_nodes_inuse * (sizeof(str= uct tmpfs_node) \ - + sizeof(struct tmpfs_dirent)), PAGE_SIZE)) -#define TMPFS_FILE_PAGES(tmp) ((tmp)->tm_pages_used) - -#define TMPFS_PAGES_AVAIL(tmp) (TMPFS_PAGES_MAX(tmp) > \ - TMPFS_META_PAGES(tmp)+TMPFS_FILE_PAGES(tmp)? \ - TMPFS_PAGES_MAX(tmp) - TMPFS_META_PAGES(tmp) \ - - TMPFS_FILE_PAGES(tmp):0) - #endif =20 /* --------------------------------------------------------------------- */ Index: fs/tmpfs/tmpfs_subr.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- fs/tmpfs/tmpfs_subr.c (revision 233868) +++ fs/tmpfs/tmpfs_subr.c (working copy) @@ -59,6 +59,76 @@ =20 SYSCTL_NODE(_vfs, OID_AUTO, tmpfs, CTLFLAG_RW, 0, "tmpfs file system"); =20 +static long tmpfs_swap_reserved =3D TMPFS_SWAP_MINRESERVED * 2; + +static long tmpfs_pages_reserved =3D TMPFS_PAGES_MINRESERVED; + +static int +sysctl_mem_reserved(SYSCTL_HANDLER_ARGS) +{ + int error; + long pages, bytes, reserved; + + pages =3D *(long *)arg1; + bytes =3D pages * PAGE_SIZE; + + error =3D sysctl_handle_long(oidp, &bytes, 0, req); + if (error || !req->newptr) + return (error); + + pages =3D bytes / PAGE_SIZE; + if (arg1 =3D=3D &tmpfs_swap_reserved) + reserved =3D TMPFS_SWAP_MINRESERVED; + else + reserved =3D TMPFS_PAGES_MINRESERVED; + if (pages < reserved) + return (EINVAL); + + *(long *)arg1 =3D pages; + return (0); +} + +SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, memory_reserved, CTLTYPE_LONG|CTLFLAG_RW, + &tmpfs_pages_reserved, 0, sysctl_mem_reserved, "L", "reserved memory"); +SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, swap_reserved, CTLTYPE_LONG|CTLFLAG_RW, + &tmpfs_swap_reserved, 0, sysctl_mem_reserved, "L", "reserved swap memo= ry"); + +size_t +tmpfs_mem_avail(void) +{ + vm_ooffset_t avail_swap, avail_mem; + + avail_swap =3D swap_pager_avail - tmpfs_swap_reserved; + if (__predict_false(avail_swap <=3D 0)) { + /* FIXME No swap or disabled swap check */ + if (swap_pager_avail =3D=3D 0) + avail_swap =3D 0; + else + return (0); + } + avail_mem =3D cnt.v_free_count + cnt.v_cache_count - tmpfs_pages_reserved; + if (__predict_false(avail_mem < 0)) + avail_mem =3D 0; + return (avail_swap + avail_mem); +} + +static size_t +tmpfs_pages_check_avail(struct tmpfs_mount *tmp, size_t req_pages) +{ + size_t avail; + + avail =3D tmpfs_mem_avail(); + if (avail < req_pages) + return (0); + + if (tmp->tm_pages_max !=3D SIZE_MAX) + avail =3D tmp->tm_pages_max - tmpfs_pages_used(tmp); + if (avail < req_pages) + return (0); + + return (1); +} + /* --------------------------------------------------------------------- */ =20 /* @@ -99,6 +169,8 @@ =20 if (tmp->tm_nodes_inuse >=3D tmp->tm_nodes_max) return (ENOSPC); + if (tmpfs_pages_check_avail(tmp, 1) =3D=3D 0) + return (ENOSPC); =20 nnode =3D (struct tmpfs_node *)uma_zalloc_arg( tmp->tm_node_pool, tmp, M_WAITOK); @@ -917,7 +989,7 @@ MPASS(oldpages =3D=3D uobj->size); newpages =3D OFF_TO_IDX(newsize + PAGE_MASK); if (newpages > oldpages && - newpages - oldpages > TMPFS_PAGES_AVAIL(tmp)) + tmpfs_pages_check_avail(tmp, newpages - oldpages) =3D=3D 0) return (ENOSPC); =20 VM_OBJECT_LOCK(uobj); Index: fs/tmpfs/tmpfs_vfsops.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- fs/tmpfs/tmpfs_vfsops.c (revision 233868) +++ fs/tmpfs/tmpfs_vfsops.c (working copy) @@ -90,6 +90,8 @@ struct tmpfs_node *node =3D (struct tmpfs_node *)mem; =20 node->tn_gen++; + if (node->tn_gen =3D=3D 0) + node->tn_gen =3D (arc4random() / 2) + 1; node->tn_size =3D 0; node->tn_status =3D 0; node->tn_flags =3D 0; @@ -114,7 +116,7 @@ node->tn_id =3D 0; =20 mtx_init(&node->tn_interlock, "tmpfs node interlock", NULL, MTX_DEF); - node->tn_gen =3D arc4random(); + node->tn_gen =3D (arc4random() / 2) + 1; =20 return (0); } @@ -127,17 +129,59 @@ mtx_destroy(&node->tn_interlock); } =20 +/* + * XXX Rename to vfs_getopt_size() + */ static int +tmpfs_getopt_size(struct vfsoptlist *opts, const char *name, u_quad_t *dat= a) +{ + char *opt_value, *vtp; + quad_t iv; + int error, opt_len; + + error =3D vfs_getopt(opts, name, (void **)&opt_value, &opt_len); + if (error !=3D 0) + return (error); + if (opt_len =3D=3D 0 || opt_value =3D=3D NULL) + return (EINVAL); + if (opt_value[0] =3D=3D '\0' || opt_value[opt_len - 1] !=3D '\0') + return (EINVAL); + + iv =3D strtoq(opt_value, &vtp, 0); + if (vtp =3D=3D opt_value || (vtp[0] !=3D '\0' && vtp[1] !=3D '\0')) + return (EINVAL); + if (iv < 0) + return (EINVAL); + switch (vtp[0]) { + case 't': case 'T': + iv *=3D 1024; + case 'g': case 'G': + iv *=3D 1024; + case 'm': case 'M': + iv *=3D 1024; + case 'k': case 'K': + iv *=3D 1024; + case '\0': + break; + default: + return (EINVAL); + } + *data =3D iv; + + return (0); +} + +static int tmpfs_mount(struct mount *mp) { + const size_t nodes_per_page =3D howmany(PAGE_SIZE, + sizeof(struct tmpfs_dirent) + sizeof(struct tmpfs_node)); struct tmpfs_mount *tmp; struct tmpfs_node *root; - size_t pages; - uint32_t nodes; int error; /* Size counters. */ - u_int nodes_max; - u_quad_t size_max, maxfilesize; + u_quad_t pages; + u_quad_t nodes_max, size_max, maxfilesize; =20 /* Root node attributes. */ uid_t root_uid; @@ -173,17 +217,16 @@ if (mp->mnt_cred->cr_ruid !=3D 0 || vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) !=3D 1) root_mode =3D va.va_mode; - if (vfs_scanopt(mp->mnt_optnew, "inodes", "%u", &nodes_max) !=3D 1) + if (tmpfs_getopt_size(mp->mnt_optnew, "inodes", &nodes_max) !=3D 0) nodes_max =3D 0; - if (vfs_scanopt(mp->mnt_optnew, "size", "%qu", &size_max) !=3D 1) + if (tmpfs_getopt_size(mp->mnt_optnew, "size", &size_max) !=3D 0) size_max =3D 0; - if (vfs_scanopt(mp->mnt_optnew, "maxfilesize", "%qu", - &maxfilesize) !=3D 1) + if (tmpfs_getopt_size(mp->mnt_optnew, "maxfilesize", &maxfilesize) !=3D 0) maxfilesize =3D 0; =20 /* Do not allow mounts if we do not have enough memory to preserve * the minimum reserved pages. */ - if (tmpfs_mem_info() < TMPFS_PAGES_RESERVED) + if (tmpfs_mem_avail() < TMPFS_PAGES_MINRESERVED) return ENOSPC; =20 /* Get the maximum number of memory pages this file system is @@ -196,21 +239,27 @@ pages =3D howmany(size_max, PAGE_SIZE); MPASS(pages > 0); =20 + if (pages < SIZE_MAX / PAGE_SIZE) + size_max =3D pages * PAGE_SIZE; + else + size_max =3D SIZE_MAX; + if (nodes_max <=3D 3) { - if (pages > UINT32_MAX - 3) - nodes =3D UINT32_MAX; + if (pages < INT_MAX / nodes_per_page) + nodes_max =3D pages * nodes_per_page; else - nodes =3D pages + 3; - } else - nodes =3D nodes_max; - MPASS(nodes >=3D 3); + nodes_max =3D INT_MAX; + } + if (nodes_max > INT_MAX) + nodes_max =3D INT_MAX; + MPASS(nodes_max >=3D 3); =20 /* Allocate the tmpfs mount structure and fill it. */ tmp =3D (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount), M_TMPFSMNT, M_WAITOK | M_ZERO); =20 mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF); - tmp->tm_nodes_max =3D nodes; + tmp->tm_nodes_max =3D nodes_max; tmp->tm_nodes_inuse =3D 0; tmp->tm_maxfilesize =3D maxfilesize > 0 ? maxfilesize : UINT64_MAX; LIST_INIT(&tmp->tm_nodes_used); @@ -355,16 +404,16 @@ if (tfhp->tf_len !=3D sizeof(struct tmpfs_fid)) return EINVAL; =20 - if (tfhp->tf_id >=3D tmp->tm_nodes_max) + if (tfhp->tf_id > INT_MAX || tfhp->tf_id <=3D 0) return EINVAL; =20 found =3D FALSE; =20 TMPFS_LOCK(tmp); LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) { - if (node->tn_id =3D=3D tfhp->tf_id && - node->tn_gen =3D=3D tfhp->tf_gen) { - found =3D TRUE; + if (node->tn_id =3D=3D tfhp->tf_id) { + if (node->tn_gen =3D=3D tfhp->tf_gen) + found =3D TRUE; break; } } @@ -373,7 +422,7 @@ if (found) return (tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp)); =20 - return (EINVAL); + return (ESTALE); } =20 /* --------------------------------------------------------------------- */ @@ -382,22 +431,26 @@ static int tmpfs_statfs(struct mount *mp, struct statfs *sbp) { - fsfilcnt_t freenodes; struct tmpfs_mount *tmp; + size_t used; =20 tmp =3D VFS_TO_TMPFS(mp); =20 sbp->f_iosize =3D PAGE_SIZE; sbp->f_bsize =3D PAGE_SIZE; =20 - sbp->f_blocks =3D TMPFS_PAGES_MAX(tmp); - sbp->f_bavail =3D sbp->f_bfree =3D TMPFS_PAGES_AVAIL(tmp); - - freenodes =3D MIN(tmp->tm_nodes_max - tmp->tm_nodes_inuse, - TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node)); - - sbp->f_files =3D freenodes + tmp->tm_nodes_inuse; - sbp->f_ffree =3D freenodes; + used =3D tmpfs_pages_used(tmp); + if (tmp->tm_pages_max !=3D SIZE_MAX) + sbp->f_blocks =3D tmp->tm_pages_max; + else + sbp->f_blocks =3D used + tmpfs_mem_avail(); + if (sbp->f_blocks <=3D used) + sbp->f_bavail =3D 0; + else + sbp->f_bavail =3D sbp->f_blocks - used; + sbp->f_bfree =3D sbp->f_bavail; + sbp->f_files =3D tmp->tm_nodes_max; + sbp->f_ffree =3D tmp->tm_nodes_max - tmp->tm_nodes_inuse; /* sbp->f_owner =3D tmp->tn_uid; */ =20 return 0; Index: conf/newvers.sh =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- conf/newvers.sh (revision 233868) +++ conf/newvers.sh (working copy) @@ -87,55 +87,25 @@ v=3D`cat version` u=3D${USER:-root} d=3D`pwd` h=3D${HOSTNAME:-`hostname`} = t=3D`date` i=3D`${MAKE:-make} -V KERN_IDENT` =20 -for dir in /bin /usr/bin /usr/local/bin; do - if [ -x "${dir}/svnversion" ] ; then - svnversion=3D${dir}/svnversion - break - fi -done -if [ -d "${SYSDIR}/../.git" ] ; then - for dir in /bin /usr/bin /usr/local/bin; do - if [ -x "${dir}/git" ] ; then - git_cmd=3D"${dir}/git --git-dir=3D${SYSDIR}/../.git" - break - fi - done +if [ -r ${SYSDIR}/conf/get_version_from_vcs.sh ] ; then + . ${SYSDIR}/conf/get_version_from_vcs.sh +else + # Fallback function to get a "version ID" if we can't find + # a replacement function. + get_version_from_vcs() { + date +%s + } fi +version_from_vcs=3D`get_version_from_vcs` =20 -if [ -n "$svnversion" ] ; then - svn=3D`cd ${SYSDIR} && $svnversion` - case "$svn" in - [0-9]*) svn=3D" r${svn}" ;; - *) unset svn ;; - esac +if [ -n "$version_from_vcs" ]; then + version_from_vcs=3D" $version_from_vcs" fi =20 -if [ -n "$git_cmd" ] ; then - git=3D`$git_cmd rev-parse --verify --short HEAD 2>/dev/null` - svn=3D`$git_cmd svn find-rev $git 2>/dev/null` - if [ -n "$svn" ] ; then - svn=3D" r${svn}" - git=3D"=3D${git}" - else - svn=3D`$git_cmd log | fgrep 'git-svn-id:' | head -1 | \ - sed -n 's/^.*@\([0-9][0-9]*\).*$/\1/p'` - if [ -n $svn ] ; then - svn=3D" r${svn}" - git=3D"+${git}" - else - git=3D" ${git}" - fi - fi - if $git_cmd --work-tree=3D${SYSDIR}/.. diff-index \ - --name-only HEAD | read dummy; then - git=3D"${git}-dirty" - fi -fi - cat << EOF > vers.c $COPYRIGHT -#define SCCSSTR "@(#)${VERSION} #${v}${svn}${git}: ${t}" -#define VERSTR "${VERSION} #${v}${svn}${git}: ${t}\\n ${u}@${h}:${d}\\n" +#define SCCSSTR "@(#)${VERSION} #${v}${version_from_vcs}: ${t}" +#define VERSTR "${VERSION} #${v}${version_from_vcs}: ${t}\\n ${u}@${h}:= ${d}\\n" #define RELSTR "${RELEASE}" =20 char sccs[sizeof(SCCSSTR) > 128 ? sizeof(SCCSSTR) : 128] =3D SCCSSTR; --LWVQOr/QoF/fPPTS-- --D+WCZLadiceW8Bs8 Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (FreeBSD) iEYEARECAAYFAk99f+0ACgkQmprOCmdXAD3FhgCfaMe8kd8u5RK+KBIlS6eh7W3U 9m4An1g1/9qlKdk4iIgfkRmf6Os52suH =s6F7 -----END PGP SIGNATURE----- --D+WCZLadiceW8Bs8--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120405112014.GH1420>