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

        cd /sys && svn diff

Peace,
david
-- 
David H. Wolfskill                              da...@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.
Index: fs/tmpfs/tmpfs.h
===================================================================
--- 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;
 
-       /* 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;
 
        /* Pointer to the node representing the root directory of this
@@ -486,58 +485,32 @@
  * Memory management stuff.
  */
 
-/* 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)
 
 /*
- * 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
 
-       return (swap_pager_avail + cnt.v_free_count + cnt.v_cache_count);
-}
+size_t tmpfs_mem_avail(void);
 
-/* 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 = sizeof(struct tmpfs_node) +
+           sizeof(struct tmpfs_dirent);
+       size_t meta_pages;
 
-       freepages = tmpfs_mem_info();
-       freepages -= freepages < TMPFS_PAGES_RESERVED ?
-           freepages : TMPFS_PAGES_RESERVED;
-
-       return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used);
+       meta_pages = howmany((uintmax_t)tmp->tm_nodes_inuse * node_size,
+           PAGE_SIZE);
+       return (meta_pages + tmp->tm_pages_used);
 }
 
-/* Returns the available space for the given file system. */
-#define TMPFS_META_PAGES(tmp) (howmany((tmp)->tm_nodes_inuse * (sizeof(struct 
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
 
 /* --------------------------------------------------------------------- */
Index: fs/tmpfs/tmpfs_subr.c
===================================================================
--- fs/tmpfs/tmpfs_subr.c       (revision 233868)
+++ fs/tmpfs/tmpfs_subr.c       (working copy)
@@ -59,6 +59,76 @@
 
 SYSCTL_NODE(_vfs, OID_AUTO, tmpfs, CTLFLAG_RW, 0, "tmpfs file system");
 
