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