checkpoint (first pass at "...")
[unix-history] / usr / src / sys / miscfs / union / union_vnops.c
CommitLineData
a1fa407d
JSP
1/*
2 * Copyright (c) 1992, 1993, 1994 The Regents of the University of California.
3 * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
12abe7b1 7 * Jan-Simon Pendry.
a1fa407d
JSP
8 *
9 * %sccs.include.redist.c%
10 *
5bc3cb24 11 * @(#)union_vnops.c 8.18 (Berkeley) %G%
a1fa407d
JSP
12 */
13
14#include <sys/param.h>
15#include <sys/systm.h>
16#include <sys/proc.h>
17#include <sys/file.h>
a1fa407d
JSP
18#include <sys/time.h>
19#include <sys/types.h>
20#include <sys/vnode.h>
21#include <sys/mount.h>
22#include <sys/namei.h>
23#include <sys/malloc.h>
24#include <sys/buf.h>
58572fc0 25#include <sys/queue.h>
2e1ae99e 26#include <miscfs/union/union.h>
a1fa407d 27
c1b204a8
JSP
28#define FIXUP(un) { \
29 if (((un)->un_flags & UN_ULOCK) == 0) { \
30 union_fixup(un); \
31 } \
32}
33
34static void
35union_fixup(un)
36 struct union_node *un;
37{
38
39 VOP_LOCK(un->un_uppervp);
40 un->un_flags |= UN_ULOCK;
41}
42
a1fa407d 43static int
df24bc61 44union_lookup1(udvp, dvpp, vpp, cnp)
79f80c71 45 struct vnode *udvp;
df24bc61 46 struct vnode **dvpp;
a1fa407d
JSP
47 struct vnode **vpp;
48 struct componentname *cnp;
49{
50 int error;
51 struct vnode *tdvp;
df24bc61 52 struct vnode *dvp;
a1fa407d
JSP
53 struct mount *mp;
54
df24bc61
JSP
55 dvp = *dvpp;
56
81be6ee0
JSP
57 /*
58 * If stepping up the directory tree, check for going
59 * back across the mount point, in which case do what
60 * lookup would do by stepping back down the mount
61 * hierarchy.
62 */
a1fa407d 63 if (cnp->cn_flags & ISDOTDOT) {
df24bc61 64 while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
692a90df
JSP
65 /*
66 * Don't do the NOCROSSMOUNT check
67 * at this level. By definition,
68 * union fs deals with namespaces, not
69 * filesystems.
70 */
a1fa407d 71 tdvp = dvp;
df24bc61 72 *dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
a1fa407d
JSP
73 vput(tdvp);
74 VREF(dvp);
75 VOP_LOCK(dvp);
76 }
77 }
ed5969c8 78
a1fa407d
JSP
79 error = VOP_LOOKUP(dvp, &tdvp, cnp);
80 if (error)
81 return (error);
82
81be6ee0 83 /*
ed5969c8
JSP
84 * The parent directory will have been unlocked, unless lookup
85 * found the last component. In which case, re-lock the node
86 * here to allow it to be unlocked again (phew) in union_lookup.
81be6ee0 87 */
ed5969c8 88 if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
81be6ee0
JSP
89 VOP_LOCK(dvp);
90
a1fa407d 91 dvp = tdvp;
81be6ee0
JSP
92
93 /*
94 * Lastly check if the current node is a mount point in
692a90df 95 * which case walk up the mount hierarchy making sure not to
81be6ee0
JSP
96 * bump into the root of the mount tree (ie. dvp != udvp).
97 */
79f80c71 98 while (dvp != udvp && (dvp->v_type == VDIR) &&
692a90df 99 (mp = dvp->v_mountedhere)) {
a1fa407d
JSP
100
101 if (mp->mnt_flag & MNT_MLOCK) {
102 mp->mnt_flag |= MNT_MWAIT;
103 sleep((caddr_t) mp, PVFS);
104 continue;
105 }
106
107 if (error = VFS_ROOT(mp, &tdvp)) {
108 vput(dvp);
109 return (error);
110 }
111
01dac67e 112 vput(dvp);
a1fa407d
JSP
113 dvp = tdvp;
114 }
115
116 *vpp = dvp;
117 return (0);
118}
119
120int
121union_lookup(ap)
122 struct vop_lookup_args /* {
123 struct vnodeop_desc *a_desc;
124 struct vnode *a_dvp;
125 struct vnode **a_vpp;
126 struct componentname *a_cnp;
127 } */ *ap;
128{
01dac67e 129 int error;
a1fa407d
JSP
130 int uerror, lerror;
131 struct vnode *uppervp, *lowervp;
132 struct vnode *upperdvp, *lowerdvp;
133 struct vnode *dvp = ap->a_dvp;
79f80c71 134 struct union_node *dun = VTOUNION(dvp);
a1fa407d
JSP
135 struct componentname *cnp = ap->a_cnp;
136 int lockparent = cnp->cn_flags & LOCKPARENT;
81be6ee0 137 int rdonly = cnp->cn_flags & RDONLY;
3b293975 138 struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
c1b204a8 139 struct ucred *saved_cred;
a1fa407d 140
5bc3cb24
JSP
141#ifdef notyet
142 if (cnp->cn_namelen == 3 &&
143 cnp->cn_nameptr[2] == '.' &&
144 cnp->cn_nameptr[1] == '.' &&
145 cnp->cn_nameptr[0] == '.') {
146 dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
147 if (dvp == NULLVP)
148 return (ENOENT);
149 VREF(dvp);
150 VOP_LOCK(dvp);
151 if (!lockparent || !(cnp->cn_flags & ISLASTCN))
152 VOP_UNLOCK(ap->a_dvp);
153 return (0);
154 }
155#endif
156
01dac67e
JSP
157 cnp->cn_flags |= LOCKPARENT;
158
a1fa407d
JSP
159 upperdvp = dun->un_uppervp;
160 lowerdvp = dun->un_lowervp;
3b293975
JSP
161 uppervp = NULLVP;
162 lowervp = NULLVP;
a1fa407d
JSP
163
164 /*
165 * do the lookup in the upper level.
166 * if that level comsumes additional pathnames,
167 * then assume that something special is going
168 * on and just return that vnode.
169 */
050766c6 170 if (upperdvp != NULLVP) {
c1b204a8 171 FIXUP(dun);
df24bc61 172 uerror = union_lookup1(um->um_uppervp, &upperdvp,
3b293975 173 &uppervp, cnp);
e2a2f3a7
JSP
174 /*if (uppervp == upperdvp)
175 dun->un_flags |= UN_KLOCK;*/
01dac67e 176
a1fa407d
JSP
177 if (cnp->cn_consume != 0) {
178 *ap->a_vpp = uppervp;
01dac67e
JSP
179 if (!lockparent)
180 cnp->cn_flags &= ~LOCKPARENT;
a1fa407d
JSP
181 return (uerror);
182 }
a1fa407d
JSP
183 } else {
184 uerror = ENOENT;
185 }
186
187 /*
188 * in a similar way to the upper layer, do the lookup
189 * in the lower layer. this time, if there is some
190 * component magic going on, then vput whatever we got
191 * back from the upper layer and return the lower vnode
192 * instead.
193 */
050766c6 194 if (lowerdvp != NULLVP) {
e2a2f3a7
JSP
195 int nameiop;
196
01dac67e 197 VOP_LOCK(lowerdvp);
e2a2f3a7
JSP
198
199 /*
200 * Only do a LOOKUP on the bottom node, since
201 * we won't be making changes to it anyway.
202 */
203 nameiop = cnp->cn_nameiop;
204 cnp->cn_nameiop = LOOKUP;
c1b204a8
JSP
205 if (um->um_op == UNMNT_BELOW) {
206 saved_cred = cnp->cn_cred;
207 cnp->cn_cred = um->um_cred;
208 }
df24bc61 209 lerror = union_lookup1(um->um_lowervp, &lowerdvp,
e2a2f3a7 210 &lowervp, cnp);
c1b204a8
JSP
211 if (um->um_op == UNMNT_BELOW)
212 cnp->cn_cred = saved_cred;
e2a2f3a7
JSP
213 cnp->cn_nameiop = nameiop;
214
79f80c71
JSP
215 if (lowervp != lowerdvp)
216 VOP_UNLOCK(lowerdvp);
01dac67e 217
a1fa407d 218 if (cnp->cn_consume != 0) {
050766c6 219 if (uppervp != NULLVP) {
e2a2f3a7
JSP
220 if (uppervp == upperdvp)
221 vrele(uppervp);
222 else
223 vput(uppervp);
3b293975 224 uppervp = NULLVP;
a1fa407d
JSP
225 }
226 *ap->a_vpp = lowervp;
01dac67e
JSP
227 if (!lockparent)
228 cnp->cn_flags &= ~LOCKPARENT;
a1fa407d
JSP
229 return (lerror);
230 }
a1fa407d
JSP
231 } else {
232 lerror = ENOENT;
9192c54f
JSP
233 if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
234 lowervp = LOWERVP(dun->un_pvp);
235 if (lowervp != NULLVP) {
236 VREF(lowervp);
237 VOP_LOCK(lowervp);
238 lerror = 0;
239 }
240 }
a1fa407d
JSP
241 }
242
01dac67e
JSP
243 if (!lockparent)
244 cnp->cn_flags &= ~LOCKPARENT;
245
a1fa407d
JSP
246 /*
247 * at this point, we have uerror and lerror indicating
248 * possible errors with the lookups in the upper and lower
249 * layers. additionally, uppervp and lowervp are (locked)
250 * references to existing vnodes in the upper and lower layers.
251 *
252 * there are now three cases to consider.
253 * 1. if both layers returned an error, then return whatever
254 * error the upper layer generated.
255 *
256 * 2. if the top layer failed and the bottom layer succeeded
257 * then two subcases occur.
258 * a. the bottom vnode is not a directory, in which
259 * case just return a new union vnode referencing
260 * an empty top layer and the existing bottom layer.
261 * b. the bottom vnode is a directory, in which case
262 * create a new directory in the top-level and
263 * continue as in case 3.
264 *
265 * 3. if the top layer succeeded then return a new union
266 * vnode referencing whatever the new top layer and
267 * whatever the bottom layer returned.
268 */
269
ed5969c8
JSP
270 *ap->a_vpp = NULLVP;
271
a1fa407d
JSP
272 /* case 1. */
273 if ((uerror != 0) && (lerror != 0)) {
a1fa407d
JSP
274 return (uerror);
275 }
276
277 /* case 2. */
278 if (uerror != 0 /* && (lerror == 0) */ ) {
279 if (lowervp->v_type == VDIR) { /* case 2b. */
e2a2f3a7
JSP
280 dun->un_flags &= ~UN_ULOCK;
281 VOP_UNLOCK(upperdvp);
3b293975 282 uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
e2a2f3a7
JSP
283 VOP_LOCK(upperdvp);
284 dun->un_flags |= UN_ULOCK;
285
a1fa407d 286 if (uerror) {
050766c6 287 if (lowervp != NULLVP) {
a1fa407d 288 vput(lowervp);
3b293975 289 lowervp = NULLVP;
a1fa407d
JSP
290 }
291 return (uerror);
292 }
293 }
294 }
295
050766c6 296 if (lowervp != NULLVP)
01dac67e
JSP
297 VOP_UNLOCK(lowervp);
298
3b293975
JSP
299 error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
300 uppervp, lowervp);
301
01dac67e 302 if (error) {
050766c6 303 if (uppervp != NULLVP)
e2a2f3a7 304 vput(uppervp);
050766c6 305 if (lowervp != NULLVP)
01dac67e
JSP
306 vrele(lowervp);
307 } else {
81be6ee0
JSP
308 if (*ap->a_vpp != dvp)
309 if (!lockparent || !(cnp->cn_flags & ISLASTCN))
310 VOP_UNLOCK(dvp);
01dac67e
JSP
311 }
312
313 return (error);
a1fa407d
JSP
314}
315
12abe7b1
JSP
316int
317union_create(ap)
318 struct vop_create_args /* {
319 struct vnode *a_dvp;
320 struct vnode **a_vpp;
321 struct componentname *a_cnp;
322 struct vattr *a_vap;
323 } */ *ap;
324{
325 struct union_node *un = VTOUNION(ap->a_dvp);
326 struct vnode *dvp = un->un_uppervp;
327
050766c6 328 if (dvp != NULLVP) {
12abe7b1
JSP
329 int error;
330 struct vnode *vp;
12abe7b1 331
c1b204a8
JSP
332 FIXUP(un);
333
12abe7b1 334 VREF(dvp);
e2a2f3a7 335 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
336 vput(ap->a_dvp);
337 error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap);
338 if (error)
339 return (error);
340
341 error = union_allocvp(
342 ap->a_vpp,
79f80c71
JSP
343 ap->a_dvp->v_mount,
344 ap->a_dvp,
01dac67e 345 NULLVP,
12abe7b1
JSP
346 ap->a_cnp,
347 vp,
348 NULLVP);
01dac67e 349 if (error)
e2a2f3a7 350 vput(vp);
12abe7b1
JSP
351 return (error);
352 }
353
354 vput(ap->a_dvp);
355 return (EROFS);
356}
357
358int
359union_mknod(ap)
360 struct vop_mknod_args /* {
361 struct vnode *a_dvp;
362 struct vnode **a_vpp;
363 struct componentname *a_cnp;
364 struct vattr *a_vap;
365 } */ *ap;
366{
367 struct union_node *un = VTOUNION(ap->a_dvp);
368 struct vnode *dvp = un->un_uppervp;
369
050766c6 370 if (dvp != NULLVP) {
12abe7b1
JSP
371 int error;
372 struct vnode *vp;
12abe7b1 373
c1b204a8
JSP
374 FIXUP(un);
375
12abe7b1 376 VREF(dvp);
e2a2f3a7 377 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
378 vput(ap->a_dvp);
379 error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap);
380 if (error)
381 return (error);
382
050766c6 383 if (vp != NULLVP) {
01dac67e
JSP
384 error = union_allocvp(
385 ap->a_vpp,
79f80c71
JSP
386 ap->a_dvp->v_mount,
387 ap->a_dvp,
01dac67e
JSP
388 NULLVP,
389 ap->a_cnp,
390 vp,
391 NULLVP);
01dac67e 392 if (error)
e2a2f3a7 393 vput(vp);
01dac67e 394 }
12abe7b1
JSP
395 return (error);
396 }
397
398 vput(ap->a_dvp);
399 return (EROFS);
400}
401
a1fa407d
JSP
402int
403union_open(ap)
404 struct vop_open_args /* {
405 struct vnodeop_desc *a_desc;
406 struct vnode *a_vp;
407 int a_mode;
408 struct ucred *a_cred;
409 struct proc *a_p;
410 } */ *ap;
411{
412 struct union_node *un = VTOUNION(ap->a_vp);
01dac67e 413 struct vnode *tvp;
a1fa407d
JSP
414 int mode = ap->a_mode;
415 struct ucred *cred = ap->a_cred;
416 struct proc *p = ap->a_p;
01dac67e 417 int error;
a1fa407d
JSP
418
419 /*
420 * If there is an existing upper vp then simply open that.
421 */
01dac67e
JSP
422 tvp = un->un_uppervp;
423 if (tvp == NULLVP) {
a1fa407d 424 /*
01dac67e
JSP
425 * If the lower vnode is being opened for writing, then
426 * copy the file contents to the upper vnode and open that,
427 * otherwise can simply open the lower vnode.
a1fa407d 428 */
01dac67e
JSP
429 tvp = un->un_lowervp;
430 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
6f40eb24 431 error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
01dac67e
JSP
432 if (error == 0)
433 error = VOP_OPEN(un->un_uppervp, mode, cred, p);
01dac67e 434 return (error);
a1fa407d 435 }
e2a2f3a7
JSP
436
437 /*
438 * Just open the lower vnode
439 */
ed5969c8 440 un->un_openl++;
e2a2f3a7
JSP
441 VOP_LOCK(tvp);
442 error = VOP_OPEN(tvp, mode, cred, p);
443 VOP_UNLOCK(tvp);
444
445 return (error);
a1fa407d
JSP
446 }
447
c1b204a8
JSP
448 FIXUP(un);
449
01dac67e 450 error = VOP_OPEN(tvp, mode, cred, p);
01dac67e
JSP
451
452 return (error);
a1fa407d
JSP
453}
454
12abe7b1
JSP
455int
456union_close(ap)
457 struct vop_close_args /* {
458 struct vnode *a_vp;
459 int a_fflag;
460 struct ucred *a_cred;
461 struct proc *a_p;
462 } */ *ap;
463{
3b293975
JSP
464 struct union_node *un = VTOUNION(ap->a_vp);
465 struct vnode *vp;
12abe7b1 466
050766c6 467 if (un->un_uppervp != NULLVP) {
3b293975
JSP
468 vp = un->un_uppervp;
469 } else {
ed5969c8
JSP
470#ifdef UNION_DIAGNOSTIC
471 if (un->un_openl <= 0)
472 panic("union: un_openl cnt");
3b293975 473#endif
ed5969c8 474 --un->un_openl;
3b293975
JSP
475 vp = un->un_lowervp;
476 }
ed5969c8 477
3b293975 478 return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p));
12abe7b1
JSP
479}
480
481/*
482 * Check access permission on the union vnode.
483 * The access check being enforced is to check
484 * against both the underlying vnode, and any
485 * copied vnode. This ensures that no additional
486 * file permissions are given away simply because
487 * the user caused an implicit file copy.
488 */
489int
490union_access(ap)
491 struct vop_access_args /* {
492 struct vnodeop_desc *a_desc;
493 struct vnode *a_vp;
494 int a_mode;
495 struct ucred *a_cred;
496 struct proc *a_p;
497 } */ *ap;
498{
499 struct union_node *un = VTOUNION(ap->a_vp);
7315c41f 500 int error = EACCES;
12abe7b1
JSP
501 struct vnode *vp;
502
050766c6 503 if ((vp = un->un_uppervp) != NULLVP) {
c1b204a8
JSP
504 FIXUP(un);
505 return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p));
506 }
507
050766c6 508 if ((vp = un->un_lowervp) != NULLVP) {
01dac67e 509 VOP_LOCK(vp);
12abe7b1 510 error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
c1b204a8
JSP
511 if (error == 0) {
512 struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
513
514 if (um->um_op == UNMNT_BELOW)
515 error = VOP_ACCESS(vp, ap->a_mode,
516 um->um_cred, ap->a_p);
517 }
01dac67e 518 VOP_UNLOCK(vp);
12abe7b1
JSP
519 if (error)
520 return (error);
521 }
522
01dac67e 523 return (error);
12abe7b1
JSP
524}
525
a1fa407d 526/*
8a9c17f6
JSP
527 * We handle getattr only to change the fsid and
528 * track object sizes
a1fa407d
JSP
529 */
530int
531union_getattr(ap)
532 struct vop_getattr_args /* {
533 struct vnode *a_vp;
534 struct vattr *a_vap;
535 struct ucred *a_cred;
536 struct proc *a_p;
537 } */ *ap;
538{
539 int error;
0931f2d9
JSP
540 struct union_node *un = VTOUNION(ap->a_vp);
541 struct vnode *vp = un->un_uppervp;
542 struct vattr *vap;
543 struct vattr va;
544
545
546 /*
547 * Some programs walk the filesystem hierarchy by counting
548 * links to directories to avoid stat'ing all the time.
549 * This means the link count on directories needs to be "correct".
550 * The only way to do that is to call getattr on both layers
551 * and fix up the link count. The link count will not necessarily
552 * be accurate but will be large enough to defeat the tree walkers.
553 */
554
555 vap = ap->a_vap;
556
557 vp = un->un_uppervp;
558 if (vp != NULLVP) {
463c0360
JSP
559 /*
560 * It's not clear whether VOP_GETATTR is to be
561 * called with the vnode locked or not. stat() calls
562 * it with (vp) locked, and fstat calls it with
563 * (vp) unlocked.
564 * In the mean time, compensate here by checking
565 * the union_node's lock flag.
566 */
567 if (un->un_flags & UN_LOCKED)
568 FIXUP(un);
569
0931f2d9
JSP
570 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
571 if (error)
572 return (error);
8a9c17f6 573 union_newsize(ap->a_vp, vap->va_size, VNOVAL);
0931f2d9 574 }
01dac67e 575
0931f2d9
JSP
576 if (vp == NULLVP) {
577 vp = un->un_lowervp;
578 } else if (vp->v_type == VDIR) {
579 vp = un->un_lowervp;
580 vap = &va;
581 } else {
582 vp = NULLVP;
583 }
584
585 if (vp != NULLVP) {
e2a2f3a7 586 VOP_LOCK(vp);
0931f2d9 587 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
e2a2f3a7 588 VOP_UNLOCK(vp);
0931f2d9
JSP
589 if (error)
590 return (error);
8a9c17f6 591 union_newsize(ap->a_vp, VNOVAL, vap->va_size);
0931f2d9
JSP
592 }
593
594 if ((vap != ap->a_vap) && (vap->va_type == VDIR))
595 ap->a_vap->va_nlink += vap->va_nlink;
a1fa407d 596
8de82e02 597 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
a1fa407d
JSP
598 return (0);
599}
600
a1fa407d 601int
01dac67e 602union_setattr(ap)
12abe7b1 603 struct vop_setattr_args /* {
a1fa407d 604 struct vnode *a_vp;
12abe7b1 605 struct vattr *a_vap;
a1fa407d 606 struct ucred *a_cred;
12abe7b1 607 struct proc *a_p;
a1fa407d
JSP
608 } */ *ap;
609{
610 struct union_node *un = VTOUNION(ap->a_vp);
12abe7b1 611 int error;
a1fa407d 612
d596128e
JSP
613 /*
614 * Handle case of truncating lower object to zero size,
615 * by creating a zero length upper object. This is to
616 * handle the case of open with O_TRUNC and O_CREAT.
617 */
618 if ((un->un_uppervp == NULLVP) &&
619 /* assert(un->un_lowervp != NULLVP) */
620 (un->un_lowervp->v_type == VREG) &&
621 (ap->a_vap->va_size == 0)) {
622 struct vnode *vp;
623
624 error = union_vn_create(&vp, un, ap->a_p);
625 if (error)
626 return (error);
627
628 /* at this point, uppervp is locked */
629 union_newupper(un, vp);
630
631 VOP_UNLOCK(vp);
632 union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p);
633 VOP_LOCK(vp);
634 un->un_flags |= UN_ULOCK;
635 }
636
637 /*
638 * Try to set attributes in upper layer,
639 * otherwise return read-only filesystem error.
640 */
641 if (un->un_uppervp != NULLVP) {
c1b204a8 642 FIXUP(un);
12abe7b1
JSP
643 error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
644 ap->a_cred, ap->a_p);
8a9c17f6
JSP
645 if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
646 union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
12abe7b1 647 } else {
12abe7b1
JSP
648 error = EROFS;
649 }
a1fa407d 650
12abe7b1 651 return (error);
a1fa407d
JSP
652}
653
654int
12abe7b1
JSP
655union_read(ap)
656 struct vop_read_args /* {
a1fa407d 657 struct vnode *a_vp;
12abe7b1
JSP
658 struct uio *a_uio;
659 int a_ioflag;
660 struct ucred *a_cred;
a1fa407d
JSP
661 } */ *ap;
662{
12abe7b1
JSP
663 int error;
664 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 665 int dolock = (vp == LOWERVP(ap->a_vp));
a1fa407d 666
e2a2f3a7
JSP
667 if (dolock)
668 VOP_LOCK(vp);
c1b204a8
JSP
669 else
670 FIXUP(VTOUNION(ap->a_vp));
12abe7b1 671 error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
e2a2f3a7
JSP
672 if (dolock)
673 VOP_UNLOCK(vp);
12abe7b1 674
8a9c17f6
JSP
675 /*
676 * XXX
677 * perhaps the size of the underlying object has changed under
678 * our feet. take advantage of the offset information present
679 * in the uio structure.
680 */
681 if (error == 0) {
682 struct union_node *un = VTOUNION(ap->a_vp);
683 off_t cur = ap->a_uio->uio_offset;
684
685 if (vp == un->un_uppervp) {
686 if (cur > un->un_uppersz)
687 union_newsize(ap->a_vp, cur, VNOVAL);
688 } else {
689 if (cur > un->un_lowersz)
690 union_newsize(ap->a_vp, VNOVAL, cur);
691 }
692 }
693
12abe7b1 694 return (error);
a1fa407d
JSP
695}
696
697int
12abe7b1
JSP
698union_write(ap)
699 struct vop_read_args /* {
a1fa407d 700 struct vnode *a_vp;
12abe7b1
JSP
701 struct uio *a_uio;
702 int a_ioflag;
703 struct ucred *a_cred;
a1fa407d
JSP
704 } */ *ap;
705{
12abe7b1
JSP
706 int error;
707 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 708 int dolock = (vp == LOWERVP(ap->a_vp));
a1fa407d 709
e2a2f3a7
JSP
710 if (dolock)
711 VOP_LOCK(vp);
c1b204a8
JSP
712 else
713 FIXUP(VTOUNION(ap->a_vp));
12abe7b1 714 error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
e2a2f3a7
JSP
715 if (dolock)
716 VOP_UNLOCK(vp);
a1fa407d 717
8a9c17f6
JSP
718 /*
719 * the size of the underlying object may be changed by the
720 * write.
721 */
722 if (error == 0) {
723 struct union_node *un = VTOUNION(ap->a_vp);
724 off_t cur = ap->a_uio->uio_offset;
725
726 if (vp == un->un_uppervp) {
727 if (cur > un->un_uppersz)
728 union_newsize(ap->a_vp, cur, VNOVAL);
729 } else {
730 if (cur > un->un_lowersz)
731 union_newsize(ap->a_vp, VNOVAL, cur);
732 }
733 }
734
12abe7b1
JSP
735 return (error);
736}
a1fa407d
JSP
737
738int
12abe7b1
JSP
739union_ioctl(ap)
740 struct vop_ioctl_args /* {
a1fa407d 741 struct vnode *a_vp;
12abe7b1
JSP
742 int a_command;
743 caddr_t a_data;
744 int a_fflag;
745 struct ucred *a_cred;
746 struct proc *a_p;
a1fa407d
JSP
747 } */ *ap;
748{
a1fa407d 749
12abe7b1
JSP
750 return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data,
751 ap->a_fflag, ap->a_cred, ap->a_p));
a1fa407d
JSP
752}
753
a1fa407d 754int
12abe7b1
JSP
755union_select(ap)
756 struct vop_select_args /* {
757 struct vnode *a_vp;
758 int a_which;
759 int a_fflags;
760 struct ucred *a_cred;
761 struct proc *a_p;
762 } */ *ap;
763{
764
765 return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags,
766 ap->a_cred, ap->a_p));
767}
768
769int
770union_mmap(ap)
771 struct vop_mmap_args /* {
772 struct vnode *a_vp;
773 int a_fflags;
774 struct ucred *a_cred;
775 struct proc *a_p;
776 } */ *ap;
777{
778
779 return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags,
780 ap->a_cred, ap->a_p));
781}
782
783int
784union_fsync(ap)
785 struct vop_fsync_args /* {
786 struct vnode *a_vp;
787 struct ucred *a_cred;
788 int a_waitfor;
789 struct proc *a_p;
790 } */ *ap;
791{
792 int error = 0;
793 struct vnode *targetvp = OTHERVP(ap->a_vp);
794
050766c6 795 if (targetvp != NULLVP) {
e2a2f3a7
JSP
796 int dolock = (targetvp == LOWERVP(ap->a_vp));
797
798 if (dolock)
799 VOP_LOCK(targetvp);
c1b204a8
JSP
800 else
801 FIXUP(VTOUNION(ap->a_vp));
12abe7b1
JSP
802 error = VOP_FSYNC(targetvp, ap->a_cred,
803 ap->a_waitfor, ap->a_p);
e2a2f3a7
JSP
804 if (dolock)
805 VOP_UNLOCK(targetvp);
12abe7b1
JSP
806 }
807
808 return (error);
809}
810
811int
812union_seek(ap)
813 struct vop_seek_args /* {
814 struct vnode *a_vp;
815 off_t a_oldoff;
816 off_t a_newoff;
817 struct ucred *a_cred;
818 } */ *ap;
819{
820
821 return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred));
822}
823
824int
825union_remove(ap)
826 struct vop_remove_args /* {
827 struct vnode *a_dvp;
828 struct vnode *a_vp;
829 struct componentname *a_cnp;
a1fa407d
JSP
830 } */ *ap;
831{
a1fa407d 832 int error;
12abe7b1
JSP
833 struct union_node *dun = VTOUNION(ap->a_dvp);
834 struct union_node *un = VTOUNION(ap->a_vp);
a1fa407d 835
050766c6 836 if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) {
12abe7b1
JSP
837 struct vnode *dvp = dun->un_uppervp;
838 struct vnode *vp = un->un_uppervp;
a1fa407d 839
c1b204a8 840 FIXUP(dun);
12abe7b1 841 VREF(dvp);
e2a2f3a7 842 dun->un_flags |= UN_KLOCK;
12abe7b1 843 vput(ap->a_dvp);
c1b204a8 844 FIXUP(un);
12abe7b1 845 VREF(vp);
e2a2f3a7 846 un->un_flags |= UN_KLOCK;
12abe7b1 847 vput(ap->a_vp);
a1fa407d 848
12abe7b1 849 error = VOP_REMOVE(dvp, vp, ap->a_cnp);
ed5969c8
JSP
850 if (!error)
851 union_removed_upper(un);
852
853 /*
854 * XXX: should create a whiteout here
855 */
12abe7b1
JSP
856 } else {
857 /*
858 * XXX: should create a whiteout here
859 */
860 vput(ap->a_dvp);
861 vput(ap->a_vp);
862 error = EROFS;
863 }
864
865 return (error);
866}
867
868int
869union_link(ap)
870 struct vop_link_args /* {
871 struct vnode *a_vp;
872 struct vnode *a_tdvp;
873 struct componentname *a_cnp;
874 } */ *ap;
875{
6f40eb24
JSP
876 int error = 0;
877 struct union_node *un;
878 struct vnode *vp;
879 struct vnode *tdvp;
12abe7b1 880
6f40eb24 881 un = VTOUNION(ap->a_vp);
12abe7b1 882
6f40eb24
JSP
883 if (ap->a_vp->v_op != ap->a_tdvp->v_op) {
884 tdvp = ap->a_tdvp;
12abe7b1 885 } else {
6f40eb24
JSP
886 struct union_node *tdun = VTOUNION(ap->a_tdvp);
887 if (tdun->un_uppervp == NULLVP) {
888 VOP_LOCK(ap->a_tdvp);
889 if (un->un_uppervp == tdun->un_dirvp) {
890 un->un_flags &= ~UN_ULOCK;
891 VOP_UNLOCK(un->un_uppervp);
892 }
893 error = union_copyup(tdun, 1, ap->a_cnp->cn_cred,
894 ap->a_cnp->cn_proc);
895 if (un->un_uppervp == tdun->un_dirvp) {
896 VOP_LOCK(un->un_uppervp);
897 un->un_flags |= UN_ULOCK;
898 }
899 VOP_UNLOCK(ap->a_tdvp);
900 }
901 tdvp = tdun->un_uppervp;
902 }
903
904 vp = un->un_uppervp;
905 if (vp == NULLVP)
12abe7b1 906 error = EROFS;
6f40eb24
JSP
907
908 if (error) {
909 vput(ap->a_vp);
910 return (error);
12abe7b1 911 }
a1fa407d 912
6f40eb24
JSP
913 FIXUP(un);
914 VREF(vp);
915 un->un_flags |= UN_KLOCK;
916 vput(ap->a_vp);
917
918 return (VOP_LINK(vp, tdvp, ap->a_cnp));
a1fa407d
JSP
919}
920
12abe7b1
JSP
921int
922union_rename(ap)
923 struct vop_rename_args /* {
924 struct vnode *a_fdvp;
925 struct vnode *a_fvp;
926 struct componentname *a_fcnp;
927 struct vnode *a_tdvp;
928 struct vnode *a_tvp;
929 struct componentname *a_tcnp;
930 } */ *ap;
931{
932 int error;
933
934 struct vnode *fdvp = ap->a_fdvp;
935 struct vnode *fvp = ap->a_fvp;
936 struct vnode *tdvp = ap->a_tdvp;
937 struct vnode *tvp = ap->a_tvp;
938
939 if (fdvp->v_op == union_vnodeop_p) { /* always true */
940 struct union_node *un = VTOUNION(fdvp);
3b293975 941 if (un->un_uppervp == NULLVP) {
12abe7b1
JSP
942 error = EROFS;
943 goto bad;
944 }
945
946 fdvp = un->un_uppervp;
947 VREF(fdvp);
948 vrele(ap->a_fdvp);
949 }
950
951 if (fvp->v_op == union_vnodeop_p) { /* always true */
952 struct union_node *un = VTOUNION(fvp);
3b293975 953 if (un->un_uppervp == NULLVP) {
12abe7b1
JSP
954 error = EROFS;
955 goto bad;
956 }
957
958 fvp = un->un_uppervp;
959 VREF(fvp);
960 vrele(ap->a_fvp);
961 }
962
963 if (tdvp->v_op == union_vnodeop_p) {
964 struct union_node *un = VTOUNION(tdvp);
3b293975 965 if (un->un_uppervp == NULLVP) {
050766c6
JSP
966 /*
967 * this should never happen in normal
968 * operation but might if there was
969 * a problem creating the top-level shadow
970 * directory.
971 */
12abe7b1
JSP
972 error = EROFS;
973 goto bad;
974 }
975
976 tdvp = un->un_uppervp;
977 VREF(tdvp);
e2a2f3a7 978 un->un_flags |= UN_KLOCK;
3b293975 979 vput(ap->a_tdvp);
12abe7b1
JSP
980 }
981
050766c6 982 if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
12abe7b1 983 struct union_node *un = VTOUNION(tvp);
12abe7b1
JSP
984
985 tvp = un->un_uppervp;
050766c6
JSP
986 if (tvp != NULLVP) {
987 VREF(tvp);
988 un->un_flags |= UN_KLOCK;
989 }
12abe7b1
JSP
990 vput(ap->a_tvp);
991 }
992
993 return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
994
995bad:
996 vrele(fdvp);
997 vrele(fvp);
998 vput(tdvp);
050766c6 999 if (tvp != NULLVP)
12abe7b1
JSP
1000 vput(tvp);
1001
1002 return (error);
1003}
1004
1005int
1006union_mkdir(ap)
1007 struct vop_mkdir_args /* {
1008 struct vnode *a_dvp;
1009 struct vnode **a_vpp;
1010 struct componentname *a_cnp;
1011 struct vattr *a_vap;
1012 } */ *ap;
1013{
1014 struct union_node *un = VTOUNION(ap->a_dvp);
1015 struct vnode *dvp = un->un_uppervp;
1016
050766c6 1017 if (dvp != NULLVP) {
12abe7b1
JSP
1018 int error;
1019 struct vnode *vp;
12abe7b1 1020
c1b204a8 1021 FIXUP(un);
12abe7b1 1022 VREF(dvp);
e2a2f3a7 1023 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
1024 vput(ap->a_dvp);
1025 error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
1026 if (error)
1027 return (error);
1028
1029 error = union_allocvp(
1030 ap->a_vpp,
79f80c71
JSP
1031 ap->a_dvp->v_mount,
1032 ap->a_dvp,
01dac67e 1033 NULLVP,
12abe7b1
JSP
1034 ap->a_cnp,
1035 vp,
1036 NULLVP);
01dac67e 1037 if (error)
e2a2f3a7 1038 vput(vp);
12abe7b1
JSP
1039 return (error);
1040 }
1041
1042 vput(ap->a_dvp);
1043 return (EROFS);
1044}
1045
1046int
1047union_rmdir(ap)
1048 struct vop_rmdir_args /* {
1049 struct vnode *a_dvp;
1050 struct vnode *a_vp;
1051 struct componentname *a_cnp;
1052 } */ *ap;
1053{
1054 int error;
1055 struct union_node *dun = VTOUNION(ap->a_dvp);
1056 struct union_node *un = VTOUNION(ap->a_vp);
1057
050766c6 1058 if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) {
12abe7b1
JSP
1059 struct vnode *dvp = dun->un_uppervp;
1060 struct vnode *vp = un->un_uppervp;
1061
c1b204a8 1062 FIXUP(dun);
12abe7b1 1063 VREF(dvp);
e2a2f3a7 1064 dun->un_flags |= UN_KLOCK;
12abe7b1 1065 vput(ap->a_dvp);
c1b204a8 1066 FIXUP(un);
12abe7b1 1067 VREF(vp);
e2a2f3a7 1068 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
1069 vput(ap->a_vp);
1070
e2a2f3a7 1071 error = VOP_RMDIR(dvp, vp, ap->a_cnp);
ed5969c8
JSP
1072 if (!error)
1073 union_removed_upper(un);
1074
1075 /*
1076 * XXX: should create a whiteout here
1077 */
12abe7b1
JSP
1078 } else {
1079 /*
1080 * XXX: should create a whiteout here
1081 */
1082 vput(ap->a_dvp);
1083 vput(ap->a_vp);
1084 error = EROFS;
1085 }
1086
1087 return (error);
1088}
1089
1090int
1091union_symlink(ap)
1092 struct vop_symlink_args /* {
1093 struct vnode *a_dvp;
1094 struct vnode **a_vpp;
1095 struct componentname *a_cnp;
1096 struct vattr *a_vap;
1097 char *a_target;
1098 } */ *ap;
1099{
1100 struct union_node *un = VTOUNION(ap->a_dvp);
1101 struct vnode *dvp = un->un_uppervp;
1102
050766c6 1103 if (dvp != NULLVP) {
12abe7b1
JSP
1104 int error;
1105 struct vnode *vp;
1106 struct mount *mp = ap->a_dvp->v_mount;
1107
c1b204a8 1108 FIXUP(un);
12abe7b1 1109 VREF(dvp);
e2a2f3a7 1110 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
1111 vput(ap->a_dvp);
1112 error = VOP_SYMLINK(dvp, &vp, ap->a_cnp,
1113 ap->a_vap, ap->a_target);
3b293975 1114 *ap->a_vpp = NULLVP;
12abe7b1
JSP
1115 return (error);
1116 }
1117
1118 vput(ap->a_dvp);
1119 return (EROFS);
1120}
a1fa407d
JSP
1121
1122/*
12abe7b1
JSP
1123 * union_readdir works in concert with getdirentries and
1124 * readdir(3) to provide a list of entries in the unioned
1125 * directories. getdirentries is responsible for walking
1126 * down the union stack. readdir(3) is responsible for
1127 * eliminating duplicate names from the returned data stream.
a1fa407d
JSP
1128 */
1129int
12abe7b1
JSP
1130union_readdir(ap)
1131 struct vop_readdir_args /* {
1132 struct vnodeop_desc *a_desc;
1133 struct vnode *a_vp;
1134 struct uio *a_uio;
1135 struct ucred *a_cred;
94b29fae
KM
1136 int *a_eofflag;
1137 u_long *a_cookies;
1138 int a_ncookies;
12abe7b1
JSP
1139 } */ *ap;
1140{
94b29fae
KM
1141 register struct union_node *un = VTOUNION(ap->a_vp);
1142 register struct vnode *uvp = un->un_uppervp;
12abe7b1 1143
94b29fae
KM
1144 if (uvp == NULLVP)
1145 return (0);
12abe7b1 1146
94b29fae
KM
1147 FIXUP(un);
1148 ap->a_vp = uvp;
1149 return (VOCALL(uvp->v_op, VOFFSET(vop_readdir), ap));
12abe7b1
JSP
1150}
1151
1152int
1153union_readlink(ap)
1154 struct vop_readlink_args /* {
1155 struct vnode *a_vp;
1156 struct uio *a_uio;
1157 struct ucred *a_cred;
a1fa407d
JSP
1158 } */ *ap;
1159{
a1fa407d 1160 int error;
12abe7b1 1161 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 1162 int dolock = (vp == LOWERVP(ap->a_vp));
a1fa407d 1163
e2a2f3a7
JSP
1164 if (dolock)
1165 VOP_LOCK(vp);
c1b204a8
JSP
1166 else
1167 FIXUP(VTOUNION(ap->a_vp));
12abe7b1 1168 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
e2a2f3a7
JSP
1169 if (dolock)
1170 VOP_UNLOCK(vp);
a1fa407d 1171
12abe7b1
JSP
1172 return (error);
1173}
a1fa407d 1174
12abe7b1
JSP
1175int
1176union_abortop(ap)
1177 struct vop_abortop_args /* {
1178 struct vnode *a_dvp;
1179 struct componentname *a_cnp;
1180 } */ *ap;
1181{
1182 int error;
01dac67e 1183 struct vnode *vp = OTHERVP(ap->a_dvp);
12abe7b1
JSP
1184 struct union_node *un = VTOUNION(ap->a_dvp);
1185 int islocked = un->un_flags & UN_LOCKED;
e2a2f3a7 1186 int dolock = (vp == LOWERVP(ap->a_dvp));
a1fa407d 1187
c1b204a8
JSP
1188 if (islocked) {
1189 if (dolock)
1190 VOP_LOCK(vp);
1191 else
1192 FIXUP(VTOUNION(ap->a_dvp));
1193 }
12abe7b1 1194 error = VOP_ABORTOP(vp, ap->a_cnp);
e2a2f3a7 1195 if (islocked && dolock)
12abe7b1 1196 VOP_UNLOCK(vp);
a1fa407d
JSP
1197
1198 return (error);
1199}
1200
12abe7b1
JSP
1201int
1202union_inactive(ap)
1203 struct vop_inactive_args /* {
1204 struct vnode *a_vp;
1205 } */ *ap;
1206{
463c0360 1207 struct union_node *un = VTOUNION(ap->a_vp);
12abe7b1
JSP
1208
1209 /*
1210 * Do nothing (and _don't_ bypass).
1211 * Wait to vrele lowervp until reclaim,
1212 * so that until then our union_node is in the
1213 * cache and reusable.
1214 *
1215 * NEEDSWORK: Someday, consider inactive'ing
1216 * the lowervp and then trying to reactivate it
1217 * with capabilities (v_id)
1218 * like they do in the name lookup cache code.
1219 * That's too much work for now.
1220 */
79f80c71 1221
ed5969c8 1222#ifdef UNION_DIAGNOSTIC
79f80c71
JSP
1223 if (un->un_flags & UN_LOCKED)
1224 panic("union: inactivating locked node");
463c0360
JSP
1225 if (un->un_flags & UN_ULOCK)
1226 panic("union: inactivating w/locked upper node");
79f80c71
JSP
1227#endif
1228
463c0360
JSP
1229 if ((un->un_flags & UN_CACHED) == 0)
1230 vgone(ap->a_vp);
1231
12abe7b1
JSP
1232 return (0);
1233}
1234
1235int
1236union_reclaim(ap)
1237 struct vop_reclaim_args /* {
1238 struct vnode *a_vp;
1239 } */ *ap;
1240{
12abe7b1 1241
58572fc0
JSP
1242 union_freevp(ap->a_vp);
1243
12abe7b1
JSP
1244 return (0);
1245}
1246
a1fa407d
JSP
1247int
1248union_lock(ap)
1249 struct vop_lock_args *ap;
1250{
7315c41f
JSP
1251 struct vnode *vp = ap->a_vp;
1252 struct union_node *un;
1253
1254start:
1255 while (vp->v_flag & VXLOCK) {
1256 vp->v_flag |= VXWANT;
1257 sleep((caddr_t)vp, PINOD);
1258 }
1259
1260 un = VTOUNION(vp);
a1fa407d 1261
050766c6 1262 if (un->un_uppervp != NULLVP) {
2e2839fc
JSP
1263 if (((un->un_flags & UN_ULOCK) == 0) &&
1264 (vp->v_usecount != 0)) {
e2a2f3a7 1265 un->un_flags |= UN_ULOCK;
7315c41f 1266 VOP_LOCK(un->un_uppervp);
e2a2f3a7
JSP
1267 }
1268#ifdef DIAGNOSTIC
1269 if (un->un_flags & UN_KLOCK)
1270 panic("union: dangling upper lock");
1271#endif
1272 }
1273
7315c41f 1274 if (un->un_flags & UN_LOCKED) {
a1fa407d 1275#ifdef DIAGNOSTIC
79f80c71
JSP
1276 if (curproc && un->un_pid == curproc->p_pid &&
1277 un->un_pid > -1 && curproc->p_pid > -1)
1278 panic("union: locking against myself");
a1fa407d 1279#endif
a1fa407d
JSP
1280 un->un_flags |= UN_WANT;
1281 sleep((caddr_t) &un->un_flags, PINOD);
7315c41f 1282 goto start;
a1fa407d 1283 }
79f80c71 1284
a1fa407d 1285#ifdef DIAGNOSTIC
79f80c71
JSP
1286 if (curproc)
1287 un->un_pid = curproc->p_pid;
1288 else
1289 un->un_pid = -1;
a1fa407d 1290#endif
15a86f7e 1291
7315c41f 1292 un->un_flags |= UN_LOCKED;
15a86f7e 1293 return (0);
a1fa407d
JSP
1294}
1295
1296int
1297union_unlock(ap)
1298 struct vop_lock_args *ap;
1299{
1300 struct union_node *un = VTOUNION(ap->a_vp);
1301
1302#ifdef DIAGNOSTIC
a1fa407d
JSP
1303 if ((un->un_flags & UN_LOCKED) == 0)
1304 panic("union: unlock unlocked node");
79f80c71
JSP
1305 if (curproc && un->un_pid != curproc->p_pid &&
1306 curproc->p_pid > -1 && un->un_pid > -1)
01dac67e 1307 panic("union: unlocking other process's union node");
a1fa407d
JSP
1308#endif
1309
a1fa407d 1310 un->un_flags &= ~UN_LOCKED;
e2a2f3a7
JSP
1311
1312 if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
1313 VOP_UNLOCK(un->un_uppervp);
1314
1315 un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
1316
a1fa407d
JSP
1317 if (un->un_flags & UN_WANT) {
1318 un->un_flags &= ~UN_WANT;
1319 wakeup((caddr_t) &un->un_flags);
1320 }
1321
1322#ifdef DIAGNOSTIC
1323 un->un_pid = 0;
1324#endif
15a86f7e
JSP
1325
1326 return (0);
a1fa407d
JSP
1327}
1328
12abe7b1
JSP
1329int
1330union_bmap(ap)
1331 struct vop_bmap_args /* {
1332 struct vnode *a_vp;
1333 daddr_t a_bn;
1334 struct vnode **a_vpp;
1335 daddr_t *a_bnp;
1336 int *a_runp;
1337 } */ *ap;
1338{
1339 int error;
1340 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 1341 int dolock = (vp == LOWERVP(ap->a_vp));
12abe7b1 1342
e2a2f3a7
JSP
1343 if (dolock)
1344 VOP_LOCK(vp);
c1b204a8
JSP
1345 else
1346 FIXUP(VTOUNION(ap->a_vp));
12abe7b1 1347 error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
e2a2f3a7
JSP
1348 if (dolock)
1349 VOP_UNLOCK(vp);
12abe7b1
JSP
1350
1351 return (error);
1352}
1353
1354int
1355union_print(ap)
1356 struct vop_print_args /* {
1357 struct vnode *a_vp;
1358 } */ *ap;
1359{
1360 struct vnode *vp = ap->a_vp;
1361
1362 printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
1363 vp, UPPERVP(vp), LOWERVP(vp));
1364 return (0);
1365}
1366
1367int
1368union_islocked(ap)
1369 struct vop_islocked_args /* {
1370 struct vnode *a_vp;
1371 } */ *ap;
1372{
1373
1374 return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
1375}
1376
1377int
1378union_pathconf(ap)
1379 struct vop_pathconf_args /* {
1380 struct vnode *a_vp;
1381 int a_name;
1382 int *a_retval;
1383 } */ *ap;
1384{
1385 int error;
1386 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 1387 int dolock = (vp == LOWERVP(ap->a_vp));
12abe7b1 1388
e2a2f3a7
JSP
1389 if (dolock)
1390 VOP_LOCK(vp);
c1b204a8
JSP
1391 else
1392 FIXUP(VTOUNION(ap->a_vp));
12abe7b1 1393 error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval);
e2a2f3a7
JSP
1394 if (dolock)
1395 VOP_UNLOCK(vp);
12abe7b1
JSP
1396
1397 return (error);
1398}
1399
1400int
1401union_advlock(ap)
1402 struct vop_advlock_args /* {
1403 struct vnode *a_vp;
1404 caddr_t a_id;
1405 int a_op;
1406 struct flock *a_fl;
1407 int a_flags;
1408 } */ *ap;
1409{
1410
1411 return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op,
1412 ap->a_fl, ap->a_flags));
1413}
1414
1415
a1fa407d 1416/*
12abe7b1
JSP
1417 * XXX - vop_strategy must be hand coded because it has no
1418 * vnode in its arguments.
1419 * This goes away with a merged VM/buffer cache.
a1fa407d 1420 */
12abe7b1
JSP
1421int
1422union_strategy(ap)
1423 struct vop_strategy_args /* {
1424 struct buf *a_bp;
1425 } */ *ap;
1426{
1427 struct buf *bp = ap->a_bp;
1428 int error;
1429 struct vnode *savedvp;
1430
1431 savedvp = bp->b_vp;
1432 bp->b_vp = OTHERVP(bp->b_vp);
a1fa407d 1433
12abe7b1 1434#ifdef DIAGNOSTIC
3b293975 1435 if (bp->b_vp == NULLVP)
12abe7b1
JSP
1436 panic("union_strategy: nil vp");
1437 if (((bp->b_flags & B_READ) == 0) &&
1438 (bp->b_vp == LOWERVP(savedvp)))
1439 panic("union_strategy: writing to lowervp");
1440#endif
a1fa407d 1441
12abe7b1
JSP
1442 error = VOP_STRATEGY(bp);
1443 bp->b_vp = savedvp;
a1fa407d 1444
12abe7b1
JSP
1445 return (error);
1446}
a1fa407d 1447
12abe7b1
JSP
1448/*
1449 * Global vfs data structures
1450 */
1451int (**union_vnodeop_p)();
01dac67e 1452struct vnodeopv_entry_desc union_vnodeop_entries[] = {
12abe7b1
JSP
1453 { &vop_default_desc, vn_default_error },
1454 { &vop_lookup_desc, union_lookup }, /* lookup */
1455 { &vop_create_desc, union_create }, /* create */
1456 { &vop_mknod_desc, union_mknod }, /* mknod */
1457 { &vop_open_desc, union_open }, /* open */
1458 { &vop_close_desc, union_close }, /* close */
1459 { &vop_access_desc, union_access }, /* access */
1460 { &vop_getattr_desc, union_getattr }, /* getattr */
1461 { &vop_setattr_desc, union_setattr }, /* setattr */
1462 { &vop_read_desc, union_read }, /* read */
1463 { &vop_write_desc, union_write }, /* write */
1464 { &vop_ioctl_desc, union_ioctl }, /* ioctl */
1465 { &vop_select_desc, union_select }, /* select */
1466 { &vop_mmap_desc, union_mmap }, /* mmap */
1467 { &vop_fsync_desc, union_fsync }, /* fsync */
1468 { &vop_seek_desc, union_seek }, /* seek */
1469 { &vop_remove_desc, union_remove }, /* remove */
1470 { &vop_link_desc, union_link }, /* link */
1471 { &vop_rename_desc, union_rename }, /* rename */
1472 { &vop_mkdir_desc, union_mkdir }, /* mkdir */
1473 { &vop_rmdir_desc, union_rmdir }, /* rmdir */
1474 { &vop_symlink_desc, union_symlink }, /* symlink */
1475 { &vop_readdir_desc, union_readdir }, /* readdir */
1476 { &vop_readlink_desc, union_readlink }, /* readlink */
1477 { &vop_abortop_desc, union_abortop }, /* abortop */
1478 { &vop_inactive_desc, union_inactive }, /* inactive */
1479 { &vop_reclaim_desc, union_reclaim }, /* reclaim */
1480 { &vop_lock_desc, union_lock }, /* lock */
1481 { &vop_unlock_desc, union_unlock }, /* unlock */
1482 { &vop_bmap_desc, union_bmap }, /* bmap */
1483 { &vop_strategy_desc, union_strategy }, /* strategy */
1484 { &vop_print_desc, union_print }, /* print */
1485 { &vop_islocked_desc, union_islocked }, /* islocked */
1486 { &vop_pathconf_desc, union_pathconf }, /* pathconf */
1487 { &vop_advlock_desc, union_advlock }, /* advlock */
1488#ifdef notdef
1489 { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */
1490 { &vop_valloc_desc, union_valloc }, /* valloc */
1491 { &vop_vfree_desc, union_vfree }, /* vfree */
1492 { &vop_truncate_desc, union_truncate }, /* truncate */
1493 { &vop_update_desc, union_update }, /* update */
1494 { &vop_bwrite_desc, union_bwrite }, /* bwrite */
1495#endif
a1fa407d
JSP
1496 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
1497};
1498struct vnodeopv_desc union_vnodeop_opv_desc =
1499 { &union_vnodeop_p, union_vnodeop_entries };