1 /*
   2  * CDDL HEADER START
   3  *
   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 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Nexenta Systems, Inc.
  28  */
  29 
  30 #include <sys/atomic.h>
  31 #include <sys/cmn_err.h>
  32 #include <sys/errno.h>
  33 #include <sys/mount.h>
  34 #include <sharefs/sharefs.h>
  35 #include <sys/vfs_opreg.h>
  36 #include <sys/policy.h>
  37 #include <sys/sunddi.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/systm.h>
  40 
  41 #include <sys/mntent.h>
  42 #include <sys/vfs.h>
  43 
  44 /*
  45  * Kernel sharetab filesystem.
  46  *
  47  * This is a pseudo filesystem which exports information about shares currently
  48  * in kernel memory. The only element of the pseudo filesystem is a file.
  49  *
  50  * This file contains functions that interact with the VFS layer.
  51  *
  52  *      sharetab        sharefs_datanode_t      sharefs.c
  53  *
  54  */
  55 
  56 vnodeops_t                      *sharefs_ops_data;
  57 
  58 static const fs_operation_def_t sharefs_vfstops[];
  59 static gfs_opsvec_t              sharefs_opsvec[];
  60 
  61 static int sharefs_init(int, char *);
  62 
  63 /*
  64  * The sharefs system call.
  65  */
  66 static struct sysent sharefs_sysent = {
  67         3,
  68         SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
  69         sharefs
  70 };
  71 
  72 static struct modlsys modlsys = {
  73         &mod_syscallops,
  74         "sharefs syscall",
  75         &sharefs_sysent
  76 };
  77 
  78 #ifdef  _SYSCALL32_IMPL
  79 static struct modlsys modlsys32 = {
  80         &mod_syscallops32,
  81         "sharefs syscall (32-bit)",
  82         &sharefs_sysent
  83 };
  84 #endif /* _SYSCALL32_IMPL */
  85 
  86 /*
  87  * Module linkage
  88  */
  89 static mntopts_t sharefs_mntopts = {
  90         0,
  91         NULL
  92 };
  93 
  94 static vfsdef_t vfw = {
  95         VFSDEF_VERSION,
  96         "sharefs",
  97         sharefs_init,
  98         VSW_HASPROTO | VSW_ZMOUNT,
  99         &sharefs_mntopts,
 100 };
 101 
 102 extern struct mod_ops   mod_fsops;
 103 
 104 static struct modlfs modlfs = {
 105         &mod_fsops,
 106         "sharetab filesystem",
 107         &vfw
 108 };
 109 
 110 static struct modlinkage modlinkage = {
 111         MODREV_1,
 112         &modlfs,
 113         &modlsys,
 114 #ifdef  _SYSCALL32_IMPL
 115         &modlsys32,
 116 #endif
 117         NULL
 118 };
 119 
 120 int
 121 _init(void)
 122 {
 123         return (mod_install(&modlinkage));
 124 }
 125 
 126 int
 127 _info(struct modinfo *modinfop)
 128 {
 129         return (mod_info(&modlinkage, modinfop));
 130 }
 131 
 132 int
 133 _fini(void)
 134 {
 135         /*
 136          * The sharetab filesystem cannot be unloaded.
 137          */
 138         return (EBUSY);
 139 }
 140 
 141 /*
 142  * Filesystem initialization.
 143  */
 144 
 145 static int sharefs_fstype;
 146 static major_t sharefs_major;
 147 static minor_t sharefs_minor;
 148 
 149 static gfs_opsvec_t sharefs_opsvec[] = {
 150         { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data },
 151         { NULL }
 152 };
 153 
 154 /* ARGSUSED */
 155 static int
 156 sharefs_init(int fstype, char *name)
 157 {
 158         vfsops_t        *vfsops;
 159         int             error;
 160 
 161         sharefs_fstype = fstype;
 162         if (error = vfs_setfsops(fstype, sharefs_vfstops, &vfsops)) {
 163                 cmn_err(CE_WARN, "sharefs_init: bad vfs ops template");
 164                 return (error);
 165         }
 166 
 167         if (error = gfs_make_opsvec(sharefs_opsvec)) {
 168                 (void) vfs_freevfsops(vfsops);
 169                 return (error);
 170         }
 171 
 172         if ((sharefs_major = getudev()) == (major_t)-1) {
 173                 cmn_err(CE_WARN,
 174                     "sharefs_init: can't get unique device number");
 175                 sharefs_major = 0;
 176         }
 177 
 178         sharefs_sharetab_init();
 179 
 180         return (0);
 181 }
 182 
 183 /*
 184  * VFS entry points
 185  */
 186 static int
 187 sharefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
 188 {
 189         sharefs_vfs_t   *data;
 190         dev_t           dev;
 191 
 192         if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
 193                 return (EPERM);
 194 
 195         if ((uap->flags & MS_OVERLAY) == 0 &&
 196             (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
 197                 return (EBUSY);
 198 
 199         data = kmem_alloc(sizeof (sharefs_vfs_t), KM_SLEEP);
 200 
 201         /*
 202          * Initialize vfs fields
 203          */
 204         vfsp->vfs_bsize = DEV_BSIZE;
 205         vfsp->vfs_fstype = sharefs_fstype;
 206         do {
 207                 dev = makedevice(sharefs_major,
 208                     atomic_inc_32_nv(&sharefs_minor) & L_MAXMIN32);
 209         } while (vfs_devismounted(dev));
 210         vfs_make_fsid(&vfsp->vfs_fsid, dev, sharefs_fstype);
 211         vfsp->vfs_data = data;
 212         vfsp->vfs_dev = dev;
 213 
 214         /*
 215          * Create root
 216          */
 217         data->sharefs_vfs_root = sharefs_create_root_file(vfsp);
 218 
 219         return (0);
 220 }
 221 
 222 static int
 223 sharefs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
 224 {
 225         sharefs_vfs_t   *data;
 226 
 227         if (secpolicy_fs_unmount(cr, vfsp) != 0)
 228                 return (EPERM);
 229 
 230         /*
 231          * We do not currently support forced unmounts
 232          */
 233         if (flag & MS_FORCE)
 234                 return (ENOTSUP);
 235 
 236         /*
 237          * We should never have a reference count of less than 2: one for the
 238          * caller, one for the root vnode.
 239          */
 240         ASSERT(vfsp->vfs_count >= 2);
 241 
 242         /*
 243          * Any active vnodes will result in a hold on the root vnode
 244          */
 245         data = vfsp->vfs_data;
 246         if (data->sharefs_vfs_root->v_count > 1)
 247                 return (EBUSY);
 248 
 249         /*
 250          * Release the last hold on the root vnode
 251          */
 252         VN_RELE(data->sharefs_vfs_root);
 253 
 254         kmem_free(data, sizeof (sharefs_vfs_t));
 255 
 256         return (0);
 257 }
 258 
 259 static int
 260 sharefs_root(vfs_t *vfsp, vnode_t **vpp)
 261 {
 262         sharefs_vfs_t   *data = vfsp->vfs_data;
 263 
 264         *vpp = data->sharefs_vfs_root;
 265         VN_HOLD(*vpp);
 266 
 267         return (0);
 268 }
 269 
 270 static int
 271 sharefs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
 272 {
 273         dev32_t d32;
 274         int     total = 1;
 275 
 276         bzero(sp, sizeof (*sp));
 277         sp->f_bsize = DEV_BSIZE;
 278         sp->f_frsize = DEV_BSIZE;
 279         sp->f_files = total;
 280         sp->f_ffree = sp->f_favail = INT_MAX - total;
 281         (void) cmpldev(&d32, vfsp->vfs_dev);
 282         sp->f_fsid = d32;
 283         (void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
 284             sizeof (sp->f_basetype));
 285         sp->f_flag = vf_to_stf(vfsp->vfs_flag);
 286         sp->f_namemax = SHAREFS_NAME_MAX;
 287         (void) strlcpy(sp->f_fstr, "sharefs", sizeof (sp->f_fstr));
 288 
 289         return (0);
 290 }
 291 
 292 static const fs_operation_def_t sharefs_vfstops[] = {
 293         { VFSNAME_MOUNT,        { .vfs_mount = sharefs_mount } },
 294         { VFSNAME_UNMOUNT,      { .vfs_unmount = sharefs_unmount } },
 295         { VFSNAME_ROOT,         { .vfs_root = sharefs_root } },
 296         { VFSNAME_STATVFS,      { .vfs_statvfs = sharefs_statvfs } },
 297         { NULL }
 298 };