1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 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 8.1 (Berkeley) 06/10/93 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 <miscfs/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 if (rootvp->v_usecount > 1) 186 return (EBUSY); 187 if (error = vflush(mp, rootvp, flags)) 188 return (error); 189 190 #ifdef LOFS_DIAGNOSTIC 191 /* 192 * Flush any remaining vnode references 193 */ 194 lofs_flushmp(mp); 195 #endif 196 197 #ifdef LOFS_DIAGNOSTIC 198 vprint("alias root of target", rootvp); 199 #endif 200 /* 201 * Release reference on underlying root vnode 202 */ 203 vrele(rootvp); 204 /* 205 * And blow it away for future re-use 206 */ 207 vgone(rootvp); 208 /* 209 * Finally, throw away the lofsmount structure 210 */ 211 free(mp->mnt_data, M_UFSMNT); /* XXX */ 212 mp->mnt_data = 0; 213 return 0; 214 } 215 216 lofs_root(mp, vpp) 217 struct mount *mp; 218 struct vnode **vpp; 219 { 220 struct vnode *vp; 221 222 #ifdef LOFS_DIAGNOSTIC 223 printf("lofs_root(mp = %x, vp = %x->%x)\n", mp, 224 VFSTOLOFS(mp)->rootvp, 225 LOFSVP(VFSTOLOFS(mp)->rootvp) 226 ); 227 #endif 228 229 /* 230 * Return locked reference to root. 231 */ 232 vp = VFSTOLOFS(mp)->rootvp; 233 VREF(vp); 234 VOP_LOCK(vp); 235 *vpp = vp; 236 return 0; 237 } 238 239 lofs_quotactl(mp, cmd, uid, arg, p) 240 struct mount *mp; 241 int cmd; 242 uid_t uid; 243 caddr_t arg; 244 struct proc *p; 245 { 246 return VFS_QUOTACTL(VFSTOLOFS(mp)->looped_vfs, cmd, uid, arg, p); 247 } 248 249 lofs_statfs(mp, sbp, p) 250 struct mount *mp; 251 struct statfs *sbp; 252 struct proc *p; 253 { 254 int error; 255 struct statfs mstat; 256 257 #ifdef LOFS_DIAGNOSTIC 258 printf("lofs_statfs(mp = %x, vp = %x->%x)\n", mp, 259 VFSTOLOFS(mp)->rootvp, 260 LOFSVP(VFSTOLOFS(mp)->rootvp) 261 ); 262 #endif 263 264 bzero(&mstat, sizeof(mstat)); 265 266 error = VFS_STATFS(VFSTOLOFS(mp)->looped_vfs, &mstat, p); 267 if (error) 268 return (error); 269 270 /* now copy across the "interesting" information and fake the rest */ 271 sbp->f_type = mstat.f_type; 272 sbp->f_flags = mstat.f_flags; 273 sbp->f_bsize = mstat.f_bsize; 274 sbp->f_iosize = mstat.f_iosize; 275 sbp->f_blocks = mstat.f_blocks; 276 sbp->f_bfree = mstat.f_bfree; 277 sbp->f_bavail = mstat.f_bavail; 278 sbp->f_files = mstat.f_files; 279 sbp->f_ffree = mstat.f_ffree; 280 if (sbp != &mp->mnt_stat) { 281 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 282 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 283 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 284 } 285 return (0); 286 } 287 288 lofs_sync(mp, waitfor) 289 struct mount *mp; 290 int waitfor; 291 { 292 return (0); 293 } 294 295 /* 296 * LOFS flat namespace lookup. 297 * Currently unsupported. 298 */ 299 lofs_vget(mp, ino, vpp) 300 struct mount *mp; 301 ino_t ino; 302 struct vnode **vpp; 303 { 304 305 return (EOPNOTSUPP); 306 } 307 308 lofs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 309 register struct mount *mp; 310 struct fid *fhp; 311 struct mbuf *nam; 312 struct vnode **vpp; 313 int *exflagsp; 314 struct ucred **credanonp; 315 { 316 return VFS_FHTOVP(VFSTOLOFS(mp)->looped_vfs, fhp, nam, vpp, exflagsp, credanonp); 317 } 318 319 lofs_vptofh(vp, fhp) 320 struct vnode *vp; 321 struct fid *fhp; 322 { 323 return VFS_VPTOFH(LOFSVP(vp), fhp); 324 } 325 326 int lofs_init __P((void)); 327 328 struct vfsops lofs_vfsops = { 329 lofs_mount, 330 lofs_start, 331 lofs_unmount, 332 lofs_root, 333 lofs_quotactl, 334 lofs_statfs, 335 lofs_sync, 336 lofs_vget, 337 lofs_fhtovp, 338 lofs_vptofh, 339 lofs_init, 340 }; 341