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