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 if (UBCINFOMISSING(vp) ||
192 UBCINFORECLAIMED(vp)) {
193 #ifdef AFS_DARWIN14_ENV
194 if (UBCINFORECLAIMED(vp) && ISSET(vp->v_flag, (VXLOCK|VORECLAIM))) {
201 /* The parent directory comes in locked. We unlock it on return
202 * unless the caller wants it left locked.
203 * we also always return the vnode locked. */
205 if (flags & ISDOTDOT) {
206 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
207 /* always return the child locked */
208 if (lockparent && (flags & ISLASTCN)
209 && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
214 } else if (vp == dvp) {
215 /* they're the same; afs_lookup() already ref'ed the leaf.
216 * It came in locked, so we don't need to ref OR lock it */
218 if (!lockparent || !(flags & ISLASTCN))
219 VOP_UNLOCK(dvp, 0, p); /* done with parent. */
220 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
221 /* always return the child locked */
225 if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
226 || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
227 cnp->cn_flags |= SAVENAME;
235 struct vop_create_args /* {
236 * struct vnode *a_dvp;
237 * struct vnode **a_vpp;
238 * struct componentname *a_cnp;
239 * struct vattr *a_vap;
244 register struct vnode *dvp = ap->a_dvp;
249 /* vnode layer handles excl/nonexcl */
252 afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
256 VOP_ABORTOP(dvp, cnp);
263 *ap->a_vpp = AFSTOV(vcp);
264 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
265 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
266 if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
267 #ifdef AFS_DARWIN14_ENV
268 if (UBCINFORECLAIMED(*ap->a_vpp) && ISSET((*ap->a_vpp)->v_flag,
269 (VXLOCK|VORECLAIM))) {
275 ubc_info_init(*ap->a_vpp);
280 if ((cnp->cn_flags & SAVESTART) == 0)
281 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
289 struct vop_mknod_args /* {
290 * struct vnode *a_dvp;
291 * struct vnode **a_vpp;
292 * struct componentname *a_cnp;
293 * struct vattr *a_vap;
296 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
303 struct vop_open_args /* {
304 * struct vnode *a_vp;
306 * struct ucred *a_cred;
311 struct vnode *vp = ap->a_vp;
312 struct vcache *vc = VTOAFS(vp);
313 #ifdef AFS_DARWIN14_ENV
315 /*----------------------------------------------------------------
316 * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
317 * can later be passed to vn_open(), which will skip the call to
318 * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
319 * will be off. So we compensate by calling ubc_hold() ourselves
320 * when ui_refcount is less than 2. If an error occurs in afs_open()
321 * we must call ubc_rele(), which is what vn_open() would do if it
322 * was able to call ubc_hold() in the first place.
323 *----------------------------------------------------------------*/
324 if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
325 && vp->v_ubcinfo->ui_refcount < 2)
326 didhold = ubc_hold(vp);
327 #endif /* AFS_DARWIN14_ENV */
329 error = afs_open(&vc, ap->a_mode, ap->a_cred);
331 if (AFSTOV(vc) != vp)
332 panic("AFS open changed vnode!");
334 afs_BozonLock(&vc->pvnLock, vc);
335 osi_FlushPages(vc, ap->a_cred);
336 afs_BozonUnlock(&vc->pvnLock, vc);
338 #ifdef AFS_DARWIN14_ENV
339 if (error && didhold)
341 #endif /* AFS_DARWIN14_ENV */
347 struct vop_close_args /* {
348 * struct vnode *a_vp;
350 * struct ucred *a_cred;
355 struct vcache *avc = ap->a_vp;
358 code = afs_close(avc, ap->a_fflag, ap->a_cred, ap->a_p);
360 code = afs_close(avc, ap->a_fflag, &afs_osi_cred, ap->a_p);
361 afs_BozonLock(&avc->pvnLock, avc);
362 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
363 afs_BozonUnlock(&avc->pvnLock, avc);
365 #ifdef AFS_DARWIN14_ENV
366 if (UBCINFOEXISTS(ap->a_vp) && ap->a_vp->v_ubcinfo->ui_refcount < 2) {
368 if (ap->a_vp->v_ubcinfo->ui_refcount < 2) {
369 printf("afs: Imminent ui_refcount panic\n");
371 printf("afs: WARNING: ui_refcount panic averted\n");
381 struct vop_access_args /* {
382 * struct vnode *a_vp;
384 * struct ucred *a_cred;
390 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
397 struct vop_getattr_args /* {
398 * struct vnode *a_vp;
399 * struct vattr *a_vap;
400 * struct ucred *a_cred;
406 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
413 struct vop_setattr_args /* {
414 * struct vnode *a_vp;
415 * struct vattr *a_vap;
416 * struct ucred *a_cred;
422 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
429 struct vop_read_args /* {
430 * struct vnode *a_vp;
433 * struct ucred *a_cred;
437 struct vcache *avc = VTOAFS(ap->a_vp);
439 afs_BozonLock(&avc->pvnLock, avc);
440 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
441 code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
442 afs_BozonUnlock(&avc->pvnLock, avc);
449 struct vop_pagein_args /* {
450 * struct vnode *a_vp;
452 * vm_offset_t a_pl_offset;
455 * struct ucred *a_cred;
459 register struct vnode *vp = ap->a_vp;
461 size_t size = ap->a_size;
462 off_t f_offset = ap->a_f_offset;
463 vm_offset_t pl_offset = ap->a_pl_offset;
464 int flags = ap->a_flags;
469 struct uio *uio = &auio;
470 int nocommit = flags & UPL_NOCOMMIT;
473 struct vcache *tvc = VTOAFS(vp);
475 if (UBCINVALID(vp)) {
477 panic("afs_vop_pagein: invalid vp");
478 #endif /* DIAGNOSTIC */
482 UBCINFOCHECK("afs_vop_pagein", vp);
483 if (pl == (upl_t) NULL) {
484 panic("afs_vop_pagein: no upl");
487 cred = ubc_getcred(vp);
493 kernel_upl_abort_range(pl, pl_offset, size,
494 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
499 kernel_upl_abort_range(pl, pl_offset, size,
500 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
503 if (f_offset & PAGE_MASK)
504 panic("afs_vop_pagein: offset not page aligned");
506 auio.uio_iov = &aiov;
508 auio.uio_offset = f_offset;
509 auio.uio_segflg = UIO_SYSSPACE;
510 auio.uio_rw = UIO_READ;
511 auio.uio_procp = NULL;
512 kernel_upl_map(kernel_map, pl, &ioaddr);
514 auio.uio_resid = aiov.iov_len = size;
515 aiov.iov_base = (caddr_t) ioaddr;
517 afs_BozonLock(&tvc->pvnLock, tvc);
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);
525 afs_BozonUnlock(&tvc->pvnLock, tvc);
528 /* Zero out rest of last page if there wasn't enough data in the file */
529 if (code == 0 && auio.uio_resid > 0)
530 memset(aiov.iov_base, 0, auio.uio_resid);
532 kernel_upl_unmap(kernel_map, pl);
535 kernel_upl_abort_range(pl, pl_offset, size,
536 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
538 kernel_upl_commit_range(pl, pl_offset, size,
539 UPL_COMMIT_CLEAR_DIRTY |
540 UPL_COMMIT_FREE_ON_EMPTY,
541 UPL_GET_INTERNAL_PAGE_LIST(pl),
549 struct vop_write_args /* {
550 * struct vnode *a_vp;
553 * struct ucred *a_cred;
557 struct vcache *avc = VTOAFS(ap->a_vp);
560 afs_BozonLock(&avc->pvnLock, avc);
561 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
562 if (UBCINFOEXISTS(ap->a_vp))
563 ubc_clean(ap->a_vp, 1);
564 if (UBCINFOEXISTS(ap->a_vp))
565 osi_VM_NukePages(ap->a_vp, ap->a_uio->uio_offset,
566 ap->a_uio->uio_resid);
568 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
569 afs_BozonUnlock(&avc->pvnLock, avc);
576 struct vop_pageout_args /* {
577 * struct vnode *a_vp;
579 * vm_offset_t a_pl_offset,
582 * struct ucred *a_cred,
586 register struct vnode *vp = ap->a_vp;
588 size_t size = ap->a_size;
589 off_t f_offset = ap->a_f_offset;
590 vm_offset_t pl_offset = ap->a_pl_offset;
591 int flags = ap->a_flags;
596 struct uio *uio = &auio;
597 int nocommit = flags & UPL_NOCOMMIT;
601 struct vcache *tvc = VTOAFS(vp);
603 if (UBCINVALID(vp)) {
605 panic("afs_vop_pageout: invalid vp");
606 #endif /* DIAGNOSTIC */
610 UBCINFOCHECK("afs_vop_pageout", vp);
611 if (pl == (upl_t) NULL) {
612 panic("afs_vop_pageout: no upl");
618 int biosize = DEV_BSIZE;
620 lbn = f_offset / DEV_BSIZE;
622 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
625 if (bp = incore(vp, lbn)) {
626 if (ISSET(bp->b_flags, B_BUSY))
627 panic("nfs_pageout: found BUSY buffer incore\n");
630 SET(bp->b_flags, (B_BUSY | B_INVAL));
637 cred = ubc_getcred(vp);
643 kernel_upl_abort_range(pl, pl_offset, size,
644 UPL_ABORT_FREE_ON_EMPTY);
647 if (flags & (IO_APPEND | IO_SYNC))
648 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
651 kernel_upl_abort_range(pl, pl_offset, size,
652 UPL_ABORT_FREE_ON_EMPTY);
655 if (f_offset >= tvc->m.Length) {
657 kernel_upl_abort_range(pl, pl_offset, size,
658 UPL_ABORT_FREE_ON_EMPTY);
662 if (f_offset & PAGE_MASK)
663 panic("afs_vop_pageout: offset not page aligned");
665 /* size will always be a multiple of PAGE_SIZE */
666 /* pageout isn't supposed to extend files */
667 if (f_offset + size > tvc->m.Length)
668 iosize = tvc->m.Length - f_offset;
672 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
673 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
674 kernel_upl_abort_range(pl, pl_offset + iosize_rnd,
676 UPL_ABORT_FREE_ON_EMPTY);
678 auio.uio_iov = &aiov;
680 auio.uio_offset = f_offset;
681 auio.uio_segflg = UIO_SYSSPACE;
682 auio.uio_rw = UIO_WRITE;
683 auio.uio_procp = NULL;
684 kernel_upl_map(kernel_map, pl, &ioaddr);
686 auio.uio_resid = aiov.iov_len = iosize;
687 aiov.iov_base = (caddr_t) ioaddr;
691 * check for partial page and clear the
692 * contents past end of the file before
693 * releasing it in the VM page cache
695 if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
696 size_t io = tvc->m.Length - f_offset;
698 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
704 afs_BozonLock(&tvc->pvnLock, tvc);
705 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
706 ObtainWriteLock(&tvc->lock, 1);
708 ReleaseWriteLock(&tvc->lock);
710 code = afs_write(tvc, uio, flags, cred, 0);
712 ObtainWriteLock(&tvc->lock, 1);
713 afs_FakeClose(tvc, cred);
714 ReleaseWriteLock(&tvc->lock);
715 afs_BozonUnlock(&tvc->pvnLock, tvc);
717 kernel_upl_unmap(kernel_map, pl);
720 kernel_upl_abort_range(pl, pl_offset, size,
721 UPL_ABORT_FREE_ON_EMPTY);
723 kernel_upl_commit_range(pl, pl_offset, size,
724 UPL_COMMIT_CLEAR_DIRTY |
725 UPL_COMMIT_FREE_ON_EMPTY,
726 UPL_GET_INTERNAL_PAGE_LIST(pl),
735 struct vop_ioctl_args /* {
736 * struct vnode *a_vp;
740 * struct ucred *a_cred;
744 struct vcache *tvc = VTOAFS(ap->a_vp);
745 struct afs_ioctl data;
748 /* in case we ever get in here... */
750 AFS_STATCNT(afs_ioctl);
751 if (((ap->a_command >> 8) & 0xff) == 'V') {
752 /* This is a VICEIOCTL call */
754 error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
755 ap->a_command, ap->a_data);
759 /* No-op call; just return. */
767 struct vop_select_args /* {
768 * struct vnode *a_vp;
771 * struct ucred *a_cred;
776 * We should really check to see if I/O is possible.
784 * NB Currently unsupported.
789 struct vop_mmap_args /* {
790 * struct vnode *a_vp;
792 * struct ucred *a_cred;
801 struct vop_fsync_args /* {
802 * struct vnode *a_vp;
803 * struct ucred *a_cred;
808 int wait = ap->a_waitfor == MNT_WAIT;
810 register struct vnode *vp = ap->a_vp;
813 /*vflushbuf(vp, wait); */
815 error = afs_fsync(VTOAFS(vp), ap->a_cred);
817 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
824 struct vop_seek_args /* {
825 * struct vnode *a_vp;
828 * struct ucred *a_cred;
831 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
838 struct vop_remove_args /* {
839 * struct vnode *a_dvp;
840 * struct vnode *a_vp;
841 * struct componentname *a_cnp;
845 register struct vnode *vp = ap->a_vp;
846 register struct vnode *dvp = ap->a_dvp;
850 error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
853 if (!error && UBCINFOEXISTS(vp)) {
854 #ifdef AFS_DARWIN14_ENV
855 (void)ubc_uncache(vp);
857 int wasmapped = ubc_issetflags(vp, UI_WASMAPPED);
858 int hasobjref = ubc_issetflags(vp, UI_HASOBJREF);
860 (void)ubc_uncache(vp);
863 /* WARNING vp may not be valid after this */
872 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
879 struct vop_link_args /* {
880 * struct vnode *a_vp;
881 * struct vnode *a_tdvp;
882 * struct componentname *a_cnp;
886 register struct vnode *dvp = ap->a_tdvp;
887 register struct vnode *vp = ap->a_vp;
892 if (vp->v_type == VDIR) {
893 VOP_ABORTOP(vp, cnp);
897 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
898 VOP_ABORTOP(dvp, cnp);
902 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
904 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
906 VOP_UNLOCK(vp, 0, p);
915 struct vop_rename_args /* {
916 * struct vnode *a_fdvp;
917 * struct vnode *a_fvp;
918 * struct componentname *a_fcnp;
919 * struct vnode *a_tdvp;
920 * struct vnode *a_tvp;
921 * struct componentname *a_tcnp;
925 struct componentname *fcnp = ap->a_fcnp;
927 struct componentname *tcnp = ap->a_tcnp;
929 struct vnode *tvp = ap->a_tvp;
930 register struct vnode *tdvp = ap->a_tdvp;
931 struct vnode *fvp = ap->a_fvp;
932 register struct vnode *fdvp = ap->a_fdvp;
933 struct proc *p = fcnp->cn_proc;
935 /* Check for cross-device rename.
936 * For AFS, this means anything not in AFS-space
938 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
939 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
945 * if fvp == tvp, we're just removing one name of a pair of
946 * directory entries for the same element. convert call into rename.
947 ( (pinched from NetBSD 1.0's ufs_rename())
950 if (fvp->v_type == VDIR) {
953 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
960 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
966 /* Release destination completely. */
967 VOP_ABORTOP(tdvp, tcnp);
974 fcnp->cn_flags &= ~MODMASK;
975 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
976 if ((fcnp->cn_flags & SAVESTART) == 0)
977 panic("afs_rename: lost from startdir");
978 fcnp->cn_nameiop = DELETE;
981 error=relookup(fdvp, &fvp, fcnp);
988 error=VOP_REMOVE(fdvp, fvp, fcnp);
996 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
999 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1000 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1001 fname[fcnp->cn_namelen] = '\0';
1002 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1003 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1004 tname[tcnp->cn_namelen] = '\0';
1008 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1010 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
1013 VOP_UNLOCK(fvp, 0, p);
1014 FREE(fname, M_TEMP);
1015 FREE(tname, M_TEMP);
1017 goto abortit; /* XXX */
1031 struct vop_mkdir_args /* {
1032 * struct vnode *a_dvp;
1033 * struct vnode **a_vpp;
1034 * struct componentname *a_cnp;
1035 * struct vattr *a_vap;
1038 register struct vnode *dvp = ap->a_dvp;
1039 register struct vattr *vap = ap->a_vap;
1047 if ((cnp->cn_flags & HASBUF) == 0)
1048 panic("afs_vop_mkdir: no name");
1051 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1054 VOP_ABORTOP(dvp, cnp);
1060 *ap->a_vpp = AFSTOV(vcp);
1061 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1062 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1066 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1073 struct vop_rmdir_args /* {
1074 * struct vnode *a_dvp;
1075 * struct vnode *a_vp;
1076 * struct componentname *a_cnp;
1080 register struct vnode *vp = ap->a_vp;
1081 register struct vnode *dvp = ap->a_dvp;
1087 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1093 error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1103 struct vop_symlink_args /* {
1104 * struct vnode *a_dvp;
1105 * struct vnode **a_vpp;
1106 * struct componentname *a_cnp;
1107 * struct vattr *a_vap;
1111 register struct vnode *dvp = ap->a_dvp;
1113 /* NFS ignores a_vpp; so do we. */
1118 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
1121 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1128 struct vop_readdir_args /* {
1129 * struct vnode *a_vp;
1130 * struct uio *a_uio;
1131 * struct ucred *a_cred;
1133 * u_long *a_cookies;
1139 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1141 off = ap->a_uio->uio_offset;
1144 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1146 if (!error && ap->a_ncookies != NULL) {
1147 struct uio *uio = ap->a_uio;
1148 const struct dirent *dp, *dp_start, *dp_end;
1150 u_long *cookies, *cookiep;
1152 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1153 panic("afs_readdir: burned cookies");
1154 dp = (const struct dirent *)
1155 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1157 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1158 for (dp_start = dp, ncookies = 0; dp < dp_end;
1159 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1162 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1164 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1165 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1166 off += dp->d_reclen;
1169 *ap->a_cookies = cookies;
1170 *ap->a_ncookies = ncookies;
1177 afs_vop_readlink(ap)
1178 struct vop_readlink_args /* {
1179 * struct vnode *a_vp;
1180 * struct uio *a_uio;
1181 * struct ucred *a_cred;
1185 /* printf("readlink %x\n", ap->a_vp);*/
1187 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1192 extern int prtactive;
1195 afs_vop_inactive(ap)
1196 struct vop_inactive_args /* {
1197 * struct vnode *a_vp;
1201 register struct vnode *vp = ap->a_vp;
1203 if (prtactive && vp->v_usecount != 0)
1204 vprint("afs_vop_inactive(): pushing active", vp);
1207 afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
1209 VOP_UNLOCK(vp, 0, ap->a_p);
1215 struct vop_reclaim_args /* {
1216 * struct vnode *a_vp;
1221 register struct vnode *vp = ap->a_vp;
1223 cache_purge(vp); /* just in case... */
1227 error = afs_FlushVCache(VTOAFS(vp), &sl); /* tosses our stuff from vnode */
1230 if (!error && vp->v_data)
1231 panic("afs_reclaim: vnode not cleaned");
1234 if (vp->v_usecount == 2) {
1235 vprint("reclaim count==2", vp);
1236 } else if (vp->v_usecount == 1) {
1237 vprint("reclaim count==1", vp);
1239 vprint("reclaim bad count", vp);
1247 struct vop_lock_args /* {
1248 * struct vnode *a_vp;
1251 register struct vnode *vp = ap->a_vp;
1252 register struct vcache *avc = VTOAFS(vp);
1254 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);
1268 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1275 struct vop_bmap_args /* {
1276 * struct vnode *a_vp;
1278 * 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));