1139776Simp/*- 222521Sdyson * Copyright (c) 1994, 1995 The Regents of the University of California. 322521Sdyson * Copyright (c) 1994, 1995 Jan-Simon Pendry. 4234867Sdaichi * Copyright (c) 2005, 2006, 2012 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 5234867Sdaichi * Copyright (c) 2006, 2012 Daichi Goto <daichi@freebsd.org> 61541Srgrimes * All rights reserved. 71541Srgrimes * 81541Srgrimes * This code is derived from software donated to Berkeley by 91541Srgrimes * Jan-Simon Pendry. 101541Srgrimes * 111541Srgrimes * Redistribution and use in source and binary forms, with or without 121541Srgrimes * modification, are permitted provided that the following conditions 131541Srgrimes * are met: 141541Srgrimes * 1. Redistributions of source code must retain the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer. 161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171541Srgrimes * notice, this list of conditions and the following disclaimer in the 181541Srgrimes * documentation and/or other materials provided with the distribution. 191541Srgrimes * 4. Neither the name of the University nor the names of its contributors 201541Srgrimes * may be used to endorse or promote products derived from this software 211541Srgrimes * without specific prior written permission. 221541Srgrimes * 231541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331541Srgrimes * SUCH DAMAGE. 341541Srgrimes * 3522521Sdyson * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 3650477Speter * $FreeBSD$ 371541Srgrimes */ 381541Srgrimes 391541Srgrimes#include <sys/param.h> 401541Srgrimes#include <sys/systm.h> 41164829Srodrigc#include <sys/kdb.h> 42177785Skib#include <sys/fcntl.h> 432979Swollman#include <sys/kernel.h> 4478906Sjhb#include <sys/lock.h> 45164829Srodrigc#include <sys/malloc.h> 46164829Srodrigc#include <sys/mount.h> 47164829Srodrigc#include <sys/namei.h> 481541Srgrimes#include <sys/proc.h> 491541Srgrimes#include <sys/vnode.h> 50164829Srodrigc#include <sys/stat.h> 51164829Srodrigc 5277031Sru#include <fs/unionfs/union.h> 531541Srgrimes 54164829Srodrigcstatic MALLOC_DEFINE(M_UNIONFSMNT, "UNIONFS mount", "UNIONFS mount structure"); 5530354Sphk 56164829Srodrigcstatic vfs_fhtovp_t unionfs_fhtovp; 57164829Srodrigcstatic vfs_checkexp_t unionfs_checkexp; 58164829Srodrigcstatic vfs_mount_t unionfs_domount; 59164829Srodrigcstatic vfs_quotactl_t unionfs_quotactl; 60164829Srodrigcstatic vfs_root_t unionfs_root; 61164829Srodrigcstatic vfs_sync_t unionfs_sync; 62164829Srodrigcstatic vfs_statfs_t unionfs_statfs; 63164829Srodrigcstatic vfs_unmount_t unionfs_unmount; 64164829Srodrigcstatic vfs_vget_t unionfs_vget; 65164829Srodrigcstatic vfs_extattrctl_t unionfs_extattrctl; 6612595Sbde 67164829Srodrigcstatic struct vfsops unionfs_vfsops; 68164829Srodrigc 691541Srgrimes/* 70164829Srodrigc * Mount unionfs layer. 71164829Srodrigc */ 7231273Sphkstatic int 73191990Sattiliounionfs_domount(struct mount *mp) 741541Srgrimes{ 75164829Srodrigc int error; 76164829Srodrigc struct vnode *lowerrootvp; 77164829Srodrigc struct vnode *upperrootvp; 78164829Srodrigc struct unionfs_mount *ump; 79191990Sattilio struct thread *td; 80164829Srodrigc char *target; 81164829Srodrigc char *tmp; 82164829Srodrigc char *ep; 83164829Srodrigc int len; 84164829Srodrigc size_t done; 85164829Srodrigc int below; 86164829Srodrigc uid_t uid; 87164829Srodrigc gid_t gid; 88164829Srodrigc u_short udir; 89164829Srodrigc u_short ufile; 90164829Srodrigc unionfs_copymode copymode; 91172643Sdaichi unionfs_whitemode whitemode; 92164829Srodrigc struct nameidata nd, *ndp; 93164829Srodrigc struct vattr va; 941541Srgrimes 95164829Srodrigc UNIONFSDEBUG("unionfs_mount(mp = %p)\n", (void *)mp); 961541Srgrimes 97164829Srodrigc error = 0; 98164829Srodrigc below = 0; 99164829Srodrigc uid = 0; 100164829Srodrigc gid = 0; 101164829Srodrigc udir = 0; 102164829Srodrigc ufile = 0; 103172642Sdaichi copymode = UNIONFS_TRANSPARENT; /* default */ 104172643Sdaichi whitemode = UNIONFS_WHITE_ALWAYS; 105164829Srodrigc ndp = &nd; 106191990Sattilio td = curthread; 10729888Skato 108165036Srodrigc if (mp->mnt_flag & MNT_ROOTFS) { 109165036Srodrigc vfs_mount_error(mp, "Cannot union mount root filesystem"); 110137479Sphk return (EOPNOTSUPP); 111165036Srodrigc } 112164829Srodrigc 11329888Skato /* 114164829Srodrigc * Update is a no operation. 1151541Srgrimes */ 116165036Srodrigc if (mp->mnt_flag & MNT_UPDATE) { 117165036Srodrigc vfs_mount_error(mp, "unionfs does not support mount update"); 11897195Smux return (EOPNOTSUPP); 119165036Srodrigc } 1201541Srgrimes 1211541Srgrimes /* 122164829Srodrigc * Get argument 1231541Srgrimes */ 124164829Srodrigc error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 125164829Srodrigc if (error) 126164829Srodrigc error = vfs_getopt(mp->mnt_optnew, "from", (void **)&target, 127164829Srodrigc &len); 128164829Srodrigc if (error || target[len - 1] != '\0') { 129164829Srodrigc vfs_mount_error(mp, "Invalid target"); 13097195Smux return (EINVAL); 131164829Srodrigc } 132164829Srodrigc if (vfs_getopt(mp->mnt_optnew, "below", NULL, NULL) == 0) 133164829Srodrigc below = 1; 134164829Srodrigc if (vfs_getopt(mp->mnt_optnew, "udir", (void **)&tmp, NULL) == 0) { 135164829Srodrigc if (tmp != NULL) 136164829Srodrigc udir = (mode_t)strtol(tmp, &ep, 8); 137164829Srodrigc if (tmp == NULL || *ep) { 138164829Srodrigc vfs_mount_error(mp, "Invalid udir"); 13998266Smux return (EINVAL); 140164829Srodrigc } 141185284Sdaichi udir &= S_IRWXU | S_IRWXG | S_IRWXO; 14298266Smux } 143164829Srodrigc if (vfs_getopt(mp->mnt_optnew, "ufile", (void **)&tmp, NULL) == 0) { 144164829Srodrigc if (tmp != NULL) 145164829Srodrigc ufile = (mode_t)strtol(tmp, &ep, 8); 146164829Srodrigc if (tmp == NULL || *ep) { 147164829Srodrigc vfs_mount_error(mp, "Invalid ufile"); 148164829Srodrigc return (EINVAL); 149164829Srodrigc } 150185284Sdaichi ufile &= S_IRWXU | S_IRWXG | S_IRWXO; 151164829Srodrigc } 152164829Srodrigc /* check umask, uid and gid */ 153164829Srodrigc if (udir == 0 && ufile != 0) 154164829Srodrigc udir = ufile; 155164829Srodrigc if (ufile == 0 && udir != 0) 156164829Srodrigc ufile = udir; 15797195Smux 158175202Sattilio vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY); 159182371Sattilio error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred); 160164829Srodrigc if (!error) { 161164829Srodrigc if (udir == 0) 162164829Srodrigc udir = va.va_mode; 163164829Srodrigc if (ufile == 0) 164164829Srodrigc ufile = va.va_mode; 165164829Srodrigc uid = va.va_uid; 166164829Srodrigc gid = va.va_gid; 167164829Srodrigc } 168234867Sdaichi VOP_UNLOCK(mp->mnt_vnodecovered, LK_RELEASE); 1693496Sphk if (error) 170164829Srodrigc return (error); 1711541Srgrimes 172164829Srodrigc if (mp->mnt_cred->cr_ruid == 0) { /* root only */ 173164829Srodrigc if (vfs_getopt(mp->mnt_optnew, "uid", (void **)&tmp, 174164829Srodrigc NULL) == 0) { 175164829Srodrigc if (tmp != NULL) 176164829Srodrigc uid = (uid_t)strtol(tmp, &ep, 10); 177164829Srodrigc if (tmp == NULL || *ep) { 178164829Srodrigc vfs_mount_error(mp, "Invalid uid"); 179164829Srodrigc return (EINVAL); 180164829Srodrigc } 181164829Srodrigc } 182164829Srodrigc if (vfs_getopt(mp->mnt_optnew, "gid", (void **)&tmp, 183164829Srodrigc NULL) == 0) { 184164829Srodrigc if (tmp != NULL) 185164829Srodrigc gid = (gid_t)strtol(tmp, &ep, 10); 186164829Srodrigc if (tmp == NULL || *ep) { 187164829Srodrigc vfs_mount_error(mp, "Invalid gid"); 188164829Srodrigc return (EINVAL); 189164829Srodrigc } 190164829Srodrigc } 191164829Srodrigc if (vfs_getopt(mp->mnt_optnew, "copymode", (void **)&tmp, 192164829Srodrigc NULL) == 0) { 193164829Srodrigc if (tmp == NULL) { 194164829Srodrigc vfs_mount_error(mp, "Invalid copymode"); 195164829Srodrigc return (EINVAL); 196164829Srodrigc } else if (strcasecmp(tmp, "traditional") == 0) 197164829Srodrigc copymode = UNIONFS_TRADITIONAL; 198164829Srodrigc else if (strcasecmp(tmp, "transparent") == 0) 199164829Srodrigc copymode = UNIONFS_TRANSPARENT; 200164829Srodrigc else if (strcasecmp(tmp, "masquerade") == 0) 201164829Srodrigc copymode = UNIONFS_MASQUERADE; 202164829Srodrigc else { 203164829Srodrigc vfs_mount_error(mp, "Invalid copymode"); 204164829Srodrigc return (EINVAL); 205164829Srodrigc } 206164829Srodrigc } 207172643Sdaichi if (vfs_getopt(mp->mnt_optnew, "whiteout", (void **)&tmp, 208172643Sdaichi NULL) == 0) { 209172643Sdaichi if (tmp == NULL) { 210172643Sdaichi vfs_mount_error(mp, "Invalid whiteout mode"); 211172643Sdaichi return (EINVAL); 212172643Sdaichi } else if (strcasecmp(tmp, "always") == 0) 213172643Sdaichi whitemode = UNIONFS_WHITE_ALWAYS; 214172643Sdaichi else if (strcasecmp(tmp, "whenneeded") == 0) 215172643Sdaichi whitemode = UNIONFS_WHITE_WHENNEEDED; 216172643Sdaichi else { 217172643Sdaichi vfs_mount_error(mp, "Invalid whiteout mode"); 218172643Sdaichi return (EINVAL); 219172643Sdaichi } 220172643Sdaichi } 22124921Skato } 222164829Srodrigc /* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */ 223164829Srodrigc if (copymode == UNIONFS_TRADITIONAL) { 224164829Srodrigc uid = mp->mnt_cred->cr_ruid; 225164829Srodrigc gid = mp->mnt_cred->cr_rgid; 2261541Srgrimes } 2278876Srgrimes 228164829Srodrigc UNIONFSDEBUG("unionfs_mount: uid=%d, gid=%d\n", uid, gid); 229164829Srodrigc UNIONFSDEBUG("unionfs_mount: udir=0%03o, ufile=0%03o\n", udir, ufile); 230164829Srodrigc UNIONFSDEBUG("unionfs_mount: copymode=%d\n", copymode); 231164829Srodrigc 2321541Srgrimes /* 233164829Srodrigc * Find upper node 2341541Srgrimes */ 235184650Sjhb NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, target, td); 236164829Srodrigc if ((error = namei(ndp))) 237164829Srodrigc return (error); 2381541Srgrimes 239164829Srodrigc NDFREE(ndp, NDF_ONLY_PNBUF); 24051688Sdillon 241164829Srodrigc /* get root vnodes */ 242164829Srodrigc lowerrootvp = mp->mnt_vnodecovered; 243164829Srodrigc upperrootvp = ndp->ni_vp; 24451688Sdillon 245164829Srodrigc /* create unionfs_mount */ 246164829Srodrigc ump = (struct unionfs_mount *)malloc(sizeof(struct unionfs_mount), 247164829Srodrigc M_UNIONFSMNT, M_WAITOK | M_ZERO); 248136135Stakawata 249164829Srodrigc /* 250164829Srodrigc * Save reference 251164829Srodrigc */ 252164829Srodrigc if (below) { 253234867Sdaichi VOP_UNLOCK(upperrootvp, LK_RELEASE); 254175202Sattilio vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY); 255164829Srodrigc ump->um_lowervp = upperrootvp; 256164829Srodrigc ump->um_uppervp = lowerrootvp; 257164829Srodrigc } else { 258164829Srodrigc ump->um_lowervp = lowerrootvp; 259164829Srodrigc ump->um_uppervp = upperrootvp; 260164829Srodrigc } 261164829Srodrigc ump->um_rootvp = NULLVP; 262164829Srodrigc ump->um_uid = uid; 263164829Srodrigc ump->um_gid = gid; 264164829Srodrigc ump->um_udir = udir; 265164829Srodrigc ump->um_ufile = ufile; 266164829Srodrigc ump->um_copymode = copymode; 267172643Sdaichi ump->um_whitemode = whitemode; 2681541Srgrimes 269172697Salfred mp->mnt_data = ump; 2701541Srgrimes 271164829Srodrigc /* 272164829Srodrigc * Copy upper layer's RDONLY flag. 273164829Srodrigc */ 274164829Srodrigc mp->mnt_flag |= ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY; 2751541Srgrimes 27622521Sdyson /* 277164829Srodrigc * Unlock the node 278164829Srodrigc */ 279234867Sdaichi VOP_UNLOCK(ump->um_uppervp, LK_RELEASE); 2801541Srgrimes 2811541Srgrimes /* 282164829Srodrigc * Get the unionfs root vnode. 2831541Srgrimes */ 284164829Srodrigc error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp, 285164829Srodrigc NULLVP, &(ump->um_rootvp), NULL, td); 286172641Sdaichi vrele(upperrootvp); 287164829Srodrigc if (error) { 288164829Srodrigc free(ump, M_UNIONFSMNT); 289164829Srodrigc mp->mnt_data = NULL; 290164829Srodrigc return (error); 2911541Srgrimes } 2921541Srgrimes 2931541Srgrimes /* 294164829Srodrigc * Check mnt_flag 2951541Srgrimes */ 296164829Srodrigc if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) && 297164829Srodrigc (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) 298164829Srodrigc mp->mnt_flag |= MNT_LOCAL; 2991541Srgrimes 300164829Srodrigc /* 301164829Srodrigc * Get new fsid 302164829Srodrigc */ 30322521Sdyson vfs_getnewfsid(mp); 3041541Srgrimes 305164829Srodrigc len = MNAMELEN - 1; 306164829Srodrigc tmp = mp->mnt_stat.f_mntfromname; 307164829Srodrigc copystr((below ? "<below>:" : "<above>:"), tmp, len, &done); 308164829Srodrigc len -= done - 1; 309164829Srodrigc tmp += done - 1; 310164829Srodrigc copystr(target, tmp, len, NULL); 3111541Srgrimes 312164829Srodrigc UNIONFSDEBUG("unionfs_mount: from %s, on %s\n", 313164829Srodrigc mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 3141541Srgrimes 3151541Srgrimes return (0); 3161541Srgrimes} 3171541Srgrimes 3181541Srgrimes/* 319164829Srodrigc * Free reference to unionfs layer 3201541Srgrimes */ 32131273Sphkstatic int 322191990Sattiliounionfs_unmount(struct mount *mp, int mntflags) 3231541Srgrimes{ 324164829Srodrigc struct unionfs_mount *ump; 325164829Srodrigc int error; 326164829Srodrigc int num; 327164829Srodrigc int freeing; 328164829Srodrigc int flags; 3291541Srgrimes 330164829Srodrigc UNIONFSDEBUG("unionfs_unmount: mp = %p\n", (void *)mp); 3311541Srgrimes 332164829Srodrigc ump = MOUNTTOUNIONFSMOUNT(mp); 333164829Srodrigc flags = 0; 334164829Srodrigc 33522521Sdyson if (mntflags & MNT_FORCE) 33622521Sdyson flags |= FORCECLOSE; 33722521Sdyson 338164829Srodrigc /* vflush (no need to call vrele) */ 339191990Sattilio for (freeing = 0; (error = vflush(mp, 1, flags, curthread)) != 0;) { 340164829Srodrigc num = mp->mnt_nvnodelistsize; 341164829Srodrigc if (num == freeing) 34222521Sdyson break; 343164829Srodrigc freeing = num; 3441541Srgrimes } 3451541Srgrimes 34676688Siedowse if (error) 34776688Siedowse return (error); 3481541Srgrimes 349164829Srodrigc free(ump, M_UNIONFSMNT); 350232918Skevlo mp->mnt_data = NULL; 351164829Srodrigc 3521541Srgrimes return (0); 3531541Srgrimes} 3541541Srgrimes 35531273Sphkstatic int 356191990Sattiliounionfs_root(struct mount *mp, int flags, struct vnode **vpp) 3571541Srgrimes{ 358164829Srodrigc struct unionfs_mount *ump; 359164829Srodrigc struct vnode *vp; 3601541Srgrimes 361164829Srodrigc ump = MOUNTTOUNIONFSMOUNT(mp); 362164829Srodrigc vp = ump->um_rootvp; 36351688Sdillon 364164829Srodrigc UNIONFSDEBUG("unionfs_root: rootvp=%p locked=%x\n", 365176559Sattilio vp, VOP_ISLOCKED(vp)); 3661541Srgrimes 367164829Srodrigc vref(vp); 368164829Srodrigc if (flags & LK_TYPE_MASK) 369175202Sattilio vn_lock(vp, flags); 3701541Srgrimes 371164829Srodrigc *vpp = vp; 372164829Srodrigc 373164829Srodrigc return (0); 3741541Srgrimes} 3751541Srgrimes 37631273Sphkstatic int 377191990Sattiliounionfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg) 3781541Srgrimes{ 379164829Srodrigc struct unionfs_mount *ump; 3801541Srgrimes 381164829Srodrigc ump = MOUNTTOUNIONFSMOUNT(mp); 3821541Srgrimes 383164829Srodrigc /* 384164829Srodrigc * Writing is always performed to upper vnode. 385164829Srodrigc */ 386191990Sattilio return (VFS_QUOTACTL(ump->um_uppervp->v_mount, cmd, uid, arg)); 387164829Srodrigc} 388164829Srodrigc 389164829Srodrigcstatic int 390191990Sattiliounionfs_statfs(struct mount *mp, struct statfs *sbp) 391164829Srodrigc{ 392164829Srodrigc struct unionfs_mount *ump; 393164829Srodrigc int error; 394164829Srodrigc struct statfs mstat; 395164829Srodrigc uint64_t lbsize; 396164829Srodrigc 397164829Srodrigc ump = MOUNTTOUNIONFSMOUNT(mp); 398164829Srodrigc 399164829Srodrigc UNIONFSDEBUG("unionfs_statfs(mp = %p, lvp = %p, uvp = %p)\n", 400164829Srodrigc (void *)mp, (void *)ump->um_lowervp, (void *)ump->um_uppervp); 401164829Srodrigc 4021541Srgrimes bzero(&mstat, sizeof(mstat)); 4031541Srgrimes 404191990Sattilio error = VFS_STATFS(ump->um_lowervp->v_mount, &mstat); 405164829Srodrigc if (error) 406164829Srodrigc return (error); 4071541Srgrimes 408164829Srodrigc /* now copy across the "interesting" information and fake the rest */ 4091541Srgrimes sbp->f_blocks = mstat.f_blocks; 4101541Srgrimes sbp->f_files = mstat.f_files; 4111541Srgrimes 412164829Srodrigc lbsize = mstat.f_bsize; 413164829Srodrigc 414191990Sattilio error = VFS_STATFS(ump->um_uppervp->v_mount, &mstat); 4151541Srgrimes if (error) 4161541Srgrimes return (error); 4171541Srgrimes 418164829Srodrigc /* 419164829Srodrigc * The FS type etc is copy from upper vfs. 420164829Srodrigc * (write able vfs have priority) 421164829Srodrigc */ 422164829Srodrigc sbp->f_type = mstat.f_type; 4231541Srgrimes sbp->f_flags = mstat.f_flags; 4241541Srgrimes sbp->f_bsize = mstat.f_bsize; 4251541Srgrimes sbp->f_iosize = mstat.f_iosize; 4261541Srgrimes 42722521Sdyson if (mstat.f_bsize != lbsize) 428164829Srodrigc sbp->f_blocks = ((off_t)sbp->f_blocks * lbsize) / mstat.f_bsize; 42922521Sdyson 4301541Srgrimes sbp->f_blocks += mstat.f_blocks; 43122521Sdyson sbp->f_bfree = mstat.f_bfree; 43222521Sdyson sbp->f_bavail = mstat.f_bavail; 4331541Srgrimes sbp->f_files += mstat.f_files; 43422521Sdyson sbp->f_ffree = mstat.f_ffree; 4351541Srgrimes return (0); 4361541Srgrimes} 4371541Srgrimes 438164829Srodrigcstatic int 439191990Sattiliounionfs_sync(struct mount *mp, int waitfor) 440164829Srodrigc{ 441164829Srodrigc /* nothing to do */ 442164829Srodrigc return (0); 443164829Srodrigc} 444164829Srodrigc 445164829Srodrigcstatic int 446164829Srodrigcunionfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 447164829Srodrigc{ 448164829Srodrigc return (EOPNOTSUPP); 449164829Srodrigc} 450164829Srodrigc 451164829Srodrigcstatic int 452222167Srmacklemunionfs_fhtovp(struct mount *mp, struct fid *fidp, int flags, 453222167Srmacklem struct vnode **vpp) 454164829Srodrigc{ 455164829Srodrigc return (EOPNOTSUPP); 456164829Srodrigc} 457164829Srodrigc 458164829Srodrigcstatic int 459164829Srodrigcunionfs_checkexp(struct mount *mp, struct sockaddr *nam, int *extflagsp, 460184588Sdfr struct ucred **credanonp, int *numsecflavors, int **secflavors) 461164829Srodrigc{ 462164829Srodrigc return (EOPNOTSUPP); 463164829Srodrigc} 464164829Srodrigc 465164829Srodrigcstatic int 466164829Srodrigcunionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, 467191990Sattilio int namespace, const char *attrname) 468164829Srodrigc{ 469164829Srodrigc struct unionfs_mount *ump; 470164829Srodrigc struct unionfs_node *unp; 471164829Srodrigc 472164829Srodrigc ump = MOUNTTOUNIONFSMOUNT(mp); 473164829Srodrigc unp = VTOUNIONFS(filename_vp); 474164829Srodrigc 475164829Srodrigc if (unp->un_uppervp != NULLVP) { 476164829Srodrigc return (VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd, 477191990Sattilio unp->un_uppervp, namespace, attrname)); 478164829Srodrigc } else { 479164829Srodrigc return (VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd, 480191990Sattilio unp->un_lowervp, namespace, attrname)); 481164829Srodrigc } 482164829Srodrigc} 483164829Srodrigc 484164829Srodrigcstatic struct vfsops unionfs_vfsops = { 485164829Srodrigc .vfs_checkexp = unionfs_checkexp, 486164829Srodrigc .vfs_extattrctl = unionfs_extattrctl, 487164829Srodrigc .vfs_fhtovp = unionfs_fhtovp, 488164829Srodrigc .vfs_init = unionfs_init, 489164829Srodrigc .vfs_mount = unionfs_domount, 490164829Srodrigc .vfs_quotactl = unionfs_quotactl, 491164829Srodrigc .vfs_root = unionfs_root, 492164829Srodrigc .vfs_statfs = unionfs_statfs, 493164829Srodrigc .vfs_sync = unionfs_sync, 494164829Srodrigc .vfs_uninit = unionfs_uninit, 495164829Srodrigc .vfs_unmount = unionfs_unmount, 496164829Srodrigc .vfs_vget = unionfs_vget, 4971541Srgrimes}; 4982946Swollman 499164829SrodrigcVFS_SET(unionfs_vfsops, unionfs, VFCF_LOOPBACK); 500