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 56vnodeops_t *sharefs_ops_data; 57 58static const fs_operation_def_t sharefs_vfstops[]; 59static gfs_opsvec_t sharefs_opsvec[]; 60 61static int sharefs_init(int, char *); 62 63/* 64 * The sharefs system call. 65 */ 66static struct sysent sharefs_sysent = { 67 3, 68 SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD, 69 sharefs 70}; 71 72static struct modlsys modlsys = { 73 &mod_syscallops, 74 "sharefs syscall", 75 &sharefs_sysent 76}; 77 78#ifdef _SYSCALL32_IMPL 79static 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 */ 89static mntopts_t sharefs_mntopts = { 90 0, 91 NULL 92}; 93 94static vfsdef_t vfw = { 95 VFSDEF_VERSION, 96 "sharefs", 97 sharefs_init, 98 VSW_HASPROTO | VSW_ZMOUNT, 99 &sharefs_mntopts, 100}; 101 102extern struct mod_ops mod_fsops; 103 104static struct modlfs modlfs = { 105 &mod_fsops, 106 "sharetab filesystem", 107 &vfw 108}; 109 110static struct modlinkage modlinkage = { 111 MODREV_1, 112 &modlfs, 113 &modlsys, 114#ifdef _SYSCALL32_IMPL 115 &modlsys32, 116#endif 117 NULL 118}; 119 120int 121_init(void) 122{ 123 return (mod_install(&modlinkage)); 124} 125 126int 127_info(struct modinfo *modinfop) 128{ 129 return (mod_info(&modlinkage, modinfop)); 130} 131 132int 133_fini(void) 134{ 135 /* 136 * The sharetab filesystem cannot be unloaded. 137 */ 138 return (EBUSY); 139} 140 141/* 142 * Filesystem initialization. 143 */ 144 145static int sharefs_fstype; 146static major_t sharefs_major; 147static minor_t sharefs_minor; 148 149static gfs_opsvec_t sharefs_opsvec[] = { 150 { "sharefs sharetab file", sharefs_tops_data, &sharefs_ops_data }, 151 { NULL } 152}; 153 154/* ARGSUSED */ 155static int 156sharefs_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 */ 186static int 187sharefs_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 222static int 223sharefs_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 259static int 260sharefs_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 270static int 271sharefs_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 292static 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