Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / DARWIN / osi_vnodeops.c
1 /*
2 * Portions Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 */
4 #include <afsconfig.h>
5 #include <afs/param.h>
6
7
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>
13 #include <sys/ubc.h>
14 #include <vfs/vfs_support.h>
15 #ifdef AFS_DARWIN80_ENV
16 #include <sys/vnode_if.h>
17 #include <sys/kauth.h>
18 #endif
19
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)
30 #else
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)),\
38 MAX_UPL_TRANSFER)
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))
41 #endif
42
43 extern char afs_zeros[AFS_ZEROS];
44
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) *);
86 #endif
87
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
94
95 /* Global vfs data structures for AFS. */
96 int (**afs_vnodeop_p) ();
97
98 #define VOPFUNC int (*)(void *)
99
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 */
120 #endif
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 */
131 #endif
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 */
138 #endif
139 #ifdef AFS_DARWIN80_ENV
140 {VOPPREF(strategy_desc), (VOPFUNC)err_strategy}, /* strategy */
141 #else
142 {VOPPREF(strategy_desc), (VOPFUNC)afs_vop_strategy}, /* strategy */
143 #endif
144 #ifndef AFS_DARWIN80_ENV
145 {VOPPREF(print_desc), (VOPFUNC)afs_vop_print}, /* print */
146 {VOPPREF(islocked_desc), (VOPFUNC)afs_vop_islocked}, /* islocked */
147 #endif
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 */
158 #endif
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}
163 };
164 struct vnodeopv_desc afs_vnodeop_opv_desc =
165 { &afs_vnodeop_p, afs_vnodeop_entries };
166
167 #ifdef AFS_DARWIN80_ENV
168 /* vfs structures for incompletely initialized vnodes */
169 int (**afs_dead_vnodeop_p) ();
170
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}
206 };
207 struct vnodeopv_desc afs_dead_vnodeop_opv_desc =
208 { &afs_dead_vnodeop_p, afs_dead_vnodeop_entries };
209 #endif
210
211 #define GETNAME() \
212 struct componentname *cnp = ap->a_cnp; \
213 char *name; \
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'
217
218 #define DROPNAME() FREE(name, M_TEMP)
219
220 void
221 darwin_vn_hold(struct vnode *vp)
222 {
223 int haveGlock=ISAFS_GLOCK();
224 struct vcache *tvc = VTOAFS(vp);
225
226 #ifndef AFS_DARWIN80_ENV
227 tvc->f.states |= CUBCinit;
228 #endif
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));
233 #endif
234 if (haveGlock) AFS_GUNLOCK();
235
236 #ifdef AFS_DARWIN80_ENV
237 if (vnode_get(vp)) {
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();
241 return;
242 }
243 if (vnode_ref(vp)) {
244 vnode_put(vp);
245 if (haveGlock) AFS_GLOCK();
246 return;
247 }
248 vnode_put(vp);
249 #else
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. */
254
255 if (VREFCOUNT_GT(tvc, 0))
256 VREF(((struct vnode *)(vp)));
257 else
258 afs_vget(afs_globalVFS, 0, (vp));
259 #endif
260
261 #ifndef AFS_DARWIN80_ENV
262 if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
263 ubc_info_init(vp);
264 }
265 #endif
266
267 if (haveGlock) AFS_GLOCK();
268 #ifndef AFS_DARWIN80_ENV
269 tvc->f.states &= ~CUBCinit;
270 #endif
271 }
272 int
273 afs_vop_lookup(ap)
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;
279 * } */ *ap;
280 {
281 int error;
282 struct vcache *vcp;
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 */
287 struct proc *p;
288 #ifdef AFS_DARWIN80_ENV
289 vcp = VTOAFS(ap->a_dvp);
290 /*
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.
294 */
295 if (ap->a_context == afs_osi_ctxtp)
296 return ENOENT;
297 if (vcp->mvstat != AFS_MVSTAT_MTPT) {
298 error = cache_lookup(ap->a_dvp, ap->a_vpp, ap->a_cnp);
299 if (error == -1)
300 return 0;
301 if (error == ENOENT)
302 return error;
303 }
304 #endif
305
306 GETNAME();
307 p = vop_cn_proc;
308
309 lockparent = flags & LOCKPARENT;
310 wantparent = flags & (LOCKPARENT | WANTPARENT);
311
312 if (!vnode_isdir(ap->a_dvp)) {
313 *ap->a_vpp = 0;
314 DROPNAME();
315 return ENOTDIR;
316 }
317 dvp = ap->a_dvp;
318 #ifndef AFS_DARWIN80_ENV
319 if (flags & ISDOTDOT)
320 VOP_UNLOCK(dvp, 0, p);
321 #endif
322 AFS_GLOCK();
323 error = afs_lookup(VTOAFS(dvp), name, &vcp, vop_cn_cred);
324 AFS_GUNLOCK();
325 if (error) {
326 #ifndef AFS_DARWIN80_ENV
327 if (flags & ISDOTDOT)
328 VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p);
329 #endif
330 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
331 && (flags & ISLASTCN) && error == ENOENT)
332 error = EJUSTRETURN;
333 #ifndef AFS_DARWIN80_ENV
334 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
335 cnp->cn_flags |= SAVENAME;
336 #endif
337 DROPNAME();
338 *ap->a_vpp = 0;
339 return (error);
340 }
341 #ifdef AFS_DARWIN80_ENV
342 if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0))) {
343 DROPNAME();
344 *ap->a_vpp = 0;
345 return error;
346 }
347 #endif
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;
351
352 if (UBCINFOMISSING(vp) ||
353 UBCINFORECLAIMED(vp)) {
354 ubc_info_init(vp);
355 }
356 #endif
357
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. */
362
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))) {
368 vput(vp);
369 DROPNAME();
370 return (error);
371 }
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 */
375 } else {
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 */
380 }
381 #endif
382 *ap->a_vpp = vp;
383
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;
388 #endif
389
390 DROPNAME();
391 return error;
392 }
393
394 int
395 afs_vop_create(ap)
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;
401 * } */ *ap;
402 {
403 int error = 0;
404 struct vcache *vcp;
405 struct vnode *dvp = ap->a_dvp;
406 struct proc *p;
407 GETNAME();
408 p = vop_cn_proc;
409
410 /* vnode layer handles excl/nonexcl */
411 AFS_GLOCK();
412 error =
413 afs_create(VTOAFS(dvp), name, ap->a_vap, NONEXCL, ap->a_vap->va_mode,
414 &vcp, vop_cn_cred);
415 AFS_GUNLOCK();
416 if (error) {
417 #ifndef AFS_DARWIN80_ENV
418 VOP_ABORTOP(dvp, cnp);
419 vput(dvp);
420 #endif
421 DROPNAME();
422 return (error);
423 }
424
425 if (vcp) {
426 #ifdef AFS_DARWIN80_ENV
427 if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0))) {
428 DROPNAME();
429 *ap->a_vpp=0;
430 return error;
431 }
432 #endif
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;
441 }
442 #endif
443 } else
444 *ap->a_vpp = 0;
445
446 #ifndef AFS_DARWIN80_ENV
447 if ((cnp->cn_flags & SAVESTART) == 0)
448 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
449 vput(dvp);
450 #endif
451 DROPNAME();
452 return error;
453 }
454
455 int
456 afs_vop_mknod(ap)
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;
462 * } */ *ap;
463 {
464 #ifndef AFS_DARWIN80_ENV
465 FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
466 vput(ap->a_dvp);
467 #endif
468 return (ENODEV);
469 }
470
471 int
472 afs_vop_open(ap)
473 struct VOPPROT(open_args) /* {
474 * struct vnode *a_vp;
475 * int a_mode;
476 * struct ucred *a_cred;
477 * struct proc *a_p;
478 * } */ *ap;
479 {
480 int error;
481 struct vnode *vp = ap->a_vp;
482 struct vcache *vc = VTOAFS(vp);
483 #if !defined(AFS_DARWIN80_ENV)
484 int didhold = 0;
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 */
498 AFS_GLOCK();
499 error = afs_open(&vc, ap->a_mode, vop_cred);
500 #ifdef DIAGNOSTIC
501 if (AFSTOV(vc) != vp)
502 panic("AFS open changed vnode!");
503 #endif
504 osi_FlushPages(vc, vop_cred);
505 AFS_GUNLOCK();
506 #if !defined(AFS_DARWIN80_ENV)
507 if (error && didhold)
508 ubc_rele(vp);
509 #endif /* !AFS_DARWIN80_ENV */
510 return error;
511 }
512
513 int
514 afs_vop_close(ap)
515 struct VOPPROT(close_args) /* {
516 * struct vnode *a_vp;
517 * int a_fflag;
518 * struct ucred *a_cred;
519 * struct proc *a_p;
520 * } */ *ap;
521 {
522 int code;
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)
527 return 0;
528 AFS_GLOCK();
529 if (vop_cred)
530 code = afs_close(avc, ap->a_fflag, vop_cred);
531 else
532 code = afs_close(avc, ap->a_fflag, &afs_osi_cred);
533 osi_FlushPages(avc, vop_cred); /* hold GLOCK, but not basic vnode lock */
534 /* This is legit; it just forces the fstrace event to happen */
535 code = afs_CheckCode(code, NULL, 60);
536 AFS_GUNLOCK();
537
538 return code;
539 }
540
541 #ifdef AFS_DARWIN80_ENV
542 extern int afs_fakestat_enable;
543
544 int
545 afs_vop_access(ap)
546 struct VOPPROT(access_args) /* {
547 * struct vnode *a_vp;
548 * int a_action;
549 * vfs_context_t a_context;
550 * } */ *ap;
551 {
552 int code;
553 struct vrequest treq;
554 struct afs_fakestat_state fakestate;
555 struct vcache * tvc = VTOAFS(ap->a_vp);
556 int bits=0;
557 int cmb = CHECK_MODE_BITS;
558 #ifdef AFS_DARWIN80_ENV
559 /*
560 * needed for fsevents. ._ file attribute mirroring touches this.
561 * we can't flag the vcache, as there is none, so fail here.
562 */
563 if (ap->a_context == afs_osi_ctxtp)
564 return ENOENT;
565 #endif
566 AFS_GLOCK();
567 afs_InitFakeStat(&fakestate);
568 if ((code = afs_InitReq(&treq, vop_cred)))
569 goto out2;
570
571 code = afs_TryEvalFakeStat(&tvc, &fakestate, &treq);
572 if (code) {
573 code = afs_CheckCode(code, &treq, 55);
574 goto out;
575 }
576
577 code = afs_VerifyVCache(tvc, &treq);
578 if (code) {
579 code = afs_CheckCode(code, &treq, 56);
580 goto out;
581 }
582 if (afs_fakestat_enable && tvc->mvstat != AFS_MVSTAT_FILE && !(tvc->f.states & CStatd)) {
583 code = 0;
584 goto out;
585 }
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;
604 #endif
605 } else {
606 if (ap->a_action & KAUTH_VNODE_READ_DATA)
607 bits |= PRSFS_READ;
608 if (ap->a_action & KAUTH_VNODE_WRITE_DATA)
609 bits |= PRSFS_WRITE;
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;
622 }
623 if (ap->a_action & KAUTH_VNODE_WRITE_ATTRIBUTES)
624 bits |= PRSFS_WRITE;
625 #if 0 /* no extended attributes */
626 if (ap->a_action & KAUTH_VNODE_READ_EXTATTRIBUTES)
627 bits |= PRSFS_READ;
628 if (ap->a_action & KAUTH_VNODE_WRITE_EXTATTRIBUTES)
629 bits |= PRSFS_WRITE;
630 #endif
631 if (ap->a_action & KAUTH_VNODE_WRITE_SECURITY)
632 bits |= PRSFS_WRITE;
633 /* we can't check for KAUTH_VNODE_TAKE_OWNERSHIP, so we always permit it */
634
635 code = afs_AccessOK(tvc, bits, &treq, cmb);
636 /*
637 * Special cased dropbox handling:
638 * cp on 10.4 behaves badly, looping on EACCES
639 * Finder may reopen the file. Let it.
640 */
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);
646
647 if (code == 1 && vnode_vtype(ap->a_vp) == VREG &&
648 ap->a_action & KAUTH_VNODE_EXECUTE &&
649 (tvc->f.m.Mode & 0100) != 0100) {
650 code = 0;
651 }
652 if (code) {
653 code= 0; /* if access is ok */
654 } else {
655 code = afs_CheckCode(EACCES, &treq, 57); /* failure code */
656 }
657 out:
658 afs_PutFakeStat(&fakestate);
659 out2:
660 AFS_GUNLOCK();
661 return code;
662 }
663 #else
664 int
665 afs_vop_access(ap)
666 struct VOPPROT(access_args) /* {
667 * struct vnode *a_vp;
668 * int a_mode;
669 * struct ucred *a_cred;
670 * struct proc *a_p;
671 * } */ *ap;
672 {
673 int code;
674 AFS_GLOCK();
675 code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, vop_cred);
676 AFS_GUNLOCK();
677 return code;
678 }
679 #endif
680
681 int
682 afs_vop_getattr(ap)
683 struct VOPPROT(getattr_args) /* {
684 * struct vnode *a_vp;
685 * struct vattr *a_vap;
686 * struct ucred *a_cred;
687 * struct proc *a_p;
688 * } */ *ap;
689 {
690 int code;
691
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();
698
699 /* this is needed because of how and when we re-enter */
700 if (!isglock)
701 AFS_GLOCK();
702 /* do minimal work to return fake result for fsevents */
703 if (afs_fakestat_enable && VTOAFS(ap->a_vp)->mvstat == AFS_MVSTAT_MTPT) {
704 struct afs_fakestat_state fakestat;
705 struct vrequest treq;
706
707 code = afs_InitReq(&treq, vop_cred);
708 if (code) {
709 if (!isglock)
710 AFS_GUNLOCK();
711 return code;
712 }
713 afs_InitFakeStat(&fakestat);
714 /* expects GLOCK */
715 code = afs_TryEvalFakeStat(&avc, &fakestat, &treq);
716 if (code) {
717 if (!isglock)
718 AFS_GUNLOCK();
719 afs_PutFakeStat(&fakestat);
720 return code;
721 }
722 }
723 code = afs_CopyOutAttrs(avc, ap->a_vap);
724 if (!isglock)
725 AFS_GUNLOCK();
726 if (0 && !code) {
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);
730 }
731 } else
732 #endif
733 {
734 AFS_GLOCK();
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);
738 AFS_GUNLOCK();
739 }
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);
756 #endif
757 return code;
758 }
759
760 int
761 afs_vop_setattr(ap)
762 struct VOPPROT(setattr_args) /* {
763 * struct vnode *a_vp;
764 * struct vattr *a_vap;
765 * struct ucred *a_cred;
766 * struct proc *a_p;
767 * } */ *ap;
768 {
769 int code, pass = 0;
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)
774 return 0;
775 #endif
776 AFS_GLOCK();
777 retry:
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);
784 pass++;
785 goto retry;
786 }
787 AFS_GUNLOCK();
788 return code;
789 }
790
791 int
792 afs_vop_read(ap)
793 struct VOPPROT(read_args) /* {
794 * struct vnode *a_vp;
795 * struct uio *a_uio;
796 * int a_ioflag;
797 * struct ucred *a_cred;
798 * } */ *ap;
799 {
800 int code;
801 struct vnode *vp = ap->a_vp;
802 struct vcache *avc = VTOAFS(vp);
803
804 if (vnode_isdir(ap->a_vp))
805 return EISDIR;
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);
808 #else
809 if (UBCINFOEXISTS(ap->a_vp)) {
810 ubc_clean(ap->a_vp, 0);
811 }
812 #endif
813 AFS_GLOCK();
814 osi_FlushPages(avc, vop_cred); /* hold GLOCK, but not basic vnode lock */
815 code = afs_read(avc, ap->a_uio, vop_cred, 0);
816 AFS_GUNLOCK();
817 return code;
818 }
819
820 int
821 afs_vop_pagein(ap)
822 struct VOPPROT(pagein_args) /* {
823 * struct vnode *a_vp;
824 * upl_t a_pl;
825 * vm_offset_t a_pl_offset;
826 * off_t a_f_offset;
827 * size_t a_size;
828 * struct ucred *a_cred;
829 * int a_flags;
830 * } */ *ap;
831 {
832 struct vnode *vp = ap->a_vp;
833 upl_t pl = ap->a_pl;
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;
838 struct ucred *cred;
839 vm_offset_t ioaddr;
840 int code;
841 struct vcache *tvc = VTOAFS(vp);
842 int nocommit = flags & UPL_NOCOMMIT;
843 #ifdef AFS_DARWIN80_ENV
844 struct uio *uio;
845 #else
846 struct uio auio;
847 struct iovec aiov;
848 struct uio *uio = &auio;
849
850 memset(&auio, 0, sizeof(auio));
851 memset(&aiov, 0, sizeof(aiov));
852 #endif
853
854 #ifndef AFS_DARWIN80_ENV
855 if (UBCINVALID(vp)) {
856 #if DIAGNOSTIC
857 panic("afs_vop_pagein: invalid vp");
858 #endif /* DIAGNOSTIC */
859 return (EPERM);
860 }
861
862 UBCINFOCHECK("afs_vop_pagein", vp);
863 #endif
864 if (pl == (upl_t) NULL) {
865 panic("afs_vop_pagein: no upl");
866 }
867
868 cred = ubc_getcred(vp);
869 if (cred == NOCRED)
870 cred = vop_cred;
871
872 if (size == 0) {
873 if (!nocommit)
874 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
875 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
876 return (0);
877 }
878 if (f_offset < 0) {
879 if (!nocommit)
880 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
881 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
882 return (EINVAL);
883 }
884 if (f_offset & PAGE_MASK)
885 panic("afs_vop_pagein: offset not page aligned");
886
887 OSI_UPL_MAP(pl, &ioaddr);
888 ioaddr += pl_offset;
889 #ifdef AFS_DARWIN80_ENV
890 uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
891 uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
892 #else
893 auio.uio_iov = &aiov;
894 auio.uio_iovcnt = 1;
895 auio.uio_offset = f_offset;
896 auio.uio_segflg = UIO_SYSSPACE;
897 auio.uio_rw = UIO_READ;
898 auio.uio_procp = NULL;
899 auio.uio_resid = aiov.iov_len = size;
900 aiov.iov_base = (caddr_t) ioaddr;
901 #endif
902 AFS_GLOCK();
903 osi_FlushPages(tvc, vop_cred); /* hold GLOCK, but not basic vnode lock */
904 code = afs_read(tvc, uio, cred, 0);
905 if (code == 0) {
906 ObtainWriteLock(&tvc->lock, 2);
907 tvc->f.states |= CMAPPED;
908 ReleaseWriteLock(&tvc->lock);
909 }
910 AFS_GUNLOCK();
911
912 /* Zero out rest of last page if there wasn't enough data in the file */
913 if (code == 0 && AFS_UIO_RESID(uio) > 0) {
914 #ifdef AFS_DARWIN80_ENV
915 memset(((caddr_t)ioaddr) + (size - AFS_UIO_RESID(uio)), 0,
916 AFS_UIO_RESID(uio));
917 #else
918 memset(aiov.iov_base, 0, auio.uio_resid);
919 #endif
920 }
921
922 OSI_UPL_UNMAP(pl);
923 if (!nocommit) {
924 if (code)
925 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
926 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
927 else
928 OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
929 UPL_COMMIT_CLEAR_DIRTY |
930 UPL_COMMIT_FREE_ON_EMPTY);
931 }
932 #ifdef AFS_DARWIN80_ENV
933 uio_free(uio);
934 #endif
935 return code;
936 }
937
938 int
939 afs_vop_write(ap)
940 struct VOPPROT(write_args) /* {
941 * struct vnode *a_vp;
942 * struct uio *a_uio;
943 * int a_ioflag;
944 * struct ucred *a_cred;
945 * } */ *ap;
946 {
947 int code;
948 struct vcache *avc = VTOAFS(ap->a_vp);
949 void *object;
950 #ifdef AFS_DARWIN80_ENV
951 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);
952 #else
953 if (UBCINFOEXISTS(ap->a_vp)) {
954 ubc_clean(ap->a_vp, 1);
955 }
956 if (UBCINFOEXISTS(ap->a_vp))
957 osi_VM_NukePages(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio),
958 AFS_UIO_RESID(ap->a_uio));
959 #endif
960 AFS_GLOCK();
961 osi_FlushPages(avc, vop_cred); /* hold GLOCK, but not basic vnode lock */
962 code =
963 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, vop_cred, 0);
964 AFS_GUNLOCK();
965 return code;
966 }
967
968 int
969 afs_vop_pageout(ap)
970 struct VOPPROT(pageout_args) /* {
971 * struct vnode *a_vp;
972 * upl_t a_pl,
973 * vm_offset_t a_pl_offset,
974 * off_t a_f_offset,
975 * size_t a_size,
976 * struct ucred *a_cred,
977 * int a_flags
978 * } */ *ap;
979 {
980 struct vnode *vp = ap->a_vp;
981 upl_t pl = ap->a_pl;
982 size_t size = ap->a_size;
983 off_t f_offset = ap->a_f_offset;
984 vm_offset_t pl_offset = ap->a_pl_offset;
985 int flags = ap->a_flags;
986 struct ucred *cred;
987 vm_offset_t ioaddr;
988 int nocommit = flags & UPL_NOCOMMIT;
989 int iosize;
990 int code;
991 struct vcache *tvc = VTOAFS(vp);
992 #ifdef AFS_DARWIN80_ENV
993 struct uio *uio;
994 #else
995 struct uio auio;
996 struct iovec aiov;
997 struct uio *uio = &auio;
998
999 memset(&auio, 0, sizeof(auio));
1000 memset(&aiov, 0, sizeof(aiov));
1001 #endif
1002
1003 #ifndef AFS_DARWIN80_ENV
1004 if (UBCINVALID(vp)) {
1005 #if DIAGNOSTIC
1006 panic("afs_vop_pageout: invalid vp");
1007 #endif /* DIAGNOSTIC */
1008 return (EPERM);
1009 }
1010
1011 UBCINFOCHECK("afs_vop_pageout", vp);
1012 #endif
1013 if (pl == (upl_t) NULL) {
1014 panic("afs_vop_pageout: no upl");
1015 }
1016 #if !defined(AFS_DARWIN80_ENV) /* XXX nfs now uses it's own bufs (struct nfsbuf)
1017 maybe the generic
1018 layer doesn't have them anymore? In any case,
1019 we can't just copy code from nfs... */
1020 {
1021 int lbn, s;
1022 struct buf *bp;
1023 int biosize = DEV_BSIZE;
1024
1025 lbn = f_offset / DEV_BSIZE;
1026
1027 for (iosize = size; iosize > 0; iosize -= biosize, lbn++) {
1028
1029 s = splbio();
1030 if (bp = incore(vp, lbn)) {
1031 if (ISSET(bp->b_flags, B_BUSY))
1032 panic("nfs_pageout: found BUSY buffer incore\n");
1033
1034 bremfree(bp);
1035 SET(bp->b_flags, (B_BUSY | B_INVAL));
1036 brelse(bp);
1037 }
1038 splx(s);
1039 }
1040 }
1041 #endif
1042 cred = ubc_getcred(vp);
1043 if (cred == NOCRED)
1044 cred = vop_cred;
1045
1046 if (size == 0) {
1047 if (!nocommit)
1048 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1049 UPL_ABORT_FREE_ON_EMPTY);
1050 return (0);
1051 }
1052 if (flags & (IO_APPEND | IO_SYNC))
1053 panic("nfs_pageout: (IO_APPEND | IO_SYNC)");
1054 if (f_offset < 0) {
1055 if (!nocommit)
1056 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1057 UPL_ABORT_FREE_ON_EMPTY);
1058 return (EINVAL);
1059 }
1060 if (f_offset >= tvc->f.m.Length) {
1061 if (!nocommit)
1062 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1063 UPL_ABORT_FREE_ON_EMPTY);
1064 return (EINVAL);
1065 }
1066
1067 if (f_offset & PAGE_MASK)
1068 panic("afs_vop_pageout: offset not page aligned");
1069
1070 /* size will always be a multiple of PAGE_SIZE */
1071 /* pageout isn't supposed to extend files */
1072 if (f_offset + size > tvc->f.m.Length)
1073 iosize = tvc->f.m.Length - f_offset;
1074 else
1075 iosize = size;
1076
1077 if (size > (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK && !nocommit) {
1078 int iosize_rnd=(iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
1079 OSI_UPL_ABORT_RANGE(pl, pl_offset + iosize_rnd,
1080 size - iosize_rnd,
1081 UPL_ABORT_FREE_ON_EMPTY);
1082 }
1083 OSI_UPL_MAP(pl, &ioaddr);
1084 ioaddr += pl_offset;
1085 #ifdef AFS_DARWIN80_ENV
1086 uio = uio_create(1, f_offset, UIO_SYSSPACE32, UIO_READ);
1087 uio_addiov(uio, CAST_USER_ADDR_T(ioaddr), size);
1088 #else
1089 auio.uio_iov = &aiov;
1090 auio.uio_iovcnt = 1;
1091 auio.uio_offset = f_offset;
1092 auio.uio_segflg = UIO_SYSSPACE;
1093 auio.uio_rw = UIO_WRITE;
1094 auio.uio_procp = NULL;
1095 auio.uio_resid = aiov.iov_len = iosize;
1096 aiov.iov_base = (caddr_t) ioaddr;
1097 #endif
1098 {
1099 /* USV?
1100 * check for partial page and clear the
1101 * contents past end of the file before
1102 * releasing it in the VM page cache
1103 */
1104 if ((f_offset < tvc->f.m.Length) && (f_offset + size) > tvc->f.m.Length) {
1105 size_t io = tvc->f.m.Length - f_offset;
1106
1107 memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
1108 }
1109 }
1110
1111 AFS_GLOCK();
1112 osi_FlushPages(tvc, vop_cred); /* hold GLOCK, but not basic vnode lock */
1113 ObtainWriteLock(&tvc->lock, 1);
1114 afs_FakeOpen(tvc);
1115 ReleaseWriteLock(&tvc->lock);
1116
1117 code = afs_write(tvc, uio, flags, cred, 0);
1118
1119 ObtainWriteLock(&tvc->lock, 1);
1120 afs_FakeClose(tvc, cred);
1121 ReleaseWriteLock(&tvc->lock);
1122 AFS_GUNLOCK();
1123 OSI_UPL_UNMAP(pl);
1124 if (!nocommit) {
1125 if (code)
1126 OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
1127 UPL_ABORT_FREE_ON_EMPTY);
1128 else
1129 OSI_UPL_COMMIT_RANGE(pl, pl_offset, size,
1130 UPL_COMMIT_CLEAR_DIRTY |
1131 UPL_COMMIT_FREE_ON_EMPTY);
1132 }
1133
1134 #ifdef AFS_DARWIN80_ENV
1135 uio_free(uio);
1136 #endif
1137 return code;
1138 }
1139
1140 int
1141 afs_vop_ioctl(ap)
1142 struct VOPPROT(ioctl_args) /* {
1143 * struct vnode *a_vp;
1144 * int a_command;
1145 * caddr_t a_data;
1146 * int a_fflag;
1147 * struct ucred *a_cred;
1148 * struct proc *a_p;
1149 * } */ *ap;
1150 {
1151 struct vcache *tvc = VTOAFS(ap->a_vp);
1152 struct afs_ioctl data;
1153 int error = 0;
1154
1155 /* in case we ever get in here... */
1156
1157 AFS_STATCNT(afs_ioctl);
1158 if (((ap->a_command >> 8) & 0xff) == 'V') {
1159 /* This is a VICEIOCTL call */
1160 AFS_GLOCK();
1161 error = HandleIoctl(tvc, ap->a_command, ap->a_data);
1162 AFS_GUNLOCK();
1163 return (error);
1164 } else {
1165 /* No-op call; just return. */
1166 return (ENOTTY);
1167 }
1168 }
1169
1170 /* ARGSUSED */
1171 int
1172 afs_vop_select(ap)
1173 struct VOPPROT(select_args) /* {
1174 * struct vnode *a_vp;
1175 * int a_which;
1176 * int a_fflags;
1177 * struct ucred *a_cred;
1178 * struct proc *a_p;
1179 * } */ *ap;
1180 {
1181 /*
1182 * We should really check to see if I/O is possible.
1183 */
1184 return (1);
1185 }
1186
1187 /*
1188 * Mmap a file
1189 *
1190 * NB Currently unsupported.
1191 */
1192 /* ARGSUSED */
1193 int
1194 afs_vop_mmap(ap)
1195 struct VOPPROT(mmap_args) /* {
1196 * struct vnode *a_vp;
1197 * int a_fflags;
1198 * struct ucred *a_cred;
1199 * struct proc *a_p;
1200 * } */ *ap;
1201 {
1202 return (EINVAL);
1203 }
1204
1205 int
1206 afs_vop_fsync(ap)
1207 struct VOPPROT(fsync_args) /* {
1208 * struct vnode *a_vp;
1209 * struct ucred *a_cred;
1210 * int a_waitfor;
1211 * struct proc *a_p;
1212 * } */ *ap;
1213 {
1214 int wait = ap->a_waitfor == MNT_WAIT;
1215 int error;
1216 struct vnode *vp = ap->a_vp;
1217 int haveGlock = ISAFS_GLOCK();
1218
1219 /* in order to recycle faked vnodes for bulkstat */
1220 if (VTOAFS(vp) == NULL)
1221 return ENOTSUP;
1222
1223 /* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
1224 if (!haveGlock) AFS_GLOCK();
1225 if (vop_cred)
1226 error = afs_fsync(VTOAFS(vp), vop_cred);
1227 else
1228 error = afs_fsync(VTOAFS(vp), &afs_osi_cred);
1229 if (!haveGlock) AFS_GUNLOCK();
1230 return error;
1231 }
1232
1233 #ifndef AFS_DARWIN80_ENV
1234 int
1235 afs_vop_seek(ap)
1236 struct VOPPROT(seek_args) /* {
1237 * struct vnode *a_vp;
1238 * off_t a_oldoff;
1239 * off_t a_newoff;
1240 * struct ucred *a_cred;
1241 * } */ *ap;
1242 {
1243 if (ap->a_newoff > ULONG_MAX) /* AFS doesn't support 64-bit offsets */
1244 return EINVAL;
1245 return (0);
1246 }
1247 #endif
1248
1249 int
1250 afs_vop_remove(ap)
1251 struct VOPPROT(remove_args) /* {
1252 * struct vnode *a_dvp;
1253 * struct vnode *a_vp;
1254 * struct componentname *a_cnp;
1255 * } */ *ap;
1256 {
1257 int error = 0;
1258 struct vnode *vp = ap->a_vp;
1259 struct vnode *dvp = ap->a_dvp;
1260
1261 #ifdef AFS_DARWIN80_ENV
1262 if (ap->a_flags & VNODE_REMOVE_NODELETEBUSY) {
1263 /* Caller requested Carbon delete semantics */
1264 if (vnode_isinuse(vp, 0)) {
1265 return EBUSY;
1266 }
1267 }
1268 #endif
1269
1270 GETNAME();
1271 AFS_GLOCK();
1272 error = afs_remove(VTOAFS(dvp), name, vop_cn_cred);
1273 error = afs_CheckCode(error, NULL, 61);
1274 AFS_GUNLOCK();
1275 cache_purge(vp);
1276 if (!error) {
1277 #ifdef AFS_DARWIN80_ENV
1278 struct vcache *tvc = VTOAFS(vp);
1279
1280 if (!(tvc->f.states & CUnlinked)) {
1281 ubc_setsize(vp, (off_t)0);
1282 vnode_recycle(vp);
1283 }
1284 #else
1285 /* necessary so we don't deadlock ourselves in vclean */
1286 VOP_UNLOCK(vp, 0, cnp->cn_proc);
1287
1288 /* If crashes continue in ubc_hold, comment this out */
1289 (void)ubc_uncache(vp);
1290 #endif
1291 } else {
1292 /* should check for PRSFS_INSERT and not PRSFS_DELETE, but the
1293 goal here is to deal with Finder's unhappiness with resource
1294 forks that have no resources in a dropbox setting */
1295 if (name[0] == '.' && name[1] == '_' && error == EACCES)
1296 error = 0;
1297 }
1298
1299 #ifndef AFS_DARWIN80_ENV
1300 vput(dvp);
1301 if (dvp == vp)
1302 vrele(vp);
1303 else
1304 vput(vp);
1305 #endif
1306
1307 #ifndef AFS_DARWIN80_ENV
1308 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1309 #endif
1310 DROPNAME();
1311 return error;
1312 }
1313
1314 int
1315 afs_vop_link(ap)
1316 struct VOPPROT(link_args) /* {
1317 * struct vnode *a_vp;
1318 * struct vnode *a_tdvp;
1319 * struct componentname *a_cnp;
1320 * } */ *ap;
1321 {
1322 int error = 0;
1323 struct vnode *dvp = ap->a_tdvp;
1324 struct vnode *vp = ap->a_vp;
1325 struct proc *p;
1326
1327 GETNAME();
1328 p = vop_cn_proc;
1329 if (vnode_isdir(vp)) {
1330 VOP_ABORTOP(vp, cnp);
1331 error = EISDIR;
1332 goto out;
1333 }
1334 #ifndef AFS_DARWIN80_ENV
1335 if (error = vn_lock(vp, LK_EXCLUSIVE, p)) {
1336 VOP_ABORTOP(dvp, cnp);
1337 goto out;
1338 }
1339 #endif
1340 AFS_GLOCK();
1341 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, vop_cn_cred);
1342 AFS_GUNLOCK();
1343 #ifndef AFS_DARWIN80_ENV
1344 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1345 #endif
1346 #ifndef AFS_DARWIN80_ENV
1347 if (dvp != vp)
1348 VOP_UNLOCK(vp, 0, p);
1349 #endif
1350 out:
1351 #ifndef AFS_DARWIN80_ENV
1352 vput(dvp);
1353 #endif
1354 DROPNAME();
1355 return error;
1356 }
1357
1358 int
1359 afs_vop_rename(ap)
1360 struct VOPPROT(rename_args) /* {
1361 * struct vnode *a_fdvp;
1362 * struct vnode *a_fvp;
1363 * struct componentname *a_fcnp;
1364 * struct vnode *a_tdvp;
1365 * struct vnode *a_tvp;
1366 * struct componentname *a_tcnp;
1367 * } */ *ap;
1368 {
1369 int error = 0;
1370 struct componentname *fcnp = ap->a_fcnp;
1371 char *fname;
1372 struct componentname *tcnp = ap->a_tcnp;
1373 char *tname;
1374 struct vnode *tvp = ap->a_tvp;
1375 struct vnode *tdvp = ap->a_tdvp;
1376 struct vnode *fvp = ap->a_fvp;
1377 struct vnode *fdvp = ap->a_fdvp;
1378 struct proc *p;
1379
1380 p = cn_proc(fcnp);
1381
1382 #ifdef AFS_DARWIN80_ENV
1383 /*
1384 * generic code tests for v_mount equality, so we don't have to, but we
1385 * don't get the multiple-mount "benefits" of the old behavior
1386 * the generic code doesn't do this, so we really should, but all the
1387 * vrele's are wrong...
1388 */
1389 #else
1390 /* Check for cross-device rename.
1391 * For AFS, this means anything not in AFS-space
1392 */
1393 if ((0 != strcmp(tdvp->v_mount->mnt_stat.f_fstypename, "afs")) ||
1394 (tvp && (0 != strcmp(tvp->v_mount->mnt_stat.f_fstypename, "afs")))) {
1395 error = EXDEV;
1396 goto abortit;
1397 }
1398
1399 /*
1400 * if fvp == tvp, we're just removing one name of a pair of
1401 * directory entries for the same element. convert call into rename.
1402 ( (pinched from NetBSD 1.0's ufs_rename())
1403 */
1404 if (fvp == tvp) {
1405 if (vnode_isdir(fvp)) {
1406 error = EINVAL;
1407 abortit:
1408 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
1409 if (tdvp == tvp)
1410 vrele(tdvp);
1411 else
1412 vput(tdvp);
1413 if (tvp)
1414 vput(tvp);
1415 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
1416 vrele(fdvp);
1417 vrele(fvp);
1418 return (error);
1419 }
1420
1421 /* Release destination completely. */
1422 VOP_ABORTOP(tdvp, tcnp);
1423 vput(tdvp);
1424 vput(tvp);
1425 /* Delete source. */
1426 vrele(fdvp);
1427 vrele(fvp);
1428 fcnp->cn_flags &= ~MODMASK;
1429 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1430 if ((fcnp->cn_flags & SAVESTART) == 0)
1431 panic("afs_rename: lost from startdir");
1432 fcnp->cn_nameiop = DELETE;
1433
1434 VREF(fdvp);
1435 error=relookup(fdvp, &fvp, fcnp);
1436 if (error == 0)
1437 vrele(fdvp);
1438 if (fvp == NULL) {
1439 return (ENOENT);
1440 }
1441 error=VOP_REMOVE(fdvp, fvp, fcnp);
1442
1443 if (fdvp == fvp)
1444 vrele(fdvp);
1445 else
1446 vput(fdvp);
1447 vput(fvp);
1448 return (error);
1449 }
1450 if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
1451 goto abortit;
1452 #endif
1453
1454 MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1455 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
1456 fname[fcnp->cn_namelen] = '\0';
1457 MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
1458 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
1459 tname[tcnp->cn_namelen] = '\0';
1460
1461
1462 AFS_GLOCK();
1463 /* XXX use "from" or "to" creds? NFS uses "to" creds */
1464 error =
1465 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, cn_cred(tcnp));
1466
1467 #if !defined(AFS_DARWIN80_ENV)
1468 AFS_GUNLOCK();
1469 VOP_UNLOCK(fvp, 0, p);
1470 if (error)
1471 goto abortit; /* XXX */
1472 if (tdvp == tvp)
1473 vrele(tdvp);
1474 else
1475 vput(tdvp);
1476 if (tvp)
1477 vput(tvp);
1478 vrele(fdvp);
1479 vrele(fvp);
1480 #else
1481 if (error == EXDEV) {
1482 struct brequest *tb;
1483 struct afs_uspc_param mvReq;
1484 struct vcache *tvc;
1485 struct vcache *fvc = VTOAFS(fdvp);
1486 int code = 0;
1487 struct afs_fakestat_state fakestate;
1488 int fakestatdone = 0;
1489
1490 tvc = VTOAFS(tdvp);
1491
1492 /* unrewritten mount point? */
1493 if (tvc->mvstat == AFS_MVSTAT_MTPT) {
1494 if (tvc->mvid.target_root && (tvc->f.states & CMValid)) {
1495 struct vrequest treq;
1496
1497 afs_InitFakeStat(&fakestate);
1498 code = afs_InitReq(&treq, vop_cred);
1499 if (!code) {
1500 fakestatdone = 1;
1501 code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
1502 } else
1503 afs_PutFakeStat(&fakestate);
1504 }
1505 }
1506
1507 if (!code) {
1508 /* at some point in the future we should allow other types */
1509 mvReq.reqtype = AFS_USPC_UMV;
1510 mvReq.req.umv.id = afs_cr_uid(cn_cred(tcnp));
1511 mvReq.req.umv.idtype = IDTYPE_UID;
1512 mvReq.req.umv.sCell = fvc->f.fid.Cell;
1513 mvReq.req.umv.sVolume = fvc->f.fid.Fid.Volume;
1514 mvReq.req.umv.sVnode = fvc->f.fid.Fid.Vnode;
1515 mvReq.req.umv.sUnique = fvc->f.fid.Fid.Unique;
1516 mvReq.req.umv.dCell = tvc->f.fid.Cell;
1517 mvReq.req.umv.dVolume = tvc->f.fid.Fid.Volume;
1518 mvReq.req.umv.dVnode = tvc->f.fid.Fid.Vnode;
1519 mvReq.req.umv.dUnique = tvc->f.fid.Fid.Unique;
1520
1521 /*
1522 * su %d -c mv /afs/.:mount/%d:%d:%d:%d/%s
1523 * /afs/.:mount/%d:%d:%d:%d/%s where:
1524 * mvReq.req.umv.id, fvc->f.fid.Cell, fvc->f.fid.Fid.Volume,
1525 * fvc->f.fid.Fid.Vnode, fvc->f.fid.Fid.Unique, fname,
1526 * tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode,
1527 * tvc->f.fid.Fid.Unique, tname
1528 */
1529
1530 tb = afs_BQueue(BOP_MOVE, NULL, 0, 1, cn_cred(tcnp),
1531 0L, 0L, &mvReq, fname, tname);
1532 /* wait to collect result */
1533 while ((tb->flags & BUVALID) == 0) {
1534 tb->flags |= BUWAIT;
1535 afs_osi_Sleep(tb);
1536 }
1537 /* if we succeeded, clear the error. otherwise, EXDEV */
1538 if (mvReq.retval == 0)
1539 error = 0;
1540
1541 afs_BRelease(tb);
1542 }
1543
1544 if (fakestatdone)
1545 afs_PutFakeStat(&fakestate);
1546 }
1547 AFS_GUNLOCK();
1548
1549 cache_purge(fdvp);
1550 cache_purge(fvp);
1551 cache_purge(tdvp);
1552 if (tvp) {
1553 cache_purge(tvp);
1554 if (!error) {
1555 vnode_recycle(tvp);
1556 }
1557 }
1558 if (!error)
1559 cache_enter(tdvp, fvp, tcnp);
1560 #endif
1561 FREE(fname, M_TEMP);
1562 FREE(tname, M_TEMP);
1563 return error;
1564 }
1565
1566 int
1567 afs_vop_mkdir(ap)
1568 struct VOPPROT(mkdir_args) /* {
1569 * struct vnode *a_dvp;
1570 * struct vnode **a_vpp;
1571 * struct componentname *a_cnp;
1572 * struct vattr *a_vap;
1573 * } */ *ap;
1574 {
1575 struct vnode *dvp = ap->a_dvp;
1576 struct vattr *vap = ap->a_vap;
1577 int error = 0;
1578 struct vcache *vcp;
1579 struct proc *p;
1580
1581 GETNAME();
1582 p = vop_cn_proc;
1583 #if defined(DIAGNOSTIC) && !defined(AFS_DARWIN80_ENV)
1584 if ((cnp->cn_flags & HASBUF) == 0)
1585 panic("afs_vop_mkdir: no name");
1586 #endif
1587 AFS_GLOCK();
1588 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, vop_cn_cred);
1589 AFS_GUNLOCK();
1590 if (error) {
1591 #ifndef AFS_DARWIN80_ENV
1592 VOP_ABORTOP(dvp, cnp);
1593 vput(dvp);
1594 #endif
1595 DROPNAME();
1596 return (error);
1597 }
1598 if (vcp) {
1599 #ifdef AFS_DARWIN80_ENV
1600 afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0);
1601 #endif
1602 *ap->a_vpp = AFSTOV(vcp);
1603 #ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
1604 (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
1605 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
1606 #endif
1607 } else
1608 *ap->a_vpp = 0;
1609 DROPNAME();
1610 #ifndef AFS_DARWIN80_ENV
1611 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1612 vput(dvp);
1613 #endif
1614 return error;
1615 }
1616
1617 int
1618 afs_vop_rmdir(ap)
1619 struct VOPPROT(rmdir_args) /* {
1620 * struct vnode *a_dvp;
1621 * struct vnode *a_vp;
1622 * struct componentname *a_cnp;
1623 * } */ *ap;
1624 {
1625 int error = 0;
1626 struct vnode *vp = ap->a_vp;
1627 struct vnode *dvp = ap->a_dvp;
1628
1629 GETNAME();
1630 if (dvp == vp) {
1631 #ifndef AFS_DARWIN80_ENV
1632 vrele(dvp);
1633 vput(vp);
1634 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1635 #endif
1636 DROPNAME();
1637 return (EINVAL);
1638 }
1639
1640 AFS_GLOCK();
1641 error = afs_rmdir(VTOAFS(dvp), name, vop_cn_cred);
1642 AFS_GUNLOCK();
1643 DROPNAME();
1644 cache_purge(dvp);
1645 cache_purge(vp);
1646 #ifndef AFS_DARWIN80_ENV
1647 vput(dvp);
1648 vput(vp);
1649 #endif
1650 return error;
1651 }
1652
1653 int
1654 afs_vop_symlink(ap)
1655 struct VOPPROT(symlink_args) /* {
1656 * struct vnode *a_dvp;
1657 * struct vnode **a_vpp;
1658 * struct componentname *a_cnp;
1659 * struct vattr *a_vap;
1660 * char *a_target;
1661 * } */ *ap;
1662 {
1663 struct vnode *dvp = ap->a_dvp;
1664 struct vcache *pvc = NULL;
1665 int error = 0;
1666
1667 GETNAME();
1668 AFS_GLOCK();
1669 error = afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, &pvc,
1670 vop_cn_cred);
1671 AFS_GUNLOCK();
1672 #ifndef AFS_DARWIN80_ENV
1673 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1674 vput(dvp);
1675 #endif
1676 *ap->a_vpp = NULL;
1677 if (!error) {
1678 error = afs_darwin_finalizevnode(pvc, dvp, ap->a_cnp, 0, 0);
1679 if (!error)
1680 *ap->a_vpp = AFSTOV(pvc);
1681 }
1682 DROPNAME();
1683 return error;
1684 }
1685
1686 int
1687 afs_vop_readdir(ap)
1688 struct VOPPROT(readdir_args) /* {
1689 * struct vnode *a_vp;
1690 * struct uio *a_uio;
1691 * struct ucred *a_cred;
1692 * int *a_eofflag;
1693 * u_long *a_cookies;
1694 * int ncookies;
1695 * } */ *ap;
1696 {
1697 int error;
1698 off_t off;
1699 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1700 ap->a_ncookies); */
1701 #ifdef AFS_DARWIN80_ENV
1702 /* too much work for now */
1703 /* should only break nfs exports */
1704 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1705 return (EINVAL);
1706 #endif
1707 off = AFS_UIO_OFFSET(ap->a_uio);
1708 AFS_GLOCK();
1709 error =
1710 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, vop_cred, ap->a_eofflag);
1711 AFS_GUNLOCK();
1712 #ifndef AFS_DARWIN80_ENV
1713 if (!error && ap->a_ncookies != NULL) {
1714 struct uio *uio = ap->a_uio;
1715 const struct dirent *dp, *dp_start, *dp_end;
1716 int ncookies;
1717 u_long *cookies, *cookiep;
1718
1719 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1720 panic("afs_readdir: burned cookies");
1721 dp = (const struct dirent *)
1722 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1723
1724 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1725 for (dp_start = dp, ncookies = 0; dp < dp_end;
1726 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1727 ncookies++;
1728
1729 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1730 M_WAITOK);
1731 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1732 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1733 off += dp->d_reclen;
1734 *cookiep++ = off;
1735 }
1736 *ap->a_cookies = cookies;
1737 *ap->a_ncookies = ncookies;
1738 }
1739 #endif
1740
1741 return error;
1742 }
1743
1744 int
1745 afs_vop_readlink(ap)
1746 struct VOPPROT(readlink_args) /* {
1747 * struct vnode *a_vp;
1748 * struct uio *a_uio;
1749 * struct ucred *a_cred;
1750 * } */ *ap;
1751 {
1752 int error;
1753 /* printf("readlink %x\n", ap->a_vp);*/
1754 AFS_GLOCK();
1755 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, vop_cred);
1756 AFS_GUNLOCK();
1757 return error;
1758 }
1759
1760 extern int prtactive;
1761
1762 int
1763 afs_vop_inactive(ap)
1764 struct VOPPROT(inactive_args) /* {
1765 * struct vnode *a_vp;
1766 * struct proc *a_p;
1767 * } */ *ap;
1768 {
1769 struct vnode *vp = ap->a_vp;
1770 struct vcache *tvc = VTOAFS(vp);
1771 #ifndef AFS_DARWIN80_ENV
1772 if (prtactive && vp->v_usecount != 0)
1773 vprint("afs_vop_inactive(): pushing active", vp);
1774 #endif
1775 if (tvc) {
1776 #ifdef AFS_DARWIN80_ENV
1777 int unlinked = tvc->f.states & CUnlinked;
1778 #endif
1779 AFS_GLOCK();
1780 afs_InactiveVCache(tvc, 0); /* decrs ref counts */
1781 AFS_GUNLOCK();
1782 #ifdef AFS_DARWIN80_ENV
1783 if (unlinked) {
1784 vnode_recycle(vp);
1785 cache_purge(vp);
1786 }
1787 #endif
1788 }
1789 #ifndef AFS_DARWIN80_ENV
1790 VOP_UNLOCK(vp, 0, ap->a_p);
1791 #endif
1792 return 0;
1793 }
1794
1795 int
1796 afs_vop_reclaim(ap)
1797 struct VOPPROT(reclaim_args) /* {
1798 * struct vnode *a_vp;
1799 * } */ *ap;
1800 {
1801 int error = 0;
1802 int sl, writelocked;
1803 struct vnode *vp = ap->a_vp;
1804 struct vcache *tvc = VTOAFS(vp);
1805
1806 osi_Assert(!ISAFS_GLOCK());
1807 cache_purge(vp); /* just in case... */
1808 if (tvc) {
1809 AFS_GLOCK();
1810 writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335));
1811 if (!writelocked) {
1812 ObtainWriteLock(&afs_xvreclaim, 176);
1813 #ifdef AFS_DARWIN80_ENV
1814 vnode_clearfsnode(AFSTOV(tvc));
1815 vnode_removefsref(AFSTOV(tvc));
1816 #else
1817 tvc->v->v_data = NULL; /* remove from vnode */
1818 #endif
1819 AFSTOV(tvc) = NULL; /* also drop the ptr to vnode */
1820 tvc->f.states |= CVInit; /* also CDeadVnode? */
1821 tvc->nextfree = ReclaimedVCList;
1822 ReclaimedVCList = tvc;
1823 ReleaseWriteLock(&afs_xvreclaim);
1824 } else {
1825 error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */
1826 if (tvc->f.states & (CVInit
1827 #ifdef AFS_DARWIN80_ENV
1828 | CDeadVnode
1829 #endif
1830 )) {
1831 tvc->f.states &= ~(CVInit
1832 #ifdef AFS_DARWIN80_ENV
1833 | CDeadVnode
1834 #endif
1835 );
1836 afs_osi_Wakeup(&tvc->f.states);
1837 }
1838 if (!error && vnode_fsnode(vp))
1839 panic("afs_reclaim: vnode not cleaned");
1840 if (!error && (tvc->v != NULL))
1841 panic("afs_reclaim: vcache not cleaned");
1842 ReleaseWriteLock(&afs_xvcache);
1843 }
1844 AFS_GUNLOCK();
1845 }
1846 return error;
1847 }
1848
1849 /*
1850 * Return POSIX pathconf information applicable to ufs filesystems.
1851 */
1852 afs_vop_pathconf(ap)
1853 struct VOPPROT(pathconf_args) /* {
1854 * struct vnode *a_vp;
1855 * int a_name;
1856 * int *a_retval;
1857 * } */ *ap;
1858 {
1859 AFS_STATCNT(afs_cntl);
1860 switch (ap->a_name) {
1861 case _PC_LINK_MAX:
1862 *ap->a_retval = LINK_MAX;
1863 break;
1864 case _PC_NAME_MAX:
1865 *ap->a_retval = NAME_MAX;
1866 break;
1867 case _PC_PATH_MAX:
1868 *ap->a_retval = PATH_MAX;
1869 break;
1870 case _PC_CHOWN_RESTRICTED:
1871 *ap->a_retval = 1;
1872 break;
1873 case _PC_NO_TRUNC:
1874 *ap->a_retval = 1;
1875 break;
1876 case _PC_PIPE_BUF:
1877 return EINVAL;
1878 break;
1879 case _PC_NAME_CHARS_MAX:
1880 *ap->a_retval = NAME_MAX;
1881 break;
1882 case _PC_CASE_SENSITIVE:
1883 *ap->a_retval = 1;
1884 break;
1885 case _PC_CASE_PRESERVING:
1886 *ap->a_retval = 1;
1887 break;
1888 default:
1889 return EINVAL;
1890 }
1891 return 0;
1892 }
1893
1894 /*
1895 * Advisory record locking support (fcntl() POSIX style)
1896 */
1897 int
1898 afs_vop_advlock(ap)
1899 struct VOPPROT(advlock_args) /* {
1900 * struct vnode *a_vp;
1901 * caddr_t a_id;
1902 * int a_op;
1903 * struct flock *a_fl;
1904 * int a_flags;
1905 * } */ *ap;
1906 {
1907 int error;
1908 struct ucred *tcr;
1909 int clid;
1910 int op;
1911 #ifdef AFS_DARWIN80_ENV
1912 proc_t p;
1913 tcr=vop_cred;
1914 #else
1915 struct proc *p = current_proc();
1916 struct ucred cr;
1917 pcred_readlock(p);
1918 cr = *p->p_cred->pc_ucred;
1919 pcred_unlock(p);
1920 tcr=&cr;
1921 #endif
1922 if (ap->a_flags & F_POSIX) {
1923 #ifdef AFS_DARWIN80_ENV
1924 p = (proc_t) ap->a_id;
1925 clid = proc_pid(p);
1926 #else
1927 p = (struct proc *) ap->a_id;
1928 clid = p->p_pid;
1929 #endif
1930 } else {
1931 clid = (int)ap->a_id;
1932 }
1933 if (ap->a_op == F_UNLCK) {
1934 op = F_SETLK;
1935 } else if (ap->a_op == F_SETLK && ap->a_flags & F_WAIT) {
1936 op = F_SETLKW;
1937 } else {
1938 op = ap->a_op;
1939 }
1940 AFS_GLOCK();
1941 error = afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, op, tcr, clid);
1942 AFS_GUNLOCK();
1943 return error;
1944 }
1945
1946 int
1947 afs_vop_blktooff(ap)
1948 struct VOPPROT(blktooff_args) /* {
1949 * struct vnode *a_vp;
1950 * daddr_t a_lblkno;
1951 * off_t *a_offset;
1952 * } */ *ap;
1953 {
1954 *ap->a_offset = (off_t) (ap->a_lblkno * DEV_BSIZE);
1955 return 0;
1956 }
1957
1958 int
1959 afs_vop_offtoblk(ap)
1960 struct VOPPROT(offtoblk_args) /* {
1961 * struct vnode *a_vp;
1962 * off_t a_offset;
1963 * daddr_t *a_lblkno;
1964 * } */ *ap;
1965 {
1966 *ap->a_lblkno = (daddr_t) (ap->a_offset / DEV_BSIZE);
1967
1968 return (0);
1969 }
1970
1971 #ifndef AFS_DARWIN80_ENV
1972 int
1973 afs_vop_lock(ap)
1974 struct VOPPROT(lock_args) /* {
1975 * struct vnode *a_vp;
1976 * } */ *ap;
1977 {
1978 struct vnode *vp = ap->a_vp;
1979 struct vcache *avc = VTOAFS(vp);
1980
1981 if (vp->v_tag == VT_NON)
1982 return (ENOENT);
1983
1984 return (lockmgr(&avc->rwlock, ap->a_flags, &vp->v_interlock, ap->a_p));
1985 }
1986
1987 int
1988 afs_vop_unlock(ap)
1989 struct VOPPROT(unlock_args) /* {
1990 * struct vnode *a_vp;
1991 * } */ *ap;
1992 {
1993 struct vnode *vp = ap->a_vp;
1994 struct vcache *avc = VTOAFS(vp);
1995
1996 return (lockmgr
1997 (&avc->rwlock, ap->a_flags | LK_RELEASE, &vp->v_interlock,
1998 ap->a_p));
1999
2000 }
2001
2002 int
2003 afs_vop_truncate(ap)
2004 struct VOPPROT(truncate_args) /* {
2005 * struct vnode *a_vp;
2006 * off_t a_length;
2007 * int a_flags;
2008 * struct ucred *a_cred;
2009 * struct proc *a_p;
2010 * } */ *ap;
2011 {
2012 /* printf("stray afs_vop_truncate\n"); */
2013 return ENOTSUP;
2014 }
2015
2016 int
2017 afs_vop_update(ap)
2018 struct VOPPROT(update_args) /* {
2019 * struct vnode *a_vp;
2020 * struct timeval *a_access;
2021 * struct timeval *a_modify;
2022 * int a_waitfor;
2023 * } */ *ap;
2024 {
2025 /* printf("stray afs_vop_update\n"); */
2026 return ENOTSUP;
2027 }
2028
2029 int
2030 afs_vop_bmap(ap)
2031 struct VOPPROT(bmap_args) /* {
2032 * struct vnode *a_vp;
2033 * daddr_t a_bn;
2034 * struct vnode **a_vpp;
2035 * daddr_t *a_bnp;
2036 * int *a_runp;
2037 * int *a_runb;
2038 * } */ *ap;
2039 {
2040 int error;
2041 if (ap->a_bnp) {
2042 *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE);
2043 }
2044 if (ap->a_vpp) {
2045 *ap->a_vpp = ap->a_vp;
2046 }
2047 if (ap->a_runp != NULL)
2048 *ap->a_runp = 0;
2049 #ifdef notyet
2050 if (ap->a_runb != NULL)
2051 *ap->a_runb = 0;
2052 #endif
2053
2054 return 0;
2055 }
2056
2057 int
2058 afs_vop_strategy(ap)
2059 struct VOPPROT(strategy_args) /* {
2060 * struct buf *a_bp;
2061 * } */ *ap;
2062 {
2063 int error;
2064 AFS_GLOCK();
2065 error = afs_ustrategy(ap->a_bp);
2066 AFS_GUNLOCK();
2067 return error;
2068 }
2069
2070 int
2071 afs_vop_print(ap)
2072 struct VOPPROT(print_args) /* {
2073 * struct vnode *a_vp;
2074 * } */ *ap;
2075 {
2076 struct vnode *vp = ap->a_vp;
2077 struct vcache *vc = VTOAFS(ap->a_vp);
2078 int s = vc->f.states;
2079 printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
2080 vc->f.fid.Cell, vc->f.fid.Fid.Volume, vc->f.fid.Fid.Vnode,
2081 vc->f.fid.Fid.Unique, vc->opens, vc->execsOrWriters);
2082 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
2083 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
2084 (s & CMAPPED) ? " mapped" : "",
2085 (s & CVFlushed) ? " flush in progress" : "");
2086 if (UBCISVALID(vp)) {
2087 printf("\n UBC: ");
2088 if (UBCINFOEXISTS(vp)) {
2089 printf("exists, ");
2090 printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
2091 ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
2092 ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
2093 } else
2094 printf("does not exist");
2095 }
2096 printf("\n");
2097 return 0;
2098 }
2099
2100 int
2101 afs_vop_islocked(ap)
2102 struct VOPPROT(islocked_args) /* {
2103 * struct vnode *a_vp;
2104 * } */ *ap;
2105 {
2106 struct vcache *vc = VTOAFS(ap->a_vp);
2107 return lockstatus(&vc->rwlock);
2108 }
2109
2110 int
2111 afs_vop_cmap(ap)
2112 struct VOPPROT(cmap_args) /* {
2113 * struct vnode *a_vp;
2114 * off_t a_foffset;
2115 * size_t a_size;
2116 * daddr_t *a_bpn;
2117 * size_t *a_run;
2118 * void *a_poff;
2119 * } */ *ap;
2120 {
2121 *ap->a_bpn = (daddr_t) (ap->a_foffset / DEV_BSIZE);
2122 *ap->a_run = MAX(ap->a_size, AFS_CHUNKSIZE(ap->a_foffset));
2123 return 0;
2124 }
2125 #endif
2126
2127 int
2128 afs_darwin_getnewvnode(struct vcache *avc)
2129 {
2130 #ifdef AFS_DARWIN80_ENV
2131 vnode_t vp;
2132 int error, dead;
2133 struct vnode_fsparam par;
2134
2135 memset(&par, 0, sizeof(struct vnode_fsparam));
2136 par.vnfs_vtype = VNON;
2137 par.vnfs_vops = afs_dead_vnodeop_p;
2138 par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
2139 par.vnfs_mp = afs_globalVFS;
2140 par.vnfs_fsnode = avc;
2141
2142 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &vp);
2143 if (!error) {
2144 vnode_addfsref(vp);
2145 vnode_ref(vp);
2146 avc->v = vp;
2147 vnode_recycle(vp); /* terminate as soon as iocount drops */
2148 avc->f.states |= CDeadVnode;
2149 }
2150 return error;
2151 #else
2152 while (getnewvnode(VT_AFS, afs_globalVFS, afs_vnodeop_p, &avc->v)) {
2153 /* no vnodes available, force an alloc (limits be damned)! */
2154 printf("failed to get vnode\n");
2155 }
2156 avc->v->v_data = (void *)avc;
2157 return 0;
2158 #endif
2159 }
2160 #ifdef AFS_DARWIN80_ENV
2161 /* if this fails, then tvc has been unrefed and may have been freed.
2162 Don't touch! */
2163 int
2164 afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp,
2165 struct componentname *cnp, int isroot, int locked)
2166 {
2167 vnode_t ovp;
2168 vnode_t nvp;
2169 int error;
2170 struct vnode_fsparam par;
2171
2172 if (!locked) {
2173 AFS_GLOCK();
2174 ObtainWriteLock(&avc->lock,325);
2175 }
2176 ovp = AFSTOV(avc);
2177
2178 if (!(avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
2179 AFS_GUNLOCK();
2180 #if 0 /* unsupported */
2181 if (dvp && cnp)
2182 vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
2183 cnp->cn_hash,
2184 VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
2185 #endif
2186 /* Can end up in reclaim... drop GLOCK */
2187 vnode_rele(ovp);
2188 AFS_GLOCK();
2189 if (!locked) {
2190 ReleaseWriteLock(&avc->lock);
2191 AFS_GUNLOCK();
2192 }
2193 return 0;
2194 }
2195
2196 if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
2197 panic("vcache %p should not be CDeadVnode", avc);
2198 AFS_GUNLOCK();
2199 memset(&par, 0, sizeof(struct vnode_fsparam));
2200 par.vnfs_mp = afs_globalVFS;
2201 par.vnfs_vtype = avc->f.m.Type;
2202 par.vnfs_vops = afs_vnodeop_p;
2203 par.vnfs_filesize = avc->f.m.Length;
2204 par.vnfs_fsnode = avc;
2205 par.vnfs_dvp = dvp;
2206 if (cnp && (cnp->cn_flags & ISDOTDOT) == 0)
2207 par.vnfs_cnp = cnp;
2208 if (!dvp || !cnp || (cnp->cn_flags & MAKEENTRY) == 0)
2209 par.vnfs_flags = VNFS_NOCACHE;
2210 if (isroot)
2211 par.vnfs_markroot = 1;
2212 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
2213 if (!error) {
2214 vnode_addfsref(nvp);
2215 if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
2216 printf("vcache %p should not be CDeadVnode", avc);
2217 if (avc->v == ovp) {
2218 if (!(avc->f.states & CVInit)) {
2219 vnode_clearfsnode(ovp);
2220 vnode_removefsref(ovp);
2221 }
2222 /* we're discarding on a fixup. mark for recycle */
2223 if (!(avc->f.states & CDeadVnode))
2224 vnode_recycle(ovp);
2225 }
2226 avc->v = nvp;
2227 avc->f.states &=~ CDeadVnode;
2228 /* If we were carrying an extra ref for dirty, hold/push it. */
2229 if (avc->f.ddirty_flags) {
2230 vnode_get(nvp);
2231 vnode_ref(nvp);
2232 }
2233 /* If we were carrying an extra ref for shadow, hold/push it. */
2234 if (avc->f.shadow.vnode) {
2235 vnode_get(nvp);
2236 vnode_ref(nvp);
2237 }
2238 }
2239 /* Drop any extra dirty ref on the old vnode */
2240 if (avc->f.ddirty_flags) {
2241 vnode_put(ovp);
2242 vnode_rele(ovp);
2243 }
2244 /* Drop any extra shadow ref on the old vnode */
2245 if (avc->f.shadow.vnode) {
2246 vnode_put(ovp);
2247 vnode_rele(ovp);
2248 }
2249 /* If it's ref'd still, unmark stat'd to force new lookup */
2250 if ((vnode_vtype(ovp) != avc->f.m.Type) && VREFCOUNT_GT(avc, 1))
2251 avc->f.states &= ~CStatd;
2252
2253 vnode_put(ovp);
2254 vnode_rele(ovp);
2255 AFS_GLOCK();
2256 if (!locked)
2257 ReleaseWriteLock(&avc->lock);
2258 if (!error)
2259 afs_osi_Wakeup(&avc->f.states);
2260 if (!locked)
2261 AFS_GUNLOCK();
2262 return error;
2263 }
2264 #endif