+static long tmpfs_swap_reserved = TMPFS_SWAP_MINRESERVED * 2;
+
+static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESERVED;
+
+static int
+sysctl_mem_reserved(SYSCTL_HANDLER_ARGS)
+{
+       int error;
+       long pages, bytes, reserved;
+
+       pages = *(long *)arg1;
+       bytes = pages * PAGE_SIZE;
+
+       error = sysctl_handle_long(oidp, &bytes, 0, req);
+       if (error || !req->newptr)
+               return (error);
+
+       pages = bytes / PAGE_SIZE;
+       if (arg1 == &tmpfs_swap_reserved)
+               reserved = TMPFS_SWAP_MINRESERVED;
+       else
+               reserved = TMPFS_PAGES_MINRESERVED;
+       if (pages < reserved)
+               return (EINVAL);
+
+       *(long *)arg1 = 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 memory");
+
+size_t
+tmpfs_mem_avail(void)
+{
+       vm_ooffset_t avail_swap, avail_mem;
+
+       avail_swap = swap_pager_avail - tmpfs_swap_reserved;
+       if (__predict_false(avail_swap <= 0)) {
+               /* FIXME No swap or disabled swap check */
+               if (swap_pager_avail == 0)
+                       avail_swap = 0;
+               else
+                       return (0);
+       }
+       avail_mem = cnt.v_free_count + cnt.v_cache_count - tmpfs_pages_reserved;
+       if (__predict_false(avail_mem < 0))
+               avail_mem = 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 = tmpfs_mem_avail();
+       if (avail < req_pages)
+               return (0);
+
+       if (tmp->tm_pages_max != SIZE_MAX)
+               avail = tmp->tm_pages_max - tmpfs_pages_used(tmp);
+               if (avail < req_pages)
+                       return (0);
+
+       return (1);
+}
+
 /* --------------------------------------------------------------------- */
 
 /*
@@ -99,6 +169,8 @@
 
        if (tmp->tm_nodes_inuse >= tmp->tm_nodes_max)
                return (ENOSPC);
+       if (tmpfs_pages_check_avail(tmp, 1) == 0)
+               return (ENOSPC);
 
        nnode = (struct tmpfs_node *)uma_zalloc_arg(
                                tmp->tm_node_pool, tmp, M_WAITOK);
@@ -917,7 +989,7 @@
        MPASS(oldpages == uobj->size);
        newpages = OFF_TO_IDX(newsize + PAGE_MASK);
        if (newpages > oldpages &&
-           newpages - oldpages > TMPFS_PAGES_AVAIL(tmp))
+           tmpfs_pages_check_avail(tmp, newpages - oldpages) == 0)
                return (ENOSPC);
 
        VM_OBJECT_LOCK(uobj);
Index: fs/tmpfs/tmpfs_vfsops.c
===================================================================
--- fs/tmpfs/tmpfs_vfsops.c     (revision 233868)
+++ fs/tmpfs/tmpfs_vfsops.c     (working copy)
@@ -90,6 +90,8 @@
        struct tmpfs_node *node = (struct tmpfs_node *)mem;
 
        node->tn_gen++;
+       if (node->tn_gen == 0)
+               node->tn_gen = (arc4random() / 2) + 1;
        node->tn_size = 0;
        node->tn_status = 0;
        node->tn_flags = 0;
@@ -114,7 +116,7 @@
        node->tn_id = 0;
 
        mtx_init(&node->tn_interlock, "tmpfs node interlock", NULL, MTX_DEF);
-       node->tn_gen = arc4random();
+       node->tn_gen = (arc4random() / 2) + 1;
 
        return (0);
 }
@@ -127,17 +129,59 @@
        mtx_destroy(&node->tn_interlock);
 }
 
+/*
+ * XXX Rename to vfs_getopt_size()
+ */
 static int
+tmpfs_getopt_size(struct vfsoptlist *opts, const char *name, u_quad_t *data)
+{
+       char *opt_value, *vtp;
+       quad_t  iv;
+       int error, opt_len;
+
+       error = vfs_getopt(opts, name, (void **)&opt_value, &opt_len);
+       if (error != 0)
+               return (error);
+       if (opt_len == 0 || opt_value == NULL)
+               return (EINVAL);
+       if (opt_value[0] == '\0' || opt_value[opt_len - 1] != '\0')
+               return (EINVAL);
+
+       iv = strtoq(opt_value, &vtp, 0);
+       if (vtp == opt_value || (vtp[0] != '\0' && vtp[1] != '\0'))
+               return (EINVAL);
+       if (iv < 0)
+               return (EINVAL);
+       switch (vtp[0]) {
+       case 't': case 'T':
+               iv *= 1024;
+       case 'g': case 'G':
+               iv *= 1024;
+       case 'm': case 'M':
+               iv *= 1024;
+       case 'k': case 'K':
+               iv *= 1024;
+       case '\0':
+               break;
+       default:
+               return (EINVAL);
+       }
+       *data = iv;
+
+       return (0);
+}
+
+static int
 tmpfs_mount(struct mount *mp)
 {
+       const size_t nodes_per_page = 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;
 
        /* Root node attributes. */
        uid_t root_uid;
@@ -173,17 +217,16 @@
        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", "%u", &nodes_max) != 1)
+       if (tmpfs_getopt_size(mp->mnt_optnew, "inodes", &nodes_max) != 0)
                nodes_max = 0;
-       if (vfs_scanopt(mp->mnt_optnew, "size", "%qu", &size_max) != 1)
+       if (tmpfs_getopt_size(mp->mnt_optnew, "size", &size_max) != 0)
                size_max = 0;
-       if (vfs_scanopt(mp->mnt_optnew, "maxfilesize", "%qu",
-           &maxfilesize) != 1)
+       if (tmpfs_getopt_size(mp->mnt_optnew, "maxfilesize", &maxfilesize) != 0)
                maxfilesize = 0;
 
        /* 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;
 
        /* Get the maximum number of memory pages this file system is
@@ -196,21 +239,27 @@
                pages = howmany(size_max, PAGE_SIZE);
        MPASS(pages > 0);
 
+       if (pages < SIZE_MAX / PAGE_SIZE)
+               size_max = pages * PAGE_SIZE;
+       else
+               size_max = SIZE_MAX;
+
        if (nodes_max <= 3) {
-               if (pages > UINT32_MAX - 3)
-                       nodes = UINT32_MAX;
+               if (pages < INT_MAX / nodes_per_page)
+                       nodes_max = pages * nodes_per_page;
                else
-                       nodes = pages + 3;
-       } else
-               nodes = nodes_max;
-       MPASS(nodes >= 3);
+                       nodes_max = INT_MAX;
+       }
+       if (nodes_max > INT_MAX)
+               nodes_max = INT_MAX;
+       MPASS(nodes_max >= 3);
 
        /* Allocate the tmpfs mount structure and fill it. */
        tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount),
            M_TMPFSMNT, M_WAITOK | M_ZERO);
 
        mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF);
-       tmp->tm_nodes_max = nodes;
+       tmp->tm_nodes_max = nodes_max;
        tmp->tm_nodes_inuse = 0;
        tmp->tm_maxfilesize = maxfilesize > 0 ? maxfilesize : UINT64_MAX;
        LIST_INIT(&tmp->tm_nodes_used);
