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.3 (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 vput(um_rootvp); 166 return (EBUSY); 167 } 168 if (error = vflush(mp, um_rootvp, flags)) { 169 vput(um_rootvp); 170 return (error); 171 } 172 173 #ifdef UNION_DIAGNOSTIC 174 vprint("alias root of lower", um_rootvp); 175 #endif 176 /* 177 * Discard references to upper and lower target vnodes. 178 */ 179 vrele(um->um_lowervp); 180 vrele(um->um_uppervp); 181 crfree(um->um_cred); 182 /* 183 * Release reference on underlying root vnode 184 */ 185 vput(um_rootvp); 186 /* 187 * And blow it away for future re-use 188 */ 189 vgone(um_rootvp); 190 /* 191 * Finally, throw away the union_mount structure 192 */ 193 free(mp->mnt_data, M_UFSMNT); /* XXX */ 194 mp->mnt_data = 0; 195 return 0; 196 } 197 198 int 199 union_root(mp, vpp) 200 struct mount *mp; 201 struct vnode **vpp; 202 { 203 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 204 int error; 205 206 #ifdef UNION_DIAGNOSTIC 207 printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp, 208 um->um_lowervp, 209 um->um_uppervp); 210 #endif 211 212 /* 213 * Return locked reference to root. 214 */ 215 VREF(um->um_uppervp); 216 VREF(um->um_lowervp); 217 error = union_allocvp(vpp, mp, (struct vnode *) 0, 218 (struct componentname *) 0, 219 um->um_uppervp, 220 um->um_lowervp); 221 222 if (error) { 223 vrele(um->um_uppervp); 224 vrele(um->um_lowervp); 225 } else { 226 (*vpp)->v_flag |= VROOT; 227 } 228 229 return (error); 230 } 231 232 int 233 union_quotactl(mp, cmd, uid, arg, p) 234 struct mount *mp; 235 int cmd; 236 uid_t uid; 237 caddr_t arg; 238 struct proc *p; 239 { 240 241 return (EOPNOTSUPP); 242 } 243 244 int 245 union_statfs(mp, sbp, p) 246 struct mount *mp; 247 struct statfs *sbp; 248 struct proc *p; 249 { 250 int error; 251 struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 252 struct statfs mstat; 253 int lbsize; 254 255 #ifdef UNION_DIAGNOSTIC 256 printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp, 257 um->um_lowervp, 258 um->um_uppervp); 259 #endif 260 261 bzero(&mstat, sizeof(mstat)); 262 263 error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p); 264 if (error) 265 return (error); 266 267 /* now copy across the "interesting" information and fake the rest */ 268 #if 0 269 sbp->f_type = mstat.f_type; 270 sbp->f_flags = mstat.f_flags; 271 sbp->f_bsize = mstat.f_bsize; 272 sbp->f_iosize = mstat.f_iosize; 273 #endif 274 lbsize = mstat.f_bsize; 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 281 error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p); 282 if (error) 283 return (error); 284 285 sbp->f_type = mstat.f_type; 286 sbp->f_flags = mstat.f_flags; 287 sbp->f_bsize = mstat.f_bsize; 288 sbp->f_iosize = mstat.f_iosize; 289 290 /* 291 * if the lower and upper blocksizes differ, then frig the 292 * block counts so that the sizes reported by df make some 293 * kind of sense. none of this makes sense though. 294 */ 295 296 if (mstat.f_bsize != lbsize) { 297 sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize; 298 sbp->f_bfree = sbp->f_bfree * lbsize / mstat.f_bsize; 299 sbp->f_bavail = sbp->f_bavail * lbsize / mstat.f_bsize; 300 } 301 sbp->f_blocks += mstat.f_blocks; 302 sbp->f_bfree += mstat.f_bfree; 303 sbp->f_bavail += mstat.f_bavail; 304 sbp->f_files += mstat.f_files; 305 sbp->f_ffree += mstat.f_ffree; 306 307 if (sbp != &mp->mnt_stat) { 308 bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 309 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 310 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 311 } 312 return (0); 313 } 314 315 int 316 union_sync(mp, waitfor, cred, p) 317 struct mount *mp; 318 int waitfor; 319 struct ucred *cred; 320 struct proc *p; 321 { 322 323 /* 324 * XXX - Assumes no data cached at union layer. 325 */ 326 return (0); 327 } 328 329 int 330 union_vget(mp, ino, vpp) 331 struct mount *mp; 332 ino_t ino; 333 struct vnode **vpp; 334 { 335 336 return (EOPNOTSUPP); 337 } 338 339 int 340 union_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 341 struct mount *mp; 342 struct fid *fidp; 343 struct mbuf *nam; 344 struct vnode **vpp; 345 int *exflagsp; 346 struct ucred **credanonp; 347 { 348 349 return (EOPNOTSUPP); 350 } 351 352 int 353 union_vptofh(vp, fhp) 354 struct vnode *vp; 355 struct fid *fhp; 356 { 357 358 return (EOPNOTSUPP); 359 } 360 361 int union_init __P((void)); 362 363 struct vfsops union_vfsops = { 364 union_mount, 365 union_start, 366 union_unmount, 367 union_root, 368 union_quotactl, 369 union_statfs, 370 union_sync, 371 union_vget, 372 union_fhtovp, 373 union_vptofh, 374 union_init, 375 }; 376