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!");
348 osi_FlushPages(vc, ap->a_cred);
350 #ifdef AFS_DARWIN14_ENV
351 if (error && didhold)
353 #endif /* AFS_DARWIN14_ENV */
359 struct vop_close_args /* {
360 * struct vnode *a_vp;
362 * struct ucred *a_cred;
367 struct vnode *vp = ap->a_vp;
368 struct vcache *avc = VTOAFS(vp);
371 code = afs_close(avc, ap->a_fflag, ap->a_cred, ap->a_p);
373 code = afs_close(avc, ap->a_fflag, &afs_osi_cred, ap->a_p);
374 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
382 struct vop_access_args /* {
383 * struct vnode *a_vp;
385 * struct ucred *a_cred;
391 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
398 struct vop_getattr_args /* {
399 * struct vnode *a_vp;
400 * struct vattr *a_vap;
401 * struct ucred *a_cred;
408 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
415 struct vop_setattr_args /* {
416 * struct vnode *a_vp;
417 * struct vattr *a_vap;
418 * struct ucred *a_cred;
424 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
431 struct vop_read_args /* {
432 * struct vnode *a_vp;
435 * struct ucred *a_cred;
439 struct vnode *vp = ap->a_vp;
440 struct vcache *avc = VTOAFS(vp);
442 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
443 code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
450 struct vop_pagein_args /* {
451 * struct vnode *a_vp;
453 * vm_offset_t a_pl_offset;
456 * struct ucred *a_cred;
460 register struct vnode *vp = ap->a_vp;
462 size_t size = ap->a_size;
463 off_t f_offset = ap->a_f_offset;
464 vm_offset_t pl_offset = ap->a_pl_offset;
465 int flags = ap->a_flags;
470 struct uio *uio = &auio;
471 int nocommit = flags & UPL_NOCOMMIT;
474 struct vcache *tvc = VTOAFS(vp);
476 if (UBCINVALID(vp)) {
478 panic("afs_vop_pagein: invalid vp");
479 #endif /* DIAGNOSTIC */
483 UBCINFOCHECK("afs_vop_pagein", vp);
484 if (pl == (upl_t) NULL) {
485 panic("afs_vop_pagein: no upl");
488 cred = ubc_getcred(vp);
494 kernel_upl_abort_range(pl, pl_offset, size,
495 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
500 kernel_upl_abort_range(pl, pl_offset, size,
501 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
504 if (f_offset & PAGE_MASK)
505 panic("afs_vop_pagein: offset not page aligned");
507 auio.uio_iov = &aiov;
509 auio.uio_offset = f_offset;
510 auio.uio_segflg = UIO_SYSSPACE;
511 auio.uio_rw = UIO_READ;
512 auio.uio_procp = NULL;
513 kernel_upl_map(kernel_map, pl, &ioaddr);
515 auio.uio_resid = aiov.iov_len = size;
516 aiov.iov_base = (caddr_t) ioaddr;
518 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
519 code = afs_read(tvc, uio, cred, 0, 0, 0);
521 ObtainWriteLock(&tvc->lock, 2);
522 tvc->states |= CMAPPED;
523 ReleaseWriteLock(&tvc->lock);
527 /* Zero out rest of last page if there wasn't enough data in the file */
528 if (code == 0 && auio.uio_resid > 0)
529 memset(aiov.iov_base, 0, auio.uio_resid);
531 kernel_upl_unmap(kernel_map, pl);
534 kernel_upl_abort_range(pl, pl_offset, size,
535 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
537 kernel_upl_commit_range(pl, pl_offset, size,
538 UPL_COMMIT_CLEAR_DIRTY |
539 UPL_COMMIT_FREE_ON_EMPTY,
540 UPL_GET_INTERNAL_PAGE_LIST(pl),
548 struct vop_write_args /* {
549 * struct vnode *a_vp;
552 * struct ucred *a_cred;
556 struct vcache *avc = VTOAFS(ap->a_vp);
559 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
560 if (UBCINFOEXISTS(ap->a_vp)) {
561 ubc_clean(ap->a_vp, 1);
563 if (UBCINFOEXISTS(ap->a_vp))
564 osi_VM_NukePages(ap->a_vp, ap->a_uio->uio_offset,
565 ap->a_uio->uio_resid);
567 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
574 struct vop_pageout_args /* {
575 * struct vnode *a_vp;
577 * vm_offset_t a_pl_offset,
580 * struct ucred *a_cred,
584 register struct vnode *vp = ap->a_vp;
586 size_t size = ap->a_size;
587 off_t f_offset = ap->a_f_offset;
588 vm_offset_t pl_offset = ap->a_pl_offset;
589 int flags = ap->a_flags;
594 struct uio *uio = &auio;
595 int nocommit = flags & UPL_NOCOMMIT;
599 struct vcache *tvc = VTOAFS(vp);
601 if (UBCINVALID(vp)) {
603 panic("afs_vop_pageout: invalid vp");
604 #endif /* DIAGNOSTIC */
608 UBCINFOCHECK("afs_vop_pageout", vp);
609 if (pl == (upl_t) NULL) {
610 panic("afs_vop_pageout: no upl");
616 int biosize = DEV_BSIZE;
618 lbn = f_offset / DEV_BSIZE;
620 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
623 if (bp = incore(vp, lbn)) {
624 if (ISSET(bp->b_flags, B_BUSY))
625 panic("nfs_pageout: found BUSY buffer incore\n");
628 SET(bp->b_flags, (B_BUSY | B_INVAL));
635 cred = ubc_getcred(vp);
641 kernel_upl_abort_range(pl, pl_offset, size,
642 UPL_ABORT_FREE_ON_EMPTY);
645 if (flags & (IO_APPEND | IO_SYNC))
646 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
649 kernel_upl_abort_range(pl, pl_offset, size,
650 UPL_ABORT_FREE_ON_EMPTY);
653 if (f_offset >= tvc->m.Length) {
655 kernel_upl_abort_range(pl, pl_offset, size,
656 UPL_ABORT_FREE_ON_EMPTY);
660 if (f_offset & PAGE_MASK)
661 panic("afs_vop_pageout: offset not page aligned");
663 /* size will always be a multiple of PAGE_SIZE */
664 /* pageout isn't supposed to extend files */
665 if (f_offset + size > tvc->m.Length)
666 iosize = tvc->m.Length - f_offset;
670 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
671 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
672 kernel_upl_abort_range(pl, pl_offset + iosize_rnd,
674 UPL_ABORT_FREE_ON_EMPTY);
676 auio.uio_iov = &aiov;
678 auio.uio_offset = f_offset;
679 auio.uio_segflg = UIO_SYSSPACE;
680 auio.uio_rw = UIO_WRITE;
681 auio.uio_procp = NULL;
682 kernel_upl_map(kernel_map, pl, &ioaddr);
684 auio.uio_resid = aiov.iov_len = iosize;
685 aiov.iov_base = (caddr_t) ioaddr;
689 * check for partial page and clear the
690 * contents past end of the file before
691 * releasing it in the VM page cache
693 if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
694 size_t io = tvc->m.Length - f_offset;
696 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
702 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
703 ObtainWriteLock(&tvc->lock, 1);
705 ReleaseWriteLock(&tvc->lock);
707 code = afs_write(tvc, uio, flags, cred, 0);
709 ObtainWriteLock(&tvc->lock, 1);
710 afs_FakeClose(tvc, cred);
711 ReleaseWriteLock(&tvc->lock);
713 kernel_upl_unmap(kernel_map, pl);
716 kernel_upl_abort_range(pl, pl_offset, size,
717 UPL_ABORT_FREE_ON_EMPTY);
719 kernel_upl_commit_range(pl, pl_offset, size,
720 UPL_COMMIT_CLEAR_DIRTY |
721 UPL_COMMIT_FREE_ON_EMPTY,
722 UPL_GET_INTERNAL_PAGE_LIST(pl),
731 struct vop_ioctl_args /* {
732 * struct vnode *a_vp;
736 * struct ucred *a_cred;
740 struct vcache *tvc = VTOAFS(ap->a_vp);
741 struct afs_ioctl data;
744 /* in case we ever get in here... */
746 AFS_STATCNT(afs_ioctl);
747 if (((ap->a_command >> 8) & 0xff) == 'V') {
748 /* This is a VICEIOCTL call */
750 error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
751 ap->a_command, ap->a_data);
755 /* No-op call; just return. */
763 struct vop_select_args /* {
764 * struct vnode *a_vp;
767 * struct ucred *a_cred;
772 * We should really check to see if I/O is possible.
780 * NB Currently unsupported.
785 struct vop_mmap_args /* {
786 * struct vnode *a_vp;
788 * struct ucred *a_cred;
797 struct vop_fsync_args /* {
798 * struct vnode *a_vp;
799 * struct ucred *a_cred;
804 int wait = ap->a_waitfor == MNT_WAIT;
806 register struct vnode *vp = ap->a_vp;
807 int haveGlock = ISAFS_GLOCK();
809 /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
810 if (!haveGlock) AFS_GLOCK();
812 error = afs_fsync(VTOAFS(vp), ap->a_cred);
814 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
815 if (!haveGlock) AFS_GUNLOCK();
821 struct vop_seek_args /* {
822 * struct vnode *a_vp;
825 * struct ucred *a_cred;
828 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
835 struct vop_remove_args /* {
836 * struct vnode *a_dvp;
837 * struct vnode *a_vp;
838 * struct componentname *a_cnp;
842 register struct vnode *vp = ap->a_vp;
843 register struct vnode *dvp = ap->a_dvp;
847 error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
852 /* necessary so we don't deadlock ourselves in vclean */
853 VOP_UNLOCK(vp, 0, cnp->cn_proc);
855 /* If crashes continue in ubc_hold, comment this out */
856 (void)ubc_uncache(vp);
864 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
871 struct vop_link_args /* {
872 * struct vnode *a_vp;
873 * struct vnode *a_tdvp;
874 * struct componentname *a_cnp;
878 register struct vnode *dvp = ap->a_tdvp;
879 register struct vnode *vp = ap->a_vp;
884 if (vp->v_type == VDIR) {
885 VOP_ABORTOP(vp, cnp);
889 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
890 VOP_ABORTOP(dvp, cnp);
894 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
896 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
898 VOP_UNLOCK(vp, 0, p);
907 struct vop_rename_args /* {
908 * struct vnode *a_fdvp;
909 * struct vnode *a_fvp;
910 * struct componentname *a_fcnp;
911 * struct vnode *a_tdvp;
912 * struct vnode *a_tvp;
913 * struct componentname *a_tcnp;
917 struct componentname *fcnp = ap->a_fcnp;
919 struct componentname *tcnp = ap->a_tcnp;
921 struct vnode *tvp = ap->a_tvp;
922 register struct vnode *tdvp = ap->a_tdvp;
923 struct vnode *fvp = ap->a_fvp;
924 register struct vnode *fdvp = ap->a_fdvp;
925 struct proc *p = fcnp->cn_proc;
927 /* Check for cross-device rename.
928 * For AFS, this means anything not in AFS-space
930 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
931 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
937 * if fvp == tvp, we're just removing one name of a pair of
938 * directory entries for the same element. convert call into rename.
939 ( (pinched from NetBSD 1.0's ufs_rename())
942 if (fvp->v_type == VDIR) {
945 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
952 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
958 /* Release destination completely. */
959 VOP_ABORTOP(tdvp, tcnp);
966 fcnp->cn_flags &= ~MODMASK;
967 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
968 if ((fcnp->cn_flags & SAVESTART) == 0)
969 panic("afs_rename: lost from startdir");
970 fcnp->cn_nameiop = DELETE;
973 error=relookup(fdvp, &fvp, fcnp);
980 error=VOP_REMOVE(fdvp, fvp, fcnp);
988 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
991 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
992 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
993 fname[fcnp->cn_namelen] = '\0';
994 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
995 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
996 tname[tcnp->cn_namelen] = '\0';
1000 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1002 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
1005 VOP_UNLOCK(fvp, 0, p);
1006 FREE(fname, M_TEMP);
1007 FREE(tname, M_TEMP);
1009 goto abortit; /* XXX */
1023 struct vop_mkdir_args /* {
1024 * struct vnode *a_dvp;
1025 * struct vnode **a_vpp;
1026 * struct componentname *a_cnp;
1027 * struct vattr *a_vap;
1030 register struct vnode *dvp = ap->a_dvp;
1031 register struct vattr *vap = ap->a_vap;
1039 if ((cnp->cn_flags & HASBUF) == 0)
1040 panic("afs_vop_mkdir: no name");
1043 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1046 VOP_ABORTOP(dvp, cnp);
1052 *ap->a_vpp = AFSTOV(vcp);
1053 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1054 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1058 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1065 struct vop_rmdir_args /* {
1066 * struct vnode *a_dvp;
1067 * struct vnode *a_vp;
1068 * struct componentname *a_cnp;
1072 register struct vnode *vp = ap->a_vp;
1073 register struct vnode *dvp = ap->a_dvp;
1079 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1085 error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1095 struct vop_symlink_args /* {
1096 * struct vnode *a_dvp;
1097 * struct vnode **a_vpp;
1098 * struct componentname *a_cnp;
1099 * struct vattr *a_vap;
1103 register struct vnode *dvp = ap->a_dvp;
1105 /* NFS ignores a_vpp; so do we. */
1110 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
1113 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1120 struct vop_readdir_args /* {
1121 * struct vnode *a_vp;
1122 * struct uio *a_uio;
1123 * struct ucred *a_cred;
1125 * u_long *a_cookies;
1131 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1133 off = ap->a_uio->uio_offset;
1136 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1138 if (!error && ap->a_ncookies != NULL) {
1139 struct uio *uio = ap->a_uio;
1140 const struct dirent *dp, *dp_start, *dp_end;
1142 u_long *cookies, *cookiep;
1144 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1145 panic("afs_readdir: burned cookies");
1146 dp = (const struct dirent *)
1147 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1149 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1150 for (dp_start = dp, ncookies = 0; dp < dp_end;
1151 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1154 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1156 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1157 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1158 off += dp->d_reclen;
1161 *ap->a_cookies = cookies;
1162 *ap->a_ncookies = ncookies;
1169 afs_vop_readlink(ap)
1170 struct vop_readlink_args /* {
1171 * struct vnode *a_vp;
1172 * struct uio *a_uio;
1173 * struct ucred *a_cred;
1177 /* printf("readlink %x\n", ap->a_vp);*/
1179 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1184 extern int prtactive;
1187 afs_vop_inactive(ap)
1188 struct vop_inactive_args /* {
1189 * struct vnode *a_vp;
1193 register struct vnode *vp = ap->a_vp;
1195 if (prtactive && vp->v_usecount != 0)
1196 vprint("afs_vop_inactive(): pushing active", vp);
1199 afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
1201 VOP_UNLOCK(vp, 0, ap->a_p);
1207 struct vop_reclaim_args /* {
1208 * struct vnode *a_vp;
1213 register struct vnode *vp = ap->a_vp;
1214 int haveGlock = ISAFS_GLOCK();
1215 struct vcache *tvc = VTOAFS(vp);
1217 cache_purge(vp); /* just in case... */
1220 error = afs_FlushVCache(VTOAFS(vp), &sl); /* toss our stuff from vnode */
1224 if (!error && vp->v_data)
1225 panic("afs_reclaim: vnode not cleaned");
1226 if (!error && (tvc->v != NULL))
1227 panic("afs_reclaim: vcache not cleaned");
1234 struct vop_lock_args /* {
1235 * struct vnode *a_vp;
1238 register struct vnode *vp = ap->a_vp;
1239 register struct vcache *avc = VTOAFS(vp);
1241 if (vp->v_tag == VT_NON)
1244 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1249 struct vop_unlock_args /* {
1250 * struct vnode *a_vp;
1253 struct vnode *vp = ap->a_vp;
1254 struct vcache *avc = VTOAFS(vp);
1257 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1264 struct vop_bmap_args /* {
1265 * struct vnode *a_vp;
1267 * struct vnode **a_vpp;
1275 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1278 *ap->a_vpp = ap->a_vp;
1280 if (ap->a_runp != NULL)
1283 if (ap->a_runb != NULL)
1291 afs_vop_strategy(ap)
1292 struct vop_strategy_args /* {
1298 error = afs_ustrategy(ap->a_bp);
1305 struct vop_print_args /* {
1306 * struct vnode *a_vp;
1309 register struct vnode *vp = ap->a_vp;
1310 register struct vcache *vc = VTOAFS(ap->a_vp);
1312 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1313 vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1314 vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1315 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1316 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1317 (s & CMAPPED) ? " mapped" : "",
1318 (s & CVFlushed) ? " flush in progress" : "");
1319 if (UBCISVALID(vp)) {
1321 if (UBCINFOEXISTS(vp)) {
1323 #ifdef AFS_DARWIN14_ENV
1324 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1325 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1326 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1328 printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1331 printf("does not exist");
1338 afs_vop_islocked(ap)
1339 struct vop_islocked_args /* {
1340 * struct vnode *a_vp;
1343 struct vcache *vc = VTOAFS(ap->a_vp);
1344 return lockstatus(&vc->rwlock);
1348 * Return POSIX pathconf information applicable to ufs filesystems.
1350 afs_vop_pathconf(ap)
1351 struct vop_pathconf_args /* {
1352 * struct vnode *a_vp;
1357 AFS_STATCNT(afs_cntl);
1358 switch (ap->a_name) {
1360 *ap->a_retval = LINK_MAX;
1363 *ap->a_retval = NAME_MAX;
1366 *ap->a_retval = PATH_MAX;
1368 case _PC_CHOWN_RESTRICTED:
1377 #if defined(AFS_DARWIN70_ENV)
1378 case _PC_NAME_CHARS_MAX:
1379 *ap->a_retval = NAME_MAX;
1381 case _PC_CASE_SENSITIVE:
1384 case _PC_CASE_PRESERVING:
1387 #endif /* defined(AFS_DARWIN70_ENV) */
1395 * Advisory record locking support (fcntl() POSIX style)
1399 struct vop_advlock_args /* {
1400 * struct vnode *a_vp;
1403 * struct flock *a_fl;
1408 struct proc *p = current_proc();
1411 cr = *p->p_cred->pc_ucred;
1415 afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
1421 afs_vop_truncate(ap)
1422 struct vop_truncate_args /* {
1423 * struct vnode *a_vp;
1426 * struct ucred *a_cred;
1430 printf("stray afs_vop_truncate\n");
1436 struct vop_update_args /* {
1437 * struct vnode *a_vp;
1438 * struct timeval *a_access;
1439 * struct timeval *a_modify;
1443 printf("stray afs_vop_update\n");
1448 afs_vop_blktooff(ap)
1449 struct vop_blktooff_args /* {
1450 * struct vnode *a_vp;
1455 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1460 afs_vop_offtoblk(ap)
1461 struct vop_offtoblk_args /* {
1462 * struct vnode *a_vp;
1464 * daddr_t *a_lblkno;
1467 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1474 struct vop_cmap_args /* {
1475 * struct vnode *a_vp;
1483 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
1484 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
1489 afs_darwin_getnewvnode(struct vcache *tvc)
1491 while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &tvc->v)) {
1492 /* no vnodes available, force an alloc (limits be damned)! */
1493 printf("failed to get vnode\n");
1495 tvc->v->v_data = (void *)tvc;