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 
 117 int
 118 _init(void)
 119 {
 120         return (mod_install(&modlinkage));
 121 }
 122 
 123 int
 124 _info(struct modinfo *modinfop)
 125 {
 126         return (mod_info(&modlinkage, modinfop));
 127 }
 128 
 129 int
 130 _fini(void)
 131 {
 132         /*
 133          * The sharetab filesystem cannot be unloaded.
 134          */
 135         return (EBUSY);
 136 }
 137 
 138 /*
 139  * Filesystem initialization.
 140  */
 141 
 142 static int sharefs_fstype;
 143 static major_t sharefs_major;
 144 static minor_t sharefs_minor;
 145 
 146 static gfs_opsvec_t sharefs_opsvec[] = {
 147         { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data },
 148         { NULL }
 149 };
 150 
 151 /* ARGSUSED */
 152 static int
 153 sharefs_init(int fstype, char *name)
 154 {
 155         vfsops_t        *vfsops;
 156         int             error;
 157 
 158         sharefs_fstype = fstype;
 159         if (error = vfs_setfsops(fstype, sharefs_vfstops, &vfsops)) {
 160                 cmn_err(CE_WARN, "sharefs_init: bad vfs ops template");
 161                 return (error);
 162         }
 163 
 164         if (error = gfs_make_opsvec(sharefs_opsvec)) {
 165                 (void) vfs_freevfsops(vfsops);
 166                 return (error);
 167         }
 168 
 169         if ((sharefs_major = getudev()) == (major_t)-1) {
 170                 cmn_err(CE_WARN,
 171                     "sharefs_init: can't get unique device number");
 172                 sharefs_major = 0;
 173         }
 174 
 175         sharefs_sharetab_init();
 176 
 177         return (0);
 178 }
 179 
 180 /*
 181  * VFS entry points
 182  */
 183 static int
 184 sharefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
 185 {
 186         sharefs_vfs_t   *data;
 187         dev_t           dev;
 188 
 189         if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
 190                 return (EPERM);
 191 
 192         if ((uap->flags & MS_OVERLAY) == 0 &&
 193             (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
 194                 return (EBUSY);
 195 
 196         data = kmem_alloc(sizeof (sharefs_vfs_t), KM_SLEEP);
 197 
 198         /*
 199          * Initialize vfs fields
 200          */
 201         vfsp->vfs_bsize = DEV_BSIZE;
 202         vfsp->vfs_fstype = sharefs_fstype;
 203         do {
 204                 dev = makedevice(sharefs_major,
 205                     atomic_inc_32_nv(&sharefs_minor) & L_MAXMIN32);
 206         } while (vfs_devismounted(dev));
 207         vfs_make_fsid(&vfsp->vfs_fsid, dev, sharefs_fstype);
 208         vfsp->vfs_data = data;
 209         vfsp->vfs_dev = dev;
 210 
 211         /*
 212          * Create root
 213          */
 214         data->sharefs_vfs_root = sharefs_create_root_file(vfsp);
 215 
 216         return (0);
 217 }
 218 
 219 static int
 220 sharefs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
 221 {
 222         sharefs_vfs_t   *data;
 223 
 224         if (secpolicy_fs_unmount(cr, vfsp) != 0)
 225                 return (EPERM);
 226 
 227         /*
 228          * We do not currently support forced unmounts
 229          */
 230         if (flag & MS_FORCE)
 231                 return (ENOTSUP);
 232 
 233         /*
 234          * We should never have a reference count of less than 2: one for the
 235          * caller, one for the root vnode.
 236          */
 237         ASSERT(vfsp->vfs_count >= 2);
 238 
 239         /*
 240          * Any active vnodes will result in a hold on the root vnode
 241          */
 242         data = vfsp->vfs_data;
 243         if (data->sharefs_vfs_root->v_count > 1)
 244                 return (EBUSY);
 245 
 246         /*
 247          * Only allow an unmount iff there are no entries in memory.
 248          */
 249         rw_enter(&sharetab_lock, RW_READER);
 250         if (sharetab_size != 0) {
 251                 rw_exit(&sharetab_lock);
 252                 return (EBUSY);
 253         }
 254         rw_exit(&sharetab_lock);
 255 
 256         /*
 257          * Release the last hold on the root vnode
 258          */
 259         VN_RELE(data->sharefs_vfs_root);
 260 
 261         kmem_free(data, sizeof (sharefs_vfs_t));
 262 
 263         return (0);
 264 }
 265 
 266 static int
 267 sharefs_root(vfs_t *vfsp, vnode_t **vpp)
 268 {
 269         sharefs_vfs_t   *data = vfsp->vfs_data;
 270 
 271         *vpp = data->sharefs_vfs_root;
 272         VN_HOLD(*vpp);
 273 
 274         return (0);
 275 }
 276 
 277 static int
 278 sharefs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
 279 {
 280         dev32_t d32;
 281         int     total = 1;
 282 
 283         bzero(sp, sizeof (*sp));
 284         sp->f_bsize = DEV_BSIZE;
 285         sp->f_frsize = DEV_BSIZE;
 286         sp->f_files = total;
 287         sp->f_ffree = sp->f_favail = INT_MAX - total;
 288         (void) cmpldev(&d32, vfsp->vfs_dev);
 289         sp->f_fsid = d32;
 290         (void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
 291             sizeof (sp->f_basetype));
 292         sp->f_flag = vf_to_stf(vfsp->vfs_flag);
 293         sp->f_namemax = SHAREFS_NAME_MAX;
 294         (void) strlcpy(sp->f_fstr, "sharefs", sizeof (sp->f_fstr));
 295 
 296         return (0);
 297 }
 298 
 299 static const fs_operation_def_t sharefs_vfstops[] = {
 300         { VFSNAME_MOUNT,        { .vfs_mount = sharefs_mount } },
 301         { VFSNAME_UNMOUNT,      { .vfs_unmount = sharefs_unmount } },
 302         { VFSNAME_ROOT,         { .vfs_root = sharefs_root } },
 303         { VFSNAME_STATVFS,      { .vfs_statvfs = sharefs_statvfs } },
 304         { NULL }
 305 };