13957Sth199096 /*
23957Sth199096 * CDDL HEADER START
33957Sth199096 *
43957Sth199096 * The contents of this file are subject to the terms of the
53957Sth199096 * Common Development and Distribution License (the "License").
63957Sth199096 * You may not use this file except in compliance with the License.
73957Sth199096 *
83957Sth199096 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93957Sth199096 * or http://www.opensolaris.org/os/licensing.
103957Sth199096 * See the License for the specific language governing permissions
113957Sth199096 * and limitations under the License.
123957Sth199096 *
133957Sth199096 * When distributing Covered Code, include this CDDL HEADER in each
143957Sth199096 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153957Sth199096 * If applicable, add the following below this CDDL HEADER, with the
163957Sth199096 * fields enclosed by brackets "[]" replaced with your own identifying
173957Sth199096 * information: Portions Copyright [yyyy] [name of copyright owner]
183957Sth199096 *
193957Sth199096 * CDDL HEADER END
203957Sth199096 */
213957Sth199096
223957Sth199096 /*
23*12633Sjohn.levon@sun.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
243957Sth199096 */
253957Sth199096
263957Sth199096 #include <sys/atomic.h>
273957Sth199096 #include <sys/cmn_err.h>
283957Sth199096 #include <sys/errno.h>
293957Sth199096 #include <sys/mount.h>
303957Sth199096 #include <sharefs/sharefs.h>
313957Sth199096 #include <sys/vfs_opreg.h>
323957Sth199096 #include <sys/policy.h>
333957Sth199096 #include <sys/sunddi.h>
343957Sth199096 #include <sys/sysmacros.h>
353957Sth199096 #include <sys/systm.h>
363957Sth199096
373957Sth199096 #include <sys/mntent.h>
383957Sth199096 #include <sys/vfs.h>
393957Sth199096
403957Sth199096 /*
413957Sth199096 * Kernel sharetab filesystem.
423957Sth199096 *
433957Sth199096 * This is a pseudo filesystem which exports information about shares currently
443957Sth199096 * in kernel memory. The only element of the pseudo filesystem is a file.
453957Sth199096 *
463957Sth199096 * This file contains functions that interact with the VFS layer.
473957Sth199096 *
483957Sth199096 * sharetab sharefs_datanode_t sharefs.c
493957Sth199096 *
503957Sth199096 */
513957Sth199096
523957Sth199096 vnodeops_t *sharefs_ops_data;
533957Sth199096
543957Sth199096 static const fs_operation_def_t sharefs_vfstops[];
553957Sth199096 static gfs_opsvec_t sharefs_opsvec[];
563957Sth199096
573957Sth199096 static int sharefs_init(int, char *);
583957Sth199096
593957Sth199096 /*
603957Sth199096 * The sharefs system call.
613957Sth199096 */
623957Sth199096 static struct sysent sharefs_sysent = {
633957Sth199096 3,
643957Sth199096 SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
653957Sth199096 sharefs
663957Sth199096 };
673957Sth199096
683957Sth199096 static struct modlsys modlsys = {
693957Sth199096 &mod_syscallops,
703957Sth199096 "sharefs syscall",
713957Sth199096 &sharefs_sysent
723957Sth199096 };
733957Sth199096
743957Sth199096 #ifdef _SYSCALL32_IMPL
753957Sth199096 static struct modlsys modlsys32 = {
763957Sth199096 &mod_syscallops32,
773957Sth199096 "sharefs syscall (32-bit)",
783957Sth199096 &sharefs_sysent
793957Sth199096 };
803957Sth199096 #endif /* _SYSCALL32_IMPL */
813957Sth199096
823957Sth199096 /*
833957Sth199096 * Module linkage
843957Sth199096 */
853957Sth199096 static mntopts_t sharefs_mntopts = {
863957Sth199096 0,
873957Sth199096 NULL
883957Sth199096 };
893957Sth199096
903957Sth199096 static vfsdef_t vfw = {
913957Sth199096 VFSDEF_VERSION,
923957Sth199096 "sharefs",
933957Sth199096 sharefs_init,
94*12633Sjohn.levon@sun.com VSW_HASPROTO | VSW_ZMOUNT,
953957Sth199096 &sharefs_mntopts,
963957Sth199096 };
973957Sth199096
983957Sth199096 extern struct mod_ops mod_fsops;
993957Sth199096
1003957Sth199096 static struct modlfs modlfs = {
1013957Sth199096 &mod_fsops,
1023957Sth199096 "sharetab filesystem",
1033957Sth199096 &vfw
1043957Sth199096 };
1053957Sth199096
1063957Sth199096 static struct modlinkage modlinkage = {
1073957Sth199096 MODREV_1,
1083957Sth199096 &modlfs,
1093957Sth199096 &modlsys,
1103957Sth199096 #ifdef _SYSCALL32_IMPL
1113957Sth199096 &modlsys32,
1123957Sth199096 #endif
1133957Sth199096 NULL
1143957Sth199096 };
1153957Sth199096
1163957Sth199096 int
_init(void)1173957Sth199096 _init(void)
1183957Sth199096 {
1193957Sth199096 return (mod_install(&modlinkage));
1203957Sth199096 }
1213957Sth199096
1223957Sth199096 int
_info(struct modinfo * modinfop)1233957Sth199096 _info(struct modinfo *modinfop)
1243957Sth199096 {
1253957Sth199096 return (mod_info(&modlinkage, modinfop));
1263957Sth199096 }
1273957Sth199096
1283957Sth199096 int
_fini(void)1293957Sth199096 _fini(void)
1303957Sth199096 {
1313957Sth199096 /*
1323957Sth199096 * The sharetab filesystem cannot be unloaded.
1333957Sth199096 */
1343957Sth199096 return (EBUSY);
1353957Sth199096 }
1363957Sth199096
1373957Sth199096 /*
1383957Sth199096 * Filesystem initialization.
1393957Sth199096 */
1403957Sth199096
1413957Sth199096 static int sharefs_fstype;
1423957Sth199096 static major_t sharefs_major;
1433957Sth199096 static minor_t sharefs_minor;
1443957Sth199096
1453957Sth199096 static gfs_opsvec_t sharefs_opsvec[] = {
1463957Sth199096 { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data },
1473957Sth199096 { NULL }
1483957Sth199096 };
1493957Sth199096
1503957Sth199096 /* ARGSUSED */
1513957Sth199096 static int
sharefs_init(int fstype,char * name)1523957Sth199096 sharefs_init(int fstype, char *name)
1533957Sth199096 {
1543957Sth199096 vfsops_t *vfsops;
1553957Sth199096 int error;
1563957Sth199096
1573957Sth199096 sharefs_fstype = fstype;
1583957Sth199096 if (error = vfs_setfsops(fstype, sharefs_vfstops, &vfsops)) {
1593957Sth199096 cmn_err(CE_WARN, "sharefs_init: bad vfs ops template");
1603957Sth199096 return (error);
1613957Sth199096 }
1623957Sth199096
1633957Sth199096 if (error = gfs_make_opsvec(sharefs_opsvec)) {
1643957Sth199096 (void) vfs_freevfsops(vfsops);
1653957Sth199096 return (error);
1663957Sth199096 }
1673957Sth199096
1683957Sth199096 if ((sharefs_major = getudev()) == (major_t)-1) {
1693957Sth199096 cmn_err(CE_WARN,
1704995Sth199096 "sharefs_init: can't get unique device number");
1713957Sth199096 sharefs_major = 0;
1723957Sth199096 }
1733957Sth199096
1743957Sth199096 sharefs_sharetab_init();
1753957Sth199096
1763957Sth199096 return (0);
1773957Sth199096 }
1783957Sth199096
1793957Sth199096 /*
1803957Sth199096 * VFS entry points
1813957Sth199096 */
1823957Sth199096 static int
sharefs_mount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)1833957Sth199096 sharefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
1843957Sth199096 {
1853957Sth199096 sharefs_vfs_t *data;
1863957Sth199096 dev_t dev;
1873957Sth199096
1883957Sth199096 if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
1893957Sth199096 return (EPERM);
1903957Sth199096
1913957Sth199096 if ((uap->flags & MS_OVERLAY) == 0 &&
1923957Sth199096 (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
1933957Sth199096 return (EBUSY);
1943957Sth199096
1953957Sth199096 data = kmem_alloc(sizeof (sharefs_vfs_t), KM_SLEEP);
1963957Sth199096
1973957Sth199096 /*
1983957Sth199096 * Initialize vfs fields
1993957Sth199096 */
2003957Sth199096 vfsp->vfs_bsize = DEV_BSIZE;
2013957Sth199096 vfsp->vfs_fstype = sharefs_fstype;
2023957Sth199096 do {
2033957Sth199096 dev = makedevice(sharefs_major,
2043957Sth199096 atomic_add_32_nv(&sharefs_minor, 1) & L_MAXMIN32);
2053957Sth199096 } while (vfs_devismounted(dev));
2063957Sth199096 vfs_make_fsid(&vfsp->vfs_fsid, dev, sharefs_fstype);
2073957Sth199096 vfsp->vfs_data = data;
2083957Sth199096 vfsp->vfs_dev = dev;
2093957Sth199096
2103957Sth199096 /*
2113957Sth199096 * Create root
2123957Sth199096 */
2133957Sth199096 data->sharefs_vfs_root = sharefs_create_root_file(vfsp);
2143957Sth199096
2153957Sth199096 return (0);
2163957Sth199096 }
2173957Sth199096
2183957Sth199096 static int
sharefs_unmount(vfs_t * vfsp,int flag,struct cred * cr)2193957Sth199096 sharefs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
2203957Sth199096 {
2213957Sth199096 sharefs_vfs_t *data;
2223957Sth199096
2233957Sth199096 if (secpolicy_fs_unmount(cr, vfsp) != 0)
2243957Sth199096 return (EPERM);
2253957Sth199096
2263957Sth199096 /*
2273957Sth199096 * We do not currently support forced unmounts
2283957Sth199096 */
2293957Sth199096 if (flag & MS_FORCE)
2303957Sth199096 return (ENOTSUP);
2313957Sth199096
2323957Sth199096 /*
2333957Sth199096 * We should never have a reference count of less than 2: one for the
2343957Sth199096 * caller, one for the root vnode.
2353957Sth199096 */
2363957Sth199096 ASSERT(vfsp->vfs_count >= 2);
2373957Sth199096
2383957Sth199096 /*
2393957Sth199096 * Any active vnodes will result in a hold on the root vnode
2403957Sth199096 */
2413957Sth199096 data = vfsp->vfs_data;
2423957Sth199096 if (data->sharefs_vfs_root->v_count > 1)
2433957Sth199096 return (EBUSY);
2443957Sth199096
2453957Sth199096 /*
2463957Sth199096 * Only allow an unmount iff there are no entries in memory.
2473957Sth199096 */
2483957Sth199096 rw_enter(&sharetab_lock, RW_READER);
2493957Sth199096 if (sharetab_size != 0) {
2503957Sth199096 rw_exit(&sharetab_lock);
2513957Sth199096 return (EBUSY);
2523957Sth199096 }
2533957Sth199096 rw_exit(&sharetab_lock);
2543957Sth199096
2553957Sth199096 /*
2563957Sth199096 * Release the last hold on the root vnode
2573957Sth199096 */
2583957Sth199096 VN_RELE(data->sharefs_vfs_root);
2593957Sth199096
2603957Sth199096 kmem_free(data, sizeof (sharefs_vfs_t));
2613957Sth199096
2623957Sth199096 return (0);
2633957Sth199096 }
2643957Sth199096
2653957Sth199096 static int
sharefs_root(vfs_t * vfsp,vnode_t ** vpp)2663957Sth199096 sharefs_root(vfs_t *vfsp, vnode_t **vpp)
2673957Sth199096 {
2683957Sth199096 sharefs_vfs_t *data = vfsp->vfs_data;
2693957Sth199096
2703957Sth199096 *vpp = data->sharefs_vfs_root;
2713957Sth199096 VN_HOLD(*vpp);
2723957Sth199096
2733957Sth199096 return (0);
2743957Sth199096 }
2753957Sth199096
2763957Sth199096 static int
sharefs_statvfs(vfs_t * vfsp,statvfs64_t * sp)2773957Sth199096 sharefs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
2783957Sth199096 {
2793957Sth199096 dev32_t d32;
2803957Sth199096 int total = 1;
2813957Sth199096
2823957Sth199096 bzero(sp, sizeof (*sp));
2833957Sth199096 sp->f_bsize = DEV_BSIZE;
2843957Sth199096 sp->f_frsize = DEV_BSIZE;
2853957Sth199096 sp->f_files = total;
2863957Sth199096 sp->f_ffree = sp->f_favail = INT_MAX - total;
2873957Sth199096 (void) cmpldev(&d32, vfsp->vfs_dev);
2883957Sth199096 sp->f_fsid = d32;
2893957Sth199096 (void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
2903957Sth199096 sizeof (sp->f_basetype));
2913957Sth199096 sp->f_flag = vf_to_stf(vfsp->vfs_flag);
2923957Sth199096 sp->f_namemax = SHAREFS_NAME_MAX;
2933957Sth199096 (void) strlcpy(sp->f_fstr, "sharefs", sizeof (sp->f_fstr));
2943957Sth199096
2953957Sth199096 return (0);
2963957Sth199096 }
2973957Sth199096
2983957Sth199096 static const fs_operation_def_t sharefs_vfstops[] = {
2993957Sth199096 { VFSNAME_MOUNT, { .vfs_mount = sharefs_mount } },
3003957Sth199096 { VFSNAME_UNMOUNT, { .vfs_unmount = sharefs_unmount } },
3013957Sth199096 { VFSNAME_ROOT, { .vfs_root = sharefs_root } },
3023957Sth199096 { VFSNAME_STATVFS, { .vfs_statvfs = sharefs_statvfs } },
3033957Sth199096 { NULL }
3043957Sth199096 };
305