]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/unionfs/union_vnops.c
gnu/dts: Update our copy of arm dts from Linux 4.16
[FreeBSD/FreeBSD.git] / sys / fs / unionfs / union_vnops.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
5  * Copyright (c) 1992, 1993, 1994, 1995
6  *      The Regents of the University of California.
7  * Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
8  * Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org>
9  * All rights reserved.
10  *
11  * This code is derived from software contributed to Berkeley by
12  * Jan-Simon Pendry.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      @(#)union_vnops.c       8.32 (Berkeley) 6/23/95
39  * $FreeBSD$
40  *
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/conf.h>
46 #include <sys/kernel.h>
47 #include <sys/lock.h>
48 #include <sys/malloc.h>
49 #include <sys/mount.h>
50 #include <sys/mutex.h>
51 #include <sys/namei.h>
52 #include <sys/sysctl.h>
53 #include <sys/vnode.h>
54 #include <sys/kdb.h>
55 #include <sys/fcntl.h>
56 #include <sys/stat.h>
57 #include <sys/dirent.h>
58 #include <sys/proc.h>
59 #include <sys/bio.h>
60 #include <sys/buf.h>
61
62 #include <fs/unionfs/union.h>
63
64 #include <vm/vm.h>
65 #include <vm/vm_extern.h>
66 #include <vm/vm_object.h>
67 #include <vm/vnode_pager.h>
68
69 #if 0
70 #define UNIONFS_INTERNAL_DEBUG(msg, args...)    printf(msg, ## args)
71 #define UNIONFS_IDBG_RENAME
72 #else
73 #define UNIONFS_INTERNAL_DEBUG(msg, args...)
74 #endif
75
76 #define KASSERT_UNIONFS_VNODE(vp) \
77         KASSERT(((vp)->v_op == &unionfs_vnodeops), \
78             ("unionfs: it is not unionfs-vnode"))
79
80 static int
81 unionfs_lookup(struct vop_cachedlookup_args *ap)
82 {
83         int             iswhiteout;
84         int             lockflag;
85         int             error , uerror, lerror;
86         u_long          nameiop;
87         u_long          cnflags, cnflagsbk;
88         struct unionfs_node *dunp;
89         struct vnode   *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
90         struct vattr    va;
91         struct componentname *cnp;
92         struct thread  *td;
93
94         iswhiteout = 0;
95         lockflag = 0;
96         error = uerror = lerror = ENOENT;
97         cnp = ap->a_cnp;
98         nameiop = cnp->cn_nameiop;
99         cnflags = cnp->cn_flags;
100         dvp = ap->a_dvp;
101         dunp = VTOUNIONFS(dvp);
102         udvp = dunp->un_uppervp;
103         ldvp = dunp->un_lowervp;
104         vp = uvp = lvp = NULLVP;
105         td = curthread;
106         *(ap->a_vpp) = NULLVP;
107
108         UNIONFS_INTERNAL_DEBUG("unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n", nameiop, cnflags, cnp->cn_nameptr);
109
110         if (dvp->v_type != VDIR)
111                 return (ENOTDIR);
112
113         /*
114          * If read-only and op is not LOOKUP, will return EROFS.
115          */
116         if ((cnflags & ISLASTCN) &&
117             (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
118             LOOKUP != nameiop)
119                 return (EROFS);
120
121         /*
122          * lookup dotdot
123          */
124         if (cnflags & ISDOTDOT) {
125                 if (LOOKUP != nameiop && udvp == NULLVP)
126                         return (EROFS);
127
128                 if (udvp != NULLVP) {
129                         dtmpvp = udvp;
130                         if (ldvp != NULLVP)
131                                 VOP_UNLOCK(ldvp, LK_RELEASE);
132                 }
133                 else
134                         dtmpvp = ldvp;
135
136                 error = VOP_LOOKUP(dtmpvp, &vp, cnp);
137
138                 if (dtmpvp == udvp && ldvp != NULLVP) {
139                         VOP_UNLOCK(udvp, LK_RELEASE);
140                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
141                 }
142
143                 if (error == 0) {
144                         /*
145                          * Exchange lock and reference from vp to
146                          * dunp->un_dvp. vp is upper/lower vnode, but it
147                          * will need to return the unionfs vnode.
148                          */
149                         if (nameiop == DELETE  || nameiop == RENAME ||
150                             (cnp->cn_lkflags & LK_TYPE_MASK))
151                                 VOP_UNLOCK(vp, LK_RELEASE);
152                         vrele(vp);
153
154                         VOP_UNLOCK(dvp, LK_RELEASE);
155                         *(ap->a_vpp) = dunp->un_dvp;
156                         vref(dunp->un_dvp);
157
158                         if (nameiop == DELETE || nameiop == RENAME)
159                                 vn_lock(dunp->un_dvp, LK_EXCLUSIVE | LK_RETRY);
160                         else if (cnp->cn_lkflags & LK_TYPE_MASK)
161                                 vn_lock(dunp->un_dvp, cnp->cn_lkflags |
162                                     LK_RETRY);
163
164                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
165                 } else if (error == ENOENT && (cnflags & MAKEENTRY) != 0)
166                         cache_enter(dvp, NULLVP, cnp);
167
168                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
169
170                 return (error);
171         }
172
173         /*
174          * lookup upper layer
175          */
176         if (udvp != NULLVP) {
177                 uerror = VOP_LOOKUP(udvp, &uvp, cnp);
178
179                 if (uerror == 0) {
180                         if (udvp == uvp) {      /* is dot */
181                                 vrele(uvp);
182                                 *(ap->a_vpp) = dvp;
183                                 vref(dvp);
184
185                                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", uerror);
186
187                                 return (uerror);
188                         }
189                         if (nameiop == DELETE || nameiop == RENAME ||
190                             (cnp->cn_lkflags & LK_TYPE_MASK))
191                                 VOP_UNLOCK(uvp, LK_RELEASE);
192                 }
193
194                 /* check whiteout */
195                 if (uerror == ENOENT || uerror == EJUSTRETURN)
196                         if (cnp->cn_flags & ISWHITEOUT)
197                                 iswhiteout = 1; /* don't lookup lower */
198                 if (iswhiteout == 0 && ldvp != NULLVP)
199                         if (!VOP_GETATTR(udvp, &va, cnp->cn_cred) &&
200                             (va.va_flags & OPAQUE))
201                                 iswhiteout = 1; /* don't lookup lower */
202 #if 0
203                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: debug: whiteout=%d, path=%s\n", iswhiteout, cnp->cn_nameptr);
204 #endif
205         }
206
207         /*
208          * lookup lower layer
209          */
210         if (ldvp != NULLVP && !(cnflags & DOWHITEOUT) && iswhiteout == 0) {
211                 /* always op is LOOKUP */
212                 cnp->cn_nameiop = LOOKUP;
213                 cnflagsbk = cnp->cn_flags;
214                 cnp->cn_flags = cnflags;
215
216                 lerror = VOP_LOOKUP(ldvp, &lvp, cnp);
217
218                 cnp->cn_nameiop = nameiop;
219                 if (udvp != NULLVP && (uerror == 0 || uerror == EJUSTRETURN))
220                         cnp->cn_flags = cnflagsbk;
221
222                 if (lerror == 0) {
223                         if (ldvp == lvp) {      /* is dot */
224                                 if (uvp != NULLVP)
225                                         vrele(uvp);     /* no need? */
226                                 vrele(lvp);
227                                 *(ap->a_vpp) = dvp;
228                                 vref(dvp);
229
230                                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", lerror);
231
232                                 return (lerror);
233                         }
234                         if (cnp->cn_lkflags & LK_TYPE_MASK)
235                                 VOP_UNLOCK(lvp, LK_RELEASE);
236                 }
237         }
238
239         /*
240          * check lookup result
241          */
242         if (uvp == NULLVP && lvp == NULLVP) {
243                 UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n",
244                     (udvp != NULLVP ? uerror : lerror));
245                 return (udvp != NULLVP ? uerror : lerror);
246         }
247
248         /*
249          * check vnode type
250          */
251         if (uvp != NULLVP && lvp != NULLVP && uvp->v_type != lvp->v_type) {
252                 vrele(lvp);
253                 lvp = NULLVP;
254         }
255
256         /*
257          * check shadow dir
258          */
259         if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULLVP &&
260             lerror == 0 && lvp != NULLVP && lvp->v_type == VDIR &&
261             !(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
262             (1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
263                 /* get unionfs vnode in order to create a new shadow dir. */
264                 error = unionfs_nodeget(dvp->v_mount, NULLVP, lvp, dvp, &vp,
265                     cnp, td);
266                 if (error != 0)
267                         goto unionfs_lookup_out;
268
269                 if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
270                         VOP_UNLOCK(vp, LK_RELEASE);
271                 if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) {
272                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
273                         lockflag = 1;
274                 }
275                 error = unionfs_mkshadowdir(MOUNTTOUNIONFSMOUNT(dvp->v_mount),
276                     udvp, VTOUNIONFS(vp), cnp, td);
277                 if (lockflag != 0)
278                         VOP_UNLOCK(vp, LK_RELEASE);
279                 if (error != 0) {
280                         UNIONFSDEBUG("unionfs_lookup: Unable to create shadow dir.");
281                         if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
282                                 vput(vp);
283                         else
284                                 vrele(vp);
285                         goto unionfs_lookup_out;
286                 }
287                 if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED)
288                         vn_lock(vp, LK_SHARED | LK_RETRY);
289         }
290         /*
291          * get unionfs vnode.
292          */
293         else {
294                 if (uvp != NULLVP)
295                         error = uerror;
296                 else
297                         error = lerror;
298                 if (error != 0)
299                         goto unionfs_lookup_out;
300                 /*
301                  * get socket vnode.
302                  */
303                 if (uvp != NULLVP && uvp->v_type == VSOCK) {
304                         vp = uvp;
305                         vref(vp);
306                         if (cnp->cn_lkflags & LK_TYPE_MASK)
307                                 vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
308                 }
309                 else if (lvp != NULLVP && lvp->v_type == VSOCK) {
310                         vp = lvp;
311                         vref(vp);
312                         if (cnp->cn_lkflags & LK_TYPE_MASK)
313                                 vn_lock(vp, cnp->cn_lkflags | LK_RETRY);
314                 }
315                 /*
316                  * get unionfs vnode.
317                  */
318                 else
319                         error = unionfs_nodeget(dvp->v_mount, uvp, lvp,
320                             dvp, &vp, cnp, td);
321                 if (error != 0) {
322                         UNIONFSDEBUG("unionfs_lookup: Unable to create unionfs vnode.");
323                         goto unionfs_lookup_out;
324                 }
325                 if ((nameiop == DELETE || nameiop == RENAME) &&
326                     (cnp->cn_lkflags & LK_TYPE_MASK) == 0)
327                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
328         }
329
330         *(ap->a_vpp) = vp;
331
332         if ((cnflags & MAKEENTRY) && vp->v_type != VSOCK)
333                 cache_enter(dvp, vp, cnp);
334
335 unionfs_lookup_out:
336         if (uvp != NULLVP)
337                 vrele(uvp);
338         if (lvp != NULLVP)
339                 vrele(lvp);
340
341         if (error == ENOENT && (cnflags & MAKEENTRY) != 0)
342                 cache_enter(dvp, NULLVP, cnp);
343
344         UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
345
346         return (error);
347 }
348
349 static int
350 unionfs_create(struct vop_create_args *ap)
351 {
352         struct unionfs_node *dunp;
353         struct componentname *cnp;
354         struct vnode   *udvp;
355         struct vnode   *vp;
356         int             error;
357
358         UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
359
360         KASSERT_UNIONFS_VNODE(ap->a_dvp);
361
362         dunp = VTOUNIONFS(ap->a_dvp);
363         cnp = ap->a_cnp;
364         udvp = dunp->un_uppervp;
365         error = EROFS;
366
367         if (udvp != NULLVP) {
368                 error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap);
369                 if (error != 0)
370                         goto unionfs_create_abort;
371
372                 if (vp->v_type == VSOCK)
373                         *(ap->a_vpp) = vp;
374                 else {
375                         VOP_UNLOCK(vp, LK_RELEASE);
376                         error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
377                             ap->a_dvp, ap->a_vpp, cnp, curthread);
378                         vrele(vp);
379                 }
380         }
381
382 unionfs_create_abort:
383         UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
384
385         return (error);
386 }
387
388 static int
389 unionfs_whiteout(struct vop_whiteout_args *ap)
390 {
391         struct unionfs_node *dunp;
392         struct componentname *cnp;
393         struct vnode   *udvp;
394         int             error;
395
396         UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
397
398         KASSERT_UNIONFS_VNODE(ap->a_dvp);
399
400         dunp = VTOUNIONFS(ap->a_dvp);
401         cnp = ap->a_cnp;
402         udvp = dunp->un_uppervp;
403         error = EOPNOTSUPP;
404
405         if (udvp != NULLVP) {
406                 switch (ap->a_flags) {
407                 case CREATE:
408                 case DELETE:
409                 case LOOKUP:
410                         error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
411                         break;
412                 default:
413                         error = EINVAL;
414                         break;
415                 }
416         }
417
418         UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
419
420         return (error);
421 }
422
423 static int
424 unionfs_mknod(struct vop_mknod_args *ap)
425 {
426         struct unionfs_node *dunp;
427         struct componentname *cnp;
428         struct vnode   *udvp;
429         struct vnode   *vp;
430         int             error;
431
432         UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
433
434         KASSERT_UNIONFS_VNODE(ap->a_dvp);
435
436         dunp = VTOUNIONFS(ap->a_dvp);
437         cnp = ap->a_cnp;
438         udvp = dunp->un_uppervp;
439         error = EROFS;
440
441         if (udvp != NULLVP) {
442                 error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap);
443                 if (error != 0)
444                         goto unionfs_mknod_abort;
445
446                 if (vp->v_type == VSOCK)
447                         *(ap->a_vpp) = vp;
448                 else {
449                         VOP_UNLOCK(vp, LK_RELEASE);
450                         error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULLVP,
451                             ap->a_dvp, ap->a_vpp, cnp, curthread);
452                         vrele(vp);
453                 }
454         }
455
456 unionfs_mknod_abort:
457         UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
458
459         return (error);
460 }
461
462 static int
463 unionfs_open(struct vop_open_args *ap)
464 {
465         int             error;
466         struct unionfs_node *unp;
467         struct unionfs_node_status *unsp;
468         struct vnode   *uvp;
469         struct vnode   *lvp;
470         struct vnode   *targetvp;
471         struct ucred   *cred;
472         struct thread  *td;
473
474         UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
475
476         KASSERT_UNIONFS_VNODE(ap->a_vp);
477
478         error = 0;
479         unp = VTOUNIONFS(ap->a_vp);
480         uvp = unp->un_uppervp;
481         lvp = unp->un_lowervp;
482         targetvp = NULLVP;
483         cred = ap->a_cred;
484         td = ap->a_td;
485
486         unionfs_get_node_status(unp, td, &unsp);
487
488         if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
489                 /* vnode is already opend. */
490                 if (unsp->uns_upper_opencnt > 0)
491                         targetvp = uvp;
492                 else
493                         targetvp = lvp;
494
495                 if (targetvp == lvp &&
496                     (ap->a_mode & FWRITE) && lvp->v_type == VREG)
497                         targetvp = NULLVP;
498         }
499         if (targetvp == NULLVP) {
500                 if (uvp == NULLVP) {
501                         if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
502                                 error = unionfs_copyfile(unp,
503                                     !(ap->a_mode & O_TRUNC), cred, td);
504                                 if (error != 0)
505                                         goto unionfs_open_abort;
506                                 targetvp = uvp = unp->un_uppervp;
507                         } else
508                                 targetvp = lvp;
509                 } else
510                         targetvp = uvp;
511         }
512
513         error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp);
514         if (error == 0) {
515                 if (targetvp == uvp) {
516                         if (uvp->v_type == VDIR && lvp != NULLVP &&
517                             unsp->uns_lower_opencnt <= 0) {
518                                 /* open lower for readdir */
519                                 error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
520                                 if (error != 0) {
521                                         VOP_CLOSE(uvp, ap->a_mode, cred, td);
522                                         goto unionfs_open_abort;
523                                 }
524                                 unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
525                                 unsp->uns_lower_opencnt++;
526                         }
527                         unsp->uns_upper_opencnt++;
528                 } else {
529                         unsp->uns_lower_opencnt++;
530                         unsp->uns_lower_openmode = ap->a_mode;
531                 }
532                 ap->a_vp->v_object = targetvp->v_object;
533         }
534
535 unionfs_open_abort:
536         if (error != 0)
537                 unionfs_tryrem_node_status(unp, unsp);
538
539         UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
540
541         return (error);
542 }
543
544 static int
545 unionfs_close(struct vop_close_args *ap)
546 {
547         int             error;
548         int             locked;
549         struct unionfs_node *unp;
550         struct unionfs_node_status *unsp;
551         struct ucred   *cred;
552         struct thread  *td;
553         struct vnode   *vp;
554         struct vnode   *ovp;
555
556         UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
557
558         KASSERT_UNIONFS_VNODE(ap->a_vp);
559
560         locked = 0;
561         vp = ap->a_vp;
562         unp = VTOUNIONFS(vp);
563         cred = ap->a_cred;
564         td = ap->a_td;
565
566         if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
567                 if (vn_lock(vp, LK_UPGRADE) != 0)
568                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
569                 locked = 1;
570         }
571         unionfs_get_node_status(unp, td, &unsp);
572
573         if (unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0) {
574 #ifdef DIAGNOSTIC
575                 printf("unionfs_close: warning: open count is 0\n");
576 #endif
577                 if (unp->un_uppervp != NULLVP)
578                         ovp = unp->un_uppervp;
579                 else
580                         ovp = unp->un_lowervp;
581         } else if (unsp->uns_upper_opencnt > 0)
582                 ovp = unp->un_uppervp;
583         else
584                 ovp = unp->un_lowervp;
585
586         error = VOP_CLOSE(ovp, ap->a_fflag, cred, td);
587
588         if (error != 0)
589                 goto unionfs_close_abort;
590
591         vp->v_object = ovp->v_object;
592
593         if (ovp == unp->un_uppervp) {
594                 unsp->uns_upper_opencnt--;
595                 if (unsp->uns_upper_opencnt == 0) {
596                         if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
597                                 VOP_CLOSE(unp->un_lowervp, FREAD, cred, td);
598                                 unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
599                                 unsp->uns_lower_opencnt--;
600                         }
601                         if (unsp->uns_lower_opencnt > 0)
602                                 vp->v_object = unp->un_lowervp->v_object;
603                 }
604         } else
605                 unsp->uns_lower_opencnt--;
606
607 unionfs_close_abort:
608         unionfs_tryrem_node_status(unp, unsp);
609
610         if (locked != 0)
611                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
612
613         UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
614
615         return (error);
616 }
617
618 /*
619  * Check the access mode toward shadow file/dir.
620  */
621 static int
622 unionfs_check_corrected_access(accmode_t accmode,
623                              struct vattr *va,
624                              struct ucred *cred)
625 {
626         int             count;
627         uid_t           uid;    /* upper side vnode's uid */
628         gid_t           gid;    /* upper side vnode's gid */
629         u_short         vmode;  /* upper side vnode's mode */
630         u_short         mask;
631
632         mask = 0;
633         uid = va->va_uid;
634         gid = va->va_gid;
635         vmode = va->va_mode;
636
637         /* check owner */
638         if (cred->cr_uid == uid) {
639                 if (accmode & VEXEC)
640                         mask |= S_IXUSR;
641                 if (accmode & VREAD)
642                         mask |= S_IRUSR;
643                 if (accmode & VWRITE)
644                         mask |= S_IWUSR;
645                 return ((vmode & mask) == mask ? 0 : EACCES);
646         }
647
648         /* check group */
649         count = 0;
650         if (groupmember(gid, cred)) {
651                 if (accmode & VEXEC)
652                         mask |= S_IXGRP;
653                 if (accmode & VREAD)
654                         mask |= S_IRGRP;
655                 if (accmode & VWRITE)
656                         mask |= S_IWGRP;
657                 return ((vmode & mask) == mask ? 0 : EACCES);
658         }
659
660         /* check other */
661         if (accmode & VEXEC)
662                 mask |= S_IXOTH;
663         if (accmode & VREAD)
664                 mask |= S_IROTH;
665         if (accmode & VWRITE)
666                 mask |= S_IWOTH;
667
668         return ((vmode & mask) == mask ? 0 : EACCES);
669 }
670
671 static int
672 unionfs_access(struct vop_access_args *ap)
673 {
674         struct unionfs_mount *ump;
675         struct unionfs_node *unp;
676         struct vnode   *uvp;
677         struct vnode   *lvp;
678         struct thread  *td;
679         struct vattr    va;
680         accmode_t       accmode;
681         int             error;
682
683         UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
684
685         KASSERT_UNIONFS_VNODE(ap->a_vp);
686
687         ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
688         unp = VTOUNIONFS(ap->a_vp);
689         uvp = unp->un_uppervp;
690         lvp = unp->un_lowervp;
691         td = ap->a_td;
692         accmode = ap->a_accmode;
693         error = EACCES;
694
695         if ((accmode & VWRITE) &&
696             (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
697                 switch (ap->a_vp->v_type) {
698                 case VREG:
699                 case VDIR:
700                 case VLNK:
701                         return (EROFS);
702                 default:
703                         break;
704                 }
705         }
706
707         if (uvp != NULLVP) {
708                 error = VOP_ACCESS(uvp, accmode, ap->a_cred, td);
709
710                 UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
711
712                 return (error);
713         }
714
715         if (lvp != NULLVP) {
716                 if (accmode & VWRITE) {
717                         if (ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY) {
718                                 switch (ap->a_vp->v_type) {
719                                 case VREG:
720                                 case VDIR:
721                                 case VLNK:
722                                         return (EROFS);
723                                 default:
724                                         break;
725                                 }
726                         } else if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
727                                 /* check shadow file/dir */
728                                 if (ump->um_copymode != UNIONFS_TRANSPARENT) {
729                                         error = unionfs_create_uppervattr(ump,
730                                             lvp, &va, ap->a_cred, td);
731                                         if (error != 0)
732                                                 return (error);
733
734                                         error = unionfs_check_corrected_access(
735                                             accmode, &va, ap->a_cred);
736                                         if (error != 0)
737                                                 return (error);
738                                 }
739                         }
740                         accmode &= ~(VWRITE | VAPPEND);
741                         accmode |= VREAD; /* will copy to upper */
742                 }
743                 error = VOP_ACCESS(lvp, accmode, ap->a_cred, td);
744         }
745
746         UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
747
748         return (error);
749 }
750
751 static int
752 unionfs_getattr(struct vop_getattr_args *ap)
753 {
754         int             error;
755         struct unionfs_node *unp;
756         struct unionfs_mount *ump;
757         struct vnode   *uvp;
758         struct vnode   *lvp;
759         struct thread  *td;
760         struct vattr    va;
761
762         UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
763
764         KASSERT_UNIONFS_VNODE(ap->a_vp);
765
766         unp = VTOUNIONFS(ap->a_vp);
767         ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
768         uvp = unp->un_uppervp;
769         lvp = unp->un_lowervp;
770         td = curthread;
771
772         if (uvp != NULLVP) {
773                 if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0)
774                         ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
775
776                 UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
777                     ap->a_vap->va_mode, ap->a_vap->va_uid,
778                     ap->a_vap->va_gid, error);
779
780                 return (error);
781         }
782
783         error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
784
785         if (error == 0 && !(ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY)) {
786                 /* correct the attr toward shadow file/dir. */
787                 if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
788                         unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);
789                         ap->a_vap->va_mode = va.va_mode;
790                         ap->a_vap->va_uid = va.va_uid;
791                         ap->a_vap->va_gid = va.va_gid;
792                 }
793         }
794
795         if (error == 0)
796                 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
797
798         UNIONFS_INTERNAL_DEBUG("unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
799             ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
800
801         return (error);
802 }
803
804 static int
805 unionfs_setattr(struct vop_setattr_args *ap)
806 {
807         int             error;
808         struct unionfs_node *unp;
809         struct vnode   *uvp;
810         struct vnode   *lvp;
811         struct thread  *td;
812         struct vattr   *vap;
813
814         UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
815
816         KASSERT_UNIONFS_VNODE(ap->a_vp);
817
818         error = EROFS;
819         unp = VTOUNIONFS(ap->a_vp);
820         uvp = unp->un_uppervp;
821         lvp = unp->un_lowervp;
822         td = curthread;
823         vap = ap->a_vap;
824
825         if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
826             (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
827              vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
828              vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
829                 return (EROFS);
830
831         if (uvp == NULLVP && lvp->v_type == VREG) {
832                 error = unionfs_copyfile(unp, (vap->va_size != 0),
833                     ap->a_cred, td);
834                 if (error != 0)
835                         return (error);
836                 uvp = unp->un_uppervp;
837         }
838
839         if (uvp != NULLVP)
840                 error = VOP_SETATTR(uvp, vap, ap->a_cred);
841
842         UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
843
844         return (error);
845 }
846
847 static int
848 unionfs_read(struct vop_read_args *ap)
849 {
850         int             error;
851         struct unionfs_node *unp;
852         struct vnode   *tvp;
853
854         /* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
855
856         KASSERT_UNIONFS_VNODE(ap->a_vp);
857
858         unp = VTOUNIONFS(ap->a_vp);
859         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
860
861         error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
862
863         /* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
864
865         return (error);
866 }
867
868 static int
869 unionfs_write(struct vop_write_args *ap)
870 {
871         int             error;
872         struct unionfs_node *unp;
873         struct vnode   *tvp;
874
875         /* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
876
877         KASSERT_UNIONFS_VNODE(ap->a_vp);
878
879         unp = VTOUNIONFS(ap->a_vp);
880         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
881
882         error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
883
884         /* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
885
886         return (error);
887 }
888
889 static int
890 unionfs_ioctl(struct vop_ioctl_args *ap)
891 {
892         int error;
893         struct unionfs_node *unp;
894         struct unionfs_node_status *unsp;
895         struct vnode   *ovp;
896
897         UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
898
899         KASSERT_UNIONFS_VNODE(ap->a_vp);
900
901         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
902         unp = VTOUNIONFS(ap->a_vp);
903         unionfs_get_node_status(unp, ap->a_td, &unsp);
904         ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
905         unionfs_tryrem_node_status(unp, unsp);
906         VOP_UNLOCK(ap->a_vp, LK_RELEASE);
907
908         if (ovp == NULLVP)
909                 return (EBADF);
910
911         error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
912             ap->a_cred, ap->a_td);
913
914         UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error);
915
916         return (error);
917 }
918
919 static int
920 unionfs_poll(struct vop_poll_args *ap)
921 {
922         struct unionfs_node *unp;
923         struct unionfs_node_status *unsp;
924         struct vnode   *ovp;
925
926         KASSERT_UNIONFS_VNODE(ap->a_vp);
927
928         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
929         unp = VTOUNIONFS(ap->a_vp);
930         unionfs_get_node_status(unp, ap->a_td, &unsp);
931         ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
932         unionfs_tryrem_node_status(unp, unsp);
933         VOP_UNLOCK(ap->a_vp, LK_RELEASE);
934
935         if (ovp == NULLVP)
936                 return (EBADF);
937
938         return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td));
939 }
940
941 static int
942 unionfs_fsync(struct vop_fsync_args *ap)
943 {
944         struct unionfs_node *unp;
945         struct unionfs_node_status *unsp;
946         struct vnode   *ovp;
947
948         KASSERT_UNIONFS_VNODE(ap->a_vp);
949
950         unp = VTOUNIONFS(ap->a_vp);
951         unionfs_get_node_status(unp, ap->a_td, &unsp);
952         ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
953         unionfs_tryrem_node_status(unp, unsp);
954
955         if (ovp == NULLVP)
956                 return (EBADF);
957
958         return (VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td));
959 }
960
961 static int
962 unionfs_remove(struct vop_remove_args *ap)
963 {
964         int             error;
965         char           *path;
966         struct unionfs_node *dunp;
967         struct unionfs_node *unp;
968         struct unionfs_mount *ump;
969         struct vnode   *udvp;
970         struct vnode   *uvp;
971         struct vnode   *lvp;
972         struct vnode   *vp;
973         struct componentname *cnp;
974         struct componentname cn;
975         struct thread  *td;
976
977         UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
978
979         KASSERT_UNIONFS_VNODE(ap->a_dvp);
980
981         error = 0;
982         dunp = VTOUNIONFS(ap->a_dvp);
983         udvp = dunp->un_uppervp;
984         cnp = ap->a_cnp;
985         td = curthread;
986
987         if (ap->a_vp->v_op != &unionfs_vnodeops) {
988                 if (ap->a_vp->v_type != VSOCK)
989                         return (EINVAL);
990                 ump = NULL;
991                 vp = uvp = lvp = NULLVP;
992                 /* search vnode */
993                 VOP_UNLOCK(ap->a_vp, LK_RELEASE);
994                 error = unionfs_relookup(udvp, &vp, cnp, &cn, td,
995                     cnp->cn_nameptr, strlen(cnp->cn_nameptr), DELETE);
996                 if (error != 0 && error != ENOENT) {
997                         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
998                         return (error);
999                 }
1000
1001                 if (error == 0 && vp == ap->a_vp) {
1002                         /* target vnode in upper */
1003                         uvp = vp;
1004                         vrele(vp);
1005                         path = NULL;
1006                 } else {
1007                         /* target vnode in lower */
1008                         if (vp != NULLVP) {
1009                                 if (udvp == vp)
1010                                         vrele(vp);
1011                                 else
1012                                         vput(vp);
1013                         }
1014                         vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1015                         lvp = ap->a_vp;
1016                         path = ap->a_cnp->cn_nameptr;
1017                 }
1018         } else {
1019                 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1020                 unp = VTOUNIONFS(ap->a_vp);
1021                 uvp = unp->un_uppervp;
1022                 lvp = unp->un_lowervp;
1023                 path = unp->un_path;
1024         }
1025
1026         if (udvp == NULLVP)
1027                 return (EROFS);
1028
1029         if (uvp != NULLVP) {
1030                 /*
1031                  * XXX: if the vnode type is VSOCK, it will create whiteout
1032                  *      after remove.
1033                  */
1034                 if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS ||
1035                     lvp != NULLVP)
1036                         cnp->cn_flags |= DOWHITEOUT;
1037                 error = VOP_REMOVE(udvp, uvp, cnp);
1038         } else if (lvp != NULLVP)
1039                 error = unionfs_mkwhiteout(udvp, cnp, td, path);
1040
1041         UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
1042
1043         return (error);
1044 }
1045
1046 static int
1047 unionfs_link(struct vop_link_args *ap)
1048 {
1049         int             error;
1050         int             needrelookup;
1051         struct unionfs_node *dunp;
1052         struct unionfs_node *unp;
1053         struct vnode   *udvp;
1054         struct vnode   *uvp;
1055         struct componentname *cnp;
1056         struct thread  *td;
1057
1058         UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
1059
1060         KASSERT_UNIONFS_VNODE(ap->a_tdvp);
1061         KASSERT_UNIONFS_VNODE(ap->a_vp);
1062
1063         error = 0;
1064         needrelookup = 0;
1065         dunp = VTOUNIONFS(ap->a_tdvp);
1066         unp = NULL;
1067         udvp = dunp->un_uppervp;
1068         uvp = NULLVP;
1069         cnp = ap->a_cnp;
1070         td = curthread;
1071
1072         if (udvp == NULLVP)
1073                 return (EROFS);
1074
1075         if (ap->a_vp->v_op != &unionfs_vnodeops)
1076                 uvp = ap->a_vp;
1077         else {
1078                 unp = VTOUNIONFS(ap->a_vp);
1079
1080                 if (unp->un_uppervp == NULLVP) {
1081                         if (ap->a_vp->v_type != VREG)
1082                                 return (EOPNOTSUPP);
1083
1084                         error = unionfs_copyfile(unp, 1, cnp->cn_cred, td);
1085                         if (error != 0)
1086                                 return (error);
1087                         needrelookup = 1;
1088                 }
1089                 uvp = unp->un_uppervp;
1090         }
1091
1092         if (needrelookup != 0)
1093                 error = unionfs_relookup_for_create(ap->a_tdvp, cnp, td);
1094
1095         if (error == 0)
1096                 error = VOP_LINK(udvp, uvp, cnp);
1097
1098         UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
1099
1100         return (error);
1101 }
1102
1103 static int
1104 unionfs_rename(struct vop_rename_args *ap)
1105 {
1106         int             error;
1107         struct vnode   *fdvp;
1108         struct vnode   *fvp;
1109         struct componentname *fcnp;
1110         struct vnode   *tdvp;
1111         struct vnode   *tvp;
1112         struct componentname *tcnp;
1113         struct vnode   *ltdvp;
1114         struct vnode   *ltvp;
1115         struct thread  *td;
1116
1117         /* rename target vnodes */
1118         struct vnode   *rfdvp;
1119         struct vnode   *rfvp;
1120         struct vnode   *rtdvp;
1121         struct vnode   *rtvp;
1122
1123         int             needrelookup;
1124         struct unionfs_mount *ump;
1125         struct unionfs_node *unp;
1126
1127         UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1128
1129         error = 0;
1130         fdvp = ap->a_fdvp;
1131         fvp = ap->a_fvp;
1132         fcnp = ap->a_fcnp;
1133         tdvp = ap->a_tdvp;
1134         tvp = ap->a_tvp;
1135         tcnp = ap->a_tcnp;
1136         ltdvp = NULLVP;
1137         ltvp = NULLVP;
1138         td = curthread;
1139         rfdvp = fdvp;
1140         rfvp = fvp;
1141         rtdvp = tdvp;
1142         rtvp = tvp;
1143         needrelookup = 0;
1144
1145 #ifdef DIAGNOSTIC
1146         if (!(fcnp->cn_flags & HASBUF) || !(tcnp->cn_flags & HASBUF))
1147                 panic("unionfs_rename: no name");
1148 #endif
1149
1150         /* check for cross device rename */
1151         if (fvp->v_mount != tdvp->v_mount ||
1152             (tvp != NULLVP && fvp->v_mount != tvp->v_mount)) {
1153                 if (fvp->v_op != &unionfs_vnodeops)
1154                         error = ENODEV;
1155                 else
1156                         error = EXDEV;
1157                 goto unionfs_rename_abort;
1158         }
1159
1160         /* Renaming a file to itself has no effect. */
1161         if (fvp == tvp)
1162                 goto unionfs_rename_abort;
1163
1164         /*
1165          * from/to vnode is unionfs node.
1166          */
1167
1168         KASSERT_UNIONFS_VNODE(fdvp);
1169         KASSERT_UNIONFS_VNODE(fvp);
1170         KASSERT_UNIONFS_VNODE(tdvp);
1171         if (tvp != NULLVP)
1172                 KASSERT_UNIONFS_VNODE(tvp);
1173
1174         unp = VTOUNIONFS(fdvp);
1175 #ifdef UNIONFS_IDBG_RENAME
1176         UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n", fdvp, unp->un_uppervp, unp->un_lowervp);
1177 #endif
1178         if (unp->un_uppervp == NULLVP) {
1179                 error = ENODEV;
1180                 goto unionfs_rename_abort;
1181         }
1182         rfdvp = unp->un_uppervp;
1183         vref(rfdvp);
1184
1185         unp = VTOUNIONFS(fvp);
1186 #ifdef UNIONFS_IDBG_RENAME
1187         UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n", fvp, unp->un_uppervp, unp->un_lowervp);
1188 #endif
1189         ump = MOUNTTOUNIONFSMOUNT(fvp->v_mount);
1190         if (unp->un_uppervp == NULLVP) {
1191                 switch (fvp->v_type) {
1192                 case VREG:
1193                         if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1194                                 goto unionfs_rename_abort;
1195                         error = unionfs_copyfile(unp, 1, fcnp->cn_cred, td);
1196                         VOP_UNLOCK(fvp, LK_RELEASE);
1197                         if (error != 0)
1198                                 goto unionfs_rename_abort;
1199                         break;
1200                 case VDIR:
1201                         if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1202                                 goto unionfs_rename_abort;
1203                         error = unionfs_mkshadowdir(ump, rfdvp, unp, fcnp, td);
1204                         VOP_UNLOCK(fvp, LK_RELEASE);
1205                         if (error != 0)
1206                                 goto unionfs_rename_abort;
1207                         break;
1208                 default:
1209                         error = ENODEV;
1210                         goto unionfs_rename_abort;
1211                 }
1212
1213                 needrelookup = 1;
1214         }
1215
1216         if (unp->un_lowervp != NULLVP)
1217                 fcnp->cn_flags |= DOWHITEOUT;
1218         rfvp = unp->un_uppervp;
1219         vref(rfvp);
1220
1221         unp = VTOUNIONFS(tdvp);
1222 #ifdef UNIONFS_IDBG_RENAME
1223         UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n", tdvp, unp->un_uppervp, unp->un_lowervp);
1224 #endif
1225         if (unp->un_uppervp == NULLVP) {
1226                 error = ENODEV;
1227                 goto unionfs_rename_abort;
1228         }
1229         rtdvp = unp->un_uppervp;
1230         ltdvp = unp->un_lowervp;
1231         vref(rtdvp);
1232
1233         if (tdvp == tvp) {
1234                 rtvp = rtdvp;
1235                 vref(rtvp);
1236         } else if (tvp != NULLVP) {
1237                 unp = VTOUNIONFS(tvp);
1238 #ifdef UNIONFS_IDBG_RENAME
1239                 UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n", tvp, unp->un_uppervp, unp->un_lowervp);
1240 #endif
1241                 if (unp->un_uppervp == NULLVP)
1242                         rtvp = NULLVP;
1243                 else {
1244                         if (tvp->v_type == VDIR) {
1245                                 error = EINVAL;
1246                                 goto unionfs_rename_abort;
1247                         }
1248                         rtvp = unp->un_uppervp;
1249                         ltvp = unp->un_lowervp;
1250                         vref(rtvp);
1251                 }
1252         }
1253
1254         if (rfvp == rtvp)
1255                 goto unionfs_rename_abort;
1256
1257         if (needrelookup != 0) {
1258                 if ((error = vn_lock(fdvp, LK_EXCLUSIVE)) != 0)
1259                         goto unionfs_rename_abort;
1260                 error = unionfs_relookup_for_delete(fdvp, fcnp, td);
1261                 VOP_UNLOCK(fdvp, LK_RELEASE);
1262                 if (error != 0)
1263                         goto unionfs_rename_abort;
1264
1265                 /* Locke of tvp is canceled in order to avoid recursive lock. */
1266                 if (tvp != NULLVP && tvp != tdvp)
1267                         VOP_UNLOCK(tvp, LK_RELEASE);
1268                 error = unionfs_relookup_for_rename(tdvp, tcnp, td);
1269                 if (tvp != NULLVP && tvp != tdvp)
1270                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1271                 if (error != 0)
1272                         goto unionfs_rename_abort;
1273         }
1274
1275         error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1276
1277         if (error == 0) {
1278                 if (rtvp != NULLVP && rtvp->v_type == VDIR)
1279                         cache_purge(tdvp);
1280                 if (fvp->v_type == VDIR && fdvp != tdvp)
1281                         cache_purge(fdvp);
1282         }
1283
1284         if (ltdvp != NULLVP)
1285                 VOP_UNLOCK(ltdvp, LK_RELEASE);
1286         if (tdvp != rtdvp)
1287                 vrele(tdvp);
1288         if (ltvp != NULLVP)
1289                 VOP_UNLOCK(ltvp, LK_RELEASE);
1290         if (tvp != rtvp && tvp != NULLVP) {
1291                 if (rtvp == NULLVP)
1292                         vput(tvp);
1293                 else
1294                         vrele(tvp);
1295         }
1296         if (fdvp != rfdvp)
1297                 vrele(fdvp);
1298         if (fvp != rfvp)
1299                 vrele(fvp);
1300
1301         UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1302
1303         return (error);
1304
1305 unionfs_rename_abort:
1306         vput(tdvp);
1307         if (tdvp != rtdvp)
1308                 vrele(rtdvp);
1309         if (tvp != NULLVP) {
1310                 if (tdvp != tvp)
1311                         vput(tvp);
1312                 else
1313                         vrele(tvp);
1314         }
1315         if (tvp != rtvp && rtvp != NULLVP)
1316                 vrele(rtvp);
1317         if (fdvp != rfdvp)
1318                 vrele(rfdvp);
1319         if (fvp != rfvp)
1320                 vrele(rfvp);
1321         vrele(fdvp);
1322         vrele(fvp);
1323
1324         UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1325
1326         return (error);
1327 }
1328
1329 static int
1330 unionfs_mkdir(struct vop_mkdir_args *ap)
1331 {
1332         int             error;
1333         int             lkflags;
1334         struct unionfs_node *dunp;
1335         struct componentname *cnp;
1336         struct thread  *td;
1337         struct vnode   *udvp;
1338         struct vnode   *uvp;
1339         struct vattr    va;
1340
1341         UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1342
1343         KASSERT_UNIONFS_VNODE(ap->a_dvp);
1344
1345         error = EROFS;
1346         dunp = VTOUNIONFS(ap->a_dvp);
1347         cnp = ap->a_cnp;
1348         lkflags = cnp->cn_lkflags;
1349         td = curthread;
1350         udvp = dunp->un_uppervp;
1351
1352         if (udvp != NULLVP) {
1353                 /* check opaque */
1354                 if (!(cnp->cn_flags & ISWHITEOUT)) {
1355                         error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1356                         if (error != 0)
1357                                 return (error);
1358                         if (va.va_flags & OPAQUE) 
1359                                 cnp->cn_flags |= ISWHITEOUT;
1360                 }
1361
1362                 if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
1363                         VOP_UNLOCK(uvp, LK_RELEASE);
1364                         cnp->cn_lkflags = LK_EXCLUSIVE;
1365                         error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1366                             ap->a_dvp, ap->a_vpp, cnp, td);
1367                         cnp->cn_lkflags = lkflags;
1368                         vrele(uvp);
1369                 }
1370         }
1371
1372         UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1373
1374         return (error);
1375 }
1376
1377 static int
1378 unionfs_rmdir(struct vop_rmdir_args *ap)
1379 {
1380         int             error;
1381         struct unionfs_node *dunp;
1382         struct unionfs_node *unp;
1383         struct unionfs_mount *ump;
1384         struct componentname *cnp;
1385         struct thread  *td;
1386         struct vnode   *udvp;
1387         struct vnode   *uvp;
1388         struct vnode   *lvp;
1389
1390         UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1391
1392         KASSERT_UNIONFS_VNODE(ap->a_dvp);
1393         KASSERT_UNIONFS_VNODE(ap->a_vp);
1394
1395         error = 0;
1396         dunp = VTOUNIONFS(ap->a_dvp);
1397         unp = VTOUNIONFS(ap->a_vp);
1398         cnp = ap->a_cnp;
1399         td = curthread;
1400         udvp = dunp->un_uppervp;
1401         uvp = unp->un_uppervp;
1402         lvp = unp->un_lowervp;
1403
1404         if (udvp == NULLVP)
1405                 return (EROFS);
1406
1407         if (udvp == uvp)
1408                 return (EOPNOTSUPP);
1409
1410         if (uvp != NULLVP) {
1411                 if (lvp != NULLVP) {
1412                         error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1413                         if (error != 0)
1414                                 return (error);
1415                 }
1416                 ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1417                 if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP)
1418                         cnp->cn_flags |= DOWHITEOUT;
1419                 error = unionfs_relookup_for_delete(ap->a_dvp, cnp, td);
1420                 if (!error)
1421                         error = VOP_RMDIR(udvp, uvp, cnp);
1422         }
1423         else if (lvp != NULLVP)
1424                 error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path);
1425
1426         if (error == 0) {
1427                 cache_purge(ap->a_dvp);
1428                 cache_purge(ap->a_vp);
1429         }
1430
1431         UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1432
1433         return (error);
1434 }
1435
1436 static int
1437 unionfs_symlink(struct vop_symlink_args *ap)
1438 {
1439         int             error;
1440         int             lkflags;
1441         struct unionfs_node *dunp;
1442         struct componentname *cnp;
1443         struct thread  *td;
1444         struct vnode   *udvp;
1445         struct vnode   *uvp;
1446
1447         UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1448
1449         KASSERT_UNIONFS_VNODE(ap->a_dvp);
1450
1451         error = EROFS;
1452         dunp = VTOUNIONFS(ap->a_dvp);
1453         cnp = ap->a_cnp;
1454         lkflags = cnp->cn_lkflags;
1455         td = curthread;
1456         udvp = dunp->un_uppervp;
1457
1458         if (udvp != NULLVP) {
1459                 error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1460                 if (error == 0) {
1461                         VOP_UNLOCK(uvp, LK_RELEASE);
1462                         cnp->cn_lkflags = LK_EXCLUSIVE;
1463                         error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
1464                             ap->a_dvp, ap->a_vpp, cnp, td);
1465                         cnp->cn_lkflags = lkflags;
1466                         vrele(uvp);
1467                 }
1468         }
1469
1470         UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1471
1472         return (error);
1473 }
1474
1475 static int
1476 unionfs_readdir(struct vop_readdir_args *ap)
1477 {
1478         int             error;
1479         int             eofflag;
1480         int             locked;
1481         int             uio_offset_bk;
1482         struct unionfs_node *unp;
1483         struct unionfs_node_status *unsp;
1484         struct uio     *uio;
1485         struct vnode   *vp;
1486         struct vnode   *uvp;
1487         struct vnode   *lvp;
1488         struct thread  *td;
1489         struct vattr    va;
1490
1491         int             ncookies_bk;
1492         u_long         *cookies_bk;
1493
1494         UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1495
1496         KASSERT_UNIONFS_VNODE(ap->a_vp);
1497
1498         error = 0;
1499         eofflag = 0;
1500         locked = 0;
1501         uio_offset_bk = 0;
1502         uio = ap->a_uio;
1503         uvp = NULLVP;
1504         lvp = NULLVP;
1505         td = uio->uio_td;
1506         ncookies_bk = 0;
1507         cookies_bk = NULL;
1508
1509         vp = ap->a_vp;
1510         if (vp->v_type != VDIR)
1511                 return (ENOTDIR);
1512
1513         /* check the open count. unionfs needs to open before readdir. */
1514         if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
1515                 if (vn_lock(vp, LK_UPGRADE) != 0)
1516                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1517                 locked = 1;
1518         }
1519         unp = VTOUNIONFS(vp);
1520         if (unp == NULL)
1521                 error = EBADF;
1522         else {
1523                 uvp = unp->un_uppervp;
1524                 lvp = unp->un_lowervp;
1525                 unionfs_get_node_status(unp, td, &unsp);
1526                 if ((uvp != NULLVP && unsp->uns_upper_opencnt <= 0) ||
1527                         (lvp != NULLVP && unsp->uns_lower_opencnt <= 0)) {
1528                         unionfs_tryrem_node_status(unp, unsp);
1529                         error = EBADF;
1530                 }
1531         }
1532         if (locked)
1533                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
1534         if (error != 0)
1535                 goto unionfs_readdir_exit;
1536
1537         /* check opaque */
1538         if (uvp != NULLVP && lvp != NULLVP) {
1539                 if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1540                         goto unionfs_readdir_exit;
1541                 if (va.va_flags & OPAQUE)
1542                         lvp = NULLVP;
1543         }
1544
1545         /* upper only */
1546         if (uvp != NULLVP && lvp == NULLVP) {
1547                 error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1548                     ap->a_ncookies, ap->a_cookies);
1549                 unsp->uns_readdir_status = 0;
1550
1551                 goto unionfs_readdir_exit;
1552         }
1553
1554         /* lower only */
1555         if (uvp == NULLVP && lvp != NULLVP) {
1556                 error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1557                     ap->a_ncookies, ap->a_cookies);
1558                 unsp->uns_readdir_status = 2;
1559
1560                 goto unionfs_readdir_exit;
1561         }
1562
1563         /*
1564          * readdir upper and lower
1565          */
1566         KASSERT(uvp != NULLVP, ("unionfs_readdir: null upper vp"));
1567         KASSERT(lvp != NULLVP, ("unionfs_readdir: null lower vp"));
1568         if (uio->uio_offset == 0)
1569                 unsp->uns_readdir_status = 0;
1570
1571         if (unsp->uns_readdir_status == 0) {
1572                 /* read upper */
1573                 error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1574                                     ap->a_ncookies, ap->a_cookies);
1575
1576                 if (error != 0 || eofflag == 0)
1577                         goto unionfs_readdir_exit;
1578                 unsp->uns_readdir_status = 1;
1579
1580                 /*
1581                  * UFS(and other FS) needs size of uio_resid larger than
1582                  * DIRBLKSIZ.
1583                  * size of DIRBLKSIZ equals DEV_BSIZE.
1584                  * (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1585                  */
1586                 if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1587                         goto unionfs_readdir_exit;
1588
1589                 /*
1590                  * Backup cookies.
1591                  * It prepares to readdir in lower.
1592                  */
1593                 if (ap->a_ncookies != NULL) {
1594                         ncookies_bk = *(ap->a_ncookies);
1595                         *(ap->a_ncookies) = 0;
1596                 }
1597                 if (ap->a_cookies != NULL) {
1598                         cookies_bk = *(ap->a_cookies);
1599                         *(ap->a_cookies) = NULL;
1600                 }
1601         }
1602
1603         /* initialize for readdir in lower */
1604         if (unsp->uns_readdir_status == 1) {
1605                 unsp->uns_readdir_status = 2;
1606                 /*
1607                  * Backup uio_offset. See the comment after the
1608                  * VOP_READDIR call on the lower layer.
1609                  */
1610                 uio_offset_bk = uio->uio_offset;
1611                 uio->uio_offset = 0;
1612         }
1613
1614         if (lvp == NULLVP) {
1615                 error = EBADF;
1616                 goto unionfs_readdir_exit;
1617         }
1618         /* read lower */
1619         error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1620                             ap->a_ncookies, ap->a_cookies);
1621
1622         /*
1623          * We can't return an uio_offset of 0: this would trigger an
1624          * infinite loop, because the next call to unionfs_readdir would
1625          * always restart with the upper layer (uio_offset == 0) and
1626          * always return some data.
1627          *
1628          * This happens when the lower layer root directory is removed.
1629          * (A root directory deleting of unionfs should not be permitted.
1630          *  But current VFS can not do it.)
1631          */
1632         if (uio->uio_offset == 0)
1633                 uio->uio_offset = uio_offset_bk;
1634
1635         if (cookies_bk != NULL) {
1636                 /* merge cookies */
1637                 int             size;
1638                 u_long         *newcookies, *pos;
1639
1640                 size = *(ap->a_ncookies) + ncookies_bk;
1641                 newcookies = (u_long *) malloc(size * sizeof(u_long),
1642                     M_TEMP, M_WAITOK);
1643                 pos = newcookies;
1644
1645                 memcpy(pos, cookies_bk, ncookies_bk * sizeof(u_long));
1646                 pos += ncookies_bk;
1647                 memcpy(pos, *(ap->a_cookies), *(ap->a_ncookies) * sizeof(u_long));
1648                 free(cookies_bk, M_TEMP);
1649                 free(*(ap->a_cookies), M_TEMP);
1650                 *(ap->a_ncookies) = size;
1651                 *(ap->a_cookies) = newcookies;
1652         }
1653
1654 unionfs_readdir_exit:
1655         if (error != 0 && ap->a_eofflag != NULL)
1656                 *(ap->a_eofflag) = 1;
1657
1658         UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
1659
1660         return (error);
1661 }
1662
1663 static int
1664 unionfs_readlink(struct vop_readlink_args *ap)
1665 {
1666         int error;
1667         struct unionfs_node *unp;
1668         struct vnode   *vp;
1669
1670         UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
1671
1672         KASSERT_UNIONFS_VNODE(ap->a_vp);
1673
1674         unp = VTOUNIONFS(ap->a_vp);
1675         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
1676
1677         error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
1678
1679         UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
1680
1681         return (error);
1682 }
1683
1684 static int
1685 unionfs_getwritemount(struct vop_getwritemount_args *ap)
1686 {
1687         int             error;
1688         struct vnode   *uvp;
1689         struct vnode   *vp;
1690
1691         UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
1692
1693         error = 0;
1694         vp = ap->a_vp;
1695
1696         if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY))
1697                 return (EACCES);
1698
1699         KASSERT_UNIONFS_VNODE(vp);
1700
1701         uvp = UNIONFSVPTOUPPERVP(vp);
1702         if (uvp == NULLVP && VREG == vp->v_type)
1703                 uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp);
1704
1705         if (uvp != NULLVP)
1706                 error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
1707         else {
1708                 VI_LOCK(vp);
1709                 if (vp->v_iflag & VI_FREE)
1710                         error = EOPNOTSUPP;
1711                 else
1712                         error = EACCES;
1713                 VI_UNLOCK(vp);
1714         }
1715
1716         UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
1717
1718         return (error);
1719 }
1720
1721 static int
1722 unionfs_inactive(struct vop_inactive_args *ap)
1723 {
1724         ap->a_vp->v_object = NULL;
1725         vrecycle(ap->a_vp);
1726         return (0);
1727 }
1728
1729 static int
1730 unionfs_reclaim(struct vop_reclaim_args *ap)
1731 {
1732         /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
1733
1734         unionfs_noderem(ap->a_vp, ap->a_td);
1735
1736         /* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
1737
1738         return (0);
1739 }
1740
1741 static int
1742 unionfs_print(struct vop_print_args *ap)
1743 {
1744         struct unionfs_node *unp;
1745         /* struct unionfs_node_status *unsp; */
1746
1747         unp = VTOUNIONFS(ap->a_vp);
1748         /* unionfs_get_node_status(unp, curthread, &unsp); */
1749
1750         printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
1751             ap->a_vp, unp->un_uppervp, unp->un_lowervp);
1752         /*
1753         printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
1754             unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
1755         */
1756
1757         if (unp->un_uppervp != NULLVP)
1758                 vn_printf(unp->un_uppervp, "unionfs: upper ");
1759         if (unp->un_lowervp != NULLVP)
1760                 vn_printf(unp->un_lowervp, "unionfs: lower ");
1761
1762         return (0);
1763 }
1764
1765 static int
1766 unionfs_islocked(struct vop_islocked_args *ap)
1767 {
1768         struct unionfs_node *unp;
1769
1770         KASSERT_UNIONFS_VNODE(ap->a_vp);
1771
1772         unp = VTOUNIONFS(ap->a_vp);
1773         if (unp == NULL)
1774                 return (vop_stdislocked(ap));
1775
1776         if (unp->un_uppervp != NULLVP)
1777                 return (VOP_ISLOCKED(unp->un_uppervp));
1778         if (unp->un_lowervp != NULLVP)
1779                 return (VOP_ISLOCKED(unp->un_lowervp));
1780         return (vop_stdislocked(ap));
1781 }
1782
1783 static int
1784 unionfs_get_llt_revlock(struct vnode *vp, int flags)
1785 {
1786         int revlock;
1787
1788         revlock = 0;
1789
1790         switch (flags & LK_TYPE_MASK) {
1791         case LK_SHARED:
1792                 if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
1793                         revlock = LK_UPGRADE;
1794                 else
1795                         revlock = LK_RELEASE;
1796                 break;
1797         case LK_EXCLUSIVE:
1798         case LK_UPGRADE:
1799                 revlock = LK_RELEASE;
1800                 break;
1801         case LK_DOWNGRADE:
1802                 revlock = LK_UPGRADE;
1803                 break;
1804         default:
1805                 break;
1806         }
1807
1808         return (revlock);
1809 }
1810
1811 /*
1812  * The state of an acquired lock is adjusted similarly to
1813  * the time of error generating. 
1814  * flags: LK_RELEASE or LK_UPGRADE
1815  */
1816 static void
1817 unionfs_revlock(struct vnode *vp, int flags)
1818 {
1819         if (flags & LK_RELEASE)
1820                 VOP_UNLOCK(vp, flags);
1821         else {
1822                 /* UPGRADE */
1823                 if (vn_lock(vp, flags) != 0)
1824                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1825         }
1826 }
1827
1828 static int
1829 unionfs_lock(struct vop_lock1_args *ap)
1830 {
1831         int             error;
1832         int             flags;
1833         int             revlock;
1834         int             interlock;
1835         int             uhold;
1836         struct mount   *mp;
1837         struct unionfs_mount *ump;
1838         struct unionfs_node *unp;
1839         struct vnode   *vp;
1840         struct vnode   *uvp;
1841         struct vnode   *lvp;
1842
1843         KASSERT_UNIONFS_VNODE(ap->a_vp);
1844
1845         error = 0;
1846         interlock = 1;
1847         uhold = 0;
1848         flags = ap->a_flags;
1849         vp = ap->a_vp;
1850
1851         if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
1852                 return (VOP_UNLOCK(vp, flags | LK_RELEASE));
1853
1854         if ((flags & LK_INTERLOCK) == 0)
1855                 VI_LOCK(vp);
1856
1857         mp = vp->v_mount;
1858         if (mp == NULL)
1859                 goto unionfs_lock_null_vnode;
1860
1861         ump = MOUNTTOUNIONFSMOUNT(mp);
1862         unp = VTOUNIONFS(vp);
1863         if (ump == NULL || unp == NULL)
1864                 goto unionfs_lock_null_vnode;
1865         lvp = unp->un_lowervp;
1866         uvp = unp->un_uppervp;
1867
1868         if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0)
1869                 panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK);
1870
1871         if ((vp->v_iflag & VI_OWEINACT) != 0)
1872                 flags |= LK_NOWAIT;
1873
1874         /*
1875          * Sometimes, lower or upper is already exclusive locked.
1876          * (ex. vfs_domount: mounted vnode is already locked.)
1877          */
1878         if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
1879             vp == ump->um_rootvp)
1880                 flags |= LK_CANRECURSE;
1881
1882         if (lvp != NULLVP) {
1883                 if (uvp != NULLVP && flags & LK_UPGRADE) {
1884                         /* Share Lock is once released and a deadlock is avoided.  */
1885                         VI_LOCK_FLAGS(uvp, MTX_DUPOK);
1886                         vholdl(uvp);
1887                         uhold = 1;
1888                         VI_UNLOCK(vp);
1889                         VOP_UNLOCK(uvp, LK_RELEASE | LK_INTERLOCK);
1890                         VI_LOCK(vp);
1891                         unp = VTOUNIONFS(vp);
1892                         if (unp == NULL) {
1893                                 /* vnode is released. */
1894                                 VI_UNLOCK(vp);
1895                                 VOP_UNLOCK(lvp, LK_RELEASE);
1896                                 vdrop(uvp);
1897                                 return (EBUSY);
1898                         }
1899                 }
1900                 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
1901                 flags |= LK_INTERLOCK;
1902                 vholdl(lvp);
1903
1904                 VI_UNLOCK(vp);
1905                 ap->a_flags &= ~LK_INTERLOCK;
1906
1907                 error = VOP_LOCK(lvp, flags);
1908
1909                 VI_LOCK(vp);
1910                 unp = VTOUNIONFS(vp);
1911                 if (unp == NULL) {
1912                         /* vnode is released. */
1913                         VI_UNLOCK(vp);
1914                         if (error == 0)
1915                                 VOP_UNLOCK(lvp, LK_RELEASE);
1916                         vdrop(lvp);
1917                         if (uhold != 0)
1918                                 vdrop(uvp);
1919                         return (vop_stdlock(ap));
1920                 }
1921         }
1922
1923         if (error == 0 && uvp != NULLVP) {
1924                 if (uhold && flags & LK_UPGRADE) {
1925                         flags &= ~LK_TYPE_MASK;
1926                         flags |= LK_EXCLUSIVE;
1927                 }
1928                 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
1929                 flags |= LK_INTERLOCK;
1930                 if (uhold == 0) {
1931                         vholdl(uvp);
1932                         uhold = 1;
1933                 }
1934
1935                 VI_UNLOCK(vp);
1936                 ap->a_flags &= ~LK_INTERLOCK;
1937
1938                 error = VOP_LOCK(uvp, flags);
1939
1940                 VI_LOCK(vp);
1941                 unp = VTOUNIONFS(vp);
1942                 if (unp == NULL) {
1943                         /* vnode is released. */
1944                         VI_UNLOCK(vp);
1945                         if (error == 0)
1946                                 VOP_UNLOCK(uvp, LK_RELEASE);
1947                         vdrop(uvp);
1948                         if (lvp != NULLVP) {
1949                                 VOP_UNLOCK(lvp, LK_RELEASE);
1950                                 vdrop(lvp);
1951                         }
1952                         return (vop_stdlock(ap));
1953                 }
1954                 if (error != 0 && lvp != NULLVP) {
1955                         /* rollback */
1956                         VI_UNLOCK(vp);
1957                         unionfs_revlock(lvp, revlock);
1958                         interlock = 0;
1959                 }
1960         }
1961
1962         if (interlock)
1963                 VI_UNLOCK(vp);
1964         if (lvp != NULLVP)
1965                 vdrop(lvp);
1966         if (uhold != 0)
1967                 vdrop(uvp);
1968
1969         return (error);
1970
1971 unionfs_lock_null_vnode:
1972         ap->a_flags |= LK_INTERLOCK;
1973         return (vop_stdlock(ap));
1974 }
1975
1976 static int
1977 unionfs_unlock(struct vop_unlock_args *ap)
1978 {
1979         int             error;
1980         int             flags;
1981         int             mtxlkflag;
1982         int             uhold;
1983         struct vnode   *vp;
1984         struct vnode   *lvp;
1985         struct vnode   *uvp;
1986         struct unionfs_node *unp;
1987
1988         KASSERT_UNIONFS_VNODE(ap->a_vp);
1989
1990         error = 0;
1991         mtxlkflag = 0;
1992         uhold = 0;
1993         flags = ap->a_flags | LK_RELEASE;
1994         vp = ap->a_vp;
1995
1996         if ((flags & LK_INTERLOCK) != 0)
1997                 mtxlkflag = 1;
1998         else if (mtx_owned(VI_MTX(vp)) == 0) {
1999                 VI_LOCK(vp);
2000                 mtxlkflag = 2;
2001         }
2002
2003         unp = VTOUNIONFS(vp);
2004         if (unp == NULL)
2005                 goto unionfs_unlock_null_vnode;
2006         lvp = unp->un_lowervp;
2007         uvp = unp->un_uppervp;
2008
2009         if (lvp != NULLVP) {
2010                 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
2011                 flags |= LK_INTERLOCK;
2012                 vholdl(lvp);
2013
2014                 VI_UNLOCK(vp);
2015                 ap->a_flags &= ~LK_INTERLOCK;
2016
2017                 error = VOP_UNLOCK(lvp, flags);
2018
2019                 VI_LOCK(vp);
2020         }
2021
2022         if (error == 0 && uvp != NULLVP) {
2023                 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
2024                 flags |= LK_INTERLOCK;
2025                 vholdl(uvp);
2026                 uhold = 1;
2027
2028                 VI_UNLOCK(vp);
2029                 ap->a_flags &= ~LK_INTERLOCK;
2030
2031                 error = VOP_UNLOCK(uvp, flags);
2032
2033                 VI_LOCK(vp);
2034         }
2035
2036         VI_UNLOCK(vp);
2037         if (lvp != NULLVP)
2038                 vdrop(lvp);
2039         if (uhold != 0)
2040                 vdrop(uvp);
2041         if (mtxlkflag == 0)
2042                 VI_LOCK(vp);
2043
2044         return error;
2045
2046 unionfs_unlock_null_vnode:
2047         if (mtxlkflag == 2)
2048                 VI_UNLOCK(vp);
2049         return (vop_stdunlock(ap));
2050 }
2051
2052 static int
2053 unionfs_pathconf(struct vop_pathconf_args *ap)
2054 {
2055         struct unionfs_node *unp;
2056         struct vnode   *vp;
2057
2058         KASSERT_UNIONFS_VNODE(ap->a_vp);
2059
2060         unp = VTOUNIONFS(ap->a_vp);
2061         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2062
2063         return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2064 }
2065
2066 static int
2067 unionfs_advlock(struct vop_advlock_args *ap)
2068 {
2069         int error;
2070         struct unionfs_node *unp;
2071         struct unionfs_node_status *unsp;
2072         struct vnode   *vp;
2073         struct vnode   *uvp;
2074         struct thread  *td;
2075
2076         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2077
2078         KASSERT_UNIONFS_VNODE(ap->a_vp);
2079
2080         vp = ap->a_vp;
2081         td = curthread;
2082
2083         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2084
2085         unp = VTOUNIONFS(ap->a_vp);
2086         uvp = unp->un_uppervp;
2087
2088         if (uvp == NULLVP) {
2089                 error = unionfs_copyfile(unp, 1, td->td_ucred, td);
2090                 if (error != 0)
2091                         goto unionfs_advlock_abort;
2092                 uvp = unp->un_uppervp;
2093
2094                 unionfs_get_node_status(unp, td, &unsp);
2095                 if (unsp->uns_lower_opencnt > 0) {
2096                         /* try reopen the vnode */
2097                         error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2098                                 td->td_ucred, td, NULL);
2099                         if (error)
2100                                 goto unionfs_advlock_abort;
2101                         unsp->uns_upper_opencnt++;
2102                         VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td);
2103                         unsp->uns_lower_opencnt--;
2104                 } else
2105                         unionfs_tryrem_node_status(unp, unsp);
2106         }
2107
2108         VOP_UNLOCK(vp, LK_RELEASE);
2109
2110         error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2111
2112         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2113
2114         return error;
2115
2116 unionfs_advlock_abort:
2117         VOP_UNLOCK(vp, LK_RELEASE);
2118
2119         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2120
2121         return error;
2122 }
2123
2124 static int
2125 unionfs_strategy(struct vop_strategy_args *ap)
2126 {
2127         struct unionfs_node *unp;
2128         struct vnode   *vp;
2129
2130         KASSERT_UNIONFS_VNODE(ap->a_vp);
2131
2132         unp = VTOUNIONFS(ap->a_vp);
2133         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2134
2135 #ifdef DIAGNOSTIC
2136         if (vp == NULLVP)
2137                 panic("unionfs_strategy: nullvp");
2138
2139         if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2140                 panic("unionfs_strategy: writing to lowervp");
2141 #endif
2142
2143         return (VOP_STRATEGY(vp, ap->a_bp));
2144 }
2145
2146 static int
2147 unionfs_getacl(struct vop_getacl_args *ap)
2148 {
2149         int             error;
2150         struct unionfs_node *unp;
2151         struct vnode   *vp;
2152
2153         KASSERT_UNIONFS_VNODE(ap->a_vp);
2154
2155         unp = VTOUNIONFS(ap->a_vp);
2156         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2157
2158         UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2159
2160         error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2161
2162         UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2163
2164         return (error);
2165 }
2166
2167 static int
2168 unionfs_setacl(struct vop_setacl_args *ap)
2169 {
2170         int             error;
2171         struct unionfs_node *unp;
2172         struct vnode   *uvp;
2173         struct vnode   *lvp;
2174         struct thread  *td;
2175
2176         UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2177
2178         KASSERT_UNIONFS_VNODE(ap->a_vp);
2179
2180         error = EROFS;
2181         unp = VTOUNIONFS(ap->a_vp);
2182         uvp = unp->un_uppervp;
2183         lvp = unp->un_lowervp;
2184         td = ap->a_td;
2185
2186         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2187                 return (EROFS);
2188
2189         if (uvp == NULLVP && lvp->v_type == VREG) {
2190                 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2191                         return (error);
2192                 uvp = unp->un_uppervp;
2193         }
2194
2195         if (uvp != NULLVP)
2196                 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2197
2198         UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2199
2200         return (error);
2201 }
2202
2203 static int
2204 unionfs_aclcheck(struct vop_aclcheck_args *ap)
2205 {
2206         int             error;
2207         struct unionfs_node *unp;
2208         struct vnode   *vp;
2209
2210         UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2211
2212         KASSERT_UNIONFS_VNODE(ap->a_vp);
2213
2214         unp = VTOUNIONFS(ap->a_vp);
2215         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2216
2217         error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2218
2219         UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2220
2221         return (error);
2222 }
2223
2224 static int
2225 unionfs_openextattr(struct vop_openextattr_args *ap)
2226 {
2227         int             error;
2228         struct unionfs_node *unp;
2229         struct vnode   *vp;
2230         struct vnode   *tvp;
2231
2232         KASSERT_UNIONFS_VNODE(ap->a_vp);
2233
2234         vp = ap->a_vp;
2235         unp = VTOUNIONFS(vp);
2236         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2237
2238         if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2239             (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2240                 return (EBUSY);
2241
2242         error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2243
2244         if (error == 0) {
2245                 if (vn_lock(vp, LK_UPGRADE) != 0)
2246                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2247                 if (tvp == unp->un_uppervp)
2248                         unp->un_flag |= UNIONFS_OPENEXTU;
2249                 else
2250                         unp->un_flag |= UNIONFS_OPENEXTL;
2251                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2252         }
2253
2254         return (error);
2255 }
2256
2257 static int
2258 unionfs_closeextattr(struct vop_closeextattr_args *ap)
2259 {
2260         int             error;
2261         struct unionfs_node *unp;
2262         struct vnode   *vp;
2263         struct vnode   *tvp;
2264
2265         KASSERT_UNIONFS_VNODE(ap->a_vp);
2266
2267         vp = ap->a_vp;
2268         unp = VTOUNIONFS(vp);
2269         tvp = NULLVP;
2270
2271         if (unp->un_flag & UNIONFS_OPENEXTU)
2272                 tvp = unp->un_uppervp;
2273         else if (unp->un_flag & UNIONFS_OPENEXTL)
2274                 tvp = unp->un_lowervp;
2275
2276         if (tvp == NULLVP)
2277                 return (EOPNOTSUPP);
2278
2279         error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2280
2281         if (error == 0) {
2282                 if (vn_lock(vp, LK_UPGRADE) != 0)
2283                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2284                 if (tvp == unp->un_uppervp)
2285                         unp->un_flag &= ~UNIONFS_OPENEXTU;
2286                 else
2287                         unp->un_flag &= ~UNIONFS_OPENEXTL;
2288                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2289         }
2290
2291         return (error);
2292 }
2293
2294 static int
2295 unionfs_getextattr(struct vop_getextattr_args *ap)
2296 {
2297         struct unionfs_node *unp;
2298         struct vnode   *vp;
2299
2300         KASSERT_UNIONFS_VNODE(ap->a_vp);
2301
2302         unp = VTOUNIONFS(ap->a_vp);
2303         vp = NULLVP;
2304
2305         if (unp->un_flag & UNIONFS_OPENEXTU)
2306                 vp = unp->un_uppervp;
2307         else if (unp->un_flag & UNIONFS_OPENEXTL)
2308                 vp = unp->un_lowervp;
2309
2310         if (vp == NULLVP)
2311                 return (EOPNOTSUPP);
2312
2313         return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2314             ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2315 }
2316
2317 static int
2318 unionfs_setextattr(struct vop_setextattr_args *ap)
2319 {
2320         int             error;
2321         struct unionfs_node *unp;
2322         struct vnode   *uvp;
2323         struct vnode   *lvp;
2324         struct vnode   *ovp;
2325         struct ucred   *cred;
2326         struct thread  *td;
2327
2328         KASSERT_UNIONFS_VNODE(ap->a_vp);
2329
2330         error = EROFS;
2331         unp = VTOUNIONFS(ap->a_vp);
2332         uvp = unp->un_uppervp;
2333         lvp = unp->un_lowervp;
2334         ovp = NULLVP;
2335         cred = ap->a_cred;
2336         td = ap->a_td;
2337
2338         UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag);
2339
2340         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2341                 return (EROFS);
2342
2343         if (unp->un_flag & UNIONFS_OPENEXTU)
2344                 ovp = unp->un_uppervp;
2345         else if (unp->un_flag & UNIONFS_OPENEXTL)
2346                 ovp = unp->un_lowervp;
2347
2348         if (ovp == NULLVP)
2349                 return (EOPNOTSUPP);
2350
2351         if (ovp == lvp && lvp->v_type == VREG) {
2352                 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2353                 if (uvp == NULLVP &&
2354                     (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2355 unionfs_setextattr_reopen:
2356                         if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2357                             VOP_OPENEXTATTR(lvp, cred, td)) {
2358 #ifdef DIAGNOSTIC
2359                                 panic("unionfs: VOP_OPENEXTATTR failed");
2360 #endif
2361                                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2362                         }
2363                         goto unionfs_setextattr_abort;
2364                 }
2365                 uvp = unp->un_uppervp;
2366                 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2367                         goto unionfs_setextattr_reopen;
2368                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2369                 unp->un_flag |= UNIONFS_OPENEXTU;
2370                 ovp = uvp;
2371         }
2372
2373         if (ovp == uvp)
2374                 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2375                     ap->a_uio, cred, td);
2376
2377 unionfs_setextattr_abort:
2378         UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2379
2380         return (error);
2381 }
2382
2383 static int
2384 unionfs_listextattr(struct vop_listextattr_args *ap)
2385 {
2386         struct unionfs_node *unp;
2387         struct vnode   *vp;
2388
2389         KASSERT_UNIONFS_VNODE(ap->a_vp);
2390
2391         unp = VTOUNIONFS(ap->a_vp);
2392         vp = NULLVP;
2393
2394         if (unp->un_flag & UNIONFS_OPENEXTU)
2395                 vp = unp->un_uppervp;
2396         else if (unp->un_flag & UNIONFS_OPENEXTL)
2397                 vp = unp->un_lowervp;
2398
2399         if (vp == NULLVP)
2400                 return (EOPNOTSUPP);
2401
2402         return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2403             ap->a_size, ap->a_cred, ap->a_td));
2404 }
2405
2406 static int
2407 unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2408 {
2409         int             error;
2410         struct unionfs_node *unp;
2411         struct vnode   *uvp;
2412         struct vnode   *lvp;
2413         struct vnode   *ovp;
2414         struct ucred   *cred;
2415         struct thread  *td;
2416
2417         KASSERT_UNIONFS_VNODE(ap->a_vp);
2418
2419         error = EROFS;
2420         unp = VTOUNIONFS(ap->a_vp);
2421         uvp = unp->un_uppervp;
2422         lvp = unp->un_lowervp;
2423         ovp = NULLVP;
2424         cred = ap->a_cred;
2425         td = ap->a_td;
2426
2427         UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag);
2428
2429         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2430                 return (EROFS);
2431
2432         if (unp->un_flag & UNIONFS_OPENEXTU)
2433                 ovp = unp->un_uppervp;
2434         else if (unp->un_flag & UNIONFS_OPENEXTL)
2435                 ovp = unp->un_lowervp;
2436
2437         if (ovp == NULLVP)
2438                 return (EOPNOTSUPP);
2439
2440         if (ovp == lvp && lvp->v_type == VREG) {
2441                 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2442                 if (uvp == NULLVP &&
2443                     (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2444 unionfs_deleteextattr_reopen:
2445                         if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2446                             VOP_OPENEXTATTR(lvp, cred, td)) {
2447 #ifdef DIAGNOSTIC
2448                                 panic("unionfs: VOP_OPENEXTATTR failed");
2449 #endif
2450                                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2451                         }
2452                         goto unionfs_deleteextattr_abort;
2453                 }
2454                 uvp = unp->un_uppervp;
2455                 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2456                         goto unionfs_deleteextattr_reopen;
2457                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2458                 unp->un_flag |= UNIONFS_OPENEXTU;
2459                 ovp = uvp;
2460         }
2461
2462         if (ovp == uvp)
2463                 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2464                     ap->a_cred, ap->a_td);
2465
2466 unionfs_deleteextattr_abort:
2467         UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2468
2469         return (error);
2470 }
2471
2472 static int
2473 unionfs_setlabel(struct vop_setlabel_args *ap)
2474 {
2475         int             error;
2476         struct unionfs_node *unp;
2477         struct vnode   *uvp;
2478         struct vnode   *lvp;
2479         struct thread  *td;
2480
2481         UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2482
2483         KASSERT_UNIONFS_VNODE(ap->a_vp);
2484
2485         error = EROFS;
2486         unp = VTOUNIONFS(ap->a_vp);
2487         uvp = unp->un_uppervp;
2488         lvp = unp->un_lowervp;
2489         td = ap->a_td;
2490
2491         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2492                 return (EROFS);
2493
2494         if (uvp == NULLVP && lvp->v_type == VREG) {
2495                 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2496                         return (error);
2497                 uvp = unp->un_uppervp;
2498         }
2499
2500         if (uvp != NULLVP)
2501                 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2502
2503         UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2504
2505         return (error);
2506 }
2507
2508 static int
2509 unionfs_vptofh(struct vop_vptofh_args *ap)
2510 {
2511         return (EOPNOTSUPP);
2512 }
2513
2514 struct vop_vector unionfs_vnodeops = {
2515         .vop_default =          &default_vnodeops,
2516
2517         .vop_access =           unionfs_access,
2518         .vop_aclcheck =         unionfs_aclcheck,
2519         .vop_advlock =          unionfs_advlock,
2520         .vop_bmap =             VOP_EOPNOTSUPP,
2521         .vop_cachedlookup =     unionfs_lookup,
2522         .vop_close =            unionfs_close,
2523         .vop_closeextattr =     unionfs_closeextattr,
2524         .vop_create =           unionfs_create,
2525         .vop_deleteextattr =    unionfs_deleteextattr,
2526         .vop_fsync =            unionfs_fsync,
2527         .vop_getacl =           unionfs_getacl,
2528         .vop_getattr =          unionfs_getattr,
2529         .vop_getextattr =       unionfs_getextattr,
2530         .vop_getwritemount =    unionfs_getwritemount,
2531         .vop_inactive =         unionfs_inactive,
2532         .vop_islocked =         unionfs_islocked,
2533         .vop_ioctl =            unionfs_ioctl,
2534         .vop_link =             unionfs_link,
2535         .vop_listextattr =      unionfs_listextattr,
2536         .vop_lock1 =            unionfs_lock,
2537         .vop_lookup =           vfs_cache_lookup,
2538         .vop_mkdir =            unionfs_mkdir,
2539         .vop_mknod =            unionfs_mknod,
2540         .vop_open =             unionfs_open,
2541         .vop_openextattr =      unionfs_openextattr,
2542         .vop_pathconf =         unionfs_pathconf,
2543         .vop_poll =             unionfs_poll,
2544         .vop_print =            unionfs_print,
2545         .vop_read =             unionfs_read,
2546         .vop_readdir =          unionfs_readdir,
2547         .vop_readlink =         unionfs_readlink,
2548         .vop_reclaim =          unionfs_reclaim,
2549         .vop_remove =           unionfs_remove,
2550         .vop_rename =           unionfs_rename,
2551         .vop_rmdir =            unionfs_rmdir,
2552         .vop_setacl =           unionfs_setacl,
2553         .vop_setattr =          unionfs_setattr,
2554         .vop_setextattr =       unionfs_setextattr,
2555         .vop_setlabel =         unionfs_setlabel,
2556         .vop_strategy =         unionfs_strategy,
2557         .vop_symlink =          unionfs_symlink,
2558         .vop_unlock =           unionfs_unlock,
2559         .vop_whiteout =         unionfs_whiteout,
2560         .vop_write =            unionfs_write,
2561         .vop_vptofh =           unionfs_vptofh,
2562 };