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 vnode *vp = ap->a_vp;
356 struct vcache *avc = VTOAFS(vp);
359 code = afs_close(avc, ap->a_fflag, ap->a_cred, ap->a_p);
361 code = afs_close(avc, ap->a_fflag, &afs_osi_cred, ap->a_p);
362 afs_BozonLock(&avc->pvnLock, avc);
363 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
364 afs_BozonUnlock(&avc->pvnLock, avc);
366 #ifdef AFS_DARWIN14_ENV
367 if (UBCINFOEXISTS(ap->a_vp) && ap->a_vp->v_ubcinfo->ui_refcount < 2) {
369 if (ap->a_vp->v_ubcinfo->ui_refcount < 2) {
370 printf("afs: Imminent ui_refcount panic\n");
372 printf("afs: WARNING: ui_refcount panic averted\n");
375 if (UBCINFOMISSING(ap->a_vp) ||
376 UBCINFORECLAIMED(ap->a_vp)) {
377 if (UBCINFORECLAIMED(ap->a_vp) && ISSET(ap->a_vp->v_flag,
378 (VXLOCK|VORECLAIM))) {
379 printf("no ubc for %x in close, reclaim set\n", ap->a_vp);
382 printf("no ubc for %x in close, put back\n", ap->a_vp);
383 ubc_info_init(ap->a_vp);
393 struct vop_access_args /* {
394 * struct vnode *a_vp;
396 * struct ucred *a_cred;
402 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred);
409 struct vop_getattr_args /* {
410 * struct vnode *a_vp;
411 * struct vattr *a_vap;
412 * struct ucred *a_cred;
418 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
425 struct vop_setattr_args /* {
426 * struct vnode *a_vp;
427 * struct vattr *a_vap;
428 * struct ucred *a_cred;
434 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
441 struct vop_read_args /* {
442 * struct vnode *a_vp;
445 * struct ucred *a_cred;
449 struct vcache *avc = VTOAFS(ap->a_vp);
451 afs_BozonLock(&avc->pvnLock, avc);
452 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
453 code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
454 afs_BozonUnlock(&avc->pvnLock, avc);
461 struct vop_pagein_args /* {
462 * struct vnode *a_vp;
464 * vm_offset_t a_pl_offset;
467 * struct ucred *a_cred;
471 register struct vnode *vp = ap->a_vp;
473 size_t size = ap->a_size;
474 off_t f_offset = ap->a_f_offset;
475 vm_offset_t pl_offset = ap->a_pl_offset;
476 int flags = ap->a_flags;
481 struct uio *uio = &auio;
482 int nocommit = flags & UPL_NOCOMMIT;
485 struct vcache *tvc = VTOAFS(vp);
487 if (UBCINVALID(vp)) {
489 panic("afs_vop_pagein: invalid vp");
490 #endif /* DIAGNOSTIC */
494 UBCINFOCHECK("afs_vop_pagein", vp);
495 if (pl == (upl_t) NULL) {
496 panic("afs_vop_pagein: no upl");
499 cred = ubc_getcred(vp);
505 kernel_upl_abort_range(pl, pl_offset, size,
506 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
511 kernel_upl_abort_range(pl, pl_offset, size,
512 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
515 if (f_offset & PAGE_MASK)
516 panic("afs_vop_pagein: offset not page aligned");
518 auio.uio_iov = &aiov;
520 auio.uio_offset = f_offset;
521 auio.uio_segflg = UIO_SYSSPACE;
522 auio.uio_rw = UIO_READ;
523 auio.uio_procp = NULL;
524 kernel_upl_map(kernel_map, pl, &ioaddr);
526 auio.uio_resid = aiov.iov_len = size;
527 aiov.iov_base = (caddr_t) ioaddr;
529 afs_BozonLock(&tvc->pvnLock, tvc);
530 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
531 code = afs_read(tvc, uio, cred, 0, 0, 0);
533 ObtainWriteLock(&tvc->lock, 2);
534 tvc->states |= CMAPPED;
535 ReleaseWriteLock(&tvc->lock);
537 afs_BozonUnlock(&tvc->pvnLock, tvc);
540 /* Zero out rest of last page if there wasn't enough data in the file */
541 if (code == 0 && auio.uio_resid > 0)
542 memset(aiov.iov_base, 0, auio.uio_resid);
544 kernel_upl_unmap(kernel_map, pl);
547 kernel_upl_abort_range(pl, pl_offset, size,
548 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
550 kernel_upl_commit_range(pl, pl_offset, size,
551 UPL_COMMIT_CLEAR_DIRTY |
552 UPL_COMMIT_FREE_ON_EMPTY,
553 UPL_GET_INTERNAL_PAGE_LIST(pl),
561 struct vop_write_args /* {
562 * struct vnode *a_vp;
565 * struct ucred *a_cred;
569 struct vcache *avc = VTOAFS(ap->a_vp);
572 afs_BozonLock(&avc->pvnLock, avc);
573 osi_FlushPages(avc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
574 if (UBCINFOEXISTS(ap->a_vp))
575 ubc_clean(ap->a_vp, 1);
576 if (UBCINFOEXISTS(ap->a_vp))
577 osi_VM_NukePages(ap->a_vp, ap->a_uio->uio_offset,
578 ap->a_uio->uio_resid);
580 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
581 afs_BozonUnlock(&avc->pvnLock, avc);
588 struct vop_pageout_args /* {
589 * struct vnode *a_vp;
591 * vm_offset_t a_pl_offset,
594 * struct ucred *a_cred,
598 register struct vnode *vp = ap->a_vp;
600 size_t size = ap->a_size;
601 off_t f_offset = ap->a_f_offset;
602 vm_offset_t pl_offset = ap->a_pl_offset;
603 int flags = ap->a_flags;
608 struct uio *uio = &auio;
609 int nocommit = flags & UPL_NOCOMMIT;
613 struct vcache *tvc = VTOAFS(vp);
615 if (UBCINVALID(vp)) {
617 panic("afs_vop_pageout: invalid vp");
618 #endif /* DIAGNOSTIC */
622 UBCINFOCHECK("afs_vop_pageout", vp);
623 if (pl == (upl_t) NULL) {
624 panic("afs_vop_pageout: no upl");
630 int biosize = DEV_BSIZE;
632 lbn = f_offset / DEV_BSIZE;
634 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
637 if (bp = incore(vp, lbn)) {
638 if (ISSET(bp->b_flags, B_BUSY))
639 panic("nfs_pageout: found BUSY buffer incore\n");
642 SET(bp->b_flags, (B_BUSY | B_INVAL));
649 cred = ubc_getcred(vp);
655 kernel_upl_abort_range(pl, pl_offset, size,
656 UPL_ABORT_FREE_ON_EMPTY);
659 if (flags & (IO_APPEND | IO_SYNC))
660 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
663 kernel_upl_abort_range(pl, pl_offset, size,
664 UPL_ABORT_FREE_ON_EMPTY);
667 if (f_offset >= tvc->m.Length) {
669 kernel_upl_abort_range(pl, pl_offset, size,
670 UPL_ABORT_FREE_ON_EMPTY);
674 if (f_offset & PAGE_MASK)
675 panic("afs_vop_pageout: offset not page aligned");
677 /* size will always be a multiple of PAGE_SIZE */
678 /* pageout isn't supposed to extend files */
679 if (f_offset + size > tvc->m.Length)
680 iosize = tvc->m.Length - f_offset;
684 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
685 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
686 kernel_upl_abort_range(pl, pl_offset + iosize_rnd,
688 UPL_ABORT_FREE_ON_EMPTY);
690 auio.uio_iov = &aiov;
692 auio.uio_offset = f_offset;
693 auio.uio_segflg = UIO_SYSSPACE;
694 auio.uio_rw = UIO_WRITE;
695 auio.uio_procp = NULL;
696 kernel_upl_map(kernel_map, pl, &ioaddr);
698 auio.uio_resid = aiov.iov_len = iosize;
699 aiov.iov_base = (caddr_t) ioaddr;
703 * check for partial page and clear the
704 * contents past end of the file before
705 * releasing it in the VM page cache
707 if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
708 size_t io = tvc->m.Length - f_offset;
710 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
716 afs_BozonLock(&tvc->pvnLock, tvc);
717 osi_FlushPages(tvc, ap->a_cred); /* hold bozon lock, but not basic vnode lock */
718 ObtainWriteLock(&tvc->lock, 1);
720 ReleaseWriteLock(&tvc->lock);
722 code = afs_write(tvc, uio, flags, cred, 0);
724 ObtainWriteLock(&tvc->lock, 1);
725 afs_FakeClose(tvc, cred);
726 ReleaseWriteLock(&tvc->lock);
727 afs_BozonUnlock(&tvc->pvnLock, tvc);
729 kernel_upl_unmap(kernel_map, pl);
732 kernel_upl_abort_range(pl, pl_offset, size,
733 UPL_ABORT_FREE_ON_EMPTY);
735 kernel_upl_commit_range(pl, pl_offset, size,
736 UPL_COMMIT_CLEAR_DIRTY |
737 UPL_COMMIT_FREE_ON_EMPTY,
738 UPL_GET_INTERNAL_PAGE_LIST(pl),
747 struct vop_ioctl_args /* {
748 * struct vnode *a_vp;
752 * struct ucred *a_cred;
756 struct vcache *tvc = VTOAFS(ap->a_vp);
757 struct afs_ioctl data;
760 /* in case we ever get in here... */
762 AFS_STATCNT(afs_ioctl);
763 if (((ap->a_command >> 8) & 0xff) == 'V') {
764 /* This is a VICEIOCTL call */
766 error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
767 ap->a_command, ap->a_data);
771 /* No-op call; just return. */
779 struct vop_select_args /* {
780 * struct vnode *a_vp;
783 * struct ucred *a_cred;
788 * We should really check to see if I/O is possible.
796 * NB Currently unsupported.
801 struct vop_mmap_args /* {
802 * struct vnode *a_vp;
804 * struct ucred *a_cred;
813 struct vop_fsync_args /* {
814 * struct vnode *a_vp;
815 * struct ucred *a_cred;
820 int wait = ap->a_waitfor == MNT_WAIT;
822 register struct vnode *vp = ap->a_vp;
825 /*vflushbuf(vp, wait); */
827 error = afs_fsync(VTOAFS(vp), ap->a_cred);
829 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
836 struct vop_seek_args /* {
837 * struct vnode *a_vp;
840 * struct ucred *a_cred;
843 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
850 struct vop_remove_args /* {
851 * struct vnode *a_dvp;
852 * struct vnode *a_vp;
853 * struct componentname *a_cnp;
857 register struct vnode *vp = ap->a_vp;
858 register struct vnode *dvp = ap->a_dvp;
862 error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
865 if (!error && UBCINFOEXISTS(vp)) {
866 #ifdef AFS_DARWIN14_ENV
867 /* If crashes continue in ubc_hold, comment this out */
868 /* (void)ubc_uncache(vp);*/
870 int wasmapped = ubc_issetflags(vp, UI_WASMAPPED);
871 int hasobjref = ubc_issetflags(vp, UI_HASOBJREF);
873 (void)ubc_uncache(vp);
876 /* WARNING vp may not be valid after this */
885 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
892 struct vop_link_args /* {
893 * struct vnode *a_vp;
894 * struct vnode *a_tdvp;
895 * struct componentname *a_cnp;
899 register struct vnode *dvp = ap->a_tdvp;
900 register struct vnode *vp = ap->a_vp;
905 if (vp->v_type == VDIR) {
906 VOP_ABORTOP(vp, cnp);
910 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
911 VOP_ABORTOP(dvp, cnp);
915 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
917 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
919 VOP_UNLOCK(vp, 0, p);
928 struct vop_rename_args /* {
929 * struct vnode *a_fdvp;
930 * struct vnode *a_fvp;
931 * struct componentname *a_fcnp;
932 * struct vnode *a_tdvp;
933 * struct vnode *a_tvp;
934 * struct componentname *a_tcnp;
938 struct componentname *fcnp = ap->a_fcnp;
940 struct componentname *tcnp = ap->a_tcnp;
942 struct vnode *tvp = ap->a_tvp;
943 register struct vnode *tdvp = ap->a_tdvp;
944 struct vnode *fvp = ap->a_fvp;
945 register struct vnode *fdvp = ap->a_fdvp;
946 struct proc *p = fcnp->cn_proc;
948 /* Check for cross-device rename.
949 * For AFS, this means anything not in AFS-space
951 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
952 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
958 * if fvp == tvp, we're just removing one name of a pair of
959 * directory entries for the same element. convert call into rename.
960 ( (pinched from NetBSD 1.0's ufs_rename())
963 if (fvp->v_type == VDIR) {
966 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
973 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
979 /* Release destination completely. */
980 VOP_ABORTOP(tdvp, tcnp);
987 fcnp->cn_flags &= ~MODMASK;
988 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
989 if ((fcnp->cn_flags & SAVESTART) == 0)
990 panic("afs_rename: lost from startdir");
991 fcnp->cn_nameiop = DELETE;
994 error=relookup(fdvp, &fvp, fcnp);
1001 error=VOP_REMOVE(fdvp, fvp, fcnp);
1009 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1012 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1013 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1014 fname[fcnp->cn_namelen] = '\0';
1015 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1016 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1017 tname[tcnp->cn_namelen] = '\0';
1021 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1023 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
1026 VOP_UNLOCK(fvp, 0, p);
1027 FREE(fname, M_TEMP);
1028 FREE(tname, M_TEMP);
1030 goto abortit; /* XXX */
1044 struct vop_mkdir_args /* {
1045 * struct vnode *a_dvp;
1046 * struct vnode **a_vpp;
1047 * struct componentname *a_cnp;
1048 * struct vattr *a_vap;
1051 register struct vnode *dvp = ap->a_dvp;
1052 register struct vattr *vap = ap->a_vap;
1060 if ((cnp->cn_flags & HASBUF) == 0)
1061 panic("afs_vop_mkdir: no name");
1064 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1067 VOP_ABORTOP(dvp, cnp);
1073 *ap->a_vpp = AFSTOV(vcp);
1074 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1075 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1079 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1086 struct vop_rmdir_args /* {
1087 * struct vnode *a_dvp;
1088 * struct vnode *a_vp;
1089 * struct componentname *a_cnp;
1093 register struct vnode *vp = ap->a_vp;
1094 register struct vnode *dvp = ap->a_dvp;
1100 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1106 error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1116 struct vop_symlink_args /* {
1117 * struct vnode *a_dvp;
1118 * struct vnode **a_vpp;
1119 * struct componentname *a_cnp;
1120 * struct vattr *a_vap;
1124 register struct vnode *dvp = ap->a_dvp;
1126 /* NFS ignores a_vpp; so do we. */
1131 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
1134 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1141 struct vop_readdir_args /* {
1142 * struct vnode *a_vp;
1143 * struct uio *a_uio;
1144 * struct ucred *a_cred;
1146 * u_long *a_cookies;
1152 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1154 off = ap->a_uio->uio_offset;
1157 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1159 if (!error && ap->a_ncookies != NULL) {
1160 struct uio *uio = ap->a_uio;
1161 const struct dirent *dp, *dp_start, *dp_end;
1163 u_long *cookies, *cookiep;
1165 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1166 panic("afs_readdir: burned cookies");
1167 dp = (const struct dirent *)
1168 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1170 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1171 for (dp_start = dp, ncookies = 0; dp < dp_end;
1172 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1175 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1177 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1178 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1179 off += dp->d_reclen;
1182 *ap->a_cookies = cookies;
1183 *ap->a_ncookies = ncookies;
1190 afs_vop_readlink(ap)
1191 struct vop_readlink_args /* {
1192 * struct vnode *a_vp;
1193 * struct uio *a_uio;
1194 * struct ucred *a_cred;
1198 /* printf("readlink %x\n", ap->a_vp);*/
1200 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1205 extern int prtactive;
1208 afs_vop_inactive(ap)
1209 struct vop_inactive_args /* {
1210 * struct vnode *a_vp;
1214 register struct vnode *vp = ap->a_vp;
1216 if (prtactive && vp->v_usecount != 0)
1217 vprint("afs_vop_inactive(): pushing active", vp);
1220 afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
1222 VOP_UNLOCK(vp, 0, ap->a_p);
1228 struct vop_reclaim_args /* {
1229 * struct vnode *a_vp;
1234 register struct vnode *vp = ap->a_vp;
1236 cache_purge(vp); /* just in case... */
1240 error = afs_FlushVCache(VTOAFS(vp), &sl); /* tosses our stuff from vnode */
1243 if (!error && vp->v_data)
1244 panic("afs_reclaim: vnode not cleaned");
1247 if (vp->v_usecount == 2) {
1248 vprint("reclaim count==2", vp);
1249 } else if (vp->v_usecount == 1) {
1250 vprint("reclaim count==1", vp);
1252 vprint("reclaim bad count", vp);
1260 struct vop_lock_args /* {
1261 * struct vnode *a_vp;
1264 register struct vnode *vp = ap->a_vp;
1265 register struct vcache *avc = VTOAFS(vp);
1267 if (vp->v_tag == VT_NON)
1269 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1274 struct vop_unlock_args /* {
1275 * struct vnode *a_vp;
1278 struct vnode *vp = ap->a_vp;
1279 struct vcache *avc = VTOAFS(vp);
1281 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1288 struct vop_bmap_args /* {
1289 * struct vnode *a_vp;
1291 * struct vnode **a_vpp;
1300 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1303 *ap->a_vpp = ap->a_vp;
1305 if (ap->a_runp != NULL)
1308 if (ap->a_runb != NULL)
1316 afs_vop_strategy(ap)
1317 struct vop_strategy_args /* {
1323 error = afs_ustrategy(ap->a_bp);
1330 struct vop_print_args /* {
1331 * struct vnode *a_vp;
1334 register struct vnode *vp = ap->a_vp;
1335 register struct vcache *vc = VTOAFS(ap->a_vp);
1337 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1338 vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
1339 vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1340 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1341 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1342 (s & CMAPPED) ? " mapped" : "",
1343 (s & CVFlushed) ? " flush in progress" : "");
1344 if (UBCISVALID(vp)) {
1346 if (UBCINFOEXISTS(vp)) {
1348 #ifdef AFS_DARWIN14_ENV
1349 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1350 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1351 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1353 printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1356 printf("does not exist");
1363 afs_vop_islocked(ap)
1364 struct vop_islocked_args /* {
1365 * struct vnode *a_vp;
1368 struct vcache *vc = VTOAFS(ap->a_vp);
1369 return lockstatus(&vc->rwlock);
1373 * Return POSIX pathconf information applicable to ufs filesystems.
1375 afs_vop_pathconf(ap)
1376 struct vop_pathconf_args /* {
1377 * struct vnode *a_vp;
1382 AFS_STATCNT(afs_cntl);
1383 switch (ap->a_name) {
1385 *ap->a_retval = LINK_MAX;
1388 *ap->a_retval = NAME_MAX;
1391 *ap->a_retval = PATH_MAX;
1393 case _PC_CHOWN_RESTRICTED:
1402 #if defined(AFS_DARWIN70_ENV)
1403 case _PC_NAME_CHARS_MAX:
1404 *ap->a_retval = NAME_MAX;
1406 case _PC_CASE_SENSITIVE:
1409 case _PC_CASE_PRESERVING:
1412 #endif /* defined(AFS_DARWIN70_ENV) */
1420 * Advisory record locking support (fcntl() POSIX style)
1424 struct vop_advlock_args /* {
1425 * struct vnode *a_vp;
1428 * struct flock *a_fl;
1433 struct proc *p = current_proc();
1436 cr = *p->p_cred->pc_ucred;
1440 afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
1446 afs_vop_truncate(ap)
1447 struct vop_truncate_args /* {
1448 * struct vnode *a_vp;
1451 * struct ucred *a_cred;
1455 printf("stray afs_vop_truncate\n");
1461 struct vop_update_args /* {
1462 * struct vnode *a_vp;
1463 * struct timeval *a_access;
1464 * struct timeval *a_modify;
1468 printf("stray afs_vop_update\n");
1473 afs_vop_blktooff(ap)
1474 struct vop_blktooff_args /* {
1475 * struct vnode *a_vp;
1480 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1485 afs_vop_offtoblk(ap)
1486 struct vop_offtoblk_args /* {
1487 * struct vnode *a_vp;
1489 * daddr_t *a_lblkno;
1492 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1499 struct vop_cmap_args /* {
1500 * struct vnode *a_vp;
1508 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
1509 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));