1d167cf6fSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1995 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * This code is derived from software donated to Berkeley by 8df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 34df8bae1dSRodney W. Grimes * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 37c3aac50fSPeter Wemm * $FreeBSD$ 38df8bae1dSRodney W. Grimes */ 39df8bae1dSRodney W. Grimes 40df8bae1dSRodney W. Grimes /* 41df8bae1dSRodney W. Grimes * Null Layer 42df8bae1dSRodney W. Grimes * (See null_vnops.c for a description of what this does.) 43df8bae1dSRodney W. Grimes */ 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 4757b4252eSKonstantin Belousov #include <sys/fcntl.h> 48fdc0430eSMike Pritchard #include <sys/kernel.h> 49fb919e4dSMark Murray #include <sys/lock.h> 50a1c995b6SPoul-Henning Kamp #include <sys/malloc.h> 51df8bae1dSRodney W. Grimes #include <sys/mount.h> 52df8bae1dSRodney W. Grimes #include <sys/namei.h> 53fb919e4dSMark Murray #include <sys/proc.h> 54fb919e4dSMark Murray #include <sys/vnode.h> 55bf3db8aaSMartin Matuska #include <sys/jail.h> 56fb919e4dSMark Murray 5799d300a1SRuslan Ermilov #include <fs/nullfs/null.h> 58df8bae1dSRodney W. Grimes 595bb84bc8SRobert Watson static MALLOC_DEFINE(M_NULLFSMNT, "nullfs_mount", "NULLFS mount structure"); 60a1c995b6SPoul-Henning Kamp 617652131bSPoul-Henning Kamp static vfs_fhtovp_t nullfs_fhtovp; 625e8c582aSPoul-Henning Kamp static vfs_mount_t nullfs_mount; 637652131bSPoul-Henning Kamp static vfs_quotactl_t nullfs_quotactl; 647652131bSPoul-Henning Kamp static vfs_root_t nullfs_root; 657652131bSPoul-Henning Kamp static vfs_sync_t nullfs_sync; 667652131bSPoul-Henning Kamp static vfs_statfs_t nullfs_statfs; 677652131bSPoul-Henning Kamp static vfs_unmount_t nullfs_unmount; 687652131bSPoul-Henning Kamp static vfs_vget_t nullfs_vget; 697652131bSPoul-Henning Kamp static vfs_extattrctl_t nullfs_extattrctl; 709b5e8b3aSBruce Evans 71df8bae1dSRodney W. Grimes /* 72df8bae1dSRodney W. Grimes * Mount null layer 73df8bae1dSRodney W. Grimes */ 74d4b7a369SPoul-Henning Kamp static int 75dfd233edSAttilio Rao nullfs_mount(struct mount *mp) 76df8bae1dSRodney W. Grimes { 775fc9e11cSKonstantin Belousov struct vnode *lowerrootvp; 78df8bae1dSRodney W. Grimes struct vnode *nullm_rootvp; 79df8bae1dSRodney W. Grimes struct null_mount *xmp; 80930cc2dbSKonstantin Belousov struct null_node *nn; 81930cc2dbSKonstantin Belousov struct nameidata nd, *ndp; 829fcc512cSMaxime Henrion char *target; 83930cc2dbSKonstantin Belousov int error, len; 84930cc2dbSKonstantin Belousov bool isvnunlocked; 85df8bae1dSRodney W. Grimes 868da80660SBoris Popov NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); 87df8bae1dSRodney W. Grimes 8864042a76SPoul-Henning Kamp if (mp->mnt_flag & MNT_ROOTFS) 8964042a76SPoul-Henning Kamp return (EOPNOTSUPP); 909cf4c952SKonstantin Belousov 91df8bae1dSRodney W. Grimes /* 92df8bae1dSRodney W. Grimes * Update is a no-op 93df8bae1dSRodney W. Grimes */ 94df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_UPDATE) { 95ebbf93fdSCraig Rodrigues /* 96ebbf93fdSCraig Rodrigues * Only support update mounts for NFS export. 97ebbf93fdSCraig Rodrigues */ 98ebbf93fdSCraig Rodrigues if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 99ebbf93fdSCraig Rodrigues return (0); 100ebbf93fdSCraig Rodrigues else 101df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 102df8bae1dSRodney W. Grimes } 103df8bae1dSRodney W. Grimes 104df8bae1dSRodney W. Grimes /* 105df8bae1dSRodney W. Grimes * Get argument 106df8bae1dSRodney W. Grimes */ 107e3c51151SEdward Tomasz Napierala error = vfs_getopt(mp->mnt_optnew, "from", (void **)&target, &len); 108e3c51151SEdward Tomasz Napierala if (error != 0) 1099fcc512cSMaxime Henrion error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 1109fcc512cSMaxime Henrion if (error || target[len - 1] != '\0') 1119fcc512cSMaxime Henrion return (EINVAL); 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes /* 1149ce73797SPeter Holm * Unlock lower node to avoid possible deadlock. 115f85e8fc5SKATO Takenori */ 116930cc2dbSKonstantin Belousov if (mp->mnt_vnodecovered->v_op == &null_vnodeops && 1179ce73797SPeter Holm VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) { 118b249ce48SMateusz Guzik VOP_UNLOCK(mp->mnt_vnodecovered); 119930cc2dbSKonstantin Belousov isvnunlocked = true; 120930cc2dbSKonstantin Belousov } else { 121930cc2dbSKonstantin Belousov isvnunlocked = false; 122f85e8fc5SKATO Takenori } 123930cc2dbSKonstantin Belousov 124f85e8fc5SKATO Takenori /* 125df8bae1dSRodney W. Grimes * Find lower node 126df8bae1dSRodney W. Grimes */ 127930cc2dbSKonstantin Belousov ndp = &nd; 1287e1d3eefSMateusz Guzik NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target); 1293a773ad0SPoul-Henning Kamp error = namei(ndp); 130d9e9650aSKonstantin Belousov 131f85e8fc5SKATO Takenori /* 132f85e8fc5SKATO Takenori * Re-lock vnode. 133d9e9650aSKonstantin Belousov * XXXKIB This is deadlock-prone as well. 134f85e8fc5SKATO Takenori */ 135ffa43617SKonstantin Belousov if (isvnunlocked) 136cb05b60aSAttilio Rao vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 137f85e8fc5SKATO Takenori 1383a773ad0SPoul-Henning Kamp if (error) 139df8bae1dSRodney W. Grimes return (error); 140bb92cd7bSMateusz Guzik NDFREE_PNBUF(ndp); 141df8bae1dSRodney W. Grimes 142df8bae1dSRodney W. Grimes /* 143df8bae1dSRodney W. Grimes * Sanity check on lower vnode 144df8bae1dSRodney W. Grimes */ 145df8bae1dSRodney W. Grimes lowerrootvp = ndp->ni_vp; 146df8bae1dSRodney W. Grimes 147f85e8fc5SKATO Takenori /* 148f85e8fc5SKATO Takenori * Check multi null mount to avoid `lock against myself' panic. 149f85e8fc5SKATO Takenori */ 15025728e84SKonstantin Belousov if (mp->mnt_vnodecovered->v_op == &null_vnodeops) { 15125728e84SKonstantin Belousov nn = VTONULL(mp->mnt_vnodecovered); 15225728e84SKonstantin Belousov if (nn == NULL || lowerrootvp == nn->null_lowervp) { 1538da80660SBoris Popov NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 1546716c905SBoris Popov vput(lowerrootvp); 155747e9157SKATO Takenori return (EDEADLK); 156f85e8fc5SKATO Takenori } 15725728e84SKonstantin Belousov } 158f85e8fc5SKATO Takenori 159df8bae1dSRodney W. Grimes xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 1609cf4c952SKonstantin Belousov M_NULLFSMNT, M_WAITOK | M_ZERO); 161df8bae1dSRodney W. Grimes 162df8bae1dSRodney W. Grimes /* 1635fc9e11cSKonstantin Belousov * Save pointer to underlying FS and the reference to the 1645fc9e11cSKonstantin Belousov * lower root vnode. 165df8bae1dSRodney W. Grimes */ 166c746ed72SJason A. Harmening xmp->nullm_vfs = vfs_register_upper_from_vp(lowerrootvp, mp, 167c746ed72SJason A. Harmening &xmp->upper_node); 16859409cb9SJason A. Harmening if (xmp->nullm_vfs == NULL) { 16959409cb9SJason A. Harmening vput(lowerrootvp); 17059409cb9SJason A. Harmening free(xmp, M_NULLFSMNT); 17159409cb9SJason A. Harmening return (ENOENT); 17259409cb9SJason A. Harmening } 1735fc9e11cSKonstantin Belousov vref(lowerrootvp); 1745fc9e11cSKonstantin Belousov xmp->nullm_lowerrootvp = lowerrootvp; 1755fc9e11cSKonstantin Belousov mp->mnt_data = xmp; 176df8bae1dSRodney W. Grimes 177df8bae1dSRodney W. Grimes /* 1785fc9e11cSKonstantin Belousov * Make sure the node alias worked. 179df8bae1dSRodney W. Grimes */ 1805fc9e11cSKonstantin Belousov error = null_nodeget(mp, lowerrootvp, &nullm_rootvp); 1815fc9e11cSKonstantin Belousov if (error != 0) { 182c746ed72SJason A. Harmening vfs_unregister_upper(xmp->nullm_vfs, &xmp->upper_node); 1835fc9e11cSKonstantin Belousov vrele(lowerrootvp); 184dd0f9532SKonstantin Belousov free(xmp, M_NULLFSMNT); 185df8bae1dSRodney W. Grimes return (error); 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes 1885da56ddbSTor Egge if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { 1895da56ddbSTor Egge MNT_ILOCK(mp); 190df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_LOCAL; 1915da56ddbSTor Egge MNT_IUNLOCK(mp); 1925da56ddbSTor Egge } 1939cf4c952SKonstantin Belousov 1949cf4c952SKonstantin Belousov xmp->nullm_flags |= NULLM_CACHE; 195abc15156SKonstantin Belousov if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0 || 196abc15156SKonstantin Belousov (xmp->nullm_vfs->mnt_kern_flag & MNTK_NULL_NOCACHE) != 0) 1979cf4c952SKonstantin Belousov xmp->nullm_flags &= ~NULLM_CACHE; 1989cf4c952SKonstantin Belousov 199c746ed72SJason A. Harmening if ((xmp->nullm_flags & NULLM_CACHE) != 0) { 200c746ed72SJason A. Harmening vfs_register_for_notification(xmp->nullm_vfs, mp, 201c746ed72SJason A. Harmening &xmp->notify_node); 202c746ed72SJason A. Harmening } 203c746ed72SJason A. Harmening 204*0ef861e6SJason A. Harmening if (lowerrootvp == mp->mnt_vnodecovered) { 205*0ef861e6SJason A. Harmening vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE); 206*0ef861e6SJason A. Harmening lowerrootvp->v_vflag |= VV_CROSSLOCK; 207*0ef861e6SJason A. Harmening VOP_UNLOCK(lowerrootvp); 208*0ef861e6SJason A. Harmening } 209*0ef861e6SJason A. Harmening 2105da56ddbSTor Egge MNT_ILOCK(mp); 2119cf4c952SKonstantin Belousov if ((xmp->nullm_flags & NULLM_CACHE) != 0) { 21237a1046eSKonstantin Belousov mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & 2139cf4c952SKonstantin Belousov (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | 2149cf4c952SKonstantin Belousov MNTK_EXTENDED_SHARED); 2159cf4c952SKonstantin Belousov } 216aeabf8d4SMateusz Guzik mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNLOCKED_INSMNTQUE; 2174fce16e4SMateusz Guzik mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & 218f36aa2b7SKonstantin Belousov (MNTK_USES_BCACHE | MNTK_NO_IOPF | MNTK_UNMAPPED_BUFS); 2195da56ddbSTor Egge MNT_IUNLOCK(mp); 220996c772fSJohn Dyson vfs_getnewfsid(mp); 2217ab8c8c0SPoul-Henning Kamp vfs_mountedfrom(mp, target); 2225fc9e11cSKonstantin Belousov vput(nullm_rootvp); 2237ab8c8c0SPoul-Henning Kamp 2248da80660SBoris Popov NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 225df8bae1dSRodney W. Grimes mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 226df8bae1dSRodney W. Grimes return (0); 227df8bae1dSRodney W. Grimes } 228df8bae1dSRodney W. Grimes 229df8bae1dSRodney W. Grimes /* 230df8bae1dSRodney W. Grimes * Free reference to null layer 231df8bae1dSRodney W. Grimes */ 232d4b7a369SPoul-Henning Kamp static int 233dfd233edSAttilio Rao nullfs_unmount(mp, mntflags) 234df8bae1dSRodney W. Grimes struct mount *mp; 235df8bae1dSRodney W. Grimes int mntflags; 236df8bae1dSRodney W. Grimes { 237d9e9650aSKonstantin Belousov struct null_mount *mntdata; 2385fc9e11cSKonstantin Belousov int error, flags; 239df8bae1dSRodney W. Grimes 2408da80660SBoris Popov NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 241df8bae1dSRodney W. Grimes 242996c772fSJohn Dyson if (mntflags & MNT_FORCE) 243d9e9650aSKonstantin Belousov flags = FORCECLOSE; 244d9e9650aSKonstantin Belousov else 245d9e9650aSKonstantin Belousov flags = 0; 246df8bae1dSRodney W. Grimes 2475fc9e11cSKonstantin Belousov for (;;) { 2480864ef1eSIan Dowse /* There is 1 extra root vnode reference (nullm_rootvp). */ 2495fc9e11cSKonstantin Belousov error = vflush(mp, 0, flags, curthread); 2503a773ad0SPoul-Henning Kamp if (error) 251df8bae1dSRodney W. Grimes return (error); 2527ae3486eSKonstantin Belousov MNT_ILOCK(mp); 2537ae3486eSKonstantin Belousov if (mp->mnt_nvnodelistsize == 0) { 2547ae3486eSKonstantin Belousov MNT_IUNLOCK(mp); 2557ae3486eSKonstantin Belousov break; 2567ae3486eSKonstantin Belousov } 2577ae3486eSKonstantin Belousov MNT_IUNLOCK(mp); 2587ae3486eSKonstantin Belousov if ((mntflags & MNT_FORCE) == 0) 2597ae3486eSKonstantin Belousov return (EBUSY); 2607ae3486eSKonstantin Belousov } 261df8bae1dSRodney W. Grimes 262df8bae1dSRodney W. Grimes /* 263df8bae1dSRodney W. Grimes * Finally, throw away the null_mount structure 264df8bae1dSRodney W. Grimes */ 2658da80660SBoris Popov mntdata = mp->mnt_data; 2669cf4c952SKonstantin Belousov if ((mntdata->nullm_flags & NULLM_CACHE) != 0) { 267c746ed72SJason A. Harmening vfs_unregister_for_notification(mntdata->nullm_vfs, 268c746ed72SJason A. Harmening &mntdata->notify_node); 269d9e9650aSKonstantin Belousov } 270*0ef861e6SJason A. Harmening if (mntdata->nullm_lowerrootvp == mp->mnt_vnodecovered) { 271*0ef861e6SJason A. Harmening vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE); 272*0ef861e6SJason A. Harmening mp->mnt_vnodecovered->v_vflag &= ~VV_CROSSLOCK; 273*0ef861e6SJason A. Harmening VOP_UNLOCK(mp->mnt_vnodecovered); 274*0ef861e6SJason A. Harmening } 275c746ed72SJason A. Harmening vfs_unregister_upper(mntdata->nullm_vfs, &mntdata->upper_node); 2765fc9e11cSKonstantin Belousov vrele(mntdata->nullm_lowerrootvp); 27711753bd0SKevin Lo mp->mnt_data = NULL; 2784451405fSBoris Popov free(mntdata, M_NULLFSMNT); 279d9e9650aSKonstantin Belousov return (0); 280df8bae1dSRodney W. Grimes } 281df8bae1dSRodney W. Grimes 282d4b7a369SPoul-Henning Kamp static int 283dfd233edSAttilio Rao nullfs_root(mp, flags, vpp) 284df8bae1dSRodney W. Grimes struct mount *mp; 285d9b2d9f7SJeff Roberson int flags; 286df8bae1dSRodney W. Grimes struct vnode **vpp; 287df8bae1dSRodney W. Grimes { 288df8bae1dSRodney W. Grimes struct vnode *vp; 2895fc9e11cSKonstantin Belousov struct null_mount *mntdata; 2905fc9e11cSKonstantin Belousov int error; 291df8bae1dSRodney W. Grimes 2925fc9e11cSKonstantin Belousov mntdata = MOUNTTONULLMOUNT(mp); 2935fc9e11cSKonstantin Belousov NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", mp, 2945fc9e11cSKonstantin Belousov mntdata->nullm_lowerrootvp); 295df8bae1dSRodney W. Grimes 296a92a971bSMateusz Guzik error = vget(mntdata->nullm_lowerrootvp, flags); 2975fc9e11cSKonstantin Belousov if (error == 0) { 2985fc9e11cSKonstantin Belousov error = null_nodeget(mp, mntdata->nullm_lowerrootvp, &vp); 2995fc9e11cSKonstantin Belousov if (error == 0) { 300df8bae1dSRodney W. Grimes *vpp = vp; 3015fc9e11cSKonstantin Belousov } 3025fc9e11cSKonstantin Belousov } 3035fc9e11cSKonstantin Belousov return (error); 304df8bae1dSRodney W. Grimes } 305df8bae1dSRodney W. Grimes 306d4b7a369SPoul-Henning Kamp static int 307a4b07a27SJason A. Harmening nullfs_quotactl(mp, cmd, uid, arg, mp_busy) 308df8bae1dSRodney W. Grimes struct mount *mp; 309df8bae1dSRodney W. Grimes int cmd; 310df8bae1dSRodney W. Grimes uid_t uid; 3110430a5e2SDag-Erling Smørgrav void *arg; 312a4b07a27SJason A. Harmening bool *mp_busy; 313df8bae1dSRodney W. Grimes { 314a4b07a27SJason A. Harmening struct mount *lowermp; 315a4b07a27SJason A. Harmening struct null_mount *mntdata; 316a4b07a27SJason A. Harmening int error; 317a4b07a27SJason A. Harmening bool unbusy; 318a4b07a27SJason A. Harmening 319a4b07a27SJason A. Harmening mntdata = MOUNTTONULLMOUNT(mp); 320a4b07a27SJason A. Harmening lowermp = atomic_load_ptr(&mntdata->nullm_vfs); 321a4b07a27SJason A. Harmening KASSERT(*mp_busy == true, ("upper mount not busy")); 322a4b07a27SJason A. Harmening /* 323a4b07a27SJason A. Harmening * See comment in sys_quotactl() for an explanation of why the 324a4b07a27SJason A. Harmening * lower mount needs to be busied by the caller of VFS_QUOTACTL() 325a4b07a27SJason A. Harmening * but may be unbusied by the implementation. We must unbusy 326a4b07a27SJason A. Harmening * the upper mount for the same reason; otherwise a namei lookup 327a4b07a27SJason A. Harmening * issued by the VFS_QUOTACTL() implementation could traverse the 328a4b07a27SJason A. Harmening * upper mount and deadlock. 329a4b07a27SJason A. Harmening */ 330a4b07a27SJason A. Harmening vfs_unbusy(mp); 331a4b07a27SJason A. Harmening *mp_busy = false; 332a4b07a27SJason A. Harmening unbusy = true; 333a4b07a27SJason A. Harmening error = vfs_busy(lowermp, 0); 334a4b07a27SJason A. Harmening if (error == 0) 335a4b07a27SJason A. Harmening error = VFS_QUOTACTL(lowermp, cmd, uid, arg, &unbusy); 336a4b07a27SJason A. Harmening if (unbusy) 337a4b07a27SJason A. Harmening vfs_unbusy(lowermp); 338a4b07a27SJason A. Harmening 339a4b07a27SJason A. Harmening return (error); 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes 342d4b7a369SPoul-Henning Kamp static int 343dfd233edSAttilio Rao nullfs_statfs(mp, sbp) 344df8bae1dSRodney W. Grimes struct mount *mp; 345df8bae1dSRodney W. Grimes struct statfs *sbp; 346df8bae1dSRodney W. Grimes { 347df8bae1dSRodney W. Grimes int error; 3482f304845SKonstantin Belousov struct statfs *mstat; 349df8bae1dSRodney W. Grimes 3508da80660SBoris Popov NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 35189785a16SBruce Evans (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 35289785a16SBruce Evans (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 353df8bae1dSRodney W. Grimes 3542f304845SKonstantin Belousov mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO); 355df8bae1dSRodney W. Grimes 3562f304845SKonstantin Belousov error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, mstat); 3572f304845SKonstantin Belousov if (error) { 3582f304845SKonstantin Belousov free(mstat, M_STATFS); 359df8bae1dSRodney W. Grimes return (error); 3602f304845SKonstantin Belousov } 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes /* now copy across the "interesting" information and fake the rest */ 3632f304845SKonstantin Belousov sbp->f_type = mstat->f_type; 3646d6a91c5SJilles Tjoelker sbp->f_flags = (sbp->f_flags & (MNT_RDONLY | MNT_NOEXEC | MNT_NOSUID | 365ed5cdcb6SEdward Tomasz Napierala MNT_UNION | MNT_NOSYMFOLLOW | MNT_AUTOMOUNTED)) | 366ed5cdcb6SEdward Tomasz Napierala (mstat->f_flags & ~(MNT_ROOTFS | MNT_AUTOMOUNTED)); 3672f304845SKonstantin Belousov sbp->f_bsize = mstat->f_bsize; 3682f304845SKonstantin Belousov sbp->f_iosize = mstat->f_iosize; 3692f304845SKonstantin Belousov sbp->f_blocks = mstat->f_blocks; 3702f304845SKonstantin Belousov sbp->f_bfree = mstat->f_bfree; 3712f304845SKonstantin Belousov sbp->f_bavail = mstat->f_bavail; 3722f304845SKonstantin Belousov sbp->f_files = mstat->f_files; 3732f304845SKonstantin Belousov sbp->f_ffree = mstat->f_ffree; 3742f304845SKonstantin Belousov 3752f304845SKonstantin Belousov free(mstat, M_STATFS); 376df8bae1dSRodney W. Grimes return (0); 377df8bae1dSRodney W. Grimes } 378df8bae1dSRodney W. Grimes 379d4b7a369SPoul-Henning Kamp static int 380dfd233edSAttilio Rao nullfs_sync(mp, waitfor) 381df8bae1dSRodney W. Grimes struct mount *mp; 382df8bae1dSRodney W. Grimes int waitfor; 383df8bae1dSRodney W. Grimes { 384df8bae1dSRodney W. Grimes /* 385df8bae1dSRodney W. Grimes * XXX - Assumes no data cached at null layer. 386df8bae1dSRodney W. Grimes */ 387df8bae1dSRodney W. Grimes return (0); 388df8bae1dSRodney W. Grimes } 389df8bae1dSRodney W. Grimes 390d4b7a369SPoul-Henning Kamp static int 391a0595d02SKirk McKusick nullfs_vget(mp, ino, flags, vpp) 392df8bae1dSRodney W. Grimes struct mount *mp; 393df8bae1dSRodney W. Grimes ino_t ino; 394a0595d02SKirk McKusick int flags; 395df8bae1dSRodney W. Grimes struct vnode **vpp; 396df8bae1dSRodney W. Grimes { 3974451405fSBoris Popov int error; 398e4e1d9f3SKonstantin Belousov 399e4e1d9f3SKonstantin Belousov KASSERT((flags & LK_TYPE_MASK) != 0, 400e4e1d9f3SKonstantin Belousov ("nullfs_vget: no lock requested")); 401e4e1d9f3SKonstantin Belousov 402a0595d02SKirk McKusick error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 403d9e9650aSKonstantin Belousov if (error != 0) 4044451405fSBoris Popov return (error); 4051cfdefbbSSemen Ustimenko return (null_nodeget(mp, *vpp, vpp)); 406df8bae1dSRodney W. Grimes } 407df8bae1dSRodney W. Grimes 408d4b7a369SPoul-Henning Kamp static int 409694a586aSRick Macklem nullfs_fhtovp(mp, fidp, flags, vpp) 410df8bae1dSRodney W. Grimes struct mount *mp; 411df8bae1dSRodney W. Grimes struct fid *fidp; 412694a586aSRick Macklem int flags; 413df8bae1dSRodney W. Grimes struct vnode **vpp; 414c24fda81SAlfred Perlstein { 4154451405fSBoris Popov int error; 416c24fda81SAlfred Perlstein 417d9e9650aSKonstantin Belousov error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, flags, 418d9e9650aSKonstantin Belousov vpp); 419d9e9650aSKonstantin Belousov if (error != 0) 420d9e9650aSKonstantin Belousov return (error); 4211cfdefbbSSemen Ustimenko return (null_nodeget(mp, *vpp, vpp)); 422c24fda81SAlfred Perlstein } 423c24fda81SAlfred Perlstein 424c24fda81SAlfred Perlstein static int 425dfd233edSAttilio Rao nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname) 42691f37dcbSRobert Watson struct mount *mp; 42791f37dcbSRobert Watson int cmd; 42870f36851SRobert Watson struct vnode *filename_vp; 42970f36851SRobert Watson int namespace; 4308f073875SRobert Watson const char *attrname; 43191f37dcbSRobert Watson { 432d9e9650aSKonstantin Belousov 433d9e9650aSKonstantin Belousov return (VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, 434d9e9650aSKonstantin Belousov filename_vp, namespace, attrname)); 43591f37dcbSRobert Watson } 43691f37dcbSRobert Watson 437d9e9650aSKonstantin Belousov static void 438d9e9650aSKonstantin Belousov nullfs_reclaim_lowervp(struct mount *mp, struct vnode *lowervp) 439d9e9650aSKonstantin Belousov { 440d9e9650aSKonstantin Belousov struct vnode *vp; 441d9e9650aSKonstantin Belousov 442d9e9650aSKonstantin Belousov vp = null_hashget(mp, lowervp); 443d9e9650aSKonstantin Belousov if (vp == NULL) 444d9e9650aSKonstantin Belousov return; 4450fc6daa7SKonstantin Belousov VTONULL(vp)->null_flags |= NULLV_NOUNLOCK; 446d9e9650aSKonstantin Belousov vgone(vp); 4470fc6daa7SKonstantin Belousov vput(vp); 4480fc6daa7SKonstantin Belousov } 4490fc6daa7SKonstantin Belousov 4500fc6daa7SKonstantin Belousov static void 4510fc6daa7SKonstantin Belousov nullfs_unlink_lowervp(struct mount *mp, struct vnode *lowervp) 4520fc6daa7SKonstantin Belousov { 4530fc6daa7SKonstantin Belousov struct vnode *vp; 4540fc6daa7SKonstantin Belousov struct null_node *xp; 4550fc6daa7SKonstantin Belousov 4560fc6daa7SKonstantin Belousov vp = null_hashget(mp, lowervp); 4570fc6daa7SKonstantin Belousov if (vp == NULL) 4580fc6daa7SKonstantin Belousov return; 4590fc6daa7SKonstantin Belousov xp = VTONULL(vp); 4600fc6daa7SKonstantin Belousov xp->null_flags |= NULLV_DROP | NULLV_NOUNLOCK; 4610fc6daa7SKonstantin Belousov vhold(vp); 4620fc6daa7SKonstantin Belousov vunref(vp); 4630fc6daa7SKonstantin Belousov 4640fc6daa7SKonstantin Belousov if (vp->v_usecount == 0) { 46574c7ff1aSKonstantin Belousov /* 46674c7ff1aSKonstantin Belousov * If vunref() dropped the last use reference on the 46774c7ff1aSKonstantin Belousov * nullfs vnode, it must be reclaimed, and its lock 46874c7ff1aSKonstantin Belousov * was split from the lower vnode lock. Need to do 46974c7ff1aSKonstantin Belousov * extra unlock before allowing the final vdrop() to 47074c7ff1aSKonstantin Belousov * free the vnode. 47174c7ff1aSKonstantin Belousov */ 472abd80ddbSMateusz Guzik KASSERT(VN_IS_DOOMED(vp), 47374c7ff1aSKonstantin Belousov ("not reclaimed nullfs vnode %p", vp)); 474b249ce48SMateusz Guzik VOP_UNLOCK(vp); 47574c7ff1aSKonstantin Belousov } else { 47674c7ff1aSKonstantin Belousov /* 47774c7ff1aSKonstantin Belousov * Otherwise, the nullfs vnode still shares the lock 47874c7ff1aSKonstantin Belousov * with the lower vnode, and must not be unlocked. 47974c7ff1aSKonstantin Belousov * Also clear the NULLV_NOUNLOCK, the flag is not 48074c7ff1aSKonstantin Belousov * relevant for future reclamations. 48174c7ff1aSKonstantin Belousov */ 48274c7ff1aSKonstantin Belousov ASSERT_VOP_ELOCKED(vp, "unlink_lowervp"); 483abd80ddbSMateusz Guzik KASSERT(!VN_IS_DOOMED(vp), 48474c7ff1aSKonstantin Belousov ("reclaimed nullfs vnode %p", vp)); 48574c7ff1aSKonstantin Belousov xp->null_flags &= ~NULLV_NOUNLOCK; 4860fc6daa7SKonstantin Belousov } 4870fc6daa7SKonstantin Belousov vdrop(vp); 488d9e9650aSKonstantin Belousov } 48991f37dcbSRobert Watson 490d4b7a369SPoul-Henning Kamp static struct vfsops null_vfsops = { 4917652131bSPoul-Henning Kamp .vfs_extattrctl = nullfs_extattrctl, 4927652131bSPoul-Henning Kamp .vfs_fhtovp = nullfs_fhtovp, 4937652131bSPoul-Henning Kamp .vfs_init = nullfs_init, 4945e8c582aSPoul-Henning Kamp .vfs_mount = nullfs_mount, 4957652131bSPoul-Henning Kamp .vfs_quotactl = nullfs_quotactl, 4967652131bSPoul-Henning Kamp .vfs_root = nullfs_root, 4977652131bSPoul-Henning Kamp .vfs_statfs = nullfs_statfs, 4987652131bSPoul-Henning Kamp .vfs_sync = nullfs_sync, 4997652131bSPoul-Henning Kamp .vfs_uninit = nullfs_uninit, 5007652131bSPoul-Henning Kamp .vfs_unmount = nullfs_unmount, 5017652131bSPoul-Henning Kamp .vfs_vget = nullfs_vget, 502d9e9650aSKonstantin Belousov .vfs_reclaim_lowervp = nullfs_reclaim_lowervp, 5030fc6daa7SKonstantin Belousov .vfs_unlink_lowervp = nullfs_unlink_lowervp, 504df8bae1dSRodney W. Grimes }; 505c901836cSGarrett Wollman 50661f0e25aSMartin Matuska VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL); 507