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 };