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