Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/unionfs/union_vnops.c
39478 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 = unionfs_find_node_status(unp, td);
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 == VDIR && tdvp != fdvp) {
1482
/*
1483
* For directories, unionfs_mkshadowdir() will expect
1484
* fdvp's upper parent directory vnode to be locked
1485
* and will temporarily unlock it. If fdvp == tdvp,
1486
* we can therefore leave tdvp locked. If fdvp !=
1487
* tdvp, we should exchange the lock on tdvp for a
1488
* lock on fdvp.
1489
*/
1490
VOP_UNLOCK(tdvp);
1491
unlock_fdvp = true;
1492
relock_tdvp = true;
1493
vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
1494
}
1495
vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
1496
unp = VTOUNIONFS(fvp);
1497
if (unp == NULL)
1498
error = ENOENT;
1499
else if (unp->un_uppervp == NULL) {
1500
switch (fvp->v_type) {
1501
case VREG:
1502
error = unionfs_copyfile(fvp, 1, fcnp->cn_cred, td);
1503
break;
1504
case VDIR:
1505
error = unionfs_mkshadowdir(fdvp, fvp, fcnp, td);
1506
break;
1507
default:
1508
error = ENODEV;
1509
break;
1510
}
1511
}
1512
VOP_UNLOCK(fvp);
1513
if (unlock_fdvp)
1514
VOP_UNLOCK(fdvp);
1515
if (relock_tdvp)
1516
vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
1517
if (tvp != NULL)
1518
vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
1519
/*
1520
* Since we've dropped tdvp's lock at some point in the copy
1521
* sequence above, force the caller to re-drive the lookup
1522
* in case the relationship between tdvp and tvp has changed.
1523
*/
1524
if (error == 0)
1525
error = ERELOOKUP;
1526
goto unionfs_rename_abort;
1527
}
1528
1529
if (unp->un_lowervp != NULL)
1530
fcnp->cn_flags |= DOWHITEOUT;
1531
rfvp = unp->un_uppervp;
1532
vref(rfvp);
1533
1534
VI_UNLOCK(fvp);
1535
1536
unp = VTOUNIONFS(tdvp);
1537
1538
#ifdef UNIONFS_IDBG_RENAME
1539
UNIONFS_INTERNAL_DEBUG("tdvp=%p, utdvp=%p, ltdvp=%p\n",
1540
tdvp, unp->un_uppervp, unp->un_lowervp);
1541
#endif
1542
if (unp->un_uppervp == NULL) {
1543
error = ENODEV;
1544
goto unionfs_rename_abort;
1545
}
1546
rtdvp = unp->un_uppervp;
1547
vref(rtdvp);
1548
1549
if (tvp != NULL) {
1550
unp = VTOUNIONFS(tvp);
1551
if (unp == NULL) {
1552
error = ENOENT;
1553
goto unionfs_rename_abort;
1554
}
1555
#ifdef UNIONFS_IDBG_RENAME
1556
UNIONFS_INTERNAL_DEBUG("tvp=%p, utvp=%p, ltvp=%p\n",
1557
tvp, unp->un_uppervp, unp->un_lowervp);
1558
#endif
1559
if (unp->un_uppervp == NULL)
1560
rtvp = NULL;
1561
else {
1562
if (tvp->v_type == VDIR) {
1563
error = EINVAL;
1564
goto unionfs_rename_abort;
1565
}
1566
rtvp = unp->un_uppervp;
1567
vref(rtvp);
1568
}
1569
}
1570
1571
if (rfvp == rtvp)
1572
goto unionfs_rename_abort;
1573
1574
error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
1575
1576
if (error == 0) {
1577
if (rtvp != NULL && rtvp->v_type == VDIR)
1578
cache_purge(tdvp);
1579
if (fvp->v_type == VDIR && fdvp != tdvp)
1580
cache_purge(fdvp);
1581
}
1582
1583
if (tdvp != rtdvp)
1584
vrele(tdvp);
1585
if (tvp != rtvp && tvp != NULL) {
1586
if (rtvp == NULL)
1587
vput(tvp);
1588
else
1589
vrele(tvp);
1590
}
1591
if (fdvp != rfdvp)
1592
vrele(fdvp);
1593
if (fvp != rfvp)
1594
vrele(fvp);
1595
1596
UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1597
1598
return (error);
1599
1600
unionfs_rename_abort:
1601
vput(tdvp);
1602
if (tdvp != rtdvp)
1603
vrele(rtdvp);
1604
if (tvp != NULL) {
1605
if (tdvp != tvp)
1606
vput(tvp);
1607
else
1608
vrele(tvp);
1609
}
1610
if (tvp != rtvp && rtvp != NULL)
1611
vrele(rtvp);
1612
if (fdvp != rfdvp)
1613
vrele(rfdvp);
1614
if (fvp != rfvp)
1615
vrele(rfvp);
1616
vrele(fdvp);
1617
vrele(fvp);
1618
1619
UNIONFS_INTERNAL_DEBUG("unionfs_rename: leave (%d)\n", error);
1620
1621
return (error);
1622
}
1623
1624
static int
1625
unionfs_mkdir(struct vop_mkdir_args *ap)
1626
{
1627
struct unionfs_node *dunp;
1628
struct componentname *cnp;
1629
struct vnode *dvp;
1630
struct vnode *udvp;
1631
struct vnode *uvp;
1632
struct vattr va;
1633
int error;
1634
int lkflags;
1635
1636
UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");
1637
1638
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1639
1640
error = EROFS;
1641
dvp = ap->a_dvp;
1642
dunp = VTOUNIONFS(dvp);
1643
cnp = ap->a_cnp;
1644
lkflags = cnp->cn_lkflags;
1645
udvp = dunp->un_uppervp;
1646
1647
if (udvp != NULL) {
1648
/* check opaque */
1649
if (!(cnp->cn_flags & ISWHITEOUT)) {
1650
error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
1651
if (error != 0)
1652
goto unionfs_mkdir_cleanup;
1653
if ((va.va_flags & OPAQUE) != 0)
1654
cnp->cn_flags |= ISWHITEOUT;
1655
}
1656
1657
int udvp_lkflags;
1658
bool uvp_created = false;
1659
unionfs_forward_vop_start(udvp, &udvp_lkflags);
1660
error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap);
1661
if (error == 0)
1662
uvp_created = true;
1663
if (__predict_false(unionfs_forward_vop_finish(dvp, udvp,
1664
udvp_lkflags)) && error == 0)
1665
error = ENOENT;
1666
if (error == 0) {
1667
VOP_UNLOCK(uvp);
1668
cnp->cn_lkflags = LK_EXCLUSIVE;
1669
error = unionfs_nodeget(dvp->v_mount, uvp, NULL,
1670
dvp, ap->a_vpp, cnp);
1671
vrele(uvp);
1672
cnp->cn_lkflags = lkflags;
1673
} else if (uvp_created)
1674
vput(uvp);
1675
}
1676
1677
unionfs_mkdir_cleanup:
1678
UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);
1679
1680
return (error);
1681
}
1682
1683
static int
1684
unionfs_rmdir(struct vop_rmdir_args *ap)
1685
{
1686
struct unionfs_node *dunp;
1687
struct unionfs_node *unp;
1688
struct unionfs_mount *ump;
1689
struct componentname *cnp;
1690
struct thread *td;
1691
struct vnode *udvp;
1692
struct vnode *uvp;
1693
struct vnode *lvp;
1694
int error;
1695
1696
UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: enter\n");
1697
1698
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1699
KASSERT_UNIONFS_VNODE(ap->a_vp);
1700
1701
error = 0;
1702
dunp = VTOUNIONFS(ap->a_dvp);
1703
unp = VTOUNIONFS(ap->a_vp);
1704
cnp = ap->a_cnp;
1705
td = curthread;
1706
udvp = dunp->un_uppervp;
1707
uvp = unp->un_uppervp;
1708
lvp = unp->un_lowervp;
1709
1710
if (udvp == NULL)
1711
return (EROFS);
1712
1713
if (udvp == uvp)
1714
return (EOPNOTSUPP);
1715
1716
if (uvp != NULL) {
1717
if (lvp != NULL) {
1718
/*
1719
* We need to keep dvp and vp's upper vnodes locked
1720
* going into the VOP_RMDIR() call, but the empty
1721
* directory check also requires the lower vnode lock.
1722
* For this third, cross-filesystem lock we use a
1723
* similar approach taken by various FS' VOP_RENAME
1724
* implementations (which require 2-4 vnode locks).
1725
* First we attempt a NOWAIT acquisition, then if
1726
* that fails we drops the other two vnode locks,
1727
* acquire lvp's lock in the normal fashion to reduce
1728
* the likelihood of spinning on it in the future,
1729
* then drop, reacquire the other locks, and return
1730
* ERELOOKUP to re-drive the lookup in case the dvp->
1731
* vp relationship has changed.
1732
*/
1733
if (vn_lock(lvp, LK_SHARED | LK_NOWAIT) != 0) {
1734
VOP_UNLOCK(ap->a_vp);
1735
VOP_UNLOCK(ap->a_dvp);
1736
vn_lock(lvp, LK_SHARED | LK_RETRY);
1737
VOP_UNLOCK(lvp);
1738
vn_lock(ap->a_dvp, LK_EXCLUSIVE | LK_RETRY);
1739
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY);
1740
return (ERELOOKUP);
1741
}
1742
error = unionfs_check_rmdir(ap->a_vp, cnp->cn_cred, td);
1743
/*
1744
* It's possible for a direct operation on the lower FS
1745
* to make the lower directory non-empty after we drop
1746
* the lock, but it's also possible for the upper-layer
1747
* VOP_RMDIR to relock udvp/uvp which would lead to
1748
* LOR if we kept lvp locked across that call.
1749
*/
1750
VOP_UNLOCK(lvp);
1751
if (error != 0)
1752
return (error);
1753
}
1754
ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount);
1755
if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULL)
1756
cnp->cn_flags |= (DOWHITEOUT | IGNOREWHITEOUT);
1757
int udvp_lkflags, uvp_lkflags;
1758
unionfs_forward_vop_start_pair(udvp, &udvp_lkflags,
1759
uvp, &uvp_lkflags);
1760
error = VOP_RMDIR(udvp, uvp, cnp);
1761
unionfs_forward_vop_finish_pair(ap->a_dvp, udvp, udvp_lkflags,
1762
ap->a_vp, uvp, uvp_lkflags);
1763
} else if (lvp != NULL) {
1764
error = unionfs_mkwhiteout(ap->a_dvp, ap->a_vp, cnp, td,
1765
unp->un_path, unp->un_pathlen);
1766
}
1767
1768
if (error == 0) {
1769
cache_purge(ap->a_dvp);
1770
cache_purge(ap->a_vp);
1771
}
1772
1773
UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
1774
1775
return (error);
1776
}
1777
1778
static int
1779
unionfs_symlink(struct vop_symlink_args *ap)
1780
{
1781
struct unionfs_node *dunp;
1782
struct componentname *cnp;
1783
struct vnode *udvp;
1784
struct vnode *uvp;
1785
int error;
1786
int lkflags;
1787
1788
UNIONFS_INTERNAL_DEBUG("unionfs_symlink: enter\n");
1789
1790
KASSERT_UNIONFS_VNODE(ap->a_dvp);
1791
1792
error = EROFS;
1793
dunp = VTOUNIONFS(ap->a_dvp);
1794
cnp = ap->a_cnp;
1795
lkflags = cnp->cn_lkflags;
1796
udvp = dunp->un_uppervp;
1797
1798
if (udvp != NULL) {
1799
int udvp_lkflags;
1800
bool uvp_created = false;
1801
unionfs_forward_vop_start(udvp, &udvp_lkflags);
1802
error = VOP_SYMLINK(udvp, &uvp, cnp, ap->a_vap, ap->a_target);
1803
if (error == 0)
1804
uvp_created = true;
1805
if (__predict_false(unionfs_forward_vop_finish(ap->a_dvp, udvp,
1806
udvp_lkflags)) && error == 0)
1807
error = ENOENT;
1808
if (error == 0) {
1809
VOP_UNLOCK(uvp);
1810
cnp->cn_lkflags = LK_EXCLUSIVE;
1811
error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULL,
1812
ap->a_dvp, ap->a_vpp, cnp);
1813
vrele(uvp);
1814
cnp->cn_lkflags = lkflags;
1815
} else if (uvp_created)
1816
vput(uvp);
1817
}
1818
1819
UNIONFS_INTERNAL_DEBUG("unionfs_symlink: leave (%d)\n", error);
1820
1821
return (error);
1822
}
1823
1824
static int
1825
unionfs_readdir(struct vop_readdir_args *ap)
1826
{
1827
struct unionfs_node *unp;
1828
struct unionfs_node_status *unsp;
1829
struct uio *uio;
1830
struct vnode *vp;
1831
struct vnode *uvp;
1832
struct vnode *lvp;
1833
struct thread *td;
1834
struct vattr va;
1835
1836
uint64_t *cookies_bk;
1837
int error;
1838
int eofflag;
1839
int lkflags;
1840
int ncookies_bk;
1841
int uio_offset_bk;
1842
enum unionfs_lkupgrade lkstatus;
1843
1844
UNIONFS_INTERNAL_DEBUG("unionfs_readdir: enter\n");
1845
1846
KASSERT_UNIONFS_VNODE(ap->a_vp);
1847
1848
error = 0;
1849
eofflag = 0;
1850
uio_offset_bk = 0;
1851
uio = ap->a_uio;
1852
uvp = NULL;
1853
lvp = NULL;
1854
td = uio->uio_td;
1855
ncookies_bk = 0;
1856
cookies_bk = NULL;
1857
1858
vp = ap->a_vp;
1859
if (vp->v_type != VDIR)
1860
return (ENOTDIR);
1861
1862
/*
1863
* If the vnode is reclaimed while upgrading, we can't safely use unp
1864
* or do anything else unionfs- specific.
1865
*/
1866
lkstatus = unionfs_upgrade_lock(vp);
1867
if (lkstatus == UNIONFS_LKUPGRADE_DOOMED)
1868
error = EBADF;
1869
if (error == 0) {
1870
unp = VTOUNIONFS(vp);
1871
uvp = unp->un_uppervp;
1872
lvp = unp->un_lowervp;
1873
/* check the open count. unionfs needs open before readdir. */
1874
unionfs_get_node_status(unp, td, &unsp);
1875
if ((uvp != NULL && unsp->uns_upper_opencnt <= 0) ||
1876
(lvp != NULL && unsp->uns_lower_opencnt <= 0)) {
1877
unionfs_tryrem_node_status(unp, unsp);
1878
error = EBADF;
1879
}
1880
}
1881
unionfs_downgrade_lock(vp, lkstatus);
1882
if (error != 0)
1883
goto unionfs_readdir_exit;
1884
1885
/* check opaque */
1886
if (uvp != NULL && lvp != NULL) {
1887
if ((error = VOP_GETATTR(uvp, &va, ap->a_cred)) != 0)
1888
goto unionfs_readdir_exit;
1889
if (va.va_flags & OPAQUE)
1890
lvp = NULL;
1891
}
1892
1893
/* upper only */
1894
if (uvp != NULL && lvp == NULL) {
1895
unionfs_forward_vop_start(uvp, &lkflags);
1896
error = VOP_READDIR(uvp, uio, ap->a_cred, ap->a_eofflag,
1897
ap->a_ncookies, ap->a_cookies);
1898
if (unionfs_forward_vop_finish(vp, uvp, lkflags))
1899
error = error ? error : ENOENT;
1900
else
1901
unsp->uns_readdir_status = 0;
1902
1903
goto unionfs_readdir_exit;
1904
}
1905
1906
/* lower only */
1907
if (uvp == NULL && lvp != NULL) {
1908
unionfs_forward_vop_start(lvp, &lkflags);
1909
error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1910
ap->a_ncookies, ap->a_cookies);
1911
if (unionfs_forward_vop_finish(vp, lvp, lkflags))
1912
error = error ? error : ENOENT;
1913
else
1914
unsp->uns_readdir_status = 2;
1915
1916
goto unionfs_readdir_exit;
1917
}
1918
1919
/*
1920
* readdir upper and lower
1921
*/
1922
KASSERT(uvp != NULL, ("unionfs_readdir: null upper vp"));
1923
KASSERT(lvp != NULL, ("unionfs_readdir: null lower vp"));
1924
1925
if (uio->uio_offset == 0)
1926
unsp->uns_readdir_status = 0;
1927
1928
if (unsp->uns_readdir_status == 0) {
1929
/* read upper */
1930
unionfs_forward_vop_start(uvp, &lkflags);
1931
error = VOP_READDIR(uvp, uio, ap->a_cred, &eofflag,
1932
ap->a_ncookies, ap->a_cookies);
1933
if (unionfs_forward_vop_finish(vp, uvp, lkflags) && error == 0)
1934
error = ENOENT;
1935
if (error != 0 || eofflag == 0)
1936
goto unionfs_readdir_exit;
1937
unsp->uns_readdir_status = 1;
1938
1939
/*
1940
* UFS(and other FS) needs size of uio_resid larger than
1941
* DIRBLKSIZ.
1942
* size of DIRBLKSIZ equals DEV_BSIZE.
1943
* (see: ufs/ufs/ufs_vnops.c ufs_readdir func , ufs/ufs/dir.h)
1944
*/
1945
if (uio->uio_resid <= (uio->uio_resid & (DEV_BSIZE -1)))
1946
goto unionfs_readdir_exit;
1947
1948
/*
1949
* Backup cookies.
1950
* It prepares to readdir in lower.
1951
*/
1952
if (ap->a_ncookies != NULL) {
1953
ncookies_bk = *(ap->a_ncookies);
1954
*(ap->a_ncookies) = 0;
1955
}
1956
if (ap->a_cookies != NULL) {
1957
cookies_bk = *(ap->a_cookies);
1958
*(ap->a_cookies) = NULL;
1959
}
1960
}
1961
1962
/* initialize for readdir in lower */
1963
if (unsp->uns_readdir_status == 1) {
1964
unsp->uns_readdir_status = 2;
1965
/*
1966
* Backup uio_offset. See the comment after the
1967
* VOP_READDIR call on the lower layer.
1968
*/
1969
uio_offset_bk = uio->uio_offset;
1970
uio->uio_offset = 0;
1971
}
1972
1973
lvp = unionfs_lock_lvp(vp, &lkflags);
1974
if (lvp == NULL) {
1975
error = ENOENT;
1976
goto unionfs_readdir_exit;
1977
}
1978
1979
/* read lower */
1980
error = VOP_READDIR(lvp, uio, ap->a_cred, ap->a_eofflag,
1981
ap->a_ncookies, ap->a_cookies);
1982
1983
1984
unp = unionfs_unlock_lvp(vp, lvp, lkflags);
1985
if (unp == NULL && error == 0)
1986
error = ENOENT;
1987
1988
1989
/*
1990
* We can't return an uio_offset of 0: this would trigger an
1991
* infinite loop, because the next call to unionfs_readdir would
1992
* always restart with the upper layer (uio_offset == 0) and
1993
* always return some data.
1994
*
1995
* This happens when the lower layer root directory is removed.
1996
* (A root directory deleting of unionfs should not be permitted.
1997
* But current VFS can not do it.)
1998
*/
1999
if (uio->uio_offset == 0)
2000
uio->uio_offset = uio_offset_bk;
2001
2002
if (cookies_bk != NULL) {
2003
/* merge cookies */
2004
int size;
2005
uint64_t *newcookies, *pos;
2006
2007
size = *(ap->a_ncookies) + ncookies_bk;
2008
newcookies = (uint64_t *) malloc(size * sizeof(*newcookies),
2009
M_TEMP, M_WAITOK);
2010
pos = newcookies;
2011
2012
memcpy(pos, cookies_bk, ncookies_bk * sizeof(*newcookies));
2013
pos += ncookies_bk;
2014
memcpy(pos, *(ap->a_cookies),
2015
*(ap->a_ncookies) * sizeof(*newcookies));
2016
free(cookies_bk, M_TEMP);
2017
free(*(ap->a_cookies), M_TEMP);
2018
*(ap->a_ncookies) = size;
2019
*(ap->a_cookies) = newcookies;
2020
}
2021
2022
unionfs_readdir_exit:
2023
if (error != 0 && ap->a_eofflag != NULL)
2024
*(ap->a_eofflag) = 1;
2025
2026
UNIONFS_INTERNAL_DEBUG("unionfs_readdir: leave (%d)\n", error);
2027
2028
return (error);
2029
}
2030
2031
static int
2032
unionfs_readlink(struct vop_readlink_args *ap)
2033
{
2034
struct unionfs_node *unp;
2035
struct vnode *vp;
2036
int error;
2037
2038
UNIONFS_INTERNAL_DEBUG("unionfs_readlink: enter\n");
2039
2040
KASSERT_UNIONFS_VNODE(ap->a_vp);
2041
2042
unp = VTOUNIONFS(ap->a_vp);
2043
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2044
2045
error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
2046
2047
UNIONFS_INTERNAL_DEBUG("unionfs_readlink: leave (%d)\n", error);
2048
2049
return (error);
2050
}
2051
2052
static int
2053
unionfs_getwritemount(struct vop_getwritemount_args *ap)
2054
{
2055
struct unionfs_node *unp;
2056
struct vnode *uvp;
2057
struct vnode *vp, *ovp;
2058
int error;
2059
2060
UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
2061
2062
error = 0;
2063
vp = ap->a_vp;
2064
uvp = NULL;
2065
2066
VI_LOCK(vp);
2067
unp = VTOUNIONFS(vp);
2068
if (unp != NULL)
2069
uvp = unp->un_uppervp;
2070
2071
/*
2072
* If our node has no upper vnode, check the parent directory.
2073
* We may be initiating a write operation that will produce a
2074
* new upper vnode through CoW.
2075
*/
2076
if (uvp == NULL && unp != NULL) {
2077
ovp = vp;
2078
vp = unp->un_dvp;
2079
/*
2080
* Only the root vnode should have an empty parent, but it
2081
* should not have an empty uppervp, so we shouldn't get here.
2082
*/
2083
VNASSERT(vp != NULL, ovp, ("%s: NULL parent vnode", __func__));
2084
VI_UNLOCK(ovp);
2085
VI_LOCK(vp);
2086
unp = VTOUNIONFS(vp);
2087
if (unp != NULL)
2088
uvp = unp->un_uppervp;
2089
if (uvp == NULL)
2090
error = EACCES;
2091
}
2092
2093
if (uvp != NULL) {
2094
vholdnz(uvp);
2095
VI_UNLOCK(vp);
2096
error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
2097
vdrop(uvp);
2098
} else {
2099
VI_UNLOCK(vp);
2100
*(ap->a_mpp) = NULL;
2101
}
2102
2103
UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);
2104
2105
return (error);
2106
}
2107
2108
static int
2109
unionfs_inactive(struct vop_inactive_args *ap)
2110
{
2111
ap->a_vp->v_object = NULL;
2112
vrecycle(ap->a_vp);
2113
return (0);
2114
}
2115
2116
static int
2117
unionfs_reclaim(struct vop_reclaim_args *ap)
2118
{
2119
/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
2120
2121
unionfs_noderem(ap->a_vp);
2122
2123
/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
2124
2125
return (0);
2126
}
2127
2128
static int
2129
unionfs_print(struct vop_print_args *ap)
2130
{
2131
struct unionfs_node *unp;
2132
/* struct unionfs_node_status *unsp; */
2133
2134
unp = VTOUNIONFS(ap->a_vp);
2135
/* unionfs_get_node_status(unp, curthread, &unsp); */
2136
2137
printf("unionfs_vp=%p, uppervp=%p, lowervp=%p\n",
2138
ap->a_vp, unp->un_uppervp, unp->un_lowervp);
2139
/*
2140
printf("unionfs opencnt: uppervp=%d, lowervp=%d\n",
2141
unsp->uns_upper_opencnt, unsp->uns_lower_opencnt);
2142
*/
2143
2144
if (unp->un_uppervp != NULL)
2145
vn_printf(unp->un_uppervp, "unionfs: upper ");
2146
if (unp->un_lowervp != NULL)
2147
vn_printf(unp->un_lowervp, "unionfs: lower ");
2148
2149
return (0);
2150
}
2151
2152
static int
2153
unionfs_lock(struct vop_lock1_args *ap)
2154
{
2155
struct unionfs_node *unp;
2156
struct vnode *vp;
2157
struct vnode *tvp;
2158
int error;
2159
int flags;
2160
bool lvp_locked;
2161
2162
error = 0;
2163
flags = ap->a_flags;
2164
vp = ap->a_vp;
2165
2166
if (LK_RELEASE == (flags & LK_TYPE_MASK) || !(flags & LK_TYPE_MASK))
2167
return (VOP_UNLOCK_FLAGS(vp, flags | LK_RELEASE));
2168
2169
unionfs_lock_restart:
2170
/*
2171
* We currently need the interlock here to ensure we can safely
2172
* access the unionfs vnode's private data. We may be able to
2173
* eliminate this extra locking by instead using vfs_smr_enter()
2174
* and vn_load_v_data_smr() here in conjunction with an SMR UMA
2175
* zone for unionfs nodes.
2176
*/
2177
if ((flags & LK_INTERLOCK) == 0)
2178
VI_LOCK(vp);
2179
else
2180
flags &= ~LK_INTERLOCK;
2181
2182
unp = VTOUNIONFS(vp);
2183
if (unp == NULL) {
2184
VI_UNLOCK(vp);
2185
ap->a_flags = flags;
2186
return (vop_stdlock(ap));
2187
}
2188
2189
if (unp->un_uppervp != NULL) {
2190
tvp = unp->un_uppervp;
2191
lvp_locked = false;
2192
} else {
2193
tvp = unp->un_lowervp;
2194
lvp_locked = true;
2195
}
2196
2197
/*
2198
* During unmount, the root vnode lock may be taken recursively,
2199
* because it may share the same v_vnlock field as the vnode covered by
2200
* the unionfs mount. The covered vnode is locked across VFS_UNMOUNT(),
2201
* and the same lock may be taken recursively here during vflush()
2202
* issued by unionfs_unmount().
2203
*/
2204
if ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE &&
2205
(vp->v_vflag & VV_ROOT) != 0)
2206
flags |= LK_CANRECURSE;
2207
2208
vholdnz(tvp);
2209
VI_UNLOCK(vp);
2210
error = VOP_LOCK(tvp, flags);
2211
vdrop(tvp);
2212
if (error == 0 && (lvp_locked || VTOUNIONFS(vp) == NULL)) {
2213
/*
2214
* After dropping the interlock above, there exists a window
2215
* in which another thread may acquire the lower vnode lock
2216
* and then either doom the unionfs vnode or create an upper
2217
* vnode. In either case, we will effectively be holding the
2218
* wrong lock, so we must drop the lower vnode lock and
2219
* restart the lock operation.
2220
*
2221
* If unp is not already NULL, we assume that we can safely
2222
* access it because we currently hold lvp's lock.
2223
* unionfs_noderem() acquires lvp's lock before freeing
2224
* the vnode private data, ensuring it can't be concurrently
2225
* freed while we are using it here. Likewise,
2226
* unionfs_node_update() acquires lvp's lock before installing
2227
* an upper vnode. Without those guarantees, we would need to
2228
* reacquire the vnode interlock here.
2229
* Note that unionfs_noderem() doesn't acquire lvp's lock if
2230
* this is the root vnode, but the root vnode should always
2231
* have an upper vnode and therefore we should never use its
2232
* lower vnode lock here.
2233
*/
2234
unp = VTOUNIONFS(vp);
2235
if (unp == NULL || unp->un_uppervp != NULL) {
2236
VOP_UNLOCK(tvp);
2237
/*
2238
* If we previously held the lock, the upgrade may
2239
* have temporarily dropped the lock, in which case
2240
* concurrent dooming or copy-up will necessitate
2241
* acquiring a different lock. Since we never held
2242
* the new lock, LK_UPGRADE must be cleared here to
2243
* avoid triggering a lockmgr panic.
2244
*/
2245
if (flags & LK_UPGRADE)
2246
flags = (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE;
2247
VNASSERT((flags & LK_DOWNGRADE) == 0, vp,
2248
("%s: vnode doomed during downgrade", __func__));
2249
goto unionfs_lock_restart;
2250
}
2251
}
2252
2253
return (error);
2254
}
2255
2256
static int
2257
unionfs_unlock(struct vop_unlock_args *ap)
2258
{
2259
struct vnode *vp;
2260
struct vnode *tvp;
2261
struct unionfs_node *unp;
2262
int error;
2263
2264
KASSERT_UNIONFS_VNODE(ap->a_vp);
2265
2266
vp = ap->a_vp;
2267
2268
unp = VTOUNIONFS(vp);
2269
if (unp == NULL)
2270
return (vop_stdunlock(ap));
2271
2272
tvp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2273
2274
vholdnz(tvp);
2275
error = VOP_UNLOCK(tvp);
2276
vdrop(tvp);
2277
2278
return (error);
2279
}
2280
2281
static int
2282
unionfs_pathconf(struct vop_pathconf_args *ap)
2283
{
2284
struct unionfs_node *unp;
2285
struct vnode *vp;
2286
2287
KASSERT_UNIONFS_VNODE(ap->a_vp);
2288
2289
unp = VTOUNIONFS(ap->a_vp);
2290
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2291
2292
return (VOP_PATHCONF(vp, ap->a_name, ap->a_retval));
2293
}
2294
2295
static int
2296
unionfs_advlock(struct vop_advlock_args *ap)
2297
{
2298
struct unionfs_node *unp;
2299
struct unionfs_node_status *unsp;
2300
struct vnode *vp;
2301
struct vnode *uvp;
2302
struct thread *td;
2303
int error;
2304
2305
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n");
2306
2307
KASSERT_UNIONFS_VNODE(ap->a_vp);
2308
2309
vp = ap->a_vp;
2310
td = curthread;
2311
2312
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2313
2314
unp = VTOUNIONFS(ap->a_vp);
2315
uvp = unp->un_uppervp;
2316
2317
if (uvp == NULL) {
2318
error = unionfs_copyfile(ap->a_vp, 1, td->td_ucred, td);
2319
if (error != 0)
2320
goto unionfs_advlock_abort;
2321
uvp = unp->un_uppervp;
2322
2323
unionfs_get_node_status(unp, td, &unsp);
2324
if (unsp->uns_lower_opencnt > 0) {
2325
/* try reopen the vnode */
2326
error = VOP_OPEN(uvp, unsp->uns_lower_openmode,
2327
td->td_ucred, td, NULL);
2328
if (error)
2329
goto unionfs_advlock_abort;
2330
unsp->uns_upper_opencnt++;
2331
VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode,
2332
td->td_ucred, td);
2333
unsp->uns_lower_opencnt--;
2334
} else
2335
unionfs_tryrem_node_status(unp, unsp);
2336
}
2337
2338
VOP_UNLOCK(vp);
2339
2340
error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags);
2341
2342
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2343
2344
return error;
2345
2346
unionfs_advlock_abort:
2347
VOP_UNLOCK(vp);
2348
2349
UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error);
2350
2351
return error;
2352
}
2353
2354
static int
2355
unionfs_strategy(struct vop_strategy_args *ap)
2356
{
2357
struct unionfs_node *unp;
2358
struct vnode *vp;
2359
2360
KASSERT_UNIONFS_VNODE(ap->a_vp);
2361
2362
unp = VTOUNIONFS(ap->a_vp);
2363
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2364
2365
#ifdef DIAGNOSTIC
2366
if (vp == NULL)
2367
panic("unionfs_strategy: nullvp");
2368
2369
if (ap->a_bp->b_iocmd == BIO_WRITE && vp == unp->un_lowervp)
2370
panic("unionfs_strategy: writing to lowervp");
2371
#endif
2372
2373
return (VOP_STRATEGY(vp, ap->a_bp));
2374
}
2375
2376
static int
2377
unionfs_getacl(struct vop_getacl_args *ap)
2378
{
2379
struct unionfs_node *unp;
2380
struct vnode *vp;
2381
int error;
2382
2383
KASSERT_UNIONFS_VNODE(ap->a_vp);
2384
2385
unp = VTOUNIONFS(ap->a_vp);
2386
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2387
2388
UNIONFS_INTERNAL_DEBUG("unionfs_getacl: enter\n");
2389
2390
error = VOP_GETACL(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2391
2392
UNIONFS_INTERNAL_DEBUG("unionfs_getacl: leave (%d)\n", error);
2393
2394
return (error);
2395
}
2396
2397
static int
2398
unionfs_setacl(struct vop_setacl_args *ap)
2399
{
2400
struct unionfs_node *unp;
2401
struct vnode *uvp;
2402
struct vnode *lvp;
2403
struct thread *td;
2404
int error;
2405
2406
UNIONFS_INTERNAL_DEBUG("unionfs_setacl: enter\n");
2407
2408
KASSERT_UNIONFS_VNODE(ap->a_vp);
2409
2410
error = EROFS;
2411
unp = VTOUNIONFS(ap->a_vp);
2412
uvp = unp->un_uppervp;
2413
lvp = unp->un_lowervp;
2414
td = ap->a_td;
2415
2416
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2417
return (EROFS);
2418
2419
if (uvp == NULL && lvp->v_type == VREG) {
2420
if ((error = unionfs_copyfile(ap->a_vp, 1, ap->a_cred, td)) != 0)
2421
return (error);
2422
uvp = unp->un_uppervp;
2423
}
2424
2425
if (uvp != NULL) {
2426
int lkflags;
2427
unionfs_forward_vop_start(uvp, &lkflags);
2428
error = VOP_SETACL(uvp, ap->a_type, ap->a_aclp, ap->a_cred, td);
2429
unionfs_forward_vop_finish(ap->a_vp, uvp, lkflags);
2430
}
2431
2432
UNIONFS_INTERNAL_DEBUG("unionfs_setacl: leave (%d)\n", error);
2433
2434
return (error);
2435
}
2436
2437
static int
2438
unionfs_aclcheck(struct vop_aclcheck_args *ap)
2439
{
2440
struct unionfs_node *unp;
2441
struct vnode *vp;
2442
int error;
2443
2444
UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: enter\n");
2445
2446
KASSERT_UNIONFS_VNODE(ap->a_vp);
2447
2448
unp = VTOUNIONFS(ap->a_vp);
2449
vp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2450
2451
error = VOP_ACLCHECK(vp, ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td);
2452
2453
UNIONFS_INTERNAL_DEBUG("unionfs_aclcheck: leave (%d)\n", error);
2454
2455
return (error);
2456
}
2457
2458
static int
2459
unionfs_openextattr(struct vop_openextattr_args *ap)
2460
{
2461
struct unionfs_node *unp;
2462
struct vnode *vp;
2463
struct vnode *tvp;
2464
int error;
2465
2466
KASSERT_UNIONFS_VNODE(ap->a_vp);
2467
2468
vp = ap->a_vp;
2469
unp = VTOUNIONFS(vp);
2470
tvp = (unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp);
2471
2472
if ((tvp == unp->un_uppervp && (unp->un_flag & UNIONFS_OPENEXTU)) ||
2473
(tvp == unp->un_lowervp && (unp->un_flag & UNIONFS_OPENEXTL)))
2474
return (EBUSY);
2475
2476
error = VOP_OPENEXTATTR(tvp, ap->a_cred, ap->a_td);
2477
2478
if (error == 0) {
2479
if (vn_lock(vp, LK_UPGRADE) != 0)
2480
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2481
if (!VN_IS_DOOMED(vp)) {
2482
if (tvp == unp->un_uppervp)
2483
unp->un_flag |= UNIONFS_OPENEXTU;
2484
else
2485
unp->un_flag |= UNIONFS_OPENEXTL;
2486
}
2487
vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2488
}
2489
2490
return (error);
2491
}
2492
2493
static int
2494
unionfs_closeextattr(struct vop_closeextattr_args *ap)
2495
{
2496
struct unionfs_node *unp;
2497
struct vnode *vp;
2498
struct vnode *tvp;
2499
int error;
2500
2501
KASSERT_UNIONFS_VNODE(ap->a_vp);
2502
2503
vp = ap->a_vp;
2504
unp = VTOUNIONFS(vp);
2505
tvp = NULL;
2506
2507
if (unp->un_flag & UNIONFS_OPENEXTU)
2508
tvp = unp->un_uppervp;
2509
else if (unp->un_flag & UNIONFS_OPENEXTL)
2510
tvp = unp->un_lowervp;
2511
2512
if (tvp == NULL)
2513
return (EOPNOTSUPP);
2514
2515
error = VOP_CLOSEEXTATTR(tvp, ap->a_commit, ap->a_cred, ap->a_td);
2516
2517
if (error == 0) {
2518
if (vn_lock(vp, LK_UPGRADE) != 0)
2519
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2520
if (!VN_IS_DOOMED(vp)) {
2521
if (tvp == unp->un_uppervp)
2522
unp->un_flag &= ~UNIONFS_OPENEXTU;
2523
else
2524
unp->un_flag &= ~UNIONFS_OPENEXTL;
2525
}
2526
vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
2527
}
2528
2529
return (error);
2530
}
2531
2532
static int
2533
unionfs_getextattr(struct vop_getextattr_args *ap)
2534
{
2535
struct unionfs_node *unp;
2536
struct vnode *vp;
2537
2538
KASSERT_UNIONFS_VNODE(ap->a_vp);
2539
2540
unp = VTOUNIONFS(ap->a_vp);
2541
vp = NULL;
2542
2543
if (unp->un_flag & UNIONFS_OPENEXTU)
2544
vp = unp->un_uppervp;
2545
else if (unp->un_flag & UNIONFS_OPENEXTL)
2546
vp = unp->un_lowervp;
2547
2548
if (vp == NULL)
2549
return (EOPNOTSUPP);
2550
2551
return (VOP_GETEXTATTR(vp, ap->a_attrnamespace, ap->a_name,
2552
ap->a_uio, ap->a_size, ap->a_cred, ap->a_td));
2553
}
2554
2555
static int
2556
unionfs_setextattr(struct vop_setextattr_args *ap)
2557
{
2558
struct unionfs_node *unp;
2559
struct vnode *uvp;
2560
struct vnode *lvp;
2561
struct vnode *ovp;
2562
struct ucred *cred;
2563
struct thread *td;
2564
int error;
2565
2566
KASSERT_UNIONFS_VNODE(ap->a_vp);
2567
2568
error = EROFS;
2569
unp = VTOUNIONFS(ap->a_vp);
2570
uvp = unp->un_uppervp;
2571
lvp = unp->un_lowervp;
2572
ovp = NULL;
2573
cred = ap->a_cred;
2574
td = ap->a_td;
2575
2576
UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: enter (un_flag=%x)\n",
2577
unp->un_flag);
2578
2579
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2580
return (EROFS);
2581
2582
if (unp->un_flag & UNIONFS_OPENEXTU)
2583
ovp = unp->un_uppervp;
2584
else if (unp->un_flag & UNIONFS_OPENEXTL)
2585
ovp = unp->un_lowervp;
2586
2587
if (ovp == NULL)
2588
return (EOPNOTSUPP);
2589
2590
if (ovp == lvp && lvp->v_type == VREG) {
2591
VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2592
if (uvp == NULL &&
2593
(error = unionfs_copyfile(ap->a_vp, 1, cred, td)) != 0) {
2594
unionfs_setextattr_reopen:
2595
unp = VTOUNIONFS(ap->a_vp);
2596
if (unp != NULL && (unp->un_flag & UNIONFS_OPENEXTL) &&
2597
VOP_OPENEXTATTR(lvp, cred, td)) {
2598
#ifdef DIAGNOSTIC
2599
panic("unionfs: VOP_OPENEXTATTR failed");
2600
#endif
2601
unp->un_flag &= ~UNIONFS_OPENEXTL;
2602
}
2603
goto unionfs_setextattr_abort;
2604
}
2605
uvp = unp->un_uppervp;
2606
if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2607
goto unionfs_setextattr_reopen;
2608
unp->un_flag &= ~UNIONFS_OPENEXTL;
2609
unp->un_flag |= UNIONFS_OPENEXTU;
2610
ovp = uvp;
2611
}
2612
2613
if (ovp == uvp) {
2614
int lkflags;
2615
unionfs_forward_vop_start(ovp, &lkflags);
2616
error = VOP_SETEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2617
ap->a_uio, cred, td);
2618
unionfs_forward_vop_finish(ap->a_vp, ovp, lkflags);
2619
}
2620
2621
unionfs_setextattr_abort:
2622
UNIONFS_INTERNAL_DEBUG("unionfs_setextattr: leave (%d)\n", error);
2623
2624
return (error);
2625
}
2626
2627
static int
2628
unionfs_listextattr(struct vop_listextattr_args *ap)
2629
{
2630
struct unionfs_node *unp;
2631
struct vnode *vp;
2632
2633
KASSERT_UNIONFS_VNODE(ap->a_vp);
2634
2635
unp = VTOUNIONFS(ap->a_vp);
2636
vp = NULL;
2637
2638
if (unp->un_flag & UNIONFS_OPENEXTU)
2639
vp = unp->un_uppervp;
2640
else if (unp->un_flag & UNIONFS_OPENEXTL)
2641
vp = unp->un_lowervp;
2642
2643
if (vp == NULL)
2644
return (EOPNOTSUPP);
2645
2646
return (VOP_LISTEXTATTR(vp, ap->a_attrnamespace, ap->a_uio,
2647
ap->a_size, ap->a_cred, ap->a_td));
2648
}
2649
2650
static int
2651
unionfs_deleteextattr(struct vop_deleteextattr_args *ap)
2652
{
2653
struct unionfs_node *unp;
2654
struct vnode *uvp;
2655
struct vnode *lvp;
2656
struct vnode *ovp;
2657
struct ucred *cred;
2658
struct thread *td;
2659
int error;
2660
2661
KASSERT_UNIONFS_VNODE(ap->a_vp);
2662
2663
error = EROFS;
2664
unp = VTOUNIONFS(ap->a_vp);
2665
uvp = unp->un_uppervp;
2666
lvp = unp->un_lowervp;
2667
ovp = NULL;
2668
cred = ap->a_cred;
2669
td = ap->a_td;
2670
2671
UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: enter (un_flag=%x)\n",
2672
unp->un_flag);
2673
2674
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2675
return (EROFS);
2676
2677
if (unp->un_flag & UNIONFS_OPENEXTU)
2678
ovp = unp->un_uppervp;
2679
else if (unp->un_flag & UNIONFS_OPENEXTL)
2680
ovp = unp->un_lowervp;
2681
2682
if (ovp == NULL)
2683
return (EOPNOTSUPP);
2684
2685
if (ovp == lvp && lvp->v_type == VREG) {
2686
VOP_CLOSEEXTATTR(lvp, 0, cred, td);
2687
if (uvp == NULL &&
2688
(error = unionfs_copyfile(ap->a_vp, 1, cred, td)) != 0) {
2689
unionfs_deleteextattr_reopen:
2690
unp = VTOUNIONFS(ap->a_vp);
2691
if (unp != NULL && (unp->un_flag & UNIONFS_OPENEXTL) &&
2692
VOP_OPENEXTATTR(lvp, cred, td)) {
2693
#ifdef DIAGNOSTIC
2694
panic("unionfs: VOP_OPENEXTATTR failed");
2695
#endif
2696
unp->un_flag &= ~UNIONFS_OPENEXTL;
2697
}
2698
goto unionfs_deleteextattr_abort;
2699
}
2700
uvp = unp->un_uppervp;
2701
if ((error = VOP_OPENEXTATTR(uvp, cred, td)) != 0)
2702
goto unionfs_deleteextattr_reopen;
2703
unp->un_flag &= ~UNIONFS_OPENEXTL;
2704
unp->un_flag |= UNIONFS_OPENEXTU;
2705
ovp = uvp;
2706
}
2707
2708
if (ovp == uvp)
2709
error = VOP_DELETEEXTATTR(ovp, ap->a_attrnamespace, ap->a_name,
2710
ap->a_cred, ap->a_td);
2711
2712
unionfs_deleteextattr_abort:
2713
UNIONFS_INTERNAL_DEBUG("unionfs_deleteextattr: leave (%d)\n", error);
2714
2715
return (error);
2716
}
2717
2718
static int
2719
unionfs_setlabel(struct vop_setlabel_args *ap)
2720
{
2721
struct unionfs_node *unp;
2722
struct vnode *uvp;
2723
struct vnode *lvp;
2724
struct thread *td;
2725
int error;
2726
2727
UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: enter\n");
2728
2729
KASSERT_UNIONFS_VNODE(ap->a_vp);
2730
2731
error = EROFS;
2732
unp = VTOUNIONFS(ap->a_vp);
2733
uvp = unp->un_uppervp;
2734
lvp = unp->un_lowervp;
2735
td = ap->a_td;
2736
2737
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
2738
return (EROFS);
2739
2740
if (uvp == NULL && lvp->v_type == VREG) {
2741
if ((error = unionfs_copyfile(ap->a_vp, 1, ap->a_cred, td)) != 0)
2742
return (error);
2743
uvp = unp->un_uppervp;
2744
}
2745
2746
if (uvp != NULL)
2747
error = VOP_SETLABEL(uvp, ap->a_label, ap->a_cred, td);
2748
2749
UNIONFS_INTERNAL_DEBUG("unionfs_setlabel: leave (%d)\n", error);
2750
2751
return (error);
2752
}
2753
2754
static int
2755
unionfs_vptofh(struct vop_vptofh_args *ap)
2756
{
2757
return (EOPNOTSUPP);
2758
}
2759
2760
static int
2761
unionfs_add_writecount(struct vop_add_writecount_args *ap)
2762
{
2763
struct vnode *tvp, *vp;
2764
struct unionfs_node *unp;
2765
int error, writerefs __diagused;
2766
2767
vp = ap->a_vp;
2768
unp = VTOUNIONFS(vp);
2769
tvp = unp->un_uppervp;
2770
KASSERT(tvp != NULL,
2771
("%s: adding write ref without upper vnode", __func__));
2772
error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
2773
if (error != 0)
2774
return (error);
2775
/*
2776
* We need to track the write refs we've passed to the underlying
2777
* vnodes so that we can undo them in case we are forcibly unmounted.
2778
*/
2779
writerefs = atomic_fetchadd_int(&vp->v_writecount, ap->a_inc);
2780
/* text refs are bypassed to lowervp */
2781
VNASSERT(writerefs >= 0, vp,
2782
("%s: invalid write count %d", __func__, writerefs));
2783
VNASSERT(writerefs + ap->a_inc >= 0, vp,
2784
("%s: invalid write count inc %d + %d", __func__,
2785
writerefs, ap->a_inc));
2786
return (0);
2787
}
2788
2789
static int
2790
unionfs_vput_pair(struct vop_vput_pair_args *ap)
2791
{
2792
struct mount *mp;
2793
struct vnode *dvp, *vp, **vpp, *lvp, *uvp, *tvp, *tdvp, *tempvp;
2794
struct unionfs_node *dunp, *unp;
2795
int error, res;
2796
2797
dvp = ap->a_dvp;
2798
vpp = ap->a_vpp;
2799
vp = NULL;
2800
lvp = NULL;
2801
uvp = NULL;
2802
tvp = NULL;
2803
unp = NULL;
2804
2805
dunp = VTOUNIONFS(dvp);
2806
if (dunp->un_uppervp != NULL)
2807
tdvp = dunp->un_uppervp;
2808
else
2809
tdvp = dunp->un_lowervp;
2810
2811
/*
2812
* Underlying vnodes should be locked because the encompassing unionfs
2813
* node is locked, but will not be referenced, as the reference will
2814
* only be on the unionfs node. Reference them now so that the vput()s
2815
* performed by VOP_VPUT_PAIR() will have a reference to drop.
2816
*/
2817
vref(tdvp);
2818
2819
if (vpp != NULL)
2820
vp = *vpp;
2821
2822
if (vp != NULL) {
2823
unp = VTOUNIONFS(vp);
2824
uvp = unp->un_uppervp;
2825
lvp = unp->un_lowervp;
2826
if (uvp != NULL)
2827
tvp = uvp;
2828
else
2829
tvp = lvp;
2830
vref(tvp);
2831
2832
/*
2833
* If we're being asked to return a locked child vnode, then
2834
* we may need to create a replacement vnode in case the
2835
* original is reclaimed while the lock is dropped. In that
2836
* case we'll need to ensure the mount and the underlying
2837
* vnodes aren't also recycled during that window.
2838
*/
2839
if (!ap->a_unlock_vp) {
2840
vhold(vp);
2841
if (uvp != NULL)
2842
vhold(uvp);
2843
if (lvp != NULL)
2844
vhold(lvp);
2845
mp = vp->v_mount;
2846
vfs_ref(mp);
2847
}
2848
}
2849
2850
ASSERT_VOP_LOCKED(tdvp, __func__);
2851
ASSERT_VOP_LOCKED(tvp, __func__);
2852
2853
if (tdvp == dunp->un_uppervp && tvp != NULL && tvp == lvp) {
2854
vput(tvp);
2855
vput(tdvp);
2856
res = 0;
2857
} else {
2858
res = VOP_VPUT_PAIR(tdvp, tvp != NULL ? &tvp : NULL, true);
2859
}
2860
2861
ASSERT_VOP_UNLOCKED(tdvp, __func__);
2862
ASSERT_VOP_UNLOCKED(tvp, __func__);
2863
2864
/*
2865
* VOP_VPUT_PAIR() dropped the references we added to the underlying
2866
* vnodes, now drop the caller's reference to the unionfs vnodes.
2867
*/
2868
if (vp != NULL && ap->a_unlock_vp)
2869
vrele(vp);
2870
vrele(dvp);
2871
2872
if (vp == NULL || ap->a_unlock_vp)
2873
return (res);
2874
2875
/*
2876
* We're being asked to return a locked vnode. At this point, the
2877
* underlying vnodes have been unlocked, so vp may have been reclaimed.
2878
*/
2879
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2880
if (vp->v_data == NULL && vfs_busy(mp, MBF_NOWAIT) == 0) {
2881
vput(vp);
2882
error = unionfs_nodeget(mp, uvp, lvp, dvp, &tempvp, NULL);
2883
if (error == 0) {
2884
vn_lock(tempvp, LK_EXCLUSIVE | LK_RETRY);
2885
*vpp = tempvp;
2886
} else
2887
vget(vp, LK_EXCLUSIVE | LK_RETRY);
2888
vfs_unbusy(mp);
2889
}
2890
if (lvp != NULL)
2891
vdrop(lvp);
2892
if (uvp != NULL)
2893
vdrop(uvp);
2894
vdrop(vp);
2895
vfs_rel(mp);
2896
2897
return (res);
2898
}
2899
2900
static int
2901
unionfs_set_text(struct vop_set_text_args *ap)
2902
{
2903
struct vnode *tvp;
2904
struct unionfs_node *unp;
2905
int error;
2906
2907
/*
2908
* We assume text refs are managed against lvp/uvp through the
2909
* executable mapping backed by its VM object. We therefore don't
2910
* need to track leased text refs in the case of a forcible unmount.
2911
*/
2912
unp = VTOUNIONFS(ap->a_vp);
2913
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2914
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2915
error = VOP_SET_TEXT(tvp);
2916
return (error);
2917
}
2918
2919
static int
2920
unionfs_unset_text(struct vop_unset_text_args *ap)
2921
{
2922
struct vnode *tvp;
2923
struct unionfs_node *unp;
2924
2925
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2926
unp = VTOUNIONFS(ap->a_vp);
2927
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2928
VOP_UNSET_TEXT_CHECKED(tvp);
2929
return (0);
2930
}
2931
2932
static int
2933
unionfs_unp_bind(struct vop_unp_bind_args *ap)
2934
{
2935
struct vnode *tvp;
2936
struct unionfs_node *unp;
2937
2938
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2939
unp = VTOUNIONFS(ap->a_vp);
2940
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2941
VOP_UNP_BIND(tvp, ap->a_unpcb);
2942
return (0);
2943
}
2944
2945
static int
2946
unionfs_unp_connect(struct vop_unp_connect_args *ap)
2947
{
2948
struct vnode *tvp;
2949
struct unionfs_node *unp;
2950
2951
ASSERT_VOP_LOCKED(ap->a_vp, __func__);
2952
unp = VTOUNIONFS(ap->a_vp);
2953
tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
2954
VOP_UNP_CONNECT(tvp, ap->a_unpcb);
2955
return (0);
2956
}
2957
2958
static int
2959
unionfs_unp_detach(struct vop_unp_detach_args *ap)
2960
{
2961
struct vnode *tvp;
2962
struct unionfs_node *unp;
2963
2964
tvp = NULL;
2965
/*
2966
* VOP_UNP_DETACH() is not guaranteed to be called with the unionfs
2967
* vnode locked, so we take the interlock to prevent a concurrent
2968
* unmount from freeing the unionfs private data.
2969
*/
2970
VI_LOCK(ap->a_vp);
2971
unp = VTOUNIONFS(ap->a_vp);
2972
if (unp != NULL) {
2973
tvp = unp->un_uppervp != NULL ?
2974
unp->un_uppervp : unp->un_lowervp;
2975
/*
2976
* Hold the target vnode to prevent a concurrent unionfs
2977
* unmount from causing it to be recycled once the interlock
2978
* is dropped.
2979
*/
2980
vholdnz(tvp);
2981
}
2982
VI_UNLOCK(ap->a_vp);
2983
if (tvp != NULL) {
2984
VOP_UNP_DETACH(tvp);
2985
vdrop(tvp);
2986
}
2987
return (0);
2988
}
2989
2990
struct vop_vector unionfs_vnodeops = {
2991
.vop_default = &default_vnodeops,
2992
2993
.vop_access = unionfs_access,
2994
.vop_aclcheck = unionfs_aclcheck,
2995
.vop_advlock = unionfs_advlock,
2996
.vop_bmap = VOP_EOPNOTSUPP,
2997
.vop_cachedlookup = unionfs_lookup,
2998
.vop_close = unionfs_close,
2999
.vop_closeextattr = unionfs_closeextattr,
3000
.vop_create = unionfs_create,
3001
.vop_deleteextattr = unionfs_deleteextattr,
3002
.vop_fsync = unionfs_fsync,
3003
.vop_getacl = unionfs_getacl,
3004
.vop_getattr = unionfs_getattr,
3005
.vop_getextattr = unionfs_getextattr,
3006
.vop_getwritemount = unionfs_getwritemount,
3007
.vop_inactive = unionfs_inactive,
3008
.vop_need_inactive = vop_stdneed_inactive,
3009
.vop_islocked = vop_stdislocked,
3010
.vop_ioctl = unionfs_ioctl,
3011
.vop_link = unionfs_link,
3012
.vop_listextattr = unionfs_listextattr,
3013
.vop_lock1 = unionfs_lock,
3014
.vop_lookup = vfs_cache_lookup,
3015
.vop_mkdir = unionfs_mkdir,
3016
.vop_mknod = unionfs_mknod,
3017
.vop_open = unionfs_open,
3018
.vop_openextattr = unionfs_openextattr,
3019
.vop_pathconf = unionfs_pathconf,
3020
.vop_poll = unionfs_poll,
3021
.vop_print = unionfs_print,
3022
.vop_read = unionfs_read,
3023
.vop_readdir = unionfs_readdir,
3024
.vop_readlink = unionfs_readlink,
3025
.vop_reclaim = unionfs_reclaim,
3026
.vop_remove = unionfs_remove,
3027
.vop_rename = unionfs_rename,
3028
.vop_rmdir = unionfs_rmdir,
3029
.vop_setacl = unionfs_setacl,
3030
.vop_setattr = unionfs_setattr,
3031
.vop_setextattr = unionfs_setextattr,
3032
.vop_setlabel = unionfs_setlabel,
3033
.vop_strategy = unionfs_strategy,
3034
.vop_symlink = unionfs_symlink,
3035
.vop_unlock = unionfs_unlock,
3036
.vop_whiteout = unionfs_whiteout,
3037
.vop_write = unionfs_write,
3038
.vop_vptofh = unionfs_vptofh,
3039
.vop_add_writecount = unionfs_add_writecount,
3040
.vop_vput_pair = unionfs_vput_pair,
3041
.vop_set_text = unionfs_set_text,
3042
.vop_unset_text = unionfs_unset_text,
3043
.vop_unp_bind = unionfs_unp_bind,
3044
.vop_unp_connect = unionfs_unp_connect,
3045
.vop_unp_detach = unionfs_unp_detach,
3046
};
3047
VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);
3048
3049