1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * Portions Copyright 2007-2013 Apple Inc. 29 */ 30 31#pragma ident "@(#)auto_vnops.c 1.70 05/12/19 SMI" 32 33#include <mach/mach_types.h> 34#include <mach/machine/boolean.h> 35#include <mach/host_priv.h> 36#include <mach/host_special_ports.h> 37#include <mach/vm_map.h> 38#include <vm/vm_map.h> 39#include <vm/vm_kern.h> 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/kernel.h> 44#include <sys/file.h> 45#include <sys/stat.h> 46#include <sys/buf.h> 47#include <sys/proc.h> 48#include <sys/conf.h> 49#include <sys/mount.h> 50#include <sys/vnode.h> 51#include <sys/malloc.h> 52#include <sys/dirent.h> 53#include <sys/namei.h> 54#include <sys/kauth.h> 55#include <sys/attr.h> 56#include <sys/vnode_if.h> 57#include <sys/vfs_context.h> 58#include <sys/vm.h> 59#include <sys/errno.h> 60#include <vfs/vfs_support.h> 61#include <sys/uio.h> 62 63#include <kern/assert.h> 64#include <kern/host.h> 65 66#include <IOKit/IOLib.h> 67 68#include "autofs.h" 69#include "triggers.h" 70#include "triggers_priv.h" 71#include "autofs_kern.h" 72#include "autofs_protUser.h" 73 74/* 75 * Vnode ops for autofs 76 */ 77static int auto_getattr(struct vnop_getattr_args *); 78static int auto_setattr(struct vnop_setattr_args *); 79static int auto_lookup(struct vnop_lookup_args *); 80static int auto_readdir(struct vnop_readdir_args *); 81static int auto_readlink(struct vnop_readlink_args *); 82static int auto_pathconf(struct vnop_pathconf_args *); 83static int auto_fsctl(struct vnop_ioctl_args *); 84static int auto_getxattr(struct vnop_getxattr_args *); 85static int auto_listxattr(struct vnop_listxattr_args *); 86static int auto_inactive(struct vnop_inactive_args *); 87static int auto_reclaim(struct vnop_reclaim_args *); 88 89int (**autofs_vnodeop_p)(void *); 90 91#define VOPFUNC int (*)(void *) 92 93struct vnodeopv_entry_desc autofs_vnodeop_entries[] = { 94 {&vnop_default_desc, (VOPFUNC)vn_default_error}, 95 {&vnop_lookup_desc, (VOPFUNC)auto_lookup}, /* lookup */ 96 {&vnop_open_desc, (VOPFUNC)nop_open}, /* open - NOP */ 97 {&vnop_close_desc, (VOPFUNC)nop_close}, /* close - NOP */ 98 {&vnop_getattr_desc, (VOPFUNC)auto_getattr}, /* getattr */ 99 {&vnop_setattr_desc, (VOPFUNC)auto_setattr}, /* setattr */ 100 {&vnop_fsync_desc, (VOPFUNC)nop_fsync}, /* fsync - NOP */ 101 {&vnop_readdir_desc, (VOPFUNC)auto_readdir}, /* readdir */ 102 {&vnop_readlink_desc, (VOPFUNC)auto_readlink}, /* readlink */ 103 {&vnop_pathconf_desc, (VOPFUNC)auto_pathconf}, /* pathconf */ 104 {&vnop_ioctl_desc, (VOPFUNC)auto_fsctl}, /* ioctl (really fsctl) */ 105 {&vnop_getxattr_desc, (VOPFUNC)auto_getxattr}, /* getxattr */ 106 {&vnop_listxattr_desc, (VOPFUNC)auto_listxattr}, /* listxattr */ 107 {&vnop_inactive_desc, (VOPFUNC)auto_inactive}, /* inactive */ 108 {&vnop_reclaim_desc, (VOPFUNC)auto_reclaim}, /* reclaim */ 109 {NULL, NULL} 110}; 111 112struct vnodeopv_desc autofsfs_vnodeop_opv_desc = 113 { &autofs_vnodeop_p, autofs_vnodeop_entries }; 114 115static int autofs_nobrowse = 0; 116 117/* 118 * Returns 1 if a readdir on the vnode will only return names for the 119 * vnodes we have, 0 otherwise. 120 * 121 * XXX - come up with a better name. 122 */ 123int 124auto_nobrowse(vnode_t vp) 125{ 126 fnnode_t *fnp = vntofn(vp); 127 fninfo_t *fnip = vfstofni(vnode_mount(vp)); 128 129 if (fnp == vntofn(fnip->fi_rootvp)) { 130 /* 131 * This is the root directory of the mount, so a 132 * readdir on the vnode will only return names for 133 * the vnodes we already have if we've globally 134 * disabled browsing or the map was mounted with 135 * "nobrowse". 136 */ 137 return (autofs_nobrowse || 138 (fnip->fi_mntflags & AUTOFS_MNT_NOBROWSE)); 139 } else { 140 /* 141 * This is a subdirectory of the mount; a readdir 142 * on the vnode will always make an upcall, as 143 * we need to enumerate all the subdirectories 144 * generated by the submounts. 145 */ 146 return (0); 147 } 148} 149 150static int 151auto_getattr(ap) 152 struct vnop_getattr_args /* { 153 struct vnodeop_desc *a_desc; 154 vnode_t a_vp; 155 struct vnode_attr *a_vap; 156 vfs_context_t a_context; 157 } */ *ap; 158{ 159 vnode_t vp = ap->a_vp; 160 struct vnode_attr *vap = ap->a_vap; 161 162 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp)); 163 164 /* XXX - lock the fnnode? */ 165 166 auto_get_attributes(vp, vap); 167 168 return (0); 169} 170 171void 172auto_get_attributes(vnode_t vp, struct vnode_attr *vap) 173{ 174 fnnode_t *fnp = vntofn(vp); 175 176 VATTR_RETURN(vap, va_rdev, 0); 177 switch (vnode_vtype(vp)) { 178 case VDIR: 179 /* 180 * fn_linkcnt doesn't count the "." link, as we're using it 181 * as a count of references to the fnnode from other vnnodes 182 * (so that if it goes to 0, we know no other fnnode refers 183 * to it). 184 */ 185 VATTR_RETURN(vap, va_nlink, fnp->fn_linkcnt + 1); 186 187 /* 188 * The "size" of a directory is the number of entries 189 * in its list of directory entries, plus 1. 190 * (Solaris added 1 for some reason.) 191 */ 192 VATTR_RETURN(vap, va_data_size, fnp->fn_direntcnt + 1); 193 break; 194 case VLNK: 195 VATTR_RETURN(vap, va_nlink, fnp->fn_linkcnt); 196 VATTR_RETURN(vap, va_data_size, fnp->fn_symlinklen); 197 break; 198 default: 199 VATTR_RETURN(vap, va_nlink, fnp->fn_linkcnt); 200 VATTR_RETURN(vap, va_data_size, 0); 201 break; 202 } 203 VATTR_RETURN(vap, va_total_size, roundup(vap->va_data_size, AUTOFS_BLOCKSIZE)); 204 VATTR_RETURN(vap, va_iosize, AUTOFS_BLOCKSIZE); 205 206 VATTR_RETURN(vap, va_uid, fnp->fn_uid); 207 VATTR_RETURN(vap, va_gid, 0); 208 VATTR_RETURN(vap, va_mode, fnp->fn_mode); 209 /* 210 * Does our caller want the BSD flags? 211 */ 212 if (VATTR_IS_ACTIVE(vap, va_flags)) { 213 /* 214 * If this is the root of a mount, and if the "hide this 215 * from the Finder" mount option is set on that mount, 216 * return the hidden bit, so the Finder won't show it. 217 */ 218 if (vnode_isvroot(vp)) { 219 fninfo_t *fnip = vfstofni(vnode_mount(vp)); 220 221 if (fnip->fi_mntflags & AUTOFS_MNT_HIDEFROMFINDER) 222 VATTR_RETURN(vap, va_flags, UF_HIDDEN); 223 else 224 VATTR_RETURN(vap, va_flags, 0); 225 } else 226 VATTR_RETURN(vap, va_flags, 0); 227 } 228 vap->va_access_time.tv_sec = fnp->fn_atime.tv_sec; 229 vap->va_access_time.tv_nsec = fnp->fn_atime.tv_usec * 1000; 230 VATTR_SET_SUPPORTED(vap, va_access_time); 231 vap->va_modify_time.tv_sec = fnp->fn_mtime.tv_sec; 232 vap->va_modify_time.tv_nsec = fnp->fn_mtime.tv_usec * 1000; 233 VATTR_SET_SUPPORTED(vap, va_modify_time); 234 vap->va_change_time.tv_sec = fnp->fn_ctime.tv_sec; 235 vap->va_change_time.tv_nsec = fnp->fn_ctime.tv_usec * 1000; 236 VATTR_SET_SUPPORTED(vap, va_change_time); 237 VATTR_RETURN(vap, va_fileid, fnp->fn_nodeid); 238 VATTR_RETURN(vap, va_fsid, vfs_statfs(vnode_mount(vp))->f_fsid.val[0]); 239 VATTR_RETURN(vap, va_filerev, 0); 240 VATTR_RETURN(vap, va_type, vnode_vtype(vp)); 241} 242 243static int 244auto_setattr(ap) 245 struct vnop_setattr_args /* { 246 struct vnodeop_desc *a_desc; 247 vnode_t a_vp; 248 struct vnode_attr *a_vap; 249 vfs_context_t a_context; 250 } */ *ap; 251{ 252 vnode_t vp = ap->a_vp; 253 struct vnode_attr *vap = ap->a_vap; 254 fnnode_t *fnp = vntofn(vp); 255 256 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp)); 257 258 /* 259 * Only root can change the attributes. 260 */ 261 if (!kauth_cred_issuser(vfs_context_ucred(ap->a_context))) 262 return (EPERM); 263 264 /* 265 * All you can set are the UID and the permissions; that's to 266 * allow the automounter to give the mount point to the user 267 * on whose behalf we're doing the mount, and make it writable 268 * by them, so we can do AFP and SMB mounts as that user (so 269 * the connection can be authenticated as them). 270 * 271 * We pretend to allow the GID to be set, but we don't actually 272 * set it. 273 */ 274 VATTR_SET_SUPPORTED(vap, va_uid); 275 if (VATTR_IS_ACTIVE(vap, va_uid)) 276 fnp->fn_uid = vap->va_uid; 277 VATTR_SET_SUPPORTED(vap, va_gid); 278 VATTR_SET_SUPPORTED(vap, va_mode); 279 if (VATTR_IS_ACTIVE(vap, va_mode)) 280 fnp->fn_mode = vap->va_mode & ALLPERMS; 281 return (0); 282} 283 284#include <sys/syslog.h> 285static int 286auto_lookup(ap) 287 struct vnop_lookup_args /* { 288 struct vnodeop_desc *a_desc; 289 vnode_t a_dvp; 290 vnode_t *a_vpp; 291 struct componentname *a_cnp; 292 vfs_context_t a_context; 293 } */ *ap; 294{ 295 vnode_t dvp = ap->a_dvp; 296 vnode_t *vpp = ap->a_vpp; 297 struct componentname *cnp = ap->a_cnp; 298 u_long nameiop = cnp->cn_nameiop; 299 u_long flags = cnp->cn_flags; 300 int namelen = cnp->cn_namelen; 301 vfs_context_t context = ap->a_context; 302 int pid = vfs_context_pid(context); 303 int error = 0; 304 fninfo_t *dfnip; 305 fnnode_t *dfnp = NULL; 306 fnnode_t *fnp = NULL; 307 vnode_t vp; 308 uint32_t vid; 309 char *searchnm; 310 int searchnmlen; 311 int do_notify = 0; 312 struct vnode_attr vattr; 313 int node_type; 314 boolean_t have_lock = 0; 315 int retry_count = 0; 316 317 dfnip = vfstofni(vnode_mount(dvp)); 318 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%.*s\n", 319 (void *)dvp, dfnip->fi_map, namelen, cnp->cn_nameptr)); 320 321 /* This must be a directory. */ 322 if (!vnode_isdir(dvp)) 323 return (ENOTDIR); 324 325 /* 326 * XXX - is this necessary? 327 */ 328 if (namelen == 0) { 329 error = vnode_get(dvp); 330 if (error) 331 return (error); 332 *vpp = dvp; 333 return (0); 334 } 335 336 /* first check for "." and ".." */ 337 if (cnp->cn_nameptr[0] == '.') { 338 if (namelen == 1) { 339 /* 340 * "." requested 341 */ 342 343 /* 344 * Thou shalt not rename ".". 345 * (No, the VFS layer doesn't catch this for us.) 346 */ 347 if ((nameiop == RENAME) && (flags & WANTPARENT) && 348 (flags & ISLASTCN)) 349 return (EISDIR); 350 351 error = vnode_get(dvp); 352 if (error) 353 return (error); 354 *vpp = dvp; 355 return (0); 356 } else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) { 357 fnnode_t *pdfnp; 358 359 pdfnp = (vntofn(dvp))->fn_parent; 360 assert(pdfnp != NULL); 361 362 /* 363 * Since it is legitimate to have the VROOT flag set for the 364 * subdirectories of the indirect map in autofs filesystem, 365 * rootfnnodep is checked against fnnode of dvp instead of 366 * just checking whether VROOT flag is set in dvp 367 */ 368 369#if 0 370 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) { 371 vnode_t vp; 372 373 vfs_lock_wait(vnode_mount(dvp)); 374 if (vnode_mount(dvp)->vfs_flag & VFS_UNMOUNTED) { 375 vfs_unlock(vnode_mount(dvp)); 376 return (EIO); 377 } 378 vp = vnode_mount(dvp)->mnt_vnodecovered; 379 error = vnode_get(vp); /* XXX - what if it fails? */ 380 vfs_unlock(vnode_mount(dvp)); 381 error = VNOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred); 382 vnode_put(vp); 383 return (error); 384 } else { 385#else 386 { 387#endif 388 *vpp = fntovn(pdfnp); 389 return (vnode_get(*vpp)); 390 } 391 } 392 } 393 394 dfnp = vntofn(dvp); 395 searchnm = cnp->cn_nameptr; 396 searchnmlen = namelen; 397 398 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp, 399 (void *)dfnp)); 400 401 have_lock = auto_fninfo_lock_shared(dfnip, pid); 402 403top: 404 /* 405 * If this vnode is a trigger, then something should 406 * be mounted atop it, and there should be nothing 407 * in this file system below it. (We shouldn't 408 * normally get here, as we should have resolved 409 * the trigger. It's possible we've hit a retrigger 410 * window. Send the system call back to restart. 411 */ 412 if (dfnp->fn_trigger_info != NULL) { 413 auto_fninfo_unlock_shared(dfnip, have_lock); 414 if (dfnp->fn_restart_cnt++ > 3) { 415 dfnp->fn_restart_cnt = 0; 416 return ENOENT; 417 } 418 log(LOG_ALERT, "auto_lookup called with trigger dir\n"); 419 return ERESTART; 420 } 421 dfnp->fn_restart_cnt = 0; 422 423 /* 424 * See if we have done something with this name already, so we 425 * already have it. 426 */ 427 lck_rw_lock_shared(dfnp->fn_rwlock); 428 fnp = auto_search(dfnp, cnp->cn_nameptr, cnp->cn_namelen); 429 if (fnp == NULL) { 430 /* 431 * No, we don't, so we need to make an upcall to see 432 * if something with that name should exist. 433 * 434 * Drop the writer lock on the directory, so 435 * that we don't block reclaims of autofs 436 * vnodes in that directory while we're 437 * waiting for automountd to respond 438 * (automountd, or some process on which 439 * it depends, might be doing something 440 * that requires the allocation of a 441 * vnode, and that might involve reclaiming 442 * an autofs vnode) or while we're trying 443 * to allocate a vnode for the file or 444 * directory we're looking up. 445 */ 446 lck_rw_unlock_shared(dfnp->fn_rwlock); 447 448 /* 449 * Check whether this map is in the process of being 450 * unmounted. If so, return ENOENT; see auto_control_ioctl() 451 * for the reason why this is done. 452 */ 453 if (dfnip->fi_flags & MF_UNMOUNTING) { 454 error = ENOENT; 455 goto fail; 456 } 457 458 /* 459 * Ask automountd whether something with this 460 * name exists. 461 */ 462 error = auto_lookup_aux(dfnip, dfnp, searchnm, 463 searchnmlen, context, &node_type); 464 if (error != 0) 465 goto fail; /* nope */ 466 467 /* 468 * OK, it exists. We need to create the 469 * fnnode for it, and enter it into the 470 * directory. 471 * 472 * Create the fnnode first, as we must 473 * not grab the writer lock on the 474 * directory, as per the above. 475 */ 476 error = auto_makefnnode(&fnp, node_type, 477 vnode_mount(dvp), cnp, NULL, dvp, 0, 478 dfnp->fn_globals); 479 if (error) 480 goto fail; 481 482 /* 483 * Now enter the fnnode in the directory. 484 * 485 * Note that somebody might have created the 486 * name while we weren't holding the lock; 487 * if so, then auto_enter() will return 488 * EEXIST, and will have discarded the 489 * vnode we created and handed us back 490 * an fnnode referring to what they'd 491 * already created. 492 */ 493 error = auto_enter(dfnp, cnp, &fnp); 494 if (error) { 495 if (error == EEXIST) { 496 /* 497 * We found the name. Act as if 498 * the auto_search() above succeeded. 499 */ 500 error = 0; 501 } else if (error == EJUSTRETURN) { 502 /* 503 * We could not acquire either 504 * a) an iocount on the existing vnode and the 505 * autofs mount point is getting unmounted. 506 * or 507 * b) a reference on the parent directory. 508 * 509 * In either case we no longer have an iocount 510 * on the vnode we created. EJUSTRETURN is used 511 * as a subsitute for ENOMORERETRIES. 512 * 513 * This should ideally redrive the lookup 514 * instead i.e we should be able to return 515 * ERECYCLE and have namei do a limited number 516 * retries but ERECYCLE is not exported and 517 * namei does not impose a limit on the number 518 * of retries it will do. 519 * 520 * We'll just return ENOENT which may have the 521 * unfortunate side effect of getting transient 522 * ENOENT's in a unmount->retrigger window. 523 */ 524 error = ENOENT; 525 goto fail; 526 } else { 527 /* 528 * We found the name, but couldn't 529 * get an iocount on the vnode for 530 * its fnnode. That's probably 531 * because it was in the process 532 * of being recycled. if we havn't already done 533 * it 3 times, Redo the search, as the 534 * directory might have changed. 535 */ 536 if (++retry_count >= 3) { 537 error = ENOENT; 538 goto fail; 539 } 540 error = 0; 541 goto top; 542 } 543 } else { 544 /* 545 * We added an entry to the directory, 546 * so we might want to notify 547 * interested parties about that. 548 * XXX 549 */ 550 do_notify = 1; 551 } 552 } else { 553 /* 554 * Yes, we did. 555 * 556 * We're holding a read lock on that directory, so this 557 * won't be released out from under us. We'll have to 558 * drop the read lock when we do a vnode_getwithvid() to 559 * allow in-progress reclaims to finish, but that means 560 * such a reclaim could free the fnnode. 561 * 562 * We get the vnode for the fnnode - which will remain 563 * a vnode even if it's reclaimed - and the vnode ID it 564 * had when we created the fnnode. 565 */ 566 vp = fntovn(fnp); 567 vid = fnp->fn_vid; 568 569 /* 570 * Now we can, and must, drop the rwlock to allow 571 * in-progress reclaims to finish. 572 */ 573 lck_rw_unlock_shared(dfnp->fn_rwlock); 574 575 /* 576 * Now let's try to get an iocount on the fnnode, so it 577 * doesn't vanish out from under us; this also checks 578 * whether the vnode has been reclaimed out from under 579 * us, and, thus, whether the fnnode has already vanished 580 * out from under us. 581 */ 582 if (vnode_getwithvid(vp, vid) != 0) { 583 /* 584 * We failed; the vnode was reclaimed. The fnnode 585 * is gone; redo the search. 586 */ 587 error = 0; 588 goto top; 589 } 590 591 /* 592 * OK, that succeeded, and the vnode is still what it 593 * was when we created the fnnode, so the fnnode is 594 * still there - and, as we're holding an iocount 595 * on the vnode, it's not going away. 596 */ 597 } 598 599fail: 600 auto_fninfo_unlock_shared(dfnip, have_lock); 601 602 if (error) { 603 /* 604 * If this is a CREATE operation, and this is the last 605 * component, and the error is ENOENT, make it ENOTSUP, 606 * instead, so that somebody trying to create a file or 607 * directory gets told "sorry, we don't support that". 608 * Do the same for RENAME operations, so somebody trying 609 * to rename a file or directory gets told that. 610 */ 611 if (error == ENOENT && 612 (nameiop == CREATE || nameiop == RENAME) && 613 (flags & ISLASTCN)) 614 error = ENOTSUP; 615 goto done; 616 } 617 618 /* 619 * We now have the actual fnnode we're interested in. 620 */ 621 *vpp = fntovn(fnp); 622 623 /* 624 * If the directory in which we created this is one on which a 625 * readdir will only return names corresponding to the vnodes 626 * we have for it, and somebody cares whether something was 627 * created in it, notify them. 628 * 629 * XXX - defer until we trigger a mount atop it? 630 */ 631 if (do_notify && vnode_ismonitored(dvp) && auto_nobrowse(dvp)) { 632 vfs_get_notify_attributes(&vattr); 633 auto_get_attributes(dvp, &vattr); 634 vnode_notify(dvp, VNODE_EVENT_WRITE, &vattr); 635 } 636 637done: 638 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n", 639 cnp->cn_nameptr, (void *)*vpp, error)); 640 641 return (error); 642} 643 644/* 645#% readdir vp L L L 646# 647vnop_readdir { 648 IN vnode_t vp; 649 INOUT struct uio *uio; 650 INOUT int *eofflag; 651 OUT int *ncookies; 652 INOUT u_long **cookies; 653 IN vfs_context_t context; 654*/ 655 656#define MAXDIRBUFSIZE 65536 657 658/* 659 * "Transient" fnnodes are fnnodes that don't have anything mounted on 660 * them and don't have subdirectories. 661 * Those are subject to evaporating in the near term, so we don't 662 * return them from a readdir - and don't filter them out from names 663 * we get from automountd. 664 */ 665#define IS_TRANSIENT(fnp) \ 666 (!vnode_mountedhere(fntovn(fnp)) && (fnp)->fn_direntcnt == 0) 667 668int 669auto_readdir(ap) 670 struct vnop_readdir_args /* { 671 vnode_t a_vp; 672 struct uio *a_uio; 673 int a_flags; 674 int *a_eofflag; 675 int *a_numdirent; 676 vfs_context_t a_context; 677 } */ *ap; 678{ 679 vnode_t vp = ap->a_vp; 680 struct uio *uiop = ap->a_uio; 681 int pid = vfs_context_pid(ap->a_context); 682 int64_t return_offset; 683 boolean_t return_eof; 684 byte_buffer return_buffer; 685 mach_msg_type_number_t return_bufcount; 686 vm_map_offset_t map_data; 687 vm_offset_t data; 688 fnnode_t *fnp = vntofn(vp); 689 fnnode_t *cfnp, *nfnp; 690 struct dirent *dp; 691 off_t offset; 692 u_int outcount = 0; 693 mach_msg_type_number_t count; 694 void *outbuf; 695 user_ssize_t user_alloc_count; 696 u_int alloc_count; 697 fninfo_t *fnip = vfstofni(vnode_mount(vp)); 698 kern_return_t ret; 699 int error = 0; 700 int reached_max = 0; 701 int myeof = 0; 702 u_int this_reclen; 703 boolean_t have_lock = 0; 704 705 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n", 706 (void *)vp, uio_offset(uiop))); 707 708 if (ap->a_numdirent != NULL) 709 *ap->a_numdirent = 0; 710 711 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) 712 return (EINVAL); 713 714 if (ap->a_eofflag != NULL) 715 *ap->a_eofflag = 0; 716 717 user_alloc_count = uio_resid(uiop); 718 /* 719 * Reject too-small user requests. 720 */ 721 if (user_alloc_count < (user_ssize_t) DIRENT_RECLEN(1)) 722 return (EINVAL); 723 /* 724 * Trim too-large user requests. 725 */ 726 if (user_alloc_count > (user_ssize_t) MAXDIRBUFSIZE) 727 user_alloc_count = MAXDIRBUFSIZE; 728 alloc_count = (u_int)user_alloc_count; 729 730 /* 731 * Make sure the mounted map won't change out from under us. 732 */ 733 have_lock = auto_fninfo_lock_shared(fnip, pid); 734 735 /* 736 * Make sure the directory we're reading won't change out from 737 * under us while we're scanning it. 738 */ 739 lck_rw_lock_shared(fnp->fn_rwlock); 740 741 if (uio_offset(uiop) >= AUTOFS_DAEMONCOOKIE) { 742 /* 743 * If we're in the middle of unmounting the map, we won't 744 * create anything under it in a lookup, so we should 745 * only return directory entries for things that are 746 * already there. 747 */ 748 if (fnip->fi_flags & MF_UNMOUNTING) { 749 myeof = 1; 750 if (ap->a_eofflag != NULL) 751 *ap->a_eofflag = 1; 752 goto done; 753 } 754 755again: 756 /* 757 * Do readdir of daemon contents only 758 * Drop readers lock and reacquire after reply. 759 */ 760 lck_rw_unlock_shared(fnp->fn_rwlock); 761 762 count = 0; 763 error = auto_readdir_aux(fnip, fnp, 764 uio_offset(uiop), alloc_count, 765 &return_offset, &return_eof, &return_buffer, 766 &return_bufcount); 767 768 /* 769 * reacquire previously dropped lock 770 */ 771 lck_rw_lock_shared(fnp->fn_rwlock); 772 773 if (error) 774 goto done; 775 776 ret = vm_map_copyout(kernel_map, &map_data, 777 (vm_map_copy_t)return_buffer); 778 if (ret != KERN_SUCCESS) { 779 IOLog("autofs: vm_map_copyout failed, status 0x%08x\n", 780 ret); 781 /* XXX - deal with Mach errors */ 782 error = EIO; 783 goto done; 784 } 785 data = CAST_DOWN(vm_offset_t, map_data); 786 787 if (return_bufcount != 0) { 788 struct dirent *odp; /* next in output buffer */ 789 struct dirent *cdp; /* current examined entry */ 790 791 /* 792 * Check for duplicates of entries that have 793 * fnnodes, and for illegal values (".", "..", 794 * and anything with a "/" in it), here. 795 */ 796 dp = (struct dirent *)data; 797 odp = dp; 798 cdp = dp; 799 do { 800 this_reclen = RECLEN(cdp); 801 cfnp = auto_search(fnp, cdp->d_name, 802 cdp->d_namlen); 803 if (cfnp == NULL || IS_TRANSIENT(cfnp)) { 804 /* 805 * entry not found in kernel list, 806 * or found but is transient, so 807 * include it in readdir output. 808 * 809 * If we are skipping entries. then 810 * we need to copy this entry to the 811 * correct position in the buffer 812 * to be copied out. 813 */ 814 if (cdp != odp) 815 bcopy(cdp, odp, 816 (size_t)this_reclen); 817 odp = nextdp(odp); 818 outcount += this_reclen; 819 if (ap->a_numdirent) 820 ++(*ap->a_numdirent); 821 } else { 822 /* 823 * Entry was found in the kernel 824 * list. If it is the first entry 825 * in this buffer, then just skip it 826 */ 827 if (odp == dp) { 828 dp = nextdp(dp); 829 odp = dp; 830 } 831 } 832 count += this_reclen; 833 cdp = (struct dirent *) 834 ((char *)cdp + this_reclen); 835 } while (count < return_bufcount); 836 837 if (outcount) 838 error = uiomove((caddr_t)dp, outcount, uiop); 839 uio_setoffset(uiop, return_offset); 840 } else { 841 if (return_eof == 0) { 842 /* 843 * alloc_count not large enough for one 844 * directory entry 845 */ 846 error = EINVAL; 847 } 848 } 849 vm_deallocate(kernel_map, data, return_bufcount); 850 if (return_eof && !error) { 851 myeof = 1; 852 if (ap->a_eofflag != NULL) 853 *ap->a_eofflag = 1; 854 } 855 if (!error && !myeof && outcount == 0) { 856 /* 857 * call daemon with new cookie, all previous 858 * elements happened to be duplicates 859 */ 860 goto again; 861 } 862 goto done; 863 } 864 865 /* 866 * Not past the "magic" offset, so we return only the entries 867 * we get without talking to the daemon. 868 */ 869 MALLOC(outbuf, void *, alloc_count, M_AUTOFS, M_WAITOK); 870 dp = outbuf; 871 if (uio_offset(uiop) == 0) { 872 /* 873 * first time: so fudge the . and .. 874 */ 875 this_reclen = DIRENT_RECLEN(1); 876 if (alloc_count < this_reclen) { 877 error = EINVAL; 878 goto done; 879 } 880 dp->d_ino = (ino_t)fnp->fn_nodeid; 881 dp->d_reclen = (uint16_t)this_reclen; 882#if 0 883 dp->d_type = DT_DIR; 884#else 885 dp->d_type = DT_UNKNOWN; 886#endif 887 dp->d_namlen = 1; 888 889 /* use strncpy() to zero out uninitialized bytes */ 890 891 (void) strncpy(dp->d_name, ".", DIRENT_NAMELEN(this_reclen)); 892 outcount += dp->d_reclen; 893 dp = nextdp(dp); 894 895 if (ap->a_numdirent) 896 ++(*ap->a_numdirent); 897 898 this_reclen = DIRENT_RECLEN(2); 899 if (alloc_count < outcount + this_reclen) { 900 error = EINVAL; 901 FREE(outbuf, M_AUTOFS); 902 goto done; 903 } 904 dp->d_reclen = (uint16_t)this_reclen; 905 dp->d_ino = (ino_t)fnp->fn_parent->fn_nodeid; 906#if 0 907 dp->d_type = DT_DIR; 908#else 909 dp->d_type = DT_UNKNOWN; 910#endif 911 dp->d_namlen = 2; 912 913 /* use strncpy() to zero out uninitialized bytes */ 914 915 (void) strncpy(dp->d_name, "..", 916 DIRENT_NAMELEN(this_reclen)); 917 outcount += dp->d_reclen; 918 dp = nextdp(dp); 919 920 if (ap->a_numdirent) 921 ++(*ap->a_numdirent); 922 } 923 924 offset = 2; 925 cfnp = fnp->fn_dirents; 926 while (cfnp != NULL) { 927 nfnp = cfnp->fn_next; 928 offset = cfnp->fn_offset; 929 /* 930 * XXX - what is this lock protecting against? We're 931 * holding a read lock on the directory we're reading, 932 * which should keep its fn_dirents list from changing 933 * and thus keep fnnodes in that list from being freed. 934 */ 935 lck_rw_lock_shared(cfnp->fn_rwlock); 936 if ((offset >= uio_offset(uiop)) && !IS_TRANSIENT(cfnp)) { 937 int reclen; 938 939 lck_rw_unlock_shared(cfnp->fn_rwlock); 940 941 /* 942 * include node only if its offset is greater or 943 * equal to the one required and isn't 944 * transient 945 */ 946 reclen = (int)DIRENT_RECLEN(cfnp->fn_namelen); 947 if (outcount + reclen > alloc_count) { 948 reached_max = 1; 949 break; 950 } 951 dp->d_reclen = (uint16_t)reclen; 952 dp->d_ino = (ino_t)cfnp->fn_nodeid; 953#if 0 954 dp->d_type = vnode_isdir(fntovn(cfnp)) ? DT_DIR : DT_LNK; 955#else 956 dp->d_type = DT_UNKNOWN; 957#endif 958 dp->d_namlen = cfnp->fn_namelen; 959 960 /* use strncpy() to zero out uninitialized bytes */ 961 962 (void) strncpy(dp->d_name, cfnp->fn_name, 963 DIRENT_NAMELEN(reclen)); 964 outcount += dp->d_reclen; 965 dp = nextdp(dp); 966 967 if (ap->a_numdirent) 968 ++(*ap->a_numdirent); 969 } else 970 lck_rw_unlock_shared(cfnp->fn_rwlock); 971 cfnp = nfnp; 972 } 973 974 if (outcount) 975 error = uiomove(outbuf, outcount, uiop); 976 if (!error) { 977 if (reached_max) { 978 /* 979 * This entry did not get added to the buffer on this, 980 * call. We need to add it on the next call therefore 981 * set uio_offset to this entry's offset. If there 982 * wasn't enough space for one dirent, return EINVAL. 983 */ 984 uio_setoffset(uiop, offset); 985 if (outcount == 0) 986 error = EINVAL; 987 } else if (auto_nobrowse(vp)) { 988 /* 989 * done reading directory entries 990 */ 991 uio_setoffset(uiop, offset + 1); 992 if (ap->a_eofflag != NULL) 993 *ap->a_eofflag = 1; 994 } else { 995 /* 996 * Need to get the rest of the entries from the daemon. 997 */ 998 uio_setoffset(uiop, AUTOFS_DAEMONCOOKIE); 999 } 1000 } 1001 FREE(outbuf, M_AUTOFS); 1002 1003done: 1004 lck_rw_unlock_shared(fnp->fn_rwlock); 1005 auto_fninfo_unlock_shared(fnip, have_lock); 1006 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n", 1007 (void *)vp, uio_offset(uiop), myeof)); 1008 return (error); 1009} 1010 1011static int 1012auto_readlink(ap) 1013 struct vnop_readlink_args /* { 1014 struct vnodeop_desc *a_desc; 1015 vnode_t a_vp; 1016 struct uio *a_uio; 1017 vfs_context_t a_context; 1018 } */ *ap; 1019{ 1020 vnode_t vp = ap->a_vp; 1021 uio_t uiop = ap->a_uio; 1022 fnnode_t *fnp = vntofn(vp); 1023 struct timeval now; 1024 int error; 1025 1026 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp)); 1027 1028 if (!vnode_islnk(vp)) 1029 error = EINVAL; 1030 else { 1031 microtime(&now); 1032 fnp->fn_atime = now; 1033 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen, 1034 (int)uio_resid(uiop)), uiop); 1035 } 1036 1037 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error)); 1038 return (error); 1039} 1040 1041static int 1042auto_pathconf(ap) 1043 struct vnop_pathconf_args /* { 1044 struct vnode *a_vp; 1045 int a_name; 1046 int *a_retval; 1047 vfs_context_t a_context; 1048 } */ *ap; 1049{ 1050 switch (ap->a_name) { 1051 case _PC_LINK_MAX: 1052 /* arbitrary limit matching HFS; autofs has no hard limit */ 1053 *ap->a_retval = 32767; 1054 break; 1055 case _PC_NAME_MAX: 1056 *ap->a_retval = NAME_MAX; 1057 break; 1058 case _PC_PATH_MAX: 1059 *ap->a_retval = PATH_MAX; 1060 break; 1061 case _PC_CHOWN_RESTRICTED: 1062 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ 1063 break; 1064 case _PC_NO_TRUNC: 1065 *ap->a_retval = 0; 1066 break; 1067 case _PC_CASE_SENSITIVE: 1068 *ap->a_retval = 1; 1069 break; 1070 case _PC_CASE_PRESERVING: 1071 *ap->a_retval = 1; 1072 break; 1073 default: 1074 return (EINVAL); 1075 } 1076 1077 return (0); 1078} 1079 1080static int 1081auto_fsctl(ap) 1082 struct vnop_ioctl_args /* { 1083 struct vnodeop_desc *a_desc; 1084 vnode_t a_vp; 1085 int32_t a_command; 1086 caddr_t a_data; 1087 int32_t a_fflag; 1088 vfs_context_t a_context; 1089 }; */ *ap; 1090{ 1091 vnode_t vp = ap->a_vp; 1092 1093 /* 1094 * The only operation we support is "mark this as having a home 1095 * directory mount in progress". 1096 */ 1097 if (ap->a_command != IOCBASECMD(AUTOFS_MARK_HOMEDIRMOUNT)) 1098 return (EINVAL); 1099 1100 /* 1101 * <13595777> homedirmounter getting ready to do a mount so we 1102 * want to take the mutex 1103 */ 1104 return (auto_mark_vnode_homedirmount(vp, 1105 vfs_context_pid(ap->a_context), 1106 1)); 1107} 1108 1109static int 1110auto_getxattr(ap) 1111 struct vnop_getxattr_args /* { 1112 struct vnodeop_desc *a_desc; 1113 vnode_t a_vp; 1114 char * a_name; 1115 uio_t a_uio; 1116 size_t *a_size; 1117 int a_options; 1118 vfs_context_t a_context; 1119 }; */ *ap; 1120{ 1121 struct uio *uio = ap->a_uio; 1122 1123 /* do not support position argument */ 1124 if (uio_offset(uio) != 0) 1125 return (EINVAL); 1126 1127 /* 1128 * We don't actually offer any extended attributes; we just say 1129 * we do, so that nobody wastes our time - or any server's time, 1130 * with wildcard maps - looking for ._ files. 1131 */ 1132 return (ENOATTR); 1133} 1134 1135static int 1136auto_listxattr(ap) 1137 struct vnop_listxattr_args /* { 1138 struct vnodeop_desc *a_desc; 1139 vnode_t a_vp; 1140 uio_t a_uio; 1141 size_t *a_size; 1142 int a_options; 1143 vfs_context_t a_context; 1144 }; */ *ap; 1145{ 1146 *ap->a_size = 0; 1147 1148 /* we have no extended attributes, so just return 0 */ 1149 return (0); 1150} 1151 1152/* 1153 * Called when the I/O count (in-progress vnops) is 0, and either 1154 * the use count (long-term references) is 0 or the vnode is being 1155 * forcibly disconnected from us (e.g., on a forced unmount, in which 1156 * case the vnode will be reassociated with deadfs). 1157 * 1158 * We just recycle the vnode, which encourages its reclamation; we 1159 * can't disconnect it until it's actually reclaimed. 1160 */ 1161static int 1162auto_inactive(ap) 1163 struct vnop_inactive_args /* { 1164 struct vnodeop_desc *a_desc; 1165 vnode_t a_vp; 1166 vfs_context_t a_context; 1167 } */ *ap; 1168{ 1169 AUTOFS_DPRINT((4, "auto_inactive: vp=%p\n", (void *)vp)); 1170 1171 vnode_recycle(ap->a_vp); 1172 1173 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p\n", (void *)vp)); 1174 return (0); 1175} 1176 1177static int 1178auto_reclaim(ap) 1179 struct vnop_reclaim_args /* { 1180 struct vnodeop_desc *a_desc; 1181 vnode_t a_vp; 1182 vfs_context_t a_context; 1183 } */ *ap; 1184{ 1185 vnode_t vp = ap->a_vp; 1186 fnnode_t *fnp = vntofn(vp); 1187 vnode_t pvp = fnp->fn_parentvp; 1188 int is_symlink = (vnode_vtype(vp) == VLNK) ? 1 : 0; 1189 1190 AUTOFS_DPRINT((4, "auto_reclaim: vp=%p fn_link=%d\n", 1191 (void *)vp, fnp->fn_linkcnt)); 1192 1193 /* 1194 * There are no filesystem calls in progress on this vnode, and 1195 * none will be made until we're done. 1196 * 1197 * Thus, it's safe to disconnect this from its parent directory, 1198 * if it has one. 1199 */ 1200 fnnode_t *dfnp = fnp->fn_parent; 1201 if (dfnp != NULL) { 1202 int needs_put = 0; 1203 1204 if (pvp && pvp != vp) { 1205 if (vnode_getwithvid(pvp, fnp->fn_parentvid)) { 1206 /* 1207 * parent has been reclaimed, just release the 1208 * reference acquired in auto_lookup. 1209 */ 1210 fnp->fn_parent = NULL; 1211 fnp->fn_parentvp = NULL; 1212 vnode_rele(pvp); 1213 goto free_node; 1214 } 1215 needs_put = 1; 1216 } 1217 1218 lck_rw_lock_exclusive(dfnp->fn_rwlock); 1219 /* 1220 * If there's only one link to this, namely the link to it 1221 * from its parent, get rid of it by removing it from 1222 * its parent's list of child fnnodes and recycle it; 1223 * a subsequent reference to it will recreate it if 1224 * the name is still there in the map. 1225 * 1226 * However, even if there is more than 1 link and we are in 1227 * reclaim it just means that the parent is getting reclaimed 1228 * before the child. This can happen and autofs can't prevent 1229 * it because vflush with FORCECLOSE has already happened 1230 * by the time autofs gets to say that it doesn't support 1231 * forced unmounts in auto_unmount. The > 1 case is that case 1232 * and we have to disconnect ourselves from the parent in that 1233 * case as well. 1234 */ 1235 if (fnp->fn_linkcnt >= 1) { 1236 /* 1237 * This will drop the write lock on dfnp. 1238 */ 1239 auto_disconnect(dfnp, fnp); 1240 } else if (fnp->fn_linkcnt == 0) { 1241 /* 1242 * Root vnode; we've already removed it from the 1243 * "parent" (the master node for all autofs file 1244 * systems) - just null out the parent pointer, so 1245 * that we don't trip any assertions 1246 * in auto_freefnnode(). 1247 */ 1248 fnp->fn_parent = NULL; 1249 fnp->fn_parentvp = NULL; 1250 lck_rw_unlock_exclusive(dfnp->fn_rwlock); 1251 } 1252 1253 if (needs_put) { 1254 vnode_put(pvp); 1255 } 1256 } 1257free_node: 1258 auto_freefnnode(fnp, is_symlink); 1259 vnode_clearfsnode(vp); 1260 AUTOFS_DPRINT((5, "auto_reclaim: (exit) vp=%p freed\n", 1261 (void *)vp)); 1262 return (0); 1263} 1264