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