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