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; 128*7e1d3eefSMateusz 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); 140762e6b85SEivind Eklund NDFREE(ndp, NDF_ONLY_PNBUF); 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 2045da56ddbSTor Egge MNT_ILOCK(mp); 2059cf4c952SKonstantin Belousov if ((xmp->nullm_flags & NULLM_CACHE) != 0) { 20637a1046eSKonstantin Belousov mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & 2079cf4c952SKonstantin Belousov (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | 2089cf4c952SKonstantin Belousov MNTK_EXTENDED_SHARED); 2099cf4c952SKonstantin Belousov } 210be4cd691SMateusz Guzik mp->mnt_kern_flag |= MNTK_LOOKUP_EXCL_DOTDOT | MNTK_NOMSYNC; 2114fce16e4SMateusz Guzik mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & 212f36aa2b7SKonstantin Belousov (MNTK_USES_BCACHE | MNTK_NO_IOPF | MNTK_UNMAPPED_BUFS); 2135da56ddbSTor Egge MNT_IUNLOCK(mp); 214996c772fSJohn Dyson vfs_getnewfsid(mp); 2157ab8c8c0SPoul-Henning Kamp vfs_mountedfrom(mp, target); 2165fc9e11cSKonstantin Belousov vput(nullm_rootvp); 2177ab8c8c0SPoul-Henning Kamp 2188da80660SBoris Popov NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 219df8bae1dSRodney W. Grimes mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 220df8bae1dSRodney W. Grimes return (0); 221df8bae1dSRodney W. Grimes } 222df8bae1dSRodney W. Grimes 223df8bae1dSRodney W. Grimes /* 224df8bae1dSRodney W. Grimes * Free reference to null layer 225df8bae1dSRodney W. Grimes */ 226d4b7a369SPoul-Henning Kamp static int 227dfd233edSAttilio Rao nullfs_unmount(mp, mntflags) 228df8bae1dSRodney W. Grimes struct mount *mp; 229df8bae1dSRodney W. Grimes int mntflags; 230df8bae1dSRodney W. Grimes { 231d9e9650aSKonstantin Belousov struct null_mount *mntdata; 2325fc9e11cSKonstantin Belousov int error, flags; 233df8bae1dSRodney W. Grimes 2348da80660SBoris Popov NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 235df8bae1dSRodney W. Grimes 236996c772fSJohn Dyson if (mntflags & MNT_FORCE) 237d9e9650aSKonstantin Belousov flags = FORCECLOSE; 238d9e9650aSKonstantin Belousov else 239d9e9650aSKonstantin Belousov flags = 0; 240df8bae1dSRodney W. Grimes 2415fc9e11cSKonstantin Belousov for (;;) { 2420864ef1eSIan Dowse /* There is 1 extra root vnode reference (nullm_rootvp). */ 2435fc9e11cSKonstantin Belousov error = vflush(mp, 0, flags, curthread); 2443a773ad0SPoul-Henning Kamp if (error) 245df8bae1dSRodney W. Grimes return (error); 2467ae3486eSKonstantin Belousov MNT_ILOCK(mp); 2477ae3486eSKonstantin Belousov if (mp->mnt_nvnodelistsize == 0) { 2487ae3486eSKonstantin Belousov MNT_IUNLOCK(mp); 2497ae3486eSKonstantin Belousov break; 2507ae3486eSKonstantin Belousov } 2517ae3486eSKonstantin Belousov MNT_IUNLOCK(mp); 2527ae3486eSKonstantin Belousov if ((mntflags & MNT_FORCE) == 0) 2537ae3486eSKonstantin Belousov return (EBUSY); 2547ae3486eSKonstantin Belousov } 255df8bae1dSRodney W. Grimes 256df8bae1dSRodney W. Grimes /* 257df8bae1dSRodney W. Grimes * Finally, throw away the null_mount structure 258df8bae1dSRodney W. Grimes */ 2598da80660SBoris Popov mntdata = mp->mnt_data; 2609cf4c952SKonstantin Belousov if ((mntdata->nullm_flags & NULLM_CACHE) != 0) { 261c746ed72SJason A. Harmening vfs_unregister_for_notification(mntdata->nullm_vfs, 262c746ed72SJason A. Harmening &mntdata->notify_node); 263d9e9650aSKonstantin Belousov } 264c746ed72SJason A. Harmening vfs_unregister_upper(mntdata->nullm_vfs, &mntdata->upper_node); 2655fc9e11cSKonstantin Belousov vrele(mntdata->nullm_lowerrootvp); 26611753bd0SKevin Lo mp->mnt_data = NULL; 2674451405fSBoris Popov free(mntdata, M_NULLFSMNT); 268d9e9650aSKonstantin Belousov return (0); 269df8bae1dSRodney W. Grimes } 270df8bae1dSRodney W. Grimes 271d4b7a369SPoul-Henning Kamp static int 272dfd233edSAttilio Rao nullfs_root(mp, flags, vpp) 273df8bae1dSRodney W. Grimes struct mount *mp; 274d9b2d9f7SJeff Roberson int flags; 275df8bae1dSRodney W. Grimes struct vnode **vpp; 276df8bae1dSRodney W. Grimes { 277df8bae1dSRodney W. Grimes struct vnode *vp; 2785fc9e11cSKonstantin Belousov struct null_mount *mntdata; 2795fc9e11cSKonstantin Belousov int error; 280df8bae1dSRodney W. Grimes 2815fc9e11cSKonstantin Belousov mntdata = MOUNTTONULLMOUNT(mp); 2825fc9e11cSKonstantin Belousov NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", mp, 2835fc9e11cSKonstantin Belousov mntdata->nullm_lowerrootvp); 284df8bae1dSRodney W. Grimes 285a92a971bSMateusz Guzik error = vget(mntdata->nullm_lowerrootvp, flags); 2865fc9e11cSKonstantin Belousov if (error == 0) { 2875fc9e11cSKonstantin Belousov error = null_nodeget(mp, mntdata->nullm_lowerrootvp, &vp); 2885fc9e11cSKonstantin Belousov if (error == 0) { 289df8bae1dSRodney W. Grimes *vpp = vp; 2905fc9e11cSKonstantin Belousov } 2915fc9e11cSKonstantin Belousov } 2925fc9e11cSKonstantin Belousov return (error); 293df8bae1dSRodney W. Grimes } 294df8bae1dSRodney W. Grimes 295d4b7a369SPoul-Henning Kamp static int 296a4b07a27SJason A. Harmening nullfs_quotactl(mp, cmd, uid, arg, mp_busy) 297df8bae1dSRodney W. Grimes struct mount *mp; 298df8bae1dSRodney W. Grimes int cmd; 299df8bae1dSRodney W. Grimes uid_t uid; 3000430a5e2SDag-Erling Smørgrav void *arg; 301a4b07a27SJason A. Harmening bool *mp_busy; 302df8bae1dSRodney W. Grimes { 303a4b07a27SJason A. Harmening struct mount *lowermp; 304a4b07a27SJason A. Harmening struct null_mount *mntdata; 305a4b07a27SJason A. Harmening int error; 306a4b07a27SJason A. Harmening bool unbusy; 307a4b07a27SJason A. Harmening 308a4b07a27SJason A. Harmening mntdata = MOUNTTONULLMOUNT(mp); 309a4b07a27SJason A. Harmening lowermp = atomic_load_ptr(&mntdata->nullm_vfs); 310a4b07a27SJason A. Harmening KASSERT(*mp_busy == true, ("upper mount not busy")); 311a4b07a27SJason A. Harmening /* 312a4b07a27SJason A. Harmening * See comment in sys_quotactl() for an explanation of why the 313a4b07a27SJason A. Harmening * lower mount needs to be busied by the caller of VFS_QUOTACTL() 314a4b07a27SJason A. Harmening * but may be unbusied by the implementation. We must unbusy 315a4b07a27SJason A. Harmening * the upper mount for the same reason; otherwise a namei lookup 316a4b07a27SJason A. Harmening * issued by the VFS_QUOTACTL() implementation could traverse the 317a4b07a27SJason A. Harmening * upper mount and deadlock. 318a4b07a27SJason A. Harmening */ 319a4b07a27SJason A. Harmening vfs_unbusy(mp); 320a4b07a27SJason A. Harmening *mp_busy = false; 321a4b07a27SJason A. Harmening unbusy = true; 322a4b07a27SJason A. Harmening error = vfs_busy(lowermp, 0); 323a4b07a27SJason A. Harmening if (error == 0) 324a4b07a27SJason A. Harmening error = VFS_QUOTACTL(lowermp, cmd, uid, arg, &unbusy); 325a4b07a27SJason A. Harmening if (unbusy) 326a4b07a27SJason A. Harmening vfs_unbusy(lowermp); 327a4b07a27SJason A. Harmening 328a4b07a27SJason A. Harmening return (error); 329df8bae1dSRodney W. Grimes } 330df8bae1dSRodney W. Grimes 331d4b7a369SPoul-Henning Kamp static int 332dfd233edSAttilio Rao nullfs_statfs(mp, sbp) 333df8bae1dSRodney W. Grimes struct mount *mp; 334df8bae1dSRodney W. Grimes struct statfs *sbp; 335df8bae1dSRodney W. Grimes { 336df8bae1dSRodney W. Grimes int error; 3372f304845SKonstantin Belousov struct statfs *mstat; 338df8bae1dSRodney W. Grimes 3398da80660SBoris Popov NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 34089785a16SBruce Evans (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 34189785a16SBruce Evans (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 342df8bae1dSRodney W. Grimes 3432f304845SKonstantin Belousov mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO); 344df8bae1dSRodney W. Grimes 3452f304845SKonstantin Belousov error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, mstat); 3462f304845SKonstantin Belousov if (error) { 3472f304845SKonstantin Belousov free(mstat, M_STATFS); 348df8bae1dSRodney W. Grimes return (error); 3492f304845SKonstantin Belousov } 350df8bae1dSRodney W. Grimes 351df8bae1dSRodney W. Grimes /* now copy across the "interesting" information and fake the rest */ 3522f304845SKonstantin Belousov sbp->f_type = mstat->f_type; 3536d6a91c5SJilles Tjoelker sbp->f_flags = (sbp->f_flags & (MNT_RDONLY | MNT_NOEXEC | MNT_NOSUID | 354ed5cdcb6SEdward Tomasz Napierala MNT_UNION | MNT_NOSYMFOLLOW | MNT_AUTOMOUNTED)) | 355ed5cdcb6SEdward Tomasz Napierala (mstat->f_flags & ~(MNT_ROOTFS | MNT_AUTOMOUNTED)); 3562f304845SKonstantin Belousov sbp->f_bsize = mstat->f_bsize; 3572f304845SKonstantin Belousov sbp->f_iosize = mstat->f_iosize; 3582f304845SKonstantin Belousov sbp->f_blocks = mstat->f_blocks; 3592f304845SKonstantin Belousov sbp->f_bfree = mstat->f_bfree; 3602f304845SKonstantin Belousov sbp->f_bavail = mstat->f_bavail; 3612f304845SKonstantin Belousov sbp->f_files = mstat->f_files; 3622f304845SKonstantin Belousov sbp->f_ffree = mstat->f_ffree; 3632f304845SKonstantin Belousov 3642f304845SKonstantin Belousov free(mstat, M_STATFS); 365df8bae1dSRodney W. Grimes return (0); 366df8bae1dSRodney W. Grimes } 367df8bae1dSRodney W. Grimes 368d4b7a369SPoul-Henning Kamp static int 369dfd233edSAttilio Rao nullfs_sync(mp, waitfor) 370df8bae1dSRodney W. Grimes struct mount *mp; 371df8bae1dSRodney W. Grimes int waitfor; 372df8bae1dSRodney W. Grimes { 373df8bae1dSRodney W. Grimes /* 374df8bae1dSRodney W. Grimes * XXX - Assumes no data cached at null layer. 375df8bae1dSRodney W. Grimes */ 376df8bae1dSRodney W. Grimes return (0); 377df8bae1dSRodney W. Grimes } 378df8bae1dSRodney W. Grimes 379d4b7a369SPoul-Henning Kamp static int 380a0595d02SKirk McKusick nullfs_vget(mp, ino, flags, vpp) 381df8bae1dSRodney W. Grimes struct mount *mp; 382df8bae1dSRodney W. Grimes ino_t ino; 383a0595d02SKirk McKusick int flags; 384df8bae1dSRodney W. Grimes struct vnode **vpp; 385df8bae1dSRodney W. Grimes { 3864451405fSBoris Popov int error; 387e4e1d9f3SKonstantin Belousov 388e4e1d9f3SKonstantin Belousov KASSERT((flags & LK_TYPE_MASK) != 0, 389e4e1d9f3SKonstantin Belousov ("nullfs_vget: no lock requested")); 390e4e1d9f3SKonstantin Belousov 391a0595d02SKirk McKusick error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 392d9e9650aSKonstantin Belousov if (error != 0) 3934451405fSBoris Popov return (error); 3941cfdefbbSSemen Ustimenko return (null_nodeget(mp, *vpp, vpp)); 395df8bae1dSRodney W. Grimes } 396df8bae1dSRodney W. Grimes 397d4b7a369SPoul-Henning Kamp static int 398694a586aSRick Macklem nullfs_fhtovp(mp, fidp, flags, vpp) 399df8bae1dSRodney W. Grimes struct mount *mp; 400df8bae1dSRodney W. Grimes struct fid *fidp; 401694a586aSRick Macklem int flags; 402df8bae1dSRodney W. Grimes struct vnode **vpp; 403c24fda81SAlfred Perlstein { 4044451405fSBoris Popov int error; 405c24fda81SAlfred Perlstein 406d9e9650aSKonstantin Belousov error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, flags, 407d9e9650aSKonstantin Belousov vpp); 408d9e9650aSKonstantin Belousov if (error != 0) 409d9e9650aSKonstantin Belousov return (error); 4101cfdefbbSSemen Ustimenko return (null_nodeget(mp, *vpp, vpp)); 411c24fda81SAlfred Perlstein } 412c24fda81SAlfred Perlstein 413c24fda81SAlfred Perlstein static int 414dfd233edSAttilio Rao nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname) 41591f37dcbSRobert Watson struct mount *mp; 41691f37dcbSRobert Watson int cmd; 41770f36851SRobert Watson struct vnode *filename_vp; 41870f36851SRobert Watson int namespace; 4198f073875SRobert Watson const char *attrname; 42091f37dcbSRobert Watson { 421d9e9650aSKonstantin Belousov 422d9e9650aSKonstantin Belousov return (VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, 423d9e9650aSKonstantin Belousov filename_vp, namespace, attrname)); 42491f37dcbSRobert Watson } 42591f37dcbSRobert Watson 426d9e9650aSKonstantin Belousov static void 427d9e9650aSKonstantin Belousov nullfs_reclaim_lowervp(struct mount *mp, struct vnode *lowervp) 428d9e9650aSKonstantin Belousov { 429d9e9650aSKonstantin Belousov struct vnode *vp; 430d9e9650aSKonstantin Belousov 431d9e9650aSKonstantin Belousov vp = null_hashget(mp, lowervp); 432d9e9650aSKonstantin Belousov if (vp == NULL) 433d9e9650aSKonstantin Belousov return; 4340fc6daa7SKonstantin Belousov VTONULL(vp)->null_flags |= NULLV_NOUNLOCK; 435d9e9650aSKonstantin Belousov vgone(vp); 4360fc6daa7SKonstantin Belousov vput(vp); 4370fc6daa7SKonstantin Belousov } 4380fc6daa7SKonstantin Belousov 4390fc6daa7SKonstantin Belousov static void 4400fc6daa7SKonstantin Belousov nullfs_unlink_lowervp(struct mount *mp, struct vnode *lowervp) 4410fc6daa7SKonstantin Belousov { 4420fc6daa7SKonstantin Belousov struct vnode *vp; 4430fc6daa7SKonstantin Belousov struct null_node *xp; 4440fc6daa7SKonstantin Belousov 4450fc6daa7SKonstantin Belousov vp = null_hashget(mp, lowervp); 4460fc6daa7SKonstantin Belousov if (vp == NULL) 4470fc6daa7SKonstantin Belousov return; 4480fc6daa7SKonstantin Belousov xp = VTONULL(vp); 4490fc6daa7SKonstantin Belousov xp->null_flags |= NULLV_DROP | NULLV_NOUNLOCK; 4500fc6daa7SKonstantin Belousov vhold(vp); 4510fc6daa7SKonstantin Belousov vunref(vp); 4520fc6daa7SKonstantin Belousov 4530fc6daa7SKonstantin Belousov if (vp->v_usecount == 0) { 45474c7ff1aSKonstantin Belousov /* 45574c7ff1aSKonstantin Belousov * If vunref() dropped the last use reference on the 45674c7ff1aSKonstantin Belousov * nullfs vnode, it must be reclaimed, and its lock 45774c7ff1aSKonstantin Belousov * was split from the lower vnode lock. Need to do 45874c7ff1aSKonstantin Belousov * extra unlock before allowing the final vdrop() to 45974c7ff1aSKonstantin Belousov * free the vnode. 46074c7ff1aSKonstantin Belousov */ 461abd80ddbSMateusz Guzik KASSERT(VN_IS_DOOMED(vp), 46274c7ff1aSKonstantin Belousov ("not reclaimed nullfs vnode %p", vp)); 463b249ce48SMateusz Guzik VOP_UNLOCK(vp); 46474c7ff1aSKonstantin Belousov } else { 46574c7ff1aSKonstantin Belousov /* 46674c7ff1aSKonstantin Belousov * Otherwise, the nullfs vnode still shares the lock 46774c7ff1aSKonstantin Belousov * with the lower vnode, and must not be unlocked. 46874c7ff1aSKonstantin Belousov * Also clear the NULLV_NOUNLOCK, the flag is not 46974c7ff1aSKonstantin Belousov * relevant for future reclamations. 47074c7ff1aSKonstantin Belousov */ 47174c7ff1aSKonstantin Belousov ASSERT_VOP_ELOCKED(vp, "unlink_lowervp"); 472abd80ddbSMateusz Guzik KASSERT(!VN_IS_DOOMED(vp), 47374c7ff1aSKonstantin Belousov ("reclaimed nullfs vnode %p", vp)); 47474c7ff1aSKonstantin Belousov xp->null_flags &= ~NULLV_NOUNLOCK; 4750fc6daa7SKonstantin Belousov } 4760fc6daa7SKonstantin Belousov vdrop(vp); 477d9e9650aSKonstantin Belousov } 47891f37dcbSRobert Watson 479d4b7a369SPoul-Henning Kamp static struct vfsops null_vfsops = { 4807652131bSPoul-Henning Kamp .vfs_extattrctl = nullfs_extattrctl, 4817652131bSPoul-Henning Kamp .vfs_fhtovp = nullfs_fhtovp, 4827652131bSPoul-Henning Kamp .vfs_init = nullfs_init, 4835e8c582aSPoul-Henning Kamp .vfs_mount = nullfs_mount, 4847652131bSPoul-Henning Kamp .vfs_quotactl = nullfs_quotactl, 4857652131bSPoul-Henning Kamp .vfs_root = nullfs_root, 4867652131bSPoul-Henning Kamp .vfs_statfs = nullfs_statfs, 4877652131bSPoul-Henning Kamp .vfs_sync = nullfs_sync, 4887652131bSPoul-Henning Kamp .vfs_uninit = nullfs_uninit, 4897652131bSPoul-Henning Kamp .vfs_unmount = nullfs_unmount, 4907652131bSPoul-Henning Kamp .vfs_vget = nullfs_vget, 491d9e9650aSKonstantin Belousov .vfs_reclaim_lowervp = nullfs_reclaim_lowervp, 4920fc6daa7SKonstantin Belousov .vfs_unlink_lowervp = nullfs_unlink_lowervp, 493df8bae1dSRodney W. Grimes }; 494c901836cSGarrett Wollman 49561f0e25aSMartin Matuska VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL); 496