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