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 #include <vfs/vfs_support.h>
15 #ifdef AFS_DARWIN80_ENV
16 #include <sys/vnode_if.h>
17 #include <sys/kauth.h>
20 #ifdef AFS_DARWIN80_ENV
21 #define VOPPREF(x) &vnop_ ## x
22 #define VOPPROT(x) vnop_ ## x
23 #define OSI_UPL_ABORT_RANGE(pl, offset, size, flags) \
24 ubc_upl_abort_range((pl), (offset), (size), (flags))
25 #define OSI_UPL_COMMIT_RANGE(pl, offset, size, flags) \
26 ubc_upl_commit_range((pl), (offset), (size), (flags))
27 #define OSI_UPL_MAP(upl, offset) ubc_upl_map((upl), (offset))
28 #define OSI_UPL_UNMAP(upl) ubc_upl_unmap((upl))
29 #define VOP_ABORTOP(x, y)
31 #define VOPPREF(x) &vop_ ## x
32 #define VOPPROT(x) vop_ ## x
33 #define OSI_UPL_ABORT_RANGE(pl, offset, size, flags) \
34 kernel_upl_abort_range((pl), (offset), (size), (flags))
35 #define OSI_UPL_COMMIT_RANGE(pl, offset, size, flags) \
36 kernel_upl_commit_range((pl), (offset), (size), (flags), \
37 UPL_GET_INTERNAL_PAGE_LIST((pl)),\
39 #define OSI_UPL_MAP(upl, offset) kernel_upl_map(kernel_map, (upl), (offset))
40 #define OSI_UPL_UNMAP(upl) kernel_upl_unmap(kernel_map, (upl))
43 extern char afs_zeros[AFS_ZEROS];
45 int afs_vop_lookup(struct VOPPROT(lookup_args) *);
46 int afs_vop_create(struct VOPPROT(create_args) *);
47 int afs_vop_mknod(struct VOPPROT(mknod_args) *);
48 int afs_vop_open(struct VOPPROT(open_args) *);
49 int afs_vop_close(struct VOPPROT(close_args) *);
50 int afs_vop_access(struct VOPPROT(access_args) *);
51 int afs_vop_getattr(struct VOPPROT(getattr_args) *);
52 int afs_vop_setattr(struct VOPPROT(setattr_args) *);
53 int afs_vop_read(struct VOPPROT(read_args) *);
54 int afs_vop_write(struct VOPPROT(write_args) *);
55 int afs_vop_pagein(struct VOPPROT(pagein_args) *);
56 int afs_vop_pageout(struct VOPPROT(pageout_args) *);
57 int afs_vop_ioctl(struct VOPPROT(ioctl_args) *);
58 int afs_vop_select(struct VOPPROT(select_args) *);
59 int afs_vop_mmap(struct VOPPROT(mmap_args) *);
60 int afs_vop_fsync(struct VOPPROT(fsync_args) *);
61 int afs_vop_remove(struct VOPPROT(remove_args) *);
62 int afs_vop_link(struct VOPPROT(link_args) *);
63 int afs_vop_rename(struct VOPPROT(rename_args) *);
64 int afs_vop_mkdir(struct VOPPROT(mkdir_args) *);
65 int afs_vop_rmdir(struct VOPPROT(rmdir_args) *);
66 int afs_vop_symlink(struct VOPPROT(symlink_args) *);
67 int afs_vop_readdir(struct VOPPROT(readdir_args) *);
68 int afs_vop_readlink(struct VOPPROT(readlink_args) *);
69 int afs_vop_inactive(struct VOPPROT(inactive_args) *);
70 int afs_vop_reclaim(struct VOPPROT(reclaim_args) *);
71 int afs_vop_strategy(struct VOPPROT(strategy_args) *);
72 int afs_vop_pathconf(struct VOPPROT(pathconf_args) *);
73 int afs_vop_advlock(struct VOPPROT(advlock_args) *);
74 int afs_vop_blktooff __P((struct VOPPROT(blktooff_args) *));
75 int afs_vop_offtoblk __P((struct VOPPROT(offtoblk_args) *));
76 #ifndef AFS_DARWIN80_ENV
77 int afs_vop_truncate(struct VOPPROT(truncate_args) *);
78 int afs_vop_update(struct VOPPROT(update_args) *);
79 int afs_vop_lock(struct VOPPROT(lock_args) *);
80 int afs_vop_unlock(struct VOPPROT(unlock_args) *);
81 int afs_vop_bmap(struct VOPPROT(bmap_args) *);
82 int afs_vop_seek(struct VOPPROT(seek_args) *);
83 int afs_vop_cmap __P((struct VOPPROT(cmap_args) *));
84 int afs_vop_print(struct VOPPROT(print_args) *);
85 int afs_vop_islocked(struct VOPPROT(islocked_args) *);
88 #define afs_vop_opnotsupp \
89 ((int (*) __P((struct vop_reallocblks_args *)))eopnotsupp)
90 #define afs_vop_valloc afs_vop_opnotsupp
91 #define afs_vop_vfree afs_vop_opnotsupp
92 #define afs_vop_blkatoff afs_vop_opnotsupp
93 #define afs_vop_reallocblks afs_vop_opnotsupp
95 /* Global vfs data structures for AFS. */
96 int (**afs_vnodeop_p) ();
98 #define VOPFUNC int (*)(void *)
100 struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
101 {VOPPREF(default_desc), (VOPFUNC)vn_default_error},
102 {VOPPREF(lookup_desc), (VOPFUNC)afs_vop_lookup}, /* lookup */
103 {VOPPREF(create_desc), (VOPFUNC)afs_vop_create}, /* create */
104 {VOPPREF(mknod_desc), (VOPFUNC)afs_vop_mknod}, /* mknod */
105 {VOPPREF(open_desc), (VOPFUNC)afs_vop_open}, /* open */
106 {VOPPREF(close_desc), (VOPFUNC)afs_vop_close}, /* close */
107 {VOPPREF(access_desc), (VOPFUNC)afs_vop_access}, /* access */
108 {VOPPREF(getattr_desc), (VOPFUNC)afs_vop_getattr}, /* getattr */
109 {VOPPREF(setattr_desc), (VOPFUNC)afs_vop_setattr}, /* setattr */
110 {VOPPREF(read_desc), (VOPFUNC)afs_vop_read}, /* read */
111 {VOPPREF(write_desc), (VOPFUNC)afs_vop_write}, /* write */
112 {VOPPREF(pagein_desc), (VOPFUNC)afs_vop_pagein}, /* read */
113 {VOPPREF(pageout_desc), (VOPFUNC)afs_vop_pageout}, /* write */
114 {VOPPREF(ioctl_desc), (VOPFUNC)afs_vop_ioctl}, /* XXX ioctl */
115 {VOPPREF(select_desc), (VOPFUNC)afs_vop_select}, /* select */
116 {VOPPREF(mmap_desc), (VOPFUNC)afs_vop_mmap}, /* mmap */
117 {VOPPREF(fsync_desc), (VOPFUNC)afs_vop_fsync}, /* fsync */
118 #ifndef AFS_DARWIN80_ENV
119 {VOPPREF(seek_desc), (VOPFUNC)afs_vop_seek}, /* seek */
121 {VOPPREF(remove_desc), (VOPFUNC)afs_vop_remove}, /* remove */
122 {VOPPREF(link_desc), (VOPFUNC)afs_vop_link}, /* link */
123 {VOPPREF(rename_desc), (VOPFUNC)afs_vop_rename}, /* rename */
124 {VOPPREF(mkdir_desc), (VOPFUNC)afs_vop_mkdir}, /* mkdir */
125 {VOPPREF(rmdir_desc), (VOPFUNC)afs_vop_rmdir}, /* rmdir */
126 {VOPPREF(symlink_desc), (VOPFUNC)afs_vop_symlink}, /* symlink */
127 {VOPPREF(readdir_desc), (VOPFUNC)afs_vop_readdir}, /* readdir */
128 {VOPPREF(readlink_desc), (VOPFUNC)afs_vop_readlink}, /* readlink */
129 #ifndef AFS_DARWIN80_ENV
130 {VOPPREF(abortop_desc), (VOPFUNC)nop_abortop }, /* abortop */
132 {VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive}, /* inactive */
133 {VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim}, /* reclaim */
134 #ifndef AFS_DARWIN80_ENV
135 {VOPPREF(lock_desc), (VOPFUNC)afs_vop_lock}, /* lock */
136 {VOPPREF(unlock_desc), (VOPFUNC)afs_vop_unlock}, /* unlock */
137 {VOPPREF(bmap_desc), (VOPFUNC)afs_vop_bmap}, /* bmap */
139 #ifdef AFS_DARWIN80_ENV
140 {VOPPREF(strategy_desc), (VOPFUNC)err_strategy}, /* strategy */
142 {VOPPREF(strategy_desc), (VOPFUNC)afs_vop_strategy}, /* strategy */
144 #ifndef AFS_DARWIN80_ENV
145 {VOPPREF(print_desc), (VOPFUNC)afs_vop_print}, /* print */
146 {VOPPREF(islocked_desc), (VOPFUNC)afs_vop_islocked}, /* islocked */
148 {VOPPREF(pathconf_desc), (VOPFUNC)afs_vop_pathconf}, /* pathconf */
149 {VOPPREF(advlock_desc), (VOPFUNC)afs_vop_advlock}, /* advlock */
150 #ifndef AFS_DARWIN80_ENV
151 {VOPPREF(blkatoff_desc), (VOPFUNC)afs_vop_blkatoff}, /* blkatoff */
152 {VOPPREF(valloc_desc), (VOPFUNC)afs_vop_valloc}, /* valloc */
153 {VOPPREF(reallocblks_desc), (VOPFUNC)afs_vop_reallocblks}, /* reallocblks */
154 {VOPPREF(vfree_desc), (VOPFUNC)afs_vop_vfree}, /* vfree */
155 {VOPPREF(update_desc), (VOPFUNC)afs_vop_update}, /* update */
156 {VOPPREF(cmap_desc), (VOPFUNC)afs_vop_cmap}, /* cmap */
157 {VOPPREF(truncate_desc), (VOPFUNC)afs_vop_truncate}, /* truncate */
159 {VOPPREF(blktooff_desc), (VOPFUNC)afs_vop_blktooff}, /* blktooff */
160 {VOPPREF(offtoblk_desc), (VOPFUNC)afs_vop_offtoblk}, /* offtoblk */
161 {VOPPREF(bwrite_desc), (VOPFUNC)vn_bwrite},
162 {NULL, (void (*)())NULL}
164 struct vnodeopv_desc afs_vnodeop_opv_desc =
165 { &afs_vnodeop_p, afs_vnodeop_entries };
167 #ifdef AFS_DARWIN80_ENV
168 /* vfs structures for incompletely initialized vnodes */
169 int (**afs_dead_vnodeop_p) ();
171 struct vnodeopv_entry_desc afs_dead_vnodeop_entries[] = {
172 {VOPPREF(default_desc), (VOPFUNC)vn_default_error},
173 {VOPPREF(lookup_desc), (VOPFUNC)vn_default_error}, /* lookup */
174 {VOPPREF(create_desc), (VOPFUNC)err_create}, /* create */
175 {VOPPREF(mknod_desc), (VOPFUNC)err_mknod}, /* mknod */
176 {VOPPREF(open_desc), (VOPFUNC)err_open}, /* open */
177 {VOPPREF(close_desc), (VOPFUNC)err_close}, /* close */
178 {VOPPREF(access_desc), (VOPFUNC)err_access}, /* access */
179 {VOPPREF(getattr_desc), (VOPFUNC)err_getattr}, /* getattr */
180 {VOPPREF(setattr_desc), (VOPFUNC)err_setattr}, /* setattr */
181 {VOPPREF(read_desc), (VOPFUNC)err_read}, /* read */
182 {VOPPREF(write_desc), (VOPFUNC)err_write}, /* write */
183 {VOPPREF(pagein_desc), (VOPFUNC)err_pagein}, /* read */
184 {VOPPREF(pageout_desc), (VOPFUNC)err_pageout}, /* write */
185 {VOPPREF(ioctl_desc), (VOPFUNC)err_ioctl}, /* XXX ioctl */
186 {VOPPREF(select_desc), (VOPFUNC)nop_select}, /* select */
187 {VOPPREF(mmap_desc), (VOPFUNC)err_mmap}, /* mmap */
188 {VOPPREF(fsync_desc), (VOPFUNC)err_fsync}, /* fsync */
189 {VOPPREF(remove_desc), (VOPFUNC)err_remove}, /* remove */
190 {VOPPREF(link_desc), (VOPFUNC)err_link}, /* link */
191 {VOPPREF(rename_desc), (VOPFUNC)err_rename}, /* rename */
192 {VOPPREF(mkdir_desc), (VOPFUNC)err_mkdir}, /* mkdir */
193 {VOPPREF(rmdir_desc), (VOPFUNC)err_rmdir}, /* rmdir */
194 {VOPPREF(symlink_desc), (VOPFUNC)err_symlink}, /* symlink */
195 {VOPPREF(readdir_desc), (VOPFUNC)err_readdir}, /* readdir */
196 {VOPPREF(readlink_desc), (VOPFUNC)err_readlink}, /* readlink */
197 {VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive}, /* inactive */
198 {VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim}, /* reclaim */
199 {VOPPREF(strategy_desc), (VOPFUNC)err_strategy}, /* strategy */
200 {VOPPREF(pathconf_desc), (VOPFUNC)err_pathconf}, /* pathconf */
201 {VOPPREF(advlock_desc), (VOPFUNC)err_advlock}, /* advlock */
202 {VOPPREF(blktooff_desc), (VOPFUNC)err_blktooff}, /* blktooff */
203 {VOPPREF(offtoblk_desc), (VOPFUNC)err_offtoblk}, /* offtoblk */
204 {VOPPREF(bwrite_desc), (VOPFUNC)err_bwrite},
205 {NULL, (void (*)())NULL}
207 struct vnodeopv_desc afs_dead_vnodeop_opv_desc =
208 { &afs_dead_vnodeop_p, afs_dead_vnodeop_entries };
212 struct componentname *cnp = ap->a_cnp; \
214 MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
215 memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
216 name[cnp->cn_namelen] = '\0'
218 #define DROPNAME() FREE(name, M_TEMP)
221 darwin_vn_hold(struct vnode *vp)
223 int haveGlock=ISAFS_GLOCK();
224 struct vcache *tvc = VTOAFS(vp);
226 #ifndef AFS_DARWIN80_ENV
227 tvc->f.states |= CUBCinit;
229 #ifdef AFS_DARWIN80_ENV
230 osi_Assert((tvc->f.states & CVInit) == 0);
231 if (tvc->f.states & CDeadVnode)
232 osi_Assert(!vnode_isinuse(vp, 1));
234 if (haveGlock) AFS_GUNLOCK();
236 #ifdef AFS_DARWIN80_ENV
238 /* being terminated. kernel won't give us a ref. Now what? our
239 callers don't expect us to fail */
240 if (haveGlock) AFS_GLOCK();
245 if (haveGlock) AFS_GLOCK();
250 /* vget needed for 0 ref'd vnode in GetVCache to not panic in vref.
251 vref needed for multiref'd vnode in vnop_remove not to deadlock
252 ourselves during vop_inactive, except we also need to not reinst
253 the ubc... so we just call VREF there now anyway. */
255 if (VREFCOUNT_GT(tvc, 0))
256 VREF(((struct vnode *)(vp)));
258 afs_vget(afs_globalVFS, 0, (vp));
261 #ifndef AFS_DARWIN80_ENV
262 if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
267 if (haveGlock) AFS_GLOCK();
268 #ifndef AFS_DARWIN80_ENV
269 tvc->f.states &= ~CUBCinit;
274 struct VOPPROT(lookup_args)/* {
275 * struct vnodeop_desc * a_desc;
276 * struct vnode *a_dvp;
277 * struct vnode **a_vpp;
278 * struct componentname *a_cnp;
283 struct vnode *vp, *dvp;
284 int flags = ap->a_cnp->cn_flags;
285 int lockparent; /* 1 => lockparent flag is set */
286 int wantparent; /* 1 => wantparent or lockparent flag */
288 #ifdef AFS_DARWIN80_ENV
289 vcp = VTOAFS(ap->a_dvp);
291 * ._ file attribute mirroring touches this.
292 * we can't flag the vcache as there is none, so fail here.
293 * needed for fsevents support.
295 if (ap->a_context == afs_osi_ctxtp)
297 if (vcp->mvstat != 1) {
298 error = cache_lookup(ap->a_dvp, ap->a_vpp, ap->a_cnp);
309 lockparent = flags & LOCKPARENT;
310 wantparent = flags & (LOCKPARENT | WANTPARENT);
312 if (!vnode_isdir(ap->a_dvp)) {
318 #ifndef AFS_DARWIN80_ENV
319 if (flags & ISDOTDOT)
320 VOP_UNLOCK(dvp, 0, p);
323 error = afs_lookup(VTOAFS(dvp), name, &vcp, vop_cn_cred);
326 #ifndef AFS_DARWIN80_ENV
327 if (flags & ISDOTDOT)
328 VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
330 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
331 && (flags & ISLASTCN) && error == ENOENT)
333 #ifndef AFS_DARWIN80_ENV
334 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
335 cnp->cn_flags |= SAVENAME;
341 #ifdef AFS_DARWIN80_ENV
342 if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0))) {
348 vp = AFSTOV(vcp); /* always get a node if no error */
349 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
350 vp->v_vfsp = dvp->v_vfsp;
352 if (UBCINFOMISSING(vp) ||
353 UBCINFORECLAIMED(vp)) {
358 #ifndef AFS_DARWIN80_ENV
359 /* The parent directory comes in locked. We unlock it on return
360 * unless the caller wants it left locked.
361 * we also always return the vnode locked. */
363 if (flags & ISDOTDOT) {
364 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
365 /* always return the child locked */
366 if (lockparent && (flags & ISLASTCN)
367 && (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
372 } else if (vp == dvp) {
373 /* they're the same; afs_lookup() already ref'ed the leaf.
374 * It came in locked, so we don't need to ref OR lock it */
376 if (!lockparent || !(flags & ISLASTCN))
377 VOP_UNLOCK(dvp, 0, p); /* done with parent. */
378 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
379 /* always return the child locked */
384 #ifndef AFS_DARWIN80_ENV
385 if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)
386 || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))))
387 cnp->cn_flags |= SAVENAME;
396 struct VOPPROT(create_args) /* {
397 * struct vnode *a_dvp;
398 * struct vnode **a_vpp;
399 * struct componentname *a_cnp;
400 * struct vattr *a_vap;
405 struct vnode *dvp = ap->a_dvp;
410 /* vnode layer handles excl/nonexcl */
413 afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
417 #ifndef AFS_DARWIN80_ENV
418 VOP_ABORTOP(dvp, cnp);
426 #ifdef AFS_DARWIN80_ENV
427 if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0))) {
433 *ap->a_vpp = AFSTOV(vcp);
434 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
435 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
436 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
437 if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
438 vcp->f.states |= CUBCinit;
439 ubc_info_init(*ap->a_vpp);
440 vcp->f.states &= ~CUBCinit;
446 #ifndef AFS_DARWIN80_ENV
447 if ((cnp->cn_flags & SAVESTART) == 0)
448 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
457 struct VOPPROT(mknod_args) /* {
458 * struct vnode *a_dvp;
459 * struct vnode **a_vpp;
460 * struct componentname *a_cnp;
461 * struct vattr *a_vap;
464 #ifndef AFS_DARWIN80_ENV
465 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
473 struct VOPPROT(open_args) /* {
474 * struct vnode *a_vp;
476 * struct ucred *a_cred;
481 struct vnode *vp = ap->a_vp;
482 struct vcache *vc = VTOAFS(vp);
483 #if !defined(AFS_DARWIN80_ENV)
485 /*----------------------------------------------------------------
486 * osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
487 * can later be passed to vn_open(), which will skip the call to
488 * ubc_hold(), and when the ubcinfo is later added, the ui_refcount
489 * will be off. So we compensate by calling ubc_hold() ourselves
490 * when ui_refcount is less than 2. If an error occurs in afs_open()
491 * we must call ubc_rele(), which is what vn_open() would do if it
492 * was able to call ubc_hold() in the first place.
493 *----------------------------------------------------------------*/
494 if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
495 && vp->v_ubcinfo->ui_refcount < 2)
496 didhold = ubc_hold(vp);
497 #endif /* !AFS_DARWIN80_ENV */
499 error = afs_open(&vc, ap->a_mode, vop_cred);
501 if (AFSTOV(vc) != vp)
502 panic("AFS open changed vnode!");
504 osi_FlushPages(vc, vop_cred);
506 #if !defined(AFS_DARWIN80_ENV)
507 if (error && didhold)
509 #endif /* !AFS_DARWIN80_ENV */
515 struct VOPPROT(close_args) /* {
516 * struct vnode *a_vp;
518 * struct ucred *a_cred;
523 struct vnode *vp = ap->a_vp;
524 struct vcache *avc = VTOAFS(vp);
525 /* allows faking FSE_CONTENT_MODIFIED */
526 if (afs_osi_ctxtp == ap->a_context)
530 code = afs_close(avc, ap->a_fflag, vop_cred);
532 code = afs_close(avc, ap->a_fflag, &afs_osi_cred);
533 osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
534 /* This is legit; it just forces the fstrace event to happen */
535 code = afs_CheckCode(code, NULL, 60);
541 #ifdef AFS_DARWIN80_ENV
542 extern int afs_fakestat_enable;
546 struct VOPPROT(access_args) /* {
547 * struct vnode *a_vp;
549 * vfs_context_t a_context;
553 struct vrequest treq;
554 struct afs_fakestat_state fakestate;
555 struct vcache * tvc = VTOAFS(ap->a_vp);
557 int cmb = CHECK_MODE_BITS;
558 #ifdef AFS_DARWIN80_ENV
560 * needed for fsevents. ._ file attribute mirroring touches this.
561 * we can't flag the vcache, as there is none, so fail here.
563 if (ap->a_context == afs_osi_ctxtp)
567 afs_InitFakeStat(&fakestate);
568 if ((code = afs_InitReq(&treq, vop_cred)))
571 code = afs_TryEvalFakeStat(&tvc, &fakestate, &treq);
573 code = afs_CheckCode(code, &treq, 55);
577 code = afs_VerifyVCache(tvc, &treq);
579 code = afs_CheckCode(code, &treq, 56);
582 if (afs_fakestat_enable && tvc->mvstat && !(tvc->f.states & CStatd)) {
586 if (vnode_isdir(ap->a_vp)) {
587 if (ap->a_action & KAUTH_VNODE_LIST_DIRECTORY)
588 bits |= PRSFS_LOOKUP;
589 if (ap->a_action & KAUTH_VNODE_ADD_FILE)
590 bits |= PRSFS_INSERT;
591 if (ap->a_action & KAUTH_VNODE_SEARCH)
592 bits |= PRSFS_LOOKUP;
593 if (ap->a_action & KAUTH_VNODE_DELETE)
594 bits |= PRSFS_DELETE;
595 if (ap->a_action & KAUTH_VNODE_ADD_SUBDIRECTORY)
596 bits |= PRSFS_INSERT;
597 if (ap->a_action & KAUTH_VNODE_DELETE_CHILD)
598 bits |= PRSFS_DELETE;
599 #if 0 /* I'd argue this should be enforced on the parent. But that's ugly */
600 if (ap->a_action & KAUTH_VNODE_READ_ATTRIBUTES)
601 bits |= PRSFS_LOOKUP;
602 if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
603 bits |= PRSFS_LOOKUP;
606 if (ap->a_action & KAUTH_VNODE_READ_DATA)
608 if (ap->a_action & KAUTH_VNODE_WRITE_DATA)
610 if (ap->a_action & KAUTH_VNODE_EXECUTE)
611 bits |= PRSFS_READ; /* and mode bits.... */
612 if (ap->a_action & KAUTH_VNODE_READ_ATTRIBUTES)
613 bits |= PRSFS_LOOKUP;
614 if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
615 bits |= PRSFS_LOOKUP;
616 if ((ap->a_action & ((1 << 25) - 1)) == KAUTH_VNODE_EXECUTE)
617 /* if only exec, don't check for read mode bit */
618 /* high bits of ap->a_action are not for 'generic rights bits', and
619 so should not be checked (KAUTH_VNODE_ACCESS is often present
620 and needs to be masked off) */
621 cmb |= CMB_ALLOW_EXEC_AS_READ;
623 if (ap->a_action & KAUTH_VNODE_WRITE_ATTRIBUTES)
625 #if 0 /* no extended attributes */
626 if (ap->a_action & KAUTH_VNODE_READ_EXTATTRIBUTES)
628 if (ap->a_action & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
631 if (ap->a_action & KAUTH_VNODE_WRITE_SECURITY)
633 /* we can't check for KAUTH_VNODE_TAKE_OWNERSHIP, so we always permit it */
635 code = afs_AccessOK(tvc, bits, &treq, cmb);
637 * Special cased dropbox handling:
638 * cp on 10.4 behaves badly, looping on EACCES
639 * Finder may reopen the file. Let it.
641 if (code == 0 && ((bits &~(PRSFS_READ|PRSFS_WRITE)) == 0))
642 code = afs_AccessOK(tvc, PRSFS_ADMINISTER|PRSFS_INSERT|bits, &treq, cmb);
643 /* Finder also treats dropboxes as insert+delete. fake it out. */
644 if (code == 0 && (bits == (PRSFS_INSERT|PRSFS_DELETE)))
645 code = afs_AccessOK(tvc, PRSFS_INSERT, &treq, cmb);
647 if (code == 1 && vnode_vtype(ap->a_vp) == VREG &&
648 ap->a_action & KAUTH_VNODE_EXECUTE &&
649 (tvc->f.m.Mode & 0100) != 0100) {
653 code= 0; /* if access is ok */
655 code = afs_CheckCode(EACCES, &treq, 57); /* failure code */
658 afs_PutFakeStat(&fakestate);
666 struct VOPPROT(access_args) /* {
667 * struct vnode *a_vp;
669 * struct ucred *a_cred;
675 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, vop_cred);
683 struct VOPPROT(getattr_args) /* {
684 * struct vnode *a_vp;
685 * struct vattr *a_vap;
686 * struct ucred *a_cred;
692 #ifdef AFS_DARWIN80_ENV
693 /* CEvent excludes the fsevent. our context excludes the ._ */
694 if ((VTOAFS(ap->a_vp)->f.states & CEvent) ||
695 (ap->a_context == afs_osi_ctxtp)){
696 struct vcache *avc = VTOAFS(ap->a_vp);
697 int isglock = ISAFS_GLOCK();
699 /* this is needed because of how and when we re-enter */
702 /* do minimal work to return fake result for fsevents */
703 if (afs_fakestat_enable && VTOAFS(ap->a_vp)->mvstat == 1) {
704 struct afs_fakestat_state fakestat;
705 struct vrequest treq;
707 code = afs_InitReq(&treq, vop_cred);
713 afs_InitFakeStat(&fakestat);
715 code = afs_TryEvalFakeStat(&avc, &fakestat, &treq);
719 afs_PutFakeStat(&fakestat);
723 code = afs_CopyOutAttrs(avc, ap->a_vap);
727 /* tweak things so finder will recheck */
728 (ap->a_vap)->va_gid = ((ap->a_vap)->va_gid == 1) ? 2 : 1;
729 (ap->a_vap)->va_mode &= ~(VSGID);
735 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
736 /* This is legit; it just forces the fstrace event to happen */
737 code = afs_CheckCode(code, NULL, 58);
740 #ifdef AFS_DARWIN80_ENV
741 VATTR_SET_SUPPORTED(ap->a_vap, va_type);
742 VATTR_SET_SUPPORTED(ap->a_vap, va_mode);
743 VATTR_SET_SUPPORTED(ap->a_vap, va_uid);
744 VATTR_SET_SUPPORTED(ap->a_vap, va_gid);
745 VATTR_SET_SUPPORTED(ap->a_vap, va_fsid);
746 VATTR_SET_SUPPORTED(ap->a_vap, va_fileid);
747 VATTR_SET_SUPPORTED(ap->a_vap, va_nlink);
748 VATTR_SET_SUPPORTED(ap->a_vap, va_data_size);
749 VATTR_SET_SUPPORTED(ap->a_vap, va_access_time);
750 VATTR_SET_SUPPORTED(ap->a_vap, va_modify_time);
751 VATTR_SET_SUPPORTED(ap->a_vap, va_change_time);
752 VATTR_SET_SUPPORTED(ap->a_vap, va_gen);
753 VATTR_SET_SUPPORTED(ap->a_vap, va_flags);
754 VATTR_SET_SUPPORTED(ap->a_vap, va_iosize);
755 VATTR_SET_SUPPORTED(ap->a_vap, va_total_alloc);
762 struct VOPPROT(setattr_args) /* {
763 * struct vnode *a_vp;
764 * struct vattr *a_vap;
765 * struct ucred *a_cred;
770 struct vcache *avc = VTOAFS(ap->a_vp);
771 #ifdef AFS_DARWIN80_ENV
772 /* fsevents tries to set attributes. drop it. */
773 if (ap->a_context == afs_osi_ctxtp)
778 code = afs_setattr(avc, ap->a_vap, vop_cred);
779 /* This is legit; it just forces the fstrace event to happen */
780 code = afs_CheckCode(code, NULL, 59);
781 if (!pass && code == EINVAL && (VATTR_IS_ACTIVE(ap->a_vap, va_mode) &&
782 (vType(avc) == VLNK))) {
783 VATTR_CLEAR_ACTIVE(ap->a_vap, va_mode);
793 struct VOPPROT(read_args) /* {
794 * struct vnode *a_vp;
797 * struct ucred *a_cred;
801 struct vnode *vp = ap->a_vp;
802 struct vcache *avc = VTOAFS(vp);
804 if (vnode_isdir(ap->a_vp))
806 #ifdef AFS_DARWIN80_ENV
807 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);
809 if (UBCINFOEXISTS(ap->a_vp)) {
810 ubc_clean(ap->a_vp, 0);
814 osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
815 code = afs_read(avc, ap->a_uio, vop_cred, 0);
822 struct VOPPROT(pagein_args) /* {
823 * struct vnode *a_vp;
825 * vm_offset_t a_pl_offset;
828 * struct ucred *a_cred;
832 struct vnode *vp = ap->a_vp;
834 size_t size = ap->a_size;
835 off_t f_offset = ap->a_f_offset;
836 vm_offset_t pl_offset = ap->a_pl_offset;
837 int flags = ap->a_flags;
840 #ifdef AFS_DARWIN80_ENV
845 struct uio *uio = &auio;
847 int nocommit = flags & UPL_NOCOMMIT;
850 struct vcache *tvc = VTOAFS(vp);
851 #ifndef AFS_DARWIN80_ENV
852 if (UBCINVALID(vp)) {
854 panic("afs_vop_pagein: invalid vp");
855 #endif /* DIAGNOSTIC */
859 UBCINFOCHECK("afs_vop_pagein", vp);
861 if (pl == (upl_t) NULL) {
862 panic("afs_vop_pagein: no upl");
865 cred = ubc_getcred(vp);
871 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
872 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
877 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
878 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
881 if (f_offset & PAGE_MASK)
882 panic("afs_vop_pagein: offset not page aligned");
884 OSI_UPL_MAP(pl, &ioaddr);
886 #ifdef AFS_DARWIN80_ENV
887 uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
888 uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
890 auio.uio_iov = &aiov;
892 auio.uio_offset = f_offset;
893 auio.uio_segflg = UIO_SYSSPACE;
894 auio.uio_rw = UIO_READ;
895 auio.uio_procp = NULL;
896 auio.uio_resid = aiov.iov_len = size;
897 aiov.iov_base = (caddr_t) ioaddr;
900 osi_FlushPages(tvc, vop_cred); /* hold bozon lock, but not basic vnode lock */
901 code = afs_read(tvc, uio, cred, 0);
903 ObtainWriteLock(&tvc->lock, 2);
904 tvc->f.states |= CMAPPED;
905 ReleaseWriteLock(&tvc->lock);
909 /* Zero out rest of last page if there wasn't enough data in the file */
910 if (code == 0 && AFS_UIO_RESID(uio) > 0) {
911 #ifdef AFS_DARWIN80_ENV
912 memset(((caddr_t)ioaddr) + (size - AFS_UIO_RESID(uio)), 0,
915 memset(aiov.iov_base, 0, auio.uio_resid);
922 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
923 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
925 OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
926 UPL_COMMIT_CLEAR_DIRTY |
927 UPL_COMMIT_FREE_ON_EMPTY);
929 #ifdef AFS_DARWIN80_ENV
937 struct VOPPROT(write_args) /* {
938 * struct vnode *a_vp;
941 * struct ucred *a_cred;
945 struct vcache *avc = VTOAFS(ap->a_vp);
947 #ifdef AFS_DARWIN80_ENV
948 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);
950 if (UBCINFOEXISTS(ap->a_vp)) {
951 ubc_clean(ap->a_vp, 1);
953 if (UBCINFOEXISTS(ap->a_vp))
954 osi_VM_NukePages(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio),
955 AFS_UIO_RESID(ap->a_uio));
958 osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
960 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, vop_cred, 0);
967 struct VOPPROT(pageout_args) /* {
968 * struct vnode *a_vp;
970 * vm_offset_t a_pl_offset,
973 * struct ucred *a_cred,
977 struct vnode *vp = ap->a_vp;
979 size_t size = ap->a_size;
980 off_t f_offset = ap->a_f_offset;
981 vm_offset_t pl_offset = ap->a_pl_offset;
982 int flags = ap->a_flags;
985 #ifdef AFS_DARWIN80_ENV
990 struct uio *uio = &auio;
992 int nocommit = flags & UPL_NOCOMMIT;
996 struct vcache *tvc = VTOAFS(vp);
997 #ifndef AFS_DARWIN80_ENV
998 if (UBCINVALID(vp)) {
1000 panic("afs_vop_pageout: invalid vp");
1001 #endif /* DIAGNOSTIC */
1005 UBCINFOCHECK("afs_vop_pageout", vp);
1007 if (pl == (upl_t) NULL) {
1008 panic("afs_vop_pageout: no upl");
1010 #if !defined(AFS_DARWIN80_ENV) /* XXX nfs now uses it's own bufs (struct nfsbuf)
1012 layer doesn't have them anymore? In any case,
1013 we can't just copy code from nfs... */
1017 int biosize = DEV_BSIZE;
1019 lbn = f_offset / DEV_BSIZE;
1021 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
1024 if (bp = incore(vp, lbn)) {
1025 if (ISSET(bp->b_flags, B_BUSY))
1026 panic("nfs_pageout: found BUSY buffer incore\n");
1029 SET(bp->b_flags, (B_BUSY | B_INVAL));
1036 cred = ubc_getcred(vp);
1042 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1043 UPL_ABORT_FREE_ON_EMPTY);
1046 if (flags & (IO_APPEND | IO_SYNC))
1047 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
1050 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1051 UPL_ABORT_FREE_ON_EMPTY);
1054 if (f_offset >= tvc->f.m.Length) {
1056 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1057 UPL_ABORT_FREE_ON_EMPTY);
1061 if (f_offset & PAGE_MASK)
1062 panic("afs_vop_pageout: offset not page aligned");
1064 /* size will always be a multiple of PAGE_SIZE */
1065 /* pageout isn't supposed to extend files */
1066 if (f_offset + size > tvc->f.m.Length)
1067 iosize = tvc->f.m.Length - f_offset;
1071 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
1072 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
1073 OSI_UPL_ABORT_RANGE(pl, pl_offset + iosize_rnd,
1075 UPL_ABORT_FREE_ON_EMPTY);
1077 OSI_UPL_MAP(pl, &ioaddr);
1078 ioaddr += pl_offset;
1079 #ifdef AFS_DARWIN80_ENV
1080 uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
1081 uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
1083 auio.uio_iov = &aiov;
1084 auio.uio_iovcnt = 1;
1085 auio.uio_offset = f_offset;
1086 auio.uio_segflg = UIO_SYSSPACE;
1087 auio.uio_rw = UIO_WRITE;
1088 auio.uio_procp = NULL;
1089 auio.uio_resid = aiov.iov_len = iosize;
1090 aiov.iov_base = (caddr_t) ioaddr;
1094 * check for partial page and clear the
1095 * contents past end of the file before
1096 * releasing it in the VM page cache
1098 if ((f_offset < tvc->f.m.Length) && (f_offset + size) > tvc->f.m.Length) {
1099 size_t io = tvc->f.m.Length - f_offset;
1101 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
1106 osi_FlushPages(tvc, vop_cred); /* hold bozon lock, but not basic vnode lock */
1107 ObtainWriteLock(&tvc->lock, 1);
1109 ReleaseWriteLock(&tvc->lock);
1111 code = afs_write(tvc, uio, flags, cred, 0);
1113 ObtainWriteLock(&tvc->lock, 1);
1114 afs_FakeClose(tvc, cred);
1115 ReleaseWriteLock(&tvc->lock);
1120 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1121 UPL_ABORT_FREE_ON_EMPTY);
1123 OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
1124 UPL_COMMIT_CLEAR_DIRTY |
1125 UPL_COMMIT_FREE_ON_EMPTY);
1128 #ifdef AFS_DARWIN80_ENV
1136 struct VOPPROT(ioctl_args) /* {
1137 * struct vnode *a_vp;
1141 * struct ucred *a_cred;
1145 struct vcache *tvc = VTOAFS(ap->a_vp);
1146 struct afs_ioctl data;
1149 /* in case we ever get in here... */
1151 AFS_STATCNT(afs_ioctl);
1152 if (((ap->a_command >> 8) & 0xff) == 'V') {
1153 /* This is a VICEIOCTL call */
1155 error = HandleIoctl(tvc, ap->a_command, ap->a_data);
1159 /* No-op call; just return. */
1167 struct VOPPROT(select_args) /* {
1168 * struct vnode *a_vp;
1171 * struct ucred *a_cred;
1176 * We should really check to see if I/O is possible.
1184 * NB Currently unsupported.
1189 struct VOPPROT(mmap_args) /* {
1190 * struct vnode *a_vp;
1192 * struct ucred *a_cred;
1201 struct VOPPROT(fsync_args) /* {
1202 * struct vnode *a_vp;
1203 * struct ucred *a_cred;
1208 int wait = ap->a_waitfor == MNT_WAIT;
1210 struct vnode *vp = ap->a_vp;
1211 int haveGlock = ISAFS_GLOCK();
1213 /* in order to recycle faked vnodes for bulkstat */
1214 if (VTOAFS(vp) == NULL)
1217 /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
1218 if (!haveGlock) AFS_GLOCK();
1220 error = afs_fsync(VTOAFS(vp), vop_cred);
1222 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
1223 if (!haveGlock) AFS_GUNLOCK();
1227 #ifndef AFS_DARWIN80_ENV
1230 struct VOPPROT(seek_args) /* {
1231 * struct vnode *a_vp;
1234 * struct ucred *a_cred;
1237 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
1245 struct VOPPROT(remove_args) /* {
1246 * struct vnode *a_dvp;
1247 * struct vnode *a_vp;
1248 * struct componentname *a_cnp;
1252 struct vnode *vp = ap->a_vp;
1253 struct vnode *dvp = ap->a_dvp;
1255 #ifdef AFS_DARWIN80_ENV
1256 if (ap->a_flags & VNODE_REMOVE_NODELETEBUSY) {
1257 /* Caller requested Carbon delete semantics */
1258 if (vnode_isinuse(vp, 0)) {
1266 error = afs_remove(VTOAFS(dvp), name, vop_cn_cred);
1267 error = afs_CheckCode(error, NULL, 61);
1271 #ifdef AFS_DARWIN80_ENV
1272 struct vcache *tvc = VTOAFS(vp);
1274 if (!(tvc->f.states & CUnlinked)) {
1275 ubc_setsize(vp, (off_t)0);
1279 /* necessary so we don't deadlock ourselves in vclean */
1280 VOP_UNLOCK(vp, 0, cnp->cn_proc);
1282 /* If crashes continue in ubc_hold, comment this out */
1283 (void)ubc_uncache(vp);
1286 /* should check for PRSFS_INSERT and not PRSFS_DELETE, but the
1287 goal here is to deal with Finder's unhappiness with resource
1288 forks that have no resources in a dropbox setting */
1289 if (name[0] == '.' && name[1] == '_' && error == EACCES)
1293 #ifndef AFS_DARWIN80_ENV
1301 #ifndef AFS_DARWIN80_ENV
1302 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1310 struct VOPPROT(link_args) /* {
1311 * struct vnode *a_vp;
1312 * struct vnode *a_tdvp;
1313 * struct componentname *a_cnp;
1317 struct vnode *dvp = ap->a_tdvp;
1318 struct vnode *vp = ap->a_vp;
1323 if (vnode_isdir(vp)) {
1324 VOP_ABORTOP(vp, cnp);
1328 #ifndef AFS_DARWIN80_ENV
1329 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
1330 VOP_ABORTOP(dvp, cnp);
1335 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, vop_cn_cred);
1337 #ifndef AFS_DARWIN80_ENV
1338 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1340 #ifndef AFS_DARWIN80_ENV
1342 VOP_UNLOCK(vp, 0, p);
1345 #ifndef AFS_DARWIN80_ENV
1354 struct VOPPROT(rename_args) /* {
1355 * struct vnode *a_fdvp;
1356 * struct vnode *a_fvp;
1357 * struct componentname *a_fcnp;
1358 * struct vnode *a_tdvp;
1359 * struct vnode *a_tvp;
1360 * struct componentname *a_tcnp;
1364 struct componentname *fcnp = ap->a_fcnp;
1366 struct componentname *tcnp = ap->a_tcnp;
1368 struct vnode *tvp = ap->a_tvp;
1369 struct vnode *tdvp = ap->a_tdvp;
1370 struct vnode *fvp = ap->a_fvp;
1371 struct vnode *fdvp = ap->a_fdvp;
1376 #ifdef AFS_DARWIN80_ENV
1378 * generic code tests for v_mount equality, so we don't have to, but we
1379 * don't get the multiple-mount "benefits" of the old behavior
1380 * the generic code doesn't do this, so we really should, but all the
1381 * vrele's are wrong...
1384 /* Check for cross-device rename.
1385 * For AFS, this means anything not in AFS-space
1387 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
1388 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
1394 * if fvp == tvp, we're just removing one name of a pair of
1395 * directory entries for the same element. convert call into rename.
1396 ( (pinched from NetBSD 1.0's ufs_rename())
1399 if (vnode_isdir(fvp)) {
1402 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
1409 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
1415 /* Release destination completely. */
1416 VOP_ABORTOP(tdvp, tcnp);
1419 /* Delete source. */
1422 fcnp->cn_flags &= ~MODMASK;
1423 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1424 if ((fcnp->cn_flags & SAVESTART) == 0)
1425 panic("afs_rename: lost from startdir");
1426 fcnp->cn_nameiop = DELETE;
1429 error=relookup(fdvp, &fvp, fcnp);
1435 error=VOP_REMOVE(fdvp, fvp, fcnp);
1444 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1448 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1449 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1450 fname[fcnp->cn_namelen] = '\0';
1451 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1452 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1453 tname[tcnp->cn_namelen] = '\0';
1457 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1459 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, cn_cred(tcnp));
1461 #if !defined(AFS_DARWIN80_ENV)
1463 VOP_UNLOCK(fvp, 0, p);
1465 goto abortit; /* XXX */
1475 if (error == EXDEV) {
1476 struct brequest *tb;
1477 struct afs_uspc_param mvReq;
1479 struct vcache *fvc = VTOAFS(fdvp);
1481 struct afs_fakestat_state fakestate;
1482 int fakestatdone = 0;
1486 /* unrewritten mount point? */
1487 if (tvc->mvstat == 1) {
1488 if (tvc->mvid && (tvc->f.states & CMValid)) {
1489 struct vrequest treq;
1491 afs_InitFakeStat(&fakestate);
1492 code = afs_InitReq(&treq, vop_cred);
1495 code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
1497 afs_PutFakeStat(&fakestate);
1502 /* at some point in the future we should allow other types */
1503 mvReq.reqtype = AFS_USPC_UMV;
1504 mvReq.req.umv.id = afs_cr_uid(cn_cred(tcnp));
1505 mvReq.req.umv.idtype = IDTYPE_UID;
1506 mvReq.req.umv.sCell = fvc->f.fid.Cell;
1507 mvReq.req.umv.sVolume = fvc->f.fid.Fid.Volume;
1508 mvReq.req.umv.sVnode = fvc->f.fid.Fid.Vnode;
1509 mvReq.req.umv.sUnique = fvc->f.fid.Fid.Unique;
1510 mvReq.req.umv.dCell = tvc->f.fid.Cell;
1511 mvReq.req.umv.dVolume = tvc->f.fid.Fid.Volume;
1512 mvReq.req.umv.dVnode = tvc->f.fid.Fid.Vnode;
1513 mvReq.req.umv.dUnique = tvc->f.fid.Fid.Unique;
1516 * su %d -c mv /afs/.:mount/%d:%d:%d:%d/%s
1517 * /afs/.:mount/%d:%d:%d:%d/%s where:
1518 * mvReq.req.umv.id, fvc->f.fid.Cell, fvc->f.fid.Fid.Volume,
1519 * fvc->f.fid.Fid.Vnode, fvc->f.fid.Fid.Unique, fname,
1520 * tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode,
1521 * tvc->f.fid.Fid.Unique, tname
1524 tb = afs_BQueue(BOP_MOVE, NULL, 0, 1, cn_cred(tcnp),
1525 0L, 0L, &mvReq, fname, tname);
1526 /* wait to collect result */
1527 while ((tb->flags & BUVALID) == 0) {
1528 tb->flags |= BUWAIT;
1531 /* if we succeeded, clear the error. otherwise, EXDEV */
1532 if (mvReq.retval == 0)
1539 afs_PutFakeStat(&fakestate);
1553 cache_enter(tdvp, fvp, tcnp);
1555 FREE(fname, M_TEMP);
1556 FREE(tname, M_TEMP);
1562 struct VOPPROT(mkdir_args) /* {
1563 * struct vnode *a_dvp;
1564 * struct vnode **a_vpp;
1565 * struct componentname *a_cnp;
1566 * struct vattr *a_vap;
1569 struct vnode *dvp = ap->a_dvp;
1570 struct vattr *vap = ap->a_vap;
1577 #if defined(DIAGNOSTIC) && !defined(AFS_DARWIN80_ENV)
1578 if ((cnp->cn_flags & HASBUF) == 0)
1579 panic("afs_vop_mkdir: no name");
1582 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, vop_cn_cred);
1585 #ifndef AFS_DARWIN80_ENV
1586 VOP_ABORTOP(dvp, cnp);
1593 #ifdef AFS_DARWIN80_ENV
1594 afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0);
1596 *ap->a_vpp = AFSTOV(vcp);
1597 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
1598 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1599 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1604 #ifndef AFS_DARWIN80_ENV
1605 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1613 struct VOPPROT(rmdir_args) /* {
1614 * struct vnode *a_dvp;
1615 * struct vnode *a_vp;
1616 * struct componentname *a_cnp;
1620 struct vnode *vp = ap->a_vp;
1621 struct vnode *dvp = ap->a_dvp;
1625 #ifndef AFS_DARWIN80_ENV
1628 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1635 error = afs_rmdir(VTOAFS(dvp), name, vop_cn_cred);
1640 #ifndef AFS_DARWIN80_ENV
1649 struct VOPPROT(symlink_args) /* {
1650 * struct vnode *a_dvp;
1651 * struct vnode **a_vpp;
1652 * struct componentname *a_cnp;
1653 * struct vattr *a_vap;
1657 struct vnode *dvp = ap->a_dvp;
1659 /* NFS ignores a_vpp; so do we. */
1664 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, vop_cn_cred);
1667 #ifndef AFS_DARWIN80_ENV
1668 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1676 struct VOPPROT(readdir_args) /* {
1677 * struct vnode *a_vp;
1678 * struct uio *a_uio;
1679 * struct ucred *a_cred;
1681 * u_long *a_cookies;
1687 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1689 #ifdef AFS_DARWIN80_ENV
1690 /* too much work for now */
1691 /* should only break nfs exports */
1692 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1695 off = AFS_UIO_OFFSET(ap->a_uio);
1698 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, vop_cred, ap->a_eofflag);
1700 #ifndef AFS_DARWIN80_ENV
1701 if (!error && ap->a_ncookies != NULL) {
1702 struct uio *uio = ap->a_uio;
1703 const struct dirent *dp, *dp_start, *dp_end;
1705 u_long *cookies, *cookiep;
1707 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1708 panic("afs_readdir: burned cookies");
1709 dp = (const struct dirent *)
1710 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1712 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1713 for (dp_start = dp, ncookies = 0; dp < dp_end;
1714 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1717 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1719 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1720 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1721 off += dp->d_reclen;
1724 *ap->a_cookies = cookies;
1725 *ap->a_ncookies = ncookies;
1733 afs_vop_readlink(ap)
1734 struct VOPPROT(readlink_args) /* {
1735 * struct vnode *a_vp;
1736 * struct uio *a_uio;
1737 * struct ucred *a_cred;
1741 /* printf("readlink %x\n", ap->a_vp);*/
1743 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, vop_cred);
1748 extern int prtactive;
1751 afs_vop_inactive(ap)
1752 struct VOPPROT(inactive_args) /* {
1753 * struct vnode *a_vp;
1757 struct vnode *vp = ap->a_vp;
1758 struct vcache *tvc = VTOAFS(vp);
1759 #ifndef AFS_DARWIN80_ENV
1760 if (prtactive && vp->v_usecount != 0)
1761 vprint("afs_vop_inactive(): pushing active", vp);
1764 #ifdef AFS_DARWIN80_ENV
1765 int unlinked = tvc->f.states & CUnlinked;
1768 afs_InactiveVCache(tvc, 0); /* decrs ref counts */
1770 #ifdef AFS_DARWIN80_ENV
1777 #ifndef AFS_DARWIN80_ENV
1778 VOP_UNLOCK(vp, 0, ap->a_p);
1785 struct VOPPROT(reclaim_args) /* {
1786 * struct vnode *a_vp;
1790 int sl, writelocked;
1791 struct vnode *vp = ap->a_vp;
1792 struct vcache *tvc = VTOAFS(vp);
1794 osi_Assert(!ISAFS_GLOCK());
1795 cache_purge(vp); /* just in case... */
1798 writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335));
1800 ObtainWriteLock(&afs_xvreclaim, 176);
1801 #ifdef AFS_DARWIN80_ENV
1802 vnode_clearfsnode(AFSTOV(tvc));
1803 vnode_removefsref(AFSTOV(tvc));
1805 tvc->v->v_data = NULL; /* remove from vnode */
1807 AFSTOV(tvc) = NULL; /* also drop the ptr to vnode */
1808 tvc->f.states |= CVInit; /* also CDeadVnode? */
1809 tvc->nextfree = ReclaimedVCList;
1810 ReclaimedVCList = tvc;
1811 ReleaseWriteLock(&afs_xvreclaim);
1813 error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */
1814 if (tvc->f.states & (CVInit
1815 #ifdef AFS_DARWIN80_ENV
1819 tvc->f.states &= ~(CVInit
1820 #ifdef AFS_DARWIN80_ENV
1824 afs_osi_Wakeup(&tvc->f.states);
1826 if (!error && vnode_fsnode(vp))
1827 panic("afs_reclaim: vnode not cleaned");
1828 if (!error && (tvc->v != NULL))
1829 panic("afs_reclaim: vcache not cleaned");
1830 ReleaseWriteLock(&afs_xvcache);
1838 * Return POSIX pathconf information applicable to ufs filesystems.
1840 afs_vop_pathconf(ap)
1841 struct VOPPROT(pathconf_args) /* {
1842 * struct vnode *a_vp;
1847 AFS_STATCNT(afs_cntl);
1848 switch (ap->a_name) {
1850 *ap->a_retval = LINK_MAX;
1853 *ap->a_retval = NAME_MAX;
1856 *ap->a_retval = PATH_MAX;
1858 case _PC_CHOWN_RESTRICTED:
1867 case _PC_NAME_CHARS_MAX:
1868 *ap->a_retval = NAME_MAX;
1870 case _PC_CASE_SENSITIVE:
1873 case _PC_CASE_PRESERVING:
1883 * Advisory record locking support (fcntl() POSIX style)
1887 struct VOPPROT(advlock_args) /* {
1888 * struct vnode *a_vp;
1891 * struct flock *a_fl;
1899 #ifdef AFS_DARWIN80_ENV
1903 struct proc *p = current_proc();
1906 cr = *p->p_cred->pc_ucred;
1910 if (ap->a_flags & F_POSIX) {
1911 #ifdef AFS_DARWIN80_ENV
1912 p = (proc_t) ap->a_id;
1915 p = (struct proc *) ap->a_id;
1919 clid = (int)ap->a_id;
1921 if (ap->a_op == F_UNLCK) {
1923 } else if (ap->a_op == F_SETLK && ap->a_flags & F_WAIT) {
1929 error = afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, op, tcr, clid);
1935 afs_vop_blktooff(ap)
1936 struct VOPPROT(blktooff_args) /* {
1937 * struct vnode *a_vp;
1942 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1947 afs_vop_offtoblk(ap)
1948 struct VOPPROT(offtoblk_args) /* {
1949 * struct vnode *a_vp;
1951 * daddr_t *a_lblkno;
1954 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1959 #ifndef AFS_DARWIN80_ENV
1962 struct VOPPROT(lock_args) /* {
1963 * struct vnode *a_vp;
1966 struct vnode *vp = ap->a_vp;
1967 struct vcache *avc = VTOAFS(vp);
1969 if (vp->v_tag == VT_NON)
1972 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1977 struct VOPPROT(unlock_args) /* {
1978 * struct vnode *a_vp;
1981 struct vnode *vp = ap->a_vp;
1982 struct vcache *avc = VTOAFS(vp);
1985 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1991 afs_vop_truncate(ap)
1992 struct VOPPROT(truncate_args) /* {
1993 * struct vnode *a_vp;
1996 * struct ucred *a_cred;
2000 /* printf("stray afs_vop_truncate\n"); */
2006 struct VOPPROT(update_args) /* {
2007 * struct vnode *a_vp;
2008 * struct timeval *a_access;
2009 * struct timeval *a_modify;
2013 /* printf("stray afs_vop_update\n"); */
2019 struct VOPPROT(bmap_args) /* {
2020 * struct vnode *a_vp;
2022 * struct vnode **a_vpp;
2030 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
2033 *ap->a_vpp = ap->a_vp;
2035 if (ap->a_runp != NULL)
2038 if (ap->a_runb != NULL)
2046 afs_vop_strategy(ap)
2047 struct VOPPROT(strategy_args) /* {
2053 error = afs_ustrategy(ap->a_bp);
2060 struct VOPPROT(print_args) /* {
2061 * struct vnode *a_vp;
2064 struct vnode *vp = ap->a_vp;
2065 struct vcache *vc = VTOAFS(ap->a_vp);
2066 int s = vc->f.states;
2067 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
2068 vc->f.fid.Cell, vc->f.fid.Fid.Volume, vc->f.fid.Fid.Vnode,
2069 vc->f.fid.Fid.Unique, vc->opens, vc->execsOrWriters);
2070 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
2071 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
2072 (s & CMAPPED) ? " mapped" : "",
2073 (s & CVFlushed) ? " flush in progress" : "");
2074 if (UBCISVALID(vp)) {
2076 if (UBCINFOEXISTS(vp)) {
2078 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
2079 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
2080 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
2082 printf("does not exist");
2089 afs_vop_islocked(ap)
2090 struct VOPPROT(islocked_args) /* {
2091 * struct vnode *a_vp;
2094 struct vcache *vc = VTOAFS(ap->a_vp);
2095 return lockstatus(&vc->rwlock);
2100 struct VOPPROT(cmap_args) /* {
2101 * struct vnode *a_vp;
2109 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
2110 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
2116 afs_darwin_getnewvnode(struct vcache *avc)
2118 #ifdef AFS_DARWIN80_ENV
2121 struct vnode_fsparam par;
2123 memset(&par, 0, sizeof(struct vnode_fsparam));
2124 par.vnfs_vtype = VNON;
2125 par.vnfs_vops = afs_dead_vnodeop_p;
2126 par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
2127 par.vnfs_mp = afs_globalVFS;
2128 par.vnfs_fsnode = avc;
2130 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &vp);
2135 vnode_recycle(vp); /* terminate as soon as iocount drops */
2136 avc->f.states |= CDeadVnode;
2140 while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &avc->v)) {
2141 /* no vnodes available, force an alloc (limits be damned)! */
2142 printf("failed to get vnode\n");
2144 avc->v->v_data = (void *)avc;
2148 #ifdef AFS_DARWIN80_ENV
2149 /* if this fails, then tvc has been unrefed and may have been freed.
2152 afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp,
2153 struct componentname *cnp, int isroot, int locked)
2158 struct vnode_fsparam par;
2162 ObtainWriteLock(&avc->lock,325);
2166 if (!(avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
2168 #if 0 /* unsupported */
2170 vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
2172 VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
2174 /* Can end up in reclaim... drop GLOCK */
2178 ReleaseWriteLock(&avc->lock);
2184 if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
2185 panic("vcache %p should not be CDeadVnode", avc);
2187 memset(&par, 0, sizeof(struct vnode_fsparam));
2188 par.vnfs_mp = afs_globalVFS;
2189 par.vnfs_vtype = avc->f.m.Type;
2190 par.vnfs_vops = afs_vnodeop_p;
2191 par.vnfs_filesize = avc->f.m.Length;
2192 par.vnfs_fsnode = avc;
2194 if (cnp && (cnp->cn_flags & ISDOTDOT) == 0)
2196 if (!dvp || !cnp || (cnp->cn_flags & MAKEENTRY) == 0)
2197 par.vnfs_flags = VNFS_NOCACHE;
2199 par.vnfs_markroot = 1;
2200 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
2202 vnode_addfsref(nvp);
2203 if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
2204 printf("vcache %p should not be CDeadVnode", avc);
2205 if (avc->v == ovp) {
2206 if (!(avc->f.states & CVInit)) {
2207 vnode_clearfsnode(ovp);
2208 vnode_removefsref(ovp);
2210 /* we're discarding on a fixup. mark for recycle */
2211 if (!(avc->f.states & CDeadVnode))
2215 avc->f.states &=~ CDeadVnode;
2216 /* If we were carrying an extra ref for dirty, hold/push it. */
2217 if (avc->f.ddirty_flags) {
2221 /* If we were carrying an extra ref for shadow, hold/push it. */
2222 if (avc->f.shadow.vnode) {
2227 /* Drop any extra dirty ref on the old vnode */
2228 if (avc->f.ddirty_flags) {
2232 /* Drop any extra shadow ref on the old vnode */
2233 if (avc->f.shadow.vnode) {
2237 /* If it's ref'd still, unmark stat'd to force new lookup */
2238 if ((vnode_vtype(ovp) != avc->f.m.Type) && VREFCOUNT_GT(avc, 1))
2239 avc->f.states &= ~CStatd;
2245 ReleaseWriteLock(&avc->lock);
2247 afs_osi_Wakeup(&avc->f.states);