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