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