1 1.1 ad /*- 2 1.1 ad * Copyright (c) 1994, 1995 The Regents of the University of California. 3 1.1 ad * Copyright (c) 1994, 1995 Jan-Simon Pendry. 4 1.1 ad * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa (at) ongs.co.jp>, ONGS Inc. 5 1.1 ad * Copyright (c) 2006 Daichi Goto <daichi (at) freebsd.org> 6 1.1 ad * All rights reserved. 7 1.1 ad * 8 1.1 ad * This code is derived from software donated to Berkeley by 9 1.1 ad * Jan-Simon Pendry. 10 1.1 ad * 11 1.1 ad * Redistribution and use in source and binary forms, with or without 12 1.1 ad * modification, are permitted provided that the following conditions 13 1.1 ad * are met: 14 1.1 ad * 1. Redistributions of source code must retain the above copyright 15 1.1 ad * notice, this list of conditions and the following disclaimer. 16 1.1 ad * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 ad * notice, this list of conditions and the following disclaimer in the 18 1.1 ad * documentation and/or other materials provided with the distribution. 19 1.1 ad * 4. Neither the name of the University nor the names of its contributors 20 1.1 ad * may be used to endorse or promote products derived from this software 21 1.1 ad * without specific prior written permission. 22 1.1 ad * 23 1.1 ad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 1.1 ad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 ad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 ad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 1.1 ad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 ad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 ad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 ad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 ad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 ad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 ad * SUCH DAMAGE. 34 1.1 ad * 35 1.1 ad * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 36 1.1 ad * $FreeBSD: src/sys/fs/unionfs/union_vfsops.c,v 1.89 2008/01/13 14:44:06 attilio Exp $ 37 1.1 ad */ 38 1.1 ad 39 1.1 ad #include <sys/param.h> 40 1.1 ad #include <sys/systm.h> 41 1.1 ad #include <sys/kernel.h> 42 1.1 ad #include <sys/lock.h> 43 1.1 ad #include <sys/mount.h> 44 1.1 ad #include <sys/namei.h> 45 1.1 ad #include <sys/proc.h> 46 1.1 ad #include <sys/vnode.h> 47 1.1 ad #include <sys/stat.h> 48 1.1 ad #include <sys/sysctl.h> 49 1.3 rumble #include <sys/module.h> 50 1.1 ad 51 1.1 ad #include <fs/unionfs/unionfs.h> 52 1.1 ad 53 1.6 ad MODULE(MODULE_CLASS_VFS, unionfs, "layerfs"); 54 1.3 rumble 55 1.1 ad MALLOC_DEFINE(M_UNIONFSMNT, "UNIONFS mount", "UNIONFS mount structure"); 56 1.1 ad 57 1.1 ad struct vfsops unionfs_vfsops; 58 1.1 ad 59 1.1 ad VFS_PROTOS(unionfs); 60 1.1 ad 61 1.5 rumble static struct sysctllog *unionfs_sysctl_log; 62 1.5 rumble 63 1.1 ad /* 64 1.1 ad * Mount unionfs layer. 65 1.1 ad */ 66 1.1 ad int 67 1.1 ad unionfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 68 1.1 ad { 69 1.1 ad int error; 70 1.1 ad struct vnode *lowerrootvp; 71 1.1 ad struct vnode *upperrootvp; 72 1.1 ad struct unionfs_mount *ump; 73 1.1 ad int below; 74 1.1 ad uid_t uid; 75 1.1 ad gid_t gid; 76 1.1 ad u_short udir; 77 1.1 ad u_short ufile; 78 1.1 ad unionfs_copymode copymode; 79 1.1 ad unionfs_whitemode whitemode; 80 1.8 dholland struct pathbuf *pb; 81 1.1 ad struct componentname fakecn; 82 1.1 ad struct nameidata nd, *ndp; 83 1.1 ad struct vattr va; 84 1.1 ad struct union_args *args = data; 85 1.1 ad kauth_cred_t cred; 86 1.1 ad size_t size; 87 1.1 ad size_t len; 88 1.1 ad const char *cp; 89 1.1 ad char *xp; 90 1.1 ad 91 1.13 maxv if (args == NULL) 92 1.13 maxv return EINVAL; 93 1.1 ad if (*data_len < sizeof *args) 94 1.1 ad return EINVAL; 95 1.1 ad 96 1.15 christos UNIONFSDEBUG("%s(mp = %p)\n", __func__, mp); 97 1.1 ad 98 1.1 ad error = 0; 99 1.1 ad below = 0; 100 1.1 ad uid = 0; 101 1.1 ad gid = 0; 102 1.1 ad udir = 0; 103 1.1 ad ufile = 0; 104 1.1 ad copymode = UNIONFS_TRANSPARENT; /* default */ 105 1.1 ad whitemode = UNIONFS_WHITE_ALWAYS; 106 1.1 ad ndp = &nd; 107 1.1 ad 108 1.1 ad if (mp->mnt_flag & MNT_ROOTFS) { 109 1.15 christos printf("%s: cannot union mount root filesystem\n", __func__); 110 1.15 christos return EOPNOTSUPP; 111 1.1 ad } 112 1.1 ad 113 1.1 ad if (mp->mnt_flag & MNT_GETARGS) { 114 1.1 ad ump = MOUNTTOUNIONFSMOUNT(mp); 115 1.1 ad if (ump == NULL) 116 1.1 ad return EIO; 117 1.1 ad args->target = NULL; 118 1.1 ad args->mntflags = ump->um_op; 119 1.1 ad *data_len = sizeof *args; 120 1.1 ad return 0; 121 1.1 ad } 122 1.1 ad 123 1.1 ad /* 124 1.1 ad * Update is a no operation. 125 1.1 ad */ 126 1.1 ad if (mp->mnt_flag & MNT_UPDATE) { 127 1.15 christos printf("%s: cannot update union mount\n", __func__); 128 1.15 christos return EOPNOTSUPP; 129 1.1 ad } 130 1.1 ad 131 1.15 christos cred = kauth_cred_get(); 132 1.1 ad vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 133 1.1 ad error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred); 134 1.1 ad if (!error) { 135 1.1 ad if (udir == 0) 136 1.1 ad udir = va.va_mode; 137 1.1 ad if (ufile == 0) 138 1.1 ad ufile = va.va_mode; 139 1.1 ad uid = va.va_uid; 140 1.1 ad gid = va.va_gid; 141 1.1 ad } 142 1.7 hannken VOP_UNLOCK(mp->mnt_vnodecovered); 143 1.1 ad if (error) 144 1.15 christos return error; 145 1.1 ad 146 1.1 ad switch (args->mntflags & UNMNT_OPMASK) { 147 1.1 ad case UNMNT_ABOVE: 148 1.1 ad below = 0; 149 1.1 ad break; 150 1.1 ad 151 1.1 ad case UNMNT_BELOW: 152 1.1 ad below = 1; 153 1.1 ad break; 154 1.1 ad 155 1.1 ad case UNMNT_REPLACE: 156 1.1 ad default: 157 1.1 ad return EINVAL; 158 1.1 ad } 159 1.1 ad 160 1.1 ad /* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */ 161 1.1 ad if (copymode == UNIONFS_TRADITIONAL) { 162 1.1 ad uid = kauth_cred_getuid(cred); 163 1.1 ad gid = kauth_cred_getgid(cred); 164 1.1 ad } 165 1.1 ad 166 1.15 christos UNIONFSDEBUG("%s: uid=%d, gid=%d\n", __func__, uid, gid); 167 1.15 christos UNIONFSDEBUG("%s: udir=%#03o, ufile=%#03o\n", __func__, udir, ufile); 168 1.15 christos UNIONFSDEBUG("%s: copymode=%d\n", __func__, copymode); 169 1.1 ad 170 1.1 ad /* 171 1.1 ad * Find upper node 172 1.1 ad */ 173 1.8 dholland error = pathbuf_copyin(args->target, &pb); 174 1.15 christos if (error) 175 1.8 dholland return error; 176 1.8 dholland NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, pb); 177 1.8 dholland if ((error = namei(ndp))) { 178 1.8 dholland pathbuf_destroy(pb); 179 1.8 dholland return error; 180 1.8 dholland } 181 1.1 ad 182 1.1 ad /* get root vnodes */ 183 1.1 ad lowerrootvp = mp->mnt_vnodecovered; 184 1.1 ad upperrootvp = ndp->ni_vp; 185 1.1 ad 186 1.1 ad vrele(ndp->ni_dvp); 187 1.1 ad ndp->ni_dvp = NULLVP; 188 1.8 dholland pathbuf_destroy(pb); 189 1.1 ad 190 1.1 ad /* create unionfs_mount */ 191 1.15 christos ump = kmem_zalloc(sizeof(*ump), KM_SLEEP); 192 1.1 ad 193 1.1 ad /* 194 1.1 ad * Save reference 195 1.1 ad */ 196 1.1 ad if (below) { 197 1.7 hannken VOP_UNLOCK(upperrootvp); 198 1.1 ad vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY); 199 1.1 ad ump->um_lowervp = upperrootvp; 200 1.1 ad ump->um_uppervp = lowerrootvp; 201 1.1 ad } else { 202 1.1 ad ump->um_lowervp = lowerrootvp; 203 1.1 ad ump->um_uppervp = upperrootvp; 204 1.1 ad } 205 1.1 ad ump->um_rootvp = NULLVP; 206 1.1 ad ump->um_uid = uid; 207 1.1 ad ump->um_gid = gid; 208 1.1 ad ump->um_udir = udir; 209 1.1 ad ump->um_ufile = ufile; 210 1.1 ad ump->um_copymode = copymode; 211 1.1 ad ump->um_whitemode = whitemode; 212 1.1 ad 213 1.1 ad if ((lowerrootvp->v_mount->mnt_iflag & IMNT_MPSAFE) && 214 1.1 ad (upperrootvp->v_mount->mnt_flag & IMNT_MPSAFE)) 215 1.1 ad mp->mnt_iflag |= IMNT_MPSAFE; 216 1.1 ad mp->mnt_data = ump; 217 1.1 ad 218 1.1 ad /* 219 1.1 ad * Copy upper layer's RDONLY flag. 220 1.1 ad */ 221 1.1 ad mp->mnt_flag |= ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY; 222 1.1 ad 223 1.1 ad /* 224 1.1 ad * Check whiteout 225 1.1 ad */ 226 1.1 ad if ((mp->mnt_flag & MNT_RDONLY) == 0) { 227 1.1 ad memset(&fakecn, 0, sizeof(fakecn)); 228 1.1 ad fakecn.cn_nameiop = LOOKUP; 229 1.1 ad error = VOP_WHITEOUT(ump->um_uppervp, &fakecn, LOOKUP); 230 1.1 ad if (error) { 231 1.1 ad if (below) { 232 1.7 hannken VOP_UNLOCK(ump->um_uppervp); 233 1.1 ad vrele(upperrootvp); 234 1.1 ad } else 235 1.1 ad vput(ump->um_uppervp); 236 1.15 christos goto out; 237 1.1 ad } 238 1.1 ad } 239 1.1 ad 240 1.1 ad /* 241 1.1 ad * Unlock the node 242 1.1 ad */ 243 1.7 hannken VOP_UNLOCK(ump->um_uppervp); 244 1.1 ad 245 1.1 ad ump->um_op = args->mntflags & UNMNT_OPMASK; 246 1.1 ad 247 1.1 ad /* 248 1.1 ad * Get the unionfs root vnode. 249 1.1 ad */ 250 1.1 ad error = unionfs_nodeget(mp, ump->um_uppervp, ump->um_lowervp, 251 1.1 ad NULLVP, &(ump->um_rootvp), NULL); 252 1.1 ad vrele(upperrootvp); 253 1.1 ad if (error) { 254 1.15 christos goto out; 255 1.1 ad } 256 1.1 ad 257 1.1 ad /* 258 1.1 ad * Check mnt_flag 259 1.1 ad */ 260 1.1 ad if ((ump->um_lowervp->v_mount->mnt_flag & MNT_LOCAL) && 261 1.1 ad (ump->um_uppervp->v_mount->mnt_flag & MNT_LOCAL)) 262 1.1 ad mp->mnt_flag |= MNT_LOCAL; 263 1.1 ad 264 1.1 ad /* 265 1.1 ad * Get new fsid 266 1.1 ad */ 267 1.1 ad vfs_getnewfsid(mp); 268 1.1 ad 269 1.1 ad error = set_statvfs_info(path, UIO_USERSPACE, NULL, UIO_USERSPACE, 270 1.1 ad mp->mnt_op->vfs_name, mp, curlwp); 271 1.1 ad if (error) { 272 1.1 ad unionfs_noderem(ump->um_rootvp); 273 1.15 christos goto out; 274 1.1 ad } 275 1.1 ad 276 1.1 ad switch (ump->um_op) { 277 1.1 ad case UNMNT_ABOVE: 278 1.1 ad cp = "<above>:"; 279 1.1 ad break; 280 1.1 ad case UNMNT_BELOW: 281 1.1 ad cp = "<below>:"; 282 1.1 ad break; 283 1.1 ad default: 284 1.15 christos #ifdef DIAGNOSTIC 285 1.15 christos panic("%s: bad um_op", __func__); 286 1.15 christos #endif 287 1.1 ad break; 288 1.1 ad } 289 1.1 ad len = strlen(cp); 290 1.1 ad memcpy(mp->mnt_stat.f_mntfromname, cp, len); 291 1.1 ad xp = mp->mnt_stat.f_mntfromname + len; 292 1.1 ad len = MNAMELEN - len; 293 1.1 ad (void) copyinstr(args->target, xp, len - 1, &size); 294 1.1 ad memset(xp + size, 0, len - size); 295 1.1 ad 296 1.15 christos UNIONFSDEBUG("%s: from %s, on %s\n", __func__, 297 1.1 ad mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 298 1.1 ad 299 1.15 christos return 0; 300 1.15 christos out: 301 1.15 christos kmem_free(ump, sizeof(*ump)); 302 1.15 christos mp->mnt_data = NULL; 303 1.15 christos return error; 304 1.1 ad } 305 1.1 ad 306 1.1 ad /* 307 1.1 ad * Free reference to unionfs layer 308 1.1 ad */ 309 1.1 ad int 310 1.1 ad unionfs_unmount(struct mount *mp, int mntflags) 311 1.1 ad { 312 1.1 ad struct unionfs_mount *ump; 313 1.1 ad int error; 314 1.1 ad int freeing; 315 1.1 ad int flags; 316 1.1 ad 317 1.15 christos UNIONFSDEBUG("%s: mp = %p\n", __func__, mp); 318 1.1 ad 319 1.1 ad ump = MOUNTTOUNIONFSMOUNT(mp); 320 1.1 ad flags = 0; 321 1.1 ad 322 1.1 ad if (mntflags & MNT_FORCE) 323 1.1 ad flags |= FORCECLOSE; 324 1.1 ad 325 1.1 ad /* vflush (no need to call vrele) */ 326 1.1 ad for (freeing = 0; (error = vflush(mp, NULL, flags)) != 0;) { 327 1.15 christos struct vnode_iterator *marker; 328 1.1 ad struct vnode *vp; 329 1.1 ad int n; 330 1.1 ad 331 1.1 ad /* count #vnodes held on mount list */ 332 1.15 christos vfs_vnode_iterator_init(mp, &marker); 333 1.1 ad n = 0; 334 1.15 christos while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) 335 1.1 ad n++; 336 1.15 christos vfs_vnode_iterator_destroy(marker); 337 1.1 ad 338 1.1 ad /* if this is unchanged then stop */ 339 1.1 ad if (n == freeing) 340 1.1 ad break; 341 1.1 ad 342 1.1 ad /* otherwise try once more time */ 343 1.1 ad freeing = n; 344 1.1 ad } 345 1.1 ad 346 1.1 ad if (error) 347 1.15 christos return error; 348 1.1 ad 349 1.15 christos kmem_free(ump, sizeof(*ump)); 350 1.4 simonb mp->mnt_data = NULL; 351 1.1 ad 352 1.1 ad return (0); 353 1.1 ad } 354 1.1 ad 355 1.1 ad int 356 1.14 ad unionfs_root(struct mount *mp, int lktype, struct vnode **vpp) 357 1.1 ad { 358 1.1 ad struct unionfs_mount *ump; 359 1.1 ad struct vnode *vp; 360 1.1 ad 361 1.1 ad ump = MOUNTTOUNIONFSMOUNT(mp); 362 1.1 ad vp = ump->um_rootvp; 363 1.1 ad 364 1.15 christos UNIONFSDEBUG("%s: rootvp=%p locked=%#x\n", __func__, 365 1.1 ad vp, VOP_ISLOCKED(vp)); 366 1.1 ad 367 1.1 ad vref(vp); 368 1.14 ad vn_lock(vp, lktype); 369 1.1 ad 370 1.1 ad *vpp = vp; 371 1.1 ad 372 1.15 christos return 0; 373 1.1 ad } 374 1.1 ad 375 1.1 ad int 376 1.10 dholland unionfs_quotactl(struct mount *mp, struct quotactl_args *args) 377 1.1 ad { 378 1.1 ad struct unionfs_mount *ump; 379 1.1 ad 380 1.1 ad ump = MOUNTTOUNIONFSMOUNT(mp); 381 1.1 ad 382 1.1 ad /* 383 1.1 ad * Writing is always performed to upper vnode. 384 1.1 ad */ 385 1.15 christos return VFS_QUOTACTL(ump->um_uppervp->v_mount, args); 386 1.1 ad } 387 1.1 ad 388 1.1 ad int 389 1.1 ad unionfs_statvfs(struct mount *mp, struct statvfs *sbp) 390 1.1 ad { 391 1.1 ad struct unionfs_mount *ump; 392 1.1 ad int error; 393 1.1 ad uint64_t lbsize; 394 1.16 christos struct statvfs *sbuf = kmem_zalloc(sizeof(*sbuf), KM_SLEEP); 395 1.1 ad 396 1.1 ad ump = MOUNTTOUNIONFSMOUNT(mp); 397 1.1 ad 398 1.15 christos UNIONFSDEBUG("%s(mp = %p, lvp = %p, uvp = %p)\n", 399 1.15 christos __func__, mp, ump->um_lowervp, ump->um_uppervp); 400 1.1 ad 401 1.1 ad error = VFS_STATVFS(ump->um_lowervp->v_mount, sbuf); 402 1.1 ad if (error) 403 1.1 ad goto done; 404 1.1 ad 405 1.1 ad /* now copy across the "interesting" information and fake the rest */ 406 1.1 ad sbp->f_blocks = sbuf->f_blocks; 407 1.1 ad sbp->f_files = sbuf->f_files; 408 1.1 ad 409 1.1 ad lbsize = sbuf->f_bsize; 410 1.1 ad 411 1.1 ad error = VFS_STATVFS(ump->um_uppervp->v_mount, sbuf); 412 1.1 ad if (error) 413 1.1 ad goto done; 414 1.1 ad 415 1.1 ad /* 416 1.1 ad * The FS type etc is copy from upper vfs. 417 1.1 ad * (write able vfs have priority) 418 1.1 ad */ 419 1.1 ad sbp->f_flag = sbuf->f_flag; 420 1.1 ad sbp->f_bsize = sbuf->f_bsize; 421 1.1 ad sbp->f_iosize = sbuf->f_iosize; 422 1.1 ad 423 1.1 ad if (sbuf->f_bsize != lbsize) 424 1.1 ad sbp->f_blocks = ((off_t)sbp->f_blocks * lbsize) / sbuf->f_bsize; 425 1.1 ad 426 1.1 ad sbp->f_blocks += sbuf->f_blocks; 427 1.1 ad sbp->f_bfree = sbuf->f_bfree; 428 1.1 ad sbp->f_bavail = sbuf->f_bavail; 429 1.1 ad sbp->f_files += sbuf->f_files; 430 1.1 ad sbp->f_ffree = sbuf->f_ffree; 431 1.1 ad 432 1.1 ad done: 433 1.15 christos kmem_free(sbuf, sizeof(*sbuf)); 434 1.15 christos return error; 435 1.1 ad } 436 1.1 ad 437 1.1 ad int 438 1.1 ad unionfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) 439 1.1 ad { 440 1.1 ad /* nothing to do */ 441 1.15 christos return 0; 442 1.1 ad } 443 1.1 ad 444 1.1 ad int 445 1.1 ad unionfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, 446 1.1 ad int namespace, const char *attrname) 447 1.1 ad { 448 1.1 ad struct unionfs_mount *ump; 449 1.1 ad struct unionfs_node *unp; 450 1.1 ad 451 1.1 ad ump = MOUNTTOUNIONFSMOUNT(mp); 452 1.1 ad unp = VTOUNIONFS(filename_vp); 453 1.1 ad 454 1.1 ad if (unp->un_uppervp != NULLVP) { 455 1.15 christos return VFS_EXTATTRCTL(ump->um_uppervp->v_mount, cmd, 456 1.15 christos unp->un_uppervp, namespace, attrname); 457 1.1 ad } else { 458 1.15 christos return VFS_EXTATTRCTL(ump->um_lowervp->v_mount, cmd, 459 1.15 christos unp->un_lowervp, namespace, attrname); 460 1.1 ad } 461 1.1 ad } 462 1.1 ad 463 1.1 ad /* 464 1.1 ad * Initialize 465 1.1 ad */ 466 1.1 ad void 467 1.1 ad unionfs_init(void) 468 1.1 ad { 469 1.15 christos UNIONFSDEBUG("%s\n", __func__); /* printed during system boot */ 470 1.1 ad } 471 1.1 ad 472 1.1 ad static int 473 1.1 ad unionfs_renamelock_enter(struct mount *mp) 474 1.1 ad { 475 1.1 ad struct unionfs_mount *um = MOUNTTOUNIONFSMOUNT(mp); 476 1.1 ad 477 1.1 ad /* Lock just the upper fs, where the action happens. */ 478 1.1 ad return VFS_RENAMELOCK_ENTER(um->um_uppervp->v_mount); 479 1.1 ad } 480 1.1 ad 481 1.1 ad static void 482 1.1 ad unionfs_renamelock_exit(struct mount *mp) 483 1.1 ad { 484 1.1 ad struct unionfs_mount *um = MOUNTTOUNIONFSMOUNT(mp); 485 1.1 ad 486 1.1 ad VFS_RENAMELOCK_EXIT(um->um_uppervp->v_mount); 487 1.1 ad } 488 1.1 ad 489 1.1 ad int 490 1.1 ad unionfs_start(struct mount *mp, int flags) 491 1.1 ad { 492 1.1 ad 493 1.15 christos return 0; 494 1.1 ad } 495 1.1 ad 496 1.1 ad void 497 1.1 ad unionfs_done(void) 498 1.1 ad { 499 1.1 ad 500 1.1 ad /* Make sure to unset the readdir hook. */ 501 1.1 ad vn_union_readdir_hook = NULL; 502 1.1 ad } 503 1.1 ad 504 1.1 ad extern const struct vnodeopv_desc unionfs_vnodeop_opv_desc; 505 1.1 ad 506 1.1 ad const struct vnodeopv_desc * const unionfs_vnodeopv_descs[] = { 507 1.1 ad &unionfs_vnodeop_opv_desc, 508 1.1 ad NULL, 509 1.1 ad }; 510 1.1 ad 511 1.1 ad struct vfsops unionfs_vfsops = { 512 1.12 hannken .vfs_name = MOUNT_UNION, 513 1.12 hannken .vfs_min_mount_data = sizeof (struct unionfs_args), 514 1.12 hannken .vfs_mount = unionfs_mount, 515 1.12 hannken .vfs_start = unionfs_start, 516 1.12 hannken .vfs_unmount = unionfs_unmount, 517 1.12 hannken .vfs_root = unionfs_root, 518 1.12 hannken .vfs_quotactl = (void *)eopnotsupp, 519 1.12 hannken .vfs_statvfs = unionfs_statvfs, 520 1.12 hannken .vfs_sync = unionfs_sync, 521 1.15 christos .vfs_vget = (void *)eopnotsupp, 522 1.15 christos .vfs_fhtovp = (void *)eopnotsupp, 523 1.12 hannken .vfs_vptofh = (void *)eopnotsupp, 524 1.12 hannken .vfs_init = unionfs_init, 525 1.12 hannken .vfs_done = unionfs_done, 526 1.12 hannken .vfs_snapshot = (void *)eopnotsupp, 527 1.12 hannken .vfs_extattrctl = vfs_stdextattrctl, 528 1.12 hannken .vfs_suspendctl = (void *)eopnotsupp, 529 1.12 hannken .vfs_renamelock_enter = unionfs_renamelock_enter, 530 1.12 hannken .vfs_renamelock_exit = unionfs_renamelock_exit, 531 1.12 hannken .vfs_fsync = (void *)eopnotsupp, 532 1.12 hannken .vfs_opv_descs = unionfs_vnodeopv_descs 533 1.1 ad }; 534 1.3 rumble 535 1.3 rumble static int 536 1.3 rumble unionfs_modcmd(modcmd_t cmd, void *arg) 537 1.3 rumble { 538 1.5 rumble int error; 539 1.3 rumble 540 1.3 rumble switch (cmd) { 541 1.3 rumble case MODULE_CMD_INIT: 542 1.5 rumble error = vfs_attach(&unionfs_vfsops); 543 1.5 rumble if (error != 0) 544 1.5 rumble break; 545 1.5 rumble sysctl_createv(&unionfs_sysctl_log, 0, NULL, NULL, 546 1.15 christos CTLFLAG_PERMANENT, 547 1.15 christos CTLTYPE_NODE, "union", 548 1.15 christos SYSCTL_DESCR("Union file system"), 549 1.15 christos NULL, 0, NULL, 0, 550 1.15 christos CTL_VFS, 15, CTL_EOL); 551 1.5 rumble /* 552 1.5 rumble * XXX the "15" above could be dynamic, thereby eliminating 553 1.5 rumble * one more instance of the "number to vfs" mapping problem, 554 1.5 rumble * but "15" is the order as taken from sys/mount.h 555 1.5 rumble */ 556 1.5 rumble break; 557 1.3 rumble case MODULE_CMD_FINI: 558 1.5 rumble error = vfs_detach(&unionfs_vfsops); 559 1.5 rumble if (error != 0) 560 1.5 rumble break; 561 1.5 rumble sysctl_teardown(&unionfs_sysctl_log); 562 1.5 rumble break; 563 1.3 rumble default: 564 1.5 rumble error = ENOTTY; 565 1.5 rumble break; 566 1.3 rumble } 567 1.5 rumble 568 1.15 christos return error; 569 1.3 rumble } 570