Print this page
7178 tmpfs incorrectly calculates amount of free space
Reviewed by: Alexander Stetsenko <astetsenko@racktopsystems.com>


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2011, Joyent, Inc. All rights reserved.

  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/param.h>
  28 #include <sys/sysmacros.h>
  29 #include <sys/kmem.h>
  30 #include <sys/time.h>
  31 #include <sys/pathname.h>
  32 #include <sys/vfs.h>
  33 #include <sys/vfs_opreg.h>
  34 #include <sys/vnode.h>
  35 #include <sys/stat.h>
  36 #include <sys/uio.h>
  37 #include <sys/stat.h>
  38 #include <sys/errno.h>
  39 #include <sys/cmn_err.h>
  40 #include <sys/cred.h>
  41 #include <sys/statvfs.h>
  42 #include <sys/mount.h>
  43 #include <sys/debug.h>


 569         else
 570                 zp = tm->tm_vfsp->vfs_zone;
 571 
 572         if (zp == NULL)
 573                 eff_zid = GLOBAL_ZONEUNIQID;
 574         else
 575                 eff_zid = zp->zone_id;
 576 
 577         sbp->f_bsize = PAGESIZE;
 578         sbp->f_frsize = PAGESIZE;
 579 
 580         /*
 581          * Find the amount of available physical and memory swap
 582          */
 583         mutex_enter(&anoninfo_lock);
 584         ASSERT(k_anoninfo.ani_max >= k_anoninfo.ani_phys_resv);
 585         blocks = (ulong_t)CURRENT_TOTAL_AVAILABLE_SWAP;
 586         mutex_exit(&anoninfo_lock);
 587 
 588         /*
 589          * If tm_anonmax for this mount is less than the available swap space
 590          * (minus the amount tmpfs can't use), use that instead
 591          */
 592         if (blocks > tmpfs_minfree)



 593                 sbp->f_bfree = MIN(blocks - tmpfs_minfree,
 594                     tm->tm_anonmax - tm->tm_anonmem);
 595         else
 596                 sbp->f_bfree = 0;
 597 
 598         sbp->f_bavail = sbp->f_bfree;
 599 
 600         /*
 601          * Total number of blocks is what's available plus what's been used
 602          */
 603         sbp->f_blocks = (fsblkcnt64_t)(sbp->f_bfree + tm->tm_anonmem);
 604 
 605         if (eff_zid != GLOBAL_ZONEUNIQID &&
 606             zp->zone_max_swap_ctl != UINT64_MAX) {
 607                 /*
 608                  * If the fs is used by a non-global zone with a swap cap,
 609                  * then report the capped size.
 610                  */
 611                 rctl_qty_t cap, used;
 612                 pgcnt_t pgcap, pgused;
 613 
 614                 mutex_enter(&zp->zone_mem_lock);
 615                 cap = zp->zone_max_swap_ctl;
 616                 used = zp->zone_max_swap;
 617                 mutex_exit(&zp->zone_mem_lock);
 618 
 619                 pgcap = btop(cap);
 620                 pgused = btop(used);
 621 
 622                 sbp->f_bfree = MIN(pgcap - pgused, sbp->f_bfree);
 623                 sbp->f_bavail = sbp->f_bfree;
 624                 sbp->f_blocks = MIN(pgcap, sbp->f_blocks);
 625         }
 626 
 627         /*
 628          * The maximum number of files available is approximately the number
 629          * of tmpnodes we can allocate from the remaining kernel memory
 630          * available to tmpfs.  This is fairly inaccurate since it doesn't
 631          * take into account the names stored in the directory entries.
 632          */
 633         if (tmpfs_maxkmem > tmp_kmemspace)
 634                 sbp->f_ffree = (tmpfs_maxkmem - tmp_kmemspace) /
 635                     (sizeof (struct tmpnode) + sizeof (struct tdirent));
 636         else
 637                 sbp->f_ffree = 0;
 638 
 639         sbp->f_files = tmpfs_maxkmem /
 640             (sizeof (struct tmpnode) + sizeof (struct tdirent));
 641         sbp->f_favail = (fsfilcnt64_t)(sbp->f_ffree);
 642         (void) cmpldev(&d32, vfsp->vfs_dev);
 643         sbp->f_fsid = d32;
 644         (void) strcpy(sbp->f_basetype, vfssw[tmpfsfstype].vsw_name);
 645         (void) strncpy(sbp->f_fstr, tm->tm_mntpath, sizeof (sbp->f_fstr));
 646         /*
 647          * ensure null termination
 648          */
 649         sbp->f_fstr[sizeof (sbp->f_fstr) - 1] = '\0';
 650         sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
 651         sbp->f_namemax = MAXNAMELEN - 1;
 652         return (0);
 653 }
 654 
 655 static int
 656 tmp_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp)
 657 {
 658         struct tfid *tfid;
 659         struct tmount *tm = (struct tmount *)VFSTOTM(vfsp);




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
  24  * Copyright 2016 RackTop Systems.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/param.h>
  29 #include <sys/sysmacros.h>
  30 #include <sys/kmem.h>
  31 #include <sys/time.h>
  32 #include <sys/pathname.h>
  33 #include <sys/vfs.h>
  34 #include <sys/vfs_opreg.h>
  35 #include <sys/vnode.h>
  36 #include <sys/stat.h>
  37 #include <sys/uio.h>
  38 #include <sys/stat.h>
  39 #include <sys/errno.h>
  40 #include <sys/cmn_err.h>
  41 #include <sys/cred.h>
  42 #include <sys/statvfs.h>
  43 #include <sys/mount.h>
  44 #include <sys/debug.h>


 570         else
 571                 zp = tm->tm_vfsp->vfs_zone;
 572 
 573         if (zp == NULL)
 574                 eff_zid = GLOBAL_ZONEUNIQID;
 575         else
 576                 eff_zid = zp->zone_id;
 577 
 578         sbp->f_bsize = PAGESIZE;
 579         sbp->f_frsize = PAGESIZE;
 580 
 581         /*
 582          * Find the amount of available physical and memory swap
 583          */
 584         mutex_enter(&anoninfo_lock);
 585         ASSERT(k_anoninfo.ani_max >= k_anoninfo.ani_phys_resv);
 586         blocks = (ulong_t)CURRENT_TOTAL_AVAILABLE_SWAP;
 587         mutex_exit(&anoninfo_lock);
 588 
 589         /*
 590          * Compare the amount of space that should be free to this mount
 591          * (which may be limited by tm_anonmax) with the amount of space
 592          * that's actually free to all tmpfs and use the lowest value.
 593          */
 594         if (tm->tm_anonmax == ULONG_MAX)
 595                 sbp->f_bfree = MAX(blocks - tmpfs_minfree, 0);
 596         else if (blocks > tmpfs_minfree && tm->tm_anonmax > tm->tm_anonmem)
 597                 sbp->f_bfree = MIN(blocks - tmpfs_minfree,
 598                     tm->tm_anonmax - tm->tm_anonmem);
 599         else
 600                 sbp->f_bfree = 0;
 601 
 602         sbp->f_bavail = sbp->f_bfree;
 603 
 604         /*
 605          * Total number of blocks is what's available plus what's been used
 606          */
 607         sbp->f_blocks = (fsblkcnt64_t)(sbp->f_bfree + tm->tm_anonmem);
 608 
 609         if (eff_zid != GLOBAL_ZONEUNIQID &&
 610             zp->zone_max_swap_ctl != UINT64_MAX) {
 611                 /*
 612                  * If the fs is used by a non-global zone with a swap cap,
 613                  * then report the capped size.
 614                  */
 615                 rctl_qty_t cap, used;
 616                 pgcnt_t pgcap, pgused;
 617 
 618                 mutex_enter(&zp->zone_mem_lock);
 619                 cap = zp->zone_max_swap_ctl;
 620                 used = zp->zone_max_swap;
 621                 mutex_exit(&zp->zone_mem_lock);
 622 
 623                 pgcap = btop(cap);
 624                 pgused = btop(used);
 625 
 626                 sbp->f_bfree = MIN(pgcap - pgused, sbp->f_bfree);
 627                 sbp->f_bavail = sbp->f_bfree;
 628                 sbp->f_blocks = MIN(pgcap, sbp->f_blocks);
 629         }
 630 
 631         /*
 632          * The maximum number of files available is approximately the number
 633          * of tmpnodes we can allocate from the number of blocks available
 634          * to this mount.  This is fairly inaccurate since it doesn't take
 635          * into account the names stored in the directory entries.
 636          */
 637         sbp->f_ffree = sbp->f_bfree == 0 ? 0 : sbp->f_bfree /

 638             (sizeof (struct tmpnode) + sizeof (struct tdirent));
 639         sbp->f_files = sbp->f_blocks == 0 ? 0 : sbp->f_blocks /



 640             (sizeof (struct tmpnode) + sizeof (struct tdirent));
 641         sbp->f_favail = (fsfilcnt64_t)(sbp->f_ffree);
 642         (void) cmpldev(&d32, vfsp->vfs_dev);
 643         sbp->f_fsid = d32;
 644         (void) strcpy(sbp->f_basetype, vfssw[tmpfsfstype].vsw_name);
 645         (void) strncpy(sbp->f_fstr, tm->tm_mntpath, sizeof (sbp->f_fstr));
 646         /*
 647          * ensure null termination
 648          */
 649         sbp->f_fstr[sizeof (sbp->f_fstr) - 1] = '\0';
 650         sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
 651         sbp->f_namemax = MAXNAMELEN - 1;
 652         return (0);
 653 }
 654 
 655 static int
 656 tmp_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp)
 657 {
 658         struct tfid *tfid;
 659         struct tmount *tm = (struct tmount *)VFSTOTM(vfsp);