Print this page
    
7178 tmpfs incorrectly calculates amount of free space
Reviewed by: Alexander Stetsenko <astetsenko@racktopsystems.com>
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
          +++ new/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | ↓ open down ↓ | 13 lines elided | ↑ open up ↑ | 
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 2011, Joyent, Inc. All rights reserved.
       24 + * Copyright 2016 RackTop Systems.
  24   25   */
  25   26  
  26   27  #include <sys/types.h>
  27   28  #include <sys/param.h>
  28   29  #include <sys/sysmacros.h>
  29   30  #include <sys/kmem.h>
  30   31  #include <sys/time.h>
  31   32  #include <sys/pathname.h>
  32   33  #include <sys/vfs.h>
  33   34  #include <sys/vfs_opreg.h>
  34   35  #include <sys/vnode.h>
  35   36  #include <sys/stat.h>
  36   37  #include <sys/uio.h>
  37   38  #include <sys/stat.h>
  38   39  #include <sys/errno.h>
  39   40  #include <sys/cmn_err.h>
  40   41  #include <sys/cred.h>
  41   42  #include <sys/statvfs.h>
  42   43  #include <sys/mount.h>
  43   44  #include <sys/debug.h>
  44   45  #include <sys/systm.h>
  45   46  #include <sys/mntent.h>
  46   47  #include <fs/fs_subr.h>
  47   48  #include <vm/page.h>
  48   49  #include <vm/anon.h>
  49   50  #include <sys/model.h>
  50   51  #include <sys/policy.h>
  51   52  
  52   53  #include <sys/fs/swapnode.h>
  53   54  #include <sys/fs/tmp.h>
  54   55  #include <sys/fs/tmpnode.h>
  55   56  
  56   57  static int tmpfsfstype;
  57   58  
  58   59  /*
  59   60   * tmpfs vfs operations.
  60   61   */
  61   62  static int tmpfsinit(int, char *);
  62   63  static int tmp_mount(struct vfs *, struct vnode *,
  63   64          struct mounta *, struct cred *);
  64   65  static int tmp_unmount(struct vfs *, int, struct cred *);
  65   66  static int tmp_root(struct vfs *, struct vnode **);
  66   67  static int tmp_statvfs(struct vfs *, struct statvfs64 *);
  67   68  static int tmp_vget(struct vfs *, struct vnode **, struct fid *);
  68   69  
  69   70  /*
  70   71   * Loadable module wrapper
  71   72   */
  72   73  #include <sys/modctl.h>
  73   74  
  74   75  static mntopts_t tmpfs_proto_opttbl;
  75   76  
  76   77  static vfsdef_t vfw = {
  77   78          VFSDEF_VERSION,
  78   79          "tmpfs",
  79   80          tmpfsinit,
  80   81          VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_ZMOUNT,
  81   82          &tmpfs_proto_opttbl
  82   83  };
  83   84  
  84   85  /*
  85   86   * in-kernel mnttab options
  86   87   */
  87   88  static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL };
  88   89  static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL };
  89   90  
  90   91  static mntopt_t tmpfs_options[] = {
  91   92          /* Option name          Cancel Opt      Arg     Flags           Data */
  92   93          { MNTOPT_XATTR,         xattr_cancel,   NULL,   MO_DEFAULT,     NULL},
  93   94          { MNTOPT_NOXATTR,       noxattr_cancel, NULL,   NULL,           NULL},
  94   95          { "size",               NULL,           "0",    MO_HASVALUE,    NULL}
  95   96  };
  96   97  
  97   98  
  98   99  static mntopts_t tmpfs_proto_opttbl = {
  99  100          sizeof (tmpfs_options) / sizeof (mntopt_t),
 100  101          tmpfs_options
 101  102  };
 102  103  
 103  104  /*
 104  105   * Module linkage information
 105  106   */
 106  107  static struct modlfs modlfs = {
 107  108          &mod_fsops, "filesystem for tmpfs", &vfw
 108  109  };
 109  110  
 110  111  static struct modlinkage modlinkage = {
 111  112          MODREV_1, &modlfs, NULL
 112  113  };
 113  114  
 114  115  int
 115  116  _init()
 116  117  {
 117  118          return (mod_install(&modlinkage));
 118  119  }
 119  120  
 120  121  int
 121  122  _fini()
 122  123  {
 123  124          int error;
 124  125  
 125  126          error = mod_remove(&modlinkage);
 126  127          if (error)
 127  128                  return (error);
 128  129          /*
 129  130           * Tear down the operations vectors
 130  131           */
 131  132          (void) vfs_freevfsops_by_type(tmpfsfstype);
 132  133          vn_freevnodeops(tmp_vnodeops);
 133  134          return (0);
 134  135  }
 135  136  
 136  137  int
 137  138  _info(struct modinfo *modinfop)
 138  139  {
 139  140          return (mod_info(&modlinkage, modinfop));
 140  141  }
 141  142  
 142  143  /*
 143  144   * The following are patchable variables limiting the amount of system
 144  145   * resources tmpfs can use.
 145  146   *
 146  147   * tmpfs_maxkmem limits the amount of kernel kmem_alloc memory
 147  148   * tmpfs can use for it's data structures (e.g. tmpnodes, directory entries)
 148  149   * It is not determined by setting a hard limit but rather as a percentage of
 149  150   * physical memory which is determined when tmpfs is first used in the system.
 150  151   *
 151  152   * tmpfs_minfree is the minimum amount of swap space that tmpfs leaves for
 152  153   * the rest of the system.  In other words, if the amount of free swap space
 153  154   * in the system (i.e. anoninfo.ani_free) drops below tmpfs_minfree, tmpfs
 154  155   * anon allocations will fail.
 155  156   *
 156  157   * There is also a per mount limit on the amount of swap space
 157  158   * (tmount.tm_anonmax) settable via a mount option.
 158  159   */
 159  160  size_t tmpfs_maxkmem = 0;
 160  161  size_t tmpfs_minfree = 0;
 161  162  size_t tmp_kmemspace;           /* bytes of kernel heap used by all tmpfs */
 162  163  
 163  164  static major_t tmpfs_major;
 164  165  static minor_t tmpfs_minor;
 165  166  static kmutex_t tmpfs_minor_lock;
 166  167  
 167  168  /*
 168  169   * initialize global tmpfs locks and such
 169  170   * called when loading tmpfs module
 170  171   */
 171  172  static int
 172  173  tmpfsinit(int fstype, char *name)
 173  174  {
 174  175          static const fs_operation_def_t tmp_vfsops_template[] = {
 175  176                  VFSNAME_MOUNT,          { .vfs_mount = tmp_mount },
 176  177                  VFSNAME_UNMOUNT,        { .vfs_unmount = tmp_unmount },
 177  178                  VFSNAME_ROOT,           { .vfs_root = tmp_root },
 178  179                  VFSNAME_STATVFS,        { .vfs_statvfs = tmp_statvfs },
 179  180                  VFSNAME_VGET,           { .vfs_vget = tmp_vget },
 180  181                  NULL,                   NULL
 181  182          };
 182  183          int error;
 183  184          extern  void    tmpfs_hash_init();
 184  185  
 185  186          tmpfs_hash_init();
 186  187          tmpfsfstype = fstype;
 187  188          ASSERT(tmpfsfstype != 0);
 188  189  
 189  190          error = vfs_setfsops(fstype, tmp_vfsops_template, NULL);
 190  191          if (error != 0) {
 191  192                  cmn_err(CE_WARN, "tmpfsinit: bad vfs ops template");
 192  193                  return (error);
 193  194          }
 194  195  
 195  196          error = vn_make_ops(name, tmp_vnodeops_template, &tmp_vnodeops);
 196  197          if (error != 0) {
 197  198                  (void) vfs_freevfsops_by_type(fstype);
 198  199                  cmn_err(CE_WARN, "tmpfsinit: bad vnode ops template");
 199  200                  return (error);
 200  201          }
 201  202  
 202  203          /*
 203  204           * tmpfs_minfree doesn't need to be some function of configured
 204  205           * swap space since it really is an absolute limit of swap space
 205  206           * which still allows other processes to execute.
 206  207           */
 207  208          if (tmpfs_minfree == 0) {
 208  209                  /*
 209  210                   * Set if not patched
 210  211                   */
 211  212                  tmpfs_minfree = btopr(TMPMINFREE);
 212  213          }
 213  214  
 214  215          /*
 215  216           * The maximum amount of space tmpfs can allocate is
 216  217           * TMPMAXPROCKMEM percent of kernel memory
 217  218           */
 218  219          if (tmpfs_maxkmem == 0)
 219  220                  tmpfs_maxkmem = MAX(PAGESIZE, kmem_maxavail() / TMPMAXFRACKMEM);
 220  221  
 221  222          if ((tmpfs_major = getudev()) == (major_t)-1) {
 222  223                  cmn_err(CE_WARN, "tmpfsinit: Can't get unique device number.");
 223  224                  tmpfs_major = 0;
 224  225          }
 225  226          mutex_init(&tmpfs_minor_lock, NULL, MUTEX_DEFAULT, NULL);
 226  227          return (0);
 227  228  }
 228  229  
 229  230  static int
 230  231  tmp_mount(
 231  232          struct vfs *vfsp,
 232  233          struct vnode *mvp,
 233  234          struct mounta *uap,
 234  235          struct cred *cr)
 235  236  {
 236  237          struct tmount *tm = NULL;
 237  238          struct tmpnode *tp;
 238  239          struct pathname dpn;
 239  240          int error;
 240  241          pgcnt_t anonmax;
 241  242          struct vattr rattr;
 242  243          int got_attrs;
 243  244  
 244  245          char *sizestr;
 245  246  
 246  247          if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 247  248                  return (error);
 248  249  
 249  250          if (mvp->v_type != VDIR)
 250  251                  return (ENOTDIR);
 251  252  
 252  253          mutex_enter(&mvp->v_lock);
 253  254          if ((uap->flags & MS_REMOUNT) == 0 && (uap->flags & MS_OVERLAY) == 0 &&
 254  255              (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
 255  256                  mutex_exit(&mvp->v_lock);
 256  257                  return (EBUSY);
 257  258          }
 258  259          mutex_exit(&mvp->v_lock);
 259  260  
 260  261          /*
 261  262           * Having the resource be anything but "swap" doesn't make sense.
 262  263           */
 263  264          vfs_setresource(vfsp, "swap", 0);
 264  265  
 265  266          /*
 266  267           * now look for options we understand...
 267  268           */
 268  269  
 269  270          /* tmpfs doesn't support read-only mounts */
 270  271          if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) {
 271  272                  error = EINVAL;
 272  273                  goto out;
 273  274          }
 274  275  
 275  276          /*
 276  277           * tm_anonmax is set according to the mount arguments
 277  278           * if any.  Otherwise, it is set to a maximum value.
 278  279           */
 279  280          if (vfs_optionisset(vfsp, "size", &sizestr)) {
 280  281                  if ((error = tmp_convnum(sizestr, &anonmax)) != 0)
 281  282                          goto out;
 282  283          } else {
 283  284                  anonmax = ULONG_MAX;
 284  285          }
 285  286  
 286  287          if (error = pn_get(uap->dir,
 287  288              (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn))
 288  289                  goto out;
 289  290  
 290  291          if (uap->flags & MS_REMOUNT) {
 291  292                  tm = (struct tmount *)VFSTOTM(vfsp);
 292  293  
 293  294                  /*
 294  295                   * If we change the size so its less than what is currently
 295  296                   * being used, we allow that. The file system will simply be
 296  297                   * full until enough files have been removed to get below the
 297  298                   * new max.
 298  299                   */
 299  300                  mutex_enter(&tm->tm_contents);
 300  301                  tm->tm_anonmax = anonmax;
 301  302                  mutex_exit(&tm->tm_contents);
 302  303                  goto out;
 303  304          }
 304  305  
 305  306          if ((tm = tmp_memalloc(sizeof (struct tmount), 0)) == NULL) {
 306  307                  pn_free(&dpn);
 307  308                  error = ENOMEM;
 308  309                  goto out;
 309  310          }
 310  311  
 311  312          /*
 312  313           * find an available minor device number for this mount
 313  314           */
 314  315          mutex_enter(&tmpfs_minor_lock);
 315  316          do {
 316  317                  tmpfs_minor = (tmpfs_minor + 1) & L_MAXMIN32;
 317  318                  tm->tm_dev = makedevice(tmpfs_major, tmpfs_minor);
 318  319          } while (vfs_devismounted(tm->tm_dev));
 319  320          mutex_exit(&tmpfs_minor_lock);
 320  321  
 321  322          /*
 322  323           * Set but don't bother entering the mutex
 323  324           * (tmount not on mount list yet)
 324  325           */
 325  326          mutex_init(&tm->tm_contents, NULL, MUTEX_DEFAULT, NULL);
 326  327          mutex_init(&tm->tm_renamelck, NULL, MUTEX_DEFAULT, NULL);
 327  328  
 328  329          tm->tm_vfsp = vfsp;
 329  330          tm->tm_anonmax = anonmax;
 330  331  
 331  332          vfsp->vfs_data = (caddr_t)tm;
 332  333          vfsp->vfs_fstype = tmpfsfstype;
 333  334          vfsp->vfs_dev = tm->tm_dev;
 334  335          vfsp->vfs_bsize = PAGESIZE;
 335  336          vfsp->vfs_flag |= VFS_NOTRUNC;
 336  337          vfs_make_fsid(&vfsp->vfs_fsid, tm->tm_dev, tmpfsfstype);
 337  338          tm->tm_mntpath = tmp_memalloc(dpn.pn_pathlen + 1, TMP_MUSTHAVE);
 338  339          (void) strcpy(tm->tm_mntpath, dpn.pn_path);
 339  340  
 340  341          /*
 341  342           * allocate and initialize root tmpnode structure
 342  343           */
 343  344          bzero(&rattr, sizeof (struct vattr));
 344  345          rattr.va_mode = (mode_t)(S_IFDIR | 0777);       /* XXX modes */
 345  346          rattr.va_type = VDIR;
 346  347          rattr.va_rdev = 0;
 347  348          tp = tmp_memalloc(sizeof (struct tmpnode), TMP_MUSTHAVE);
 348  349          tmpnode_init(tm, tp, &rattr, cr);
 349  350  
 350  351          /*
 351  352           * Get the mode, uid, and gid from the underlying mount point.
 352  353           */
 353  354          rattr.va_mask = AT_MODE|AT_UID|AT_GID;  /* Hint to getattr */
 354  355          got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr, NULL);
 355  356  
 356  357          rw_enter(&tp->tn_rwlock, RW_WRITER);
 357  358          TNTOV(tp)->v_flag |= VROOT;
 358  359  
 359  360          /*
 360  361           * If the getattr succeeded, use its results.  Otherwise allow
 361  362           * the previously set hardwired defaults to prevail.
 362  363           */
 363  364          if (got_attrs == 0) {
 364  365                  tp->tn_mode = rattr.va_mode;
 365  366                  tp->tn_uid = rattr.va_uid;
 366  367                  tp->tn_gid = rattr.va_gid;
 367  368          }
 368  369  
 369  370          /*
 370  371           * initialize linked list of tmpnodes so that the back pointer of
 371  372           * the root tmpnode always points to the last one on the list
 372  373           * and the forward pointer of the last node is null
 373  374           */
 374  375          tp->tn_back = tp;
 375  376          tp->tn_forw = NULL;
 376  377          tp->tn_nlink = 0;
 377  378          tm->tm_rootnode = tp;
 378  379  
 379  380          tdirinit(tp, tp);
 380  381  
 381  382          rw_exit(&tp->tn_rwlock);
 382  383  
 383  384          pn_free(&dpn);
 384  385          error = 0;
 385  386  
 386  387  out:
 387  388          if (error == 0)
 388  389                  vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS);
 389  390  
 390  391          return (error);
 391  392  }
 392  393  
 393  394  static int
 394  395  tmp_unmount(struct vfs *vfsp, int flag, struct cred *cr)
 395  396  {
 396  397          struct tmount *tm = (struct tmount *)VFSTOTM(vfsp);
 397  398          struct tmpnode *tnp, *cancel;
 398  399          struct vnode    *vp;
 399  400          int error;
 400  401  
 401  402          if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
 402  403                  return (error);
 403  404  
 404  405          /*
 405  406           * forced unmount is not supported by this file system
 406  407           * and thus, ENOTSUP, is being returned.
 407  408           */
 408  409          if (flag & MS_FORCE)
 409  410                  return (ENOTSUP);
 410  411  
 411  412          mutex_enter(&tm->tm_contents);
 412  413  
 413  414          /*
 414  415           * If there are no open files, only the root node should have
 415  416           * a reference count.
 416  417           * With tm_contents held, nothing can be added or removed.
 417  418           * There may be some dirty pages.  To prevent fsflush from
 418  419           * disrupting the unmount, put a hold on each node while scanning.
 419  420           * If we find a previously referenced node, undo the holds we have
 420  421           * placed and fail EBUSY.
 421  422           */
 422  423          tnp = tm->tm_rootnode;
 423  424          if (TNTOV(tnp)->v_count > 1) {
 424  425                  mutex_exit(&tm->tm_contents);
 425  426                  return (EBUSY);
 426  427          }
 427  428  
 428  429          for (tnp = tnp->tn_forw; tnp; tnp = tnp->tn_forw) {
 429  430                  if ((vp = TNTOV(tnp))->v_count > 0) {
 430  431                          cancel = tm->tm_rootnode->tn_forw;
 431  432                          while (cancel != tnp) {
 432  433                                  vp = TNTOV(cancel);
 433  434                                  ASSERT(vp->v_count > 0);
 434  435                                  VN_RELE(vp);
 435  436                                  cancel = cancel->tn_forw;
 436  437                          }
 437  438                          mutex_exit(&tm->tm_contents);
 438  439                          return (EBUSY);
 439  440                  }
 440  441                  VN_HOLD(vp);
 441  442          }
 442  443  
 443  444          /*
 444  445           * We can drop the mutex now because no one can find this mount
 445  446           */
 446  447          mutex_exit(&tm->tm_contents);
 447  448  
 448  449          /*
 449  450           * Free all kmemalloc'd and anonalloc'd memory associated with
 450  451           * this filesystem.  To do this, we go through the file list twice,
 451  452           * once to remove all the directory entries, and then to remove
 452  453           * all the files.  We do this because there is useful code in
 453  454           * tmpnode_free which assumes that the directory entry has been
 454  455           * removed before the file.
 455  456           */
 456  457          /*
 457  458           * Remove all directory entries
 458  459           */
 459  460          for (tnp = tm->tm_rootnode; tnp; tnp = tnp->tn_forw) {
 460  461                  rw_enter(&tnp->tn_rwlock, RW_WRITER);
 461  462                  if (tnp->tn_type == VDIR)
 462  463                          tdirtrunc(tnp);
 463  464                  if (tnp->tn_vnode->v_flag & V_XATTRDIR) {
 464  465                          /*
 465  466                           * Account for implicit attrdir reference.
 466  467                           */
 467  468                          ASSERT(tnp->tn_nlink > 0);
 468  469                          DECR_COUNT(&tnp->tn_nlink, &tnp->tn_tlock);
 469  470                  }
 470  471                  rw_exit(&tnp->tn_rwlock);
 471  472          }
 472  473  
 473  474          ASSERT(tm->tm_rootnode);
 474  475  
 475  476          /*
 476  477           * All links are gone, v_count is keeping nodes in place.
 477  478           * VN_RELE should make the node disappear, unless somebody
 478  479           * is holding pages against it.  Nap and retry until it disappears.
 479  480           *
 480  481           * We re-acquire the lock to prevent others who have a HOLD on
 481  482           * a tmpnode via its pages or anon slots from blowing it away
 482  483           * (in tmp_inactive) while we're trying to get to it here. Once
 483  484           * we have a HOLD on it we know it'll stick around.
 484  485           *
 485  486           */
 486  487          mutex_enter(&tm->tm_contents);
 487  488          /*
 488  489           * Remove all the files (except the rootnode) backwards.
 489  490           */
 490  491          while ((tnp = tm->tm_rootnode->tn_back) != tm->tm_rootnode) {
 491  492                  mutex_exit(&tm->tm_contents);
 492  493                  /*
 493  494                   * Inhibit tmp_inactive from touching attribute directory
 494  495                   * as all nodes will be released here.
 495  496                   * Note we handled the link count in pass 2 above.
 496  497                   */
 497  498                  rw_enter(&tnp->tn_rwlock, RW_WRITER);
 498  499                  tnp->tn_xattrdp = NULL;
 499  500                  rw_exit(&tnp->tn_rwlock);
 500  501                  vp = TNTOV(tnp);
 501  502                  VN_RELE(vp);
 502  503                  mutex_enter(&tm->tm_contents);
 503  504                  /*
 504  505                   * It's still there after the RELE. Someone else like pageout
 505  506                   * has a hold on it so wait a bit and then try again - we know
 506  507                   * they'll give it up soon.
 507  508                   */
 508  509                  if (tnp == tm->tm_rootnode->tn_back) {
 509  510                          VN_HOLD(vp);
 510  511                          mutex_exit(&tm->tm_contents);
 511  512                          delay(hz / 4);
 512  513                          mutex_enter(&tm->tm_contents);
 513  514                  }
 514  515          }
 515  516          mutex_exit(&tm->tm_contents);
 516  517  
 517  518          tm->tm_rootnode->tn_xattrdp = NULL;
 518  519          VN_RELE(TNTOV(tm->tm_rootnode));
 519  520  
 520  521          ASSERT(tm->tm_mntpath);
 521  522  
 522  523          tmp_memfree(tm->tm_mntpath, strlen(tm->tm_mntpath) + 1);
 523  524  
 524  525          ASSERT(tm->tm_anonmem == 0);
 525  526  
 526  527          mutex_destroy(&tm->tm_contents);
 527  528          mutex_destroy(&tm->tm_renamelck);
 528  529          tmp_memfree(tm, sizeof (struct tmount));
 529  530  
 530  531          return (0);
 531  532  }
 532  533  
 533  534  /*
 534  535   * return root tmpnode for given vnode
 535  536   */
 536  537  static int
 537  538  tmp_root(struct vfs *vfsp, struct vnode **vpp)
 538  539  {
 539  540          struct tmount *tm = (struct tmount *)VFSTOTM(vfsp);
 540  541          struct tmpnode *tp = tm->tm_rootnode;
 541  542          struct vnode *vp;
 542  543  
 543  544          ASSERT(tp);
 544  545  
 545  546          vp = TNTOV(tp);
 546  547          VN_HOLD(vp);
 547  548          *vpp = vp;
 548  549          return (0);
 549  550  }
 550  551  
 551  552  static int
 552  553  tmp_statvfs(struct vfs *vfsp, struct statvfs64 *sbp)
 553  554  {
 554  555          struct tmount   *tm = (struct tmount *)VFSTOTM(vfsp);
 555  556          ulong_t blocks;
 556  557          dev32_t d32;
 557  558          zoneid_t eff_zid;
 558  559          struct zone *zp;
 559  560  
 560  561          /*
 561  562           * The file system may have been mounted by the global zone on
 562  563           * behalf of the non-global zone.  In that case, the tmount zone_id
 563  564           * will be the global zone.  We still want to show the swap cap inside
 564  565           * the zone in this case, even though the file system was mounted by
 565  566           * the global zone.
 566  567           */
 567  568          if (curproc->p_zone->zone_id != GLOBAL_ZONEUNIQID)
 568  569                  zp = curproc->p_zone;
 569  570          else
 570  571                  zp = tm->tm_vfsp->vfs_zone;
 571  572  
 572  573          if (zp == NULL)
 573  574                  eff_zid = GLOBAL_ZONEUNIQID;
 574  575          else
 575  576                  eff_zid = zp->zone_id;
 576  577  
 577  578          sbp->f_bsize = PAGESIZE;
 578  579          sbp->f_frsize = PAGESIZE;
  
    | ↓ open down ↓ | 545 lines elided | ↑ open up ↑ | 
 579  580  
 580  581          /*
 581  582           * Find the amount of available physical and memory swap
 582  583           */
 583  584          mutex_enter(&anoninfo_lock);
 584  585          ASSERT(k_anoninfo.ani_max >= k_anoninfo.ani_phys_resv);
 585  586          blocks = (ulong_t)CURRENT_TOTAL_AVAILABLE_SWAP;
 586  587          mutex_exit(&anoninfo_lock);
 587  588  
 588  589          /*
 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)
      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)
 593  597                  sbp->f_bfree = MIN(blocks - tmpfs_minfree,
 594  598                      tm->tm_anonmax - tm->tm_anonmem);
 595  599          else
 596  600                  sbp->f_bfree = 0;
 597  601  
 598  602          sbp->f_bavail = sbp->f_bfree;
 599  603  
 600  604          /*
 601  605           * Total number of blocks is what's available plus what's been used
 602  606           */
 603  607          sbp->f_blocks = (fsblkcnt64_t)(sbp->f_bfree + tm->tm_anonmem);
 604  608  
 605  609          if (eff_zid != GLOBAL_ZONEUNIQID &&
 606  610              zp->zone_max_swap_ctl != UINT64_MAX) {
 607  611                  /*
 608  612                   * If the fs is used by a non-global zone with a swap cap,
 609  613                   * then report the capped size.
 610  614                   */
 611  615                  rctl_qty_t cap, used;
 612  616                  pgcnt_t pgcap, pgused;
 613  617  
 614  618                  mutex_enter(&zp->zone_mem_lock);
 615  619                  cap = zp->zone_max_swap_ctl;
 616  620                  used = zp->zone_max_swap;
 617  621                  mutex_exit(&zp->zone_mem_lock);
 618  622  
  
    | ↓ open down ↓ | 16 lines elided | ↑ open up ↑ | 
 619  623                  pgcap = btop(cap);
 620  624                  pgused = btop(used);
 621  625  
 622  626                  sbp->f_bfree = MIN(pgcap - pgused, sbp->f_bfree);
 623  627                  sbp->f_bavail = sbp->f_bfree;
 624  628                  sbp->f_blocks = MIN(pgcap, sbp->f_blocks);
 625  629          }
 626  630  
 627  631          /*
 628  632           * 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 /
      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  640              (sizeof (struct tmpnode) + sizeof (struct tdirent));
 641  641          sbp->f_favail = (fsfilcnt64_t)(sbp->f_ffree);
 642  642          (void) cmpldev(&d32, vfsp->vfs_dev);
 643  643          sbp->f_fsid = d32;
 644  644          (void) strcpy(sbp->f_basetype, vfssw[tmpfsfstype].vsw_name);
 645  645          (void) strncpy(sbp->f_fstr, tm->tm_mntpath, sizeof (sbp->f_fstr));
 646  646          /*
 647  647           * ensure null termination
 648  648           */
 649  649          sbp->f_fstr[sizeof (sbp->f_fstr) - 1] = '\0';
 650  650          sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
 651  651          sbp->f_namemax = MAXNAMELEN - 1;
 652  652          return (0);
 653  653  }
 654  654  
 655  655  static int
 656  656  tmp_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp)
 657  657  {
 658  658          struct tfid *tfid;
 659  659          struct tmount *tm = (struct tmount *)VFSTOTM(vfsp);
 660  660          struct tmpnode *tp = NULL;
 661  661  
 662  662          tfid = (struct tfid *)fidp;
 663  663          *vpp = NULL;
 664  664  
 665  665          mutex_enter(&tm->tm_contents);
 666  666          for (tp = tm->tm_rootnode; tp; tp = tp->tn_forw) {
 667  667                  mutex_enter(&tp->tn_tlock);
 668  668                  if (tp->tn_nodeid == tfid->tfid_ino) {
 669  669                          /*
 670  670                           * If the gen numbers don't match we know the
 671  671                           * file won't be found since only one tmpnode
 672  672                           * can have this number at a time.
 673  673                           */
 674  674                          if (tp->tn_gen != tfid->tfid_gen || tp->tn_nlink == 0) {
 675  675                                  mutex_exit(&tp->tn_tlock);
 676  676                                  mutex_exit(&tm->tm_contents);
 677  677                                  return (0);
 678  678                          }
 679  679                          *vpp = (struct vnode *)TNTOV(tp);
 680  680  
 681  681                          VN_HOLD(*vpp);
 682  682  
 683  683                          if ((tp->tn_mode & S_ISVTX) &&
 684  684                              !(tp->tn_mode & (S_IXUSR | S_IFDIR))) {
 685  685                                  mutex_enter(&(*vpp)->v_lock);
 686  686                                  (*vpp)->v_flag |= VISSWAP;
 687  687                                  mutex_exit(&(*vpp)->v_lock);
 688  688                          }
 689  689                          mutex_exit(&tp->tn_tlock);
 690  690                          mutex_exit(&tm->tm_contents);
 691  691                          return (0);
 692  692                  }
 693  693                  mutex_exit(&tp->tn_tlock);
 694  694          }
 695  695          mutex_exit(&tm->tm_contents);
 696  696          return (0);
 697  697  }
  
    | ↓ open down ↓ | 48 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX