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