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