null_vfsops.c revision 138412
1193323Sed/* 2193323Sed * Copyright (c) 1992, 1993, 1995 3193323Sed * The Regents of the University of California. All rights reserved. 4193323Sed * 5193323Sed * This code is derived from software donated to Berkeley by 6193323Sed * Jan-Simon Pendry. 7193323Sed * 8193323Sed * Redistribution and use in source and binary forms, with or without 9193323Sed * modification, are permitted provided that the following conditions 10193323Sed * are met: 11193323Sed * 1. Redistributions of source code must retain the above copyright 12193323Sed * notice, this list of conditions and the following disclaimer. 13193323Sed * 2. Redistributions in binary form must reproduce the above copyright 14193323Sed * notice, this list of conditions and the following disclaimer in the 15193323Sed * documentation and/or other materials provided with the distribution. 16193323Sed * 4. Neither the name of the University nor the names of its contributors 17193323Sed * may be used to endorse or promote products derived from this software 18193323Sed * without specific prior written permission. 19193323Sed * 20193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30193323Sed * SUCH DAMAGE. 31193323Sed * 32193323Sed * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 33249423Sdim * 34249423Sdim * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 35193323Sed * $FreeBSD: head/sys/fs/nullfs/null_vfsops.c 138412 2004-12-05 22:41:02Z phk $ 36193323Sed */ 37276479Sdim 38249423Sdim/* 39210299Sed * Null Layer 40193323Sed * (See null_vnops.c for a description of what this does.) 41210299Sed */ 42193323Sed 43193323Sed#include <sys/param.h> 44193323Sed#include <sys/systm.h> 45193323Sed#include <sys/kdb.h> 46193323Sed#include <sys/kernel.h> 47193323Sed#include <sys/lock.h> 48193323Sed#include <sys/malloc.h> 49193323Sed#include <sys/mount.h> 50193323Sed#include <sys/namei.h> 51193323Sed#include <sys/proc.h> 52193323Sed#include <sys/vnode.h> 53193323Sed 54193323Sed#include <fs/nullfs/null.h> 55193323Sed 56193323Sedstatic MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure"); 57193323Sed 58193323Sedstatic vfs_fhtovp_t nullfs_fhtovp; 59193323Sedstatic vfs_checkexp_t nullfs_checkexp; 60193323Sedstatic vfs_mount_t nullfs_mount; 61193323Sedstatic vfs_quotactl_t nullfs_quotactl; 62193323Sedstatic vfs_root_t nullfs_root; 63193323Sedstatic vfs_sync_t nullfs_sync; 64193323Sedstatic vfs_statfs_t nullfs_statfs; 65193323Sedstatic vfs_unmount_t nullfs_unmount; 66193323Sedstatic vfs_vget_t nullfs_vget; 67193323Sedstatic vfs_vptofh_t nullfs_vptofh; 68193323Sedstatic vfs_extattrctl_t nullfs_extattrctl; 69193323Sed 70193323Sed/* 71193323Sed * Mount null layer 72193323Sed */ 73193323Sedstatic int 74193323Sednullfs_mount(struct mount *mp, struct thread *td) 75193323Sed{ 76193323Sed int error = 0; 77193323Sed struct vnode *lowerrootvp, *vp; 78193323Sed struct vnode *nullm_rootvp; 79193323Sed struct null_mount *xmp; 80193323Sed char *target; 81288943Sdim size_t size; 82193323Sed int isvnunlocked = 0, len; 83193323Sed struct nameidata nd, *ndp = &nd; 84193323Sed 85193323Sed NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); 86193323Sed 87193323Sed if (mp->mnt_flag & MNT_ROOTFS) 88193323Sed return (EOPNOTSUPP); 89193323Sed /* 90193323Sed * Update is a no-op 91210299Sed */ 92193323Sed if (mp->mnt_flag & MNT_UPDATE) { 93193323Sed return (EOPNOTSUPP); 94193323Sed /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, td);*/ 95193323Sed } 96193323Sed 97193323Sed /* 98193323Sed * Get argument 99193323Sed */ 100193323Sed error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 101193323Sed if (error || target[len - 1] != '\0') 102193323Sed return (EINVAL); 103234353Sdim 104193323Sed /* 105193323Sed * Unlock lower node to avoid deadlock. 106193323Sed * (XXX) VOP_ISLOCKED is needed? 107288943Sdim */ 108288943Sdim if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && 109288943Sdim VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) { 110288943Sdim VOP_UNLOCK(mp->mnt_vnodecovered, 0, td); 111288943Sdim isvnunlocked = 1; 112288943Sdim } 113193323Sed /* 114193323Sed * Find lower node 115193323Sed */ 116234353Sdim NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 117193323Sed UIO_SYSSPACE, target, td); 118193323Sed error = namei(ndp); 119193323Sed /* 120288943Sdim * Re-lock vnode. 121193323Sed */ 122193323Sed if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) 123193323Sed vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY, td); 124210299Sed 125193323Sed if (error) 126193323Sed return (error); 127193323Sed NDFREE(ndp, NDF_ONLY_PNBUF); 128288943Sdim 129288943Sdim /* 130288943Sdim * Sanity check on lower vnode 131288943Sdim */ 132193323Sed lowerrootvp = ndp->ni_vp; 133288943Sdim 134288943Sdim vrele(ndp->ni_dvp); 135288943Sdim ndp->ni_dvp = NULLVP; 136288943Sdim 137193323Sed /* 138288943Sdim * Check multi null mount to avoid `lock against myself' panic. 139193323Sed */ 140193323Sed if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 141193323Sed NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 142193323Sed vput(lowerrootvp); 143210299Sed return (EDEADLK); 144210299Sed } 145193323Sed 146193323Sed xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 147193323Sed M_NULLFSMNT, M_WAITOK); /* XXX */ 148193323Sed 149193323Sed /* 150193323Sed * Save reference to underlying FS 151193323Sed */ 152210299Sed xmp->nullm_vfs = lowerrootvp->v_mount; 153193323Sed 154193323Sed /* 155210299Sed * Save reference. Each mount also holds 156193323Sed * a reference on the root vnode. 157193323Sed */ 158193323Sed error = null_nodeget(mp, lowerrootvp, &vp); 159193323Sed /* 160288943Sdim * Make sure the node alias worked 161288943Sdim */ 162288943Sdim if (error) { 163288943Sdim VOP_UNLOCK(vp, 0, td); 164193323Sed vrele(lowerrootvp); 165193323Sed free(xmp, M_NULLFSMNT); /* XXX */ 166193323Sed return (error); 167193323Sed } 168193323Sed 169249423Sdim /* 170193323Sed * Keep a held reference to the root vnode. 171193323Sed * It is vrele'd in nullfs_unmount. 172193323Sed */ 173193323Sed nullm_rootvp = vp; 174193323Sed nullm_rootvp->v_vflag |= VV_ROOT; 175193323Sed xmp->nullm_rootvp = nullm_rootvp; 176193323Sed 177280031Sdim /* 178280031Sdim * Unlock the node (either the lower or the alias) 179193323Sed */ 180193323Sed VOP_UNLOCK(vp, 0, td); 181193323Sed 182193323Sed if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 183193323Sed mp->mnt_flag |= MNT_LOCAL; 184193323Sed mp->mnt_data = (qaddr_t) xmp; 185193323Sed vfs_getnewfsid(mp); 186193323Sed 187210299Sed (void) copystr(target, mp->mnt_stat.f_mntfromname, 188193323Sed MNAMELEN - 1, &size); 189193323Sed bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 190193323Sed (void)nullfs_statfs(mp, &mp->mnt_stat, td); 191193323Sed NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 192193323Sed mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 193193323Sed return (0); 194193323Sed} 195193323Sed 196193323Sed/* 197193323Sed * Free reference to null layer 198193323Sed */ 199193323Sedstatic int 200193323Sednullfs_unmount(mp, mntflags, td) 201193323Sed struct mount *mp; 202193323Sed int mntflags; 203193323Sed struct thread *td; 204193323Sed{ 205193323Sed void *mntdata; 206193323Sed int error; 207193323Sed int flags = 0; 208193323Sed 209193323Sed NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 210193323Sed 211193323Sed if (mntflags & MNT_FORCE) 212193323Sed flags |= FORCECLOSE; 213193323Sed 214193323Sed /* There is 1 extra root vnode reference (nullm_rootvp). */ 215193323Sed error = vflush(mp, 1, flags, td); 216193323Sed if (error) 217193323Sed return (error); 218193323Sed 219193323Sed /* 220193323Sed * Finally, throw away the null_mount structure 221193323Sed */ 222193323Sed mntdata = mp->mnt_data; 223193323Sed mp->mnt_data = 0; 224193323Sed free(mntdata, M_NULLFSMNT); 225193323Sed return 0; 226193323Sed} 227193323Sed 228193323Sedstatic int 229193323Sednullfs_root(mp, vpp, td) 230193323Sed struct mount *mp; 231193323Sed struct vnode **vpp; 232193323Sed struct thread *td; 233193323Sed{ 234193323Sed struct vnode *vp; 235193323Sed 236193323Sed NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 237193323Sed (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 238193323Sed (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 239193323Sed 240193323Sed /* 241193323Sed * Return locked reference to root. 242193323Sed */ 243193323Sed vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 244193323Sed VREF(vp); 245198090Srdivacky 246198090Srdivacky#ifdef NULLFS_DEBUG 247193323Sed if (VOP_ISLOCKED(vp, NULL)) { 248193323Sed kdb_enter("root vnode is locked.\n"); 249193323Sed vrele(vp); 250193323Sed return (EDEADLK); 251193323Sed } 252193323Sed#endif 253193323Sed vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 254193323Sed *vpp = vp; 255193323Sed return 0; 256193323Sed} 257193323Sed 258193323Sedstatic int 259193323Sednullfs_quotactl(mp, cmd, uid, arg, td) 260193323Sed struct mount *mp; 261193323Sed int cmd; 262193323Sed uid_t uid; 263193323Sed caddr_t arg; 264193323Sed struct thread *td; 265193323Sed{ 266193323Sed return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, td); 267193323Sed} 268193323Sed 269static int 270nullfs_statfs(mp, sbp, td) 271 struct mount *mp; 272 struct statfs *sbp; 273 struct thread *td; 274{ 275 int error; 276 struct statfs mstat; 277 278 NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 279 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 280 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 281 282 bzero(&mstat, sizeof(mstat)); 283 284 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, td); 285 if (error) 286 return (error); 287 288 /* now copy across the "interesting" information and fake the rest */ 289 sbp->f_type = mstat.f_type; 290 sbp->f_flags = mstat.f_flags; 291 sbp->f_bsize = mstat.f_bsize; 292 sbp->f_iosize = mstat.f_iosize; 293 sbp->f_blocks = mstat.f_blocks; 294 sbp->f_bfree = mstat.f_bfree; 295 sbp->f_bavail = mstat.f_bavail; 296 sbp->f_files = mstat.f_files; 297 sbp->f_ffree = mstat.f_ffree; 298 return (0); 299} 300 301static int 302nullfs_sync(mp, waitfor, cred, td) 303 struct mount *mp; 304 int waitfor; 305 struct ucred *cred; 306 struct thread *td; 307{ 308 /* 309 * XXX - Assumes no data cached at null layer. 310 */ 311 return (0); 312} 313 314static int 315nullfs_vget(mp, ino, flags, vpp) 316 struct mount *mp; 317 ino_t ino; 318 int flags; 319 struct vnode **vpp; 320{ 321 int error; 322 error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 323 if (error) 324 return (error); 325 326 return (null_nodeget(mp, *vpp, vpp)); 327} 328 329static int 330nullfs_fhtovp(mp, fidp, vpp) 331 struct mount *mp; 332 struct fid *fidp; 333 struct vnode **vpp; 334{ 335 int error; 336 error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp); 337 if (error) 338 return (error); 339 340 return (null_nodeget(mp, *vpp, vpp)); 341} 342 343static int 344nullfs_checkexp(mp, nam, extflagsp, credanonp) 345 struct mount *mp; 346 struct sockaddr *nam; 347 int *extflagsp; 348 struct ucred **credanonp; 349{ 350 351 return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp)->nullm_vfs, nam, 352 extflagsp, credanonp); 353} 354 355static int 356nullfs_vptofh(vp, fhp) 357 struct vnode *vp; 358 struct fid *fhp; 359{ 360 struct vnode *lvp; 361 362 lvp = NULLVPTOLOWERVP(vp); 363 return VFS_VPTOFH(lvp, fhp); 364} 365 366static int 367nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, td) 368 struct mount *mp; 369 int cmd; 370 struct vnode *filename_vp; 371 int namespace; 372 const char *attrname; 373 struct thread *td; 374{ 375 return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, 376 namespace, attrname, td); 377} 378 379 380static struct vfsops null_vfsops = { 381 .vfs_checkexp = nullfs_checkexp, 382 .vfs_extattrctl = nullfs_extattrctl, 383 .vfs_fhtovp = nullfs_fhtovp, 384 .vfs_init = nullfs_init, 385 .vfs_mount = nullfs_mount, 386 .vfs_quotactl = nullfs_quotactl, 387 .vfs_root = nullfs_root, 388 .vfs_statfs = nullfs_statfs, 389 .vfs_sync = nullfs_sync, 390 .vfs_uninit = nullfs_uninit, 391 .vfs_unmount = nullfs_unmount, 392 .vfs_vget = nullfs_vget, 393 .vfs_vptofh = nullfs_vptofh, 394}; 395 396VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK); 397