Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/unionfs/union_vnops.c
105932 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
5
* Copyright (c) 1992, 1993, 1994, 1995
6
* The Regents of the University of California.
7
* Copyright (c) 2005, 2006, 2012 Masanori Ozawa <[email protected]>, ONGS Inc.
8
* Copyright (c) 2006, 2012 Daichi Goto <[email protected]>
9
* All rights reserved.
10
*
11
* This code is derived from software contributed to Berkeley by
12
* Jan-Simon Pendry.
13
*
14
* Redistribution and use in source and binary forms, with or without
15
* modification, are permitted provided that the following conditions
16
* are met:
17
* 1. Redistributions of source code must retain the above copyright
18
* notice, this list of conditions and the following disclaimer.
19
* 2. Redistributions in binary form must reproduce the above copyright
20
* notice, this list of conditions and the following disclaimer in the
21
* documentation and/or other materials provided with the distribution.
22
* 3. Neither the name of the University nor the names of its contributors
23
* may be used to endorse or promote products derived from this software
24
* without specific prior written permission.
25
*
26
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
* SUCH DAMAGE.
37
*
38
*/
39
40
#include <sys/param.h>
41
#include <sys/systm.h>
42
#include <sys/conf.h>
43
#include <sys/kernel.h>
44
#include <sys/lock.h>
45
#include <sys/malloc.h>
46
#include <sys/mount.h>
47
#include <sys/mutex.h>
48
#include <sys/namei.h>
49
#include <sys/sysctl.h>
50
#include <sys/vnode.h>
51
#include <sys/kdb.h>
52
#include <sys/fcntl.h>
53
#include <sys/stat.h>
54
#include <sys/dirent.h>
55
#include <sys/proc.h>
56
#include <sys/bio.h>
57
#include <sys/buf.h>
58
59
#include <fs/unionfs/union.h>
60
61
#include <machine/atomic.h>
62
63
#include <vm/vm.h>
64
#include <vm/vm_extern.h>
65
#include <vm/vm_object.h>
66
#include <vm/vnode_pager.h>
67
68
#if 0
69
#define UNIONFS_INTERNAL_DEBUG(msg, args...) printf(msg, ## args)
70
#define UNIONFS_IDBG_RENAME
71
#else
72
#define UNIONFS_INTERNAL_DEBUG(msg, args...)
73
#endif
74
75
#define KASSERT_UNIONFS_VNODE(vp) \
76
VNASSERT(((vp)->v_op == &unionfs_vnodeops), vp, \
77
("%s: non-unionfs vnode", __func__))
78
79
static bool
80
unionfs_lookup_isroot(struct componentname *cnp, struct vnode *dvp)
81
{
82
struct nameidata *ndp;
83
84
if (dvp == NULL)
85
return (false);
86
if ((dvp->v_vflag & VV_ROOT) != 0)
87
return (true);
88
ndp = vfs_lookup_nameidata(cnp);
89
if (ndp == NULL)
90
return (false);
91
return (vfs_lookup_isroot(ndp, dvp));
92
}
93
94
static int
95
unionfs_lookup(struct vop_cachedlookup_args *ap)
96
{
97
struct unionfs_node *dunp, *unp;
98
struct vnode *dvp, *udvp, *ldvp, *vp, *uvp, *lvp, *dtmpvp;
99
struct vattr va;
100
struct componentname *cnp;
101
struct thread *td;
102
uint64_t cnflags;
103
u_long nameiop;
104
int lockflag;
105
int lkflags;
106
int error, uerror, lerror;
107
108
lockflag = 0;
109
error = uerror = lerror = ENOENT;
110
cnp = ap->a_cnp;
111
nameiop = cnp->cn_nameiop;
112
cnflags = cnp->cn_flags;
113
dvp = ap->a_dvp;
114
dunp = VTOUNIONFS(dvp);
115
udvp = dunp->un_uppervp;
116
ldvp = dunp->un_lowervp;
117
vp = uvp = lvp = NULL;
118
td = curthread;
119
*(ap->a_vpp) = NULL;
120
121
UNIONFS_INTERNAL_DEBUG(
122
"unionfs_lookup: enter: nameiop=%ld, flags=%lx, path=%s\n",
123
nameiop, cnflags, cnp->cn_nameptr);
124
125
if (dvp->v_type != VDIR)
126
return (ENOTDIR);
127
128
/*
129
* If read-only and op is not LOOKUP, will return EROFS.
130
*/
131
if ((cnflags & ISLASTCN) &&
132
(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
133
LOOKUP != nameiop)
134
return (EROFS);
135
136
/*
137
* Note that a lookup is in-flight, and block if another lookup
138
* is already in-flight against dvp. This is done because we may
139
* end up dropping dvp's lock to look up a lower vnode or to create
140
* a shadow directory, opening up the possibility of parallel lookups
141
* against the same directory creating duplicate unionfs vnodes for
142
* the same file(s). Note that if this function encounters an
143
* in-progress lookup for the directory, it will block until the
144
* lookup is complete and then return ERELOOKUP to allow any
145
* existing unionfs vnode to be loaded from the VFS cache.
146
* This is really a hack; filesystems that support MNTK_LOOKUP_SHARED
147
* (which unionfs currently doesn't) seem to deal with this by using
148
* the vfs_hash_* functions to manage a per-mount vnode cache keyed
149
* by the inode number (or some roughly equivalent unique ID
150
* usually assocated with the storage medium). It may make sense
151
* for unionfs to adopt something similar as a replacement for its
152
* current half-baked directory-only cache implementation, particularly
153
* if we want to support MNTK_LOOKUP_SHARED here.
154
*/
155
error = unionfs_set_in_progress_flag(dvp, UNIONFS_LOOKUP_IN_PROGRESS);
156
if (error != 0)
157
return (error);
158
/*
159
* lookup dotdot
160
*/
161
if (cnflags & ISDOTDOT) {
162
if (LOOKUP != nameiop && udvp == NULL) {
163
error = EROFS;
164
goto unionfs_lookup_return;
165
}
166
167
if (unionfs_lookup_isroot(cnp, udvp) ||
168
unionfs_lookup_isroot(cnp, ldvp)) {
169
error = ENOENT;
170
goto unionfs_lookup_return;
171
}
172
173
if (udvp != NULL)
174
dtmpvp = udvp;
175
else
176
dtmpvp = ldvp;
177
178
unionfs_forward_vop_start(dtmpvp, &lkflags);
179
error = VOP_LOOKUP(dtmpvp, &vp, cnp);
180
unionfs_forward_vop_finish(dvp, dtmpvp, lkflags);
181
182
/*
183
* Drop the lock and reference on vp. If the lookup was
184
* successful, we'll either need to exchange vp's lock and
185
* reference for the unionfs parent vnode's lock and
186
* reference, or (if dvp was reclaimed) we'll need to drop
187
* vp's lock and reference to return early.
188
*/
189
if (vp != NULL)
190
vput(vp);
191
dunp = VTOUNIONFS(dvp);
192
if (error == 0 && dunp == NULL)
193
error = ENOENT;
194
195
if (error == 0) {
196
dtmpvp = dunp->un_dvp;
197
vref(dtmpvp);
198
VOP_UNLOCK(dvp);
199
*(ap->a_vpp) = dtmpvp;
200
201
vn_lock(dtmpvp, cnp->cn_lkflags | LK_RETRY);
202
203
if (VN_IS_DOOMED(dtmpvp)) {
204
vput(dtmpvp);
205
*(ap->a_vpp) = NULL;
206
error = ENOENT;
207
}
208
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
209
}
210
211
goto unionfs_lookup_cleanup;
212
}
213
214
/*
215
* Lookup lower layer. We do this before looking up the the upper
216
* layer, as we may drop the upper parent directory's lock, and we
217
* want to ensure the upper parent remains locked from the point of
218
* lookup through any ensuing VOP that may require it to be locked.
219
* The cost of this is that we may end up performing an unnecessary
220
* lower layer lookup if a whiteout is present in the upper layer.
221
*/
222
if (ldvp != NULL && !(cnflags & DOWHITEOUT)) {
223
struct componentname lcn;
224
bool is_dot;
225
226
if (udvp != NULL) {
227
vref(ldvp);
228
VOP_UNLOCK(dvp);
229
vn_lock(ldvp, LK_EXCLUSIVE | LK_RETRY);
230
}
231
232
lcn = *cnp;
233
/* always op is LOOKUP */
234
lcn.cn_nameiop = LOOKUP;
235
lcn.cn_flags = cnflags;
236
is_dot = false;
237
238
if (udvp == NULL)
239
unionfs_forward_vop_start(ldvp, &lkflags);
240
lerror = VOP_LOOKUP(ldvp, &lvp, &lcn);
241
if (udvp == NULL &&
242
unionfs_forward_vop_finish(dvp, ldvp, lkflags)) {
243
if (lvp != NULL)
244
VOP_UNLOCK(lvp);
245
error = ENOENT;
246
goto unionfs_lookup_cleanup;
247
}
248
249
if (udvp == NULL)
250
cnp->cn_flags = lcn.cn_flags;
251
252
if (lerror == 0) {
253
if (ldvp == lvp) { /* is dot */
254
vrele(lvp);
255
*(ap->a_vpp) = dvp;
256
vref(dvp);
257
is_dot = true;
258
error = lerror;
259
} else if (lvp != NULL)
260
VOP_UNLOCK(lvp);
261
}
262
263
if (udvp != NULL) {
264
vput(ldvp);
265
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
266
if (VN_IS_DOOMED(dvp))
267
error = ENOENT;
268
}
269
if (is_dot)
270
goto unionfs_lookup_return;
271
else if (error != 0)
272
goto unionfs_lookup_cleanup;
273
}
274
/*
275
* lookup upper layer
276
*/
277
if (udvp != NULL) {
278
bool iswhiteout = false;
279
280
unionfs_forward_vop_start(udvp, &lkflags);
281
uerror = VOP_LOOKUP(udvp, &uvp, cnp);
282
if (unionfs_forward_vop_finish(dvp, udvp, lkflags)) {
283
if (uvp != NULL)
284
VOP_UNLOCK(uvp);
285
error = ENOENT;
286
goto unionfs_lookup_cleanup;
287
}
288
289
if (uerror == 0) {
290
if (udvp == uvp) { /* is dot */
291
if (lvp != NULL)
292
vrele(lvp);
293
vrele(uvp);
294
*(ap->a_vpp) = dvp;
295
vref(dvp);
296
297
error = uerror;
298
goto unionfs_lookup_return;
299
} else if (uvp != NULL)
300
VOP_UNLOCK(uvp);
301
}
302
303
/* check whiteout */
304
if ((uerror == ENOENT || uerror == EJUSTRETURN) &&
305
(cnp->cn_flags & ISWHITEOUT))
306
iswhiteout = true;
307
else if (VOP_GETATTR(udvp, &va, cnp->cn_cred) == 0 &&
308
(va.va_flags & OPAQUE))
309
iswhiteout = true;
310
311
if (iswhiteout && lvp != NULL) {
312
vrele(lvp);
313
lvp = NULL;
314
}
315
316
#if 0
317
UNIONFS_INTERNAL_DEBUG(
318
"unionfs_lookup: debug: whiteout=%d, path=%s\n",
319
iswhiteout, cnp->cn_nameptr);
320
#endif
321
}
322
323
/*
324
* check lookup result
325
*/
326
if (uvp == NULL && lvp == NULL) {
327
error = (udvp != NULL ? uerror : lerror);
328
goto unionfs_lookup_return;
329
}
330
331
/*
332
* check vnode type
333
*/
334
if (uvp != NULL && lvp != NULL && uvp->v_type != lvp->v_type) {
335
vrele(lvp);
336
lvp = NULL;
337
}
338
339
/*
340
* check shadow dir
341
*/
342
if (uerror != 0 && uerror != EJUSTRETURN && udvp != NULL &&
343
lerror == 0 && lvp != NULL && lvp->v_type == VDIR &&
344
!(dvp->v_mount->mnt_flag & MNT_RDONLY) &&
345
(1 < cnp->cn_namelen || '.' != *(cnp->cn_nameptr))) {
346
/* get unionfs vnode in order to create a new shadow dir. */
347
error = unionfs_nodeget(dvp->v_mount, NULL, lvp, dvp, &vp,
348
cnp);
349
if (error != 0)
350
goto unionfs_lookup_cleanup;
351
352
if (LK_SHARED == (cnp->cn_lkflags & LK_TYPE_MASK))
353
VOP_UNLOCK(vp);
354
if (LK_EXCLUSIVE != VOP_ISLOCKED(vp)) {
355
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
356
lockflag = 1;
357
}
358
unp = VTOUNIONFS(vp);
359
if (unp == NULL)
360
error = ENOENT;
361
else
362
error = unionfs_mkshadowdir(dvp, vp, cnp, td);
363
if (lockflag != 0)
364
VOP_UNLOCK(vp);
365
if (error != 0) {
366
UNIONFSDEBUG(
367
"unionfs_lookup: Unable to create shadow dir.");
368
if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_EXCLUSIVE)
369
vput(vp);
370
else
371
vrele(vp);
372
goto unionfs_lookup_cleanup;
373
}
374
/*
375
* TODO: Since unionfs_mkshadowdir() relocks udvp after
376
* creating the new directory, return ERELOOKUP here?
377
*/
378
if ((cnp->cn_lkflags & LK_TYPE_MASK) == LK_SHARED)
379
vn_lock(vp, LK_SHARED | LK_RETRY);
380
}
381
/*
382
* get unionfs vnode.
383
*/
384
else {
385
if (uvp != NULL)
386
error = uerror;
387
else
388
error = lerror;
389
if (error != 0)
390
goto unionfs_lookup_cleanup;
391
error = unionfs_nodeget(dvp->v_mount, uvp, lvp,
392
dvp, &vp, cnp);
393
if (error != 0) {
394
UNIONFSDEBUG(
395
"unionfs_lookup: Unable to create unionfs vnode.");
396
goto unionfs_lookup_cleanup;
397
}
398
}
399
400
if (VN_IS_DOOMED(dvp) || VN_IS_DOOMED(vp)) {
401
error = ENOENT;
402
vput(vp);
403
goto unionfs_lookup_cleanup;
404
}
405
406
*(ap->a_vpp) = vp;
407
408
if (cnflags & MAKEENTRY)
409
cache_enter(dvp, vp, cnp);
410
411
unionfs_lookup_cleanup:
412
if (uvp != NULL)
413
vrele(uvp);
414
if (lvp != NULL)
415
vrele(lvp);
416
417
if (error == ENOENT && (cnflags & MAKEENTRY) != 0 &&
418
!VN_IS_DOOMED(dvp))
419
cache_enter(dvp, NULL, cnp);
420
421
unionfs_lookup_return:
422
unionfs_clear_in_progress_flag(dvp, UNIONFS_LOOKUP_IN_PROGRESS);
423
424
UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
425
426
return (error);
427
}
428
429
static int
430
unionfs_create(struct vop_create_args *ap)
431
{
432
struct unionfs_node *dunp;
433
struct componentname *cnp;
434
struct vnode *udvp;
435
struct vnode *vp;
436
int error;
437
438
UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");
439
440
KASSERT_UNIONFS_VNODE(ap->a_dvp);
441
442
dunp = VTOUNIONFS(ap->a_dvp);
443
cnp = ap->a_cnp;
444
udvp = dunp->un_uppervp;
445
error = EROFS;
446
447
if (udvp != NULL) {
448
int lkflags;
449
bool vp_created = false;
450
unionfs_forward_vop_start(udvp, &lkflags);
451
error = VOP_CREATE(udvp, &vp, cnp, ap->a_vap);
452
if (error == 0)
453
vp_created = true;
454
if (__predict_false(unionfs_forward_vop_finish(ap->a_dvp, udvp,
455
lkflags)) && error == 0) {
456
error = ENOENT;
457
}
458
if (error == 0) {
459
VOP_UNLOCK(vp);
460
error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULL,
461
ap->a_dvp, ap->a_vpp, cnp);
462
vrele(vp);
463
} else if (vp_created)
464
vput(vp);
465
}
466
467
UNIONFS_INTERNAL_DEBUG("unionfs_create: leave (%d)\n", error);
468
469
return (error);
470
}
471
472
static int
473
unionfs_whiteout(struct vop_whiteout_args *ap)
474
{
475
struct unionfs_node *dunp;
476
struct componentname *cnp;
477
struct vnode *udvp;
478
int error;
479
480
UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: enter\n");
481
482
KASSERT_UNIONFS_VNODE(ap->a_dvp);
483
484
dunp = VTOUNIONFS(ap->a_dvp);
485
cnp = ap->a_cnp;
486
udvp = dunp->un_uppervp;
487
error = EOPNOTSUPP;
488
489
if (udvp != NULL) {
490
int lkflags;
491
switch (ap->a_flags) {
492
case CREATE:
493
case DELETE:
494
case LOOKUP:
495
unionfs_forward_vop_start(udvp, &lkflags);
496
error = VOP_WHITEOUT(udvp, cnp, ap->a_flags);
497
unionfs_forward_vop_finish(ap->a_dvp, udvp, lkflags);
498
break;
499
default:
500
error = EINVAL;
501
break;
502
}
503
}
504
505
UNIONFS_INTERNAL_DEBUG("unionfs_whiteout: leave (%d)\n", error);
506
507
return (error);
508
}
509
510
static int
511
unionfs_mknod(struct vop_mknod_args *ap)
512
{
513
struct unionfs_node *dunp;
514
struct componentname *cnp;
515
struct vnode *udvp;
516
struct vnode *vp;
517
int error;
518
519
UNIONFS_INTERNAL_DEBUG("unionfs_mknod: enter\n");
520
521
KASSERT_UNIONFS_VNODE(ap->a_dvp);
522
523
dunp = VTOUNIONFS(ap->a_dvp);
524
cnp = ap->a_cnp;
525
udvp = dunp->un_uppervp;
526
error = EROFS;
527
528
if (udvp != NULL) {
529
int lkflags;
530
bool vp_created = false;
531
unionfs_forward_vop_start(udvp, &lkflags);
532
error = VOP_MKNOD(udvp, &vp, cnp, ap->a_vap);
533
if (error == 0)
534
vp_created = true;
535
if (__predict_false(unionfs_forward_vop_finish(ap->a_dvp, udvp,
536
lkflags)) && error == 0) {
537
error = ENOENT;
538
}
539
if (error == 0) {
540
VOP_UNLOCK(vp);
541
error = unionfs_nodeget(ap->a_dvp->v_mount, vp, NULL,
542
ap->a_dvp, ap->a_vpp, cnp);
543
vrele(vp);
544
} else if (vp_created)
545
vput(vp);
546
}
547
548
UNIONFS_INTERNAL_DEBUG("unionfs_mknod: leave (%d)\n", error);
549
550
return (error);
551
}
552
553
enum unionfs_lkupgrade {
554
UNIONFS_LKUPGRADE_SUCCESS, /* lock successfully upgraded */
555
UNIONFS_LKUPGRADE_ALREADY, /* lock already held exclusive */
556
UNIONFS_LKUPGRADE_DOOMED /* lock was upgraded, but vnode reclaimed */
557
};
558
559
static inline enum unionfs_lkupgrade
560
unionfs_upgrade_lock(struct vnode *vp)
561
{
562
ASSERT_VOP_LOCKED(vp, __func__);
563
564
if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
565
return (UNIONFS_LKUPGRADE_ALREADY);
566
567
if (vn_lock(vp, LK_UPGRADE) != 0) {
568
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
569
if (VN_IS_DOOMED(vp))
570
return (UNIONFS_LKUPGRADE_DOOMED);
571
}
572
return (UNIONFS_LKUPGRADE_SUCCESS);
573
}
574
575
static inline void
576
unionfs_downgrade_lock(struct vnode *vp, enum unionfs_lkupgrade status)
577
{
578
if (status != UNIONFS_LKUPGRADE_ALREADY)
579
vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
580
}
581
582
/*
583
* Exchange the default (upper vnode) lock on a unionfs vnode for the lower
584
* vnode lock, in support of operations that require access to the lower vnode
585
* even when an upper vnode is present. We don't use vn_lock_pair() to hold
586
* both vnodes at the same time, primarily because the caller may proceed
587
* to issue VOPs to the lower layer which re-lock or perform other operations
588
* which may not be safe in the presence of a locked vnode from another FS.
589
* Moreover, vn_lock_pair()'s deadlock resolution approach can introduce
590
* additional overhead that isn't necessary on these paths.
591
*
592
* vp must be a locked unionfs vnode; the lock state of this vnode is
593
* returned through *lkflags for later use in unionfs_unlock_lvp().
594
*
595
* Returns the locked lower vnode, or NULL if the lower vnode (and therefore
596
* also the unionfs vnode above it) has been doomed.
597
*/
598
static struct vnode *
599
unionfs_lock_lvp(struct vnode *vp, int *lkflags)
600
{
601
struct unionfs_node *unp;
602
struct vnode *lvp;
603
604
unp = VTOUNIONFS(vp);
605
lvp = unp->un_lowervp;
606
ASSERT_VOP_LOCKED(vp, __func__);
607
ASSERT_VOP_UNLOCKED(lvp, __func__);
608
*lkflags = VOP_ISLOCKED(vp);
609
vref(lvp);
610
VOP_UNLOCK(vp);
611
vn_lock(lvp, *lkflags | LK_RETRY);
612
if (VN_IS_DOOMED(lvp)) {
613
vput(lvp);
614
lvp = NULL;
615
vn_lock(vp, *lkflags | LK_RETRY);
616
}
617
return (lvp);
618
}
619
620
/*
621
* Undo a previous call to unionfs_lock_lvp(), restoring the default lock
622
* on the unionfs vnode. This function reloads and returns the vnode
623
* private data for the unionfs vnode, which will be NULL if the unionfs
624
* vnode became doomed while its lock was dropped. The caller must check
625
* for this case.
626
*/
627
static struct unionfs_node *
628
unionfs_unlock_lvp(struct vnode *vp, struct vnode *lvp, int lkflags)
629
{
630
ASSERT_VOP_LOCKED(lvp, __func__);
631
ASSERT_VOP_UNLOCKED(vp, __func__);
632
vput(lvp);
633
vn_lock(vp, lkflags | LK_RETRY);
634
return (VTOUNIONFS(vp));
635
}
636
637
static int
638
unionfs_open(struct vop_open_args *ap)
639
{
640
struct unionfs_node *unp;
641
struct unionfs_node_status *unsp;
642
struct vnode *vp;
643
struct vnode *uvp;
644
struct vnode *lvp;
645
struct vnode *targetvp;
646
struct ucred *cred;
647
struct thread *td;
648
int error;
649
int lkflags;
650
enum unionfs_lkupgrade lkstatus;
651
bool lock_lvp, open_lvp;
652
653
UNIONFS_INTERNAL_DEBUG("unionfs_open: enter\n");
654
655
KASSERT_UNIONFS_VNODE(ap->a_vp);
656
657
error = 0;
658
vp = ap->a_vp;
659
targetvp = NULL;
660
cred = ap->a_cred;
661
td = ap->a_td;
662
open_lvp = lock_lvp = false;
663
664
/*
665
* The executable loader path may call this function with vp locked
666
* shared. If the vnode is reclaimed while upgrading, we can't safely
667
* use unp or do anything else unionfs- specific.
668
*/
669
lkstatus = unionfs_upgrade_lock(vp);
670
if (lkstatus == UNIONFS_LKUPGRADE_DOOMED) {
671
error = ENOENT;
672
goto unionfs_open_cleanup;
673
}
674
675
unp = VTOUNIONFS(vp);
676
uvp = unp->un_uppervp;
677
lvp = unp->un_lowervp;
678
unionfs_get_node_status(unp, td, &unsp);
679
680
if (unsp->uns_lower_opencnt > 0 || unsp->uns_upper_opencnt > 0) {
681
/* vnode is already opend. */
682
if (unsp->uns_upper_opencnt > 0)
683
targetvp = uvp;
684
else
685
targetvp = lvp;
686
687
if (targetvp == lvp &&
688
(ap->a_mode & FWRITE) && lvp->v_type == VREG)
689
targetvp = NULL;
690
}
691
if (targetvp == NULL) {
692
if (uvp == NULL) {
693
if ((ap->a_mode & FWRITE) && lvp->v_type == VREG) {
694
error = unionfs_copyfile(vp,
695
!(ap->a_mode & O_TRUNC), cred, td);
696
if (error != 0) {
697
unp = VTOUNIONFS(vp);
698
goto unionfs_open_abort;
699
}
700
targetvp = uvp = unp->un_uppervp;
701
} else
702
targetvp = lvp;
703
} else
704
targetvp = uvp;
705
}
706
707
if (targetvp == uvp && uvp->v_type == VDIR && lvp != NULL &&
708
unsp->uns_lower_opencnt <= 0)
709
open_lvp = true;
710
else if (targetvp == lvp && uvp != NULL)
711
lock_lvp = true;
712
713
if (lock_lvp) {
714
unp = NULL;
715
lvp = unionfs_lock_lvp(vp, &lkflags);
716
if (lvp == NULL) {
717
error = ENOENT;
718
goto unionfs_open_abort;
719
}
720
} else
721
unionfs_forward_vop_start(targetvp, &lkflags);
722
723
error = VOP_OPEN(targetvp, ap->a_mode, cred, td, ap->a_fp);
724
725
if (lock_lvp) {
726
unp = unionfs_unlock_lvp(vp, lvp, lkflags);
727
if (unp == NULL && error == 0)
728
error = ENOENT;
729
} else if (unionfs_forward_vop_finish(vp, targetvp, lkflags))
730
error = error ? error : ENOENT;
731
732
if (error != 0)
733
goto unionfs_open_abort;
734
735
if (targetvp == uvp) {
736
if (open_lvp) {
737
unp = NULL;
738
lvp = unionfs_lock_lvp(vp, &lkflags);
739
if (lvp == NULL) {
740
error = ENOENT;
741
goto unionfs_open_abort;
742
}
743
/* open lower for readdir */
744
error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
745
unp = unionfs_unlock_lvp(vp, lvp, lkflags);
746
if (unp == NULL) {
747
error = error ? error : ENOENT;
748
goto unionfs_open_abort;
749
}
750
if (error != 0) {
751
unionfs_forward_vop_start(uvp, &lkflags);
752
VOP_CLOSE(uvp, ap->a_mode, cred, td);
753
if (unionfs_forward_vop_finish(vp, uvp, lkflags))
754
unp = NULL;
755
goto unionfs_open_abort;
756
}
757
unsp->uns_node_flag |= UNS_OPENL_4_READDIR;
758
unsp->uns_lower_opencnt++;
759
}
760
unsp->uns_upper_opencnt++;
761
} else {
762
unsp->uns_lower_opencnt++;
763
unsp->uns_lower_openmode = ap->a_mode;
764
}
765
vp->v_object = targetvp->v_object;
766
767
unionfs_open_abort:
768
769
if (error != 0 && unp != NULL)
770
unionfs_tryrem_node_status(unp, unsp);
771
772
unionfs_open_cleanup:
773
unionfs_downgrade_lock(vp, lkstatus);
774
775
UNIONFS_INTERNAL_DEBUG("unionfs_open: leave (%d)\n", error);
776
777
return (error);
778
}
779
780
static int
781
unionfs_close(struct vop_close_args *ap)
782
{
783
struct unionfs_node *unp;
784
struct unionfs_node_status *unsp;
785
struct ucred *cred;
786
struct thread *td;
787
struct vnode *vp;
788
struct vnode *uvp;
789
struct vnode *lvp;
790
struct vnode *ovp;
791
int error;
792
int lkflags;
793
enum unionfs_lkupgrade lkstatus;
794
bool lock_lvp;
795
796
UNIONFS_INTERNAL_DEBUG("unionfs_close: enter\n");
797
798
KASSERT_UNIONFS_VNODE(ap->a_vp);
799
800
vp = ap->a_vp;
801
cred = ap->a_cred;
802
td = ap->a_td;
803
error = 0;
804
lock_lvp = false;
805
806
/*
807
* If the vnode is reclaimed while upgrading, we can't safely use unp
808
* or do anything else unionfs- specific.
809
*/
810
lkstatus = unionfs_upgrade_lock(vp);
811
if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
812
goto unionfs_close_cleanup;
813
814
unp = VTOUNIONFS(vp);
815
lvp = unp->un_lowervp;
816
uvp = unp->un_uppervp;
817
unsp = (td != NULL) ? unionfs_find_node_status(unp, td) : NULL;
818
819
if (unsp == NULL ||
820
(unsp->uns_lower_opencnt <= 0 && unsp->uns_upper_opencnt <= 0)) {
821
#ifdef DIAGNOSTIC
822
if (unsp != NULL)
823
printf("unionfs_close: warning: open count is 0\n");
824
#endif
825
if (uvp != NULL)
826
ovp = uvp;
827
else
828
ovp = lvp;
829
} else if (unsp->uns_upper_opencnt > 0)
830
ovp = uvp;
831
else
832
ovp = lvp;
833
834
if (ovp == lvp && uvp != NULL) {
835
lock_lvp = true;
836
unp = NULL;
837
lvp = unionfs_lock_lvp(vp, &lkflags);
838
if (lvp == NULL) {
839
error = ENOENT;
840
goto unionfs_close_abort;
841
}
842
} else
843
unionfs_forward_vop_start(ovp, &lkflags);
844
845
error = VOP_CLOSE(ovp, ap->a_fflag, cred, td);
846
847
if (lock_lvp) {
848
unp = unionfs_unlock_lvp(vp, lvp, lkflags);
849
if (unp == NULL && error == 0)
850
error = ENOENT;
851
} else if (unionfs_forward_vop_finish(vp, ovp, lkflags))
852
error = error ? error : ENOENT;
853
854
if (error != 0)
855
goto unionfs_close_abort;
856
857
vp->v_object = ovp->v_object;
858
859
if (ovp == uvp) {
860
if (unsp != NULL && ((--unsp->uns_upper_opencnt) == 0)) {
861
if (unsp->uns_node_flag & UNS_OPENL_4_READDIR) {
862
unp = NULL;
863
lvp = unionfs_lock_lvp(vp, &lkflags);
864
if (lvp == NULL) {
865
error = ENOENT;
866
goto unionfs_close_abort;
867
}
868
VOP_CLOSE(lvp, FREAD, cred, td);
869
unp = unionfs_unlock_lvp(vp, lvp, lkflags);
870
if (unp == NULL) {
871
error = ENOENT;
872
goto unionfs_close_abort;
873
}
874
unsp->uns_node_flag &= ~UNS_OPENL_4_READDIR;
875
unsp->uns_lower_opencnt--;
876
}
877
if (unsp->uns_lower_opencnt > 0)
878
vp->v_object = lvp->v_object;
879
}
880
} else if (unsp != NULL)
881
unsp->uns_lower_opencnt--;
882
883
unionfs_close_abort:
884
if (unp != NULL && unsp != NULL)
885
unionfs_tryrem_node_status(unp, unsp);
886
887
unionfs_close_cleanup:
888
unionfs_downgrade_lock(vp, lkstatus);
889
890
UNIONFS_INTERNAL_DEBUG("unionfs_close: leave (%d)\n", error);
891
892
return (error);
893
}
894
895
/*
896
* Check the access mode toward shadow file/dir.
897
*/
898
static int
899
unionfs_check_corrected_access(accmode_t accmode, struct vattr *va,
900
struct ucred *cred)
901
{
902
uid_t uid; /* upper side vnode's uid */
903
gid_t gid; /* upper side vnode's gid */
904
u_short vmode; /* upper side vnode's mode */
905
u_short mask;
906
907
mask = 0;
908
uid = va->va_uid;
909
gid = va->va_gid;
910
vmode = va->va_mode;
911
912
/* check owner */
913
if (cred->cr_uid == uid) {
914
if (accmode & VEXEC)
915
mask |= S_IXUSR;
916
if (accmode & VREAD)
917
mask |= S_IRUSR;
918
if (accmode & VWRITE)
919
mask |= S_IWUSR;
920
return ((vmode & mask) == mask ? 0 : EACCES);
921
}
922
923
/* check group */
924
if (groupmember(gid, cred)) {
925
if (accmode & VEXEC)
926
mask |= S_IXGRP;
927
if (accmode & VREAD)
928
mask |= S_IRGRP;
929
if (accmode & VWRITE)
930
mask |= S_IWGRP;
931
return ((vmode & mask) == mask ? 0 : EACCES);
932
}
933
934
/* check other */
935
if (accmode & VEXEC)
936
mask |= S_IXOTH;
937
if (accmode & VREAD)
938
mask |= S_IROTH;
939
if (accmode & VWRITE)
940
mask |= S_IWOTH;
941
942
return ((vmode & mask) == mask ? 0 : EACCES);
943
}
944
945
static int
946
unionfs_access(struct vop_access_args *ap)
947
{
948
struct unionfs_mount *ump;
949
struct unionfs_node *unp;
950
struct vnode *uvp;
951
struct vnode *lvp;
952
struct thread *td;
953
struct vattr va;
954
accmode_t accmode;
955
int error;
956
957
UNIONFS_INTERNAL_DEBUG("unionfs_access: enter\n");
958
959
KASSERT_UNIONFS_VNODE(ap->a_vp);
960
961
ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
962
unp = VTOUNIONFS(ap->a_vp);
963
uvp = unp->un_uppervp;
964
lvp = unp->un_lowervp;
965
td = ap->a_td;
966
accmode = ap->a_accmode;
967
error = EACCES;
968
969
if ((accmode & VWRITE) &&
970
(ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) {
971
switch (ap->a_vp->v_type) {
972
case VREG:
973
case VDIR:
974
case VLNK:
975
return (EROFS);
976
default:
977
break;
978
}
979
}
980
981
if (uvp != NULL) {
982
error = VOP_ACCESS(uvp, accmode, ap->a_cred, td);
983
984
UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
985
986
return (error);
987
}
988
989
if (lvp != NULL) {
990
if (accmode & VWRITE) {
991
if ((ump->um_uppermp->mnt_flag & MNT_RDONLY) != 0) {
992
switch (ap->a_vp->v_type) {
993
case VREG:
994
case VDIR:
995
case VLNK:
996
return (EROFS);
997
default:
998
break;
999
}
1000
} else if (ap->a_vp->v_type == VREG ||
1001
ap->a_vp->v_type == VDIR) {
1002
/* check shadow file/dir */
1003
if (ump->um_copymode != UNIONFS_TRANSPARENT) {
1004
error = unionfs_create_uppervattr(ump,
1005
lvp, &va, ap->a_cred, td);
1006
if (error != 0)
1007
return (error);
1008
1009
error = unionfs_check_corrected_access(
1010
accmode, &va, ap->a_cred);
1011
if (error != 0)
1012
return (error);
1013
}
1014
}
1015
accmode &= ~(VWRITE | VAPPEND);
1016
accmode |= VREAD; /* will copy to upper */
1017
}
1018
error = VOP_ACCESS(lvp, accmode, ap->a_cred, td);
1019
}
1020
1021
UNIONFS_INTERNAL_DEBUG("unionfs_access: leave (%d)\n", error);
1022
1023
return (error);
1024
}
1025
1026
static int
1027
unionfs_getattr(struct vop_getattr_args *ap)
1028
{
1029
struct unionfs_node *unp;
1030
struct unionfs_mount *ump;
1031
struct vnode *uvp;
1032
struct vnode *lvp;
1033
struct thread *td;
1034
struct vattr va;
1035
int error;
1036
1037
UNIONFS_INTERNAL_DEBUG("unionfs_getattr: enter\n");
1038
1039
KASSERT_UNIONFS_VNODE(ap->a_vp);
1040
1041
unp = VTOUNIONFS(ap->a_vp);
1042
ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1043
uvp = unp->un_uppervp;
1044
lvp = unp->un_lowervp;
1045
td = curthread;
1046
1047
if (uvp != NULL) {
1048
if ((error = VOP_GETATTR(uvp, ap->a_vap, ap->a_cred)) == 0)
1049
ap->a_vap->va_fsid =
1050
ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
1051
1052
UNIONFS_INTERNAL_DEBUG(
1053
"unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
1054
ap->a_vap->va_mode, ap->a_vap->va_uid,
1055
ap->a_vap->va_gid, error);
1056
1057
return (error);
1058
}
1059
1060
error = VOP_GETATTR(lvp, ap->a_vap, ap->a_cred);
1061
1062
if (error == 0 && (ump->um_uppermp->mnt_flag & MNT_RDONLY) == 0) {
1063
/* correct the attr toward shadow file/dir. */
1064
if (ap->a_vp->v_type == VREG || ap->a_vp->v_type == VDIR) {
1065
unionfs_create_uppervattr_core(ump, ap->a_vap, &va, td);
1066
ap->a_vap->va_mode = va.va_mode;
1067
ap->a_vap->va_uid = va.va_uid;
1068
ap->a_vap->va_gid = va.va_gid;
1069
}
1070
}
1071
1072
if (error == 0)
1073
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
1074
1075
UNIONFS_INTERNAL_DEBUG(
1076
"unionfs_getattr: leave mode=%o, uid=%d, gid=%d (%d)\n",
1077
ap->a_vap->va_mode, ap->a_vap->va_uid, ap->a_vap->va_gid, error);
1078
1079
return (error);
1080
}
1081
1082
static int
1083
unionfs_setattr(struct vop_setattr_args *ap)
1084
{
1085
struct unionfs_node *unp;
1086
struct vnode *uvp;
1087
struct vnode *lvp;
1088
struct thread *td;
1089
struct vattr *vap;
1090
int error;
1091
1092
UNIONFS_INTERNAL_DEBUG("unionfs_setattr: enter\n");
1093
1094
KASSERT_UNIONFS_VNODE(ap->a_vp);
1095
1096
error = EROFS;
1097
unp = VTOUNIONFS(ap->a_vp);
1098
uvp = unp->un_uppervp;
1099
lvp = unp->un_lowervp;
1100
td = curthread;
1101
vap = ap->a_vap;
1102
1103
if ((ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) &&
1104
(vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
1105
vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
1106
vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL))
1107
return (EROFS);
1108
1109
if (uvp == NULL && lvp->v_type == VREG) {
1110
error = unionfs_copyfile(ap->a_vp, (vap->va_size != 0),
1111
ap->a_cred, td);
1112
if (error != 0)
1113
return (error);
1114
uvp = unp->un_uppervp;
1115
}
1116
1117
if (uvp != NULL) {
1118
int lkflags;
1119
unionfs_forward_vop_start(uvp, &lkflags);
1120
error = VOP_SETATTR(uvp, vap, ap->a_cred);
1121
unionfs_forward_vop_finish(ap->a_vp, uvp, lkflags);
1122
}
1123
1124
UNIONFS_INTERNAL_DEBUG("unionfs_setattr: leave (%d)\n", error);
1125
1126
return (error);
1127
}
1128
1129
static int
1130
unionfs_read(struct vop_read_args *ap)
1131
{
1132
struct unionfs_node *unp;
1133
struct vnode *tvp;
1134
int error;
1135
1136
/* UNIONFS_INTERNAL_DEBUG("unionfs_read: enter\n"); */
1137
1138
KASSERT_UNIONFS_VNODE(ap->a_vp);
1139
1140
unp = VTOUNIONFS(ap->a_vp);
1141
tvp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
1142
1143
error = VOP_READ(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
1144
1145
/* UNIONFS_INTERNAL_DEBUG("unionfs_read: leave (%d)\n", error); */
1146
1147
return (error);
1148
}
1149
1150
static int
1151
unionfs_write(struct vop_write_args *ap)
1152
{
1153
struct unionfs_node *unp;
1154
struct vnode *tvp;
1155
int error;
1156
int lkflags;
1157
1158
/* UNIONFS_INTERNAL_DEBUG("unionfs_write: enter\n"); */
1159
1160
KASSERT_UNIONFS_VNODE(ap->a_vp);
1161
1162
unp = VTOUNIONFS(ap->a_vp);
1163
tvp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
1164
1165
unionfs_forward_vop_start(tvp, &lkflags);
1166
error = VOP_WRITE(tvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
1167
unionfs_forward_vop_finish(ap->a_vp, tvp, lkflags);
1168
1169
/* UNIONFS_INTERNAL_DEBUG("unionfs_write: leave (%d)\n", error); */
1170
1171
return (error);
1172
}
1173
1174
static int
1175
unionfs_ioctl(struct vop_ioctl_args *ap)
1176
{
1177
struct unionfs_node *unp;
1178
struct unionfs_node_status *unsp;
1179
struct vnode *ovp;
1180
int error;
1181
1182
UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: enter\n");
1183
1184
KASSERT_UNIONFS_VNODE(ap->a_vp);
1185
1186
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1187
unp = VTOUNIONFS(ap->a_vp);
1188
unionfs_get_node_status(unp, ap->a_td, &unsp);
1189
ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
1190
unionfs_tryrem_node_status(unp, unsp);
1191
VOP_UNLOCK(ap->a_vp);
1192
1193
if (ovp == NULL)
1194
return (EBADF);
1195
1196
error = VOP_IOCTL(ovp, ap->a_command, ap->a_data, ap->a_fflag,
1197
ap->a_cred, ap->a_td);
1198
1199
UNIONFS_INTERNAL_DEBUG("unionfs_ioctl: leave (%d)\n", error);
1200
1201
return (error);
1202
}
1203
1204
static int
1205
unionfs_poll(struct vop_poll_args *ap)
1206
{
1207
struct unionfs_node *unp;
1208
struct unionfs_node_status *unsp;
1209
struct vnode *ovp;
1210
1211
KASSERT_UNIONFS_VNODE(ap->a_vp);
1212
1213
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1214
unp = VTOUNIONFS(ap->a_vp);
1215
unionfs_get_node_status(unp, ap->a_td, &unsp);
1216
ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
1217
unionfs_tryrem_node_status(unp, unsp);
1218
VOP_UNLOCK(ap->a_vp);
1219
1220
if (ovp == NULL)
1221
return (EBADF);
1222
1223
return (VOP_POLL(ovp, ap->a_events, ap->a_cred, ap->a_td));
1224
}
1225
1226
static int
1227
unionfs_fsync(struct vop_fsync_args *ap)
1228
{
1229
struct unionfs_node *unp;
1230
struct unionfs_node_status *unsp;
1231
struct vnode *ovp;
1232
enum unionfs_lkupgrade lkstatus;
1233
int error, lkflags;
1234
1235
KASSERT_UNIONFS_VNODE(ap->a_vp);
1236
1237
unp = VTOUNIONFS(ap->a_vp);
1238
lkstatus = unionfs_upgrade_lock(ap->a_vp);
1239
if (lkstatus == UNIONFS_LKUPGRADE_DOOMED) {
1240
unionfs_downgrade_lock(ap->a_vp, lkstatus);
1241
return (ENOENT);
1242
}
1243
unionfs_get_node_status(unp, ap->a_td, &unsp);
1244
ovp = (unsp->uns_upper_opencnt ? unp->un_uppervp : unp->un_lowervp);
1245
unionfs_tryrem_node_status(unp, unsp);
1246
1247
unionfs_downgrade_lock(ap->a_vp, lkstatus);
1248
1249
if (ovp == NULL)
1250
return (EBADF);
1251
1252
unionfs_forward_vop_start(ovp, &lkflags);
1253
error = VOP_FSYNC(ovp, ap->a_waitfor, ap->a_td);
1254
unionfs_forward_vop_finish(ap->a_vp, ovp, lkflags);
1255
1256
return (error);
1257
}
1258
1259
static int
1260
unionfs_remove(struct vop_remove_args *ap)
1261
{
1262
char *path;
1263
struct unionfs_node *dunp;
1264
struct unionfs_node *unp;
1265
struct unionfs_mount *ump;
1266
struct vnode *udvp;
1267
struct vnode *uvp;
1268
struct vnode *lvp;
1269
struct componentname *cnp;
1270
struct thread *td;
1271
int error;
1272
int pathlen;
1273
1274
UNIONFS_INTERNAL_DEBUG("unionfs_remove: enter\n");
1275
1276
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1277
KASSERT_UNIONFS_VNODE(ap->a_vp);
1278
1279
error = 0;
1280
dunp = VTOUNIONFS(ap->a_dvp);
1281
udvp = dunp->un_uppervp;
1282
cnp = ap->a_cnp;
1283
td = curthread;
1284
1285
ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1286
unp = VTOUNIONFS(ap->a_vp);
1287
uvp = unp->un_uppervp;
1288
lvp = unp->un_lowervp;
1289
path = unp->un_path;
1290
pathlen = unp->un_pathlen;
1291
1292
if (udvp == NULL)
1293
return (EROFS);
1294
1295
if (uvp != NULL) {
1296
int udvp_lkflags, uvp_lkflags;
1297
if (ump == NULL || ump->um_whitemode == UNIONFS_WHITE_ALWAYS ||
1298
lvp != NULL)
1299
cnp->cn_flags |= DOWHITEOUT;
1300
unionfs_forward_vop_start_pair(udvp, &udvp_lkflags,
1301
uvp, &uvp_lkflags);
1302
error = VOP_REMOVE(udvp, uvp, cnp);
1303
unionfs_forward_vop_finish_pair(ap->a_dvp, udvp, udvp_lkflags,
1304
ap->a_vp, uvp, uvp_lkflags);
1305
} else if (lvp != NULL) {
1306
error = unionfs_mkwhiteout(ap->a_dvp, ap->a_vp, cnp, td,
1307
path, pathlen);
1308
}
1309
1310
UNIONFS_INTERNAL_DEBUG("unionfs_remove: leave (%d)\n", error);
1311
1312
return (error);
1313
}
1314
1315
static int
1316
unionfs_link(struct vop_link_args *ap)
1317
{
1318
struct unionfs_node *dunp;
1319
struct unionfs_node *unp;
1320
struct vnode *udvp;
1321
struct vnode *uvp;
1322
struct componentname *cnp;
1323
struct thread *td;
1324
int error;
1325
1326
UNIONFS_INTERNAL_DEBUG("unionfs_link: enter\n");
1327
1328
KASSERT_UNIONFS_VNODE(ap->a_tdvp);
1329
KASSERT_UNIONFS_VNODE(ap->a_vp);
1330
1331
error = 0;
1332
dunp = VTOUNIONFS(ap->a_tdvp);
1333
unp = NULL;
1334
udvp = dunp->un_uppervp;
1335
uvp = NULL;
1336
cnp = ap->a_cnp;
1337
td = curthread;
1338
1339
if (udvp == NULL)
1340
return (EROFS);
1341
1342
unp = VTOUNIONFS(ap->a_vp);
1343
1344
if (unp->un_uppervp == NULL) {
1345
if (ap->a_vp->v_type != VREG)
1346
return (EOPNOTSUPP);
1347
1348
VOP_UNLOCK(ap->a_tdvp);
1349
error = unionfs_copyfile(ap->a_vp, 1, cnp->cn_cred, td);
1350
vn_lock(ap->a_tdvp, LK_EXCLUSIVE | LK_RETRY);
1351
if (error == 0)
1352
error = ERELOOKUP;
1353
return (error);
1354
}
1355
uvp = unp->un_uppervp;
1356
1357
if (error == 0) {
1358
int udvp_lkflags, uvp_lkflags;
1359
unionfs_forward_vop_start_pair(udvp, &udvp_lkflags,
1360
uvp, &uvp_lkflags);
1361
error = VOP_LINK(udvp, uvp, cnp);
1362
unionfs_forward_vop_finish_pair(ap->a_tdvp, udvp, udvp_lkflags,
1363
ap->a_vp, uvp, uvp_lkflags);
1364
}
1365
1366
UNIONFS_INTERNAL_DEBUG("unionfs_link: leave (%d)\n", error);
1367
1368
return (error);
1369
}
1370
1371
static int
1372
unionfs_rename(struct vop_rename_args *ap)
1373
{
1374
struct vnode *fdvp;
1375
struct vnode *fvp;
1376
struct componentname *fcnp;
1377
struct vnode *tdvp;
1378
struct vnode *tvp;
1379
struct componentname *tcnp;
1380
struct thread *td;
1381
1382
/* rename target vnodes */
1383
struct vnode *rfdvp;
1384
struct vnode *rfvp;
1385
struct vnode *rtdvp;
1386
struct vnode *rtvp;
1387
1388
struct unionfs_node *unp;
1389
int error;
1390
1391
UNIONFS_INTERNAL_DEBUG("unionfs_rename: enter\n");
1392
1393
error = 0;
1394
fdvp = ap->a_fdvp;
1395
fvp = ap->a_fvp;
1396
fcnp = ap->a_fcnp;
1397
tdvp = ap->a_tdvp;
1398
tvp = ap->a_tvp;
1399
tcnp = ap->a_tcnp;
1400
td = curthread;
1401
rfdvp = fdvp;
1402
rfvp = fvp;
1403
rtdvp = tdvp;
1404
rtvp = tvp;
1405
1406
/* check for cross device rename */
1407
if (fvp->v_mount != tdvp->v_mount ||
1408
(tvp != NULL && fvp->v_mount != tvp->v_mount)) {
1409
if (fvp->v_op != &unionfs_vnodeops)
1410
error = ENODEV;
1411
else
1412
error = EXDEV;
1413
goto unionfs_rename_abort;
1414
}
1415
1416
/* Renaming a file to itself has no effect. */
1417
if (fvp == tvp)
1418
goto unionfs_rename_abort;
1419
1420
KASSERT_UNIONFS_VNODE(tdvp);
1421
if (tvp != NULL)
1422
KASSERT_UNIONFS_VNODE(tvp);
1423
if (fdvp != tdvp)
1424
VI_LOCK(fdvp);
1425
unp = VTOUNIONFS(fdvp);
1426
if (unp == NULL) {
1427
if (fdvp != tdvp)
1428
VI_UNLOCK(fdvp);
1429
error = ENOENT;
1430
goto unionfs_rename_abort;
1431
}
1432
#ifdef UNIONFS_IDBG_RENAME
1433
UNIONFS_INTERNAL_DEBUG("fdvp=%p, ufdvp=%p, lfdvp=%p\n",
1434
fdvp, unp->un_uppervp, unp->un_lowervp);
1435
#endif
1436
if (unp->un_uppervp == NULL) {
1437
error = ENODEV;
1438
} else {
1439
rfdvp = unp->un_uppervp;
1440
vref(rfdvp);
1441
}
1442
if (fdvp != tdvp)
1443
VI_UNLOCK(fdvp);
1444
if (error != 0)
1445
goto unionfs_rename_abort;
1446
1447
VI_LOCK(fvp);
1448
unp = VTOUNIONFS(fvp);
1449
if (unp == NULL) {
1450
VI_UNLOCK(fvp);
1451
error = ENOENT;
1452
goto unionfs_rename_abort;
1453
}
1454
1455
#ifdef UNIONFS_IDBG_RENAME
1456
UNIONFS_INTERNAL_DEBUG("fvp=%p, ufvp=%p, lfvp=%p\n",
1457
fvp, unp->un_uppervp, unp->un_lowervp);
1458
#endif
1459
/*
1460
* If we only have a lower vnode, copy the source file to the upper
1461
* FS so that the rename operation can be issued against the upper FS.
1462
*/
1463
if (unp->un_uppervp == NULL) {
1464
bool unlock_fdvp = false, relock_tdvp = false;
1465
VI_UNLOCK(fvp);
1466
if (tvp != NULL)
1467
VOP_UNLOCK(tvp);
1468
if (fvp->v_type == VREG) {
1469
/*
1470
* For regular files, unionfs_copyfile() will expect
1471
* fdvp's upper parent directory vnode to be unlocked
1472
* and will temporarily lock it. If fdvp == tdvp, we
1473
* should unlock tdvp to avoid recursion on tdvp's
1474
* lock. If fdvp != tdvp, we should also unlock tdvp
1475
* to avoid potential deadlock due to holding tdvp's
1476
* lock while locking unrelated vnodes associated with
1477
* fdvp/fvp.
1478
*/
1479
VOP_UNLOCK(tdvp);
1480
relock_tdvp = true;
1481
} else if (fvp->v_type == VLNK) {
1482
/*
1483
* The symbolic link case is similar to the
1484
* regular file case.
1485
*/
1486
VOP_UNLOCK(tdvp);
1487
relock_tdvp = true;
1488
} else if (fvp->v_type == VDIR && tdvp != fdvp) {
1489
/*
1490
* For directories, unionfs_mkshadowdir() will expect
1491
* fdvp's upper parent directory vnode to be locked
1492
* and will temporarily unlock it. If fdvp == tdvp,
1493
* we can therefore leave tdvp locked. If fdvp !=
1494
* tdvp, we should exchange the lock on tdvp for a
1495
* lock on fdvp.
1496
*/
1497
VOP_UNLOCK(tdvp);
1498
unlock_fdvp = true;
1499
relock_tdvp = true;
1500
vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
1501
}
1502
vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1503
unp = VTOUNIONFS(fvp);
1504
if (unp == NULL)
1505
error = ENOENT;
1506
else if (unp->un_uppervp == NULL) {
1507
switch (fvp->v_type) {
1508
case VREG:
1509
error = unionfs_copyfile(fvp, 1, fcnp->cn_cred, td);
1510
break;
1511
case VLNK:
1512
error = unionfs_copylink(fvp, fcnp->cn_cred, td);
1513
break;
1514
case VDIR:
1515
error = unionfs_mkshadowdir(fdvp, fvp, fcnp, td);
1516
break;
1517
default:
1518
error = ENODEV;
1519
break;
1520
}
1521
}
1522
VOP_UNLOCK(fvp);
1523
if (unlock_fdvp)
1524
VOP_UNLOCK(fdvp);
1525
if (relock_tdvp)
1526
vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
1527
if (tvp != NULL)
1528
vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1529
/*
1530
* Since we've dropped tdvp's lock at some point in the copy
1531
* sequence above, force the caller to re-drive the lookup
1532
* in case the relationship between tdvp and tvp has changed.
1533
*/
1534
if (error == 0)
1535
error = ERELOOKUP;
1536
goto unionfs_rename_abort;
1537
}
1538
1539
if (unp->un_lowervp != NULL)
1540
fcnp->cn_flags |= DOWHITEOUT;
1541
rfvp = unp->un_uppervp;
1542
vref(rfvp);
1543
1544
VI_UNLOCK(fvp);
1545
1546
unp = VTOUNIONFS(tdvp);
1547
1548
#ifdef UNIONFS_IDBG_RENAME
1549
UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n",
1550
tdvp, unp->un_uppervp, unp->un_lowervp);
1551
#endif
1552
if (unp->un_uppervp == NULL) {
1553
error = ENODEV;
1554
goto unionfs_rename_abort;
1555
}
1556
rtdvp = unp->un_uppervp;
1557
vref(rtdvp);
1558
1559
if (tvp != NULL) {
1560
unp = VTOUNIONFS(tvp);
1561
if (unp == NULL) {
1562
error = ENOENT;
1563
goto unionfs_rename_abort;
1564
}
1565
#ifdef UNIONFS_IDBG_RENAME
1566
UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n",
1567
tvp, unp->un_uppervp, unp->un_lowervp);
1568
#endif
1569
if (unp->un_uppervp == NULL)
1570
rtvp = NULL;
1571
else {
1572
if (tvp->v_type == VDIR) {
1573
error = EINVAL;
1574
goto unionfs_rename_abort;
1575
}
1576
rtvp = unp->un_uppervp;
1577
vref(rtvp);
1578
}
1579
}
1580
1581
if (rfvp == rtvp)
1582
goto unionfs_rename_abort;
1583
1584
error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1585
1586
if (error == 0) {
1587
if (rtvp != NULL && rtvp->v_type == VDIR)
1588
cache_purge(tdvp);
1589
if (fvp->v_type == VDIR && fdvp != tdvp)
1590
cache_purge(fdvp);
1591
}
1592
1593
if (tdvp != rtdvp)
1594
vrele(tdvp);
1595
if (tvp != rtvp && tvp != NULL) {
1596
if (rtvp == NULL)
1597
vput(tvp);
1598
else
1599
vrele(tvp);
1600
}
1601
if (fdvp != rfdvp)
1602
vrele(fdvp);
1603
if (fvp != rfvp)
1604
vrele(fvp);
1605
1606
UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1607
1608
return (error);
1609
1610
unionfs_rename_abort:
1611
vput(tdvp);
1612
if (tdvp != rtdvp)
1613
vrele(rtdvp);
1614
if (tvp != NULL) {
1615
if (tdvp != tvp)
1616
vput(tvp);
1617
else
1618
vrele(tvp);
1619
}
1620
if (tvp != rtvp && rtvp != NULL)
1621
vrele(rtvp);
1622
if (fdvp != rfdvp)
1623
vrele(rfdvp);
1624
if (fvp != rfvp)
1625
vrele(rfvp);
1626
vrele(fdvp);
1627
vrele(fvp);
1628
1629
UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1630
1631
return (error);
1632
}
1633
1634
static int
1635
unionfs_mkdir(struct vop_mkdir_args *ap)
1636
{
1637
struct unionfs_node *dunp;
1638
struct componentname *cnp;
1639
struct vnode *dvp;
1640
struct vnode *udvp;
1641
struct vnode *uvp;
1642
struct vattr va;
1643
int error;
1644
int lkflags;
1645
1646
UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1647
1648
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1649
1650
error = EROFS;
1651
dvp = ap->a_dvp;
1652
dunp = VTOUNIONFS(dvp);
1653
cnp = ap->a_cnp;
1654
lkflags = cnp->cn_lkflags;
1655
udvp = dunp->un_uppervp;
1656
1657
if (udvp != NULL) {
1658
/* check opaque */
1659
if (!(cnp->cn_flags & ISWHITEOUT)) {
1660
error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1661
if (error != 0)
1662
goto unionfs_mkdir_cleanup;
1663
if ((va.va_flags & OPAQUE) != 0)
1664
cnp->cn_flags |= ISWHITEOUT;
1665
}
1666
1667
int udvp_lkflags;
1668
bool uvp_created = false;
1669
unionfs_forward_vop_start(udvp, &udvp_lkflags);
1670
error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap);
1671
if (error == 0)
1672
uvp_created = true;
1673
if (__predict_false(unionfs_forward_vop_finish(dvp, udvp,
1674
udvp_lkflags)) && error == 0)
1675
error = ENOENT;
1676
if (error == 0) {
1677
VOP_UNLOCK(uvp);
1678
cnp->cn_lkflags = LK_EXCLUSIVE;
1679
error = unionfs_nodeget(dvp->v_mount, uvp, NULL,
1680
dvp, ap->a_vpp, cnp);
1681
vrele(uvp);
1682
cnp->cn_lkflags = lkflags;
1683
} else if (uvp_created)
1684
vput(uvp);
1685
}
1686
1687
unionfs_mkdir_cleanup:
1688
UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1689
1690
return (error);
1691
}
1692
1693
static int
1694
unionfs_rmdir(struct vop_rmdir_args *ap)
1695
{
1696
struct unionfs_node *dunp;
1697
struct unionfs_node *unp;
1698
struct unionfs_mount *ump;
1699
struct componentname *cnp;
1700
struct thread *td;
1701
struct vnode *udvp;
1702
struct vnode *uvp;
1703
struct vnode *lvp;
1704
int error;
1705
1706
UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1707
1708
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1709
KASSERT_UNIONFS_VNODE(ap->a_vp);
1710
1711
error = 0;
1712
dunp = VTOUNIONFS(ap->a_dvp);
1713
unp = VTOUNIONFS(ap->a_vp);
1714
cnp = ap->a_cnp;
1715
td = curthread;
1716
udvp = dunp->un_uppervp;
1717
uvp = unp->un_uppervp;
1718
lvp = unp->un_lowervp;
1719
1720
if (udvp == NULL)
1721
return (EROFS);
1722
1723
if (udvp == uvp)
1724
return (EOPNOTSUPP);
1725
1726
if (uvp != NULL) {
1727
if (lvp != NULL) {
1728
/*
1729
* We need to keep dvp and vp's upper vnodes locked
1730
* going into the VOP_RMDIR() call, but the empty
1731
* directory check also requires the lower vnode lock.
1732
* For this third, cross-filesystem lock we use a
1733
* similar approach taken by various FS' VOP_RENAME
1734
* implementations (which require 2-4 vnode locks).
1735
* First we attempt a NOWAIT acquisition, then if
1736
* that fails we drops the other two vnode locks,
1737
* acquire lvp's lock in the normal fashion to reduce
1738
* the likelihood of spinning on it in the future,
1739
* then drop, reacquire the other locks, and return
1740
* ERELOOKUP to re-drive the lookup in case the dvp->
1741
* vp relationship has changed.
1742
*/
1743
if (vn_lock(lvp, LK_SHARED | LK_NOWAIT) != 0) {
1744
VOP_UNLOCK(ap->a_vp);
1745
VOP_UNLOCK(ap->a_dvp);
1746
vn_lock(lvp, LK_SHARED | LK_RETRY);
1747
VOP_UNLOCK(lvp);
1748
vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY);
1749
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1750
return (ERELOOKUP);
1751
}
1752
error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1753
/*
1754
* It's possible for a direct operation on the lower FS
1755
* to make the lower directory non-empty after we drop
1756
* the lock, but it's also possible for the upper-layer
1757
* VOP_RMDIR to relock udvp/uvp which would lead to
1758
* LOR if we kept lvp locked across that call.
1759
*/
1760
VOP_UNLOCK(lvp);
1761
if (error != 0)
1762
return (error);
1763
}
1764
ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1765
if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULL)
1766
cnp->cn_flags |= (DOWHITEOUT | IGNOREWHITEOUT);
1767
int udvp_lkflags, uvp_lkflags;
1768
unionfs_forward_vop_start_pair(udvp, &udvp_lkflags,
1769
uvp, &uvp_lkflags);
1770
error = VOP_RMDIR(udvp, uvp, cnp);
1771
unionfs_forward_vop_finish_pair(ap->a_dvp, udvp, udvp_lkflags,
1772
ap->a_vp, uvp, uvp_lkflags);
1773
} else if (lvp != NULL) {
1774
error = unionfs_mkwhiteout(ap->a_dvp, ap->a_vp, cnp, td,
1775
unp->un_path, unp->un_pathlen);
1776
}
1777
1778
if (error == 0) {
1779
cache_purge(ap->a_dvp);
1780
cache_purge(ap->a_vp);
1781
}
1782
1783
UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1784
1785
return (error);
1786
}
1787
1788
static int
1789
unionfs_symlink(struct vop_symlink_args *ap)
1790
{
1791
struct unionfs_node *dunp;
1792
struct componentname *cnp;
1793
struct vnode *udvp;
1794
struct vnode *uvp;
1795
int error;
1796
int lkflags;
1797
1798
UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1799
1800
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1801
1802
error = EROFS;
1803
dunp = VTOUNIONFS(ap->a_dvp);
1804
cnp = ap->a_cnp;
1805
lkflags = cnp->cn_lkflags;
1806
udvp = dunp->un_uppervp;
1807
1808
if (udvp != NULL) {
1809
int udvp_lkflags;
1810
bool uvp_created = false;
1811
unionfs_forward_vop_start(udvp, &udvp_lkflags);
1812
error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1813
if (error == 0)
1814
uvp_created = true;
1815
if (__predict_false(unionfs_forward_vop_finish(ap->a_dvp, udvp,
1816
udvp_lkflags)) && error == 0)
1817
error = ENOENT;
1818
if (error == 0) {
1819
VOP_UNLOCK(uvp);
1820
cnp->cn_lkflags = LK_EXCLUSIVE;
1821
error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULL,
1822
ap->a_dvp, ap->a_vpp, cnp);
1823
vrele(uvp);
1824
cnp->cn_lkflags = lkflags;
1825
} else if (uvp_created)
1826
vput(uvp);
1827
}
1828
1829
UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1830
1831
return (error);
1832
}
1833
1834
static int
1835
unionfs_readdir(struct vop_readdir_args *ap)
1836
{
1837
struct unionfs_node *unp;
1838
struct unionfs_node_status *unsp;
1839
struct uio *uio;
1840
struct vnode *vp;
1841
struct vnode *uvp;
1842
struct vnode *lvp;
1843
struct thread *td;
1844
struct vattr va;
1845
1846
uint64_t *cookies_bk;
1847
int error;
1848
int eofflag;
1849
int lkflags;
1850
int ncookies_bk;
1851
int uio_offset_bk;
1852
enum unionfs_lkupgrade lkstatus;
1853
1854
UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1855
1856
KASSERT_UNIONFS_VNODE(ap->a_vp);
1857
1858
error = 0;
1859
eofflag = 0;
1860
uio_offset_bk = 0;
1861
uio = ap->a_uio;
1862
uvp = NULL;
1863
lvp = NULL;
1864
td = uio->uio_td;
1865
ncookies_bk = 0;
1866
cookies_bk = NULL;
1867
1868
vp = ap->a_vp;
1869
if (vp->v_type != VDIR)
1870
return (ENOTDIR);
1871
1872
/*
1873
* If the vnode is reclaimed while upgrading, we can't safely use unp
1874
* or do anything else unionfs- specific.
1875
*/
1876
lkstatus = unionfs_upgrade_lock(vp);
1877
if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
1878
error = EBADF;
1879
if (error == 0) {
1880
unp = VTOUNIONFS(vp);
1881
uvp = unp->un_uppervp;
1882
lvp = unp->un_lowervp;
1883
/* check the open count. unionfs needs open before readdir. */
1884
unionfs_get_node_status(unp, td, &unsp);
1885
if ((uvp != NULL && unsp->uns_upper_opencnt <= 0) ||
1886
(lvp != NULL && unsp->uns_lower_opencnt <= 0)) {
1887
unionfs_tryrem_node_status(unp, unsp);
1888
error = EBADF;
1889
}
1890
}
1891
unionfs_downgrade_lock(vp, lkstatus);
1892
if (error != 0)
1893
goto unionfs_readdir_exit;
1894
1895
/* check opaque */
1896
if (uvp != NULL && lvp != NULL) {
1897
if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1898
goto unionfs_readdir_exit;
1899
if (va.va_flags & OPAQUE)
1900
lvp = NULL;
1901
}
1902
1903
/* upper only */
1904
if (uvp != NULL && lvp == NULL) {
1905
unionfs_forward_vop_start(uvp, &lkflags);
1906
error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1907
ap->a_ncookies, ap->a_cookies);
1908
if (unionfs_forward_vop_finish(vp, uvp, lkflags))
1909
error = error ? error : ENOENT;
1910
else
1911
unsp->uns_readdir_status = 0;
1912
1913
goto unionfs_readdir_exit;
1914
}
1915
1916
/* lower only */
1917
if (uvp == NULL && lvp != NULL) {
1918
unionfs_forward_vop_start(lvp, &lkflags);
1919
error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1920
ap->a_ncookies, ap->a_cookies);
1921
if (unionfs_forward_vop_finish(vp, lvp, lkflags))
1922
error = error ? error : ENOENT;
1923
else
1924
unsp->uns_readdir_status = 2;
1925
1926
goto unionfs_readdir_exit;
1927
}
1928
1929
/*
1930
* readdir upper and lower
1931
*/
1932
KASSERT(uvp != NULL, ("unionfs_readdir: null upper vp"));
1933
KASSERT(lvp != NULL, ("unionfs_readdir: null lower vp"));
1934
1935
if (uio->uio_offset == 0)
1936
unsp->uns_readdir_status = 0;
1937
1938
if (unsp->uns_readdir_status == 0) {
1939
/* read upper */
1940
unionfs_forward_vop_start(uvp, &lkflags);
1941
error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1942
ap->a_ncookies, ap->a_cookies);
1943
if (unionfs_forward_vop_finish(vp, uvp, lkflags) && error == 0)
1944
error = ENOENT;
1945
if (error != 0 || eofflag == 0)
1946
goto unionfs_readdir_exit;
1947
unsp->uns_readdir_status = 1;
1948
1949
/*
1950
* UFS(and other FS) needs size of uio_resid larger than
1951
* DIRBLKSIZ.
1952
* size of DIRBLKSIZ equals DEV_BSIZE.
1953
* (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1954
*/
1955
if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1956
goto unionfs_readdir_exit;
1957
1958
/*
1959
* Backup cookies.
1960
* It prepares to readdir in lower.
1961
*/
1962
if (ap->a_ncookies != NULL) {
1963
ncookies_bk = *(ap->a_ncookies);
1964
*(ap->a_ncookies) = 0;
1965
}
1966
if (ap->a_cookies != NULL) {
1967
cookies_bk = *(ap->a_cookies);
1968
*(ap->a_cookies) = NULL;
1969
}
1970
}
1971
1972
/* initialize for readdir in lower */
1973
if (unsp->uns_readdir_status == 1) {
1974
unsp->uns_readdir_status = 2;
1975
/*
1976
* Backup uio_offset. See the comment after the
1977
* VOP_READDIR call on the lower layer.
1978
*/
1979
uio_offset_bk = uio->uio_offset;
1980
uio->uio_offset = 0;
1981
}
1982
1983
lvp = unionfs_lock_lvp(vp, &lkflags);
1984
if (lvp == NULL) {
1985
error = ENOENT;
1986
goto unionfs_readdir_exit;
1987
}
1988
1989
/* read lower */
1990
error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1991
ap->a_ncookies, ap->a_cookies);
1992
1993
1994
unp = unionfs_unlock_lvp(vp, lvp, lkflags);
1995
if (unp == NULL && error == 0)
1996
error = ENOENT;
1997
1998
1999
/*
2000
* We can't return an uio_offset of 0: this would trigger an
2001
* infinite loop, because the next call to unionfs_readdir would
2002
* always restart with the upper layer (uio_offset == 0) and
2003
* always return some data.
2004
*
2005
* This happens when the lower layer root directory is removed.
2006
* (A root directory deleting of unionfs should not be permitted.
2007
* But current VFS can not do it.)
2008
*/
2009
if (uio->uio_offset == 0)
2010
uio->uio_offset = uio_offset_bk;
2011
2012
if (cookies_bk != NULL) {
2013
/* merge cookies */
2014
int size;
2015
uint64_t *newcookies, *pos;
2016
2017
size = *(ap->a_ncookies) + ncookies_bk;
2018
newcookies = (uint64_t *) malloc(size * sizeof(*newcookies),
2019
M_TEMP, M_WAITOK);
2020
pos = newcookies;
2021
2022
memcpy(pos, cookies_bk, ncookies_bk * sizeof(*newcookies));
2023
pos += ncookies_bk;
2024
memcpy(pos, *(ap->a_cookies),
2025
*(ap->a_ncookies) * sizeof(*newcookies));
2026
free(cookies_bk, M_TEMP);
2027
free(*(ap->a_cookies), M_TEMP);
2028
*(ap->a_ncookies) = size;
2029
*(ap->a_cookies) = newcookies;
2030
}
2031
2032
unionfs_readdir_exit:
2033
if (error != 0 && ap->a_eofflag != NULL)
2034
*(ap->a_eofflag) = 1;
2035
2036
UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
2037
2038
return (error);
2039
}
2040
2041
static int
2042
unionfs_readlink(struct vop_readlink_args *ap)
2043
{
2044
struct unionfs_node *unp;
2045
struct vnode *vp;
2046
int error;
2047
2048
UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
2049
2050
KASSERT_UNIONFS_VNODE(ap->a_vp);
2051
2052
unp = VTOUNIONFS(ap->a_vp);
2053
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2054
2055
error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
2056
2057
UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
2058
2059
return (error);
2060
}
2061
2062
static int
2063
unionfs_getwritemount(struct vop_getwritemount_args *ap)
2064
{
2065
struct unionfs_node *unp;
2066
struct vnode *uvp;
2067
struct vnode *vp, *ovp;
2068
int error;
2069
2070
UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
2071
2072
error = 0;
2073
vp = ap->a_vp;
2074
uvp = NULL;
2075
2076
VI_LOCK(vp);
2077
unp = VTOUNIONFS(vp);
2078
if (unp != NULL)
2079
uvp = unp->un_uppervp;
2080
2081
/*
2082
* If our node has no upper vnode, check the parent directory.
2083
* We may be initiating a write operation that will produce a
2084
* new upper vnode through CoW.
2085
*/
2086
if (uvp == NULL && unp != NULL) {
2087
ovp = vp;
2088
vp = unp->un_dvp;
2089
/*
2090
* Only the root vnode should have an empty parent, but it
2091
* should not have an empty uppervp, so we shouldn't get here.
2092
*/
2093
VNASSERT(vp != NULL, ovp, ("%s: NULL parent vnode", __func__));
2094
VI_UNLOCK(ovp);
2095
VI_LOCK(vp);
2096
unp = VTOUNIONFS(vp);
2097
if (unp != NULL)
2098
uvp = unp->un_uppervp;
2099
if (uvp == NULL)
2100
error = EACCES;
2101
}
2102
2103
if (uvp != NULL) {
2104
vholdnz(uvp);
2105
VI_UNLOCK(vp);
2106
error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
2107
vdrop(uvp);
2108
} else {
2109
VI_UNLOCK(vp);
2110
*(ap->a_mpp) = NULL;
2111
}
2112
2113
UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
2114
2115
return (error);
2116
}
2117
2118
static int
2119
unionfs_getlowvnode(struct vop_getlowvnode_args *ap)
2120
{
2121
struct unionfs_node *unp;
2122
struct vnode *vp, *basevp;
2123
2124
vp = ap->a_vp;
2125
VI_LOCK(vp);
2126
unp = VTOUNIONFS(vp);
2127
if (unp == NULL) {
2128
VI_UNLOCK(vp);
2129
return (EBADF);
2130
}
2131
2132
if (ap->a_flags & FWRITE) {
2133
basevp = unp->un_uppervp;
2134
/*
2135
* If write access is being requested, we expect the unionfs
2136
* vnode has already been opened for write access and thus any
2137
* necessary copy-up has already been performed. Return an
2138
* error if that expectation is not met and an upper vnode has
2139
* not been instantiated. We could proactively do a copy-up
2140
* here, but that would require additional locking as well as
2141
* the addition of a 'cred' argument to VOP_GETLOWVNODE().
2142
*/
2143
if (basevp == NULL) {
2144
VI_UNLOCK(vp);
2145
return (EACCES);
2146
}
2147
} else {
2148
basevp = (unp->un_uppervp != NULL) ?
2149
unp->un_uppervp : unp->un_lowervp;
2150
}
2151
2152
VNASSERT(basevp != NULL, vp, ("%s: no upper/lower vnode", __func__));
2153
2154
vholdnz(basevp);
2155
VI_UNLOCK(vp);
2156
VOP_GETLOWVNODE(basevp, ap->a_vplp, ap->a_flags);
2157
vdrop(basevp);
2158
return (0);
2159
}
2160
2161
static int
2162
unionfs_inactive(struct vop_inactive_args *ap)
2163
{
2164
ap->a_vp->v_object = NULL;
2165
vrecycle(ap->a_vp);
2166
return (0);
2167
}
2168
2169
static int
2170
unionfs_reclaim(struct vop_reclaim_args *ap)
2171
{
2172
/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
2173
2174
unionfs_noderem(ap->a_vp);
2175
2176
/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
2177
2178
return (0);
2179
}
2180
2181
static int
2182
unionfs_print(struct vop_print_args *ap)
2183
{
2184
struct unionfs_node *unp;
2185
/* struct unionfs_node_status *unsp; */
2186
2187
unp = VTOUNIONFS(ap->a_vp);
2188
/* unionfs_get_node_status(unp, curthread, &unsp); */
2189
2190
printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
2191
ap->a_vp, unp->un_uppervp, unp->un_lowervp);
2192
/*
2193
printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
2194
unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
2195
*/
2196
2197
if (unp->un_uppervp != NULL)
2198
vn_printf(unp->un_uppervp, "unionfs: upper ");
2199
if (unp->un_lowervp != NULL)
2200
vn_printf(unp->un_lowervp, "unionfs: lower ");
2201
2202
return (0);
2203
}
2204
2205
static int
2206
unionfs_lock(struct vop_lock1_args *ap)
2207
{
2208
struct unionfs_node *unp;
2209
struct vnode *vp;
2210
struct vnode *tvp;
2211
int error;
2212
int flags;
2213
bool lvp_locked;
2214
2215
error = 0;
2216
flags = ap->a_flags;
2217
vp = ap->a_vp;
2218
2219
if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
2220
return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE));
2221
2222
unionfs_lock_restart:
2223
/*
2224
* We currently need the interlock here to ensure we can safely
2225
* access the unionfs vnode's private data. We may be able to
2226
* eliminate this extra locking by instead using vfs_smr_enter()
2227
* and vn_load_v_data_smr() here in conjunction with an SMR UMA
2228
* zone for unionfs nodes.
2229
*/
2230
if ((flags & LK_INTERLOCK) == 0)
2231
VI_LOCK(vp);
2232
else
2233
flags &= ~LK_INTERLOCK;
2234
2235
unp = VTOUNIONFS(vp);
2236
if (unp == NULL) {
2237
VI_UNLOCK(vp);
2238
ap->a_flags = flags;
2239
return (vop_stdlock(ap));
2240
}
2241
2242
if (unp->un_uppervp != NULL) {
2243
tvp = unp->un_uppervp;
2244
lvp_locked = false;
2245
} else {
2246
tvp = unp->un_lowervp;
2247
lvp_locked = true;
2248
}
2249
2250
/*
2251
* During unmount, the root vnode lock may be taken recursively,
2252
* because it may share the same v_vnlock field as the vnode covered by
2253
* the unionfs mount. The covered vnode is locked across VFS_UNMOUNT(),
2254
* and the same lock may be taken recursively here during vflush()
2255
* issued by unionfs_unmount().
2256
*/
2257
if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
2258
(vp->v_vflag & VV_ROOT) != 0)
2259
flags |= LK_CANRECURSE;
2260
2261
vholdnz(tvp);
2262
VI_UNLOCK(vp);
2263
error = VOP_LOCK(tvp, flags);
2264
if (error == 0 && (lvp_locked || VTOUNIONFS(vp) == NULL)) {
2265
/*
2266
* After dropping the interlock above, there exists a window
2267
* in which another thread may acquire the lower vnode lock
2268
* and then either doom the unionfs vnode or create an upper
2269
* vnode. In either case, we will effectively be holding the
2270
* wrong lock, so we must drop the lower vnode lock and
2271
* restart the lock operation.
2272
*
2273
* If unp is not already NULL, we assume that we can safely
2274
* access it because we currently hold lvp's lock.
2275
* unionfs_noderem() acquires lvp's lock before freeing
2276
* the vnode private data, ensuring it can't be concurrently
2277
* freed while we are using it here. Likewise,
2278
* unionfs_node_update() acquires lvp's lock before installing
2279
* an upper vnode. Without those guarantees, we would need to
2280
* reacquire the vnode interlock here.
2281
* Note that unionfs_noderem() doesn't acquire lvp's lock if
2282
* this is the root vnode, but the root vnode should always
2283
* have an upper vnode and therefore we should never use its
2284
* lower vnode lock here.
2285
*/
2286
unp = VTOUNIONFS(vp);
2287
if (unp == NULL || unp->un_uppervp != NULL) {
2288
VOP_UNLOCK(tvp);
2289
vdrop(tvp);
2290
/*
2291
* If we previously held the lock, the upgrade may
2292
* have temporarily dropped the lock, in which case
2293
* concurrent dooming or copy-up will necessitate
2294
* acquiring a different lock. Since we never held
2295
* the new lock, LK_UPGRADE must be cleared here to
2296
* avoid triggering a lockmgr panic.
2297
*/
2298
if (flags & LK_UPGRADE)
2299
flags = (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE;
2300
VNASSERT((flags & LK_DOWNGRADE) == 0, vp,
2301
("%s: vnode doomed during downgrade", __func__));
2302
goto unionfs_lock_restart;
2303
}
2304
}
2305
vdrop(tvp);
2306
2307
return (error);
2308
}
2309
2310
static int
2311
unionfs_unlock(struct vop_unlock_args *ap)
2312
{
2313
struct vnode *vp;
2314
struct vnode *tvp;
2315
struct unionfs_node *unp;
2316
2317
KASSERT_UNIONFS_VNODE(ap->a_vp);
2318
2319
vp = ap->a_vp;
2320
2321
unp = VTOUNIONFS(vp);
2322
if (unp == NULL)
2323
return (vop_stdunlock(ap));
2324
2325
tvp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2326
2327
return (VOP_UNLOCK(tvp));
2328
}
2329
2330
static int
2331
unionfs_pathconf(struct vop_pathconf_args *ap)
2332
{
2333
struct unionfs_node *unp;
2334
struct vnode *vp;
2335
2336
KASSERT_UNIONFS_VNODE(ap->a_vp);
2337
2338
unp = VTOUNIONFS(ap->a_vp);
2339
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2340
2341
return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2342
}
2343
2344
static int
2345
unionfs_advlock(struct vop_advlock_args *ap)
2346
{
2347
struct unionfs_node *unp;
2348
struct unionfs_node_status *unsp;
2349
struct vnode *vp;
2350
struct vnode *uvp;
2351
struct thread *td;
2352
int error;
2353
2354
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2355
2356
KASSERT_UNIONFS_VNODE(ap->a_vp);
2357
2358
vp = ap->a_vp;
2359
td = curthread;
2360
2361
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2362
2363
unp = VTOUNIONFS(ap->a_vp);
2364
uvp = unp->un_uppervp;
2365
2366
if (uvp == NULL) {
2367
error = unionfs_copyfile(ap->a_vp, 1, td->td_ucred, td);
2368
if (error != 0)
2369
goto unionfs_advlock_abort;
2370
uvp = unp->un_uppervp;
2371
2372
unionfs_get_node_status(unp, td, &unsp);
2373
if (unsp->uns_lower_opencnt > 0) {
2374
/* try reopen the vnode */
2375
error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2376
td->td_ucred, td, NULL);
2377
if (error)
2378
goto unionfs_advlock_abort;
2379
unsp->uns_upper_opencnt++;
2380
VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode,
2381
td->td_ucred, td);
2382
unsp->uns_lower_opencnt--;
2383
} else
2384
unionfs_tryrem_node_status(unp, unsp);
2385
}
2386
2387
VOP_UNLOCK(vp);
2388
2389
error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2390
2391
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2392
2393
return error;
2394
2395
unionfs_advlock_abort:
2396
VOP_UNLOCK(vp);
2397
2398
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2399
2400
return error;
2401
}
2402
2403
static int
2404
unionfs_strategy(struct vop_strategy_args *ap)
2405
{
2406
struct unionfs_node *unp;
2407
struct vnode *vp;
2408
2409
KASSERT_UNIONFS_VNODE(ap->a_vp);
2410
2411
unp = VTOUNIONFS(ap->a_vp);
2412
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2413
2414
#ifdef DIAGNOSTIC
2415
if (vp == NULL)
2416
panic("unionfs_strategy: nullvp");
2417
2418
if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2419
panic("unionfs_strategy: writing to lowervp");
2420
#endif
2421
2422
return (VOP_STRATEGY(vp, ap->a_bp));
2423
}
2424
2425
static int
2426
unionfs_getacl(struct vop_getacl_args *ap)
2427
{
2428
struct unionfs_node *unp;
2429
struct vnode *vp;
2430
int error;
2431
2432
KASSERT_UNIONFS_VNODE(ap->a_vp);
2433
2434
unp = VTOUNIONFS(ap->a_vp);
2435
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2436
2437
UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2438
2439
error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2440
2441
UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2442
2443
return (error);
2444
}
2445
2446
static int
2447
unionfs_setacl(struct vop_setacl_args *ap)
2448
{
2449
struct unionfs_node *unp;
2450
struct vnode *uvp;
2451
struct vnode *lvp;
2452
struct thread *td;
2453
int error;
2454
2455
UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2456
2457
KASSERT_UNIONFS_VNODE(ap->a_vp);
2458
2459
error = EROFS;
2460
unp = VTOUNIONFS(ap->a_vp);
2461
uvp = unp->un_uppervp;
2462
lvp = unp->un_lowervp;
2463
td = ap->a_td;
2464
2465
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2466
return (EROFS);
2467
2468
if (uvp == NULL && lvp->v_type == VREG) {
2469
if ((error = unionfs_copyfile(ap->a_vp, 1, ap->a_cred, td)) != 0)
2470
return (error);
2471
uvp = unp->un_uppervp;
2472
}
2473
2474
if (uvp != NULL) {
2475
int lkflags;
2476
unionfs_forward_vop_start(uvp, &lkflags);
2477
error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2478
unionfs_forward_vop_finish(ap->a_vp, uvp, lkflags);
2479
}
2480
2481
UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2482
2483
return (error);
2484
}
2485
2486
static int
2487
unionfs_aclcheck(struct vop_aclcheck_args *ap)
2488
{
2489
struct unionfs_node *unp;
2490
struct vnode *vp;
2491
int error;
2492
2493
UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2494
2495
KASSERT_UNIONFS_VNODE(ap->a_vp);
2496
2497
unp = VTOUNIONFS(ap->a_vp);
2498
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2499
2500
error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2501
2502
UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2503
2504
return (error);
2505
}
2506
2507
static int
2508
unionfs_openextattr(struct vop_openextattr_args *ap)
2509
{
2510
struct unionfs_node *unp;
2511
struct vnode *vp;
2512
struct vnode *tvp;
2513
int error;
2514
2515
KASSERT_UNIONFS_VNODE(ap->a_vp);
2516
2517
vp = ap->a_vp;
2518
unp = VTOUNIONFS(vp);
2519
tvp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2520
2521
if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2522
(tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2523
return (EBUSY);
2524
2525
error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2526
2527
if (error == 0) {
2528
if (vn_lock(vp, LK_UPGRADE) != 0)
2529
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2530
if (!VN_IS_DOOMED(vp)) {
2531
if (tvp == unp->un_uppervp)
2532
unp->un_flag |= UNIONFS_OPENEXTU;
2533
else
2534
unp->un_flag |= UNIONFS_OPENEXTL;
2535
}
2536
vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2537
}
2538
2539
return (error);
2540
}
2541
2542
static int
2543
unionfs_closeextattr(struct vop_closeextattr_args *ap)
2544
{
2545
struct unionfs_node *unp;
2546
struct vnode *vp;
2547
struct vnode *tvp;
2548
int error;
2549
2550
KASSERT_UNIONFS_VNODE(ap->a_vp);
2551
2552
vp = ap->a_vp;
2553
unp = VTOUNIONFS(vp);
2554
tvp = NULL;
2555
2556
if (unp->un_flag & UNIONFS_OPENEXTU)
2557
tvp = unp->un_uppervp;
2558
else if (unp->un_flag & UNIONFS_OPENEXTL)
2559
tvp = unp->un_lowervp;
2560
2561
if (tvp == NULL)
2562
return (EOPNOTSUPP);
2563
2564
error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2565
2566
if (error == 0) {
2567
if (vn_lock(vp, LK_UPGRADE) != 0)
2568
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2569
if (!VN_IS_DOOMED(vp)) {
2570
if (tvp == unp->un_uppervp)
2571
unp->un_flag &= ~UNIONFS_OPENEXTU;
2572
else
2573
unp->un_flag &= ~UNIONFS_OPENEXTL;
2574
}
2575
vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2576
}
2577
2578
return (error);
2579
}
2580
2581
static int
2582
unionfs_getextattr(struct vop_getextattr_args *ap)
2583
{
2584
struct unionfs_node *unp;
2585
struct vnode *vp;
2586
2587
KASSERT_UNIONFS_VNODE(ap->a_vp);
2588
2589
unp = VTOUNIONFS(ap->a_vp);
2590
vp = NULL;
2591
2592
if (unp->un_flag & UNIONFS_OPENEXTU)
2593
vp = unp->un_uppervp;
2594
else if (unp->un_flag & UNIONFS_OPENEXTL)
2595
vp = unp->un_lowervp;
2596
2597
if (vp == NULL)
2598
return (EOPNOTSUPP);
2599
2600
return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2601
ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2602
}
2603
2604
static int
2605
unionfs_setextattr(struct vop_setextattr_args *ap)
2606
{
2607
struct unionfs_node *unp;
2608
struct vnode *uvp;
2609
struct vnode *lvp;
2610
struct vnode *ovp;
2611
struct ucred *cred;
2612
struct thread *td;
2613
int error;
2614
2615
KASSERT_UNIONFS_VNODE(ap->a_vp);
2616
2617
error = EROFS;
2618
unp = VTOUNIONFS(ap->a_vp);
2619
uvp = unp->un_uppervp;
2620
lvp = unp->un_lowervp;
2621
ovp = NULL;
2622
cred = ap->a_cred;
2623
td = ap->a_td;
2624
2625
UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n",
2626
unp->un_flag);
2627
2628
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2629
return (EROFS);
2630
2631
if (unp->un_flag & UNIONFS_OPENEXTU)
2632
ovp = unp->un_uppervp;
2633
else if (unp->un_flag & UNIONFS_OPENEXTL)
2634
ovp = unp->un_lowervp;
2635
2636
if (ovp == NULL)
2637
return (EOPNOTSUPP);
2638
2639
if (ovp == lvp && lvp->v_type == VREG) {
2640
VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2641
if (uvp == NULL &&
2642
(error = unionfs_copyfile(ap->a_vp, 1, cred, td)) != 0) {
2643
unionfs_setextattr_reopen:
2644
unp = VTOUNIONFS(ap->a_vp);
2645
if (unp != NULL && (unp->un_flag & UNIONFS_OPENEXTL) &&
2646
VOP_OPENEXTATTR(lvp, cred, td)) {
2647
#ifdef DIAGNOSTIC
2648
panic("unionfs: VOP_OPENEXTATTR failed");
2649
#endif
2650
unp->un_flag &= ~UNIONFS_OPENEXTL;
2651
}
2652
goto unionfs_setextattr_abort;
2653
}
2654
uvp = unp->un_uppervp;
2655
if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2656
goto unionfs_setextattr_reopen;
2657
unp->un_flag &= ~UNIONFS_OPENEXTL;
2658
unp->un_flag |= UNIONFS_OPENEXTU;
2659
ovp = uvp;
2660
}
2661
2662
if (ovp == uvp) {
2663
int lkflags;
2664
unionfs_forward_vop_start(ovp, &lkflags);
2665
error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2666
ap->a_uio, cred, td);
2667
unionfs_forward_vop_finish(ap->a_vp, ovp, lkflags);
2668
}
2669
2670
unionfs_setextattr_abort:
2671
UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2672
2673
return (error);
2674
}
2675
2676
static int
2677
unionfs_listextattr(struct vop_listextattr_args *ap)
2678
{
2679
struct unionfs_node *unp;
2680
struct vnode *vp;
2681
2682
KASSERT_UNIONFS_VNODE(ap->a_vp);
2683
2684
unp = VTOUNIONFS(ap->a_vp);
2685
vp = NULL;
2686
2687
if (unp->un_flag & UNIONFS_OPENEXTU)
2688
vp = unp->un_uppervp;
2689
else if (unp->un_flag & UNIONFS_OPENEXTL)
2690
vp = unp->un_lowervp;
2691
2692
if (vp == NULL)
2693
return (EOPNOTSUPP);
2694
2695
return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2696
ap->a_size, ap->a_cred, ap->a_td));
2697
}
2698
2699
static int
2700
unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2701
{
2702
struct unionfs_node *unp;
2703
struct vnode *uvp;
2704
struct vnode *lvp;
2705
struct vnode *ovp;
2706
struct ucred *cred;
2707
struct thread *td;
2708
int error;
2709
2710
KASSERT_UNIONFS_VNODE(ap->a_vp);
2711
2712
error = EROFS;
2713
unp = VTOUNIONFS(ap->a_vp);
2714
uvp = unp->un_uppervp;
2715
lvp = unp->un_lowervp;
2716
ovp = NULL;
2717
cred = ap->a_cred;
2718
td = ap->a_td;
2719
2720
UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n",
2721
unp->un_flag);
2722
2723
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2724
return (EROFS);
2725
2726
if (unp->un_flag & UNIONFS_OPENEXTU)
2727
ovp = unp->un_uppervp;
2728
else if (unp->un_flag & UNIONFS_OPENEXTL)
2729
ovp = unp->un_lowervp;
2730
2731
if (ovp == NULL)
2732
return (EOPNOTSUPP);
2733
2734
if (ovp == lvp && lvp->v_type == VREG) {
2735
VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2736
if (uvp == NULL &&
2737
(error = unionfs_copyfile(ap->a_vp, 1, cred, td)) != 0) {
2738
unionfs_deleteextattr_reopen:
2739
unp = VTOUNIONFS(ap->a_vp);
2740
if (unp != NULL && (unp->un_flag & UNIONFS_OPENEXTL) &&
2741
VOP_OPENEXTATTR(lvp, cred, td)) {
2742
#ifdef DIAGNOSTIC
2743
panic("unionfs: VOP_OPENEXTATTR failed");
2744
#endif
2745
unp->un_flag &= ~UNIONFS_OPENEXTL;
2746
}
2747
goto unionfs_deleteextattr_abort;
2748
}
2749
uvp = unp->un_uppervp;
2750
if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2751
goto unionfs_deleteextattr_reopen;
2752
unp->un_flag &= ~UNIONFS_OPENEXTL;
2753
unp->un_flag |= UNIONFS_OPENEXTU;
2754
ovp = uvp;
2755
}
2756
2757
if (ovp == uvp)
2758
error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2759
ap->a_cred, ap->a_td);
2760
2761
unionfs_deleteextattr_abort:
2762
UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2763
2764
return (error);
2765
}
2766
2767
static int
2768
unionfs_setlabel(struct vop_setlabel_args *ap)
2769
{
2770
struct unionfs_node *unp;
2771
struct vnode *uvp;
2772
struct vnode *lvp;
2773
struct thread *td;
2774
int error;
2775
2776
UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2777
2778
KASSERT_UNIONFS_VNODE(ap->a_vp);
2779
2780
error = EROFS;
2781
unp = VTOUNIONFS(ap->a_vp);
2782
uvp = unp->un_uppervp;
2783
lvp = unp->un_lowervp;
2784
td = ap->a_td;
2785
2786
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2787
return (EROFS);
2788
2789
if (uvp == NULL && lvp->v_type == VREG) {
2790
if ((error = unionfs_copyfile(ap->a_vp, 1, ap->a_cred, td)) != 0)
2791
return (error);
2792
uvp = unp->un_uppervp;
2793
}
2794
2795
if (uvp != NULL)
2796
error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2797
2798
UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2799
2800
return (error);
2801
}
2802
2803
static int
2804
unionfs_vptofh(struct vop_vptofh_args *ap)
2805
{
2806
return (EOPNOTSUPP);
2807
}
2808
2809
static int
2810
unionfs_add_writecount(struct vop_add_writecount_args *ap)
2811
{
2812
struct vnode *tvp, *vp;
2813
struct unionfs_node *unp;
2814
int error, writerefs __diagused;
2815
2816
vp = ap->a_vp;
2817
unp = VTOUNIONFS(vp);
2818
tvp = unp->un_uppervp;
2819
KASSERT(tvp != NULL,
2820
("%s: adding write ref without upper vnode", __func__));
2821
error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
2822
if (error != 0)
2823
return (error);
2824
/*
2825
* We need to track the write refs we've passed to the underlying
2826
* vnodes so that we can undo them in case we are forcibly unmounted.
2827
*/
2828
writerefs = atomic_fetchadd_int(&vp->v_writecount, ap->a_inc);
2829
/* text refs are bypassed to lowervp */
2830
VNASSERT(writerefs >= 0, vp,
2831
("%s: invalid write count %d", __func__, writerefs));
2832
VNASSERT(writerefs + ap->a_inc >= 0, vp,
2833
("%s: invalid write count inc %d + %d", __func__,
2834
writerefs, ap->a_inc));
2835
return (0);
2836
}
2837
2838
static int
2839
unionfs_vput_pair(struct vop_vput_pair_args *ap)
2840
{
2841
struct mount *mp;
2842
struct vnode *dvp, *vp, **vpp, *lvp, *uvp, *tvp, *tdvp, *tempvp;
2843
struct unionfs_node *dunp, *unp;
2844
int error, res;
2845
2846
dvp = ap->a_dvp;
2847
vpp = ap->a_vpp;
2848
vp = NULL;
2849
lvp = NULL;
2850
uvp = NULL;
2851
tvp = NULL;
2852
unp = NULL;
2853
2854
dunp = VTOUNIONFS(dvp);
2855
if (dunp->un_uppervp != NULL)
2856
tdvp = dunp->un_uppervp;
2857
else
2858
tdvp = dunp->un_lowervp;
2859
2860
/*
2861
* Underlying vnodes should be locked because the encompassing unionfs
2862
* node is locked, but will not be referenced, as the reference will
2863
* only be on the unionfs node. Reference them now so that the vput()s
2864
* performed by VOP_VPUT_PAIR() will have a reference to drop.
2865
*/
2866
vref(tdvp);
2867
2868
if (vpp != NULL)
2869
vp = *vpp;
2870
2871
if (vp != NULL) {
2872
unp = VTOUNIONFS(vp);
2873
uvp = unp->un_uppervp;
2874
lvp = unp->un_lowervp;
2875
if (uvp != NULL)
2876
tvp = uvp;
2877
else
2878
tvp = lvp;
2879
vref(tvp);
2880
2881
/*
2882
* If we're being asked to return a locked child vnode, then
2883
* we may need to create a replacement vnode in case the
2884
* original is reclaimed while the lock is dropped. In that
2885
* case we'll need to ensure the mount and the underlying
2886
* vnodes aren't also recycled during that window.
2887
*/
2888
if (!ap->a_unlock_vp) {
2889
vhold(vp);
2890
if (uvp != NULL)
2891
vhold(uvp);
2892
if (lvp != NULL)
2893
vhold(lvp);
2894
mp = vp->v_mount;
2895
vfs_ref(mp);
2896
}
2897
}
2898
2899
ASSERT_VOP_LOCKED(tdvp, __func__);
2900
ASSERT_VOP_LOCKED(tvp, __func__);
2901
2902
if (tdvp == dunp->un_uppervp && tvp != NULL && tvp == lvp) {
2903
vput(tvp);
2904
vput(tdvp);
2905
res = 0;
2906
} else {
2907
res = VOP_VPUT_PAIR(tdvp, tvp != NULL ? &tvp : NULL, true);
2908
}
2909
2910
ASSERT_VOP_UNLOCKED(tdvp, __func__);
2911
ASSERT_VOP_UNLOCKED(tvp, __func__);
2912
2913
/*
2914
* VOP_VPUT_PAIR() dropped the references we added to the underlying
2915
* vnodes, now drop the caller's reference to the unionfs vnodes.
2916
*/
2917
if (vp != NULL && ap->a_unlock_vp)
2918
vrele(vp);
2919
vrele(dvp);
2920
2921
if (vp == NULL || ap->a_unlock_vp)
2922
return (res);
2923
2924
/*
2925
* We're being asked to return a locked vnode. At this point, the
2926
* underlying vnodes have been unlocked, so vp may have been reclaimed.
2927
*/
2928
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2929
if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) {
2930
vput(vp);
2931
error = unionfs_nodeget(mp, uvp, lvp, dvp, &tempvp, NULL);
2932
if (error == 0) {
2933
vn_lock(tempvp, LK_EXCLUSIVE | LK_RETRY);
2934
*vpp = tempvp;
2935
} else
2936
vget(vp, LK_EXCLUSIVE | LK_RETRY);
2937
vfs_unbusy(mp);
2938
}
2939
if (lvp != NULL)
2940
vdrop(lvp);
2941
if (uvp != NULL)
2942
vdrop(uvp);
2943
vdrop(vp);
2944
vfs_rel(mp);
2945
2946
return (res);
2947
}
2948
2949
static int
2950
unionfs_set_text(struct vop_set_text_args *ap)
2951
{
2952
struct vnode *tvp;
2953
struct unionfs_node *unp;
2954
int error;
2955
2956
/*
2957
* We assume text refs are managed against lvp/uvp through the
2958
* executable mapping backed by its VM object. We therefore don't
2959
* need to track leased text refs in the case of a forcible unmount.
2960
*/
2961
unp = VTOUNIONFS(ap->a_vp);
2962
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2963
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2964
error = VOP_SET_TEXT(tvp);
2965
return (error);
2966
}
2967
2968
static int
2969
unionfs_unset_text(struct vop_unset_text_args *ap)
2970
{
2971
struct vnode *tvp;
2972
struct unionfs_node *unp;
2973
2974
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2975
unp = VTOUNIONFS(ap->a_vp);
2976
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2977
VOP_UNSET_TEXT_CHECKED(tvp);
2978
return (0);
2979
}
2980
2981
static int
2982
unionfs_unp_bind(struct vop_unp_bind_args *ap)
2983
{
2984
struct vnode *tvp;
2985
struct unionfs_node *unp;
2986
2987
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2988
unp = VTOUNIONFS(ap->a_vp);
2989
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2990
VOP_UNP_BIND(tvp, ap->a_unpcb);
2991
return (0);
2992
}
2993
2994
static int
2995
unionfs_unp_connect(struct vop_unp_connect_args *ap)
2996
{
2997
struct vnode *tvp;
2998
struct unionfs_node *unp;
2999
3000
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
3001
unp = VTOUNIONFS(ap->a_vp);
3002
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
3003
VOP_UNP_CONNECT(tvp, ap->a_unpcb);
3004
return (0);
3005
}
3006
3007
static int
3008
unionfs_unp_detach(struct vop_unp_detach_args *ap)
3009
{
3010
struct vnode *tvp;
3011
struct unionfs_node *unp;
3012
3013
tvp = NULL;
3014
/*
3015
* VOP_UNP_DETACH() is not guaranteed to be called with the unionfs
3016
* vnode locked, so we take the interlock to prevent a concurrent
3017
* unmount from freeing the unionfs private data.
3018
*/
3019
VI_LOCK(ap->a_vp);
3020
unp = VTOUNIONFS(ap->a_vp);
3021
if (unp != NULL) {
3022
tvp = unp->un_uppervp != NULL ?
3023
unp->un_uppervp : unp->un_lowervp;
3024
/*
3025
* Hold the target vnode to prevent a concurrent unionfs
3026
* unmount from causing it to be recycled once the interlock
3027
* is dropped.
3028
*/
3029
vholdnz(tvp);
3030
}
3031
VI_UNLOCK(ap->a_vp);
3032
if (tvp != NULL) {
3033
VOP_UNP_DETACH(tvp);
3034
vdrop(tvp);
3035
}
3036
return (0);
3037
}
3038
3039
struct vop_vector unionfs_vnodeops = {
3040
.vop_default = &default_vnodeops,
3041
3042
.vop_access = unionfs_access,
3043
.vop_aclcheck = unionfs_aclcheck,
3044
.vop_advlock = unionfs_advlock,
3045
.vop_bmap = VOP_EOPNOTSUPP,
3046
.vop_cachedlookup = unionfs_lookup,
3047
.vop_close = unionfs_close,
3048
.vop_closeextattr = unionfs_closeextattr,
3049
.vop_create = unionfs_create,
3050
.vop_deleteextattr = unionfs_deleteextattr,
3051
.vop_fsync = unionfs_fsync,
3052
.vop_getacl = unionfs_getacl,
3053
.vop_getattr = unionfs_getattr,
3054
.vop_getextattr = unionfs_getextattr,
3055
.vop_getwritemount = unionfs_getwritemount,
3056
.vop_getlowvnode = unionfs_getlowvnode,
3057
.vop_inactive = unionfs_inactive,
3058
.vop_need_inactive = vop_stdneed_inactive,
3059
.vop_islocked = vop_stdislocked,
3060
.vop_ioctl = unionfs_ioctl,
3061
.vop_link = unionfs_link,
3062
.vop_listextattr = unionfs_listextattr,
3063
.vop_lock1 = unionfs_lock,
3064
.vop_lookup = vfs_cache_lookup,
3065
.vop_mkdir = unionfs_mkdir,
3066
.vop_mknod = unionfs_mknod,
3067
.vop_open = unionfs_open,
3068
.vop_openextattr = unionfs_openextattr,
3069
.vop_pathconf = unionfs_pathconf,
3070
.vop_poll = unionfs_poll,
3071
.vop_print = unionfs_print,
3072
.vop_read = unionfs_read,
3073
.vop_readdir = unionfs_readdir,
3074
.vop_readlink = unionfs_readlink,
3075
.vop_reclaim = unionfs_reclaim,
3076
.vop_remove = unionfs_remove,
3077
.vop_rename = unionfs_rename,
3078
.vop_rmdir = unionfs_rmdir,
3079
.vop_setacl = unionfs_setacl,
3080
.vop_setattr = unionfs_setattr,
3081
.vop_setextattr = unionfs_setextattr,
3082
.vop_setlabel = unionfs_setlabel,
3083
.vop_strategy = unionfs_strategy,
3084
.vop_symlink = unionfs_symlink,
3085
.vop_unlock = unionfs_unlock,
3086
.vop_whiteout = unionfs_whiteout,
3087
.vop_write = unionfs_write,
3088
.vop_vptofh = unionfs_vptofh,
3089
.vop_add_writecount = unionfs_add_writecount,
3090
.vop_vput_pair = unionfs_vput_pair,
3091
.vop_set_text = unionfs_set_text,
3092
.vop_unset_text = unionfs_unset_text,
3093
.vop_unp_bind = unionfs_unp_bind,
3094
.vop_unp_connect = unionfs_unp_connect,
3095
.vop_unp_detach = unionfs_unp_detach,
3096
.vop_copy_file_range = vop_stdcopy_file_range,
3097
};
3098
VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);
3099
3100