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)
143 darwin_vn_hold(struct vnode *vp)
145 int haveGlock=ISAFS_GLOCK();
146 struct vcache *tvc = VTOAFS(vp);
148 tvc->states |= CUBCinit;
149 if (haveGlock) AFS_GUNLOCK();
151 /* vget needed for 0 ref'd vnode in GetVCache to not panic in vref.
152 vref needed for multiref'd vnode in vnop_remove not to deadlock
153 ourselves during vop_inactive, except we also need to not reinst
154 the ubc... so we just call VREF there now anyway. */
156 if (VREFCOUNT(tvc) > 0)
157 VREF(((struct vnode *)(vp)));
159 afs_vget(afs_globalVFS, 0, (vp));
161 if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
165 if (haveGlock) AFS_GLOCK();
166 tvc->states &= ~CUBCinit;
171 struct vop_lookup_args /* {
172 * struct vnodeop_desc * a_desc;
173 * struct vnode *a_dvp;
174 * struct vnode **a_vpp;
175 * struct componentname *a_cnp;
180 struct vnode *vp, *dvp;
181 register int flags = ap->a_cnp->cn_flags;
182 int lockparent; /* 1 => lockparent flag is set */
183 int wantparent; /* 1 => wantparent or lockparent flag */
187 lockparent = flags & LOCKPARENT;
188 wantparent = flags & (LOCKPARENT | WANTPARENT);
190 if (ap->a_dvp->v_type != VDIR) {
196 if (flags & ISDOTDOT)
197 VOP_UNLOCK(dvp, 0, p);
199 error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
202 if (flags & ISDOTDOT)
203 VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
204 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
205 && (flags & ISLASTCN) && error == ENOENT)
207 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
208 cnp->cn_flags |= SAVENAME;
213 vp = AFSTOV(vcp); /* always get a node if no error */
214 vp->v_vfsp = dvp->v_vfsp;
216 if (UBCINFOMISSING(vp) ||
217 UBCINFORECLAIMED(vp)) {
221 /* The parent directory comes in locked. We unlock it on return
222 * unless the caller wants it left locked.
223 * we also always return the vnode locked. */
225 if (flags & ISDOTDOT) {
226 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
227 /* always return the child locked */
228 if (lockparent && (flags & ISLASTCN)
229 && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
234 } else if (vp == dvp) {
235 /* they're the same; afs_lookup() already ref'ed the leaf.
236 * It came in locked, so we don't need to ref OR lock it */
238 if (!lockparent || !(flags & ISLASTCN))
239 VOP_UNLOCK(dvp, 0, p); /* done with parent. */
240 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
241 /* always return the child locked */
245 if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
246 || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
247 cnp->cn_flags |= SAVENAME;
255 struct vop_create_args /* {
256 * struct vnode *a_dvp;
257 * struct vnode **a_vpp;
258 * struct componentname *a_cnp;
259 * struct vattr *a_vap;
264 register struct vnode *dvp = ap->a_dvp;
269 /* vnode layer handles excl/nonexcl */
272 afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
276 VOP_ABORTOP(dvp, cnp);
283 *ap->a_vpp = AFSTOV(vcp);
284 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
285 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
286 if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
287 vcp->states |= CUBCinit;
288 ubc_info_init(*ap->a_vpp);
289 vcp->states &= ~CUBCinit;
294 if ((cnp->cn_flags & SAVESTART) == 0)
295 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
303 struct vop_mknod_args /* {
304 * struct vnode *a_dvp;
305 * struct vnode **a_vpp;
306 * struct componentname *a_cnp;
307 * struct vattr *a_vap;
310 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
317 struct vop_open_args /* {
318 * struct vnode *a_vp;
320 * struct ucred *a_cred;
325 struct vnode *vp = ap->a_vp;
326 struct vcache *vc = VTOAFS(vp);
327 #ifdef AFS_DARWIN14_ENV
329 /*----------------------------------------------------------------
330 * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
331 * can later be passed to vn_open(), which will skip the call to
332 * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
333 * will be off. So we compensate by calling ubc_hold() ourselves
334 * when ui_refcount is less than 2. If an error occurs in afs_open()
335 * we must call ubc_rele(), which is what vn_open() would do if it
336 * was able to call ubc_hold() in the first place.
337 *----------------------------------------------------------------*/
338 if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
339 && vp->v_ubcinfo->ui_refcount < 2)
340 didhold = ubc_hold(vp);
341 #endif /* AFS_DARWIN14_ENV */
343 error = afs_open(&vc, ap->a_mode, ap->a_cred);
345 if (AFSTOV(vc) != vp)
346 panic("AFS open changed vnode!");
349 osi_FlushPages(vc, ap->a_cred);
352 #ifdef AFS_DARWIN14_ENV
353 if (error && didhold)
355 #endif /* AFS_DARWIN14_ENV */
361 struct vop_close_args /* {
362 * struct vnode *a_vp;
364 * struct ucred *a_cred;
369 struct vnode *vp = ap->a_vp;
370 struct vcache *avc = VTOAFS(vp);
373 code = afs_close(avc, ap->a_fflag, ap->a_cred, ap->a_p);
375 code = afs_close(avc, ap->a_fflag, &afs_osi_cred, ap->a_p);
377 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
386 struct vop_access_args /* {
387 * struct vnode *a_vp;
389 * struct ucred *a_cred;
395 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
402 struct vop_getattr_args /* {
403 * struct vnode *a_vp;
404 * struct vattr *a_vap;
405 * struct ucred *a_cred;
412 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
419 struct vop_setattr_args /* {
420 * struct vnode *a_vp;
421 * struct vattr *a_vap;
422 * struct ucred *a_cred;
428 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
435 struct vop_read_args /* {
436 * struct vnode *a_vp;
439 * struct ucred *a_cred;
443 struct vnode *vp = ap->a_vp;
444 struct vcache *avc = VTOAFS(vp);
447 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
449 code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
456 struct vop_pagein_args /* {
457 * struct vnode *a_vp;
459 * vm_offset_t a_pl_offset;
462 * struct ucred *a_cred;
466 register struct vnode *vp = ap->a_vp;
468 size_t size = ap->a_size;
469 off_t f_offset = ap->a_f_offset;
470 vm_offset_t pl_offset = ap->a_pl_offset;
471 int flags = ap->a_flags;
476 struct uio *uio = &auio;
477 int nocommit = flags & UPL_NOCOMMIT;
480 struct vcache *tvc = VTOAFS(vp);
482 if (UBCINVALID(vp)) {
484 panic("afs_vop_pagein: invalid vp");
485 #endif /* DIAGNOSTIC */
489 UBCINFOCHECK("afs_vop_pagein", vp);
490 if (pl == (upl_t) NULL) {
491 panic("afs_vop_pagein: no upl");
494 cred = ubc_getcred(vp);
500 kernel_upl_abort_range(pl, pl_offset, size,
501 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
506 kernel_upl_abort_range(pl, pl_offset, size,
507 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
510 if (f_offset & PAGE_MASK)
511 panic("afs_vop_pagein: offset not page aligned");
513 auio.uio_iov = &aiov;
515 auio.uio_offset = f_offset;
516 auio.uio_segflg = UIO_SYSSPACE;
517 auio.uio_rw = UIO_READ;
518 auio.uio_procp = NULL;
519 kernel_upl_map(kernel_map, pl, &ioaddr);
521 auio.uio_resid = aiov.iov_len = size;
522 aiov.iov_base = (caddr_t) ioaddr;
525 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
527 code = afs_read(tvc, uio, cred, 0, 0, 0);
529 ObtainWriteLock(&tvc->lock, 2);
530 tvc->states |= CMAPPED;
531 ReleaseWriteLock(&tvc->lock);
535 /* Zero out rest of last page if there wasn't enough data in the file */
536 if (code == 0 && auio.uio_resid > 0)
537 memset(aiov.iov_base, 0, auio.uio_resid);
539 kernel_upl_unmap(kernel_map, pl);
542 kernel_upl_abort_range(pl, pl_offset, size,
543 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
545 kernel_upl_commit_range(pl, pl_offset, size,
546 UPL_COMMIT_CLEAR_DIRTY |
547 UPL_COMMIT_FREE_ON_EMPTY,
548 UPL_GET_INTERNAL_PAGE_LIST(pl),
556 struct vop_write_args /* {
557 * struct vnode *a_vp;
560 * struct ucred *a_cred;
564 struct vcache *avc = VTOAFS(ap->a_vp);
568 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
570 if (UBCINFOEXISTS(ap->a_vp)) {
571 ubc_clean(ap->a_vp, 1);
573 if (UBCINFOEXISTS(ap->a_vp))
574 osi_VM_NukePages(ap->a_vp, ap->a_uio->uio_offset,
575 ap->a_uio->uio_resid);
577 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
584 struct vop_pageout_args /* {
585 * struct vnode *a_vp;
587 * vm_offset_t a_pl_offset,
590 * struct ucred *a_cred,
594 register struct vnode *vp = ap->a_vp;
596 size_t size = ap->a_size;
597 off_t f_offset = ap->a_f_offset;
598 vm_offset_t pl_offset = ap->a_pl_offset;
599 int flags = ap->a_flags;
604 struct uio *uio = &auio;
605 int nocommit = flags & UPL_NOCOMMIT;
609 struct vcache *tvc = VTOAFS(vp);
611 if (UBCINVALID(vp)) {
613 panic("afs_vop_pageout: invalid vp");
614 #endif /* DIAGNOSTIC */
618 UBCINFOCHECK("afs_vop_pageout", vp);
619 if (pl == (upl_t) NULL) {
620 panic("afs_vop_pageout: no upl");
626 int biosize = DEV_BSIZE;
628 lbn = f_offset / DEV_BSIZE;
630 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
633 if (bp = incore(vp, lbn)) {
634 if (ISSET(bp->b_flags, B_BUSY))
635 panic("nfs_pageout: found BUSY buffer incore\n");
638 SET(bp->b_flags, (B_BUSY | B_INVAL));
645 cred = ubc_getcred(vp);
651 kernel_upl_abort_range(pl, pl_offset, size,
652 UPL_ABORT_FREE_ON_EMPTY);
655 if (flags & (IO_APPEND | IO_SYNC))
656 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
659 kernel_upl_abort_range(pl, pl_offset, size,
660 UPL_ABORT_FREE_ON_EMPTY);
663 if (f_offset >= tvc->m.Length) {
665 kernel_upl_abort_range(pl, pl_offset, size,
666 UPL_ABORT_FREE_ON_EMPTY);
670 if (f_offset & PAGE_MASK)
671 panic("afs_vop_pageout: offset not page aligned");
673 /* size will always be a multiple of PAGE_SIZE */
674 /* pageout isn't supposed to extend files */
675 if (f_offset + size > tvc->m.Length)
676 iosize = tvc->m.Length - f_offset;
680 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
681 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
682 kernel_upl_abort_range(pl, pl_offset + iosize_rnd,
684 UPL_ABORT_FREE_ON_EMPTY);
686 auio.uio_iov = &aiov;
688 auio.uio_offset = f_offset;
689 auio.uio_segflg = UIO_SYSSPACE;
690 auio.uio_rw = UIO_WRITE;
691 auio.uio_procp = NULL;
692 kernel_upl_map(kernel_map, pl, &ioaddr);
694 auio.uio_resid = aiov.iov_len = iosize;
695 aiov.iov_base = (caddr_t) ioaddr;
699 * check for partial page and clear the
700 * contents past end of the file before
701 * releasing it in the VM page cache
703 if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
704 size_t io = tvc->m.Length - f_offset;
706 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
713 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
715 ObtainWriteLock(&tvc->lock, 1);
717 ReleaseWriteLock(&tvc->lock);
719 code = afs_write(tvc, uio, flags, cred, 0);
721 ObtainWriteLock(&tvc->lock, 1);
722 afs_FakeClose(tvc, cred);
723 ReleaseWriteLock(&tvc->lock);
725 kernel_upl_unmap(kernel_map, pl);
728 kernel_upl_abort_range(pl, pl_offset, size,
729 UPL_ABORT_FREE_ON_EMPTY);
731 kernel_upl_commit_range(pl, pl_offset, size,
732 UPL_COMMIT_CLEAR_DIRTY |
733 UPL_COMMIT_FREE_ON_EMPTY,
734 UPL_GET_INTERNAL_PAGE_LIST(pl),
743 struct vop_ioctl_args /* {
744 * struct vnode *a_vp;
748 * struct ucred *a_cred;
752 struct vcache *tvc = VTOAFS(ap->a_vp);
753 struct afs_ioctl data;
756 /* in case we ever get in here... */
758 AFS_STATCNT(afs_ioctl);
759 if (((ap->a_command >> 8) & 0xff) == 'V') {
760 /* This is a VICEIOCTL call */
762 error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
763 ap->a_command, ap->a_data);
767 /* No-op call; just return. */
775 struct vop_select_args /* {
776 * struct vnode *a_vp;
779 * struct ucred *a_cred;
784 * We should really check to see if I/O is possible.
792 * NB Currently unsupported.
797 struct vop_mmap_args /* {
798 * struct vnode *a_vp;
800 * struct ucred *a_cred;
809 struct vop_fsync_args /* {
810 * struct vnode *a_vp;
811 * struct ucred *a_cred;
816 int wait = ap->a_waitfor == MNT_WAIT;
818 register struct vnode *vp = ap->a_vp;
819 int haveGlock = ISAFS_GLOCK();
821 /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
822 if (!haveGlock) AFS_GLOCK();
824 error = afs_fsync(VTOAFS(vp), ap->a_cred);
826 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
827 if (!haveGlock) AFS_GUNLOCK();
833 struct vop_seek_args /* {
834 * struct vnode *a_vp;
837 * struct ucred *a_cred;
840 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
847 struct vop_remove_args /* {
848 * struct vnode *a_dvp;
849 * struct vnode *a_vp;
850 * struct componentname *a_cnp;
854 register struct vnode *vp = ap->a_vp;
855 register struct vnode *dvp = ap->a_dvp;
859 error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
864 /* necessary so we don't deadlock ourselves in vclean */
865 VOP_UNLOCK(vp, 0, cnp->cn_proc);
867 /* If crashes continue in ubc_hold, comment this out */
868 (void)ubc_uncache(vp);
876 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
883 struct vop_link_args /* {
884 * struct vnode *a_vp;
885 * struct vnode *a_tdvp;
886 * struct componentname *a_cnp;
890 register struct vnode *dvp = ap->a_tdvp;
891 register struct vnode *vp = ap->a_vp;
896 if (vp->v_type == VDIR) {
897 VOP_ABORTOP(vp, cnp);
901 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
902 VOP_ABORTOP(dvp, cnp);
906 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
908 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
910 VOP_UNLOCK(vp, 0, p);
919 struct vop_rename_args /* {
920 * struct vnode *a_fdvp;
921 * struct vnode *a_fvp;
922 * struct componentname *a_fcnp;
923 * struct vnode *a_tdvp;
924 * struct vnode *a_tvp;
925 * struct componentname *a_tcnp;
929 struct componentname *fcnp = ap->a_fcnp;
931 struct componentname *tcnp = ap->a_tcnp;
933 struct vnode *tvp = ap->a_tvp;
934 register struct vnode *tdvp = ap->a_tdvp;
935 struct vnode *fvp = ap->a_fvp;
936 register struct vnode *fdvp = ap->a_fdvp;
937 struct proc *p = fcnp->cn_proc;
939 /* Check for cross-device rename.
940 * For AFS, this means anything not in AFS-space
942 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
943 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
949 * if fvp == tvp, we're just removing one name of a pair of
950 * directory entries for the same element. convert call into rename.
951 ( (pinched from NetBSD 1.0's ufs_rename())
954 if (fvp->v_type == VDIR) {
957 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
964 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
970 /* Release destination completely. */
971 VOP_ABORTOP(tdvp, tcnp);
978 fcnp->cn_flags &= ~MODMASK;
979 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
980 if ((fcnp->cn_flags & SAVESTART) == 0)
981 panic("afs_rename: lost from startdir");
982 fcnp->cn_nameiop = DELETE;
985 error=relookup(fdvp, &fvp, fcnp);
992 error=VOP_REMOVE(fdvp, fvp, fcnp);
1000 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1003 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1004 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1005 fname[fcnp->cn_namelen] = '\0';
1006 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1007 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1008 tname[tcnp->cn_namelen] = '\0';
1012 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1014 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
1017 VOP_UNLOCK(fvp, 0, p);
1018 FREE(fname, M_TEMP);
1019 FREE(tname, M_TEMP);
1021 goto abortit; /* XXX */
1035 struct vop_mkdir_args /* {
1036 * struct vnode *a_dvp;
1037 * struct vnode **a_vpp;
1038 * struct componentname *a_cnp;
1039 * struct vattr *a_vap;
1042 register struct vnode *dvp = ap->a_dvp;
1043 register struct vattr *vap = ap->a_vap;
1051 if ((cnp->cn_flags & HASBUF) == 0)
1052 panic("afs_vop_mkdir: no name");
1055 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1058 VOP_ABORTOP(dvp, cnp);
1064 *ap->a_vpp = AFSTOV(vcp);
1065 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1066 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1070 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1077 struct vop_rmdir_args /* {
1078 * struct vnode *a_dvp;
1079 * struct vnode *a_vp;
1080 * struct componentname *a_cnp;
1084 register struct vnode *vp = ap->a_vp;
1085 register struct vnode *dvp = ap->a_dvp;
1091 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1097 error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1107 struct vop_symlink_args /* {
1108 * struct vnode *a_dvp;
1109 * struct vnode **a_vpp;
1110 * struct componentname *a_cnp;
1111 * struct vattr *a_vap;
1115 register struct vnode *dvp = ap->a_dvp;
1117 /* NFS ignores a_vpp; so do we. */
1122 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
1125 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1132 struct vop_readdir_args /* {
1133 * struct vnode *a_vp;
1134 * struct uio *a_uio;
1135 * struct ucred *a_cred;
1137 * u_long *a_cookies;
1143 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1145 off = ap->a_uio->uio_offset;
1148 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1150 if (!error && ap->a_ncookies != NULL) {
1151 struct uio *uio = ap->a_uio;
1152 const struct dirent *dp, *dp_start, *dp_end;
1154 u_long *cookies, *cookiep;
1156 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1157 panic("afs_readdir: burned cookies");
1158 dp = (const struct dirent *)
1159 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1161 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1162 for (dp_start = dp, ncookies = 0; dp < dp_end;
1163 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1166 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1168 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1169 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1170 off += dp->d_reclen;
1173 *ap->a_cookies = cookies;
1174 *ap->a_ncookies = ncookies;
1181 afs_vop_readlink(ap)
1182 struct vop_readlink_args /* {
1183 * struct vnode *a_vp;
1184 * struct uio *a_uio;
1185 * struct ucred *a_cred;
1189 /* printf("readlink %x\n", ap->a_vp);*/
1191 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1196 extern int prtactive;
1199 afs_vop_inactive(ap)
1200 struct vop_inactive_args /* {
1201 * struct vnode *a_vp;
1205 register struct vnode *vp = ap->a_vp;
1207 if (prtactive && vp->v_usecount != 0)
1208 vprint("afs_vop_inactive(): pushing active", vp);
1211 afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
1213 VOP_UNLOCK(vp, 0, ap->a_p);
1219 struct vop_reclaim_args /* {
1220 * struct vnode *a_vp;
1225 register struct vnode *vp = ap->a_vp;
1226 int haveGlock = ISAFS_GLOCK();
1227 struct vcache *tvc = VTOAFS(vp);
1229 cache_purge(vp); /* just in case... */
1232 error = afs_FlushVCache(VTOAFS(vp), &sl); /* toss our stuff from vnode */
1236 if (!error && vp->v_data)
1237 panic("afs_reclaim: vnode not cleaned");
1238 if (!error && (tvc->v != NULL))
1239 panic("afs_reclaim: vcache not cleaned");
1246 struct vop_lock_args /* {
1247 * struct vnode *a_vp;
1250 register struct vnode *vp = ap->a_vp;
1251 register struct vcache *avc = VTOAFS(vp);
1253 if (vp->v_tag == VT_NON)
1256 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1261 struct vop_unlock_args /* {
1262 * struct vnode *a_vp;
1265 struct vnode *vp = ap->a_vp;
1266 struct vcache *avc = VTOAFS(vp);
1269 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1276 struct vop_bmap_args /* {
1277 * struct vnode *a_vp;
1279 * struct vnode **a_vpp;
1287 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1290 *ap->a_vpp = ap->a_vp;
1292 if (ap->a_runp != NULL)
1295 if (ap->a_runb != NULL)
1303 afs_vop_strategy(ap)
1304 struct vop_strategy_args /* {
1310 error = afs_ustrategy(ap->a_bp);
1317 struct vop_print_args /* {
1318 * struct vnode *a_vp;
1321 register struct vnode *vp = ap->a_vp;
1322 register struct vcache *vc = VTOAFS(ap->a_vp);
1324 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1325 vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1326 vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1327 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1328 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1329 (s & CMAPPED) ? " mapped" : "",
1330 (s & CVFlushed) ? " flush in progress" : "");
1331 if (UBCISVALID(vp)) {
1333 if (UBCINFOEXISTS(vp)) {
1335 #ifdef AFS_DARWIN14_ENV
1336 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1337 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1338 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1340 printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1343 printf("does not exist");
1350 afs_vop_islocked(ap)
1351 struct vop_islocked_args /* {
1352 * struct vnode *a_vp;
1355 struct vcache *vc = VTOAFS(ap->a_vp);
1356 return lockstatus(&vc->rwlock);
1360 * Return POSIX pathconf information applicable to ufs filesystems.
1362 afs_vop_pathconf(ap)
1363 struct vop_pathconf_args /* {
1364 * struct vnode *a_vp;
1369 AFS_STATCNT(afs_cntl);
1370 switch (ap->a_name) {
1372 *ap->a_retval = LINK_MAX;
1375 *ap->a_retval = NAME_MAX;
1378 *ap->a_retval = PATH_MAX;
1380 case _PC_CHOWN_RESTRICTED:
1389 #if defined(AFS_DARWIN70_ENV)
1390 case _PC_NAME_CHARS_MAX:
1391 *ap->a_retval = NAME_MAX;
1393 case _PC_CASE_SENSITIVE:
1396 case _PC_CASE_PRESERVING:
1399 #endif /* defined(AFS_DARWIN70_ENV) */
1407 * Advisory record locking support (fcntl() POSIX style)
1411 struct vop_advlock_args /* {
1412 * struct vnode *a_vp;
1415 * struct flock *a_fl;
1420 struct proc *p = current_proc();
1423 cr = *p->p_cred->pc_ucred;
1427 afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
1433 afs_vop_truncate(ap)
1434 struct vop_truncate_args /* {
1435 * struct vnode *a_vp;
1438 * struct ucred *a_cred;
1442 printf("stray afs_vop_truncate\n");
1448 struct vop_update_args /* {
1449 * struct vnode *a_vp;
1450 * struct timeval *a_access;
1451 * struct timeval *a_modify;
1455 printf("stray afs_vop_update\n");
1460 afs_vop_blktooff(ap)
1461 struct vop_blktooff_args /* {
1462 * struct vnode *a_vp;
1467 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1472 afs_vop_offtoblk(ap)
1473 struct vop_offtoblk_args /* {
1474 * struct vnode *a_vp;
1476 * daddr_t *a_lblkno;
1479 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1486 struct vop_cmap_args /* {
1487 * struct vnode *a_vp;
1495 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
1496 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
1501 afs_darwin_getnewvnode(struct vcache *tvc)
1503 while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
1504 /* no vnodes available, force an alloc (limits be damned)! */
1505 printf("failed to get vnode\n");
1507 tvc->v->v_data = (void *)tvc;