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 52vnodeops_t *sharefs_ops_data; 53 54static const fs_operation_def_t sharefs_vfstops[]; 55static gfs_opsvec_t sharefs_opsvec[]; 56 57static int sharefs_init(int, char *); 58 59/* 60 * The sharefs system call. 61 */ 62static struct sysent sharefs_sysent = { 63 3, 64 SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD, 65 sharefs 66}; 67 68static struct modlsys modlsys = { 69 &mod_syscallops, 70 "sharefs syscall", 71 &sharefs_sysent 72}; 73 74#ifdef _SYSCALL32_IMPL 75static 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 */ 85static mntopts_t sharefs_mntopts = { 86 0, 87 NULL 88}; 89 90static vfsdef_t vfw = { 91 VFSDEF_VERSION, 92 "sharefs", 93 sharefs_init, 94 VSW_HASPROTO | VSW_ZMOUNT, 95 &sharefs_mntopts, 96}; 97 98extern struct mod_ops mod_fsops; 99 100static struct modlfs modlfs = { 101 &mod_fsops, 102 "sharetab filesystem", 103 &vfw 104}; 105 106static struct modlinkage modlinkage = { 107 MODREV_1, 108 &modlfs, 109 &modlsys, 110#ifdef _SYSCALL32_IMPL 111 &modlsys32, 112#endif 113 NULL 114}; 115 116int 117_init(void) 118{ 119 return (mod_install(&modlinkage)); 120} 121 122int 123_info(struct modinfo *modinfop) 124{ 125 return (mod_info(&modlinkage, modinfop)); 126} 127 128int 129_fini(void) 130{ 131 /* 132 * The sharetab filesystem cannot be unloaded. 133 */ 134 return (EBUSY); 135} 136 137/* 138 * Filesystem initialization. 139 */ 140 141static int sharefs_fstype; 142static major_t sharefs_major; 143static minor_t sharefs_minor; 144 145static gfs_opsvec_t sharefs_opsvec[] = { 146 { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data }, 147 { NULL } 148}; 149 150/* ARGSUSED */ 151static int 152sharefs_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 */ 182static int 183sharefs_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 218static int 219sharefs_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 265static int 266sharefs_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 276static int 277sharefs_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 298static 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}; 305