2 * Copyright (c) 1994, 1995 The Regents of the University of California.
3 * Copyright (c) 1994, 1995 Jan-Simon Pendry.
4 * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
5 * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
8 * This code is derived from software donated to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
36 * $FreeBSD: src/sys/fs/unionfs/union_vfsops.c,v 1.89 2008/01/13 14:44:06 attilio Exp $
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
45 #include <sys/namei.h>
47 #include <sys/vnode.h>
49 #include <sys/sysctl.h>
50 #include <sys/module.h>
52 #include <fs/unionfs/unionfs.h>
54 MODULE(MODULE_CLASS_VFS
, unionfs
, "layerfs");
56 MALLOC_DEFINE(M_UNIONFSMNT
, "UNIONFS mount", "UNIONFS mount structure");
58 struct vfsops unionfs_vfsops
;
62 static struct sysctllog
*unionfs_sysctl_log
;
65 * Mount unionfs layer.
68 unionfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
71 struct vnode
*lowerrootvp
;
72 struct vnode
*upperrootvp
;
73 struct unionfs_mount
*ump
;
79 unionfs_copymode copymode
;
80 unionfs_whitemode whitemode
;
81 struct componentname fakecn
;
82 struct nameidata nd
, *ndp
;
84 struct union_args
*args
= data
;
91 if (*data_len
< sizeof *args
)
94 UNIONFSDEBUG("unionfs_mount(mp = %p)\n", (void *)mp
);
102 copymode
= UNIONFS_TRANSPARENT
; /* default */
103 whitemode
= UNIONFS_WHITE_ALWAYS
;
105 cred
= kauth_cred_get();
107 if (mp
->mnt_flag
& MNT_ROOTFS
) {
108 printf("union_mount: cannot union mount root filesystem\n");
112 if (mp
->mnt_flag
& MNT_GETARGS
) {
113 ump
= MOUNTTOUNIONFSMOUNT(mp
);
117 args
->mntflags
= ump
->um_op
;
118 *data_len
= sizeof *args
;
123 * Update is a no operation.
125 if (mp
->mnt_flag
& MNT_UPDATE
) {
126 printf("union_mount: cannot update union mount\n");
130 vn_lock(mp
->mnt_vnodecovered
, LK_EXCLUSIVE
| LK_RETRY
);
131 error
= VOP_GETATTR(mp
->mnt_vnodecovered
, &va
, cred
);
140 VOP_UNLOCK(mp
->mnt_vnodecovered
, 0);
144 switch (args
->mntflags
& UNMNT_OPMASK
) {
158 /* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */
159 if (copymode
== UNIONFS_TRADITIONAL
) {
160 uid
= kauth_cred_getuid(cred
);
161 gid
= kauth_cred_getgid(cred
);
164 UNIONFSDEBUG("unionfs_mount: uid=%d, gid=%d\n", uid
, gid
);
165 UNIONFSDEBUG("unionfs_mount: udir=0%03o, ufile=0%03o\n", udir
, ufile
);
166 UNIONFSDEBUG("unionfs_mount: copymode=%d\n", copymode
);
171 NDINIT(ndp
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
, args
->target
);
172 if ((error
= namei(ndp
)))
175 /* get root vnodes */
176 lowerrootvp
= mp
->mnt_vnodecovered
;
177 upperrootvp
= ndp
->ni_vp
;
180 ndp
->ni_dvp
= NULLVP
;
182 /* create unionfs_mount */
183 ump
= (struct unionfs_mount
*)malloc(sizeof(struct unionfs_mount
),
184 M_UNIONFSMNT
, M_WAITOK
| M_ZERO
);
190 VOP_UNLOCK(upperrootvp
, 0);
191 vn_lock(lowerrootvp
, LK_EXCLUSIVE
| LK_RETRY
);
192 ump
->um_lowervp
= upperrootvp
;
193 ump
->um_uppervp
= lowerrootvp
;
195 ump
->um_lowervp
= lowerrootvp
;
196 ump
->um_uppervp
= upperrootvp
;
198 ump
->um_rootvp
= NULLVP
;
202 ump
->um_ufile
= ufile
;
203 ump
->um_copymode
= copymode
;
204 ump
->um_whitemode
= whitemode
;
206 if ((lowerrootvp
->v_mount
->mnt_iflag
& IMNT_MPSAFE
) &&
207 (upperrootvp
->v_mount
->mnt_flag
& IMNT_MPSAFE
))
208 mp
->mnt_iflag
|= IMNT_MPSAFE
;
212 * Copy upper layer's RDONLY flag.
214 mp
->mnt_flag
|= ump
->um_uppervp
->v_mount
->mnt_flag
& MNT_RDONLY
;
219 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
220 memset(&fakecn
, 0, sizeof(fakecn
));
221 fakecn
.cn_nameiop
= LOOKUP
;
222 error
= VOP_WHITEOUT(ump
->um_uppervp
, &fakecn
, LOOKUP
);
225 VOP_UNLOCK(ump
->um_uppervp
, 0);
228 vput(ump
->um_uppervp
);
229 free(ump
, M_UNIONFSMNT
);
238 VOP_UNLOCK(ump
->um_uppervp
, 0);
240 ump
->um_op
= args
->mntflags
& UNMNT_OPMASK
;
243 * Get the unionfs root vnode.
245 error
= unionfs_nodeget(mp
, ump
->um_uppervp
, ump
->um_lowervp
,
246 NULLVP
, &(ump
->um_rootvp
), NULL
);
249 free(ump
, M_UNIONFSMNT
);
257 if ((ump
->um_lowervp
->v_mount
->mnt_flag
& MNT_LOCAL
) &&
258 (ump
->um_uppervp
->v_mount
->mnt_flag
& MNT_LOCAL
))
259 mp
->mnt_flag
|= MNT_LOCAL
;
266 error
= set_statvfs_info(path
, UIO_USERSPACE
, NULL
, UIO_USERSPACE
,
267 mp
->mnt_op
->vfs_name
, mp
, curlwp
);
269 unionfs_noderem(ump
->um_rootvp
);
270 free(ump
, M_UNIONFSMNT
);
275 switch (ump
->um_op
) {
283 panic("union_mount: bad um_op");
287 memcpy(mp
->mnt_stat
.f_mntfromname
, cp
, len
);
288 xp
= mp
->mnt_stat
.f_mntfromname
+ len
;
289 len
= MNAMELEN
- len
;
290 (void) copyinstr(args
->target
, xp
, len
- 1, &size
);
291 memset(xp
+ size
, 0, len
- size
);
293 UNIONFSDEBUG("unionfs_mount: from %s, on %s\n",
294 mp
->mnt_stat
.f_mntfromname
, mp
->mnt_stat
.f_mntonname
);
300 * Free reference to unionfs layer
303 unionfs_unmount(struct mount
*mp
, int mntflags
)
305 struct unionfs_mount
*ump
;
310 UNIONFSDEBUG("unionfs_unmount: mp = %p\n", (void *)mp
);
312 ump
= MOUNTTOUNIONFSMOUNT(mp
);
315 if (mntflags
& MNT_FORCE
)
318 /* vflush (no need to call vrele) */
319 for (freeing
= 0; (error
= vflush(mp
, NULL
, flags
)) != 0;) {
323 /* count #vnodes held on mount list */
325 TAILQ_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
)
328 /* if this is unchanged then stop */
332 /* otherwise try once more time */
339 free(ump
, M_UNIONFSMNT
);
346 unionfs_root(struct mount
*mp
, struct vnode
**vpp
)
348 struct unionfs_mount
*ump
;
351 ump
= MOUNTTOUNIONFSMOUNT(mp
);
354 UNIONFSDEBUG("unionfs_root: rootvp=%p locked=%x\n",
355 vp
, VOP_ISLOCKED(vp
));
358 vn_lock(vp
, LK_EXCLUSIVE
);
366 unionfs_quotactl(struct mount
*mp
, int cmd
, uid_t uid
, void *arg
)
368 struct unionfs_mount
*ump
;
370 ump
= MOUNTTOUNIONFSMOUNT(mp
);
373 * Writing is always performed to upper vnode.
375 return (VFS_QUOTACTL(ump
->um_uppervp
->v_mount
, cmd
, uid
, arg
));
379 unionfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
381 struct unionfs_mount
*ump
;
384 struct statvfs
*sbuf
= malloc(sizeof(*sbuf
), M_TEMP
, M_WAITOK
| M_ZERO
);
386 ump
= MOUNTTOUNIONFSMOUNT(mp
);
388 UNIONFSDEBUG("unionfs_statvfs(mp = %p, lvp = %p, uvp = %p)\n",
389 (void *)mp
, (void *)ump
->um_lowervp
, (void *)ump
->um_uppervp
);
391 error
= VFS_STATVFS(ump
->um_lowervp
->v_mount
, sbuf
);
395 /* now copy across the "interesting" information and fake the rest */
396 sbp
->f_blocks
= sbuf
->f_blocks
;
397 sbp
->f_files
= sbuf
->f_files
;
399 lbsize
= sbuf
->f_bsize
;
401 error
= VFS_STATVFS(ump
->um_uppervp
->v_mount
, sbuf
);
406 * The FS type etc is copy from upper vfs.
407 * (write able vfs have priority)
409 sbp
->f_flag
= sbuf
->f_flag
;
410 sbp
->f_bsize
= sbuf
->f_bsize
;
411 sbp
->f_iosize
= sbuf
->f_iosize
;
413 if (sbuf
->f_bsize
!= lbsize
)
414 sbp
->f_blocks
= ((off_t
)sbp
->f_blocks
* lbsize
) / sbuf
->f_bsize
;
416 sbp
->f_blocks
+= sbuf
->f_blocks
;
417 sbp
->f_bfree
= sbuf
->f_bfree
;
418 sbp
->f_bavail
= sbuf
->f_bavail
;
419 sbp
->f_files
+= sbuf
->f_files
;
420 sbp
->f_ffree
= sbuf
->f_ffree
;
428 unionfs_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
435 unionfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
441 unionfs_fhtovp(struct mount
*mp
, struct fid
*fidp
, struct vnode
**vpp
)
447 unionfs_extattrctl(struct mount
*mp
, int cmd
, struct vnode
*filename_vp
,
448 int namespace, const char *attrname
)
450 struct unionfs_mount
*ump
;
451 struct unionfs_node
*unp
;
453 ump
= MOUNTTOUNIONFSMOUNT(mp
);
454 unp
= VTOUNIONFS(filename_vp
);
456 if (unp
->un_uppervp
!= NULLVP
) {
457 return (VFS_EXTATTRCTL(ump
->um_uppervp
->v_mount
, cmd
,
458 unp
->un_uppervp
, namespace, attrname
));
460 return (VFS_EXTATTRCTL(ump
->um_lowervp
->v_mount
, cmd
,
461 unp
->un_lowervp
, namespace, attrname
));
471 UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */
475 unionfs_renamelock_enter(struct mount
*mp
)
477 struct unionfs_mount
*um
= MOUNTTOUNIONFSMOUNT(mp
);
479 /* Lock just the upper fs, where the action happens. */
480 return VFS_RENAMELOCK_ENTER(um
->um_uppervp
->v_mount
);
484 unionfs_renamelock_exit(struct mount
*mp
)
486 struct unionfs_mount
*um
= MOUNTTOUNIONFSMOUNT(mp
);
488 VFS_RENAMELOCK_EXIT(um
->um_uppervp
->v_mount
);
492 unionfs_start(struct mount
*mp
, int flags
)
502 /* Make sure to unset the readdir hook. */
503 vn_union_readdir_hook
= NULL
;
506 extern const struct vnodeopv_desc unionfs_vnodeop_opv_desc
;
508 const struct vnodeopv_desc
* const unionfs_vnodeopv_descs
[] = {
509 &unionfs_vnodeop_opv_desc
,
513 struct vfsops unionfs_vfsops
= {
515 sizeof (struct unionfs_args
),
520 (void *)eopnotsupp
, /* vfs_quotactl */
524 (void *)eopnotsupp
, /* vfs_fhtovp */
525 (void *)eopnotsupp
, /* vfs_vptofh */
527 NULL
, /* vfs_reinit */
529 NULL
, /* vfs_mountroot */
530 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
532 (void *)eopnotsupp
, /* vfs_suspendctl */
533 unionfs_renamelock_enter
,
534 unionfs_renamelock_exit
,
536 unionfs_vnodeopv_descs
,
537 0, /* vfs_refcount */
542 unionfs_modcmd(modcmd_t cmd
, void *arg
)
547 case MODULE_CMD_INIT
:
548 error
= vfs_attach(&unionfs_vfsops
);
551 sysctl_createv(&unionfs_sysctl_log
, 0, NULL
, NULL
,
553 CTLTYPE_NODE
, "vfs", NULL
,
556 sysctl_createv(&unionfs_sysctl_log
, 0, NULL
, NULL
,
558 CTLTYPE_NODE
, "union",
559 SYSCTL_DESCR("Union file system"),
561 CTL_VFS
, 15, CTL_EOL
);
563 * XXX the "15" above could be dynamic, thereby eliminating
564 * one more instance of the "number to vfs" mapping problem,
565 * but "15" is the order as taken from sys/mount.h
568 case MODULE_CMD_FINI
:
569 error
= vfs_detach(&unionfs_vfsops
);
572 sysctl_teardown(&unionfs_sysctl_log
);