2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1994, 1995 The Regents of the University of California.
25 * Copyright (c) 1994, 1995 Jan-Simon Pendry.
26 * All rights reserved.
28 * This code is derived from software donated to Berkeley by
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
66 #include <sys/param.h>
67 #include <sys/systm.h>
69 #include <sys/types.h>
70 #include <sys/proc_internal.h>
71 #include <sys/kauth.h>
72 #include <sys/vnode_internal.h>
73 #include <sys/mount_internal.h>
74 #include <sys/namei.h>
75 #include <sys/malloc.h>
76 #include <sys/filedesc.h>
77 #include <sys/queue.h>
78 #include <miscfs/union/union.h>
80 static int union_itercallback(__unused vnode_t
, void *);
83 * Mount union filesystem
86 union_mount(mount_t mp
, __unused vnode_t devvp
, user_addr_t data
, vfs_context_t context
)
88 proc_t p
= vfs_context_proc(context
);
90 struct user_union_args args
;
91 struct vnode
*lowerrootvp
= NULLVP
;
92 struct vnode
*upperrootvp
= NULLVP
;
93 struct union_mount
*um
= 0;
94 kauth_cred_t cred
= NOCRED
;
100 #ifdef UNION_DIAGNOSTIC
101 printf("union_mount(mp = %x)\n", mp
);
107 if (mp
->mnt_flag
& MNT_UPDATE
) {
110 * 1. a way to convert between rdonly and rdwr mounts.
111 * 2. support for nfs exports.
120 if (vfs_context_is64bit(context
)) {
121 error
= copyin(data
, (caddr_t
)&args
, sizeof(args
));
124 struct union_args temp
;
125 error
= copyin(data
, (caddr_t
)&temp
, sizeof (temp
));
126 args
.target
= CAST_USER_ADDR_T(temp
.target
);
127 args
.mntflags
= temp
.mntflags
;
132 lowerrootvp
= mp
->mnt_vnodecovered
;
133 vnode_get(lowerrootvp
);
138 NDINIT(&nd
, LOOKUP
, FOLLOW
|WANTPARENT
,
139 (IS_64BIT_PROCESS(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
140 args
.target
, context
);
142 if ((error
= namei(&nd
)))
146 upperrootvp
= nd
.ni_vp
;
147 vnode_put(nd
.ni_dvp
);
150 if (upperrootvp
->v_type
!= VDIR
) {
155 // um = (struct union_mount *) malloc(sizeof(struct union_mount),
156 // M_UFSMNT, M_WAITOK); /* XXX */
157 MALLOC(um
, struct union_mount
*, sizeof(struct union_mount
),
161 * Keep a held reference to the target vnodes.
162 * They are vnode_put'd in union_unmount.
164 * Depending on the _BELOW flag, the filesystems are
165 * viewed in a different order. In effect, this is the
166 * same as providing a mount under option to the mount syscall.
169 um
->um_op
= args
.mntflags
& UNMNT_OPMASK
;
172 um
->um_lowervp
= lowerrootvp
;
173 um
->um_uppervp
= upperrootvp
;
177 um
->um_lowervp
= upperrootvp
;
178 um
->um_uppervp
= lowerrootvp
;
182 vnode_put(lowerrootvp
);
183 lowerrootvp
= NULLVP
;
184 um
->um_uppervp
= upperrootvp
;
185 um
->um_lowervp
= lowerrootvp
;
194 * Unless the mount is readonly, ensure that the top layer
195 * supports whiteout operations
197 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
198 error
= VNOP_WHITEOUT(um
->um_uppervp
, (struct componentname
*) 0,
204 um
->um_cred
= kauth_cred_get_with_ref();
205 um
->um_cmode
= UN_DIRMODE
&~ p
->p_fd
->fd_cmask
;
208 * Depending on what you think the MNT_LOCAL flag might mean,
209 * you may want the && to be || on the conditional below.
210 * At the moment it has been defined that the filesystem is
211 * only local if it is all local, ie the MNT_LOCAL flag implies
212 * that the entire namespace is local. If you think the MNT_LOCAL
213 * flag implies that some of the files might be stored locally
214 * then you will want to change the conditional.
216 if (um
->um_op
== UNMNT_ABOVE
) {
217 if (((um
->um_lowervp
== NULLVP
) ||
218 (um
->um_lowervp
->v_mount
->mnt_flag
& MNT_LOCAL
)) &&
219 (um
->um_uppervp
->v_mount
->mnt_flag
& MNT_LOCAL
))
220 mp
->mnt_flag
|= MNT_LOCAL
;
224 * Copy in the upper layer's RDONLY flag. This is for the benefit
225 * of lookup() which explicitly checks the flag, rather than asking
226 * the filesystem for it's own opinion. This means, that an update
227 * mount of the underlying filesystem to go from rdonly to rdwr
228 * will leave the unioned view as read-only.
230 mp
->mnt_flag
|= (um
->um_uppervp
->v_mount
->mnt_flag
& MNT_RDONLY
);
232 mp
->mnt_data
= (qaddr_t
) um
;
248 bcopy(cp
, mp
->mnt_vfsstat
.f_mntfromname
, len
);
250 cp
= mp
->mnt_vfsstat
.f_mntfromname
+ len
;
251 len
= MNAMELEN
- len
;
253 (void) copyinstr(args
.target
, cp
, len
- 1, (size_t *)&size
);
254 bzero(cp
+ size
, len
- size
);
256 #ifdef UNION_DIAGNOSTIC
257 printf("union_mount: from %s, on %s\n",
258 mp
->mnt_vfsstat
.f_mntfromname
, mp
->mnt_vfsstat
.f_mntonname
);
266 kauth_cred_rele(cred
);
268 vnode_put(upperrootvp
);
270 vnode_put(lowerrootvp
);
275 * VFS start. Nothing needed here - the start routine
276 * on the underlying filesystem(s) will have been called
277 * when that filesystem was mounted.
280 union_start(__unused
struct mount
*mp
, __unused
int flags
, __unused vfs_context_t context
)
287 union_itercallback(__unused vnode_t vp
, void *args
)
289 int num
= *(int *)args
;
291 *(int *)args
= num
+ 1;
292 return(VNODE_RETURNED
);
298 * Free reference to union layer
301 union_unmount(mount_t mp
, int mntflags
, __unused vfs_context_t context
)
303 struct union_mount
*um
= MOUNTTOUNIONMOUNT(mp
);
304 struct vnode
*um_rootvp
;
310 #ifdef UNION_DIAGNOSTIC
311 printf("union_unmount(mp = %x)\n", mp
);
314 if (mntflags
& MNT_FORCE
)
317 if ((error
= union_root(mp
, &um_rootvp
)))
321 * Keep flushing vnodes from the mount list.
322 * This is needed because of the un_pvp held
323 * reference to the parent vnode.
324 * If more vnodes have been freed on a given pass,
325 * the try again. The loop will iterate at most
326 * (d) times, where (d) is the maximum tree depth
329 for (freeing
= 0; vflush(mp
, um_rootvp
, flags
) != 0;) {
332 vnode_iterate(mp
, VNODE_NOLOCK_INTERNAL
, union_itercallback
, &n
);
334 /* if this is unchanged then stop */
338 /* otherwise try once more time */
342 /* At this point the root vnode should have a single reference */
343 if (vnode_isinuse(um_rootvp
, 0)) {
344 vnode_put(um_rootvp
);
348 #ifdef UNION_DIAGNOSTIC
349 vprint("union root", um_rootvp
);
352 * Discard references to upper and lower target vnodes.
355 vnode_put(um
->um_lowervp
);
356 vnode_put(um
->um_uppervp
);
358 if (cred
!= NOCRED
) {
359 um
->um_cred
= NOCRED
;
360 kauth_cred_rele(cred
);
363 * Release reference on underlying root vnode
365 vnode_put(um_rootvp
);
367 * And blow it away for future re-use
369 vnode_reclaim(um_rootvp
);
371 * Finally, throw away the union_mount structure
373 _FREE(mp
->mnt_data
, M_UFSMNT
); /* XXX */
379 union_root(mount_t mp
, vnode_t
*vpp
, __unused vfs_context_t context
)
381 struct union_mount
*um
= MOUNTTOUNIONMOUNT(mp
);
385 * Return locked reference to root.
387 vnode_get(um
->um_uppervp
);
389 vnode_get(um
->um_lowervp
);
390 error
= union_allocvp(vpp
, mp
,
393 (struct componentname
*) 0,
399 vnode_put(um
->um_uppervp
);
401 vnode_put(um
->um_lowervp
);
408 union_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
411 struct union_mount
*um
= MOUNTTOUNIONMOUNT(mp
);
412 struct vfs_attr attr
;
415 #ifdef UNION_DIAGNOSTIC
416 printf("union_vfs_getattr(mp = %x, lvp = %x, uvp = %x)\n", mp
,
421 /* Get values from lower file system (if any) */
422 if (um
->um_lowervp
) {
424 VFSATTR_WANTED(&attr
, f_bsize
);
425 VFSATTR_WANTED(&attr
, f_blocks
);
426 VFSATTR_WANTED(&attr
, f_bused
);
427 VFSATTR_WANTED(&attr
, f_files
);
428 error
= vfs_getattr(um
->um_lowervp
->v_mount
, &attr
, context
);
432 /* now copy across the "interesting" information and fake the rest */
433 if (VFSATTR_IS_SUPPORTED(&attr
, f_bsize
))
434 lbsize
= attr
.f_bsize
;
436 lbsize
= um
->um_lowervp
->v_mount
->mnt_devblocksize
;
437 fsap
->f_blocks
= VFSATTR_IS_SUPPORTED(&attr
, f_blocks
) ? attr
.f_blocks
: 0;
438 fsap
->f_bused
= VFSATTR_IS_SUPPORTED(&attr
, f_bused
) ? attr
.f_bused
: 0;
439 fsap
->f_files
= VFSATTR_IS_SUPPORTED(&attr
, f_files
) ? attr
.f_files
: 0;
447 VFSATTR_WANTED(&attr
, f_bsize
);
448 VFSATTR_WANTED(&attr
, f_blocks
);
449 VFSATTR_WANTED(&attr
, f_bfree
);
450 VFSATTR_WANTED(&attr
, f_bavail
);
451 VFSATTR_WANTED(&attr
, f_files
);
452 VFSATTR_WANTED(&attr
, f_ffree
);
453 error
= vfs_getattr(um
->um_uppervp
->v_mount
, &attr
, context
);
457 if (VFSATTR_IS_SUPPORTED(&attr
, f_bsize
)) {
458 fsap
->f_bsize
= attr
.f_bsize
;
459 VFSATTR_SET_SUPPORTED(fsap
, f_bsize
);
461 if (VFSATTR_IS_SUPPORTED(&attr
, f_iosize
)) {
462 fsap
->f_iosize
= attr
.f_iosize
;
463 VFSATTR_SET_SUPPORTED(fsap
, f_iosize
);
467 * if the lower and upper blocksizes differ, then frig the
468 * block counts so that the sizes reported by df make some
469 * kind of sense. none of this makes sense though.
471 if (VFSATTR_IS_SUPPORTED(&attr
, f_bsize
))
472 fsap
->f_bsize
= attr
.f_bsize
;
474 fsap
->f_bsize
= um
->um_uppervp
->v_mount
->mnt_devblocksize
;
475 VFSATTR_RETURN(fsap
, f_bsize
, attr
.f_bsize
);
476 if (fsap
->f_bsize
!= lbsize
)
477 fsap
->f_blocks
= fsap
->f_blocks
* lbsize
/ attr
.f_bsize
;
480 * The "total" fields count total resources in all layers,
481 * the "free" fields count only those resources which are
482 * free in the upper layer (since only the upper layer
485 if (VFSATTR_IS_SUPPORTED(&attr
, f_blocks
))
486 fsap
->f_blocks
+= attr
.f_blocks
;
487 if (VFSATTR_IS_SUPPORTED(&attr
, f_bfree
))
488 fsap
->f_bfree
= attr
.f_bfree
;
489 if (VFSATTR_IS_SUPPORTED(&attr
, f_bavail
))
490 fsap
->f_bavail
= attr
.f_bavail
;
491 if (VFSATTR_IS_SUPPORTED(&attr
, f_bused
))
492 fsap
->f_bused
+= attr
.f_bused
;
493 if (VFSATTR_IS_SUPPORTED(&attr
, f_files
))
494 fsap
->f_files
+= attr
.f_files
;
495 if (VFSATTR_IS_SUPPORTED(&attr
, f_ffree
))
496 fsap
->f_ffree
= attr
.f_ffree
;
498 VFSATTR_SET_SUPPORTED(fsap
, f_bsize
);
499 VFSATTR_SET_SUPPORTED(fsap
, f_blocks
);
500 VFSATTR_SET_SUPPORTED(fsap
, f_bfree
);
501 VFSATTR_SET_SUPPORTED(fsap
, f_bavail
);
502 VFSATTR_SET_SUPPORTED(fsap
, f_bused
);
503 VFSATTR_SET_SUPPORTED(fsap
, f_files
);
504 VFSATTR_SET_SUPPORTED(fsap
, f_ffree
);
510 * XXX - Assumes no data cached at union layer.
512 #define union_sync (int (*) (mount_t, int, ucred_t, vfs_context_t))nullop
514 #define union_fhtovp (int (*) (mount_t, int, unsigned char *, vnode_t *, vfs_context_t))eopnotsupp
515 int union_init (struct vfsconf
*);
516 #define union_sysctl (int (*) (int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, vfs_context_t))eopnotsupp
517 #define union_vget (int (*) (mount_t, ino64_t, vnode_t *, vfs_context_t))eopnotsupp
518 #define union_vptofh (int (*) (vnode_t, int *, unsigned char *, vfs_context_t))eopnotsupp
520 struct vfsops union_vfsops
= {