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