1 /* 2 * Copyright (c) 1992, 1993 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 * %sccs.include.redist.c% 9 * 10 * @(#)null_vfsops.c 8.4 (Berkeley) 03/29/95 11 * 12 * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 13 * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 14 */ 15 16 /* 17 * Null Layer 18 * (See null_vnops.c for a description of what this does.) 19 */ 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/time.h> 24 #include <sys/types.h> 25 #include <sys/vnode.h> 26 #include <sys/mount.h> 27 #include <sys/namei.h> 28 #include <sys/malloc.h> 29 #include <miscfs/nullfs/null.h> 30 31 /* 32 * Mount null layer 33 */ 34 int 35 nullfs_mount(mp, path, data, ndp, p) 36 struct mount *mp; 37 char *path; 38 caddr_t data; 39 struct nameidata *ndp; 40 struct proc *p; 41 { 42 int error = 0; 43 struct null_args args; 44 struct vnode *lowerrootvp, *vp; 45 struct vnode *nullm_rootvp; 46 struct null_mount *xmp; 47 u_int size; 48 49 #ifdef NULLFS_DIAGNOSTIC 50 printf("nullfs_mount(mp = %x)\n", mp); 51 #endif 52 53 /* 54 * Update is a no-op 55 */ 56 if (mp->mnt_flag & MNT_UPDATE) { 57 return (EOPNOTSUPP); 58 /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ 59 } 60 61 /* 62 * Get argument 63 */ 64 if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args))) 65 return (error); 66 67 /* 68 * Find lower node 69 */ 70 NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 71 UIO_USERSPACE, args.target, p); 72 if (error = namei(ndp)) 73 return (error); 74 75 /* 76 * Sanity check on lower vnode 77 */ 78 lowerrootvp = ndp->ni_vp; 79 80 vrele(ndp->ni_dvp); 81 ndp->ni_dvp = NULL; 82 83 xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 84 M_UFSMNT, M_WAITOK); /* XXX */ 85 86 /* 87 * Save reference to underlying FS 88 */ 89 xmp->nullm_vfs = lowerrootvp->v_mount; 90 91 /* 92 * Save reference. Each mount also holds 93 * a reference on the root vnode. 94 */ 95 error = null_node_create(mp, lowerrootvp, &vp); 96 /* 97 * Unlock the node (either the lower or the alias) 98 */ 99 VOP_UNLOCK(vp); 100 /* 101 * Make sure the node alias worked 102 */ 103 if (error) { 104 vrele(lowerrootvp); 105 free(xmp, M_UFSMNT); /* XXX */ 106 return (error); 107 } 108 109 /* 110 * Keep a held reference to the root vnode. 111 * It is vrele'd in nullfs_unmount. 112 */ 113 nullm_rootvp = vp; 114 nullm_rootvp->v_flag |= VROOT; 115 xmp->nullm_rootvp = nullm_rootvp; 116 if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 117 mp->mnt_flag |= MNT_LOCAL; 118 mp->mnt_data = (qaddr_t) xmp; 119 vfs_getnewfsid(mp); 120 121 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 122 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 123 (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 124 &size); 125 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 126 #ifdef NULLFS_DIAGNOSTIC 127 printf("nullfs_mount: lower %s, alias at %s\n", 128 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 129 #endif 130 return (0); 131 } 132 133 /* 134 * VFS start. Nothing needed here - the start routine 135 * on the underlying filesystem will have been called 136 * when that filesystem was mounted. 137 */ 138 int 139 nullfs_start(mp, flags, p) 140 struct mount *mp; 141 int flags; 142 struct proc *p; 143 { 144 return (0); 145 /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ 146 } 147 148 /* 149 * Free reference to null layer 150 */ 151 int 152 nullfs_unmount(mp, mntflags, p) 153 struct mount *mp; 154 int mntflags; 155 struct proc *p; 156 { 157 struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 158 int error; 159 int flags = 0; 160 extern int doforce; 161 162 #ifdef NULLFS_DIAGNOSTIC 163 printf("nullfs_unmount(mp = %x)\n", mp); 164 #endif 165 166 if (mntflags & MNT_FORCE) { 167 /* lofs can never be rootfs so don't check for it */ 168 if (!doforce) 169 return (EINVAL); 170 flags |= FORCECLOSE; 171 } 172 173 /* 174 * Clear out buffer cache. I don't think we 175 * ever get anything cached at this level at the 176 * moment, but who knows... 177 */ 178 #if 0 179 mntflushbuf(mp, 0); 180 if (mntinvalbuf(mp, 1)) 181 return (EBUSY); 182 #endif 183 if (nullm_rootvp->v_usecount > 1) 184 return (EBUSY); 185 if (error = vflush(mp, nullm_rootvp, flags)) 186 return (error); 187 188 #ifdef NULLFS_DIAGNOSTIC 189 vprint("alias root of lower", nullm_rootvp); 190 #endif 191 /* 192 * Release reference on underlying root vnode 193 */ 194 vrele(nullm_rootvp); 195 /* 196 * And blow it away for future re-use 197 */ 198 VOP_REVOKE(nullm_rootvp, 0); 199 /* 200 * Finally, throw away the null_mount structure 201 */ 202 free(mp->mnt_data, M_UFSMNT); /* XXX */ 203 mp->mnt_data = 0; 204 return 0; 205 } 206 207 int 208 nullfs_root(mp, vpp) 209 struct mount *mp; 210 struct vnode **vpp; 211 { 212 struct vnode *vp; 213 214 #ifdef NULLFS_DIAGNOSTIC 215 printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 216 MOUNTTONULLMOUNT(mp)->nullm_rootvp, 217 NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 218 ); 219 #endif 220 221 /* 222 * Return locked reference to root. 223 */ 224 vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 225 VREF(vp); 226 VOP_LOCK(vp); 227 *vpp = vp; 228 return 0; 229 } 230 231 int 232 nullfs_quotactl(mp, cmd, uid, arg, p) 233 struct mount *mp; 234 int cmd; 235 uid_t uid; 236 caddr_t arg; 237 struct proc *p; 238 { 239 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 240 } 241 242 int 243 nullfs_statfs(mp, sbp, p) 244 struct mount *mp; 245 struct statfs *sbp; 246 struct proc *p; 247 { 248 int error; 249 struct statfs mstat; 250 251 #ifdef NULLFS_DIAGNOSTIC 252 printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 253 MOUNTTONULLMOUNT(mp)->nullm_rootvp, 254 NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 255 ); 256 #endif 257 258 bzero(&mstat, sizeof(mstat)); 259 260 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 261 if (error) 262 return (error); 263 264 /* now copy across the "interesting" information and fake the rest */ 265 sbp->f_type = mstat.f_type; 266 sbp->f_flags = mstat.f_flags; 267 sbp->f_bsize = mstat.f_bsize; 268 sbp->f_iosize = mstat.f_iosize; 269 sbp->f_blocks = mstat.f_blocks; 270 sbp->f_bfree = mstat.f_bfree; 271 sbp->f_bavail = mstat.f_bavail; 272 sbp->f_files = mstat.f_files; 273 sbp->f_ffree = mstat.f_ffree; 274 if (sbp != &mp->mnt_stat) { 275 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 276 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 277 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 278 } 279 return (0); 280 } 281 282 int 283 nullfs_sync(mp, waitfor, cred, p) 284 struct mount *mp; 285 int waitfor; 286 struct ucred *cred; 287 struct proc *p; 288 { 289 /* 290 * XXX - Assumes no data cached at null layer. 291 */ 292 return (0); 293 } 294 295 int 296 nullfs_vget(mp, ino, vpp) 297 struct mount *mp; 298 ino_t ino; 299 struct vnode **vpp; 300 { 301 302 return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); 303 } 304 305 int 306 nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 307 struct mount *mp; 308 struct fid *fidp; 309 struct mbuf *nam; 310 struct vnode **vpp; 311 int *exflagsp; 312 struct ucred**credanonp; 313 { 314 315 return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp); 316 } 317 318 int 319 nullfs_vptofh(vp, fhp) 320 struct vnode *vp; 321 struct fid *fhp; 322 { 323 return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); 324 } 325 326 int nullfs_init __P((struct vfsconf *)); 327 328 #define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ 329 size_t, struct proc *)))eopnotsupp) 330 331 struct vfsops null_vfsops = { 332 nullfs_mount, 333 nullfs_start, 334 nullfs_unmount, 335 nullfs_root, 336 nullfs_quotactl, 337 nullfs_statfs, 338 nullfs_sync, 339 nullfs_vget, 340 nullfs_fhtovp, 341 nullfs_vptofh, 342 nullfs_init, 343 nullfs_sysctl, 344 }; 345