1 1.126 christos /* $NetBSD: puffs_vfsops.c,v 1.126 2021/04/01 19:00:33 christos Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Development of this software was supported by the 7 1.1 pooka * Google Summer of Code program and the Ulla Tuominen Foundation. 8 1.1 pooka * The Google SoC project was mentored by Bill Studenmund. 9 1.1 pooka * 10 1.1 pooka * Redistribution and use in source and binary forms, with or without 11 1.1 pooka * modification, are permitted provided that the following conditions 12 1.1 pooka * are met: 13 1.1 pooka * 1. Redistributions of source code must retain the above copyright 14 1.1 pooka * notice, this list of conditions and the following disclaimer. 15 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 pooka * notice, this list of conditions and the following disclaimer in the 17 1.1 pooka * documentation and/or other materials provided with the distribution. 18 1.1 pooka * 19 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 pooka * SUCH DAMAGE. 30 1.1 pooka */ 31 1.1 pooka 32 1.1 pooka #include <sys/cdefs.h> 33 1.126 christos __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.126 2021/04/01 19:00:33 christos Exp $"); 34 1.1 pooka 35 1.1 pooka #include <sys/param.h> 36 1.102 manu #include <sys/kernel.h> 37 1.1 pooka #include <sys/mount.h> 38 1.1 pooka #include <sys/extattr.h> 39 1.1 pooka #include <sys/queue.h> 40 1.1 pooka #include <sys/vnode.h> 41 1.1 pooka #include <sys/dirent.h> 42 1.1 pooka #include <sys/kauth.h> 43 1.47 ad #include <sys/proc.h> 44 1.80 rumble #include <sys/module.h> 45 1.84 pooka #include <sys/kthread.h> 46 1.1 pooka 47 1.99 manu #include <uvm/uvm.h> 48 1.99 manu 49 1.68 pooka #include <dev/putter/putter_sys.h> 50 1.1 pooka 51 1.78 dholland #include <miscfs/genfs/genfs.h> 52 1.78 dholland 53 1.1 pooka #include <fs/puffs/puffs_msgif.h> 54 1.1 pooka #include <fs/puffs/puffs_sys.h> 55 1.1 pooka 56 1.66 pooka #include <lib/libkern/libkern.h> 57 1.66 pooka 58 1.38 pooka #include <nfs/nfsproto.h> /* for fh sizes */ 59 1.38 pooka 60 1.81 jmcneill MODULE(MODULE_CLASS_VFS, puffs, "putter"); 61 1.80 rumble 62 1.73 pooka VFS_PROTOS(puffs_vfsop); 63 1.1 pooka 64 1.66 pooka static struct putter_ops puffs_putter = { 65 1.66 pooka .pop_getout = puffs_msgif_getout, 66 1.66 pooka .pop_releaseout = puffs_msgif_releaseout, 67 1.66 pooka .pop_waitcount = puffs_msgif_waitcount, 68 1.66 pooka .pop_dispatch = puffs_msgif_dispatch, 69 1.66 pooka .pop_close = puffs_msgif_close, 70 1.66 pooka }; 71 1.66 pooka 72 1.114 hannken static const struct genfs_ops puffs_genfsops = { 73 1.114 hannken .gop_size = puffs_gop_size, 74 1.114 hannken .gop_write = genfs_gop_write, 75 1.114 hannken .gop_markupdate = puffs_gop_markupdate, 76 1.114 hannken #if 0 77 1.114 hannken .gop_alloc, should ask userspace 78 1.114 hannken #endif 79 1.121 chs .gop_putrange = genfs_gop_putrange, 80 1.114 hannken }; 81 1.114 hannken 82 1.92 pooka /* 83 1.92 pooka * Try to ensure data structures used by the puffs protocol 84 1.92 pooka * do not unexpectedly change. 85 1.92 pooka */ 86 1.107 pooka #if defined(__i386__) && defined(__ELF__) 87 1.92 pooka CTASSERT(sizeof(struct puffs_kargs) == 3928); 88 1.92 pooka CTASSERT(sizeof(struct vattr) == 136); 89 1.92 pooka CTASSERT(sizeof(struct puffs_req) == 44); 90 1.92 pooka #endif 91 1.92 pooka 92 1.1 pooka int 93 1.73 pooka puffs_vfsop_mount(struct mount *mp, const char *path, void *data, 94 1.73 pooka size_t *data_len) 95 1.1 pooka { 96 1.22 pooka struct puffs_mount *pmp = NULL; 97 1.34 pooka struct puffs_kargs *args; 98 1.51 pooka char fstype[_VFS_NAMELEN]; 99 1.51 pooka char *p; 100 1.22 pooka int error = 0, i; 101 1.71 pooka pid_t mntpid = curlwp->l_proc->p_pid; 102 1.1 pooka 103 1.110 maxv if (data == NULL) 104 1.110 maxv return EINVAL; 105 1.48 dsl if (*data_len < sizeof *args) 106 1.48 dsl return EINVAL; 107 1.48 dsl 108 1.1 pooka if (mp->mnt_flag & MNT_GETARGS) { 109 1.1 pooka pmp = MPTOPUFFSMP(mp); 110 1.48 dsl *(struct puffs_kargs *)data = pmp->pmp_args; 111 1.48 dsl *data_len = sizeof *args; 112 1.48 dsl return 0; 113 1.1 pooka } 114 1.1 pooka 115 1.1 pooka /* update is not supported currently */ 116 1.1 pooka if (mp->mnt_flag & MNT_UPDATE) 117 1.1 pooka return EOPNOTSUPP; 118 1.1 pooka 119 1.70 pooka args = (struct puffs_kargs *)data; 120 1.17 pooka 121 1.89 pooka if (args->pa_vers != PUFFSVERSION) { 122 1.64 pooka printf("puffs_mount: development version mismatch: " 123 1.89 pooka "kernel %d, lib %d\n", PUFFSVERSION, args->pa_vers); 124 1.17 pooka error = EINVAL; 125 1.17 pooka goto out; 126 1.17 pooka } 127 1.1 pooka 128 1.54 pooka if ((args->pa_flags & ~PUFFS_KFLAG_MASK) != 0) { 129 1.54 pooka printf("puffs_mount: invalid KFLAGs 0x%x\n", args->pa_flags); 130 1.54 pooka error = EINVAL; 131 1.54 pooka goto out; 132 1.54 pooka } 133 1.54 pooka if ((args->pa_fhflags & ~PUFFS_FHFLAG_MASK) != 0) { 134 1.54 pooka printf("puffs_mount: invalid FHFLAGs 0x%x\n", args->pa_fhflags); 135 1.54 pooka error = EINVAL; 136 1.54 pooka goto out; 137 1.54 pooka } 138 1.54 pooka 139 1.91 pooka for (i = 0; i < __arraycount(args->pa_spare); i++) { 140 1.91 pooka if (args->pa_spare[i] != 0) { 141 1.91 pooka printf("puffs_mount: pa_spare[%d] = 0x%x\n", 142 1.91 pooka i, args->pa_spare[i]); 143 1.91 pooka error = EINVAL; 144 1.91 pooka goto out; 145 1.91 pooka } 146 1.91 pooka } 147 1.91 pooka 148 1.54 pooka /* use dummy value for passthrough */ 149 1.54 pooka if (args->pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) 150 1.54 pooka args->pa_fhsize = sizeof(struct fid); 151 1.8 pooka 152 1.38 pooka /* sanitize file handle length */ 153 1.38 pooka if (PUFFS_TOFHSIZE(args->pa_fhsize) > FHANDLE_SIZE_MAX) { 154 1.38 pooka printf("puffs_mount: handle size %zu too large\n", 155 1.38 pooka args->pa_fhsize); 156 1.38 pooka error = EINVAL; 157 1.38 pooka goto out; 158 1.38 pooka } 159 1.38 pooka /* sanity check file handle max sizes */ 160 1.38 pooka if (args->pa_fhsize && args->pa_fhflags & PUFFS_FHFLAG_PROTOMASK) { 161 1.38 pooka size_t kfhsize = PUFFS_TOFHSIZE(args->pa_fhsize); 162 1.38 pooka 163 1.38 pooka if (args->pa_fhflags & PUFFS_FHFLAG_NFSV2) { 164 1.38 pooka if (NFSX_FHTOOBIG_P(kfhsize, 0)) { 165 1.38 pooka printf("puffs_mount: fhsize larger than " 166 1.38 pooka "NFSv2 max %d\n", 167 1.38 pooka PUFFS_FROMFHSIZE(NFSX_V2FH)); 168 1.38 pooka error = EINVAL; 169 1.38 pooka goto out; 170 1.38 pooka } 171 1.38 pooka } 172 1.38 pooka 173 1.38 pooka if (args->pa_fhflags & PUFFS_FHFLAG_NFSV3) { 174 1.38 pooka if (NFSX_FHTOOBIG_P(kfhsize, 1)) { 175 1.38 pooka printf("puffs_mount: fhsize larger than " 176 1.38 pooka "NFSv3 max %d\n", 177 1.38 pooka PUFFS_FROMFHSIZE(NFSX_V3FHMAX)); 178 1.38 pooka error = EINVAL; 179 1.38 pooka goto out; 180 1.38 pooka } 181 1.38 pooka } 182 1.38 pooka } 183 1.38 pooka 184 1.51 pooka /* don't allow non-printing characters (like my sweet umlauts.. snif) */ 185 1.51 pooka args->pa_typename[sizeof(args->pa_typename)-1] = '\0'; 186 1.51 pooka for (p = args->pa_typename; *p; p++) 187 1.51 pooka if (*p < ' ' || *p > '~') 188 1.51 pooka *p = '.'; 189 1.51 pooka 190 1.51 pooka args->pa_mntfromname[sizeof(args->pa_mntfromname)-1] = '\0'; 191 1.51 pooka for (p = args->pa_mntfromname; *p; p++) 192 1.51 pooka if (*p < ' ' || *p > '~') 193 1.51 pooka *p = '.'; 194 1.51 pooka 195 1.1 pooka /* build real name */ 196 1.51 pooka (void)strlcpy(fstype, PUFFS_TYPEPREFIX, sizeof(fstype)); 197 1.51 pooka (void)strlcat(fstype, args->pa_typename, sizeof(fstype)); 198 1.1 pooka 199 1.1 pooka /* inform user server if it got the max request size it wanted */ 200 1.63 pooka if (args->pa_maxmsglen == 0 || args->pa_maxmsglen > PUFFS_MSG_MAXSIZE) 201 1.63 pooka args->pa_maxmsglen = PUFFS_MSG_MAXSIZE; 202 1.63 pooka else if (args->pa_maxmsglen < 2*PUFFS_MSGSTRUCT_MAX) 203 1.63 pooka args->pa_maxmsglen = 2*PUFFS_MSGSTRUCT_MAX; 204 1.63 pooka 205 1.51 pooka (void)strlcpy(args->pa_typename, fstype, sizeof(args->pa_typename)); 206 1.1 pooka 207 1.51 pooka error = set_statvfs_info(path, UIO_USERSPACE, args->pa_mntfromname, 208 1.71 pooka UIO_SYSSPACE, fstype, mp, curlwp); 209 1.1 pooka if (error) 210 1.17 pooka goto out; 211 1.10 pooka mp->mnt_stat.f_iosize = DEV_BSIZE; 212 1.94 pooka mp->mnt_stat.f_namemax = args->pa_svfsb.f_namemax; 213 1.1 pooka 214 1.42 pooka /* 215 1.42 pooka * We can't handle the VFS_STATVFS() mount_domount() does 216 1.42 pooka * after VFS_MOUNT() because we'd deadlock, so handle it 217 1.42 pooka * here already. 218 1.42 pooka */ 219 1.122 christos struct statvfs *sb = STATVFSBUF_GET(); 220 1.122 christos puffs_statvfs_to_statvfs(&args->pa_svfsb, sb); 221 1.122 christos copy_statvfs_info(sb, mp); 222 1.122 christos STATVFSBUF_PUT(sb); 223 1.122 christos 224 1.122 christos statvfs_to_puffs_statvfs(&mp->mnt_stat, &args->pa_svfsb); 225 1.42 pooka 226 1.99 manu KASSERT(curlwp != uvm.pagedaemon_lwp); 227 1.70 pooka pmp = kmem_zalloc(sizeof(struct puffs_mount), KM_SLEEP); 228 1.1 pooka 229 1.6 pooka mp->mnt_fs_bshift = DEV_BSHIFT; 230 1.6 pooka mp->mnt_dev_bshift = DEV_BSHIFT; 231 1.6 pooka mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */ 232 1.1 pooka mp->mnt_data = pmp; 233 1.6 pooka 234 1.87 pooka #if 0 235 1.87 pooka /* 236 1.87 pooka * XXX: puffs code is MPSAFE. However, VFS really isn't. 237 1.87 pooka * Currently, there is nothing which protects an inode from 238 1.87 pooka * reclaim while there are threads inside the file system. 239 1.87 pooka * This means that in the event of a server crash, an MPSAFE 240 1.87 pooka * mount is likely to end up accessing invalid memory. For the 241 1.87 pooka * non-mpsafe case, the kernel lock, general structure of 242 1.87 pooka * puffs and pmp_refcount protect the threads during escape. 243 1.87 pooka * 244 1.87 pooka * Fixing this will require: 245 1.87 pooka * a) fixing vfs 246 1.87 pooka * OR 247 1.87 pooka * b) adding a small sleep to puffs_msgif_close() between 248 1.87 pooka * userdead() and dounmount(). 249 1.87 pooka * (well, this isn't really a fix, but would solve 250 1.87 pooka * 99.999% of the race conditions). 251 1.87 pooka * 252 1.87 pooka * Also, in the event of "b", unmount -f should be used, 253 1.87 pooka * like with any other file system, sparingly and only when 254 1.87 pooka * it is "known" to be safe. 255 1.87 pooka */ 256 1.87 pooka mp->mnt_iflags |= IMNT_MPSAFE; 257 1.87 pooka #endif 258 1.87 pooka 259 1.1 pooka pmp->pmp_status = PUFFSTAT_MOUNTING; 260 1.1 pooka pmp->pmp_mp = mp; 261 1.63 pooka pmp->pmp_msg_maxsize = args->pa_maxmsglen; 262 1.17 pooka pmp->pmp_args = *args; 263 1.1 pooka 264 1.1 pooka /* 265 1.1 pooka * Inform the fileops processing code that we have a mountpoint. 266 1.1 pooka * If it doesn't know about anyone with our pid/fd having the 267 1.1 pooka * device open, punt 268 1.1 pooka */ 269 1.66 pooka if ((pmp->pmp_pi 270 1.66 pooka = putter_attach(mntpid, args->pa_fd, pmp, &puffs_putter)) == NULL) { 271 1.17 pooka error = ENOENT; 272 1.17 pooka goto out; 273 1.1 pooka } 274 1.1 pooka 275 1.42 pooka /* XXX: check parameters */ 276 1.42 pooka pmp->pmp_root_cookie = args->pa_root_cookie; 277 1.118 christos switch (args->pa_root_vtype) { 278 1.118 christos case VNON: case VREG: case VDIR: case VBLK: 279 1.118 christos case VCHR: case VLNK: case VSOCK: case VFIFO: 280 1.118 christos break; 281 1.118 christos default: 282 1.118 christos error = EINVAL; 283 1.118 christos goto out; 284 1.118 christos } 285 1.42 pooka pmp->pmp_root_vtype = args->pa_root_vtype; 286 1.118 christos 287 1.118 christos if (args->pa_root_vsize < 0) { 288 1.118 christos error = EINVAL; 289 1.118 christos goto out; 290 1.118 christos } 291 1.42 pooka pmp->pmp_root_vsize = args->pa_root_vsize; 292 1.118 christos 293 1.42 pooka pmp->pmp_root_rdev = args->pa_root_rdev; 294 1.93 pooka pmp->pmp_docompat = args->pa_time32; 295 1.42 pooka 296 1.31 pooka mutex_init(&pmp->pmp_lock, MUTEX_DEFAULT, IPL_NONE); 297 1.84 pooka mutex_init(&pmp->pmp_sopmtx, MUTEX_DEFAULT, IPL_NONE); 298 1.63 pooka cv_init(&pmp->pmp_msg_waiter_cv, "puffsget"); 299 1.41 pooka cv_init(&pmp->pmp_refcount_cv, "puffsref"); 300 1.31 pooka cv_init(&pmp->pmp_unmounting_cv, "puffsum"); 301 1.84 pooka cv_init(&pmp->pmp_sopcv, "puffsop"); 302 1.63 pooka TAILQ_INIT(&pmp->pmp_msg_touser); 303 1.63 pooka TAILQ_INIT(&pmp->pmp_msg_replywait); 304 1.102 manu TAILQ_INIT(&pmp->pmp_sopfastreqs); 305 1.105 manu TAILQ_INIT(&pmp->pmp_sopnodereqs); 306 1.84 pooka 307 1.84 pooka if ((error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, 308 1.84 pooka puffs_sop_thread, pmp, NULL, "puffsop")) != 0) 309 1.84 pooka goto out; 310 1.84 pooka pmp->pmp_sopthrcount = 1; 311 1.1 pooka 312 1.1 pooka DPRINTF(("puffs_mount: mount point at %p, puffs specific at %p\n", 313 1.1 pooka mp, MPTOPUFFSMP(mp))); 314 1.1 pooka 315 1.1 pooka vfs_getnewfsid(mp); 316 1.1 pooka 317 1.17 pooka out: 318 1.84 pooka if (error && pmp && pmp->pmp_pi) 319 1.84 pooka putter_detach(pmp->pmp_pi); 320 1.22 pooka if (error && pmp) 321 1.70 pooka kmem_free(pmp, sizeof(struct puffs_mount)); 322 1.17 pooka return error; 323 1.1 pooka } 324 1.1 pooka 325 1.1 pooka int 326 1.73 pooka puffs_vfsop_start(struct mount *mp, int flags) 327 1.1 pooka { 328 1.42 pooka struct puffs_mount *pmp = MPTOPUFFSMP(mp); 329 1.1 pooka 330 1.42 pooka KASSERT(pmp->pmp_status == PUFFSTAT_MOUNTING); 331 1.1 pooka pmp->pmp_status = PUFFSTAT_RUNNING; 332 1.1 pooka 333 1.1 pooka return 0; 334 1.1 pooka } 335 1.1 pooka 336 1.1 pooka int 337 1.73 pooka puffs_vfsop_unmount(struct mount *mp, int mntflags) 338 1.1 pooka { 339 1.63 pooka PUFFS_MSG_VARS(vfs, unmount); 340 1.1 pooka struct puffs_mount *pmp; 341 1.1 pooka int error, force; 342 1.1 pooka 343 1.1 pooka error = 0; 344 1.1 pooka force = mntflags & MNT_FORCE; 345 1.1 pooka pmp = MPTOPUFFSMP(mp); 346 1.1 pooka 347 1.1 pooka DPRINTF(("puffs_unmount: detach filesystem from vfs, current " 348 1.1 pooka "status 0x%x\n", pmp->pmp_status)); 349 1.1 pooka 350 1.1 pooka /* 351 1.1 pooka * flush all the vnodes. VOP_RECLAIM() takes care that the 352 1.1 pooka * root vnode does not get flushed until unmount. The 353 1.1 pooka * userspace root node cookie is stored in the mount 354 1.1 pooka * structure, so we can always re-instantiate a root vnode, 355 1.1 pooka * should userspace unmount decide it doesn't want to 356 1.1 pooka * cooperate. 357 1.1 pooka */ 358 1.1 pooka error = vflush(mp, NULLVP, force ? FORCECLOSE : 0); 359 1.1 pooka if (error) 360 1.1 pooka goto out; 361 1.1 pooka 362 1.1 pooka /* 363 1.1 pooka * If we are not DYING, we should ask userspace's opinion 364 1.1 pooka * about the situation 365 1.1 pooka */ 366 1.31 pooka mutex_enter(&pmp->pmp_lock); 367 1.1 pooka if (pmp->pmp_status != PUFFSTAT_DYING) { 368 1.16 pooka pmp->pmp_unmounting = 1; 369 1.31 pooka mutex_exit(&pmp->pmp_lock); 370 1.16 pooka 371 1.63 pooka PUFFS_MSG_ALLOC(vfs, unmount); 372 1.69 pooka puffs_msg_setinfo(park_unmount, 373 1.69 pooka PUFFSOP_VFS, PUFFS_VFS_UNMOUNT, NULL); 374 1.63 pooka unmount_msg->pvfsr_flags = mntflags; 375 1.63 pooka 376 1.69 pooka PUFFS_MSG_ENQUEUEWAIT(pmp, park_unmount, error); 377 1.63 pooka PUFFS_MSG_RELEASE(unmount); 378 1.16 pooka 379 1.60 pooka error = checkerr(pmp, error, __func__); 380 1.16 pooka DPRINTF(("puffs_unmount: error %d force %d\n", error, force)); 381 1.16 pooka 382 1.31 pooka mutex_enter(&pmp->pmp_lock); 383 1.16 pooka pmp->pmp_unmounting = 0; 384 1.31 pooka cv_broadcast(&pmp->pmp_unmounting_cv); 385 1.1 pooka } 386 1.1 pooka 387 1.1 pooka /* 388 1.1 pooka * if userspace cooperated or we really need to die, 389 1.1 pooka * screw what userland thinks and just die. 390 1.1 pooka */ 391 1.1 pooka if (error == 0 || force) { 392 1.84 pooka struct puffs_sopreq *psopr; 393 1.84 pooka 394 1.26 pooka /* tell waiters & other resources to go unwait themselves */ 395 1.26 pooka puffs_userdead(pmp); 396 1.66 pooka putter_detach(pmp->pmp_pi); 397 1.26 pooka 398 1.26 pooka /* 399 1.41 pooka * Wait until there are no more users for the mount resource. 400 1.41 pooka * Notice that this is hooked against transport_close 401 1.41 pooka * and return from touser. In an ideal world, it would 402 1.41 pooka * be hooked against final return from all operations. 403 1.41 pooka * But currently it works well enough, since nobody 404 1.41 pooka * does weird blocking voodoo after return from touser(). 405 1.26 pooka */ 406 1.41 pooka while (pmp->pmp_refcount != 0) 407 1.41 pooka cv_wait(&pmp->pmp_refcount_cv, &pmp->pmp_lock); 408 1.31 pooka mutex_exit(&pmp->pmp_lock); 409 1.26 pooka 410 1.84 pooka /* 411 1.84 pooka * Release kernel thread now that there is nothing 412 1.84 pooka * it would be wanting to lock. 413 1.84 pooka */ 414 1.99 manu KASSERT(curlwp != uvm.pagedaemon_lwp); 415 1.84 pooka psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP); 416 1.85 pooka psopr->psopr_sopreq = PUFFS_SOPREQSYS_EXIT; 417 1.84 pooka mutex_enter(&pmp->pmp_sopmtx); 418 1.86 pooka if (pmp->pmp_sopthrcount == 0) { 419 1.86 pooka mutex_exit(&pmp->pmp_sopmtx); 420 1.86 pooka kmem_free(psopr, sizeof(*psopr)); 421 1.86 pooka mutex_enter(&pmp->pmp_sopmtx); 422 1.86 pooka KASSERT(pmp->pmp_sopthrcount == 0); 423 1.86 pooka } else { 424 1.102 manu TAILQ_INSERT_TAIL(&pmp->pmp_sopfastreqs, 425 1.86 pooka psopr, psopr_entries); 426 1.86 pooka cv_signal(&pmp->pmp_sopcv); 427 1.86 pooka } 428 1.84 pooka while (pmp->pmp_sopthrcount > 0) 429 1.84 pooka cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx); 430 1.84 pooka mutex_exit(&pmp->pmp_sopmtx); 431 1.84 pooka 432 1.26 pooka /* free resources now that we hopefully have no waiters left */ 433 1.41 pooka cv_destroy(&pmp->pmp_unmounting_cv); 434 1.41 pooka cv_destroy(&pmp->pmp_refcount_cv); 435 1.63 pooka cv_destroy(&pmp->pmp_msg_waiter_cv); 436 1.84 pooka cv_destroy(&pmp->pmp_sopcv); 437 1.31 pooka mutex_destroy(&pmp->pmp_lock); 438 1.84 pooka mutex_destroy(&pmp->pmp_sopmtx); 439 1.31 pooka 440 1.70 pooka kmem_free(pmp, sizeof(struct puffs_mount)); 441 1.1 pooka error = 0; 442 1.16 pooka } else { 443 1.31 pooka mutex_exit(&pmp->pmp_lock); 444 1.1 pooka } 445 1.1 pooka 446 1.1 pooka out: 447 1.2 pooka DPRINTF(("puffs_unmount: return %d\n", error)); 448 1.1 pooka return error; 449 1.1 pooka } 450 1.1 pooka 451 1.1 pooka /* 452 1.1 pooka * This doesn't need to travel to userspace 453 1.1 pooka */ 454 1.1 pooka int 455 1.124 ad puffs_vfsop_root(struct mount *mp, int lktype, struct vnode **vpp) 456 1.1 pooka { 457 1.45 pooka struct puffs_mount *pmp = MPTOPUFFSMP(mp); 458 1.59 pooka int rv; 459 1.1 pooka 460 1.114 hannken rv = puffs_cookie2vnode(pmp, pmp->pmp_root_cookie, vpp); 461 1.59 pooka KASSERT(rv != PUFFS_NOSUCHCOOKIE); 462 1.114 hannken if (rv != 0) 463 1.114 hannken return rv; 464 1.124 ad rv = vn_lock(*vpp, lktype); 465 1.114 hannken if (rv != 0) { 466 1.114 hannken vrele(*vpp); 467 1.114 hannken *vpp = NULL; 468 1.114 hannken return rv; 469 1.114 hannken } 470 1.114 hannken return 0; 471 1.1 pooka } 472 1.1 pooka 473 1.1 pooka int 474 1.73 pooka puffs_vfsop_statvfs(struct mount *mp, struct statvfs *sbp) 475 1.1 pooka { 476 1.63 pooka PUFFS_MSG_VARS(vfs, statvfs); 477 1.1 pooka struct puffs_mount *pmp; 478 1.1 pooka int error = 0; 479 1.1 pooka 480 1.1 pooka pmp = MPTOPUFFSMP(mp); 481 1.1 pooka 482 1.1 pooka /* 483 1.1 pooka * If we are mounting, it means that the userspace counterpart 484 1.1 pooka * is calling mount(2), but mount(2) also calls statvfs. So 485 1.1 pooka * requesting statvfs from userspace would mean a deadlock. 486 1.1 pooka * Compensate. 487 1.1 pooka */ 488 1.87 pooka if (__predict_false(pmp->pmp_status == PUFFSTAT_MOUNTING)) 489 1.1 pooka return EINPROGRESS; 490 1.1 pooka 491 1.63 pooka PUFFS_MSG_ALLOC(vfs, statvfs); 492 1.69 pooka puffs_msg_setinfo(park_statvfs, PUFFSOP_VFS, PUFFS_VFS_STATVFS, NULL); 493 1.1 pooka 494 1.69 pooka PUFFS_MSG_ENQUEUEWAIT(pmp, park_statvfs, error); 495 1.60 pooka error = checkerr(pmp, error, __func__); 496 1.63 pooka statvfs_msg->pvfsr_sb.f_iosize = DEV_BSIZE; 497 1.10 pooka 498 1.1 pooka /* 499 1.1 pooka * Try to produce a sensible result even in the event 500 1.1 pooka * of userspace error. 501 1.1 pooka * 502 1.1 pooka * XXX: cache the copy in non-error case 503 1.1 pooka */ 504 1.126 christos if (!error) { 505 1.126 christos puffs_statvfs_to_statvfs(&statvfs_msg->pvfsr_sb, sbp); 506 1.126 christos } 507 1.123 christos copy_statvfs_info(sbp, mp); 508 1.1 pooka if (!error) { 509 1.122 christos statvfs_to_puffs_statvfs(sbp, &statvfs_msg->pvfsr_sb); 510 1.1 pooka } 511 1.1 pooka 512 1.63 pooka PUFFS_MSG_RELEASE(statvfs); 513 1.14 pooka return error; 514 1.1 pooka } 515 1.1 pooka 516 1.111 christos static bool 517 1.111 christos pageflush_selector(void *cl, struct vnode *vp) 518 1.111 christos { 519 1.120 riastrad 520 1.120 riastrad KASSERT(mutex_owned(vp->v_interlock)); 521 1.120 riastrad 522 1.113 christos return vp->v_type == VREG && 523 1.125 ad !(LIST_EMPTY(&vp->v_dirtyblkhd) && 524 1.125 ad (vp->v_iflag & VI_ONWORKLST) == 0); 525 1.125 ad 526 1.111 christos } 527 1.111 christos 528 1.26 pooka static int 529 1.83 pooka pageflush(struct mount *mp, kauth_cred_t cred, int waitfor) 530 1.1 pooka { 531 1.26 pooka struct puffs_node *pn; 532 1.108 hannken struct vnode *vp; 533 1.108 hannken struct vnode_iterator *marker; 534 1.97 manu int error, rv, fsyncwait; 535 1.1 pooka 536 1.18 pooka error = 0; 537 1.97 manu fsyncwait = (waitfor == MNT_WAIT) ? FSYNC_WAIT : 0; 538 1.18 pooka 539 1.18 pooka /* 540 1.24 pooka * Sync all cached data from regular vnodes (which are not 541 1.24 pooka * currently locked, see below). After this we call VFS_SYNC 542 1.24 pooka * for the fs server, which should handle data and metadata for 543 1.24 pooka * all the nodes it knows to exist. 544 1.18 pooka */ 545 1.108 hannken vfs_vnode_iterator_init(mp, &marker); 546 1.111 christos while ((vp = vfs_vnode_iterator_next(marker, pageflush_selector, 547 1.111 christos NULL))) 548 1.111 christos { 549 1.21 pooka /* 550 1.21 pooka * Here we try to get a reference to the vnode and to 551 1.21 pooka * lock it. This is mostly cargo-culted, but I will 552 1.21 pooka * offer an explanation to why I believe this might 553 1.21 pooka * actually do the right thing. 554 1.21 pooka * 555 1.21 pooka * If the vnode is a goner, we quite obviously don't need 556 1.21 pooka * to sync it. 557 1.21 pooka * 558 1.21 pooka * If the vnode was busy, we don't need to sync it because 559 1.21 pooka * this is never called with MNT_WAIT except from 560 1.21 pooka * dounmount(), when we are wait-flushing all the dirty 561 1.21 pooka * vnodes through other routes in any case. So there, 562 1.21 pooka * sync() doesn't actually sync. Happy now? 563 1.21 pooka */ 564 1.108 hannken error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT); 565 1.108 hannken if (error) { 566 1.108 hannken vrele(vp); 567 1.108 hannken continue; 568 1.108 hannken } 569 1.108 hannken pn = VPTOPP(vp); 570 1.83 pooka /* hmm.. is the FAF thing entirely sensible? */ 571 1.83 pooka if (waitfor == MNT_LAZY) { 572 1.96 rmind mutex_enter(vp->v_interlock); 573 1.83 pooka pn->pn_stat |= PNODE_FAF; 574 1.96 rmind mutex_exit(vp->v_interlock); 575 1.30 pooka } 576 1.97 manu rv = VOP_FSYNC(vp, cred, fsyncwait, 0, 0); 577 1.83 pooka if (waitfor == MNT_LAZY) { 578 1.96 rmind mutex_enter(vp->v_interlock); 579 1.83 pooka pn->pn_stat &= ~PNODE_FAF; 580 1.96 rmind mutex_exit(vp->v_interlock); 581 1.26 pooka } 582 1.21 pooka if (rv) 583 1.18 pooka error = rv; 584 1.18 pooka vput(vp); 585 1.18 pooka } 586 1.108 hannken vfs_vnode_iterator_destroy(marker); 587 1.18 pooka 588 1.26 pooka return error; 589 1.26 pooka } 590 1.26 pooka 591 1.26 pooka int 592 1.73 pooka puffs_vfsop_sync(struct mount *mp, int waitfor, struct kauth_cred *cred) 593 1.26 pooka { 594 1.63 pooka PUFFS_MSG_VARS(vfs, sync); 595 1.62 pooka struct puffs_mount *pmp = MPTOPUFFSMP(mp); 596 1.26 pooka int error, rv; 597 1.26 pooka 598 1.83 pooka error = pageflush(mp, cred, waitfor); 599 1.26 pooka 600 1.18 pooka /* sync fs */ 601 1.63 pooka PUFFS_MSG_ALLOC(vfs, sync); 602 1.63 pooka sync_msg->pvfsr_waitfor = waitfor; 603 1.63 pooka puffs_credcvt(&sync_msg->pvfsr_cred, cred); 604 1.69 pooka puffs_msg_setinfo(park_sync, PUFFSOP_VFS, PUFFS_VFS_SYNC, NULL); 605 1.1 pooka 606 1.69 pooka PUFFS_MSG_ENQUEUEWAIT(pmp, park_sync, rv); 607 1.62 pooka rv = checkerr(pmp, rv, __func__); 608 1.18 pooka if (rv) 609 1.18 pooka error = rv; 610 1.1 pooka 611 1.63 pooka PUFFS_MSG_RELEASE(sync); 612 1.1 pooka return error; 613 1.1 pooka } 614 1.1 pooka 615 1.1 pooka int 616 1.124 ad puffs_vfsop_fhtovp(struct mount *mp, struct fid *fhp, int lktype, 617 1.124 ad struct vnode **vpp) 618 1.1 pooka { 619 1.63 pooka PUFFS_MSG_VARS(vfs, fhtonode); 620 1.33 pooka struct puffs_mount *pmp = MPTOPUFFSMP(mp); 621 1.33 pooka struct vnode *vp; 622 1.54 pooka void *fhdata; 623 1.54 pooka size_t argsize, fhlen; 624 1.33 pooka int error; 625 1.33 pooka 626 1.38 pooka if (pmp->pmp_args.pa_fhsize == 0) 627 1.33 pooka return EOPNOTSUPP; 628 1.33 pooka 629 1.54 pooka if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) { 630 1.54 pooka fhlen = fhp->fid_len; 631 1.54 pooka fhdata = fhp; 632 1.39 pooka } else { 633 1.54 pooka fhlen = PUFFS_FROMFHSIZE(fhp->fid_len); 634 1.54 pooka fhdata = fhp->fid_data; 635 1.54 pooka 636 1.54 pooka if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) { 637 1.54 pooka if (pmp->pmp_args.pa_fhsize < fhlen) 638 1.54 pooka return EINVAL; 639 1.54 pooka } else { 640 1.54 pooka if (pmp->pmp_args.pa_fhsize != fhlen) 641 1.54 pooka return EINVAL; 642 1.54 pooka } 643 1.39 pooka } 644 1.33 pooka 645 1.63 pooka argsize = sizeof(struct puffs_vfsmsg_fhtonode) + fhlen; 646 1.75 pooka puffs_msgmem_alloc(argsize, &park_fhtonode, (void *)&fhtonode_msg, 1); 647 1.63 pooka fhtonode_msg->pvfsr_dsize = fhlen; 648 1.63 pooka memcpy(fhtonode_msg->pvfsr_data, fhdata, fhlen); 649 1.69 pooka puffs_msg_setinfo(park_fhtonode, PUFFSOP_VFS, PUFFS_VFS_FHTOVP, NULL); 650 1.33 pooka 651 1.69 pooka PUFFS_MSG_ENQUEUEWAIT(pmp, park_fhtonode, error); 652 1.60 pooka error = checkerr(pmp, error, __func__); 653 1.33 pooka if (error) 654 1.38 pooka goto out; 655 1.33 pooka 656 1.114 hannken error = puffs_getvnode(mp, fhtonode_msg->pvfsr_fhcookie, 657 1.114 hannken fhtonode_msg->pvfsr_vtype, fhtonode_msg->pvfsr_size, 658 1.114 hannken fhtonode_msg->pvfsr_rdev, &vp); 659 1.114 hannken if (error) 660 1.59 pooka goto out; 661 1.124 ad vn_lock(vp, lktype | LK_RETRY); 662 1.1 pooka 663 1.33 pooka *vpp = vp; 664 1.38 pooka out: 665 1.63 pooka puffs_msgmem_release(park_fhtonode); 666 1.38 pooka return error; 667 1.1 pooka } 668 1.1 pooka 669 1.1 pooka int 670 1.73 pooka puffs_vfsop_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) 671 1.1 pooka { 672 1.63 pooka PUFFS_MSG_VARS(vfs, nodetofh); 673 1.33 pooka struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); 674 1.54 pooka size_t argsize, fhlen; 675 1.33 pooka int error; 676 1.33 pooka 677 1.38 pooka if (pmp->pmp_args.pa_fhsize == 0) 678 1.33 pooka return EOPNOTSUPP; 679 1.33 pooka 680 1.54 pooka /* if file handles are static len, we can test len immediately */ 681 1.38 pooka if (((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) == 0) 682 1.54 pooka && ((pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) == 0) 683 1.38 pooka && (PUFFS_FROMFHSIZE(*fh_size) < pmp->pmp_args.pa_fhsize)) { 684 1.38 pooka *fh_size = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize); 685 1.33 pooka return E2BIG; 686 1.33 pooka } 687 1.1 pooka 688 1.54 pooka if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) 689 1.54 pooka fhlen = *fh_size; 690 1.54 pooka else 691 1.54 pooka fhlen = PUFFS_FROMFHSIZE(*fh_size); 692 1.54 pooka 693 1.63 pooka argsize = sizeof(struct puffs_vfsmsg_nodetofh) + fhlen; 694 1.75 pooka puffs_msgmem_alloc(argsize, &park_nodetofh, (void *)&nodetofh_msg, 1); 695 1.63 pooka nodetofh_msg->pvfsr_fhcookie = VPTOPNC(vp); 696 1.63 pooka nodetofh_msg->pvfsr_dsize = fhlen; 697 1.69 pooka puffs_msg_setinfo(park_nodetofh, PUFFSOP_VFS, PUFFS_VFS_VPTOFH, NULL); 698 1.38 pooka 699 1.69 pooka PUFFS_MSG_ENQUEUEWAIT(pmp, park_nodetofh, error); 700 1.60 pooka error = checkerr(pmp, error, __func__); 701 1.54 pooka 702 1.54 pooka if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) 703 1.63 pooka fhlen = nodetofh_msg->pvfsr_dsize; 704 1.54 pooka else if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_DYNAMIC) 705 1.63 pooka fhlen = PUFFS_TOFHSIZE(nodetofh_msg->pvfsr_dsize); 706 1.54 pooka else 707 1.54 pooka fhlen = PUFFS_TOFHSIZE(pmp->pmp_args.pa_fhsize); 708 1.54 pooka 709 1.38 pooka if (error) { 710 1.38 pooka if (error == E2BIG) 711 1.54 pooka *fh_size = fhlen; 712 1.38 pooka goto out; 713 1.38 pooka } 714 1.38 pooka 715 1.54 pooka if (fhlen > FHANDLE_SIZE_MAX) { 716 1.69 pooka puffs_senderr(pmp, PUFFS_ERR_VPTOFH, E2BIG, 717 1.60 pooka "file handle too big", VPTOPNC(vp)); 718 1.58 pooka error = EPROTO; 719 1.38 pooka goto out; 720 1.38 pooka } 721 1.33 pooka 722 1.54 pooka if (*fh_size < fhlen) { 723 1.54 pooka *fh_size = fhlen; 724 1.38 pooka error = E2BIG; 725 1.38 pooka goto out; 726 1.38 pooka } 727 1.54 pooka *fh_size = fhlen; 728 1.1 pooka 729 1.38 pooka if (fhp) { 730 1.54 pooka if (pmp->pmp_args.pa_fhflags & PUFFS_FHFLAG_PASSTHROUGH) { 731 1.63 pooka memcpy(fhp, nodetofh_msg->pvfsr_data, fhlen); 732 1.54 pooka } else { 733 1.54 pooka fhp->fid_len = *fh_size; 734 1.63 pooka memcpy(fhp->fid_data, nodetofh_msg->pvfsr_data, 735 1.63 pooka nodetofh_msg->pvfsr_dsize); 736 1.54 pooka } 737 1.38 pooka } 738 1.1 pooka 739 1.38 pooka out: 740 1.63 pooka puffs_msgmem_release(park_nodetofh); 741 1.38 pooka return error; 742 1.1 pooka } 743 1.1 pooka 744 1.114 hannken int 745 1.114 hannken puffs_vfsop_loadvnode(struct mount *mp, struct vnode *vp, 746 1.114 hannken const void *key, size_t key_len, const void **new_key) 747 1.114 hannken { 748 1.114 hannken struct puffs_mount *pmp; 749 1.114 hannken struct puffs_node *pnode; 750 1.114 hannken 751 1.114 hannken KASSERT(key_len == sizeof(puffs_cookie_t)); 752 1.114 hannken 753 1.114 hannken pmp = MPTOPUFFSMP(mp); 754 1.114 hannken 755 1.114 hannken /* Allocate and initialize the pnode. */ 756 1.114 hannken pnode = pool_get(&puffs_pnpool, PR_WAITOK); 757 1.114 hannken memset(pnode, 0, sizeof(struct puffs_node)); 758 1.114 hannken 759 1.114 hannken pnode->pn_vp = vp; 760 1.114 hannken memcpy(&pnode->pn_cookie, key, key_len); 761 1.114 hannken pnode->pn_refcount = 1; 762 1.114 hannken mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE); 763 1.114 hannken mutex_init(&pnode->pn_sizemtx, MUTEX_DEFAULT, IPL_NONE); 764 1.114 hannken selinit(&pnode->pn_sel); 765 1.114 hannken vp->v_tag = VT_PUFFS; 766 1.114 hannken vp->v_type = VNON; 767 1.114 hannken vp->v_op = puffs_vnodeop_p; 768 1.114 hannken if (pnode->pn_cookie == pmp->pmp_root_cookie) 769 1.114 hannken vp->v_vflag |= VV_ROOT; 770 1.114 hannken vp->v_data = pnode; 771 1.114 hannken 772 1.114 hannken genfs_node_init(vp, &puffs_genfsops); 773 1.114 hannken uvm_vnp_setsize(vp, 0); 774 1.114 hannken 775 1.114 hannken *new_key = &pnode->pn_cookie; 776 1.114 hannken return 0; 777 1.114 hannken } 778 1.114 hannken 779 1.1 pooka void 780 1.82 cegger puffs_vfsop_init(void) 781 1.1 pooka { 782 1.1 pooka 783 1.56 pooka /* some checks depend on this */ 784 1.56 pooka KASSERT(VNOVAL == VSIZENOTSET); 785 1.56 pooka 786 1.31 pooka pool_init(&puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, 787 1.31 pooka "puffpnpl", &pool_allocator_nointr, IPL_NONE); 788 1.101 manu pool_init(&puffs_vapool, sizeof(struct vattr), 0, 0, 0, 789 1.101 manu "puffvapl", &pool_allocator_nointr, IPL_NONE); 790 1.31 pooka puffs_msgif_init(); 791 1.1 pooka } 792 1.1 pooka 793 1.1 pooka void 794 1.82 cegger puffs_vfsop_done(void) 795 1.1 pooka { 796 1.1 pooka 797 1.31 pooka puffs_msgif_destroy(); 798 1.31 pooka pool_destroy(&puffs_pnpool); 799 1.101 manu pool_destroy(&puffs_vapool); 800 1.1 pooka } 801 1.1 pooka 802 1.1 pooka int 803 1.73 pooka puffs_vfsop_snapshot(struct mount *mp, struct vnode *vp, struct timespec *ts) 804 1.1 pooka { 805 1.1 pooka 806 1.1 pooka return EOPNOTSUPP; 807 1.1 pooka } 808 1.1 pooka 809 1.88 pooka int 810 1.88 pooka puffs_vfsop_extattrctl(struct mount *mp, int cmd, struct vnode *vp, 811 1.88 pooka int attrnamespace, const char *attrname) 812 1.88 pooka { 813 1.88 pooka PUFFS_MSG_VARS(vfs, extattrctl); 814 1.88 pooka struct puffs_mount *pmp = MPTOPUFFSMP(mp); 815 1.88 pooka struct puffs_node *pnp; 816 1.88 pooka puffs_cookie_t pnc; 817 1.88 pooka int error, flags; 818 1.88 pooka 819 1.88 pooka if (vp) { 820 1.88 pooka /* doesn't make sense for puffs servers */ 821 1.88 pooka if (vp->v_mount != mp) 822 1.88 pooka return EXDEV; 823 1.88 pooka pnp = vp->v_data; 824 1.88 pooka pnc = pnp->pn_cookie; 825 1.88 pooka flags = PUFFS_EXTATTRCTL_HASNODE; 826 1.88 pooka } else { 827 1.88 pooka pnp = pnc = NULL; 828 1.88 pooka flags = 0; 829 1.88 pooka } 830 1.88 pooka 831 1.88 pooka PUFFS_MSG_ALLOC(vfs, extattrctl); 832 1.88 pooka extattrctl_msg->pvfsr_cmd = cmd; 833 1.88 pooka extattrctl_msg->pvfsr_attrnamespace = attrnamespace; 834 1.88 pooka extattrctl_msg->pvfsr_flags = flags; 835 1.88 pooka if (attrname) { 836 1.88 pooka strlcpy(extattrctl_msg->pvfsr_attrname, attrname, 837 1.88 pooka sizeof(extattrctl_msg->pvfsr_attrname)); 838 1.88 pooka extattrctl_msg->pvfsr_flags |= PUFFS_EXTATTRCTL_HASATTRNAME; 839 1.88 pooka } 840 1.88 pooka puffs_msg_setinfo(park_extattrctl, 841 1.88 pooka PUFFSOP_VFS, PUFFS_VFS_EXTATTRCTL, pnc); 842 1.88 pooka 843 1.88 pooka puffs_msg_enqueue(pmp, park_extattrctl); 844 1.88 pooka if (vp) { 845 1.88 pooka mutex_enter(&pnp->pn_mtx); 846 1.88 pooka puffs_referencenode(pnp); 847 1.88 pooka mutex_exit(&pnp->pn_mtx); 848 1.90 hannken VOP_UNLOCK(vp); 849 1.88 pooka } 850 1.88 pooka error = puffs_msg_wait2(pmp, park_extattrctl, pnp, NULL); 851 1.88 pooka PUFFS_MSG_RELEASE(extattrctl); 852 1.88 pooka if (vp) { 853 1.88 pooka puffs_releasenode(pnp); 854 1.88 pooka } 855 1.88 pooka 856 1.88 pooka return checkerr(pmp, error, __func__); 857 1.88 pooka } 858 1.88 pooka 859 1.1 pooka const struct vnodeopv_desc * const puffs_vnodeopv_descs[] = { 860 1.1 pooka &puffs_vnodeop_opv_desc, 861 1.3 pooka &puffs_specop_opv_desc, 862 1.4 pooka &puffs_fifoop_opv_desc, 863 1.12 pooka &puffs_msgop_opv_desc, 864 1.1 pooka NULL, 865 1.1 pooka }; 866 1.1 pooka 867 1.1 pooka struct vfsops puffs_vfsops = { 868 1.109 hannken .vfs_name = MOUNT_PUFFS, 869 1.109 hannken .vfs_min_mount_data = sizeof (struct puffs_kargs), 870 1.109 hannken .vfs_mount = puffs_vfsop_mount, 871 1.109 hannken .vfs_start = puffs_vfsop_start, 872 1.109 hannken .vfs_unmount = puffs_vfsop_unmount, 873 1.109 hannken .vfs_root = puffs_vfsop_root, 874 1.109 hannken .vfs_quotactl = (void *)eopnotsupp, 875 1.109 hannken .vfs_statvfs = puffs_vfsop_statvfs, 876 1.109 hannken .vfs_sync = puffs_vfsop_sync, 877 1.109 hannken .vfs_vget = (void *)eopnotsupp, 878 1.114 hannken .vfs_loadvnode = puffs_vfsop_loadvnode, 879 1.109 hannken .vfs_fhtovp = puffs_vfsop_fhtovp, 880 1.109 hannken .vfs_vptofh = puffs_vfsop_vptofh, 881 1.109 hannken .vfs_init = puffs_vfsop_init, 882 1.109 hannken .vfs_done = puffs_vfsop_done, 883 1.109 hannken .vfs_snapshot = puffs_vfsop_snapshot, 884 1.109 hannken .vfs_extattrctl = puffs_vfsop_extattrctl, 885 1.119 hannken .vfs_suspendctl = genfs_suspendctl, 886 1.109 hannken .vfs_renamelock_enter = genfs_renamelock_enter, 887 1.109 hannken .vfs_renamelock_exit = genfs_renamelock_exit, 888 1.109 hannken .vfs_fsync = (void *)eopnotsupp, 889 1.109 hannken .vfs_opv_descs = puffs_vnodeopv_descs 890 1.1 pooka }; 891 1.80 rumble 892 1.80 rumble static int 893 1.80 rumble puffs_modcmd(modcmd_t cmd, void *arg) 894 1.80 rumble { 895 1.80 rumble 896 1.80 rumble switch (cmd) { 897 1.80 rumble case MODULE_CMD_INIT: 898 1.80 rumble return vfs_attach(&puffs_vfsops); 899 1.80 rumble case MODULE_CMD_FINI: 900 1.80 rumble return vfs_detach(&puffs_vfsops); 901 1.80 rumble default: 902 1.80 rumble return ENOTTY; 903 1.80 rumble } 904 1.80 rumble } 905