]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/unionfs/union_vnops.c
vfs: remove the always-curthread td argument from VOP_RECLAIM
[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);
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);
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);
152                         vrele(vp);
153
154                         VOP_UNLOCK(dvp);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1286         if (tdvp != rtdvp)
1287                 vrele(tdvp);
1288         if (ltvp != NULLVP)
1289                 VOP_UNLOCK(ltvp);
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);
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);
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_holdcnt == 0)
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, curthread);
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_FLAGS(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_FLAGS(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                         vholdnz(uvp);
1886                         uhold = 1;
1887                         VOP_UNLOCK(uvp);
1888                         unp = VTOUNIONFS(vp);
1889                         if (unp == NULL) {
1890                                 /* vnode is released. */
1891                                 VI_UNLOCK(vp);
1892                                 VOP_UNLOCK(lvp);
1893                                 vdrop(uvp);
1894                                 return (EBUSY);
1895                         }
1896                 }
1897                 VI_LOCK_FLAGS(lvp, MTX_DUPOK);
1898                 flags |= LK_INTERLOCK;
1899                 vholdl(lvp);
1900
1901                 VI_UNLOCK(vp);
1902                 ap->a_flags &= ~LK_INTERLOCK;
1903
1904                 error = VOP_LOCK(lvp, flags);
1905
1906                 VI_LOCK(vp);
1907                 unp = VTOUNIONFS(vp);
1908                 if (unp == NULL) {
1909                         /* vnode is released. */
1910                         VI_UNLOCK(vp);
1911                         if (error == 0)
1912                                 VOP_UNLOCK(lvp);
1913                         vdrop(lvp);
1914                         if (uhold != 0)
1915                                 vdrop(uvp);
1916                         return (vop_stdlock(ap));
1917                 }
1918         }
1919
1920         if (error == 0 && uvp != NULLVP) {
1921                 if (uhold && flags & LK_UPGRADE) {
1922                         flags &= ~LK_TYPE_MASK;
1923                         flags |= LK_EXCLUSIVE;
1924                 }
1925                 VI_LOCK_FLAGS(uvp, MTX_DUPOK);
1926                 flags |= LK_INTERLOCK;
1927                 if (uhold == 0) {
1928                         vholdl(uvp);
1929                         uhold = 1;
1930                 }
1931
1932                 VI_UNLOCK(vp);
1933                 ap->a_flags &= ~LK_INTERLOCK;
1934
1935                 error = VOP_LOCK(uvp, flags);
1936
1937                 VI_LOCK(vp);
1938                 unp = VTOUNIONFS(vp);
1939                 if (unp == NULL) {
1940                         /* vnode is released. */
1941                         VI_UNLOCK(vp);
1942                         if (error == 0)
1943                                 VOP_UNLOCK(uvp);
1944                         vdrop(uvp);
1945                         if (lvp != NULLVP) {
1946                                 VOP_UNLOCK(lvp);
1947                                 vdrop(lvp);
1948                         }
1949                         return (vop_stdlock(ap));
1950                 }
1951                 if (error != 0 && lvp != NULLVP) {
1952                         /* rollback */
1953                         VI_UNLOCK(vp);
1954                         unionfs_revlock(lvp, revlock);
1955                         interlock = 0;
1956                 }
1957         }
1958
1959         if (interlock)
1960                 VI_UNLOCK(vp);
1961         if (lvp != NULLVP)
1962                 vdrop(lvp);
1963         if (uhold != 0)
1964                 vdrop(uvp);
1965
1966         return (error);
1967
1968 unionfs_lock_null_vnode:
1969         ap->a_flags |= LK_INTERLOCK;
1970         return (vop_stdlock(ap));
1971 }
1972
1973 static int
1974 unionfs_unlock(struct vop_unlock_args *ap)
1975 {
1976         int             error;
1977         int             uhold;
1978         struct vnode   *vp;
1979         struct vnode   *lvp;
1980         struct vnode   *uvp;
1981         struct unionfs_node *unp;
1982
1983         KASSERT_UNIONFS_VNODE(ap->a_vp);
1984
1985         error = 0;
1986         uhold = 0;
1987         vp = ap->a_vp;
1988
1989         unp = VTOUNIONFS(vp);
1990         if (unp == NULL)
1991                 goto unionfs_unlock_null_vnode;
1992         lvp = unp->un_lowervp;
1993         uvp = unp->un_uppervp;
1994
1995         if (lvp != NULLVP) {
1996                 vholdnz(lvp);
1997                 error = VOP_UNLOCK(lvp);
1998         }
1999
2000         if (error == 0 && uvp != NULLVP) {
2001                 vholdnz(uvp);
2002                 uhold = 1;
2003                 error = VOP_UNLOCK(uvp);
2004         }
2005
2006         if (lvp != NULLVP)
2007                 vdrop(lvp);
2008         if (uhold != 0)
2009                 vdrop(uvp);
2010
2011         return error;
2012
2013 unionfs_unlock_null_vnode:
2014         return (vop_stdunlock(ap));
2015 }
2016
2017 static int
2018 unionfs_pathconf(struct vop_pathconf_args *ap)
2019 {
2020         struct unionfs_node *unp;
2021         struct vnode   *vp;
2022
2023         KASSERT_UNIONFS_VNODE(ap->a_vp);
2024
2025         unp = VTOUNIONFS(ap->a_vp);
2026         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2027
2028         return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2029 }
2030
2031 static int
2032 unionfs_advlock(struct vop_advlock_args *ap)
2033 {
2034         int error;
2035         struct unionfs_node *unp;
2036         struct unionfs_node_status *unsp;
2037         struct vnode   *vp;
2038         struct vnode   *uvp;
2039         struct thread  *td;
2040
2041         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2042
2043         KASSERT_UNIONFS_VNODE(ap->a_vp);
2044
2045         vp = ap->a_vp;
2046         td = curthread;
2047
2048         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2049
2050         unp = VTOUNIONFS(ap->a_vp);
2051         uvp = unp->un_uppervp;
2052
2053         if (uvp == NULLVP) {
2054                 error = unionfs_copyfile(unp, 1, td->td_ucred, td);
2055                 if (error != 0)
2056                         goto unionfs_advlock_abort;
2057                 uvp = unp->un_uppervp;
2058
2059                 unionfs_get_node_status(unp, td, &unsp);
2060                 if (unsp->uns_lower_opencnt > 0) {
2061                         /* try reopen the vnode */
2062                         error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2063                                 td->td_ucred, td, NULL);
2064                         if (error)
2065                                 goto unionfs_advlock_abort;
2066                         unsp->uns_upper_opencnt++;
2067                         VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, td->td_ucred, td);
2068                         unsp->uns_lower_opencnt--;
2069                 } else
2070                         unionfs_tryrem_node_status(unp, unsp);
2071         }
2072
2073         VOP_UNLOCK(vp);
2074
2075         error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2076
2077         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2078
2079         return error;
2080
2081 unionfs_advlock_abort:
2082         VOP_UNLOCK(vp);
2083
2084         UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2085
2086         return error;
2087 }
2088
2089 static int
2090 unionfs_strategy(struct vop_strategy_args *ap)
2091 {
2092         struct unionfs_node *unp;
2093         struct vnode   *vp;
2094
2095         KASSERT_UNIONFS_VNODE(ap->a_vp);
2096
2097         unp = VTOUNIONFS(ap->a_vp);
2098         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2099
2100 #ifdef DIAGNOSTIC
2101         if (vp == NULLVP)
2102                 panic("unionfs_strategy: nullvp");
2103
2104         if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2105                 panic("unionfs_strategy: writing to lowervp");
2106 #endif
2107
2108         return (VOP_STRATEGY(vp, ap->a_bp));
2109 }
2110
2111 static int
2112 unionfs_getacl(struct vop_getacl_args *ap)
2113 {
2114         int             error;
2115         struct unionfs_node *unp;
2116         struct vnode   *vp;
2117
2118         KASSERT_UNIONFS_VNODE(ap->a_vp);
2119
2120         unp = VTOUNIONFS(ap->a_vp);
2121         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2122
2123         UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2124
2125         error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2126
2127         UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2128
2129         return (error);
2130 }
2131
2132 static int
2133 unionfs_setacl(struct vop_setacl_args *ap)
2134 {
2135         int             error;
2136         struct unionfs_node *unp;
2137         struct vnode   *uvp;
2138         struct vnode   *lvp;
2139         struct thread  *td;
2140
2141         UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2142
2143         KASSERT_UNIONFS_VNODE(ap->a_vp);
2144
2145         error = EROFS;
2146         unp = VTOUNIONFS(ap->a_vp);
2147         uvp = unp->un_uppervp;
2148         lvp = unp->un_lowervp;
2149         td = ap->a_td;
2150
2151         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2152                 return (EROFS);
2153
2154         if (uvp == NULLVP && lvp->v_type == VREG) {
2155                 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2156                         return (error);
2157                 uvp = unp->un_uppervp;
2158         }
2159
2160         if (uvp != NULLVP)
2161                 error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2162
2163         UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2164
2165         return (error);
2166 }
2167
2168 static int
2169 unionfs_aclcheck(struct vop_aclcheck_args *ap)
2170 {
2171         int             error;
2172         struct unionfs_node *unp;
2173         struct vnode   *vp;
2174
2175         UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2176
2177         KASSERT_UNIONFS_VNODE(ap->a_vp);
2178
2179         unp = VTOUNIONFS(ap->a_vp);
2180         vp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2181
2182         error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2183
2184         UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2185
2186         return (error);
2187 }
2188
2189 static int
2190 unionfs_openextattr(struct vop_openextattr_args *ap)
2191 {
2192         int             error;
2193         struct unionfs_node *unp;
2194         struct vnode   *vp;
2195         struct vnode   *tvp;
2196
2197         KASSERT_UNIONFS_VNODE(ap->a_vp);
2198
2199         vp = ap->a_vp;
2200         unp = VTOUNIONFS(vp);
2201         tvp = (unp->un_uppervp != NULLVP ? unp->un_uppervp : unp->un_lowervp);
2202
2203         if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2204             (tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2205                 return (EBUSY);
2206
2207         error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2208
2209         if (error == 0) {
2210                 if (vn_lock(vp, LK_UPGRADE) != 0)
2211                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2212                 if (tvp == unp->un_uppervp)
2213                         unp->un_flag |= UNIONFS_OPENEXTU;
2214                 else
2215                         unp->un_flag |= UNIONFS_OPENEXTL;
2216                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2217         }
2218
2219         return (error);
2220 }
2221
2222 static int
2223 unionfs_closeextattr(struct vop_closeextattr_args *ap)
2224 {
2225         int             error;
2226         struct unionfs_node *unp;
2227         struct vnode   *vp;
2228         struct vnode   *tvp;
2229
2230         KASSERT_UNIONFS_VNODE(ap->a_vp);
2231
2232         vp = ap->a_vp;
2233         unp = VTOUNIONFS(vp);
2234         tvp = NULLVP;
2235
2236         if (unp->un_flag & UNIONFS_OPENEXTU)
2237                 tvp = unp->un_uppervp;
2238         else if (unp->un_flag & UNIONFS_OPENEXTL)
2239                 tvp = unp->un_lowervp;
2240
2241         if (tvp == NULLVP)
2242                 return (EOPNOTSUPP);
2243
2244         error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2245
2246         if (error == 0) {
2247                 if (vn_lock(vp, LK_UPGRADE) != 0)
2248                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2249                 if (tvp == unp->un_uppervp)
2250                         unp->un_flag &= ~UNIONFS_OPENEXTU;
2251                 else
2252                         unp->un_flag &= ~UNIONFS_OPENEXTL;
2253                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2254         }
2255
2256         return (error);
2257 }
2258
2259 static int
2260 unionfs_getextattr(struct vop_getextattr_args *ap)
2261 {
2262         struct unionfs_node *unp;
2263         struct vnode   *vp;
2264
2265         KASSERT_UNIONFS_VNODE(ap->a_vp);
2266
2267         unp = VTOUNIONFS(ap->a_vp);
2268         vp = NULLVP;
2269
2270         if (unp->un_flag & UNIONFS_OPENEXTU)
2271                 vp = unp->un_uppervp;
2272         else if (unp->un_flag & UNIONFS_OPENEXTL)
2273                 vp = unp->un_lowervp;
2274
2275         if (vp == NULLVP)
2276                 return (EOPNOTSUPP);
2277
2278         return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2279             ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2280 }
2281
2282 static int
2283 unionfs_setextattr(struct vop_setextattr_args *ap)
2284 {
2285         int             error;
2286         struct unionfs_node *unp;
2287         struct vnode   *uvp;
2288         struct vnode   *lvp;
2289         struct vnode   *ovp;
2290         struct ucred   *cred;
2291         struct thread  *td;
2292
2293         KASSERT_UNIONFS_VNODE(ap->a_vp);
2294
2295         error = EROFS;
2296         unp = VTOUNIONFS(ap->a_vp);
2297         uvp = unp->un_uppervp;
2298         lvp = unp->un_lowervp;
2299         ovp = NULLVP;
2300         cred = ap->a_cred;
2301         td = ap->a_td;
2302
2303         UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n", unp->un_flag);
2304
2305         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2306                 return (EROFS);
2307
2308         if (unp->un_flag & UNIONFS_OPENEXTU)
2309                 ovp = unp->un_uppervp;
2310         else if (unp->un_flag & UNIONFS_OPENEXTL)
2311                 ovp = unp->un_lowervp;
2312
2313         if (ovp == NULLVP)
2314                 return (EOPNOTSUPP);
2315
2316         if (ovp == lvp && lvp->v_type == VREG) {
2317                 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2318                 if (uvp == NULLVP &&
2319                     (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2320 unionfs_setextattr_reopen:
2321                         if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2322                             VOP_OPENEXTATTR(lvp, cred, td)) {
2323 #ifdef DIAGNOSTIC
2324                                 panic("unionfs: VOP_OPENEXTATTR failed");
2325 #endif
2326                                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2327                         }
2328                         goto unionfs_setextattr_abort;
2329                 }
2330                 uvp = unp->un_uppervp;
2331                 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2332                         goto unionfs_setextattr_reopen;
2333                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2334                 unp->un_flag |= UNIONFS_OPENEXTU;
2335                 ovp = uvp;
2336         }
2337
2338         if (ovp == uvp)
2339                 error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2340                     ap->a_uio, cred, td);
2341
2342 unionfs_setextattr_abort:
2343         UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2344
2345         return (error);
2346 }
2347
2348 static int
2349 unionfs_listextattr(struct vop_listextattr_args *ap)
2350 {
2351         struct unionfs_node *unp;
2352         struct vnode   *vp;
2353
2354         KASSERT_UNIONFS_VNODE(ap->a_vp);
2355
2356         unp = VTOUNIONFS(ap->a_vp);
2357         vp = NULLVP;
2358
2359         if (unp->un_flag & UNIONFS_OPENEXTU)
2360                 vp = unp->un_uppervp;
2361         else if (unp->un_flag & UNIONFS_OPENEXTL)
2362                 vp = unp->un_lowervp;
2363
2364         if (vp == NULLVP)
2365                 return (EOPNOTSUPP);
2366
2367         return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2368             ap->a_size, ap->a_cred, ap->a_td));
2369 }
2370
2371 static int
2372 unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2373 {
2374         int             error;
2375         struct unionfs_node *unp;
2376         struct vnode   *uvp;
2377         struct vnode   *lvp;
2378         struct vnode   *ovp;
2379         struct ucred   *cred;
2380         struct thread  *td;
2381
2382         KASSERT_UNIONFS_VNODE(ap->a_vp);
2383
2384         error = EROFS;
2385         unp = VTOUNIONFS(ap->a_vp);
2386         uvp = unp->un_uppervp;
2387         lvp = unp->un_lowervp;
2388         ovp = NULLVP;
2389         cred = ap->a_cred;
2390         td = ap->a_td;
2391
2392         UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n", unp->un_flag);
2393
2394         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2395                 return (EROFS);
2396
2397         if (unp->un_flag & UNIONFS_OPENEXTU)
2398                 ovp = unp->un_uppervp;
2399         else if (unp->un_flag & UNIONFS_OPENEXTL)
2400                 ovp = unp->un_lowervp;
2401
2402         if (ovp == NULLVP)
2403                 return (EOPNOTSUPP);
2404
2405         if (ovp == lvp && lvp->v_type == VREG) {
2406                 VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2407                 if (uvp == NULLVP &&
2408                     (error = unionfs_copyfile(unp, 1, cred, td)) != 0) {
2409 unionfs_deleteextattr_reopen:
2410                         if ((unp->un_flag & UNIONFS_OPENEXTL) &&
2411                             VOP_OPENEXTATTR(lvp, cred, td)) {
2412 #ifdef DIAGNOSTIC
2413                                 panic("unionfs: VOP_OPENEXTATTR failed");
2414 #endif
2415                                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2416                         }
2417                         goto unionfs_deleteextattr_abort;
2418                 }
2419                 uvp = unp->un_uppervp;
2420                 if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2421                         goto unionfs_deleteextattr_reopen;
2422                 unp->un_flag &= ~UNIONFS_OPENEXTL;
2423                 unp->un_flag |= UNIONFS_OPENEXTU;
2424                 ovp = uvp;
2425         }
2426
2427         if (ovp == uvp)
2428                 error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2429                     ap->a_cred, ap->a_td);
2430
2431 unionfs_deleteextattr_abort:
2432         UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2433
2434         return (error);
2435 }
2436
2437 static int
2438 unionfs_setlabel(struct vop_setlabel_args *ap)
2439 {
2440         int             error;
2441         struct unionfs_node *unp;
2442         struct vnode   *uvp;
2443         struct vnode   *lvp;
2444         struct thread  *td;
2445
2446         UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2447
2448         KASSERT_UNIONFS_VNODE(ap->a_vp);
2449
2450         error = EROFS;
2451         unp = VTOUNIONFS(ap->a_vp);
2452         uvp = unp->un_uppervp;
2453         lvp = unp->un_lowervp;
2454         td = ap->a_td;
2455
2456         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2457                 return (EROFS);
2458
2459         if (uvp == NULLVP && lvp->v_type == VREG) {
2460                 if ((error = unionfs_copyfile(unp, 1, ap->a_cred, td)) != 0)
2461                         return (error);
2462                 uvp = unp->un_uppervp;
2463         }
2464
2465         if (uvp != NULLVP)
2466                 error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2467
2468         UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2469
2470         return (error);
2471 }
2472
2473 static int
2474 unionfs_vptofh(struct vop_vptofh_args *ap)
2475 {
2476         return (EOPNOTSUPP);
2477 }
2478
2479 static int
2480 unionfs_add_writecount(struct vop_add_writecount_args *ap)
2481 {
2482         struct vnode *tvp, *vp;
2483         struct unionfs_node *unp;
2484         int error;
2485
2486         vp = ap->a_vp;
2487         unp = VTOUNIONFS(vp);
2488         tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2489         VI_LOCK(vp);
2490         /* text refs are bypassed to lowervp */
2491         VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount"));
2492         VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp,
2493             ("wrong writecount inc %d", ap->a_inc));
2494         if (tvp != NULL)
2495                 error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
2496         else if (vp->v_writecount < 0)
2497                 error = ETXTBSY;
2498         else
2499                 error = 0;
2500         if (error == 0)
2501                 vp->v_writecount += ap->a_inc;
2502         VI_UNLOCK(vp);
2503         return (error);
2504 }
2505
2506 struct vop_vector unionfs_vnodeops = {
2507         .vop_default =          &default_vnodeops,
2508
2509         .vop_access =           unionfs_access,
2510         .vop_aclcheck =         unionfs_aclcheck,
2511         .vop_advlock =          unionfs_advlock,
2512         .vop_bmap =             VOP_EOPNOTSUPP,
2513         .vop_cachedlookup =     unionfs_lookup,
2514         .vop_close =            unionfs_close,
2515         .vop_closeextattr =     unionfs_closeextattr,
2516         .vop_create =           unionfs_create,
2517         .vop_deleteextattr =    unionfs_deleteextattr,
2518         .vop_fsync =            unionfs_fsync,
2519         .vop_getacl =           unionfs_getacl,
2520         .vop_getattr =          unionfs_getattr,
2521         .vop_getextattr =       unionfs_getextattr,
2522         .vop_getwritemount =    unionfs_getwritemount,
2523         .vop_inactive =         unionfs_inactive,
2524         .vop_need_inactive =    vop_stdneed_inactive,
2525         .vop_islocked =         unionfs_islocked,
2526         .vop_ioctl =            unionfs_ioctl,
2527         .vop_link =             unionfs_link,
2528         .vop_listextattr =      unionfs_listextattr,
2529         .vop_lock1 =            unionfs_lock,
2530         .vop_lookup =           vfs_cache_lookup,
2531         .vop_mkdir =            unionfs_mkdir,
2532         .vop_mknod =            unionfs_mknod,
2533         .vop_open =             unionfs_open,
2534         .vop_openextattr =      unionfs_openextattr,
2535         .vop_pathconf =         unionfs_pathconf,
2536         .vop_poll =             unionfs_poll,
2537         .vop_print =            unionfs_print,
2538         .vop_read =             unionfs_read,
2539         .vop_readdir =          unionfs_readdir,
2540         .vop_readlink =         unionfs_readlink,
2541         .vop_reclaim =          unionfs_reclaim,
2542         .vop_remove =           unionfs_remove,
2543         .vop_rename =           unionfs_rename,
2544         .vop_rmdir =            unionfs_rmdir,
2545         .vop_setacl =           unionfs_setacl,
2546         .vop_setattr =          unionfs_setattr,
2547         .vop_setextattr =       unionfs_setextattr,
2548         .vop_setlabel =         unionfs_setlabel,
2549         .vop_strategy =         unionfs_strategy,
2550         .vop_symlink =          unionfs_symlink,
2551         .vop_unlock =           unionfs_unlock,
2552         .vop_whiteout =         unionfs_whiteout,
2553         .vop_write =            unionfs_write,
2554         .vop_vptofh =           unionfs_vptofh,
2555         .vop_add_writecount =   unionfs_add_writecount,
2556 };
2557 VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);