1/*- 2 * Copyright (c) 1992, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software donated to Berkeley by 6 * Jan-Simon Pendry. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 33 * 34 * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
| 1/*- 2 * Copyright (c) 1992, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software donated to Berkeley by 6 * Jan-Simon Pendry. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 33 * 34 * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
|
84 if (mp->mnt_flag & MNT_ROOTFS) 85 return (EOPNOTSUPP); 86 /* 87 * Update is a no-op 88 */ 89 if (mp->mnt_flag & MNT_UPDATE) { 90 /* 91 * Only support update mounts for NFS export. 92 */ 93 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 94 return (0); 95 else 96 return (EOPNOTSUPP); 97 } 98 99 /* 100 * Get argument 101 */ 102 error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 103 if (error || target[len - 1] != '\0') 104 return (EINVAL); 105 106 /* 107 * Unlock lower node to avoid possible deadlock. 108 */ 109 if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && 110 VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) { 111 VOP_UNLOCK(mp->mnt_vnodecovered, 0); 112 isvnunlocked = 1; 113 } 114 /* 115 * Find lower node 116 */ 117 NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); 118 error = namei(ndp); 119 /* 120 * Re-lock vnode. 121 */ 122 if (isvnunlocked) 123 vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 124 125 if (error) 126 return (error); 127 NDFREE(ndp, NDF_ONLY_PNBUF); 128 129 /* 130 * Sanity check on lower vnode 131 */ 132 lowerrootvp = ndp->ni_vp; 133 134 /* 135 * Check multi null mount to avoid `lock against myself' panic. 136 */ 137 if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 138 NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 139 vput(lowerrootvp); 140 return (EDEADLK); 141 } 142 143 xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 144 M_NULLFSMNT, M_WAITOK); /* XXX */ 145 146 /* 147 * Save reference to underlying FS 148 */ 149 xmp->nullm_vfs = lowerrootvp->v_mount; 150 151 /* 152 * Save reference. Each mount also holds 153 * a reference on the root vnode. 154 */ 155 error = null_nodeget(mp, lowerrootvp, &vp); 156 /* 157 * Make sure the node alias worked 158 */ 159 if (error) { 160 free(xmp, M_NULLFSMNT); 161 return (error); 162 } 163 164 /* 165 * Keep a held reference to the root vnode. 166 * It is vrele'd in nullfs_unmount. 167 */ 168 nullm_rootvp = vp; 169 nullm_rootvp->v_vflag |= VV_ROOT; 170 xmp->nullm_rootvp = nullm_rootvp; 171 172 /* 173 * Unlock the node (either the lower or the alias) 174 */ 175 VOP_UNLOCK(vp, 0); 176 177 if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { 178 MNT_ILOCK(mp); 179 mp->mnt_flag |= MNT_LOCAL; 180 MNT_IUNLOCK(mp); 181 } 182 MNT_ILOCK(mp); 183 mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; 184 MNT_IUNLOCK(mp); 185 mp->mnt_data = xmp; 186 vfs_getnewfsid(mp); 187 188 vfs_mountedfrom(mp, target); 189 190 NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 191 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 192 return (0); 193} 194 195/* 196 * Free reference to null layer 197 */ 198static int 199nullfs_unmount(mp, mntflags) 200 struct mount *mp; 201 int mntflags; 202{ 203 void *mntdata; 204 int error; 205 int flags = 0; 206 207 NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 208 209 if (mntflags & MNT_FORCE) 210 flags |= FORCECLOSE; 211 212 /* There is 1 extra root vnode reference (nullm_rootvp). */ 213 error = vflush(mp, 1, flags, curthread); 214 if (error) 215 return (error); 216 217 /* 218 * Finally, throw away the null_mount structure 219 */ 220 mntdata = mp->mnt_data; 221 mp->mnt_data = 0; 222 free(mntdata, M_NULLFSMNT); 223 return 0; 224} 225 226static int 227nullfs_root(mp, flags, vpp) 228 struct mount *mp; 229 int flags; 230 struct vnode **vpp; 231{ 232 struct vnode *vp; 233 234 NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 235 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 236 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 237 238 /* 239 * Return locked reference to root. 240 */ 241 vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 242 VREF(vp); 243 244 ASSERT_VOP_UNLOCKED(vp, "root vnode is locked"); 245 vn_lock(vp, flags | LK_RETRY); 246 *vpp = vp; 247 return 0; 248} 249 250static int 251nullfs_quotactl(mp, cmd, uid, arg) 252 struct mount *mp; 253 int cmd; 254 uid_t uid; 255 void *arg; 256{ 257 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg); 258} 259 260static int 261nullfs_statfs(mp, sbp) 262 struct mount *mp; 263 struct statfs *sbp; 264{ 265 int error; 266 struct statfs mstat; 267 268 NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 269 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 270 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 271 272 bzero(&mstat, sizeof(mstat)); 273 274 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat); 275 if (error) 276 return (error); 277 278 /* now copy across the "interesting" information and fake the rest */ 279 sbp->f_type = mstat.f_type; 280 sbp->f_flags = mstat.f_flags; 281 sbp->f_bsize = mstat.f_bsize; 282 sbp->f_iosize = mstat.f_iosize; 283 sbp->f_blocks = mstat.f_blocks; 284 sbp->f_bfree = mstat.f_bfree; 285 sbp->f_bavail = mstat.f_bavail; 286 sbp->f_files = mstat.f_files; 287 sbp->f_ffree = mstat.f_ffree; 288 return (0); 289} 290 291static int 292nullfs_sync(mp, waitfor) 293 struct mount *mp; 294 int waitfor; 295{ 296 /* 297 * XXX - Assumes no data cached at null layer. 298 */ 299 return (0); 300} 301 302static int 303nullfs_vget(mp, ino, flags, vpp) 304 struct mount *mp; 305 ino_t ino; 306 int flags; 307 struct vnode **vpp; 308{ 309 int error; 310 error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 311 if (error) 312 return (error); 313 314 return (null_nodeget(mp, *vpp, vpp)); 315} 316 317static int 318nullfs_fhtovp(mp, fidp, flags, vpp) 319 struct mount *mp; 320 struct fid *fidp; 321 int flags; 322 struct vnode **vpp; 323{ 324 int error; 325 error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, LK_EXCLUSIVE, 326 vpp); 327 if (error) 328 return (error); 329 330 return (null_nodeget(mp, *vpp, vpp)); 331} 332 333static int 334nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname) 335 struct mount *mp; 336 int cmd; 337 struct vnode *filename_vp; 338 int namespace; 339 const char *attrname; 340{ 341 return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, 342 namespace, attrname); 343} 344 345 346static struct vfsops null_vfsops = { 347 .vfs_extattrctl = nullfs_extattrctl, 348 .vfs_fhtovp = nullfs_fhtovp, 349 .vfs_init = nullfs_init, 350 .vfs_mount = nullfs_mount, 351 .vfs_quotactl = nullfs_quotactl, 352 .vfs_root = nullfs_root, 353 .vfs_statfs = nullfs_statfs, 354 .vfs_sync = nullfs_sync, 355 .vfs_uninit = nullfs_uninit, 356 .vfs_unmount = nullfs_unmount, 357 .vfs_vget = nullfs_vget, 358}; 359 360VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL);
| 89 if (mp->mnt_flag & MNT_ROOTFS) 90 return (EOPNOTSUPP); 91 /* 92 * Update is a no-op 93 */ 94 if (mp->mnt_flag & MNT_UPDATE) { 95 /* 96 * Only support update mounts for NFS export. 97 */ 98 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 99 return (0); 100 else 101 return (EOPNOTSUPP); 102 } 103 104 /* 105 * Get argument 106 */ 107 error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 108 if (error || target[len - 1] != '\0') 109 return (EINVAL); 110 111 /* 112 * Unlock lower node to avoid possible deadlock. 113 */ 114 if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && 115 VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) { 116 VOP_UNLOCK(mp->mnt_vnodecovered, 0); 117 isvnunlocked = 1; 118 } 119 /* 120 * Find lower node 121 */ 122 NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); 123 error = namei(ndp); 124 /* 125 * Re-lock vnode. 126 */ 127 if (isvnunlocked) 128 vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 129 130 if (error) 131 return (error); 132 NDFREE(ndp, NDF_ONLY_PNBUF); 133 134 /* 135 * Sanity check on lower vnode 136 */ 137 lowerrootvp = ndp->ni_vp; 138 139 /* 140 * Check multi null mount to avoid `lock against myself' panic. 141 */ 142 if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 143 NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 144 vput(lowerrootvp); 145 return (EDEADLK); 146 } 147 148 xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 149 M_NULLFSMNT, M_WAITOK); /* XXX */ 150 151 /* 152 * Save reference to underlying FS 153 */ 154 xmp->nullm_vfs = lowerrootvp->v_mount; 155 156 /* 157 * Save reference. Each mount also holds 158 * a reference on the root vnode. 159 */ 160 error = null_nodeget(mp, lowerrootvp, &vp); 161 /* 162 * Make sure the node alias worked 163 */ 164 if (error) { 165 free(xmp, M_NULLFSMNT); 166 return (error); 167 } 168 169 /* 170 * Keep a held reference to the root vnode. 171 * It is vrele'd in nullfs_unmount. 172 */ 173 nullm_rootvp = vp; 174 nullm_rootvp->v_vflag |= VV_ROOT; 175 xmp->nullm_rootvp = nullm_rootvp; 176 177 /* 178 * Unlock the node (either the lower or the alias) 179 */ 180 VOP_UNLOCK(vp, 0); 181 182 if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { 183 MNT_ILOCK(mp); 184 mp->mnt_flag |= MNT_LOCAL; 185 MNT_IUNLOCK(mp); 186 } 187 MNT_ILOCK(mp); 188 mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; 189 MNT_IUNLOCK(mp); 190 mp->mnt_data = xmp; 191 vfs_getnewfsid(mp); 192 193 vfs_mountedfrom(mp, target); 194 195 NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 196 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 197 return (0); 198} 199 200/* 201 * Free reference to null layer 202 */ 203static int 204nullfs_unmount(mp, mntflags) 205 struct mount *mp; 206 int mntflags; 207{ 208 void *mntdata; 209 int error; 210 int flags = 0; 211 212 NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 213 214 if (mntflags & MNT_FORCE) 215 flags |= FORCECLOSE; 216 217 /* There is 1 extra root vnode reference (nullm_rootvp). */ 218 error = vflush(mp, 1, flags, curthread); 219 if (error) 220 return (error); 221 222 /* 223 * Finally, throw away the null_mount structure 224 */ 225 mntdata = mp->mnt_data; 226 mp->mnt_data = 0; 227 free(mntdata, M_NULLFSMNT); 228 return 0; 229} 230 231static int 232nullfs_root(mp, flags, vpp) 233 struct mount *mp; 234 int flags; 235 struct vnode **vpp; 236{ 237 struct vnode *vp; 238 239 NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 240 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 241 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 242 243 /* 244 * Return locked reference to root. 245 */ 246 vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 247 VREF(vp); 248 249 ASSERT_VOP_UNLOCKED(vp, "root vnode is locked"); 250 vn_lock(vp, flags | LK_RETRY); 251 *vpp = vp; 252 return 0; 253} 254 255static int 256nullfs_quotactl(mp, cmd, uid, arg) 257 struct mount *mp; 258 int cmd; 259 uid_t uid; 260 void *arg; 261{ 262 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg); 263} 264 265static int 266nullfs_statfs(mp, sbp) 267 struct mount *mp; 268 struct statfs *sbp; 269{ 270 int error; 271 struct statfs mstat; 272 273 NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 274 (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 275 (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 276 277 bzero(&mstat, sizeof(mstat)); 278 279 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat); 280 if (error) 281 return (error); 282 283 /* now copy across the "interesting" information and fake the rest */ 284 sbp->f_type = mstat.f_type; 285 sbp->f_flags = mstat.f_flags; 286 sbp->f_bsize = mstat.f_bsize; 287 sbp->f_iosize = mstat.f_iosize; 288 sbp->f_blocks = mstat.f_blocks; 289 sbp->f_bfree = mstat.f_bfree; 290 sbp->f_bavail = mstat.f_bavail; 291 sbp->f_files = mstat.f_files; 292 sbp->f_ffree = mstat.f_ffree; 293 return (0); 294} 295 296static int 297nullfs_sync(mp, waitfor) 298 struct mount *mp; 299 int waitfor; 300{ 301 /* 302 * XXX - Assumes no data cached at null layer. 303 */ 304 return (0); 305} 306 307static int 308nullfs_vget(mp, ino, flags, vpp) 309 struct mount *mp; 310 ino_t ino; 311 int flags; 312 struct vnode **vpp; 313{ 314 int error; 315 error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 316 if (error) 317 return (error); 318 319 return (null_nodeget(mp, *vpp, vpp)); 320} 321 322static int 323nullfs_fhtovp(mp, fidp, flags, vpp) 324 struct mount *mp; 325 struct fid *fidp; 326 int flags; 327 struct vnode **vpp; 328{ 329 int error; 330 error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, LK_EXCLUSIVE, 331 vpp); 332 if (error) 333 return (error); 334 335 return (null_nodeget(mp, *vpp, vpp)); 336} 337 338static int 339nullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname) 340 struct mount *mp; 341 int cmd; 342 struct vnode *filename_vp; 343 int namespace; 344 const char *attrname; 345{ 346 return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, 347 namespace, attrname); 348} 349 350 351static struct vfsops null_vfsops = { 352 .vfs_extattrctl = nullfs_extattrctl, 353 .vfs_fhtovp = nullfs_fhtovp, 354 .vfs_init = nullfs_init, 355 .vfs_mount = nullfs_mount, 356 .vfs_quotactl = nullfs_quotactl, 357 .vfs_root = nullfs_root, 358 .vfs_statfs = nullfs_statfs, 359 .vfs_sync = nullfs_sync, 360 .vfs_uninit = nullfs_uninit, 361 .vfs_unmount = nullfs_unmount, 362 .vfs_vget = nullfs_vget, 363}; 364 365VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL);
|