Print this page
    
5513 KM_NORMALPRI should be documented in kmem_alloc(9f) and kmem_cache_create(9f) man pages
14465 Present KM_NOSLEEP_LAZY as documented interface
Change-Id: I002ec28ddf390650f1fcba1ca94f6abfdb241439
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c
          +++ new/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c
   1    1  /*
   2    2   * This file and its contents are supplied under the terms of the
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13   13   * Copyright (c) 2015 Joyent, Inc.
  14   14   */
  15   15  
  16   16  #include <sys/errno.h>
  17   17  #include <sys/modctl.h>
  18   18  #include <sys/types.h>
  19   19  #include <sys/mkdev.h>
  20   20  #include <sys/ddi.h>
  21   21  #include <sys/sunddi.h>
  22   22  #include <sys/vfs.h>
  23   23  #include <sys/vfs_opreg.h>
  24   24  #include <sys/systm.h>
  25   25  #include <sys/id_space.h>
  26   26  #include <sys/cmn_err.h>
  27   27  #include <sys/ksynch.h>
  28   28  #include <sys/policy.h>
  29   29  #include <sys/mount.h>
  30   30  #include <sys/sysmacros.h>
  31   31  
  32   32  #include <sys/fs/bootfs_impl.h>
  33   33  
  34   34  /*
  35   35   * While booting, additional types of modules and files can be passed in to the
  36   36   * loader. These include the familiar boot archive, as well as, a module hash
  37   37   * and additional modules that are interpreted as files. As part of the handoff
  38   38   * in early boot, information about these modules are saved as properties on the
  39   39   * root of the devinfo tree, similar to other boot-time properties.
  40   40   *
  41   41   * This file system provides a read-only view of those additional files. Due to
  42   42   * its limited scope, it has a slightly simpler construction than several other
  43   43   * file systems. When mounted, it looks for the corresponding properties and
  44   44   * creates bootfs_node_t's and vnodes for all of the corresponding files and
  45   45   * directories that exist along the way. At this time, there are currently a
  46   46   * rather small number of files passed in this way.
  47   47   *
  48   48   * This does lead to one behavior that folks used to other file systems might
  49   49   * find peculiar. Because we are not always actively creating and destroying the
  50   50   * required vnodes on demand, the count on the root vnode will not be going up
  51   51   * accordingly with the existence of other vnodes. This means that a bootfs file
  52   52   * system that is not in use will have all of its vnodes exist with a v_count of
  53   53   * one.
  54   54   */
  55   55  
  56   56  major_t bootfs_major;
  57   57  static int bootfs_fstype;
  58   58  static id_space_t *bootfs_idspace;
  59   59  static uint64_t bootfs_nactive;
  60   60  static kmutex_t bootfs_lock;
  61   61  
  62   62  static const char *bootfs_name = "bootfs";
  63   63  
  64   64  static int
  65   65  bootfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
  66   66  {
  67   67          int ret;
  68   68          bootfs_t *bfs;
  69   69          struct pathname dpn;
  70   70          dev_t fsdev;
  71   71  
  72   72          if ((ret = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
  73   73                  return (ret);
  74   74  
  75   75          if (mvp->v_type != VDIR)
  76   76                  return (ENOTDIR);
  77   77  
  78   78          if (uap->flags & MS_REMOUNT)
  79   79                  return (EBUSY);
  80   80  
  81   81          mutex_enter(&mvp->v_lock);
  82   82          if ((uap->flags & MS_OVERLAY) == 0 &&
  83   83              (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
  84   84                  mutex_exit(&mvp->v_lock);
  85   85                  return (EBUSY);
  
    | 
      ↓ open down ↓ | 
    85 lines elided | 
    
      ↑ open up ↑ | 
  
  86   86          }
  87   87          mutex_exit(&mvp->v_lock);
  88   88  
  89   89          /*
  90   90           * We indicate that the backing store is bootfs. We don't want to use
  91   91           * swap, because folks might think that this is putting all the data
  92   92           * into memory ala tmpfs. Rather these modules are always in memory and
  93   93           * there's nothing to be done about that.
  94   94           */
  95   95          vfs_setresource(vfsp, bootfs_name, 0);
  96      -        bfs = kmem_zalloc(sizeof (bootfs_t), KM_NOSLEEP | KM_NORMALPRI);
       96 +        bfs = kmem_zalloc(sizeof (bootfs_t), KM_NOSLEEP_LAZY);
  97   97          if (bfs == NULL)
  98   98                  return (ENOMEM);
  99   99  
 100  100          ret = pn_get(uap->dir,
 101  101              (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn);
 102  102          if (ret != 0) {
 103  103                  kmem_free(bfs, sizeof (bfs));
 104  104                  return (ret);
 105  105          }
 106  106  
 107  107          bfs->bfs_minor = id_alloc(bootfs_idspace);
 108  108          bfs->bfs_kstat = kstat_create_zone("bootfs", bfs->bfs_minor, "bootfs",
 109  109              "fs", KSTAT_TYPE_NAMED,
 110  110              sizeof (bootfs_stat_t) / sizeof (kstat_named_t),
 111  111              KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID);
 112  112          if (bfs->bfs_kstat == NULL) {
 113  113                  id_free(bootfs_idspace, bfs->bfs_minor);
 114  114                  pn_free(&dpn);
 115  115                  kmem_free(bfs, sizeof (bfs));
 116  116                  return (ENOMEM);
 117  117          }
 118  118          bfs->bfs_kstat->ks_data = &bfs->bfs_stat;
 119  119  
 120  120          fsdev = makedevice(bootfs_major, bfs->bfs_minor);
 121  121          bfs->bfs_vfsp = vfsp;
 122  122  
 123  123          vfsp->vfs_data = (caddr_t)bfs;
 124  124          vfsp->vfs_fstype = bootfs_fstype;
 125  125          vfsp->vfs_dev = fsdev;
 126  126          vfsp->vfs_bsize = PAGESIZE;
 127  127          vfsp->vfs_flag |= VFS_RDONLY | VFS_NOSETUID | VFS_NOTRUNC |
 128  128              VFS_UNLINKABLE;
 129  129          vfs_make_fsid(&vfsp->vfs_fsid, fsdev, bootfs_fstype);
 130  130          bfs->bfs_mntpath = kmem_alloc(dpn.pn_pathlen + 1, KM_SLEEP);
 131  131          bcopy(dpn.pn_path, bfs->bfs_mntpath, dpn.pn_pathlen);
 132  132          bfs->bfs_mntpath[dpn.pn_pathlen] = '\0';
 133  133          pn_free(&dpn);
 134  134          list_create(&bfs->bfs_nodes, sizeof (bootfs_node_t),
 135  135              offsetof(bootfs_node_t, bvn_alink));
 136  136  
 137  137          kstat_named_init(&bfs->bfs_stat.bfss_nfiles, "nfiles",
 138  138              KSTAT_DATA_UINT32);
 139  139          kstat_named_init(&bfs->bfs_stat.bfss_ndirs, "ndirs",
 140  140              KSTAT_DATA_UINT32);
 141  141          kstat_named_init(&bfs->bfs_stat.bfss_nbytes, "nbytes",
 142  142              KSTAT_DATA_UINT64);
 143  143          kstat_named_init(&bfs->bfs_stat.bfss_ndups, "ndup",
 144  144              KSTAT_DATA_UINT32);
 145  145          kstat_named_init(&bfs->bfs_stat.bfss_ndiscards, "ndiscard",
 146  146              KSTAT_DATA_UINT32);
 147  147  
 148  148          bootfs_construct(bfs);
 149  149  
 150  150          kstat_install(bfs->bfs_kstat);
 151  151  
 152  152          return (0);
 153  153  }
 154  154  
 155  155  static int
 156  156  bootfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
 157  157  {
 158  158          int ret;
 159  159          bootfs_t *bfs = vfsp->vfs_data;
 160  160          bootfs_node_t *bnp;
 161  161  
 162  162          if ((ret = secpolicy_fs_unmount(cr, vfsp)) != 0)
 163  163                  return (ret);
 164  164  
 165  165          if (flag & MS_FORCE)
 166  166                  return (ENOTSUP);
 167  167  
 168  168          for (bnp = list_head(&bfs->bfs_nodes); bnp != NULL;
 169  169              bnp = list_next(&bfs->bfs_nodes, bnp)) {
 170  170                  mutex_enter(&bnp->bvn_vnp->v_lock);
 171  171                  if (bnp->bvn_vnp->v_count > 1) {
 172  172                          mutex_exit(&bnp->bvn_vnp->v_lock);
 173  173                          return (EBUSY);
 174  174                  }
 175  175                  mutex_exit(&bnp->bvn_vnp->v_lock);
 176  176          }
 177  177  
 178  178          kstat_delete(bfs->bfs_kstat);
 179  179          bootfs_destruct(bfs);
 180  180          list_destroy(&bfs->bfs_nodes);
 181  181          kmem_free(bfs->bfs_mntpath, strlen(bfs->bfs_mntpath) + 1);
 182  182          id_free(bootfs_idspace, bfs->bfs_minor);
 183  183          kmem_free(bfs, sizeof (bootfs_t));
 184  184          return (0);
 185  185  }
 186  186  
 187  187  static int
 188  188  bootfs_root(vfs_t *vfsp, vnode_t **vpp)
 189  189  {
 190  190          bootfs_t *bfs;
 191  191  
 192  192          bfs = (bootfs_t *)vfsp->vfs_data;
 193  193          *vpp = bfs->bfs_rootvn->bvn_vnp;
 194  194          VN_HOLD(*vpp)
 195  195  
 196  196          return (0);
 197  197  }
 198  198  
 199  199  static int
 200  200  bootfs_statvfs(vfs_t *vfsp, struct statvfs64 *sbp)
 201  201  {
 202  202          const bootfs_t *bfs = (bootfs_t *)vfsp;
 203  203          dev32_t d32;
 204  204  
 205  205          sbp->f_bsize = PAGESIZE;
 206  206          sbp->f_frsize = PAGESIZE;
 207  207  
 208  208          sbp->f_blocks = bfs->bfs_stat.bfss_nbytes.value.ui64 >> PAGESHIFT;
 209  209          sbp->f_bfree = 0;
 210  210          sbp->f_bavail = 0;
 211  211  
 212  212          sbp->f_files = bfs->bfs_stat.bfss_nfiles.value.ui32 +
 213  213              bfs->bfs_stat.bfss_ndirs.value.ui32;
 214  214          sbp->f_ffree = 0;
 215  215          sbp->f_favail = 0;
 216  216  
 217  217          (void) cmpldev(&d32, vfsp->vfs_dev);
 218  218          sbp->f_fsid = d32;
 219  219          (void) strlcpy(sbp->f_basetype, bootfs_name, FSTYPSZ);
 220  220          bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
 221  221  
 222  222          return (0);
 223  223  }
 224  224  
 225  225  static const fs_operation_def_t bootfs_vfsops_tmpl[] = {
 226  226          VFSNAME_MOUNT,          { .vfs_mount = bootfs_mount },
 227  227          VFSNAME_UNMOUNT,        { .vfs_unmount = bootfs_unmount },
 228  228          VFSNAME_ROOT,           { .vfs_root = bootfs_root },
 229  229          VFSNAME_STATVFS,        { .vfs_statvfs = bootfs_statvfs },
 230  230          NULL,                   NULL
 231  231  };
 232  232  
 233  233  static int
 234  234  bootfs_init(int fstype, char *name)
 235  235  {
 236  236          int ret;
 237  237  
 238  238          bootfs_fstype = fstype;
 239  239          ASSERT(bootfs_fstype != 0);
 240  240  
 241  241          ret = vfs_setfsops(fstype, bootfs_vfsops_tmpl, NULL);
 242  242          if (ret != 0)
 243  243                  return (ret);
 244  244  
 245  245          ret = vn_make_ops(name, bootfs_vnodeops_template, &bootfs_vnodeops);
 246  246          if (ret != 0) {
 247  247                  (void) vfs_freevfsops_by_type(bootfs_fstype);
 248  248                  return (ret);
 249  249          }
 250  250  
 251  251          bootfs_major = getudev();
 252  252          if (bootfs_major == (major_t)-1) {
 253  253                  cmn_err(CE_WARN, "bootfs_init: Can't get unique device number");
 254  254                  bootfs_major = 0;
 255  255          }
 256  256  
 257  257          bootfs_nactive = 0;
 258  258          return (0);
 259  259  }
 260  260  
 261  261  static mntopts_t bootfs_mntopts = {
 262  262          0, NULL
 263  263  };
 264  264  
 265  265  static vfsdef_t bootfs_vfsdef = {
 266  266          VFSDEF_VERSION,
 267  267          "bootfs",
 268  268          bootfs_init,
 269  269          VSW_HASPROTO|VSW_STATS,
 270  270          &bootfs_mntopts
 271  271  };
 272  272  
 273  273  static struct modlfs bootfs_modlfs = {
 274  274          &mod_fsops, "boot-time modules file system", &bootfs_vfsdef
 275  275  };
 276  276  
 277  277  static struct modlinkage bootfs_modlinkage = {
 278  278          MODREV_1, &bootfs_modlfs, NULL
 279  279  };
 280  280  
 281  281  int
 282  282  _init(void)
 283  283  {
 284  284          bootfs_node_cache = kmem_cache_create("bootfs_node_cache",
 285  285              sizeof (bootfs_node_t), 0, bootfs_node_constructor,
 286  286              bootfs_node_destructor, NULL, NULL, NULL, 0);
 287  287          bootfs_idspace = id_space_create("bootfs_minors", 1, INT32_MAX);
 288  288          mutex_init(&bootfs_lock, NULL, MUTEX_DEFAULT, NULL);
 289  289  
 290  290          return (mod_install(&bootfs_modlinkage));
 291  291  }
 292  292  
 293  293  int
 294  294  _info(struct modinfo *modinfop)
 295  295  {
 296  296          return (mod_info(&bootfs_modlinkage, modinfop));
 297  297  }
 298  298  
 299  299  int
 300  300  _fini(void)
 301  301  {
 302  302          int err;
 303  303  
 304  304          mutex_enter(&bootfs_lock);
 305  305          if (bootfs_nactive > 0) {
 306  306                  mutex_exit(&bootfs_lock);
 307  307                  return (EBUSY);
 308  308          }
 309  309          mutex_exit(&bootfs_lock);
 310  310  
 311  311          err = mod_remove(&bootfs_modlinkage);
 312  312          if (err != 0)
 313  313                  return (err);
 314  314  
 315  315          (void) vfs_freevfsops_by_type(bootfs_fstype);
 316  316          vn_freevnodeops(bootfs_vnodeops);
 317  317          id_space_destroy(bootfs_idspace);
 318  318          mutex_destroy(&bootfs_lock);
 319  319          kmem_cache_destroy(bootfs_node_cache);
 320  320          return (err);
 321  321  }
  
    | 
      ↓ open down ↓ | 
    215 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX