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 * %sccs.include.redist.c% 9 * 10 * @(#)null_vfsops.c 8.6 (Berkeley) 05/10/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 161 #ifdef NULLFS_DIAGNOSTIC 162 printf("nullfs_unmount(mp = %x)\n", mp); 163 #endif 164 165 if (mntflags & MNT_FORCE) 166 flags |= FORCECLOSE; 167 168 /* 169 * Clear out buffer cache. I don't think we 170 * ever get anything cached at this level at the 171 * moment, but who knows... 172 */ 173 #if 0 174 mntflushbuf(mp, 0); 175 if (mntinvalbuf(mp, 1)) 176 return (EBUSY); 177 #endif 178 if (nullm_rootvp->v_usecount > 1) 179 return (EBUSY); 180 if (error = vflush(mp, nullm_rootvp, flags)) 181 return (error); 182 183 #ifdef NULLFS_DIAGNOSTIC 184 vprint("alias root of lower", nullm_rootvp); 185 #endif 186 /* 187 * Release reference on underlying root vnode 188 */ 189 vrele(nullm_rootvp); 190 /* 191 * And blow it away for future re-use 192 */ 193 vgone(nullm_rootvp); 194 /* 195 * Finally, throw away the null_mount structure 196 */ 197 free(mp->mnt_data, M_UFSMNT); /* XXX */ 198 mp->mnt_data = 0; 199 return 0; 200 } 201 202 int 203 nullfs_root(mp, vpp) 204 struct mount *mp; 205 struct vnode **vpp; 206 { 207 struct vnode *vp; 208 209 #ifdef NULLFS_DIAGNOSTIC 210 printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 211 MOUNTTONULLMOUNT(mp)->nullm_rootvp, 212 NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 213 ); 214 #endif 215 216 /* 217 * Return locked reference to root. 218 */ 219 vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 220 VREF(vp); 221 VOP_LOCK(vp); 222 *vpp = vp; 223 return 0; 224 } 225 226 int 227 nullfs_quotactl(mp, cmd, uid, arg, p) 228 struct mount *mp; 229 int cmd; 230 uid_t uid; 231 caddr_t arg; 232 struct proc *p; 233 { 234 return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 235 } 236 237 int 238 nullfs_statfs(mp, sbp, p) 239 struct mount *mp; 240 struct statfs *sbp; 241 struct proc *p; 242 { 243 int error; 244 struct statfs mstat; 245 246 #ifdef NULLFS_DIAGNOSTIC 247 printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 248 MOUNTTONULLMOUNT(mp)->nullm_rootvp, 249 NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 250 ); 251 #endif 252 253 bzero(&mstat, sizeof(mstat)); 254 255 error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 256 if (error) 257 return (error); 258 259 /* now copy across the "interesting" information and fake the rest */ 260 sbp->f_type = mstat.f_type; 261 sbp->f_flags = mstat.f_flags; 262 sbp->f_bsize = mstat.f_bsize; 263 sbp->f_iosize = mstat.f_iosize; 264 sbp->f_blocks = mstat.f_blocks; 265 sbp->f_bfree = mstat.f_bfree; 266 sbp->f_bavail = mstat.f_bavail; 267 sbp->f_files = mstat.f_files; 268 sbp->f_ffree = mstat.f_ffree; 269 if (sbp != &mp->mnt_stat) { 270 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 271 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 272 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 273 } 274 return (0); 275 } 276 277 int 278 nullfs_sync(mp, waitfor, cred, p) 279 struct mount *mp; 280 int waitfor; 281 struct ucred *cred; 282 struct proc *p; 283 { 284 /* 285 * XXX - Assumes no data cached at null layer. 286 */ 287 return (0); 288 } 289 290 int 291 nullfs_vget(mp, ino, vpp) 292 struct mount *mp; 293 ino_t ino; 294 struct vnode **vpp; 295 { 296 297 return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); 298 } 299 300 int 301 nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 302 struct mount *mp; 303 struct fid *fidp; 304 struct mbuf *nam; 305 struct vnode **vpp; 306 int *exflagsp; 307 struct ucred**credanonp; 308 { 309 310 return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp); 311 } 312 313 int 314 nullfs_vptofh(vp, fhp) 315 struct vnode *vp; 316 struct fid *fhp; 317 { 318 return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); 319 } 320 321 int nullfs_init __P((struct vfsconf *)); 322 323 #define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ 324 size_t, struct proc *)))eopnotsupp) 325 326 struct vfsops null_vfsops = { 327 nullfs_mount, 328 nullfs_start, 329 nullfs_unmount, 330 nullfs_root, 331 nullfs_quotactl, 332 nullfs_statfs, 333 nullfs_sync, 334 nullfs_vget, 335 nullfs_fhtovp, 336 nullfs_vptofh, 337 nullfs_init, 338 nullfs_sysctl, 339 }; 340