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