@@ -355,16 +404,16 @@
        if (tfhp->tf_len != sizeof(struct tmpfs_fid))
                return EINVAL;
 
-       if (tfhp->tf_id >= tmp->tm_nodes_max)
+       if (tfhp->tf_id > INT_MAX || tfhp->tf_id <= 0)
                return EINVAL;
 
        found = FALSE;
 
        TMPFS_LOCK(tmp);
        LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
-               if (node->tn_id == tfhp->tf_id &&
-                   node->tn_gen == tfhp->tf_gen) {
-                       found = TRUE;
+               if (node->tn_id == tfhp->tf_id) {
+                       if (node->tn_gen == tfhp->tf_gen)
+                               found = TRUE;
                        break;
                }
        }
@@ -373,7 +422,7 @@
        if (found)
                return (tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp));
 
-       return (EINVAL);
+       return (ESTALE);
 }
 
 /* --------------------------------------------------------------------- */
@@ -382,22 +431,26 @@
 static int
 tmpfs_statfs(struct mount *mp, struct statfs *sbp)
 {
-       fsfilcnt_t freenodes;
        struct tmpfs_mount *tmp;
+       size_t used;
 
        tmp = VFS_TO_TMPFS(mp);
 
        sbp->f_iosize = PAGE_SIZE;
        sbp->f_bsize = PAGE_SIZE;
 
-       sbp->f_blocks = TMPFS_PAGES_MAX(tmp);
-       sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp);
-
-       freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_inuse,
-           TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
-
-       sbp->f_files = freenodes + tmp->tm_nodes_inuse;
-       sbp->f_ffree = freenodes;
+       used = tmpfs_pages_used(tmp);
+       if (tmp->tm_pages_max != SIZE_MAX)
+                sbp->f_blocks = tmp->tm_pages_max;
+       else
+                sbp->f_blocks = used + tmpfs_mem_avail();
+       if (sbp->f_blocks <= used)
+               sbp->f_bavail = 0;
+       else
+               sbp->f_bavail = sbp->f_blocks - used;
+       sbp->f_bfree = sbp->f_bavail;
+       sbp->f_files = tmp->tm_nodes_max;
+       sbp->f_ffree = tmp->tm_nodes_max - tmp->tm_nodes_inuse;
        /* sbp->f_owner = tmp->tn_uid; */
 
        return 0;
Index: conf/newvers.sh
===================================================================
--- conf/newvers.sh     (revision 233868)
+++ conf/newvers.sh     (working copy)
@@ -87,55 +87,25 @@
 v=`cat version` u=${USER:-root} d=`pwd` h=${HOSTNAME:-`hostname`} t=`date`
 i=`${MAKE:-make} -V KERN_IDENT`
 
-for dir in /bin /usr/bin /usr/local/bin; do
-       if [ -x "${dir}/svnversion" ] ; then
-               svnversion=${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="${dir}/git --git-dir=${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=`get_version_from_vcs`
 
-if [ -n "$svnversion" ] ; then
-       svn=`cd ${SYSDIR} && $svnversion`
-       case "$svn" in
-       [0-9]*) svn=" r${svn}" ;;
-       *)      unset svn ;;
-       esac
+if [ -n "$version_from_vcs" ]; then
+       version_from_vcs=" $version_from_vcs"
 fi
 
-if [ -n "$git_cmd" ] ; then
-       git=`$git_cmd rev-parse --verify --short HEAD 2>/dev/null`
-       svn=`$git_cmd svn find-rev $git 2>/dev/null`
-       if [ -n "$svn" ] ; then
-               svn=" r${svn}"
-               git="=${git}"
-       else
-               svn=`$git_cmd log | fgrep 'git-svn-id:' | head -1 | \
-                    sed -n 's/^.*@\([0-9][0-9]*\).*$/\1/p'`
-               if [ -n $svn ] ; then
-                       svn=" r${svn}"
-                       git="+${git}"
-               else
-                       git=" ${git}"
-               fi
-       fi
-       if $git_cmd --work-tree=${SYSDIR}/.. diff-index \
-           --name-only HEAD | read dummy; then
-               git="${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}"
 
 char sccs[sizeof(SCCSSTR) > 128 ? sizeof(SCCSSTR) : 128] = SCCSSTR;

Attachment: pgpSzrywILVSV.pgp
Description: PGP signature

Reply via email to