2 * Portions Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
10 #include <afs/sysincludes.h> /* Standard vendor system headers */
11 #include <afsincludes.h> /* Afs-based standard headers */
12 #include <afs/afs_stats.h> /* statistics */
13 #include <sys/malloc.h>
14 #include <sys/namei.h>
16 #if defined(AFS_DARWIN70_ENV)
17 #include <vfs/vfs_support.h>
18 #endif /* defined(AFS_DARWIN70_ENV) */
20 int afs_vop_lookup(struct vop_lookup_args *);
21 int afs_vop_create(struct vop_create_args *);
22 int afs_vop_mknod(struct vop_mknod_args *);
23 int afs_vop_open(struct vop_open_args *);
24 int afs_vop_close(struct vop_close_args *);
25 int afs_vop_access(struct vop_access_args *);
26 int afs_vop_getattr(struct vop_getattr_args *);
27 int afs_vop_setattr(struct vop_setattr_args *);
28 int afs_vop_read(struct vop_read_args *);
29 int afs_vop_write(struct vop_write_args *);
30 int afs_vop_pagein(struct vop_pagein_args *);
31 int afs_vop_pageout(struct vop_pageout_args *);
32 int afs_vop_ioctl(struct vop_ioctl_args *);
33 int afs_vop_select(struct vop_select_args *);
34 int afs_vop_mmap(struct vop_mmap_args *);
35 int afs_vop_fsync(struct vop_fsync_args *);
36 int afs_vop_seek(struct vop_seek_args *);
37 int afs_vop_remove(struct vop_remove_args *);
38 int afs_vop_link(struct vop_link_args *);
39 int afs_vop_rename(struct vop_rename_args *);
40 int afs_vop_mkdir(struct vop_mkdir_args *);
41 int afs_vop_rmdir(struct vop_rmdir_args *);
42 int afs_vop_symlink(struct vop_symlink_args *);
43 int afs_vop_readdir(struct vop_readdir_args *);
44 int afs_vop_readlink(struct vop_readlink_args *);
45 #if !defined(AFS_DARWIN70_ENV)
46 extern int ufs_abortop(struct vop_abortop_args *);
47 #endif /* !defined(AFS_DARWIN70_ENV) */
48 int afs_vop_inactive(struct vop_inactive_args *);
49 int afs_vop_reclaim(struct vop_reclaim_args *);
50 int afs_vop_lock(struct vop_lock_args *);
51 int afs_vop_unlock(struct vop_unlock_args *);
52 int afs_vop_bmap(struct vop_bmap_args *);
53 int afs_vop_strategy(struct vop_strategy_args *);
54 int afs_vop_print(struct vop_print_args *);
55 int afs_vop_islocked(struct vop_islocked_args *);
56 int afs_vop_pathconf(struct vop_pathconf_args *);
57 int afs_vop_advlock(struct vop_advlock_args *);
58 int afs_vop_truncate(struct vop_truncate_args *);
59 int afs_vop_update(struct vop_update_args *);
60 int afs_vop_blktooff __P((struct vop_blktooff_args *));
61 int afs_vop_offtoblk __P((struct vop_offtoblk_args *));
62 int afs_vop_cmap __P((struct vop_cmap_args *));
65 #define afs_vop_opnotsupp \
66 ((int (*) __P((struct vop_reallocblks_args *)))eopnotsupp)
67 #define afs_vop_valloc afs_vop_opnotsupp
68 #define afs_vop_vfree afs_vop_opnotsupp
69 #define afs_vop_blkatoff afs_vop_opnotsupp
70 #define afs_vop_reallocblks afs_vop_opnotsupp
72 /* Global vfs data structures for AFS. */
73 int (**afs_vnodeop_p) ();
74 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
75 {&vop_default_desc, vn_default_error},
76 {&vop_lookup_desc, afs_vop_lookup}, /* lookup */
77 {&vop_create_desc, afs_vop_create}, /* create */
78 {&vop_mknod_desc, afs_vop_mknod}, /* mknod */
79 {&vop_open_desc, afs_vop_open}, /* open */
80 {&vop_close_desc, afs_vop_close}, /* close */
81 {&vop_access_desc, afs_vop_access}, /* access */
82 {&vop_getattr_desc, afs_vop_getattr}, /* getattr */
83 {&vop_setattr_desc, afs_vop_setattr}, /* setattr */
84 {&vop_read_desc, afs_vop_read}, /* read */
85 {&vop_write_desc, afs_vop_write}, /* write */
86 {&vop_pagein_desc, afs_vop_pagein}, /* read */
87 {&vop_pageout_desc, afs_vop_pageout}, /* write */
88 {&vop_ioctl_desc, afs_vop_ioctl}, /* XXX ioctl */
89 {&vop_select_desc, afs_vop_select}, /* select */
90 {&vop_mmap_desc, afs_vop_mmap}, /* mmap */
91 {&vop_fsync_desc, afs_vop_fsync}, /* fsync */
92 {&vop_seek_desc, afs_vop_seek}, /* seek */
93 {&vop_remove_desc, afs_vop_remove}, /* remove */
94 {&vop_link_desc, afs_vop_link}, /* link */
95 {&vop_rename_desc, afs_vop_rename}, /* rename */
96 {&vop_mkdir_desc, afs_vop_mkdir}, /* mkdir */
97 {&vop_rmdir_desc, afs_vop_rmdir}, /* rmdir */
98 {&vop_symlink_desc, afs_vop_symlink}, /* symlink */
99 {&vop_readdir_desc, afs_vop_readdir}, /* readdir */
100 {&vop_readlink_desc, afs_vop_readlink}, /* readlink */
101 #if defined(AFS_DARWIN70_ENV)
102 { &vop_abortop_desc, nop_abortop }, /* abortop */
103 #else /* ! defined(AFS_DARWIN70_ENV) */
104 /* Yes, we use the ufs_abortop call. It just releases the namei
106 {&vop_abortop_desc, ufs_abortop}, /* abortop */
107 #endif /* defined(AFS_DARWIN70_ENV) */
108 {&vop_inactive_desc, afs_vop_inactive}, /* inactive */
109 {&vop_reclaim_desc, afs_vop_reclaim}, /* reclaim */
110 {&vop_lock_desc, afs_vop_lock}, /* lock */
111 {&vop_unlock_desc, afs_vop_unlock}, /* unlock */
112 {&vop_bmap_desc, afs_vop_bmap}, /* bmap */
113 {&vop_strategy_desc, afs_vop_strategy}, /* strategy */
114 {&vop_print_desc, afs_vop_print}, /* print */
115 {&vop_islocked_desc, afs_vop_islocked}, /* islocked */
116 {&vop_pathconf_desc, afs_vop_pathconf}, /* pathconf */
117 {&vop_advlock_desc, afs_vop_advlock}, /* advlock */
118 {&vop_blkatoff_desc, afs_vop_blkatoff}, /* blkatoff */
119 {&vop_valloc_desc, afs_vop_valloc}, /* valloc */
120 {&vop_reallocblks_desc, afs_vop_reallocblks}, /* reallocblks */
121 {&vop_vfree_desc, afs_vop_vfree}, /* vfree */
122 {&vop_truncate_desc, afs_vop_truncate}, /* truncate */
123 {&vop_update_desc, afs_vop_update}, /* update */
124 {&vop_blktooff_desc, afs_vop_blktooff}, /* blktooff */
125 {&vop_offtoblk_desc, afs_vop_offtoblk}, /* offtoblk */
126 {&vop_cmap_desc, afs_vop_cmap}, /* cmap */
127 {&vop_bwrite_desc, vn_bwrite},
128 {(struct vnodeop_desc *)NULL, (int (*)())NULL}
130 struct vnodeopv_desc afs_vnodeop_opv_desc =
131 { &afs_vnodeop_p, afs_vnodeop_entries };
134 struct componentname *cnp = ap->a_cnp; \
136 MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
137 memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
138 name[cnp->cn_namelen] = '\0'
140 #define DROPNAME() FREE(name, M_TEMP)
146 struct vop_lookup_args /* {
147 * struct vnodeop_desc * a_desc;
148 * struct vnode *a_dvp;
149 * struct vnode **a_vpp;
150 * struct componentname *a_cnp;
155 struct vnode *vp, *dvp;
156 register int flags = ap->a_cnp->cn_flags;
157 int lockparent; /* 1 => lockparent flag is set */
158 int wantparent; /* 1 => wantparent or lockparent flag */
162 lockparent = flags & LOCKPARENT;
163 wantparent = flags & (LOCKPARENT | WANTPARENT);
165 if (ap->a_dvp->v_type != VDIR) {
171 if (flags & ISDOTDOT)
172 VOP_UNLOCK(dvp, 0, p);
174 error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
177 if (flags & ISDOTDOT)
178 VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
179 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
180 && (flags & ISLASTCN) && error == ENOENT)
182 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
183 cnp->cn_flags |= SAVENAME;
188 vp = AFSTOV(vcp); /* always get a node if no error */
189 vp->v_vfsp = dvp->v_vfsp;
191 /* The parent directory comes in locked. We unlock it on return
192 * unless the caller wants it left locked.
193 * we also always return the vnode locked. */
195 if (flags & ISDOTDOT) {
196 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
197 /* always return the child locked */
198 if (lockparent && (flags & ISLASTCN)
199 && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
204 } else if (vp == dvp) {
205 /* they're the same; afs_lookup() already ref'ed the leaf.
206 * It came in locked, so we don't need to ref OR lock it */
208 if (!lockparent || !(flags & ISLASTCN))
209 VOP_UNLOCK(dvp, 0, p); /* done with parent. */
210 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
211 /* always return the child locked */
215 if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
216 || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
217 cnp->cn_flags |= SAVENAME;
225 struct vop_create_args /* {
226 * struct vnode *a_dvp;
227 * struct vnode **a_vpp;
228 * struct componentname *a_cnp;
229 * struct vattr *a_vap;
234 register struct vnode *dvp = ap->a_dvp;
239 /* vnode layer handles excl/nonexcl */
242 afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
246 VOP_ABORTOP(dvp, cnp);
253 *ap->a_vpp = AFSTOV(vcp);
254 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
255 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
256 if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp))
257 ubc_info_init(*ap->a_vpp);
261 if ((cnp->cn_flags & SAVESTART) == 0)
262 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
270 struct vop_mknod_args /* {
271 * struct vnode *a_dvp;
272 * struct vnode **a_vpp;
273 * struct componentname *a_cnp;
274 * struct vattr *a_vap;
277 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
284 struct vop_open_args /* {
285 * struct vnode *a_vp;
287 * struct ucred *a_cred;
292 struct vnode *vp = ap->a_vp;
293 struct vcache *vc = VTOAFS(vp);
294 #ifdef AFS_DARWIN14_ENV
296 /*----------------------------------------------------------------
297 * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
298 * can later be passed to vn_open(), which will skip the call to
299 * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
300 * will be off. So we compensate by calling ubc_hold() ourselves
301 * when ui_refcount is less than 2. If an error occurs in afs_open()
302 * we must call ubc_rele(), which is what vn_open() would do if it
303 * was able to call ubc_hold() in the first place.
304 *----------------------------------------------------------------*/
305 if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
306 && vp->v_ubcinfo->ui_refcount < 2)
307 didhold = ubc_hold(vp);
308 #endif /* AFS_DARWIN14_ENV */
310 error = afs_open(&vc, ap->a_mode, ap->a_cred);
312 if (AFSTOV(vc) != vp)
313 panic("AFS open changed vnode!");
315 afs_BozonLock(&vc->pvnLock, vc);
316 osi_FlushPages(vc, ap->a_cred);
317 afs_BozonUnlock(&vc->pvnLock, vc);
319 #ifdef AFS_DARWIN14_ENV
320 if (error && didhold)
322 #endif /* AFS_DARWIN14_ENV */
328 struct vop_close_args /* {
329 * struct vnode *a_vp;
331 * struct ucred *a_cred;
336 struct vcache *avc = ap->a_vp;
339 code = afs_close(avc, ap->a_fflag, ap->a_cred, ap->a_p);
341 code = afs_close(avc, ap->a_fflag, &afs_osi_cred, ap->a_p);
342 afs_BozonLock(&avc->pvnLock, avc);
343 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
344 afs_BozonUnlock(&avc->pvnLock, avc);
346 #ifdef AFS_DARWIN14_ENV
347 if (UBCINFOEXISTS(ap->a_vp) && ap->a_vp->v_ubcinfo->ui_refcount < 2) {
349 if (ap->a_vp->v_ubcinfo->ui_refcount < 2) {
350 printf("afs: Imminent ui_refcount panic\n");
352 printf("afs: WARNING: ui_refcount panic averted\n");
362 struct vop_access_args /* {
363 * struct vnode *a_vp;
365 * struct ucred *a_cred;
371 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
378 struct vop_getattr_args /* {
379 * struct vnode *a_vp;
380 * struct vattr *a_vap;
381 * struct ucred *a_cred;
387 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
394 struct vop_setattr_args /* {
395 * struct vnode *a_vp;
396 * struct vattr *a_vap;
397 * struct ucred *a_cred;
403 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
410 struct vop_read_args /* {
411 * struct vnode *a_vp;
414 * struct ucred *a_cred;
418 struct vcache *avc = VTOAFS(ap->a_vp);
420 afs_BozonLock(&avc->pvnLock, avc);
421 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
422 code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
423 afs_BozonUnlock(&avc->pvnLock, avc);
430 struct vop_pagein_args /* {
431 * struct vnode *a_vp;
433 * vm_offset_t a_pl_offset;
436 * struct ucred *a_cred;
440 register struct vnode *vp = ap->a_vp;
442 size_t size = ap->a_size;
443 off_t f_offset = ap->a_f_offset;
444 vm_offset_t pl_offset = ap->a_pl_offset;
445 int flags = ap->a_flags;
450 struct uio *uio = &auio;
451 int nocommit = flags & UPL_NOCOMMIT;
454 struct vcache *tvc = VTOAFS(vp);
456 if (UBCINVALID(vp)) {
458 panic("afs_vop_pagein: invalid vp");
459 #endif /* DIAGNOSTIC */
463 UBCINFOCHECK("afs_vop_pagein", vp);
464 if (pl == (upl_t) NULL) {
465 panic("afs_vop_pagein: no upl");
468 cred = ubc_getcred(vp);
474 kernel_upl_abort_range(pl, pl_offset, size,
475 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
480 kernel_upl_abort_range(pl, pl_offset, size,
481 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
484 if (f_offset & PAGE_MASK)
485 panic("afs_vop_pagein: offset not page aligned");
487 auio.uio_iov = &aiov;
489 auio.uio_offset = f_offset;
490 auio.uio_segflg = UIO_SYSSPACE;
491 auio.uio_rw = UIO_READ;
492 auio.uio_procp = NULL;
493 kernel_upl_map(kernel_map, pl, &ioaddr);
495 auio.uio_resid = aiov.iov_len = size;
496 aiov.iov_base = (caddr_t) ioaddr;
498 afs_BozonLock(&tvc->pvnLock, tvc);
499 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
500 code = afs_read(tvc, uio, cred, 0, 0, 0);
502 ObtainWriteLock(&tvc->lock, 2);
503 tvc->states |= CMAPPED;
504 ReleaseWriteLock(&tvc->lock);
506 afs_BozonUnlock(&tvc->pvnLock, tvc);
509 /* Zero out rest of last page if there wasn't enough data in the file */
510 if (code == 0 && auio.uio_resid > 0)
511 memset(aiov.iov_base, 0, auio.uio_resid);
513 kernel_upl_unmap(kernel_map, pl);
516 kernel_upl_abort_range(pl, pl_offset, size,
517 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
519 kernel_upl_commit_range(pl, pl_offset, size,
520 UPL_COMMIT_CLEAR_DIRTY |
521 UPL_COMMIT_FREE_ON_EMPTY,
522 UPL_GET_INTERNAL_PAGE_LIST(pl),
530 struct vop_write_args /* {
531 * struct vnode *a_vp;
534 * struct ucred *a_cred;
538 struct vcache *avc = VTOAFS(ap->a_vp);
541 afs_BozonLock(&avc->pvnLock, avc);
542 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
543 if (UBCINFOEXISTS(ap->a_vp))
544 ubc_clean(ap->a_vp, 1);
545 if (UBCINFOEXISTS(ap->a_vp))
546 osi_VM_NukePages(ap->a_vp, ap->a_uio->uio_offset,
547 ap->a_uio->uio_resid);
549 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
550 afs_BozonUnlock(&avc->pvnLock, avc);
557 struct vop_pageout_args /* {
558 * struct vnode *a_vp;
560 * vm_offset_t a_pl_offset,
563 * struct ucred *a_cred,
567 register struct vnode *vp = ap->a_vp;
569 size_t size = ap->a_size;
570 off_t f_offset = ap->a_f_offset;
571 vm_offset_t pl_offset = ap->a_pl_offset;
572 int flags = ap->a_flags;
577 struct uio *uio = &auio;
578 int nocommit = flags & UPL_NOCOMMIT;
582 struct vcache *tvc = VTOAFS(vp);
584 if (UBCINVALID(vp)) {
586 panic("afs_vop_pageout: invalid vp");
587 #endif /* DIAGNOSTIC */
591 UBCINFOCHECK("afs_vop_pageout", vp);
592 if (pl == (upl_t) NULL) {
593 panic("afs_vop_pageout: no upl");
599 int biosize = DEV_BSIZE;
601 lbn = f_offset / DEV_BSIZE;
603 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
606 if (bp = incore(vp, lbn)) {
607 if (ISSET(bp->b_flags, B_BUSY))
608 panic("nfs_pageout: found BUSY buffer incore\n");
611 SET(bp->b_flags, (B_BUSY | B_INVAL));
618 cred = ubc_getcred(vp);
624 kernel_upl_abort_range(pl, pl_offset, size,
625 UPL_ABORT_FREE_ON_EMPTY);
628 if (flags & (IO_APPEND | IO_SYNC))
629 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
632 kernel_upl_abort_range(pl, pl_offset, size,
633 UPL_ABORT_FREE_ON_EMPTY);
636 if (f_offset >= tvc->m.Length) {
638 kernel_upl_abort_range(pl, pl_offset, size,
639 UPL_ABORT_FREE_ON_EMPTY);
643 if (f_offset & PAGE_MASK)
644 panic("afs_vop_pageout: offset not page aligned");
646 /* size will always be a multiple of PAGE_SIZE */
647 /* pageout isn't supposed to extend files */
648 if (f_offset + size > tvc->m.Length)
649 iosize = tvc->m.Length - f_offset;
653 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
654 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
655 kernel_upl_abort_range(pl, pl_offset + iosize_rnd,
657 UPL_ABORT_FREE_ON_EMPTY);
659 auio.uio_iov = &aiov;
661 auio.uio_offset = f_offset;
662 auio.uio_segflg = UIO_SYSSPACE;
663 auio.uio_rw = UIO_WRITE;
664 auio.uio_procp = NULL;
665 kernel_upl_map(kernel_map, pl, &ioaddr);
667 auio.uio_resid = aiov.iov_len = iosize;
668 aiov.iov_base = (caddr_t) ioaddr;
672 * check for partial page and clear the
673 * contents past end of the file before
674 * releasing it in the VM page cache
676 if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
677 size_t io = tvc->m.Length - f_offset;
679 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
685 afs_BozonLock(&tvc->pvnLock, tvc);
686 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
687 ObtainWriteLock(&tvc->lock, 1);
689 ReleaseWriteLock(&tvc->lock);
691 code = afs_write(tvc, uio, flags, cred, 0);
693 ObtainWriteLock(&tvc->lock, 1);
694 afs_FakeClose(tvc, cred);
695 ReleaseWriteLock(&tvc->lock);
696 afs_BozonUnlock(&tvc->pvnLock, tvc);
698 kernel_upl_unmap(kernel_map, pl);
701 kernel_upl_abort_range(pl, pl_offset, size,
702 UPL_ABORT_FREE_ON_EMPTY);
704 kernel_upl_commit_range(pl, pl_offset, size,
705 UPL_COMMIT_CLEAR_DIRTY |
706 UPL_COMMIT_FREE_ON_EMPTY,
707 UPL_GET_INTERNAL_PAGE_LIST(pl),
716 struct vop_ioctl_args /* {
717 * struct vnode *a_vp;
721 * struct ucred *a_cred;
725 struct vcache *tvc = VTOAFS(ap->a_vp);
726 struct afs_ioctl data;
729 /* in case we ever get in here... */
731 AFS_STATCNT(afs_ioctl);
732 if (((ap->a_command >> 8) & 0xff) == 'V') {
733 /* This is a VICEIOCTL call */
735 error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
736 ap->a_command, ap->a_data);
740 /* No-op call; just return. */
748 struct vop_select_args /* {
749 * struct vnode *a_vp;
752 * struct ucred *a_cred;
757 * We should really check to see if I/O is possible.
765 * NB Currently unsupported.
770 struct vop_mmap_args /* {
771 * struct vnode *a_vp;
773 * struct ucred *a_cred;
782 struct vop_fsync_args /* {
783 * struct vnode *a_vp;
784 * struct ucred *a_cred;
789 int wait = ap->a_waitfor == MNT_WAIT;
791 register struct vnode *vp = ap->a_vp;
794 /*vflushbuf(vp, wait); */
796 error = afs_fsync(VTOAFS(vp), ap->a_cred);
798 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
805 struct vop_seek_args /* {
806 * struct vnode *a_vp;
809 * struct ucred *a_cred;
812 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
819 struct vop_remove_args /* {
820 * struct vnode *a_dvp;
821 * struct vnode *a_vp;
822 * struct componentname *a_cnp;
826 register struct vnode *vp = ap->a_vp;
827 register struct vnode *dvp = ap->a_dvp;
831 error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
834 if (!error && UBCINFOEXISTS(vp)) {
835 #ifdef AFS_DARWIN14_ENV
836 (void)ubc_uncache(vp);
838 int wasmapped = ubc_issetflags(vp, UI_WASMAPPED);
839 int hasobjref = ubc_issetflags(vp, UI_HASOBJREF);
841 (void)ubc_uncache(vp);
844 /* WARNING vp may not be valid after this */
853 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
860 struct vop_link_args /* {
861 * struct vnode *a_vp;
862 * struct vnode *a_tdvp;
863 * struct componentname *a_cnp;
867 register struct vnode *dvp = ap->a_tdvp;
868 register struct vnode *vp = ap->a_vp;
873 if (vp->v_type == VDIR) {
874 VOP_ABORTOP(vp, cnp);
878 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
879 VOP_ABORTOP(dvp, cnp);
883 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
885 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
887 VOP_UNLOCK(vp, 0, p);
896 struct vop_rename_args /* {
897 * struct vnode *a_fdvp;
898 * struct vnode *a_fvp;
899 * struct componentname *a_fcnp;
900 * struct vnode *a_tdvp;
901 * struct vnode *a_tvp;
902 * struct componentname *a_tcnp;
906 struct componentname *fcnp = ap->a_fcnp;
908 struct componentname *tcnp = ap->a_tcnp;
910 struct vnode *tvp = ap->a_tvp;
911 register struct vnode *tdvp = ap->a_tdvp;
912 struct vnode *fvp = ap->a_fvp;
913 register struct vnode *fdvp = ap->a_fdvp;
914 struct proc *p = fcnp->cn_proc;
916 /* Check for cross-device rename.
917 * For AFS, this means anything not in AFS-space
919 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
920 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
926 * if fvp == tvp, we're just removing one name of a pair of
927 * directory entries for the same element. convert call into rename.
928 ( (pinched from NetBSD 1.0's ufs_rename())
931 if (fvp->v_type == VDIR) {
934 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
941 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
947 /* Release destination completely. */
948 VOP_ABORTOP(tdvp, tcnp);
955 fcnp->cn_flags &= ~MODMASK;
956 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
957 if ((fcnp->cn_flags & SAVESTART) == 0)
958 panic("afs_rename: lost from startdir");
959 fcnp->cn_nameiop = DELETE;
960 (void)relookup(fdvp, &fvp, fcnp);
961 return (VOP_REMOVE(fdvp, fvp, fcnp));
963 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
966 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
967 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
968 fname[fcnp->cn_namelen] = '\0';
969 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
970 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
971 tname[tcnp->cn_namelen] = '\0';
975 /* XXX use "from" or "to" creds? NFS uses "to" creds */
977 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
980 VOP_UNLOCK(fvp, 0, p);
984 goto abortit; /* XXX */
998 struct vop_mkdir_args /* {
999 * struct vnode *a_dvp;
1000 * struct vnode **a_vpp;
1001 * struct componentname *a_cnp;
1002 * struct vattr *a_vap;
1005 register struct vnode *dvp = ap->a_dvp;
1006 register struct vattr *vap = ap->a_vap;
1014 if ((cnp->cn_flags & HASBUF) == 0)
1015 panic("afs_vop_mkdir: no name");
1018 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1021 VOP_ABORTOP(dvp, cnp);
1027 *ap->a_vpp = AFSTOV(vcp);
1028 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1029 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1033 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1040 struct vop_rmdir_args /* {
1041 * struct vnode *a_dvp;
1042 * struct vnode *a_vp;
1043 * struct componentname *a_cnp;
1047 register struct vnode *vp = ap->a_vp;
1048 register struct vnode *dvp = ap->a_dvp;
1054 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1060 error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1070 struct vop_symlink_args /* {
1071 * struct vnode *a_dvp;
1072 * struct vnode **a_vpp;
1073 * struct componentname *a_cnp;
1074 * struct vattr *a_vap;
1078 register struct vnode *dvp = ap->a_dvp;
1080 /* NFS ignores a_vpp; so do we. */
1085 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
1088 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1095 struct vop_readdir_args /* {
1096 * struct vnode *a_vp;
1097 * struct uio *a_uio;
1098 * struct ucred *a_cred;
1100 * u_long *a_cookies;
1106 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1108 off = ap->a_uio->uio_offset;
1111 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1113 if (!error && ap->a_ncookies != NULL) {
1114 struct uio *uio = ap->a_uio;
1115 const struct dirent *dp, *dp_start, *dp_end;
1117 u_long *cookies, *cookiep;
1119 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1120 panic("afs_readdir: burned cookies");
1121 dp = (const struct dirent *)
1122 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1124 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1125 for (dp_start = dp, ncookies = 0; dp < dp_end;
1126 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1129 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1131 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1132 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1133 off += dp->d_reclen;
1136 *ap->a_cookies = cookies;
1137 *ap->a_ncookies = ncookies;
1144 afs_vop_readlink(ap)
1145 struct vop_readlink_args /* {
1146 * struct vnode *a_vp;
1147 * struct uio *a_uio;
1148 * struct ucred *a_cred;
1152 /* printf("readlink %x\n", ap->a_vp);*/
1154 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1159 extern int prtactive;
1162 afs_vop_inactive(ap)
1163 struct vop_inactive_args /* {
1164 * struct vnode *a_vp;
1168 register struct vnode *vp = ap->a_vp;
1170 if (prtactive && vp->v_usecount != 0)
1171 vprint("afs_vop_inactive(): pushing active", vp);
1174 afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
1176 VOP_UNLOCK(vp, 0, ap->a_p);
1182 struct vop_reclaim_args /* {
1183 * struct vnode *a_vp;
1188 register struct vnode *vp = ap->a_vp;
1190 cache_purge(vp); /* just in case... */
1194 error = afs_FlushVCache(VTOAFS(vp), &sl); /* tosses our stuff from vnode */
1197 if (!error && vp->v_data)
1198 panic("afs_reclaim: vnode not cleaned");
1201 if (vp->v_usecount == 2) {
1202 vprint("reclaim count==2", vp);
1203 } else if (vp->v_usecount == 1) {
1204 vprint("reclaim count==1", vp);
1206 vprint("reclaim bad count", vp);
1214 struct vop_lock_args /* {
1215 * struct vnode *a_vp;
1218 register struct vnode *vp = ap->a_vp;
1219 register struct vcache *avc = VTOAFS(vp);
1221 if (vp->v_tag == VT_NON)
1223 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1228 struct vop_unlock_args /* {
1229 * struct vnode *a_vp;
1232 struct vnode *vp = ap->a_vp;
1233 struct vcache *avc = VTOAFS(vp);
1235 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1242 struct vop_bmap_args /* {
1243 * struct vnode *a_vp;
1245 * struct vnode **a_vpp;
1254 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1257 *ap->a_vpp = ap->a_vp;
1259 if (ap->a_runp != NULL)
1262 if (ap->a_runb != NULL)
1270 afs_vop_strategy(ap)
1271 struct vop_strategy_args /* {
1277 error = afs_ustrategy(ap->a_bp);
1284 struct vop_print_args /* {
1285 * struct vnode *a_vp;
1288 register struct vnode *vp = ap->a_vp;
1289 register struct vcache *vc = VTOAFS(ap->a_vp);
1291 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1292 vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1293 vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1294 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1295 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1296 (s & CMAPPED) ? " mapped" : "",
1297 (s & CVFlushed) ? " flush in progress" : "");
1298 if (UBCISVALID(vp)) {
1300 if (UBCINFOEXISTS(vp)) {
1302 #ifdef AFS_DARWIN14_ENV
1303 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1304 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1305 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1307 printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1310 printf("does not exist");
1317 afs_vop_islocked(ap)
1318 struct vop_islocked_args /* {
1319 * struct vnode *a_vp;
1322 struct vcache *vc = VTOAFS(ap->a_vp);
1323 return lockstatus(&vc->rwlock);
1327 * Return POSIX pathconf information applicable to ufs filesystems.
1329 afs_vop_pathconf(ap)
1330 struct vop_pathconf_args /* {
1331 * struct vnode *a_vp;
1336 AFS_STATCNT(afs_cntl);
1337 switch (ap->a_name) {
1339 *ap->a_retval = LINK_MAX;
1342 *ap->a_retval = NAME_MAX;
1345 *ap->a_retval = PATH_MAX;
1347 case _PC_CHOWN_RESTRICTED:
1356 #if defined(AFS_DARWIN70_ENV)
1357 case _PC_NAME_CHARS_MAX:
1358 *ap->a_retval = NAME_MAX;
1360 case _PC_CASE_SENSITIVE:
1363 case _PC_CASE_PRESERVING:
1366 #endif /* defined(AFS_DARWIN70_ENV) */
1374 * Advisory record locking support (fcntl() POSIX style)
1378 struct vop_advlock_args /* {
1379 * struct vnode *a_vp;
1382 * struct flock *a_fl;
1387 struct proc *p = current_proc();
1390 cr = *p->p_cred->pc_ucred;
1394 afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
1400 afs_vop_truncate(ap)
1401 struct vop_truncate_args /* {
1402 * struct vnode *a_vp;
1405 * struct ucred *a_cred;
1409 printf("stray afs_vop_truncate\n");
1415 struct vop_update_args /* {
1416 * struct vnode *a_vp;
1417 * struct timeval *a_access;
1418 * struct timeval *a_modify;
1422 printf("stray afs_vop_update\n");
1427 afs_vop_blktooff(ap)
1428 struct vop_blktooff_args /* {
1429 * struct vnode *a_vp;
1434 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1439 afs_vop_offtoblk(ap)
1440 struct vop_offtoblk_args /* {
1441 * struct vnode *a_vp;
1443 * daddr_t *a_lblkno;
1446 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1453 struct vop_cmap_args /* {
1454 * struct vnode *a_vp;
1462 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
1463 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));