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