2 * Portions Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
8 #include <afs/sysincludes.h> /* Standard vendor system headers */
9 #include <afsincludes.h> /* Afs-based standard headers */
10 #include <afs/afs_stats.h> /* statistics */
11 #include <sys/malloc.h>
12 #include <sys/namei.h>
14 #if defined(AFS_DARWIN70_ENV)
15 #include <vfs/vfs_support.h>
16 #endif /* defined(AFS_DARWIN70_ENV) */
17 #ifdef AFS_DARWIN80_ENV
18 #include <sys/vnode_if.h>
19 #include <sys/kauth.h>
22 #ifdef AFS_DARWIN80_ENV
23 #define VOPPREF(x) &vnop_ ## x
24 #define VOPPROT(x) vnop_ ## x
25 #define OSI_UPL_ABORT_RANGE(pl, offset, size, flags) \
26 ubc_upl_abort_range((pl), (offset), (size), (flags))
27 #define OSI_UPL_COMMIT_RANGE(pl, offset, size, flags) \
28 ubc_upl_commit_range((pl), (offset), (size), (flags))
29 #define OSI_UPL_MAP(upl, offset) ubc_upl_map((upl), (offset))
30 #define OSI_UPL_UNMAP(upl) ubc_upl_unmap((upl))
31 #define VOP_ABORTOP(x, y)
33 #define VOPPREF(x) &vop_ ## x
34 #define VOPPROT(x) vop_ ## x
35 #define OSI_UPL_ABORT_RANGE(pl, offset, size, flags) \
36 kernel_upl_abort_range((pl), (offset), (size), (flags))
37 #define OSI_UPL_COMMIT_RANGE(pl, offset, size, flags) \
38 kernel_upl_commit_range((pl), (offset), (size), (flags), \
39 UPL_GET_INTERNAL_PAGE_LIST((pl)),\
41 #define OSI_UPL_MAP(upl, offset) kernel_upl_map(kernel_map, (upl), (offset))
42 #define OSI_UPL_UNMAP(upl) kernel_upl_unmap(kernel_map, (upl))
45 extern char afs_zeros[AFS_ZEROS];
47 int afs_vop_lookup(struct VOPPROT(lookup_args) *);
48 int afs_vop_create(struct VOPPROT(create_args) *);
49 int afs_vop_mknod(struct VOPPROT(mknod_args) *);
50 int afs_vop_open(struct VOPPROT(open_args) *);
51 int afs_vop_close(struct VOPPROT(close_args) *);
52 int afs_vop_access(struct VOPPROT(access_args) *);
53 int afs_vop_getattr(struct VOPPROT(getattr_args) *);
54 int afs_vop_setattr(struct VOPPROT(setattr_args) *);
55 int afs_vop_read(struct VOPPROT(read_args) *);
56 int afs_vop_write(struct VOPPROT(write_args) *);
57 int afs_vop_pagein(struct VOPPROT(pagein_args) *);
58 int afs_vop_pageout(struct VOPPROT(pageout_args) *);
59 int afs_vop_ioctl(struct VOPPROT(ioctl_args) *);
60 int afs_vop_select(struct VOPPROT(select_args) *);
61 int afs_vop_mmap(struct VOPPROT(mmap_args) *);
62 int afs_vop_fsync(struct VOPPROT(fsync_args) *);
63 int afs_vop_remove(struct VOPPROT(remove_args) *);
64 int afs_vop_link(struct VOPPROT(link_args) *);
65 int afs_vop_rename(struct VOPPROT(rename_args) *);
66 int afs_vop_mkdir(struct VOPPROT(mkdir_args) *);
67 int afs_vop_rmdir(struct VOPPROT(rmdir_args) *);
68 int afs_vop_symlink(struct VOPPROT(symlink_args) *);
69 int afs_vop_readdir(struct VOPPROT(readdir_args) *);
70 int afs_vop_readlink(struct VOPPROT(readlink_args) *);
71 #if !defined(AFS_DARWIN70_ENV)
72 extern int ufs_abortop(struct vop_abortop_args *);
73 #endif /* !defined(AFS_DARWIN70_ENV) */
74 int afs_vop_inactive(struct VOPPROT(inactive_args) *);
75 int afs_vop_reclaim(struct VOPPROT(reclaim_args) *);
76 int afs_vop_strategy(struct VOPPROT(strategy_args) *);
77 int afs_vop_pathconf(struct VOPPROT(pathconf_args) *);
78 int afs_vop_advlock(struct VOPPROT(advlock_args) *);
79 int afs_vop_blktooff __P((struct VOPPROT(blktooff_args) *));
80 int afs_vop_offtoblk __P((struct VOPPROT(offtoblk_args) *));
81 #ifndef AFS_DARWIN80_ENV
82 int afs_vop_truncate(struct VOPPROT(truncate_args) *);
83 int afs_vop_update(struct VOPPROT(update_args) *);
84 int afs_vop_lock(struct VOPPROT(lock_args) *);
85 int afs_vop_unlock(struct VOPPROT(unlock_args) *);
86 int afs_vop_bmap(struct VOPPROT(bmap_args) *);
87 int afs_vop_seek(struct VOPPROT(seek_args) *);
88 int afs_vop_cmap __P((struct VOPPROT(cmap_args) *));
89 int afs_vop_print(struct VOPPROT(print_args) *);
90 int afs_vop_islocked(struct VOPPROT(islocked_args) *);
93 #define afs_vop_opnotsupp \
94 ((int (*) __P((struct vop_reallocblks_args *)))eopnotsupp)
95 #define afs_vop_valloc afs_vop_opnotsupp
96 #define afs_vop_vfree afs_vop_opnotsupp
97 #define afs_vop_blkatoff afs_vop_opnotsupp
98 #define afs_vop_reallocblks afs_vop_opnotsupp
100 /* Global vfs data structures for AFS. */
101 int (**afs_vnodeop_p) ();
103 #define VOPFUNC int (*)(void *)
105 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
106 {VOPPREF(default_desc), (VOPFUNC)vn_default_error},
107 {VOPPREF(lookup_desc), (VOPFUNC)afs_vop_lookup}, /* lookup */
108 {VOPPREF(create_desc), (VOPFUNC)afs_vop_create}, /* create */
109 {VOPPREF(mknod_desc), (VOPFUNC)afs_vop_mknod}, /* mknod */
110 {VOPPREF(open_desc), (VOPFUNC)afs_vop_open}, /* open */
111 {VOPPREF(close_desc), (VOPFUNC)afs_vop_close}, /* close */
112 {VOPPREF(access_desc), (VOPFUNC)afs_vop_access}, /* access */
113 {VOPPREF(getattr_desc), (VOPFUNC)afs_vop_getattr}, /* getattr */
114 {VOPPREF(setattr_desc), (VOPFUNC)afs_vop_setattr}, /* setattr */
115 {VOPPREF(read_desc), (VOPFUNC)afs_vop_read}, /* read */
116 {VOPPREF(write_desc), (VOPFUNC)afs_vop_write}, /* write */
117 {VOPPREF(pagein_desc), (VOPFUNC)afs_vop_pagein}, /* read */
118 {VOPPREF(pageout_desc), (VOPFUNC)afs_vop_pageout}, /* write */
119 {VOPPREF(ioctl_desc), (VOPFUNC)afs_vop_ioctl}, /* XXX ioctl */
120 {VOPPREF(select_desc), (VOPFUNC)afs_vop_select}, /* select */
121 {VOPPREF(mmap_desc), (VOPFUNC)afs_vop_mmap}, /* mmap */
122 {VOPPREF(fsync_desc), (VOPFUNC)afs_vop_fsync}, /* fsync */
123 #ifndef AFS_DARWIN80_ENV
124 {VOPPREF(seek_desc), (VOPFUNC)afs_vop_seek}, /* seek */
126 {VOPPREF(remove_desc), (VOPFUNC)afs_vop_remove}, /* remove */
127 {VOPPREF(link_desc), (VOPFUNC)afs_vop_link}, /* link */
128 {VOPPREF(rename_desc), (VOPFUNC)afs_vop_rename}, /* rename */
129 {VOPPREF(mkdir_desc), (VOPFUNC)afs_vop_mkdir}, /* mkdir */
130 {VOPPREF(rmdir_desc), (VOPFUNC)afs_vop_rmdir}, /* rmdir */
131 {VOPPREF(symlink_desc), (VOPFUNC)afs_vop_symlink}, /* symlink */
132 {VOPPREF(readdir_desc), (VOPFUNC)afs_vop_readdir}, /* readdir */
133 {VOPPREF(readlink_desc), (VOPFUNC)afs_vop_readlink}, /* readlink */
134 #ifndef AFS_DARWIN80_ENV
135 #if defined(AFS_DARWIN70_ENV)
136 {VOPPREF(abortop_desc), (VOPFUNC)nop_abortop }, /* abortop */
137 #else /* ! defined(AFS_DARWIN70_ENV) */
138 /* Yes, we use the ufs_abortop call. It just releases the namei
140 {VOPPREF(abortop_desc), (VOPFUNC)ufs_abortop}, /* abortop */
141 #endif /* defined(AFS_DARWIN70_ENV) */
143 {VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive}, /* inactive */
144 {VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim}, /* reclaim */
145 #ifndef AFS_DARWIN80_ENV
146 {VOPPREF(lock_desc), (VOPFUNC)afs_vop_lock}, /* lock */
147 {VOPPREF(unlock_desc), (VOPFUNC)afs_vop_unlock}, /* unlock */
148 {VOPPREF(bmap_desc), (VOPFUNC)afs_vop_bmap}, /* bmap */
150 #ifdef AFS_DARWIN80_ENV
151 {VOPPREF(strategy_desc), (VOPFUNC)err_strategy}, /* strategy */
153 {VOPPREF(strategy_desc), (VOPFUNC)afs_vop_strategy}, /* strategy */
155 #ifndef AFS_DARWIN80_ENV
156 {VOPPREF(print_desc), (VOPFUNC)afs_vop_print}, /* print */
157 {VOPPREF(islocked_desc), (VOPFUNC)afs_vop_islocked}, /* islocked */
159 {VOPPREF(pathconf_desc), (VOPFUNC)afs_vop_pathconf}, /* pathconf */
160 {VOPPREF(advlock_desc), (VOPFUNC)afs_vop_advlock}, /* advlock */
161 #ifndef AFS_DARWIN80_ENV
162 {VOPPREF(blkatoff_desc), (VOPFUNC)afs_vop_blkatoff}, /* blkatoff */
163 {VOPPREF(valloc_desc), (VOPFUNC)afs_vop_valloc}, /* valloc */
164 {VOPPREF(reallocblks_desc), (VOPFUNC)afs_vop_reallocblks}, /* reallocblks */
165 {VOPPREF(vfree_desc), (VOPFUNC)afs_vop_vfree}, /* vfree */
166 {VOPPREF(update_desc), (VOPFUNC)afs_vop_update}, /* update */
167 {VOPPREF(cmap_desc), (VOPFUNC)afs_vop_cmap}, /* cmap */
168 {VOPPREF(truncate_desc), (VOPFUNC)afs_vop_truncate}, /* truncate */
170 {VOPPREF(blktooff_desc), (VOPFUNC)afs_vop_blktooff}, /* blktooff */
171 {VOPPREF(offtoblk_desc), (VOPFUNC)afs_vop_offtoblk}, /* offtoblk */
172 {VOPPREF(bwrite_desc), (VOPFUNC)vn_bwrite},
173 {(struct vnodeop_desc *)NULL, (void (*)())NULL}
175 struct vnodeopv_desc afs_vnodeop_opv_desc =
176 { &afs_vnodeop_p, afs_vnodeop_entries };
178 #ifdef AFS_DARWIN80_ENV
179 /* vfs structures for incompletely initialized vnodes */
180 int (**afs_dead_vnodeop_p) ();
182 struct vnodeopv_entry_desc afs_dead_vnodeop_entries[] = {
183 {VOPPREF(default_desc), (VOPFUNC)vn_default_error},
184 {VOPPREF(lookup_desc), (VOPFUNC)vn_default_error}, /* lookup */
185 {VOPPREF(create_desc), (VOPFUNC)err_create}, /* create */
186 {VOPPREF(mknod_desc), (VOPFUNC)err_mknod}, /* mknod */
187 {VOPPREF(open_desc), (VOPFUNC)err_open}, /* open */
188 {VOPPREF(close_desc), (VOPFUNC)err_close}, /* close */
189 {VOPPREF(access_desc), (VOPFUNC)err_access}, /* access */
190 {VOPPREF(getattr_desc), (VOPFUNC)err_getattr}, /* getattr */
191 {VOPPREF(setattr_desc), (VOPFUNC)err_setattr}, /* setattr */
192 {VOPPREF(read_desc), (VOPFUNC)err_read}, /* read */
193 {VOPPREF(write_desc), (VOPFUNC)err_write}, /* write */
194 {VOPPREF(pagein_desc), (VOPFUNC)err_pagein}, /* read */
195 {VOPPREF(pageout_desc), (VOPFUNC)err_pageout}, /* write */
196 {VOPPREF(ioctl_desc), (VOPFUNC)err_ioctl}, /* XXX ioctl */
197 {VOPPREF(select_desc), (VOPFUNC)nop_select}, /* select */
198 {VOPPREF(mmap_desc), (VOPFUNC)err_mmap}, /* mmap */
199 {VOPPREF(fsync_desc), (VOPFUNC)err_fsync}, /* fsync */
200 {VOPPREF(remove_desc), (VOPFUNC)err_remove}, /* remove */
201 {VOPPREF(link_desc), (VOPFUNC)err_link}, /* link */
202 {VOPPREF(rename_desc), (VOPFUNC)err_rename}, /* rename */
203 {VOPPREF(mkdir_desc), (VOPFUNC)err_mkdir}, /* mkdir */
204 {VOPPREF(rmdir_desc), (VOPFUNC)err_rmdir}, /* rmdir */
205 {VOPPREF(symlink_desc), (VOPFUNC)err_symlink}, /* symlink */
206 {VOPPREF(readdir_desc), (VOPFUNC)err_readdir}, /* readdir */
207 {VOPPREF(readlink_desc), (VOPFUNC)err_readlink}, /* readlink */
208 {VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive}, /* inactive */
209 {VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim}, /* reclaim */
210 {VOPPREF(strategy_desc), (VOPFUNC)err_strategy}, /* strategy */
211 {VOPPREF(pathconf_desc), (VOPFUNC)err_pathconf}, /* pathconf */
212 {VOPPREF(advlock_desc), (VOPFUNC)err_advlock}, /* advlock */
213 {VOPPREF(blktooff_desc), (VOPFUNC)err_blktooff}, /* blktooff */
214 {VOPPREF(offtoblk_desc), (VOPFUNC)err_offtoblk}, /* offtoblk */
215 {VOPPREF(bwrite_desc), (VOPFUNC)err_bwrite},
216 {(struct vnodeop_desc *)NULL, (void (*)())NULL}
218 struct vnodeopv_desc afs_dead_vnodeop_opv_desc =
219 { &afs_dead_vnodeop_p, afs_dead_vnodeop_entries };
223 struct componentname *cnp = ap->a_cnp; \
225 MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
226 memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
227 name[cnp->cn_namelen] = '\0'
229 #define DROPNAME() FREE(name, M_TEMP)
232 darwin_vn_hold(struct vnode *vp)
234 int haveGlock=ISAFS_GLOCK();
235 struct vcache *tvc = VTOAFS(vp);
237 #ifndef AFS_DARWIN80_ENV
238 tvc->f.states |= CUBCinit;
240 #ifdef AFS_DARWIN80_ENV
241 osi_Assert((tvc->f.states & CVInit) == 0);
242 if (tvc->f.states & CDeadVnode)
243 osi_Assert(!vnode_isinuse(vp, 1));
245 if (haveGlock) AFS_GUNLOCK();
247 #ifdef AFS_DARWIN80_ENV
249 /* being terminated. kernel won't give us a ref. Now what? our
250 callers don't expect us to fail */
251 if (haveGlock) AFS_GLOCK();
256 if (haveGlock) AFS_GLOCK();
261 /* vget needed for 0 ref'd vnode in GetVCache to not panic in vref.
262 vref needed for multiref'd vnode in vnop_remove not to deadlock
263 ourselves during vop_inactive, except we also need to not reinst
264 the ubc... so we just call VREF there now anyway. */
266 if (VREFCOUNT_GT(tvc, 0))
267 VREF(((struct vnode *)(vp)));
269 afs_vget(afs_globalVFS, 0, (vp));
272 #ifndef AFS_DARWIN80_ENV
273 if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
278 if (haveGlock) AFS_GLOCK();
279 #ifndef AFS_DARWIN80_ENV
280 tvc->f.states &= ~CUBCinit;
285 struct VOPPROT(lookup_args)/* {
286 * struct vnodeop_desc * a_desc;
287 * struct vnode *a_dvp;
288 * struct vnode **a_vpp;
289 * struct componentname *a_cnp;
294 struct vnode *vp, *dvp;
295 register int flags = ap->a_cnp->cn_flags;
296 int lockparent; /* 1 => lockparent flag is set */
297 int wantparent; /* 1 => wantparent or lockparent flag */
299 #ifdef AFS_DARWIN80_ENV
300 vcp = VTOAFS(ap->a_dvp);
301 if (vcp->mvstat != 1) {
302 error = cache_lookup(ap->a_dvp, ap->a_vpp, ap->a_cnp);
313 lockparent = flags & LOCKPARENT;
314 wantparent = flags & (LOCKPARENT | WANTPARENT);
316 if (!vnode_isdir(ap->a_dvp)) {
322 #ifndef AFS_DARWIN80_ENV
323 if (flags & ISDOTDOT)
324 VOP_UNLOCK(dvp, 0, p);
327 error = afs_lookup(VTOAFS(dvp), name, &vcp, vop_cn_cred);
330 #ifndef AFS_DARWIN80_ENV
331 if (flags & ISDOTDOT)
332 VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
334 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
335 && (flags & ISLASTCN) && error == ENOENT)
337 #ifndef AFS_DARWIN80_ENV
338 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
339 cnp->cn_flags |= SAVENAME;
345 #ifdef AFS_DARWIN80_ENV
346 if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0))) {
352 vp = AFSTOV(vcp); /* always get a node if no error */
353 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
354 vp->v_vfsp = dvp->v_vfsp;
356 if (UBCINFOMISSING(vp) ||
357 UBCINFORECLAIMED(vp)) {
362 #ifndef AFS_DARWIN80_ENV
363 /* The parent directory comes in locked. We unlock it on return
364 * unless the caller wants it left locked.
365 * we also always return the vnode locked. */
367 if (flags & ISDOTDOT) {
368 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
369 /* always return the child locked */
370 if (lockparent && (flags & ISLASTCN)
371 && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
376 } else if (vp == dvp) {
377 /* they're the same; afs_lookup() already ref'ed the leaf.
378 * It came in locked, so we don't need to ref OR lock it */
380 if (!lockparent || !(flags & ISLASTCN))
381 VOP_UNLOCK(dvp, 0, p); /* done with parent. */
382 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
383 /* always return the child locked */
388 #ifndef AFS_DARWIN80_ENV
389 if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
390 || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
391 cnp->cn_flags |= SAVENAME;
400 struct VOPPROT(create_args) /* {
401 * struct vnode *a_dvp;
402 * struct vnode **a_vpp;
403 * struct componentname *a_cnp;
404 * struct vattr *a_vap;
409 register struct vnode *dvp = ap->a_dvp;
414 /* vnode layer handles excl/nonexcl */
417 afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
421 #ifndef AFS_DARWIN80_ENV
422 VOP_ABORTOP(dvp, cnp);
430 #ifdef AFS_DARWIN80_ENV
431 if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0))) {
437 *ap->a_vpp = AFSTOV(vcp);
438 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
439 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
440 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
441 if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
442 vcp->f.states |= CUBCinit;
443 ubc_info_init(*ap->a_vpp);
444 vcp->f.states &= ~CUBCinit;
450 #ifndef AFS_DARWIN80_ENV
451 if ((cnp->cn_flags & SAVESTART) == 0)
452 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
461 struct VOPPROT(mknod_args) /* {
462 * struct vnode *a_dvp;
463 * struct vnode **a_vpp;
464 * struct componentname *a_cnp;
465 * struct vattr *a_vap;
468 #ifndef AFS_DARWIN80_ENV
469 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
477 struct VOPPROT(open_args) /* {
478 * struct vnode *a_vp;
480 * struct ucred *a_cred;
485 struct vnode *vp = ap->a_vp;
486 struct vcache *vc = VTOAFS(vp);
487 #if defined(AFS_DARWIN14_ENV) && !defined(AFS_DARWIN80_ENV)
489 /*----------------------------------------------------------------
490 * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
491 * can later be passed to vn_open(), which will skip the call to
492 * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
493 * will be off. So we compensate by calling ubc_hold() ourselves
494 * when ui_refcount is less than 2. If an error occurs in afs_open()
495 * we must call ubc_rele(), which is what vn_open() would do if it
496 * was able to call ubc_hold() in the first place.
497 *----------------------------------------------------------------*/
498 if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
499 && vp->v_ubcinfo->ui_refcount < 2)
500 didhold = ubc_hold(vp);
501 #endif /* AFS_DARWIN14_ENV */
503 error = afs_open(&vc, ap->a_mode, vop_cred);
505 if (AFSTOV(vc) != vp)
506 panic("AFS open changed vnode!");
508 osi_FlushPages(vc, vop_cred);
510 #if defined(AFS_DARWIN14_ENV) && !defined(AFS_DARWIN80_ENV)
511 if (error && didhold)
513 #endif /* AFS_DARWIN14_ENV */
519 struct VOPPROT(close_args) /* {
520 * struct vnode *a_vp;
522 * struct ucred *a_cred;
527 struct vnode *vp = ap->a_vp;
528 struct vcache *avc = VTOAFS(vp);
531 code = afs_close(avc, ap->a_fflag, vop_cred);
533 code = afs_close(avc, ap->a_fflag, &afs_osi_cred);
534 osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
535 /* This is legit; it just forces the fstrace event to happen */
536 code = afs_CheckCode(code, NULL, 60);
542 #ifdef AFS_DARWIN80_ENV
543 extern int afs_fakestat_enable;
547 struct VOPPROT(access_args) /* {
548 * struct vnode *a_vp;
550 * vfs_context_t a_context;
554 struct vrequest treq;
555 struct afs_fakestat_state fakestate;
556 struct vcache * tvc = VTOAFS(ap->a_vp);
558 int cmb = CHECK_MODE_BITS;
560 afs_InitFakeStat(&fakestate);
561 if ((code = afs_InitReq(&treq, vop_cred)))
564 code = afs_TryEvalFakeStat(&tvc, &fakestate, &treq);
566 code = afs_CheckCode(code, &treq, 55);
570 code = afs_VerifyVCache(tvc, &treq);
572 code = afs_CheckCode(code, &treq, 56);
575 if (afs_fakestat_enable && tvc->mvstat && !(tvc->f.states & CStatd)) {
579 if (vnode_isdir(ap->a_vp)) {
580 if (ap->a_action & KAUTH_VNODE_LIST_DIRECTORY)
581 bits |= PRSFS_LOOKUP;
582 if (ap->a_action & KAUTH_VNODE_ADD_FILE)
583 bits |= PRSFS_INSERT;
584 if (ap->a_action & KAUTH_VNODE_SEARCH)
585 bits |= PRSFS_LOOKUP;
586 if (ap->a_action & KAUTH_VNODE_DELETE)
587 bits |= PRSFS_DELETE;
588 if (ap->a_action & KAUTH_VNODE_ADD_SUBDIRECTORY)
589 bits |= PRSFS_INSERT;
590 if (ap->a_action & KAUTH_VNODE_DELETE_CHILD)
591 bits |= PRSFS_DELETE;
592 #if 0 /* I'd argue this should be enforced on the parent. But that's ugly */
593 if (ap->a_action & KAUTH_VNODE_READ_ATTRIBUTES)
594 bits |= PRSFS_LOOKUP;
595 if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
596 bits |= PRSFS_LOOKUP;
599 if (ap->a_action & KAUTH_VNODE_READ_DATA)
601 if (ap->a_action & KAUTH_VNODE_WRITE_DATA)
603 if (ap->a_action & KAUTH_VNODE_EXECUTE)
604 bits |= PRSFS_READ; /* and mode bits.... */
605 if (ap->a_action & KAUTH_VNODE_READ_ATTRIBUTES)
606 bits |= PRSFS_LOOKUP;
607 if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
608 bits |= PRSFS_LOOKUP;
609 if ((ap->a_action & ((1 << 25) - 1)) == KAUTH_VNODE_EXECUTE)
610 /* if only exec, don't check for read mode bit */
611 /* high bits of ap->a_action are not for 'generic rights bits', and
612 so should not be checked (KAUTH_VNODE_ACCESS is often present
613 and needs to be masked off) */
614 cmb |= CMB_ALLOW_EXEC_AS_READ;
616 if (ap->a_action & KAUTH_VNODE_WRITE_ATTRIBUTES)
618 #if 0 /* no extended attributes */
619 if (ap->a_action & KAUTH_VNODE_READ_EXTATTRIBUTES)
621 if (ap->a_action & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
624 if (ap->a_action & KAUTH_VNODE_WRITE_SECURITY)
626 /* we can't check for KAUTH_VNODE_TAKE_OWNERSHIP, so we always permit it */
628 code = afs_AccessOK(tvc, bits, &treq, cmb);
629 #if defined(AFS_DARWIN80_ENV)
630 /* In a dropbox, cp on 10.4 behaves badly, looping on EACCES */
631 /* In a dropbox, Finder may reopen the file. Let it. */
632 if (code == 0 && ((bits &~(PRSFS_READ|PRSFS_WRITE)) == 0)) {
633 code = afs_AccessOK(tvc, PRSFS_ADMINISTER|PRSFS_INSERT|bits, &treq, cmb);
636 if (code == 1 && vnode_vtype(ap->a_vp) == VREG &&
637 ap->a_action & KAUTH_VNODE_EXECUTE &&
638 (tvc->f.m.Mode & 0100) != 0100) {
642 code= 0; /* if access is ok */
644 code = afs_CheckCode(EACCES, &treq, 57); /* failure code */
647 afs_PutFakeStat(&fakestate);
655 struct VOPPROT(access_args) /* {
656 * struct vnode *a_vp;
658 * struct ucred *a_cred;
664 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, vop_cred);
672 struct VOPPROT(getattr_args) /* {
673 * struct vnode *a_vp;
674 * struct vattr *a_vap;
675 * struct ucred *a_cred;
682 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
683 /* This is legit; it just forces the fstrace event to happen */
684 code = afs_CheckCode(code, NULL, 58);
686 #ifdef AFS_DARWIN80_ENV
687 VATTR_SET_SUPPORTED(ap->a_vap, va_type);
688 VATTR_SET_SUPPORTED(ap->a_vap, va_mode);
689 VATTR_SET_SUPPORTED(ap->a_vap, va_uid);
690 VATTR_SET_SUPPORTED(ap->a_vap, va_gid);
691 VATTR_SET_SUPPORTED(ap->a_vap, va_fsid);
692 VATTR_SET_SUPPORTED(ap->a_vap, va_fileid);
693 VATTR_SET_SUPPORTED(ap->a_vap, va_nlink);
694 VATTR_SET_SUPPORTED(ap->a_vap, va_data_size);
695 VATTR_SET_SUPPORTED(ap->a_vap, va_access_time);
696 VATTR_SET_SUPPORTED(ap->a_vap, va_modify_time);
697 VATTR_SET_SUPPORTED(ap->a_vap, va_change_time);
698 VATTR_SET_SUPPORTED(ap->a_vap, va_gen);
699 VATTR_SET_SUPPORTED(ap->a_vap, va_flags);
700 VATTR_SET_SUPPORTED(ap->a_vap, va_iosize);
701 VATTR_SET_SUPPORTED(ap->a_vap, va_total_alloc);
708 struct VOPPROT(setattr_args) /* {
709 * struct vnode *a_vp;
710 * struct vattr *a_vap;
711 * struct ucred *a_cred;
717 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
718 /* This is legit; it just forces the fstrace event to happen */
719 code = afs_CheckCode(code, NULL, 59);
726 struct VOPPROT(read_args) /* {
727 * struct vnode *a_vp;
730 * struct ucred *a_cred;
734 struct vnode *vp = ap->a_vp;
735 struct vcache *avc = VTOAFS(vp);
737 if (vnode_isdir(ap->a_vp))
739 #ifdef AFS_DARWIN80_ENV
740 ubc_msync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_PUSHDIRTY);
742 if (UBCINFOEXISTS(ap->a_vp)) {
743 ubc_clean(ap->a_vp, 0);
747 osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
748 code = afs_read(avc, ap->a_uio, vop_cred, 0, 0, 0);
755 struct VOPPROT(pagein_args) /* {
756 * struct vnode *a_vp;
758 * vm_offset_t a_pl_offset;
761 * struct ucred *a_cred;
765 register struct vnode *vp = ap->a_vp;
767 size_t size = ap->a_size;
768 off_t f_offset = ap->a_f_offset;
769 vm_offset_t pl_offset = ap->a_pl_offset;
770 int flags = ap->a_flags;
773 #ifdef AFS_DARWIN80_ENV
778 struct uio *uio = &auio;
780 int nocommit = flags & UPL_NOCOMMIT;
783 struct vcache *tvc = VTOAFS(vp);
784 #ifndef AFS_DARWIN80_ENV
785 if (UBCINVALID(vp)) {
787 panic("afs_vop_pagein: invalid vp");
788 #endif /* DIAGNOSTIC */
792 UBCINFOCHECK("afs_vop_pagein", vp);
794 if (pl == (upl_t) NULL) {
795 panic("afs_vop_pagein: no upl");
798 cred = ubc_getcred(vp);
804 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
805 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
810 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
811 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
814 if (f_offset & PAGE_MASK)
815 panic("afs_vop_pagein: offset not page aligned");
817 OSI_UPL_MAP(pl, &ioaddr);
819 #ifdef AFS_DARWIN80_ENV
820 uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
821 uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
823 auio.uio_iov = &aiov;
825 auio.uio_offset = f_offset;
826 auio.uio_segflg = UIO_SYSSPACE;
827 auio.uio_rw = UIO_READ;
828 auio.uio_procp = NULL;
829 auio.uio_resid = aiov.iov_len = size;
830 aiov.iov_base = (caddr_t) ioaddr;
833 osi_FlushPages(tvc, vop_cred); /* hold bozon lock, but not basic vnode lock */
834 code = afs_read(tvc, uio, cred, 0, 0, 0);
836 ObtainWriteLock(&tvc->lock, 2);
837 tvc->f.states |= CMAPPED;
838 ReleaseWriteLock(&tvc->lock);
842 /* Zero out rest of last page if there wasn't enough data in the file */
843 if (code == 0 && AFS_UIO_RESID(uio) > 0) {
844 #ifdef AFS_DARWIN80_ENV
845 memset(((caddr_t)ioaddr) + (size - AFS_UIO_RESID(uio)), 0,
848 memset(aiov.iov_base, 0, auio.uio_resid);
855 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
856 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
858 OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
859 UPL_COMMIT_CLEAR_DIRTY |
860 UPL_COMMIT_FREE_ON_EMPTY);
862 #ifdef AFS_DARWIN80_ENV
870 struct VOPPROT(write_args) /* {
871 * struct vnode *a_vp;
874 * struct ucred *a_cred;
878 struct vcache *avc = VTOAFS(ap->a_vp);
880 #ifdef AFS_DARWIN80_ENV
881 ubc_msync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_INVALIDATE);
883 if (UBCINFOEXISTS(ap->a_vp)) {
884 ubc_clean(ap->a_vp, 1);
886 if (UBCINFOEXISTS(ap->a_vp))
887 osi_VM_NukePages(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio),
888 AFS_UIO_RESID(ap->a_uio));
891 osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
893 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, vop_cred, 0);
900 struct VOPPROT(pageout_args) /* {
901 * struct vnode *a_vp;
903 * vm_offset_t a_pl_offset,
906 * struct ucred *a_cred,
910 register struct vnode *vp = ap->a_vp;
912 size_t size = ap->a_size;
913 off_t f_offset = ap->a_f_offset;
914 vm_offset_t pl_offset = ap->a_pl_offset;
915 int flags = ap->a_flags;
918 #ifdef AFS_DARWIN80_ENV
923 struct uio *uio = &auio;
925 int nocommit = flags & UPL_NOCOMMIT;
929 struct vcache *tvc = VTOAFS(vp);
930 #ifndef AFS_DARWIN80_ENV
931 if (UBCINVALID(vp)) {
933 panic("afs_vop_pageout: invalid vp");
934 #endif /* DIAGNOSTIC */
938 UBCINFOCHECK("afs_vop_pageout", vp);
940 if (pl == (upl_t) NULL) {
941 panic("afs_vop_pageout: no upl");
943 #if !defined(AFS_DARWIN80_ENV) /* XXX nfs now uses it's own bufs (struct nfsbuf)
945 layer doesn't have them anymore? In any case,
946 we can't just copy code from nfs... */
950 int biosize = DEV_BSIZE;
952 lbn = f_offset / DEV_BSIZE;
954 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
957 if (bp = incore(vp, lbn)) {
958 if (ISSET(bp->b_flags, B_BUSY))
959 panic("nfs_pageout: found BUSY buffer incore\n");
962 SET(bp->b_flags, (B_BUSY | B_INVAL));
969 cred = ubc_getcred(vp);
975 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
976 UPL_ABORT_FREE_ON_EMPTY);
979 if (flags & (IO_APPEND | IO_SYNC))
980 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
983 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
984 UPL_ABORT_FREE_ON_EMPTY);
987 if (f_offset >= tvc->f.m.Length) {
989 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
990 UPL_ABORT_FREE_ON_EMPTY);
994 if (f_offset & PAGE_MASK)
995 panic("afs_vop_pageout: offset not page aligned");
997 /* size will always be a multiple of PAGE_SIZE */
998 /* pageout isn't supposed to extend files */
999 if (f_offset + size > tvc->f.m.Length)
1000 iosize = tvc->f.m.Length - f_offset;
1004 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
1005 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
1006 OSI_UPL_ABORT_RANGE(pl, pl_offset + iosize_rnd,
1008 UPL_ABORT_FREE_ON_EMPTY);
1010 OSI_UPL_MAP(pl, &ioaddr);
1011 ioaddr += pl_offset;
1012 #ifdef AFS_DARWIN80_ENV
1013 uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
1014 uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
1016 auio.uio_iov = &aiov;
1017 auio.uio_iovcnt = 1;
1018 auio.uio_offset = f_offset;
1019 auio.uio_segflg = UIO_SYSSPACE;
1020 auio.uio_rw = UIO_WRITE;
1021 auio.uio_procp = NULL;
1022 auio.uio_resid = aiov.iov_len = iosize;
1023 aiov.iov_base = (caddr_t) ioaddr;
1027 * check for partial page and clear the
1028 * contents past end of the file before
1029 * releasing it in the VM page cache
1031 if ((f_offset < tvc->f.m.Length) && (f_offset + size) > tvc->f.m.Length) {
1032 size_t io = tvc->f.m.Length - f_offset;
1034 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
1039 osi_FlushPages(tvc, vop_cred); /* hold bozon lock, but not basic vnode lock */
1040 ObtainWriteLock(&tvc->lock, 1);
1042 ReleaseWriteLock(&tvc->lock);
1044 code = afs_write(tvc, uio, flags, cred, 0);
1046 ObtainWriteLock(&tvc->lock, 1);
1047 afs_FakeClose(tvc, cred);
1048 ReleaseWriteLock(&tvc->lock);
1053 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1054 UPL_ABORT_FREE_ON_EMPTY);
1056 OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
1057 UPL_COMMIT_CLEAR_DIRTY |
1058 UPL_COMMIT_FREE_ON_EMPTY);
1061 #ifdef AFS_DARWIN80_ENV
1069 struct VOPPROT(ioctl_args) /* {
1070 * struct vnode *a_vp;
1074 * struct ucred *a_cred;
1078 struct vcache *tvc = VTOAFS(ap->a_vp);
1079 struct afs_ioctl data;
1082 /* in case we ever get in here... */
1084 AFS_STATCNT(afs_ioctl);
1085 if (((ap->a_command >> 8) & 0xff) == 'V') {
1086 /* This is a VICEIOCTL call */
1088 error = HandleIoctl(tvc, ap->a_command, ap->a_data);
1092 /* No-op call; just return. */
1100 struct VOPPROT(select_args) /* {
1101 * struct vnode *a_vp;
1104 * struct ucred *a_cred;
1109 * We should really check to see if I/O is possible.
1117 * NB Currently unsupported.
1122 struct VOPPROT(mmap_args) /* {
1123 * struct vnode *a_vp;
1125 * struct ucred *a_cred;
1134 struct VOPPROT(fsync_args) /* {
1135 * struct vnode *a_vp;
1136 * struct ucred *a_cred;
1141 int wait = ap->a_waitfor == MNT_WAIT;
1143 register struct vnode *vp = ap->a_vp;
1144 int haveGlock = ISAFS_GLOCK();
1146 /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
1147 if (!haveGlock) AFS_GLOCK();
1149 error = afs_fsync(VTOAFS(vp), vop_cred);
1151 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
1152 if (!haveGlock) AFS_GUNLOCK();
1156 #ifndef AFS_DARWIN80_ENV
1159 struct VOPPROT(seek_args) /* {
1160 * struct vnode *a_vp;
1163 * struct ucred *a_cred;
1166 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
1174 struct VOPPROT(remove_args) /* {
1175 * struct vnode *a_dvp;
1176 * struct vnode *a_vp;
1177 * struct componentname *a_cnp;
1181 register struct vnode *vp = ap->a_vp;
1182 register struct vnode *dvp = ap->a_dvp;
1184 #ifdef AFS_DARWIN80_ENV
1185 if (ap->a_flags & VNODE_REMOVE_NODELETEBUSY) {
1186 /* Caller requested Carbon delete semantics */
1187 if (vnode_isinuse(vp, 0)) {
1195 error = afs_remove(VTOAFS(dvp), name, vop_cn_cred);
1196 error = afs_CheckCode(error, NULL, 61);
1200 #ifdef AFS_DARWIN80_ENV
1201 struct vcache *tvc = VTOAFS(vp);
1203 if (!(tvc->f.states & CUnlinked)) {
1204 ubc_setsize(vp, (off_t)0);
1208 /* necessary so we don't deadlock ourselves in vclean */
1209 VOP_UNLOCK(vp, 0, cnp->cn_proc);
1211 /* If crashes continue in ubc_hold, comment this out */
1212 (void)ubc_uncache(vp);
1215 /* should check for PRSFS_INSERT and not PRSFS_DELETE, but the
1216 goal here is to deal with Finder's unhappiness with resource
1217 forks that have no resources in a dropbox setting */
1218 if (name[0] == '.' && name[1] == '_' && error == EACCES)
1222 #ifndef AFS_DARWIN80_ENV
1230 #ifndef AFS_DARWIN80_ENV
1231 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1239 struct VOPPROT(link_args) /* {
1240 * struct vnode *a_vp;
1241 * struct vnode *a_tdvp;
1242 * struct componentname *a_cnp;
1246 register struct vnode *dvp = ap->a_tdvp;
1247 register struct vnode *vp = ap->a_vp;
1252 if (vnode_isdir(vp)) {
1253 VOP_ABORTOP(vp, cnp);
1257 #ifndef AFS_DARWIN80_ENV
1258 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
1259 VOP_ABORTOP(dvp, cnp);
1264 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, vop_cn_cred);
1266 #ifndef AFS_DARWIN80_ENV
1267 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1269 #ifndef AFS_DARWIN80_ENV
1271 VOP_UNLOCK(vp, 0, p);
1274 #ifndef AFS_DARWIN80_ENV
1283 struct VOPPROT(rename_args) /* {
1284 * struct vnode *a_fdvp;
1285 * struct vnode *a_fvp;
1286 * struct componentname *a_fcnp;
1287 * struct vnode *a_tdvp;
1288 * struct vnode *a_tvp;
1289 * struct componentname *a_tcnp;
1293 struct componentname *fcnp = ap->a_fcnp;
1295 struct componentname *tcnp = ap->a_tcnp;
1297 struct vnode *tvp = ap->a_tvp;
1298 register struct vnode *tdvp = ap->a_tdvp;
1299 struct vnode *fvp = ap->a_fvp;
1300 register struct vnode *fdvp = ap->a_fdvp;
1305 #ifdef AFS_DARWIN80_ENV
1306 /* generic code tests for v_mount equality, so we don't have to, but we don't
1307 get the multiple-mount "benefits" of the old behavior
1310 /* Check for cross-device rename.
1311 * For AFS, this means anything not in AFS-space
1313 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
1314 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
1320 #ifdef AFS_DARWIN80_ENV
1321 /* the generic code doesn't do this, so we really should, but all the
1322 vrele's are wrong... */
1325 * if fvp == tvp, we're just removing one name of a pair of
1326 * directory entries for the same element. convert call into rename.
1327 ( (pinched from NetBSD 1.0's ufs_rename())
1330 if (vnode_isdir(fvp)) {
1333 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
1340 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
1346 /* Release destination completely. */
1347 VOP_ABORTOP(tdvp, tcnp);
1350 /* Delete source. */
1351 #if defined(AFS_DARWIN80_ENV)
1353 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1354 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1355 fname[fcnp->cn_namelen] = '\0';
1357 error = afs_remove(VTOAFS(fdvp), fname, vop_cn_cred);
1359 FREE(fname, M_TEMP);
1364 fcnp->cn_flags &= ~MODMASK;
1365 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1366 if ((fcnp->cn_flags & SAVESTART) == 0)
1367 panic("afs_rename: lost from startdir");
1368 fcnp->cn_nameiop = DELETE;
1371 error=relookup(fdvp, &fvp, fcnp);
1377 error=VOP_REMOVE(fdvp, fvp, fcnp);
1388 #if !defined(AFS_DARWIN80_ENV)
1389 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1393 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1394 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1395 fname[fcnp->cn_namelen] = '\0';
1396 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1397 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1398 tname[tcnp->cn_namelen] = '\0';
1402 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1404 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, cn_cred(tcnp));
1407 #if !defined(AFS_DARWIN80_ENV)
1408 VOP_UNLOCK(fvp, 0, p);
1411 if (error == EXDEV) {
1412 /* The idea would be to have a userspace handler like afsdb to
1413 * run mv as the user, thus:
1415 printf("su %d -c /bin/mv /afs/.:mount/%d:%d:%d:%d/%s /afs/.:mount/%d:%d:%d:%d/%s\n",
1416 afs_cr_uid(cn_cred(tcnp)), fvc->f.fid.Cell, fvc->f.fid.Fid.Volume,
1417 fvc->f.fid.Fid.Vnode, fvc->f.fid.Fid.Unique, fname,
1418 tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode,
1419 tvc->f.fid.Fid.Unique, tname);
1422 #ifdef AFS_DARWIN80_ENV
1433 cache_enter(tdvp, fvp, tcnp);
1436 goto abortit; /* XXX */
1446 FREE(fname, M_TEMP);
1447 FREE(tname, M_TEMP);
1453 struct VOPPROT(mkdir_args) /* {
1454 * struct vnode *a_dvp;
1455 * struct vnode **a_vpp;
1456 * struct componentname *a_cnp;
1457 * struct vattr *a_vap;
1460 register struct vnode *dvp = ap->a_dvp;
1461 register struct vattr *vap = ap->a_vap;
1468 #if defined(DIAGNOSTIC) && !defined(AFS_DARWIN80_ENV)
1469 if ((cnp->cn_flags & HASBUF) == 0)
1470 panic("afs_vop_mkdir: no name");
1473 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, vop_cn_cred);
1476 #ifndef AFS_DARWIN80_ENV
1477 VOP_ABORTOP(dvp, cnp);
1484 #ifdef AFS_DARWIN80_ENV
1485 afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0);
1487 *ap->a_vpp = AFSTOV(vcp);
1488 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
1489 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1490 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1495 #ifndef AFS_DARWIN80_ENV
1496 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1504 struct VOPPROT(rmdir_args) /* {
1505 * struct vnode *a_dvp;
1506 * struct vnode *a_vp;
1507 * struct componentname *a_cnp;
1511 register struct vnode *vp = ap->a_vp;
1512 register struct vnode *dvp = ap->a_dvp;
1516 #ifndef AFS_DARWIN80_ENV
1519 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1526 error = afs_rmdir(VTOAFS(dvp), name, vop_cn_cred);
1531 #ifndef AFS_DARWIN80_ENV
1540 struct VOPPROT(symlink_args) /* {
1541 * struct vnode *a_dvp;
1542 * struct vnode **a_vpp;
1543 * struct componentname *a_cnp;
1544 * struct vattr *a_vap;
1548 register struct vnode *dvp = ap->a_dvp;
1550 /* NFS ignores a_vpp; so do we. */
1555 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, vop_cn_cred);
1558 #ifndef AFS_DARWIN80_ENV
1559 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1567 struct VOPPROT(readdir_args) /* {
1568 * struct vnode *a_vp;
1569 * struct uio *a_uio;
1570 * struct ucred *a_cred;
1572 * u_long *a_cookies;
1578 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1580 #ifdef AFS_DARWIN80_ENV
1581 /* too much work for now */
1582 /* should only break nfs exports */
1583 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1586 off = AFS_UIO_OFFSET(ap->a_uio);
1589 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, vop_cred, ap->a_eofflag);
1591 #ifndef AFS_DARWIN80_ENV
1592 if (!error && ap->a_ncookies != NULL) {
1593 struct uio *uio = ap->a_uio;
1594 const struct dirent *dp, *dp_start, *dp_end;
1596 u_long *cookies, *cookiep;
1598 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1599 panic("afs_readdir: burned cookies");
1600 dp = (const struct dirent *)
1601 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1603 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1604 for (dp_start = dp, ncookies = 0; dp < dp_end;
1605 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1608 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1610 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1611 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1612 off += dp->d_reclen;
1615 *ap->a_cookies = cookies;
1616 *ap->a_ncookies = ncookies;
1624 afs_vop_readlink(ap)
1625 struct VOPPROT(readlink_args) /* {
1626 * struct vnode *a_vp;
1627 * struct uio *a_uio;
1628 * struct ucred *a_cred;
1632 /* printf("readlink %x\n", ap->a_vp);*/
1634 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, vop_cred);
1639 extern int prtactive;
1642 afs_vop_inactive(ap)
1643 struct VOPPROT(inactive_args) /* {
1644 * struct vnode *a_vp;
1648 register struct vnode *vp = ap->a_vp;
1649 struct vcache *tvc = VTOAFS(vp);
1650 #ifndef AFS_DARWIN80_ENV
1651 if (prtactive && vp->v_usecount != 0)
1652 vprint("afs_vop_inactive(): pushing active", vp);
1655 #ifdef AFS_DARWIN80_ENV
1656 int unlinked = tvc->f.states & CUnlinked;
1659 afs_InactiveVCache(tvc, 0); /* decrs ref counts */
1661 #ifdef AFS_DARWIN80_ENV
1668 #ifndef AFS_DARWIN80_ENV
1669 VOP_UNLOCK(vp, 0, ap->a_p);
1676 struct VOPPROT(reclaim_args) /* {
1677 * struct vnode *a_vp;
1681 int sl, writelocked;
1682 register struct vnode *vp = ap->a_vp;
1683 struct vcache *tvc = VTOAFS(vp);
1685 osi_Assert(!ISAFS_GLOCK());
1686 cache_purge(vp); /* just in case... */
1689 writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335));
1691 ObtainWriteLock(&afs_xvreclaim, 176);
1692 #ifdef AFS_DARWIN80_ENV
1693 vnode_clearfsnode(AFSTOV(tvc));
1694 vnode_removefsref(AFSTOV(tvc));
1696 tvc->v->v_data = NULL; /* remove from vnode */
1698 AFSTOV(tvc) = NULL; /* also drop the ptr to vnode */
1699 tvc->f.states |= CVInit; /* also CDeadVnode? */
1700 tvc->nextfree = ReclaimedVCList;
1701 ReclaimedVCList = tvc;
1702 ReleaseWriteLock(&afs_xvreclaim);
1704 error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */
1705 if (tvc->f.states & (CVInit
1706 #ifdef AFS_DARWIN80_ENV
1710 tvc->f.states &= ~(CVInit
1711 #ifdef AFS_DARWIN80_ENV
1715 afs_osi_Wakeup(&tvc->f.states);
1717 if (!error && vnode_fsnode(vp))
1718 panic("afs_reclaim: vnode not cleaned");
1719 if (!error && (tvc->v != NULL))
1720 panic("afs_reclaim: vcache not cleaned");
1721 ReleaseWriteLock(&afs_xvcache);
1729 * Return POSIX pathconf information applicable to ufs filesystems.
1731 afs_vop_pathconf(ap)
1732 struct VOPPROT(pathconf_args) /* {
1733 * struct vnode *a_vp;
1738 AFS_STATCNT(afs_cntl);
1739 switch (ap->a_name) {
1741 *ap->a_retval = LINK_MAX;
1744 *ap->a_retval = NAME_MAX;
1747 *ap->a_retval = PATH_MAX;
1749 case _PC_CHOWN_RESTRICTED:
1758 #if defined(AFS_DARWIN70_ENV)
1759 case _PC_NAME_CHARS_MAX:
1760 *ap->a_retval = NAME_MAX;
1762 case _PC_CASE_SENSITIVE:
1765 case _PC_CASE_PRESERVING:
1768 #endif /* defined(AFS_DARWIN70_ENV) */
1776 * Advisory record locking support (fcntl() POSIX style)
1780 struct VOPPROT(advlock_args) /* {
1781 * struct vnode *a_vp;
1784 * struct flock *a_fl;
1792 #ifdef AFS_DARWIN80_ENV
1796 struct proc *p = current_proc();
1799 cr = *p->p_cred->pc_ucred;
1803 if (ap->a_flags & F_POSIX) {
1804 #ifdef AFS_DARWIN80_ENV
1805 p = (proc_t) ap->a_id;
1808 p = (struct proc *) ap->a_id;
1812 clid = (int)ap->a_id;
1814 if (ap->a_op == F_UNLCK) {
1816 } else if (ap->a_op == F_SETLK && ap->a_flags & F_WAIT) {
1822 error = afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, op, tcr, clid);
1828 afs_vop_blktooff(ap)
1829 struct VOPPROT(blktooff_args) /* {
1830 * struct vnode *a_vp;
1835 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1840 afs_vop_offtoblk(ap)
1841 struct VOPPROT(offtoblk_args) /* {
1842 * struct vnode *a_vp;
1844 * daddr_t *a_lblkno;
1847 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1852 #ifndef AFS_DARWIN80_ENV
1855 struct VOPPROT(lock_args) /* {
1856 * struct vnode *a_vp;
1859 register struct vnode *vp = ap->a_vp;
1860 register struct vcache *avc = VTOAFS(vp);
1862 if (vp->v_tag == VT_NON)
1865 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1870 struct VOPPROT(unlock_args) /* {
1871 * struct vnode *a_vp;
1874 struct vnode *vp = ap->a_vp;
1875 struct vcache *avc = VTOAFS(vp);
1878 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1884 afs_vop_truncate(ap)
1885 struct VOPPROT(truncate_args) /* {
1886 * struct vnode *a_vp;
1889 * struct ucred *a_cred;
1893 printf("stray afs_vop_truncate\n");
1899 struct VOPPROT(update_args) /* {
1900 * struct vnode *a_vp;
1901 * struct timeval *a_access;
1902 * struct timeval *a_modify;
1906 printf("stray afs_vop_update\n");
1912 struct VOPPROT(bmap_args) /* {
1913 * struct vnode *a_vp;
1915 * struct vnode **a_vpp;
1923 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
1926 *ap->a_vpp = ap->a_vp;
1928 if (ap->a_runp != NULL)
1931 if (ap->a_runb != NULL)
1939 afs_vop_strategy(ap)
1940 struct VOPPROT(strategy_args) /* {
1946 error = afs_ustrategy(ap->a_bp);
1953 struct VOPPROT(print_args) /* {
1954 * struct vnode *a_vp;
1957 register struct vnode *vp = ap->a_vp;
1958 register struct vcache *vc = VTOAFS(ap->a_vp);
1959 int s = vc->f.states;
1960 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
1961 vc->f.fid.Cell, vc->f.fid.Fid.Volume, vc->f.fid.Fid.Vnode,
1962 vc->f.fid.Fid.Unique, vc->opens, vc->execsOrWriters);
1963 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1964 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1965 (s & CMAPPED) ? " mapped" : "",
1966 (s & CVFlushed) ? " flush in progress" : "");
1967 if (UBCISVALID(vp)) {
1969 if (UBCINFOEXISTS(vp)) {
1971 #ifdef AFS_DARWIN14_ENV
1972 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
1973 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
1974 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
1976 printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
1979 printf("does not exist");
1986 afs_vop_islocked(ap)
1987 struct VOPPROT(islocked_args) /* {
1988 * struct vnode *a_vp;
1991 struct vcache *vc = VTOAFS(ap->a_vp);
1992 return lockstatus(&vc->rwlock);
1997 struct VOPPROT(cmap_args) /* {
1998 * struct vnode *a_vp;
2006 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
2007 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
2013 afs_darwin_getnewvnode(struct vcache *avc)
2015 #ifdef AFS_DARWIN80_ENV
2018 struct vnode_fsparam par;
2020 memset(&par, 0, sizeof(struct vnode_fsparam));
2021 par.vnfs_vtype = VNON;
2022 par.vnfs_vops = afs_dead_vnodeop_p;
2023 par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
2024 par.vnfs_mp = afs_globalVFS;
2025 par.vnfs_fsnode = avc;
2027 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &vp);
2032 vnode_recycle(vp); /* terminate as soon as iocount drops */
2033 avc->f.states |= CDeadVnode;
2037 while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &avc->v)) {
2038 /* no vnodes available, force an alloc (limits be damned)! */
2039 printf("failed to get vnode\n");
2041 avc->v->v_data = (void *)avc;
2045 #ifdef AFS_DARWIN80_ENV
2046 /* if this fails, then tvc has been unrefed and may have been freed.
2049 afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp, struct componentname *cnp, int isroot)
2054 struct vnode_fsparam par;
2056 ObtainWriteLock(&avc->lock,325);
2058 if (!(avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
2060 #if 0 /* unsupported */
2062 vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
2064 VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
2066 /* Can end up in reclaim... drop GLOCK */
2069 ReleaseWriteLock(&avc->lock);
2073 if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
2074 panic("vcache %p should not be CDeadVnode", avc);
2076 memset(&par, 0, sizeof(struct vnode_fsparam));
2077 par.vnfs_mp = afs_globalVFS;
2078 par.vnfs_vtype = avc->f.m.Type;
2079 par.vnfs_vops = afs_vnodeop_p;
2080 par.vnfs_filesize = avc->f.m.Length;
2081 par.vnfs_fsnode = avc;
2083 if (cnp && (cnp->cn_flags & ISDOTDOT) == 0)
2085 if (!dvp || !cnp || (cnp->cn_flags & MAKEENTRY) == 0)
2086 par.vnfs_flags = VNFS_NOCACHE;
2088 par.vnfs_markroot = 1;
2089 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
2091 vnode_addfsref(nvp);
2092 if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
2093 printf("vcache %p should not be CDeadVnode", avc);
2094 if (avc->v == ovp) {
2095 if (!(avc->f.states & CVInit)) {
2096 vnode_clearfsnode(ovp);
2097 vnode_removefsref(ovp);
2101 avc->f.states &=~ CDeadVnode;
2106 ReleaseWriteLock(&avc->lock);
2108 afs_osi_Wakeup(&avc->f.states);