1 /* 2 * Copyright (c) 1994 The Regents of the University of California. 3 * Copyright (c) 1994 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 * @(#)union_vfsops.c 1.2 (Berkeley) 02/01/94 12 */ 13 14 /* 15 * Null Layer 16 * (See union_vnops.c for a description of what this does.) 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/proc.h> 24 #include <sys/vnode.h> 25 #include <sys/mount.h> 26 #include <sys/namei.h> 27 #include <sys/malloc.h> 28 #include "union.h" 29 30 /* 31 * Mount union filesystem 32 */ 33 int 34 union_mount(mp, path, data, ndp, p) 35 struct mount *mp; 36 char *path; 37 caddr_t data; 38 struct nameidata *ndp; 39 struct proc *p; 40 { 41 int error = 0; 42 struct union_args args; 43 struct vnode *lowerrootvp; 44 struct vnode *upperrootvp; 45 struct union_mount *um; 46 u_int size; 47 48 #ifdef UNION_DIAGNOSTIC 49 printf("union_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 58 /* 59 * Get argument 60 */ 61 if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args))) 62 return (error); 63 64 lowerrootvp = mp->mnt_vnodecovered; 65 VREF(lowerrootvp); 66 67 /* 68 * Find upper node 69 */ 70 NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT, 71 UIO_USERSPACE, args.target, p); 72 if (error = namei(ndp)) { 73 vrele(lowerrootvp); 74 return (error); 75 } 76 upperrootvp = ndp->ni_vp; 77 vrele(ndp->ni_dvp); 78 ndp->ni_dvp = NULL; 79 80 if (upperrootvp->v_type != VDIR) { 81 vrele(upperrootvp); 82 return (EINVAL); 83 } 84 85 um = (struct union_mount *) malloc(sizeof(struct union_mount), 86 M_UFSMNT, M_WAITOK); /* XXX */ 87 88 /* 89 * Keep a held reference to the target vnodes. 90 * They are vrele'd in union_unmount. 91 */ 92 um->um_lowervp = lowerrootvp; 93 um->um_uppervp = upperrootvp; 94 /* 95 * Take a copy of the process's credentials. This isn't 96 * quite right since the euid will always be zero and we 97 * want to get the "real" users credentials. So fix up 98 * the uid field after taking the copy. 99 */ 100 um->um_cred = crdup(p->p_ucred); 101 um->um_cred->cr_uid = p->p_cred->p_ruid; 102 103 if ((lowerrootvp->v_mount->mnt_flag & MNT_LOCAL) || 104 (upperrootvp->v_mount->mnt_flag & MNT_LOCAL)) 105 mp->mnt_flag |= MNT_LOCAL; 106 mp->mnt_data = (qaddr_t) um; 107 getnewfsid(mp, MOUNT_UNION); 108 109 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 110 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 111 (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 112 &size); 113 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 114 #ifdef UNION_DIAGNOSTIC 115 printf("union_mount: upper %s, lower at %s\n", 116 mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 117 #endif 118 return (0); 119 } 120 121 /* 122 * VFS start. Nothing needed here - the start routine 123 * on the underlying filesystem(s) will have been called 124 * when that filesystem was mounted. 125 */ 126 int 127 union_start(mp, flags, p) 128 struct mount *mp; 129 int flags; 130 struct proc *p; 131 { 132 133 return (0); 134 } 135 136 /* 137 * Free reference to union layer 138 */ 139 int 140 union_unmount(mp, mntflags, p) 141 struct mount *mp; 142 int mntflags; 143 struct proc *p; 144 { 145 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 146 struct vnode *um_rootvp; 147 int error; 148 int flags = 0; 149 extern int doforce; 150 151 #ifdef UNION_DIAGNOSTIC 152 printf("union_unmount(mp = %x)\n", mp); 153 #endif 154 155 if (mntflags & MNT_FORCE) { 156 /* union can never be rootfs so don't check for it */ 157 if (!doforce) 158 return (EINVAL); 159 flags |= FORCECLOSE; 160 } 161 162 if (error = union_root(mp, &um_rootvp)) 163 return (error); 164 if (um_rootvp->v_usecount > 1) 165 return (EBUSY); 166 if (error = vflush(mp, um_rootvp, flags)) 167 return (error); 168 169 #ifdef UNION_DIAGNOSTIC 170 vprint("alias root of lower", um_rootvp); 171 #endif 172 /* 173 * Discard references to upper and lower target vnodes. 174 */ 175 vrele(um->um_lowervp); 176 vrele(um->um_uppervp); 177 crfree(um->um_cred); 178 /* 179 * Release reference on underlying root vnode 180 */ 181 vrele(um_rootvp); 182 /* 183 * And blow it away for future re-use 184 */ 185 vgone(um_rootvp); 186 /* 187 * Finally, throw away the union_mount structure 188 */ 189 free(mp->mnt_data, M_UFSMNT); /* XXX */ 190 mp->mnt_data = 0; 191 return 0; 192 } 193 194 int 195 union_root(mp, vpp) 196 struct mount *mp; 197 struct vnode **vpp; 198 { 199 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 200 int error; 201 202 #ifdef UNION_DIAGNOSTIC 203 printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp, 204 um->um_lowervp, 205 um->um_uppervp); 206 #endif 207 208 /* 209 * Return locked reference to root. 210 */ 211 error = union_allocvp(vpp, mp, (struct vnode *) 0, 212 (struct componentname *) 0, 213 um->um_uppervp, 214 um->um_lowervp); 215 if (error == 0) 216 (*vpp)->v_flag |= VROOT; 217 218 return (error); 219 } 220 221 int 222 union_quotactl(mp, cmd, uid, arg, p) 223 struct mount *mp; 224 int cmd; 225 uid_t uid; 226 caddr_t arg; 227 struct proc *p; 228 { 229 230 return (EOPNOTSUPP); 231 } 232 233 int 234 union_statfs(mp, sbp, p) 235 struct mount *mp; 236 struct statfs *sbp; 237 struct proc *p; 238 { 239 int error; 240 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 241 struct statfs mstat; 242 int lbsize; 243 244 #ifdef UNION_DIAGNOSTIC 245 printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp, 246 um->um_lowervp, 247 um->um_uppervp); 248 #endif 249 250 bzero(&mstat, sizeof(mstat)); 251 252 error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p); 253 if (error) 254 return (error); 255 256 /* now copy across the "interesting" information and fake the rest */ 257 #if 0 258 sbp->f_type = mstat.f_type; 259 sbp->f_flags = mstat.f_flags; 260 sbp->f_bsize = mstat.f_bsize; 261 sbp->f_iosize = mstat.f_iosize; 262 #endif 263 lbsize = mstat.f_bsize; 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 270 error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p); 271 if (error) 272 return (error); 273 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 279 /* 280 * if the lower and upper blocksizes differ, then frig the 281 * block counts so that the sizes reported by df make some 282 * kind of sense. none of this makes sense though. 283 */ 284 285 if (mstat.f_bsize != lbsize) { 286 sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize; 287 sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize; 288 sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize; 289 } 290 sbp->f_blocks += mstat.f_blocks; 291 sbp->f_bfree += mstat.f_bfree; 292 sbp->f_bavail += mstat.f_bavail; 293 sbp->f_files += mstat.f_files; 294 sbp->f_ffree += mstat.f_ffree; 295 296 if (sbp != &mp->mnt_stat) { 297 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 298 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 299 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 300 } 301 return (0); 302 } 303 304 int 305 union_sync(mp, waitfor, cred, p) 306 struct mount *mp; 307 int waitfor; 308 struct ucred *cred; 309 struct proc *p; 310 { 311 312 /* 313 * XXX - Assumes no data cached at union layer. 314 */ 315 return (0); 316 } 317 318 int 319 union_vget(mp, ino, vpp) 320 struct mount *mp; 321 ino_t ino; 322 struct vnode **vpp; 323 { 324 325 return (EOPNOTSUPP); 326 } 327 328 int 329 union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 330 struct mount *mp; 331 struct fid *fidp; 332 struct mbuf *nam; 333 struct vnode **vpp; 334 int *exflagsp; 335 struct ucred **credanonp; 336 { 337 338 return (EOPNOTSUPP); 339 } 340 341 int 342 union_vptofh(vp, fhp) 343 struct vnode *vp; 344 struct fid *fhp; 345 { 346 347 return (EOPNOTSUPP); 348 } 349 350 int union_init __P((void)); 351 352 struct vfsops union_vfsops = { 353 union_mount, 354 union_start, 355 union_unmount, 356 union_root, 357 union_quotactl, 358 union_statfs, 359 union_sync, 360 union_vget, 361 union_fhtovp, 362 union_vptofh, 363 union_init, 364 }; 365