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