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