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 284static int 285auto_lookup(ap) 286 struct vnop_lookup_args /* { 287 struct vnodeop_desc *a_desc; 288 vnode_t a_dvp; 289 vnode_t *a_vpp; 290 struct componentname *a_cnp; 291 vfs_context_t a_context; 292 } */ *ap; 293{ 294 vnode_t dvp = ap->a_dvp; 295 vnode_t *vpp = ap->a_vpp; 296 struct componentname *cnp = ap->a_cnp; 297 u_long nameiop = cnp->cn_nameiop; 298 u_long flags = cnp->cn_flags; 299 int namelen = cnp->cn_namelen; 300 vfs_context_t context = ap->a_context; 301 int pid = vfs_context_pid(context); 302 int error = 0; 303 fninfo_t *dfnip; 304 fnnode_t *dfnp = NULL; 305 fnnode_t *fnp = NULL; 306 vnode_t vp; 307 uint32_t vid; 308 char *searchnm; 309 int searchnmlen; 310 int do_notify = 0; 311 struct vnode_attr vattr; 312 int node_type; 313 314 dfnip = vfstofni(vnode_mount(dvp)); 315 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%.*s\n", 316 (void *)dvp, dfnip->fi_map, namelen, cnp->cn_nameptr)); 317 318 /* This must be a directory. */ 319 if (!vnode_isdir(dvp)) 320 return (ENOTDIR); 321 322 /* 323 * XXX - is this necessary? 324 */ 325 if (namelen == 0) { 326 error = vnode_get(dvp); 327 if (error) 328 return (error); 329 *vpp = dvp; 330 return (0); 331 } 332 333 /* first check for "." and ".." */ 334 if (cnp->cn_nameptr[0] == '.') { 335 if (namelen == 1) { 336 /* 337 * "." requested 338 */ 339 340 /* 341 * Thou shalt not rename ".". 342 * (No, the VFS layer doesn't catch this for us.) 343 */ 344 if ((nameiop == RENAME) && (flags & WANTPARENT) && 345 (flags & ISLASTCN)) 346 return (EISDIR); 347 348 error = vnode_get(dvp); 349 if (error) 350 return (error); 351 *vpp = dvp; 352 return (0); 353 } else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) { 354 fnnode_t *pdfnp; 355 356 pdfnp = (vntofn(dvp))->fn_parent; 357 assert(pdfnp != NULL); 358 359 /* 360 * Since it is legitimate to have the VROOT flag set for the 361 * subdirectories of the indirect map in autofs filesystem, 362 * rootfnnodep is checked against fnnode of dvp instead of 363 * just checking whether VROOT flag is set in dvp 364 */ 365 366#if 0 367 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) { 368 vnode_t vp; 369 370 vfs_lock_wait(vnode_mount(dvp)); 371 if (vnode_mount(dvp)->vfs_flag & VFS_UNMOUNTED) { 372 vfs_unlock(vnode_mount(dvp)); 373 return (EIO); 374 } 375 vp = vnode_mount(dvp)->mnt_vnodecovered; 376 error = vnode_get(vp); /* XXX - what if it fails? */ 377 vfs_unlock(vnode_mount(dvp)); 378 error = VNOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred); 379 vnode_put(vp); 380 return (error); 381 } else { 382#else 383 { 384#endif 385 *vpp = fntovn(pdfnp); 386 return (vnode_get(*vpp)); 387 } 388 } 389 } 390 391 dfnp = vntofn(dvp); 392 searchnm = cnp->cn_nameptr; 393 searchnmlen = namelen; 394 395 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp, 396 (void *)dfnp)); 397 398 auto_fninfo_lock_shared(dfnip, pid); 399 400top: 401 /* 402 * If this vnode is a trigger, then something should 403 * be mounted atop it, and there should be nothing 404 * in this file system below it. (We shouldn't 405 * normally get here, as we should have resolved 406 * the trigger, but some special processes don't 407 * trigger mounts.) 408 */ 409 if (dfnp->fn_trigger_info != NULL) { 410 error = ENOENT; 411 goto fail; 412 } 413 414 /* 415 * See if we have done something with this name already, so we 416 * already have it. 417 */ 418 lck_rw_lock_shared(dfnp->fn_rwlock); 419 fnp = auto_search(dfnp, cnp->cn_nameptr, cnp->cn_namelen); 420 if (fnp == NULL) { 421 /* 422 * No, we don't, so we need to make an upcall to see 423 * if something with that name should exist. 424 * 425 * Drop the writer lock on the directory, so 426 * that we don't block reclaims of autofs 427 * vnodes in that directory while we're 428 * waiting for automountd to respond 429 * (automountd, or some process on which 430 * it depends, might be doing something 431 * that requires the allocation of a 432 * vnode, and that might involve reclaiming 433 * an autofs vnode) or while we're trying 434 * to allocate a vnode for the file or 435 * directory we're looking up. 436 */ 437 lck_rw_unlock_shared(dfnp->fn_rwlock); 438 439 /* 440 * Check whether this map is in the process of being 441 * unmounted. If so, return ENOENT; see auto_control_ioctl() 442 * for the reason why this is done. 443 */ 444 if (dfnip->fi_flags & MF_UNMOUNTING) { 445 error = ENOENT; 446 goto fail; 447 } 448 449 /* 450 * Ask automountd whether something with this 451 * name exists. 452 */ 453 error = auto_lookup_aux(dfnip, dfnp, searchnm, 454 searchnmlen, context, &node_type); 455 if (error != 0) 456 goto fail; /* nope */ 457 458 /* 459 * OK, it exists. We need to create the 460 * fnnode for it, and enter it into the 461 * directory. 462 * 463 * Create the fnnode first, as we must 464 * not grab the writer lock on the 465 * directory, as per the above. 466 */ 467 error = auto_makefnnode(&fnp, node_type, 468 vnode_mount(dvp), cnp, NULL, dvp, 0, 469 dfnp->fn_globals); 470 if (error) 471 goto fail; 472 473 /* 474 * Now enter the fnnode in the directory. 475 * 476 * Note that somebody might have created the 477 * name while we weren't holding the lock; 478 * if so, then auto_enter() will return 479 * EEXIST, and will have discarded the 480 * vnode we created and handed us back 481 * an fnnode referring to what they'd 482 * already created. 483 */ 484 error = auto_enter(dfnp, cnp, &fnp); 485 if (error) { 486 if (error == EEXIST) { 487 /* 488 * We found the name. Act as if 489 * the auto_search() above succeeded. 490 */ 491 error = 0; 492 } else { 493 /* 494 * We found the name, but couldn't 495 * get an iocount on the vnode for 496 * its fnnode. That's probably 497 * because it was in the process 498 * of being recycled. Redo the search, 499 * as the directory might have changed. 500 */ 501 error = 0; 502 goto top; 503 } 504 } else { 505 /* 506 * We added an entry to the directory, 507 * so we might want to notify 508 * interested parties about that. 509 * XXX 510 */ 511 do_notify = 1; 512 } 513 } else { 514 /* 515 * Yes, we did. 516 * 517 * We're holding a read lock on that directory, so this 518 * won't be released out from under us. We'll have to 519 * drop the read lock when we do a vnode_getwithvid() to 520 * allow in-progress reclaims to finish, but that means 521 * such a reclaim could free the fnnode. 522 * 523 * We get the vnode for the fnnode - which will remain 524 * a vnode even if it's reclaimed - and the vnode ID it 525 * had when we created the fnnode. 526 */ 527 vp = fntovn(fnp); 528 vid = fnp->fn_vid; 529 530 /* 531 * Now we can, and must, drop the rwlock to allow 532 * in-progress reclaims to finish. 533 */ 534 lck_rw_unlock_shared(dfnp->fn_rwlock); 535 536 /* 537 * Now let's try to get an iocount on the fnnode, so it 538 * doesn't vanish out from under us; this also checks 539 * whether the vnode has been reclaimed out from under 540 * us, and, thus, whether the fnnode has already vanished 541 * out from under us. 542 */ 543 if (vnode_getwithvid(vp, vid) != 0) { 544 /* 545 * We failed; the vnode was reclaimed. The fnnode 546 * is gone; redo the search. 547 */ 548 error = 0; 549 goto top; 550 } 551 552 /* 553 * OK, that succeeded, and the vnode is still what it 554 * was when we created the fnnode, so the fnnode is 555 * still there - and, as we're holding an iocount 556 * on the vnode, it's not going away. 557 */ 558 } 559 560fail: 561 auto_fninfo_unlock_shared(dfnip, pid); 562 563 if (error) { 564 /* 565 * If this is a CREATE operation, and this is the last 566 * component, and the error is ENOENT, make it ENOTSUP, 567 * instead, so that somebody trying to create a file or 568 * directory gets told "sorry, we don't support that". 569 * Do the same for RENAME operations, so somebody trying 570 * to rename a file or directory gets told that. 571 */ 572 if (error == ENOENT && 573 (nameiop == CREATE || nameiop == RENAME) && 574 (flags & ISLASTCN)) 575 error = ENOTSUP; 576 goto done; 577 } 578 579 /* 580 * We now have the actual fnnode we're interested in. 581 */ 582 *vpp = fntovn(fnp); 583 584 /* 585 * If the directory in which we created this is one on which a 586 * readdir will only return names corresponding to the vnodes 587 * we have for it, and somebody cares whether something was 588 * created in it, notify them. 589 * 590 * XXX - defer until we trigger a mount atop it? 591 */ 592 if (do_notify && vnode_ismonitored(dvp) && auto_nobrowse(dvp)) { 593 vfs_get_notify_attributes(&vattr); 594 auto_get_attributes(dvp, &vattr); 595 vnode_notify(dvp, VNODE_EVENT_WRITE, &vattr); 596 } 597 598done: 599 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n", 600 cnp->cn_nameptr, (void *)*vpp, error)); 601 602 return (error); 603} 604 605/* 606#% readdir vp L L L 607# 608vnop_readdir { 609 IN vnode_t vp; 610 INOUT struct uio *uio; 611 INOUT int *eofflag; 612 OUT int *ncookies; 613 INOUT u_long **cookies; 614 IN vfs_context_t context; 615*/ 616 617#define MAXDIRBUFSIZE 65536 618 619/* 620 * "Transient" fnnodes are fnnodes that don't have anything mounted on 621 * them and don't have subdirectories. 622 * Those are subject to evaporating in the near term, so we don't 623 * return them from a readdir - and don't filter them out from names 624 * we get from automountd. 625 */ 626#define IS_TRANSIENT(fnp) \ 627 (!vnode_mountedhere(fntovn(fnp)) && (fnp)->fn_direntcnt == 0) 628 629int 630auto_readdir(ap) 631 struct vnop_readdir_args /* { 632 vnode_t a_vp; 633 struct uio *a_uio; 634 int a_flags; 635 int *a_eofflag; 636 int *a_numdirent; 637 vfs_context_t a_context; 638 } */ *ap; 639{ 640 vnode_t vp = ap->a_vp; 641 struct uio *uiop = ap->a_uio; 642 int pid = vfs_context_pid(ap->a_context); 643 int64_t return_offset; 644 boolean_t return_eof; 645 byte_buffer return_buffer; 646 mach_msg_type_number_t return_bufcount; 647 vm_map_offset_t map_data; 648 vm_offset_t data; 649 fnnode_t *fnp = vntofn(vp); 650 fnnode_t *cfnp, *nfnp; 651 struct dirent *dp; 652 off_t offset; 653 u_int outcount = 0; 654 mach_msg_type_number_t count; 655 void *outbuf; 656 user_ssize_t user_alloc_count; 657 u_int alloc_count; 658 fninfo_t *fnip = vfstofni(vnode_mount(vp)); 659 kern_return_t ret; 660 int error = 0; 661 int reached_max = 0; 662 int myeof = 0; 663 u_int this_reclen; 664 665 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n", 666 (void *)vp, uio_offset(uiop))); 667 668 if (ap->a_numdirent != NULL) 669 *ap->a_numdirent = 0; 670 671 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) 672 return (EINVAL); 673 674 if (ap->a_eofflag != NULL) 675 *ap->a_eofflag = 0; 676 677 user_alloc_count = uio_resid(uiop); 678 /* 679 * Reject too-small user requests. 680 */ 681 if (user_alloc_count < (user_ssize_t) DIRENT_RECLEN(1)) 682 return (EINVAL); 683 /* 684 * Trim too-large user requests. 685 */ 686 if (user_alloc_count > (user_ssize_t) MAXDIRBUFSIZE) 687 user_alloc_count = MAXDIRBUFSIZE; 688 alloc_count = (u_int)user_alloc_count; 689 690 /* 691 * Make sure the mounted map won't change out from under us. 692 */ 693 auto_fninfo_lock_shared(fnip, pid); 694 695 /* 696 * Make sure the directory we're reading won't change out from 697 * under us while we're scanning it. 698 */ 699 lck_rw_lock_shared(fnp->fn_rwlock); 700 701 if (uio_offset(uiop) >= AUTOFS_DAEMONCOOKIE) { 702 /* 703 * If we're in the middle of unmounting the map, we won't 704 * create anything under it in a lookup, so we should 705 * only return directory entries for things that are 706 * already there. 707 */ 708 if (fnip->fi_flags & MF_UNMOUNTING) { 709 myeof = 1; 710 if (ap->a_eofflag != NULL) 711 *ap->a_eofflag = 1; 712 goto done; 713 } 714 715again: 716 /* 717 * Do readdir of daemon contents only 718 * Drop readers lock and reacquire after reply. 719 */ 720 lck_rw_unlock_shared(fnp->fn_rwlock); 721 722 count = 0; 723 error = auto_readdir_aux(fnip, fnp, 724 uio_offset(uiop), alloc_count, 725 &return_offset, &return_eof, &return_buffer, 726 &return_bufcount); 727 728 /* 729 * reacquire previously dropped lock 730 */ 731 lck_rw_lock_shared(fnp->fn_rwlock); 732 733 if (error) 734 goto done; 735 736 ret = vm_map_copyout(kernel_map, &map_data, 737 (vm_map_copy_t)return_buffer); 738 if (ret != KERN_SUCCESS) { 739 IOLog("autofs: vm_map_copyout failed, status 0x%08x\n", 740 ret); 741 /* XXX - deal with Mach errors */ 742 error = EIO; 743 goto done; 744 } 745 data = CAST_DOWN(vm_offset_t, map_data); 746 747 if (return_bufcount != 0) { 748 struct dirent *odp; /* next in output buffer */ 749 struct dirent *cdp; /* current examined entry */ 750 751 /* 752 * Check for duplicates of entries that have 753 * fnnodes, and for illegal values (".", "..", 754 * and anything with a "/" in it), here. 755 */ 756 dp = (struct dirent *)data; 757 odp = dp; 758 cdp = dp; 759 do { 760 this_reclen = RECLEN(cdp); 761 cfnp = auto_search(fnp, cdp->d_name, 762 cdp->d_namlen); 763 if (cfnp == NULL || IS_TRANSIENT(cfnp)) { 764 /* 765 * entry not found in kernel list, 766 * or found but is transient, so 767 * include it in readdir output. 768 * 769 * If we are skipping entries. then 770 * we need to copy this entry to the 771 * correct position in the buffer 772 * to be copied out. 773 */ 774 if (cdp != odp) 775 bcopy(cdp, odp, 776 (size_t)this_reclen); 777 odp = nextdp(odp); 778 outcount += this_reclen; 779 if (ap->a_numdirent) 780 ++(*ap->a_numdirent); 781 } else { 782 /* 783 * Entry was found in the kernel 784 * list. If it is the first entry 785 * in this buffer, then just skip it 786 */ 787 if (odp == dp) { 788 dp = nextdp(dp); 789 odp = dp; 790 } 791 } 792 count += this_reclen; 793 cdp = (struct dirent *) 794 ((char *)cdp + this_reclen); 795 } while (count < return_bufcount); 796 797 if (outcount) 798 error = uiomove((caddr_t)dp, outcount, uiop); 799 uio_setoffset(uiop, return_offset); 800 } else { 801 if (return_eof == 0) { 802 /* 803 * alloc_count not large enough for one 804 * directory entry 805 */ 806 error = EINVAL; 807 } 808 } 809 vm_deallocate(kernel_map, data, return_bufcount); 810 if (return_eof && !error) { 811 myeof = 1; 812 if (ap->a_eofflag != NULL) 813 *ap->a_eofflag = 1; 814 } 815 if (!error && !myeof && outcount == 0) { 816 /* 817 * call daemon with new cookie, all previous 818 * elements happened to be duplicates 819 */ 820 goto again; 821 } 822 goto done; 823 } 824 825 /* 826 * Not past the "magic" offset, so we return only the entries 827 * we get without talking to the daemon. 828 */ 829 MALLOC(outbuf, void *, alloc_count, M_AUTOFS, M_WAITOK); 830 dp = outbuf; 831 if (uio_offset(uiop) == 0) { 832 /* 833 * first time: so fudge the . and .. 834 */ 835 this_reclen = DIRENT_RECLEN(1); 836 if (alloc_count < this_reclen) { 837 error = EINVAL; 838 goto done; 839 } 840 dp->d_ino = (ino_t)fnp->fn_nodeid; 841 dp->d_reclen = (uint16_t)this_reclen; 842#if 0 843 dp->d_type = DT_DIR; 844#else 845 dp->d_type = DT_UNKNOWN; 846#endif 847 dp->d_namlen = 1; 848 849 /* use strncpy() to zero out uninitialized bytes */ 850 851 (void) strncpy(dp->d_name, ".", DIRENT_NAMELEN(this_reclen)); 852 outcount += dp->d_reclen; 853 dp = nextdp(dp); 854 855 if (ap->a_numdirent) 856 ++(*ap->a_numdirent); 857 858 this_reclen = DIRENT_RECLEN(2); 859 if (alloc_count < outcount + this_reclen) { 860 error = EINVAL; 861 FREE(outbuf, M_AUTOFS); 862 goto done; 863 } 864 dp->d_reclen = (uint16_t)this_reclen; 865 dp->d_ino = (ino_t)fnp->fn_parent->fn_nodeid; 866#if 0 867 dp->d_type = DT_DIR; 868#else 869 dp->d_type = DT_UNKNOWN; 870#endif 871 dp->d_namlen = 2; 872 873 /* use strncpy() to zero out uninitialized bytes */ 874 875 (void) strncpy(dp->d_name, "..", 876 DIRENT_NAMELEN(this_reclen)); 877 outcount += dp->d_reclen; 878 dp = nextdp(dp); 879 880 if (ap->a_numdirent) 881 ++(*ap->a_numdirent); 882 } 883 884 offset = 2; 885 cfnp = fnp->fn_dirents; 886 while (cfnp != NULL) { 887 nfnp = cfnp->fn_next; 888 offset = cfnp->fn_offset; 889 /* 890 * XXX - what is this lock protecting against? We're 891 * holding a read lock on the directory we're reading, 892 * which should keep its fn_dirents list from changing 893 * and thus keep fnnodes in that list from being freed. 894 */ 895 lck_rw_lock_shared(cfnp->fn_rwlock); 896 if ((offset >= uio_offset(uiop)) && !IS_TRANSIENT(cfnp)) { 897 int reclen; 898 899 lck_rw_unlock_shared(cfnp->fn_rwlock); 900 901 /* 902 * include node only if its offset is greater or 903 * equal to the one required and isn't 904 * transient 905 */ 906 reclen = (int)DIRENT_RECLEN(cfnp->fn_namelen); 907 if (outcount + reclen > alloc_count) { 908 reached_max = 1; 909 break; 910 } 911 dp->d_reclen = (uint16_t)reclen; 912 dp->d_ino = (ino_t)cfnp->fn_nodeid; 913#if 0 914 dp->d_type = vnode_isdir(fntovn(cfnp)) ? DT_DIR : DT_LNK; 915#else 916 dp->d_type = DT_UNKNOWN; 917#endif 918 dp->d_namlen = cfnp->fn_namelen; 919 920 /* use strncpy() to zero out uninitialized bytes */ 921 922 (void) strncpy(dp->d_name, cfnp->fn_name, 923 DIRENT_NAMELEN(reclen)); 924 outcount += dp->d_reclen; 925 dp = nextdp(dp); 926 927 if (ap->a_numdirent) 928 ++(*ap->a_numdirent); 929 } else 930 lck_rw_unlock_shared(cfnp->fn_rwlock); 931 cfnp = nfnp; 932 } 933 934 if (outcount) 935 error = uiomove(outbuf, outcount, uiop); 936 if (!error) { 937 if (reached_max) { 938 /* 939 * This entry did not get added to the buffer on this, 940 * call. We need to add it on the next call therefore 941 * set uio_offset to this entry's offset. If there 942 * wasn't enough space for one dirent, return EINVAL. 943 */ 944 uio_setoffset(uiop, offset); 945 if (outcount == 0) 946 error = EINVAL; 947 } else if (auto_nobrowse(vp)) { 948 /* 949 * done reading directory entries 950 */ 951 uio_setoffset(uiop, offset + 1); 952 if (ap->a_eofflag != NULL) 953 *ap->a_eofflag = 1; 954 } else { 955 /* 956 * Need to get the rest of the entries from the daemon. 957 */ 958 uio_setoffset(uiop, AUTOFS_DAEMONCOOKIE); 959 } 960 } 961 FREE(outbuf, M_AUTOFS); 962 963done: 964 lck_rw_unlock_shared(fnp->fn_rwlock); 965 auto_fninfo_unlock_shared(fnip, pid); 966 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n", 967 (void *)vp, uio_offset(uiop), myeof)); 968 return (error); 969} 970 971static int 972auto_readlink(ap) 973 struct vnop_readlink_args /* { 974 struct vnodeop_desc *a_desc; 975 vnode_t a_vp; 976 struct uio *a_uio; 977 vfs_context_t a_context; 978 } */ *ap; 979{ 980 vnode_t vp = ap->a_vp; 981 uio_t uiop = ap->a_uio; 982 fnnode_t *fnp = vntofn(vp); 983 struct timeval now; 984 int error; 985 986 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp)); 987 988 if (!vnode_islnk(vp)) 989 error = EINVAL; 990 else { 991 microtime(&now); 992 fnp->fn_atime = now; 993 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen, 994 (int)uio_resid(uiop)), uiop); 995 } 996 997 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error)); 998 return (error); 999} 1000 1001static int 1002auto_pathconf(ap) 1003 struct vnop_pathconf_args /* { 1004 struct vnode *a_vp; 1005 int a_name; 1006 int *a_retval; 1007 vfs_context_t a_context; 1008 } */ *ap; 1009{ 1010 switch (ap->a_name) { 1011 case _PC_LINK_MAX: 1012 /* arbitrary limit matching HFS; autofs has no hard limit */ 1013 *ap->a_retval = 32767; 1014 break; 1015 case _PC_NAME_MAX: 1016 *ap->a_retval = NAME_MAX; 1017 break; 1018 case _PC_PATH_MAX: 1019 *ap->a_retval = PATH_MAX; 1020 break; 1021 case _PC_CHOWN_RESTRICTED: 1022 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ 1023 break; 1024 case _PC_NO_TRUNC: 1025 *ap->a_retval = 0; 1026 break; 1027 case _PC_CASE_SENSITIVE: 1028 *ap->a_retval = 1; 1029 break; 1030 case _PC_CASE_PRESERVING: 1031 *ap->a_retval = 1; 1032 break; 1033 default: 1034 return (EINVAL); 1035 } 1036 1037 return (0); 1038} 1039 1040static int 1041auto_fsctl(ap) 1042 struct vnop_ioctl_args /* { 1043 struct vnodeop_desc *a_desc; 1044 vnode_t a_vp; 1045 int32_t a_command; 1046 caddr_t a_data; 1047 int32_t a_fflag; 1048 vfs_context_t a_context; 1049 }; */ *ap; 1050{ 1051 vnode_t vp = ap->a_vp; 1052 1053 /* 1054 * The only operation we support is "mark this as having a home 1055 * directory mount in progress". 1056 */ 1057 if (ap->a_command != IOCBASECMD(AUTOFS_MARK_HOMEDIRMOUNT)) 1058 return (EINVAL); 1059 1060 /* 1061 * <13595777> homedirmounter getting ready to do a mount so we 1062 * want to take the mutex 1063 */ 1064 return (auto_mark_vnode_homedirmount(vp, 1065 vfs_context_pid(ap->a_context), 1066 1)); 1067} 1068 1069static int 1070auto_getxattr(ap) 1071 struct vnop_getxattr_args /* { 1072 struct vnodeop_desc *a_desc; 1073 vnode_t a_vp; 1074 char * a_name; 1075 uio_t a_uio; 1076 size_t *a_size; 1077 int a_options; 1078 vfs_context_t a_context; 1079 }; */ *ap; 1080{ 1081 struct uio *uio = ap->a_uio; 1082 1083 /* do not support position argument */ 1084 if (uio_offset(uio) != 0) 1085 return (EINVAL); 1086 1087 /* 1088 * We don't actually offer any extended attributes; we just say 1089 * we do, so that nobody wastes our time - or any server's time, 1090 * with wildcard maps - looking for ._ files. 1091 */ 1092 return (ENOATTR); 1093} 1094 1095static int 1096auto_listxattr(ap) 1097 struct vnop_listxattr_args /* { 1098 struct vnodeop_desc *a_desc; 1099 vnode_t a_vp; 1100 uio_t a_uio; 1101 size_t *a_size; 1102 int a_options; 1103 vfs_context_t a_context; 1104 }; */ *ap; 1105{ 1106 *ap->a_size = 0; 1107 1108 /* we have no extended attributes, so just return 0 */ 1109 return (0); 1110} 1111 1112/* 1113 * Called when the I/O count (in-progress vnops) is 0, and either 1114 * the use count (long-term references) is 0 or the vnode is being 1115 * forcibly disconnected from us (e.g., on a forced unmount, in which 1116 * case the vnode will be reassociated with deadfs). 1117 * 1118 * We just recycle the vnode, which encourages its reclamation; we 1119 * can't disconnect it until it's actually reclaimed. 1120 */ 1121static int 1122auto_inactive(ap) 1123 struct vnop_inactive_args /* { 1124 struct vnodeop_desc *a_desc; 1125 vnode_t a_vp; 1126 vfs_context_t a_context; 1127 } */ *ap; 1128{ 1129 AUTOFS_DPRINT((4, "auto_inactive: vp=%p\n", (void *)vp)); 1130 1131 vnode_recycle(ap->a_vp); 1132 1133 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p\n", (void *)vp)); 1134 return (0); 1135} 1136 1137static int 1138auto_reclaim(ap) 1139 struct vnop_reclaim_args /* { 1140 struct vnodeop_desc *a_desc; 1141 vnode_t a_vp; 1142 vfs_context_t a_context; 1143 } */ *ap; 1144{ 1145 vnode_t vp = ap->a_vp; 1146 fnnode_t *fnp = vntofn(vp); 1147 fnnode_t *dfnp = fnp->fn_parent; 1148 1149 AUTOFS_DPRINT((4, "auto_reclaim: vp=%p fn_link=%d\n", 1150 (void *)vp, fnp->fn_linkcnt)); 1151 1152 /* 1153 * There are no filesystem calls in progress on this vnode, and 1154 * none will be made until we're done. 1155 * 1156 * Thus, it's safe to disconnect this from its parent directory, 1157 * if it has one. 1158 */ 1159 if (dfnp != NULL) { 1160 lck_rw_lock_exclusive(dfnp->fn_rwlock); 1161 /* 1162 * There are no active references to this. 1163 * If there's only one link to this, namely the link to it 1164 * from its parent, get rid of it by removing it from 1165 * its parent's list of child fnnodes and recycle it; 1166 * a subsequent reference to it will recreate it if 1167 * the name is still there in the map. 1168 */ 1169 if (fnp->fn_linkcnt == 1) { 1170 /* 1171 * This will drop the write lock on dfnp. 1172 */ 1173 auto_disconnect(dfnp, fnp); 1174 } else if (fnp->fn_linkcnt == 0) { 1175 /* 1176 * Root vnode; we've already removed it from the 1177 * "parent" (the master node for all autofs file 1178 * systems) - just null out the parent pointer, so 1179 * that we don't trip any assertions 1180 * in auto_freefnnode(). 1181 */ 1182 fnp->fn_parent = NULL; 1183 lck_rw_unlock_exclusive(dfnp->fn_rwlock); 1184 } else { 1185 /* 1186 * This should not happen. 1187 */ 1188 IOLog("auto_reclaim: reclaiming fnnode with linkcnt %u > 1\n", 1189 fnp->fn_linkcnt); 1190 lck_rw_unlock_exclusive(dfnp->fn_rwlock); 1191 } 1192 } 1193 auto_freefnnode(fnp); 1194 vnode_clearfsnode(vp); 1195 AUTOFS_DPRINT((5, "auto_reclaim: (exit) vp=%p freed\n", 1196 (void *)vp)); 1197 return (0); 1198} 1199