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