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 int 117 _init(void) 118 { 119 return (mod_install(&modlinkage)); 120 } 121 122 int 123 _info(struct modinfo *modinfop) 124 { 125 return (mod_info(&modlinkage, modinfop)); 126 } 127 128 int 129 _fini(void) 130 { 131 /* 132 * The sharetab filesystem cannot be unloaded. 133 */ 134 return (EBUSY); 135 } 136 137 /* 138 * Filesystem initialization. 139 */ 140 141 static int sharefs_fstype; 142 static major_t sharefs_major; 143 static minor_t sharefs_minor; 144 145 static gfs_opsvec_t sharefs_opsvec[] = { 146 { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data }, 147 { NULL } 148 }; 149 150 /* ARGSUSED */ 151 static int 152 sharefs_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 */ 182 static int 183 sharefs_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_inc_32_nv(&sharefs_minor) & 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 218 static int 219 sharefs_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 265 static int 266 sharefs_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 276 static int 277 sharefs_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 298 static 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