Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * A large chunk of this file appears to be copied directly from | |
3 | * sys/nfsclient/nfs_bio.c, which has the following license: | |
4 | */ | |
5 | /* | |
6 | * Copyright (c) 1989, 1993 | |
7 | * The Regents of the University of California. All rights reserved. | |
8 | * | |
9 | * This code is derived from software contributed to Berkeley by | |
10 | * Rick Macklem at The University of Guelph. | |
11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * 3. All advertising materials mentioning features or use of this software | |
21 | * must display the following acknowledgement: | |
22 | * This product includes software developed by the University of | |
23 | * California, Berkeley and its contributors. | |
24 | * 4. Neither the name of the University nor the names of its contributors | |
25 | * may be used to endorse or promote products derived from this software | |
26 | * without specific prior written permission. | |
27 | * | |
28 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
38 | * SUCH DAMAGE. | |
39 | * | |
40 | * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 | |
41 | */ | |
42 | /* | |
43 | * Pursuant to a statement of U.C. Berkeley dated 1999-07-22, this license | |
44 | * is amended to drop clause (3) above. | |
45 | */ | |
46 | ||
47 | #include <afsconfig.h> | |
48 | #include <afs/param.h> | |
49 | ||
50 | ||
51 | #include <afs/sysincludes.h> /* Standard vendor system headers */ | |
52 | #include <afsincludes.h> /* Afs-based standard headers */ | |
53 | #include <afs/afs_stats.h> /* statistics */ | |
54 | #include <sys/malloc.h> | |
55 | #include <sys/namei.h> | |
56 | #include <sys/unistd.h> | |
57 | #if __FreeBSD_version >= 1000030 | |
58 | #include <sys/rwlock.h> | |
59 | #endif | |
60 | #include <vm/vm_page.h> | |
61 | #include <vm/vm_object.h> | |
62 | #include <vm/vm_pager.h> | |
63 | #include <vm/vnode_pager.h> | |
64 | extern int afs_pbuf_freecnt; | |
65 | ||
66 | #ifdef AFS_FBSD60_ENV | |
67 | static vop_access_t afs_vop_access; | |
68 | static vop_advlock_t afs_vop_advlock; | |
69 | static vop_close_t afs_vop_close; | |
70 | static vop_create_t afs_vop_create; | |
71 | static vop_fsync_t afs_vop_fsync; | |
72 | static vop_getattr_t afs_vop_getattr; | |
73 | static vop_getpages_t afs_vop_getpages; | |
74 | static vop_inactive_t afs_vop_inactive; | |
75 | static vop_ioctl_t afs_vop_ioctl; | |
76 | static vop_link_t afs_vop_link; | |
77 | static vop_lookup_t afs_vop_lookup; | |
78 | static vop_mkdir_t afs_vop_mkdir; | |
79 | static vop_mknod_t afs_vop_mknod; | |
80 | static vop_open_t afs_vop_open; | |
81 | static vop_pathconf_t afs_vop_pathconf; | |
82 | static vop_print_t afs_vop_print; | |
83 | static vop_putpages_t afs_vop_putpages; | |
84 | static vop_read_t afs_vop_read; | |
85 | static vop_readdir_t afs_vop_readdir; | |
86 | static vop_readlink_t afs_vop_readlink; | |
87 | static vop_reclaim_t afs_vop_reclaim; | |
88 | static vop_remove_t afs_vop_remove; | |
89 | static vop_rename_t afs_vop_rename; | |
90 | static vop_rmdir_t afs_vop_rmdir; | |
91 | static vop_setattr_t afs_vop_setattr; | |
92 | static vop_strategy_t afs_vop_strategy; | |
93 | static vop_symlink_t afs_vop_symlink; | |
94 | static vop_write_t afs_vop_write; | |
95 | #if defined(AFS_FBSD70_ENV) && !defined(AFS_FBSD80_ENV) | |
96 | static vop_lock1_t afs_vop_lock; | |
97 | static vop_unlock_t afs_vop_unlock; | |
98 | static vop_islocked_t afs_vop_islocked; | |
99 | #endif | |
100 | ||
101 | struct vop_vector afs_vnodeops = { | |
102 | .vop_default = &default_vnodeops, | |
103 | .vop_access = afs_vop_access, | |
104 | .vop_advlock = afs_vop_advlock, | |
105 | .vop_close = afs_vop_close, | |
106 | .vop_create = afs_vop_create, | |
107 | .vop_fsync = afs_vop_fsync, | |
108 | .vop_getattr = afs_vop_getattr, | |
109 | .vop_getpages = afs_vop_getpages, | |
110 | .vop_inactive = afs_vop_inactive, | |
111 | .vop_ioctl = afs_vop_ioctl, | |
112 | #if !defined(AFS_FBSD80_ENV) | |
113 | /* removed at least temporarily (NFSv4 flux) */ | |
114 | .vop_lease = VOP_NULL, | |
115 | #endif | |
116 | .vop_link = afs_vop_link, | |
117 | .vop_lookup = afs_vop_lookup, | |
118 | .vop_mkdir = afs_vop_mkdir, | |
119 | .vop_mknod = afs_vop_mknod, | |
120 | .vop_open = afs_vop_open, | |
121 | .vop_pathconf = afs_vop_pathconf, | |
122 | .vop_print = afs_vop_print, | |
123 | .vop_putpages = afs_vop_putpages, | |
124 | .vop_read = afs_vop_read, | |
125 | .vop_readdir = afs_vop_readdir, | |
126 | .vop_readlink = afs_vop_readlink, | |
127 | .vop_reclaim = afs_vop_reclaim, | |
128 | .vop_remove = afs_vop_remove, | |
129 | .vop_rename = afs_vop_rename, | |
130 | .vop_rmdir = afs_vop_rmdir, | |
131 | .vop_setattr = afs_vop_setattr, | |
132 | .vop_strategy = afs_vop_strategy, | |
133 | .vop_symlink = afs_vop_symlink, | |
134 | .vop_write = afs_vop_write, | |
135 | #if defined(AFS_FBSD70_ENV) && !defined(AFS_FBSD80_ENV) | |
136 | .vop_lock1 = afs_vop_lock, | |
137 | .vop_unlock = afs_vop_unlock, | |
138 | .vop_islocked = afs_vop_islocked, | |
139 | #endif | |
140 | }; | |
141 | ||
142 | #else /* AFS_FBSD60_ENV */ | |
143 | ||
144 | int afs_vop_lookup(struct vop_lookup_args *); | |
145 | int afs_vop_create(struct vop_create_args *); | |
146 | int afs_vop_mknod(struct vop_mknod_args *); | |
147 | int afs_vop_open(struct vop_open_args *); | |
148 | int afs_vop_close(struct vop_close_args *); | |
149 | int afs_vop_access(struct vop_access_args *); | |
150 | int afs_vop_getattr(struct vop_getattr_args *); | |
151 | int afs_vop_setattr(struct vop_setattr_args *); | |
152 | int afs_vop_read(struct vop_read_args *); | |
153 | int afs_vop_write(struct vop_write_args *); | |
154 | int afs_vop_getpages(struct vop_getpages_args *); | |
155 | int afs_vop_putpages(struct vop_putpages_args *); | |
156 | int afs_vop_ioctl(struct vop_ioctl_args *); | |
157 | static int afs_vop_pathconf(struct vop_pathconf_args *); | |
158 | int afs_vop_fsync(struct vop_fsync_args *); | |
159 | int afs_vop_remove(struct vop_remove_args *); | |
160 | int afs_vop_link(struct vop_link_args *); | |
161 | int afs_vop_rename(struct vop_rename_args *); | |
162 | int afs_vop_mkdir(struct vop_mkdir_args *); | |
163 | int afs_vop_rmdir(struct vop_rmdir_args *); | |
164 | int afs_vop_symlink(struct vop_symlink_args *); | |
165 | int afs_vop_readdir(struct vop_readdir_args *); | |
166 | int afs_vop_readlink(struct vop_readlink_args *); | |
167 | int afs_vop_inactive(struct vop_inactive_args *); | |
168 | int afs_vop_reclaim(struct vop_reclaim_args *); | |
169 | int afs_vop_bmap(struct vop_bmap_args *); | |
170 | int afs_vop_strategy(struct vop_strategy_args *); | |
171 | int afs_vop_print(struct vop_print_args *); | |
172 | int afs_vop_advlock(struct vop_advlock_args *); | |
173 | ||
174 | ||
175 | ||
176 | /* Global vfs data structures for AFS. */ | |
177 | vop_t **afs_vnodeop_p; | |
178 | struct vnodeopv_entry_desc afs_vnodeop_entries[] = { | |
179 | {&vop_default_desc, (vop_t *) vop_defaultop}, | |
180 | {&vop_access_desc, (vop_t *) afs_vop_access}, /* access */ | |
181 | {&vop_advlock_desc, (vop_t *) afs_vop_advlock}, /* advlock */ | |
182 | {&vop_bmap_desc, (vop_t *) afs_vop_bmap}, /* bmap */ | |
183 | {&vop_close_desc, (vop_t *) afs_vop_close}, /* close */ | |
184 | {&vop_createvobject_desc, (vop_t *) vop_stdcreatevobject}, | |
185 | {&vop_destroyvobject_desc, (vop_t *) vop_stddestroyvobject}, | |
186 | {&vop_create_desc, (vop_t *) afs_vop_create}, /* create */ | |
187 | {&vop_fsync_desc, (vop_t *) afs_vop_fsync}, /* fsync */ | |
188 | {&vop_getattr_desc, (vop_t *) afs_vop_getattr}, /* getattr */ | |
189 | {&vop_getpages_desc, (vop_t *) afs_vop_getpages}, /* read */ | |
190 | {&vop_getvobject_desc, (vop_t *) vop_stdgetvobject}, | |
191 | {&vop_putpages_desc, (vop_t *) afs_vop_putpages}, /* write */ | |
192 | {&vop_inactive_desc, (vop_t *) afs_vop_inactive}, /* inactive */ | |
193 | {&vop_lease_desc, (vop_t *) vop_null}, | |
194 | {&vop_link_desc, (vop_t *) afs_vop_link}, /* link */ | |
195 | {&vop_lookup_desc, (vop_t *) afs_vop_lookup}, /* lookup */ | |
196 | {&vop_mkdir_desc, (vop_t *) afs_vop_mkdir}, /* mkdir */ | |
197 | {&vop_mknod_desc, (vop_t *) afs_vop_mknod}, /* mknod */ | |
198 | {&vop_open_desc, (vop_t *) afs_vop_open}, /* open */ | |
199 | {&vop_pathconf_desc, (vop_t *) afs_vop_pathconf}, /* pathconf */ | |
200 | {&vop_poll_desc, (vop_t *) vop_nopoll}, /* select */ | |
201 | {&vop_print_desc, (vop_t *) afs_vop_print}, /* print */ | |
202 | {&vop_read_desc, (vop_t *) afs_vop_read}, /* read */ | |
203 | {&vop_readdir_desc, (vop_t *) afs_vop_readdir}, /* readdir */ | |
204 | {&vop_readlink_desc, (vop_t *) afs_vop_readlink}, /* readlink */ | |
205 | {&vop_reclaim_desc, (vop_t *) afs_vop_reclaim}, /* reclaim */ | |
206 | {&vop_remove_desc, (vop_t *) afs_vop_remove}, /* remove */ | |
207 | {&vop_rename_desc, (vop_t *) afs_vop_rename}, /* rename */ | |
208 | {&vop_rmdir_desc, (vop_t *) afs_vop_rmdir}, /* rmdir */ | |
209 | {&vop_setattr_desc, (vop_t *) afs_vop_setattr}, /* setattr */ | |
210 | {&vop_strategy_desc, (vop_t *) afs_vop_strategy}, /* strategy */ | |
211 | {&vop_symlink_desc, (vop_t *) afs_vop_symlink}, /* symlink */ | |
212 | {&vop_write_desc, (vop_t *) afs_vop_write}, /* write */ | |
213 | {&vop_ioctl_desc, (vop_t *) afs_vop_ioctl}, /* XXX ioctl */ | |
214 | /*{ &vop_seek_desc, afs_vop_seek }, *//* seek */ | |
215 | #if defined(AFS_FBSD70_ENV) && !defined(AFS_FBSD90_ENV) | |
216 | {&vop_lock1_desc, (vop_t *) afs_vop_lock}, /* lock */ | |
217 | {&vop_unlock_desc, (vop_t *) afs_vop_unlock}, /* unlock */ | |
218 | {&vop_islocked_desc, (vop_t *) afs_vop_islocked}, /* islocked */ | |
219 | #endif | |
220 | {NULL, NULL} | |
221 | }; | |
222 | struct vnodeopv_desc afs_vnodeop_opv_desc = | |
223 | { &afs_vnodeop_p, afs_vnodeop_entries }; | |
224 | #endif /* AFS_FBSD60_ENV */ | |
225 | ||
226 | #define GETNAME() \ | |
227 | struct componentname *cnp = ap->a_cnp; \ | |
228 | char *name; \ | |
229 | MALLOC(name, char *, cnp->cn_namelen+1, M_TEMP, M_WAITOK); \ | |
230 | memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \ | |
231 | name[cnp->cn_namelen] = '\0' | |
232 | ||
233 | #define DROPNAME() FREE(name, M_TEMP) | |
234 | ||
235 | /* | |
236 | * Here we define compatibility functions/macros for interfaces that | |
237 | * have changed between different FreeBSD versions. | |
238 | */ | |
239 | #if defined(AFS_FBSD90_ENV) | |
240 | static __inline void ma_vm_page_lock_queues(void) {}; | |
241 | static __inline void ma_vm_page_unlock_queues(void) {}; | |
242 | static __inline void ma_vm_page_lock(vm_page_t m) { vm_page_lock(m); }; | |
243 | static __inline void ma_vm_page_unlock(vm_page_t m) { vm_page_unlock(m); }; | |
244 | #else | |
245 | static __inline void ma_vm_page_lock_queues(void) { vm_page_lock_queues(); }; | |
246 | static __inline void ma_vm_page_unlock_queues(void) { vm_page_unlock_queues(); }; | |
247 | static __inline void ma_vm_page_lock(vm_page_t m) {}; | |
248 | static __inline void ma_vm_page_unlock(vm_page_t m) {}; | |
249 | #endif | |
250 | ||
251 | #if defined(AFS_FBSD80_ENV) | |
252 | #define ma_vn_lock(vp, flags, p) (vn_lock(vp, flags)) | |
253 | #define MA_VOP_LOCK(vp, flags, p) (VOP_LOCK(vp, flags)) | |
254 | #define MA_VOP_UNLOCK(vp, flags, p) (VOP_UNLOCK(vp, flags)) | |
255 | #else | |
256 | #define ma_vn_lock(vp, flags, p) (vn_lock(vp, flags, p)) | |
257 | #define MA_VOP_LOCK(vp, flags, p) (VOP_LOCK(vp, flags, p)) | |
258 | #define MA_VOP_UNLOCK(vp, flags, p) (VOP_UNLOCK(vp, flags, p)) | |
259 | #endif | |
260 | ||
261 | #if defined(AFS_FBSD70_ENV) | |
262 | #define MA_PCPU_INC(c) PCPU_INC(c) | |
263 | #define MA_PCPU_ADD(c, n) PCPU_ADD(c, n) | |
264 | #else | |
265 | #define MA_PCPU_INC(c) PCPU_LAZY_INC(c) | |
266 | #define MA_PCPU_ADD(c, n) (c) += (n) | |
267 | #endif | |
268 | ||
269 | #if __FreeBSD_version >= 1000030 | |
270 | #define AFS_VM_OBJECT_WLOCK(o) VM_OBJECT_WLOCK(o) | |
271 | #define AFS_VM_OBJECT_WUNLOCK(o) VM_OBJECT_WUNLOCK(o) | |
272 | #else | |
273 | #define AFS_VM_OBJECT_WLOCK(o) VM_OBJECT_LOCK(o) | |
274 | #define AFS_VM_OBJECT_WUNLOCK(o) VM_OBJECT_UNLOCK(o) | |
275 | #endif | |
276 | ||
277 | #ifdef AFS_FBSD70_ENV | |
278 | #ifndef AFS_FBSD80_ENV | |
279 | /* From kern_lock.c */ | |
280 | #define COUNT(td, x) if ((td)) (td)->td_locks += (x) | |
281 | #define LK_ALL (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE | \ | |
282 | LK_SHARE_NONZERO | LK_WAIT_NONZERO) | |
283 | ||
284 | static __inline void | |
285 | sharelock(struct thread *td, struct lock *lkp, int incr) { | |
286 | lkp->lk_flags |= LK_SHARE_NONZERO; | |
287 | lkp->lk_sharecount += incr; | |
288 | COUNT(td, incr); | |
289 | } | |
290 | #endif | |
291 | ||
292 | /* | |
293 | * Standard lock, unlock and islocked functions. | |
294 | */ | |
295 | int | |
296 | afs_vop_lock(ap) | |
297 | struct vop_lock1_args /* { | |
298 | struct vnode *a_vp; | |
299 | int a_flags; | |
300 | struct thread *a_td; | |
301 | char *file; | |
302 | int line; | |
303 | } */ *ap; | |
304 | { | |
305 | struct vnode *vp = ap->a_vp; | |
306 | struct lock *lkp = vp->v_vnlock; | |
307 | ||
308 | #if 0 && defined(AFS_FBSD80_ENV) && !defined(UKERNEL) | |
309 | afs_warn("afs_vop_lock: tid %d pid %d \"%s\"\n", curthread->td_tid, | |
310 | curthread->td_proc->p_pid, curthread->td_name); | |
311 | kdb_backtrace(); | |
312 | #endif | |
313 | ||
314 | #ifdef AFS_FBSD80_ENV | |
315 | return (_lockmgr_args(lkp, ap->a_flags, VI_MTX(vp), | |
316 | LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, | |
317 | ap->a_file, ap->a_line)); | |
318 | #else | |
319 | return (_lockmgr(lkp, ap->a_flags, VI_MTX(vp), ap->a_td, ap->a_file, ap->a_line)); | |
320 | #endif | |
321 | } | |
322 | ||
323 | /* See above. */ | |
324 | int | |
325 | afs_vop_unlock(ap) | |
326 | struct vop_unlock_args /* { | |
327 | struct vnode *a_vp; | |
328 | int a_flags; | |
329 | struct thread *a_td; | |
330 | } */ *ap; | |
331 | { | |
332 | struct vnode *vp = ap->a_vp; | |
333 | struct lock *lkp = vp->v_vnlock; | |
334 | ||
335 | #ifdef AFS_FBSD80_ENV | |
336 | int code = 0; | |
337 | u_int op; | |
338 | op = ((ap->a_flags) | LK_RELEASE) & LK_TYPE_MASK; | |
339 | int glocked = ISAFS_GLOCK(); | |
340 | if (glocked) | |
341 | AFS_GUNLOCK(); | |
342 | if ((op & (op - 1)) != 0) { | |
343 | afs_warn("afs_vop_unlock: Shit.\n"); | |
344 | goto done; | |
345 | } | |
346 | code = lockmgr(lkp, ap->a_flags | LK_RELEASE, VI_MTX(vp)); | |
347 | done: | |
348 | if (glocked) | |
349 | AFS_GLOCK(); | |
350 | return(code); | |
351 | #else | |
352 | /* possibly in current code path where this | |
353 | * forces trace, we should have had a (shared? not | |
354 | * necessarily, see _lockmgr in kern_lock.c) lock | |
355 | * and that's the real bug. but. | |
356 | */ | |
357 | critical_enter(); | |
358 | if ((lkp->lk_exclusivecount == 0) && | |
359 | (!(lkp->lk_flags & LK_SHARE_NONZERO))) { | |
360 | sharelock(ap->a_td, lkp, 1); | |
361 | } | |
362 | critical_exit(); | |
363 | return (lockmgr(lkp, ap->a_flags | LK_RELEASE, VI_MTX(vp), | |
364 | ap->a_td)); | |
365 | #endif | |
366 | } | |
367 | ||
368 | /* See above. */ | |
369 | int | |
370 | afs_vop_islocked(ap) | |
371 | struct vop_islocked_args /* { | |
372 | struct vnode *a_vp; | |
373 | struct thread *a_td; (not in 80) | |
374 | } */ *ap; | |
375 | { | |
376 | #ifdef AFS_FBSD80_ENV | |
377 | return (lockstatus(ap->a_vp->v_vnlock)); | |
378 | #else | |
379 | return (lockstatus(ap->a_vp->v_vnlock, ap->a_td)); | |
380 | #endif | |
381 | } | |
382 | #endif /* 70 */ | |
383 | ||
384 | /* | |
385 | * Mosty copied from sys/ufs/ufs/ufs_vnops.c:ufs_pathconf(). | |
386 | * We should know the correct answers to these questions with | |
387 | * respect to the AFS protocol (which may differ from the UFS | |
388 | * values) but for the moment this will do. | |
389 | */ | |
390 | static int | |
391 | afs_vop_pathconf(struct vop_pathconf_args *ap) | |
392 | { | |
393 | int error; | |
394 | ||
395 | error = 0; | |
396 | switch (ap->a_name) { | |
397 | case _PC_LINK_MAX: | |
398 | *ap->a_retval = LINK_MAX; | |
399 | break; | |
400 | case _PC_NAME_MAX: | |
401 | *ap->a_retval = NAME_MAX; | |
402 | break; | |
403 | case _PC_PATH_MAX: | |
404 | *ap->a_retval = PATH_MAX; | |
405 | break; | |
406 | case _PC_PIPE_BUF: | |
407 | *ap->a_retval = PIPE_BUF; | |
408 | break; | |
409 | case _PC_CHOWN_RESTRICTED: | |
410 | *ap->a_retval = 1; | |
411 | break; | |
412 | case _PC_NO_TRUNC: | |
413 | *ap->a_retval = 1; | |
414 | break; | |
415 | #ifdef _PC_ACL_EXTENDED | |
416 | case _PC_ACL_EXTENDED: | |
417 | *ap->a_retval = 0; | |
418 | break; | |
419 | case _PC_ACL_PATH_MAX: | |
420 | *ap->a_retval = 3; | |
421 | break; | |
422 | #endif | |
423 | #ifdef _PC_MAC_PRESENT | |
424 | case _PC_MAC_PRESENT: | |
425 | *ap->a_retval = 0; | |
426 | break; | |
427 | #endif | |
428 | #ifdef _PC_ASYNC_IO | |
429 | case _PC_ASYNC_IO: | |
430 | /* _PC_ASYNC_IO should have been handled by upper layers. */ | |
431 | KASSERT(0, ("_PC_ASYNC_IO should not get here")); | |
432 | error = EINVAL; | |
433 | break; | |
434 | case _PC_PRIO_IO: | |
435 | *ap->a_retval = 0; | |
436 | break; | |
437 | case _PC_SYNC_IO: | |
438 | *ap->a_retval = 0; | |
439 | break; | |
440 | #endif | |
441 | #ifdef _PC_ALLOC_SIZE_MIN | |
442 | case _PC_ALLOC_SIZE_MIN: | |
443 | *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; | |
444 | break; | |
445 | #endif | |
446 | #ifdef _PC_FILESIZEBITS | |
447 | case _PC_FILESIZEBITS: | |
448 | *ap->a_retval = 32; /* XXX */ | |
449 | break; | |
450 | #endif | |
451 | #ifdef _PC_REC_INCR_XFER_SIZE | |
452 | case _PC_REC_INCR_XFER_SIZE: | |
453 | *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; | |
454 | break; | |
455 | case _PC_REC_MAX_XFER_SIZE: | |
456 | *ap->a_retval = -1; /* means ``unlimited'' */ | |
457 | break; | |
458 | case _PC_REC_MIN_XFER_SIZE: | |
459 | *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; | |
460 | break; | |
461 | case _PC_REC_XFER_ALIGN: | |
462 | *ap->a_retval = PAGE_SIZE; | |
463 | break; | |
464 | #endif | |
465 | #ifdef _PC_SYMLINK_MAX | |
466 | case _PC_SYMLINK_MAX: | |
467 | *ap->a_retval = MAXPATHLEN; | |
468 | break; | |
469 | #endif | |
470 | default: | |
471 | error = EINVAL; | |
472 | break; | |
473 | } | |
474 | return (error); | |
475 | } | |
476 | ||
477 | int | |
478 | afs_vop_lookup(ap) | |
479 | struct vop_lookup_args /* { | |
480 | * struct vnodeop_desc * a_desc; | |
481 | * struct vnode *a_dvp; | |
482 | * struct vnode **a_vpp; | |
483 | * struct componentname *a_cnp; | |
484 | * } */ *ap; | |
485 | { | |
486 | int error; | |
487 | struct vcache *vcp; | |
488 | struct vnode *vp, *dvp; | |
489 | int flags = ap->a_cnp->cn_flags; | |
490 | int lockparent; /* 1 => lockparent flag is set */ | |
491 | int wantparent; /* 1 => wantparent or lockparent flag */ | |
492 | #ifndef AFS_FBSD80_ENV | |
493 | struct thread *p = ap->a_cnp->cn_thread; | |
494 | #endif | |
495 | ||
496 | dvp = ap->a_dvp; | |
497 | if (dvp->v_type != VDIR) { | |
498 | #ifndef AFS_FBSD70_ENV | |
499 | *ap->a_vpp = 0; | |
500 | #endif | |
501 | return ENOTDIR; | |
502 | } | |
503 | ||
504 | if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) | |
505 | return EIO; | |
506 | ||
507 | GETNAME(); | |
508 | ||
509 | lockparent = flags & LOCKPARENT; | |
510 | wantparent = flags & (LOCKPARENT | WANTPARENT); | |
511 | ||
512 | #if __FreeBSD_version < 1000021 | |
513 | cnp->cn_flags |= MPSAFE; /* steel */ | |
514 | #endif | |
515 | ||
516 | if (flags & ISDOTDOT) | |
517 | MA_VOP_UNLOCK(dvp, 0, p); | |
518 | ||
519 | AFS_GLOCK(); | |
520 | error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred); | |
521 | AFS_GUNLOCK(); | |
522 | ||
523 | if (error) { | |
524 | if (flags & ISDOTDOT) | |
525 | MA_VOP_LOCK(dvp, LK_EXCLUSIVE | LK_RETRY, p); | |
526 | if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) | |
527 | && (flags & ISLASTCN) && error == ENOENT) | |
528 | error = EJUSTRETURN; | |
529 | if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) | |
530 | cnp->cn_flags |= SAVENAME; | |
531 | DROPNAME(); | |
532 | *ap->a_vpp = 0; | |
533 | return (error); | |
534 | } | |
535 | vp = AFSTOV(vcp); /* always get a node if no error */ | |
536 | ||
537 | /* The parent directory comes in locked. We unlock it on return | |
538 | * unless the caller wants it left locked. | |
539 | * we also always return the vnode locked. */ | |
540 | ||
541 | if (flags & ISDOTDOT) { | |
542 | /* vp before dvp since we go root to leaf, and .. comes first */ | |
543 | ma_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); | |
544 | ma_vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); | |
545 | /* always return the child locked */ | |
546 | if (lockparent && (flags & ISLASTCN) | |
547 | && (error = ma_vn_lock(dvp, LK_EXCLUSIVE, p))) { | |
548 | vput(vp); | |
549 | DROPNAME(); | |
550 | return (error); | |
551 | } | |
552 | } else if (vp == dvp) { | |
553 | /* they're the same; afs_lookup() already ref'ed the leaf. | |
554 | * It came in locked, so we don't need to ref OR lock it */ | |
555 | } else { | |
556 | if (!lockparent || !(flags & ISLASTCN)) { | |
557 | #ifndef AFS_FBSD70_ENV /* 6 too? */ | |
558 | MA_VOP_UNLOCK(dvp, 0, p); /* done with parent. */ | |
559 | #endif | |
560 | } | |
561 | ma_vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, p); | |
562 | /* always return the child locked */ | |
563 | } | |
564 | *ap->a_vpp = vp; | |
565 | ||
566 | if ((cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) | |
567 | || (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))) | |
568 | cnp->cn_flags |= SAVENAME; | |
569 | ||
570 | DROPNAME(); | |
571 | return error; | |
572 | } | |
573 | ||
574 | int | |
575 | afs_vop_create(ap) | |
576 | struct vop_create_args /* { | |
577 | * struct vnode *a_dvp; | |
578 | * struct vnode **a_vpp; | |
579 | * struct componentname *a_cnp; | |
580 | * struct vattr *a_vap; | |
581 | * } */ *ap; | |
582 | { | |
583 | int error = 0; | |
584 | struct vcache *vcp; | |
585 | struct vnode *dvp = ap->a_dvp; | |
586 | #ifndef AFS_FBSD80_ENV | |
587 | struct thread *p = ap->a_cnp->cn_thread; | |
588 | #endif | |
589 | GETNAME(); | |
590 | ||
591 | AFS_GLOCK(); | |
592 | error = | |
593 | afs_create(VTOAFS(dvp), name, ap->a_vap, | |
594 | ap->a_vap->va_vaflags & VA_EXCLUSIVE ? EXCL : NONEXCL, | |
595 | ap->a_vap->va_mode, &vcp, cnp->cn_cred); | |
596 | AFS_GUNLOCK(); | |
597 | if (error) { | |
598 | DROPNAME(); | |
599 | return (error); | |
600 | } | |
601 | ||
602 | if (vcp) { | |
603 | *ap->a_vpp = AFSTOV(vcp); | |
604 | ma_vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p); | |
605 | } else | |
606 | *ap->a_vpp = 0; | |
607 | ||
608 | DROPNAME(); | |
609 | return error; | |
610 | } | |
611 | ||
612 | int | |
613 | afs_vop_mknod(ap) | |
614 | struct vop_mknod_args /* { | |
615 | * struct vnode *a_dvp; | |
616 | * struct vnode **a_vpp; | |
617 | * struct componentname *a_cnp; | |
618 | * struct vattr *a_vap; | |
619 | * } */ *ap; | |
620 | { | |
621 | return (ENODEV); | |
622 | } | |
623 | ||
624 | #if 0 | |
625 | static int | |
626 | validate_vops(struct vnode *vp, int after) | |
627 | { | |
628 | int ret = 0; | |
629 | struct vnodeopv_entry_desc *this; | |
630 | for (this = afs_vnodeop_entries; this->opve_op; this++) { | |
631 | if (vp->v_op[this->opve_op->vdesc_offset] != this->opve_impl) { | |
632 | if (!ret) { | |
633 | printf("v_op %d ", after); | |
634 | vprint("check", vp); | |
635 | } | |
636 | ret = 1; | |
637 | printf("For oper %d (%s), func is %p, not %p", | |
638 | this->opve_op->vdesc_offset, this->opve_op->vdesc_name, | |
639 | vp->v_op[this->opve_op->vdesc_offset], this->opve_impl); | |
640 | } | |
641 | } | |
642 | return ret; | |
643 | } | |
644 | #endif | |
645 | int | |
646 | afs_vop_open(ap) | |
647 | struct vop_open_args /* { | |
648 | * struct vnode *a_vp; | |
649 | * int a_mode; | |
650 | * struct ucred *a_cred; | |
651 | * struct thread *a_td; | |
652 | * struct file *a_fp; | |
653 | * } */ *ap; | |
654 | { | |
655 | int error; | |
656 | struct vcache *vc = VTOAFS(ap->a_vp); | |
657 | ||
658 | AFS_GLOCK(); | |
659 | error = afs_open(&vc, ap->a_mode, ap->a_cred); | |
660 | #ifdef DIAGNOSTIC | |
661 | if (AFSTOV(vc) != ap->a_vp) | |
662 | panic("AFS open changed vnode!"); | |
663 | #endif | |
664 | AFS_GUNLOCK(); | |
665 | #ifdef AFS_FBSD60_ENV | |
666 | vnode_create_vobject(ap->a_vp, vc->f.m.Length, ap->a_td); | |
667 | #endif | |
668 | osi_FlushPages(vc, ap->a_cred); | |
669 | return error; | |
670 | } | |
671 | ||
672 | int | |
673 | afs_vop_close(ap) | |
674 | struct vop_close_args /* { | |
675 | * struct vnode *a_vp; | |
676 | * int a_fflag; | |
677 | * struct ucred *a_cred; | |
678 | * struct thread *a_td; | |
679 | * } */ *ap; | |
680 | { | |
681 | int code, iflag; | |
682 | struct vnode *vp = ap->a_vp; | |
683 | struct vcache *avc = VTOAFS(vp); | |
684 | ||
685 | #if defined(AFS_FBSD80_ENV) | |
686 | VI_LOCK(vp); | |
687 | iflag = vp->v_iflag & VI_DOOMED; | |
688 | VI_UNLOCK(vp); | |
689 | if (iflag & VI_DOOMED) { | |
690 | /* osi_FlushVCache (correctly) calls vgone() on recycled vnodes, we don't | |
691 | * have an afs_close to process, in that case */ | |
692 | if (avc->opens != 0) | |
693 | panic("afs_vop_close: doomed vnode %p has vcache %p with non-zero opens %d\n", | |
694 | vp, avc, avc->opens); | |
695 | return 0; | |
696 | } | |
697 | #endif | |
698 | ||
699 | AFS_GLOCK(); | |
700 | if (ap->a_cred) | |
701 | code = afs_close(avc, ap->a_fflag, ap->a_cred); | |
702 | else | |
703 | code = afs_close(avc, ap->a_fflag, afs_osi_credp); | |
704 | osi_FlushPages(avc, ap->a_cred); /* hold GLOCK, but not basic vnode lock */ | |
705 | AFS_GUNLOCK(); | |
706 | return code; | |
707 | } | |
708 | ||
709 | int | |
710 | afs_vop_access(ap) | |
711 | struct vop_access_args /* { | |
712 | * struct vnode *a_vp; | |
713 | * accmode_t a_accmode; | |
714 | * struct ucred *a_cred; | |
715 | * struct thread *a_td; | |
716 | * } */ *ap; | |
717 | { | |
718 | int code; | |
719 | AFS_GLOCK(); | |
720 | #if defined(AFS_FBSD80_ENV) | |
721 | code = afs_access(VTOAFS(ap->a_vp), ap->a_accmode, ap->a_cred); | |
722 | #else | |
723 | code = afs_access(VTOAFS(ap->a_vp), ap->a_mode, ap->a_cred); | |
724 | #endif | |
725 | AFS_GUNLOCK(); | |
726 | return code; | |
727 | } | |
728 | ||
729 | int | |
730 | afs_vop_getattr(ap) | |
731 | struct vop_getattr_args /* { | |
732 | * struct vnode *a_vp; | |
733 | * struct vattr *a_vap; | |
734 | * struct ucred *a_cred; | |
735 | * } */ *ap; | |
736 | { | |
737 | int code; | |
738 | ||
739 | AFS_GLOCK(); | |
740 | code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred); | |
741 | AFS_GUNLOCK(); | |
742 | ||
743 | return code; | |
744 | } | |
745 | ||
746 | int | |
747 | afs_vop_setattr(ap) | |
748 | struct vop_setattr_args /* { | |
749 | * struct vnode *a_vp; | |
750 | * struct vattr *a_vap; | |
751 | * struct ucred *a_cred; | |
752 | * } */ *ap; | |
753 | { | |
754 | int code; | |
755 | AFS_GLOCK(); | |
756 | code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred); | |
757 | AFS_GUNLOCK(); | |
758 | return code; | |
759 | } | |
760 | ||
761 | int | |
762 | afs_vop_read(ap) | |
763 | struct vop_read_args /* { | |
764 | * struct vnode *a_vp; | |
765 | * struct uio *a_uio; | |
766 | * int a_ioflag; | |
767 | * struct ucred *a_cred; | |
768 | * | |
769 | * } */ *ap; | |
770 | { | |
771 | int code; | |
772 | struct vcache *avc = VTOAFS(ap->a_vp); | |
773 | AFS_GLOCK(); | |
774 | osi_FlushPages(avc, ap->a_cred); /* hold GLOCK, but not basic vnode lock */ | |
775 | code = afs_read(avc, ap->a_uio, ap->a_cred, 0); | |
776 | AFS_GUNLOCK(); | |
777 | return code; | |
778 | } | |
779 | ||
780 | /* struct vop_getpages_args { | |
781 | * struct vnode *a_vp; | |
782 | * vm_page_t *a_m; | |
783 | * int a_count; | |
784 | * int *a_rbehind; | |
785 | * int *a_rahead; | |
786 | * }; | |
787 | */ | |
788 | int | |
789 | afs_vop_getpages(struct vop_getpages_args *ap) | |
790 | { | |
791 | int code; | |
792 | int i, nextoff, size, toff, npages, count; | |
793 | struct uio uio; | |
794 | struct iovec iov; | |
795 | struct buf *bp; | |
796 | vm_offset_t kva; | |
797 | vm_object_t object; | |
798 | vm_page_t *pages; | |
799 | struct vnode *vp; | |
800 | struct vcache *avc; | |
801 | ||
802 | memset(&uio, 0, sizeof(uio)); | |
803 | memset(&iov, 0, sizeof(iov)); | |
804 | ||
805 | vp = ap->a_vp; | |
806 | avc = VTOAFS(vp); | |
807 | pages = ap->a_m; | |
808 | #ifdef FBSD_VOP_GETPAGES_BUSIED | |
809 | npages = ap->a_count; | |
810 | if (ap->a_rbehind) | |
811 | *ap->a_rbehind = 0; | |
812 | if (ap->a_rahead) | |
813 | *ap->a_rahead = 0; | |
814 | #else | |
815 | npages = btoc(ap->a_count); | |
816 | #endif | |
817 | ||
818 | if ((object = vp->v_object) == NULL) { | |
819 | printf("afs_getpages: called with non-merged cache vnode??\n"); | |
820 | return VM_PAGER_ERROR; | |
821 | } | |
822 | ||
823 | /* | |
824 | * If the requested page is partially valid, just return it and | |
825 | * allow the pager to zero-out the blanks. Partially valid pages | |
826 | * can only occur at the file EOF. | |
827 | */ | |
828 | { | |
829 | #ifdef FBSD_VOP_GETPAGES_BUSIED | |
830 | AFS_VM_OBJECT_WLOCK(object); | |
831 | ma_vm_page_lock_queues(); | |
832 | if(pages[npages - 1]->valid != 0) { | |
833 | if (--npages == 0) { | |
834 | ma_vm_page_unlock_queues(); | |
835 | AFS_VM_OBJECT_WUNLOCK(object); | |
836 | return (VM_PAGER_OK); | |
837 | } | |
838 | } | |
839 | #else | |
840 | vm_page_t m = pages[ap->a_reqpage]; | |
841 | AFS_VM_OBJECT_WLOCK(object); | |
842 | ma_vm_page_lock_queues(); | |
843 | if (m->valid != 0) { | |
844 | /* handled by vm_fault now */ | |
845 | /* vm_page_zero_invalid(m, TRUE); */ | |
846 | for (i = 0; i < npages; ++i) { | |
847 | if (i != ap->a_reqpage) { | |
848 | ma_vm_page_lock(pages[i]); | |
849 | vm_page_free(pages[i]); | |
850 | ma_vm_page_unlock(pages[i]); | |
851 | } | |
852 | } | |
853 | ma_vm_page_unlock_queues(); | |
854 | AFS_VM_OBJECT_WUNLOCK(object); | |
855 | return (0); | |
856 | } | |
857 | #endif | |
858 | ma_vm_page_unlock_queues(); | |
859 | AFS_VM_OBJECT_WUNLOCK(object); | |
860 | } | |
861 | bp = getpbuf(&afs_pbuf_freecnt); | |
862 | ||
863 | kva = (vm_offset_t) bp->b_data; | |
864 | pmap_qenter(kva, pages, npages); | |
865 | MA_PCPU_INC(cnt.v_vnodein); | |
866 | MA_PCPU_ADD(cnt.v_vnodepgsin, npages); | |
867 | ||
868 | #ifdef FBSD_VOP_GETPAGES_BUSIED | |
869 | count = ctob(npages); | |
870 | #else | |
871 | count = ap->a_count; | |
872 | #endif | |
873 | iov.iov_base = (caddr_t) kva; | |
874 | iov.iov_len = count; | |
875 | uio.uio_iov = &iov; | |
876 | uio.uio_iovcnt = 1; | |
877 | uio.uio_offset = IDX_TO_OFF(pages[0]->pindex); | |
878 | uio.uio_resid = count; | |
879 | uio.uio_segflg = UIO_SYSSPACE; | |
880 | uio.uio_rw = UIO_READ; | |
881 | uio.uio_td = curthread; | |
882 | ||
883 | AFS_GLOCK(); | |
884 | osi_FlushPages(avc, osi_curcred()); /* hold GLOCK, but not basic vnode lock */ | |
885 | code = afs_read(avc, &uio, osi_curcred(), 0); | |
886 | AFS_GUNLOCK(); | |
887 | pmap_qremove(kva, npages); | |
888 | ||
889 | relpbuf(bp, &afs_pbuf_freecnt); | |
890 | ||
891 | if (code && (uio.uio_resid == count)) { | |
892 | #ifndef FBSD_VOP_GETPAGES_BUSIED | |
893 | AFS_VM_OBJECT_WLOCK(object); | |
894 | ma_vm_page_lock_queues(); | |
895 | for (i = 0; i < npages; ++i) { | |
896 | if (i != ap->a_reqpage) | |
897 | vm_page_free(pages[i]); | |
898 | } | |
899 | ma_vm_page_unlock_queues(); | |
900 | AFS_VM_OBJECT_WUNLOCK(object); | |
901 | #endif | |
902 | return VM_PAGER_ERROR; | |
903 | } | |
904 | ||
905 | size = count - uio.uio_resid; | |
906 | AFS_VM_OBJECT_WLOCK(object); | |
907 | ma_vm_page_lock_queues(); | |
908 | for (i = 0, toff = 0; i < npages; i++, toff = nextoff) { | |
909 | vm_page_t m; | |
910 | nextoff = toff + PAGE_SIZE; | |
911 | m = pages[i]; | |
912 | ||
913 | /* XXX not in nfsclient? */ | |
914 | m->flags &= ~PG_ZERO; | |
915 | ||
916 | if (nextoff <= size) { | |
917 | /* | |
918 | * Read operation filled an entire page | |
919 | */ | |
920 | m->valid = VM_PAGE_BITS_ALL; | |
921 | #ifndef AFS_FBSD80_ENV | |
922 | vm_page_undirty(m); | |
923 | #else | |
924 | KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m)); | |
925 | #endif | |
926 | } else if (size > toff) { | |
927 | /* | |
928 | * Read operation filled a partial page. | |
929 | */ | |
930 | m->valid = 0; | |
931 | vm_page_set_validclean(m, 0, size - toff); | |
932 | KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m)); | |
933 | } | |
934 | ||
935 | #ifndef FBSD_VOP_GETPAGES_BUSIED | |
936 | if (i != ap->a_reqpage) { | |
937 | #if __FreeBSD_version >= 1000042 | |
938 | vm_page_readahead_finish(m); | |
939 | #else | |
940 | /* | |
941 | * Whether or not to leave the page activated is up in | |
942 | * the air, but we should put the page on a page queue | |
943 | * somewhere (it already is in the object). Result: | |
944 | * It appears that emperical results show that | |
945 | * deactivating pages is best. | |
946 | */ | |
947 | ||
948 | /* | |
949 | * Just in case someone was asking for this page we | |
950 | * now tell them that it is ok to use. | |
951 | */ | |
952 | if (!code) { | |
953 | #if defined(AFS_FBSD70_ENV) | |
954 | if (m->oflags & VPO_WANTED) { | |
955 | #else | |
956 | if (m->flags & PG_WANTED) { | |
957 | #endif | |
958 | ma_vm_page_lock(m); | |
959 | vm_page_activate(m); | |
960 | ma_vm_page_unlock(m); | |
961 | } | |
962 | else { | |
963 | ma_vm_page_lock(m); | |
964 | vm_page_deactivate(m); | |
965 | ma_vm_page_unlock(m); | |
966 | } | |
967 | vm_page_wakeup(m); | |
968 | } else { | |
969 | ma_vm_page_lock(m); | |
970 | vm_page_free(m); | |
971 | ma_vm_page_unlock(m); | |
972 | } | |
973 | #endif /* __FreeBSD_version 1000042 */ | |
974 | } | |
975 | #endif /* ndef FBSD_VOP_GETPAGES_BUSIED */ | |
976 | } | |
977 | ma_vm_page_unlock_queues(); | |
978 | AFS_VM_OBJECT_WUNLOCK(object); | |
979 | return VM_PAGER_OK; | |
980 | } | |
981 | ||
982 | int | |
983 | afs_vop_write(ap) | |
984 | struct vop_write_args /* { | |
985 | * struct vnode *a_vp; | |
986 | * struct uio *a_uio; | |
987 | * int a_ioflag; | |
988 | * struct ucred *a_cred; | |
989 | * } */ *ap; | |
990 | { | |
991 | int code; | |
992 | struct vcache *avc = VTOAFS(ap->a_vp); | |
993 | AFS_GLOCK(); | |
994 | osi_FlushPages(avc, ap->a_cred); /* hold GLOCK, but not basic vnode lock */ | |
995 | code = | |
996 | afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0); | |
997 | AFS_GUNLOCK(); | |
998 | return code; | |
999 | } | |
1000 | ||
1001 | /*- | |
1002 | * struct vop_putpages_args { | |
1003 | * struct vnode *a_vp; | |
1004 | * vm_page_t *a_m; | |
1005 | * int a_count; | |
1006 | * int a_sync; | |
1007 | * int *a_rtvals; | |
1008 | * vm_oofset_t a_offset; | |
1009 | * }; | |
1010 | */ | |
1011 | /* | |
1012 | * All of the pages passed to us in ap->a_m[] are already marked as busy, | |
1013 | * so there is no additional locking required to set their flags. -GAW | |
1014 | */ | |
1015 | int | |
1016 | afs_vop_putpages(struct vop_putpages_args *ap) | |
1017 | { | |
1018 | int code; | |
1019 | int i, size, npages, sync; | |
1020 | struct uio uio; | |
1021 | struct iovec iov; | |
1022 | struct buf *bp; | |
1023 | vm_offset_t kva; | |
1024 | struct vnode *vp; | |
1025 | struct vcache *avc; | |
1026 | ||
1027 | memset(&uio, 0, sizeof(uio)); | |
1028 | memset(&iov, 0, sizeof(iov)); | |
1029 | ||
1030 | vp = ap->a_vp; | |
1031 | avc = VTOAFS(vp); | |
1032 | /* Perhaps these two checks should just be KASSERTs instead... */ | |
1033 | if (vp->v_object == NULL) { | |
1034 | printf("afs_putpages: called with non-merged cache vnode??\n"); | |
1035 | return VM_PAGER_ERROR; /* XXX I think this is insufficient */ | |
1036 | } | |
1037 | if (vType(avc) != VREG) { | |
1038 | printf("afs_putpages: not VREG"); | |
1039 | return VM_PAGER_ERROR; /* XXX I think this is insufficient */ | |
1040 | } | |
1041 | npages = btoc(ap->a_count); | |
1042 | for (i = 0; i < npages; i++) | |
1043 | ap->a_rtvals[i] = VM_PAGER_AGAIN; | |
1044 | bp = getpbuf(&afs_pbuf_freecnt); | |
1045 | ||
1046 | kva = (vm_offset_t) bp->b_data; | |
1047 | pmap_qenter(kva, ap->a_m, npages); | |
1048 | MA_PCPU_INC(cnt.v_vnodeout); | |
1049 | MA_PCPU_ADD(cnt.v_vnodepgsout, ap->a_count); | |
1050 | ||
1051 | iov.iov_base = (caddr_t) kva; | |
1052 | iov.iov_len = ap->a_count; | |
1053 | uio.uio_iov = &iov; | |
1054 | uio.uio_iovcnt = 1; | |
1055 | uio.uio_offset = IDX_TO_OFF(ap->a_m[0]->pindex); | |
1056 | uio.uio_resid = ap->a_count; | |
1057 | uio.uio_segflg = UIO_SYSSPACE; | |
1058 | uio.uio_rw = UIO_WRITE; | |
1059 | uio.uio_td = curthread; | |
1060 | sync = IO_VMIO; | |
1061 | if (ap->a_sync & VM_PAGER_PUT_SYNC) | |
1062 | sync |= IO_SYNC; | |
1063 | /*if (ap->a_sync & VM_PAGER_PUT_INVAL) | |
1064 | * sync |= IO_INVAL; */ | |
1065 | ||
1066 | AFS_GLOCK(); | |
1067 | code = afs_write(avc, &uio, sync, osi_curcred(), 0); | |
1068 | AFS_GUNLOCK(); | |
1069 | ||
1070 | pmap_qremove(kva, npages); | |
1071 | relpbuf(bp, &afs_pbuf_freecnt); | |
1072 | ||
1073 | if (!code) { | |
1074 | size = ap->a_count - uio.uio_resid; | |
1075 | for (i = 0; i < round_page(size) / PAGE_SIZE; i++) { | |
1076 | ap->a_rtvals[i] = VM_PAGER_OK; | |
1077 | vm_page_undirty(ap->a_m[i]); | |
1078 | } | |
1079 | } | |
1080 | return ap->a_rtvals[0]; | |
1081 | } | |
1082 | ||
1083 | int | |
1084 | afs_vop_ioctl(ap) | |
1085 | struct vop_ioctl_args /* { | |
1086 | * struct vnode *a_vp; | |
1087 | * u_long a_command; | |
1088 | * void *a_data; | |
1089 | * int a_fflag; | |
1090 | * struct ucred *a_cred; | |
1091 | * struct thread *a_td; | |
1092 | * } */ *ap; | |
1093 | { | |
1094 | struct vcache *tvc = VTOAFS(ap->a_vp); | |
1095 | int error = 0; | |
1096 | ||
1097 | /* in case we ever get in here... */ | |
1098 | ||
1099 | AFS_STATCNT(afs_ioctl); | |
1100 | if (((ap->a_command >> 8) & 0xff) == 'V') { | |
1101 | /* This is a VICEIOCTL call */ | |
1102 | AFS_GLOCK(); | |
1103 | error = HandleIoctl(tvc, ap->a_command, ap->a_data); | |
1104 | AFS_GUNLOCK(); | |
1105 | return (error); | |
1106 | } else { | |
1107 | /* No-op call; just return. */ | |
1108 | return (ENOTTY); | |
1109 | } | |
1110 | } | |
1111 | ||
1112 | int | |
1113 | afs_vop_fsync(ap) | |
1114 | struct vop_fsync_args /* { | |
1115 | * struct vnode *a_vp; | |
1116 | * int a_waitfor; | |
1117 | * struct thread *td; | |
1118 | * } */ *ap; | |
1119 | { | |
1120 | int error; | |
1121 | struct vnode *vp = ap->a_vp; | |
1122 | ||
1123 | AFS_GLOCK(); | |
1124 | /*vflushbuf(vp, wait); */ | |
1125 | #ifdef AFS_FBSD60_ENV | |
1126 | error = afs_fsync(VTOAFS(vp), ap->a_td->td_ucred); | |
1127 | #else | |
1128 | if (ap->a_cred) | |
1129 | error = afs_fsync(VTOAFS(vp), ap->a_cred); | |
1130 | else | |
1131 | error = afs_fsync(VTOAFS(vp), afs_osi_credp); | |
1132 | #endif | |
1133 | AFS_GUNLOCK(); | |
1134 | return error; | |
1135 | } | |
1136 | ||
1137 | int | |
1138 | afs_vop_remove(ap) | |
1139 | struct vop_remove_args /* { | |
1140 | * struct vnode *a_dvp; | |
1141 | * struct vnode *a_vp; | |
1142 | * struct componentname *a_cnp; | |
1143 | * } */ *ap; | |
1144 | { | |
1145 | int error = 0; | |
1146 | struct vnode *vp = ap->a_vp; | |
1147 | struct vnode *dvp = ap->a_dvp; | |
1148 | ||
1149 | GETNAME(); | |
1150 | AFS_GLOCK(); | |
1151 | error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred); | |
1152 | AFS_GUNLOCK(); | |
1153 | cache_purge(vp); | |
1154 | DROPNAME(); | |
1155 | return error; | |
1156 | } | |
1157 | ||
1158 | int | |
1159 | afs_vop_link(ap) | |
1160 | struct vop_link_args /* { | |
1161 | * struct vnode *a_vp; | |
1162 | * struct vnode *a_tdvp; | |
1163 | * struct componentname *a_cnp; | |
1164 | * } */ *ap; | |
1165 | { | |
1166 | int error = 0; | |
1167 | struct vnode *dvp = ap->a_tdvp; | |
1168 | struct vnode *vp = ap->a_vp; | |
1169 | #ifndef AFS_FBSD80_ENV | |
1170 | struct thread *p = ap->a_cnp->cn_thread; | |
1171 | #endif | |
1172 | ||
1173 | GETNAME(); | |
1174 | if (dvp->v_mount != vp->v_mount) { | |
1175 | error = EXDEV; | |
1176 | goto out; | |
1177 | } | |
1178 | if (vp->v_type == VDIR) { | |
1179 | error = EISDIR; | |
1180 | goto out; | |
1181 | } | |
1182 | if ((error = ma_vn_lock(vp, LK_CANRECURSE | LK_EXCLUSIVE, p)) != 0) { | |
1183 | goto out; | |
1184 | } | |
1185 | AFS_GLOCK(); | |
1186 | error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred); | |
1187 | AFS_GUNLOCK(); | |
1188 | if (dvp != vp) | |
1189 | MA_VOP_UNLOCK(vp, 0, p); | |
1190 | out: | |
1191 | DROPNAME(); | |
1192 | return error; | |
1193 | } | |
1194 | ||
1195 | int | |
1196 | afs_vop_rename(ap) | |
1197 | struct vop_rename_args /* { | |
1198 | * struct vnode *a_fdvp; | |
1199 | * struct vnode *a_fvp; | |
1200 | * struct componentname *a_fcnp; | |
1201 | * struct vnode *a_tdvp; | |
1202 | * struct vnode *a_tvp; | |
1203 | * struct componentname *a_tcnp; | |
1204 | * } */ *ap; | |
1205 | { | |
1206 | int error = 0; | |
1207 | struct componentname *fcnp = ap->a_fcnp; | |
1208 | char *fname; | |
1209 | struct componentname *tcnp = ap->a_tcnp; | |
1210 | char *tname; | |
1211 | struct vnode *tvp = ap->a_tvp; | |
1212 | struct vnode *tdvp = ap->a_tdvp; | |
1213 | struct vnode *fvp = ap->a_fvp; | |
1214 | struct vnode *fdvp = ap->a_fdvp; | |
1215 | #ifndef AFS_FBSD80_ENV | |
1216 | struct thread *p = fcnp->cn_thread; | |
1217 | #endif | |
1218 | ||
1219 | /* | |
1220 | * Check for cross-device rename. | |
1221 | */ | |
1222 | if ((fvp->v_mount != tdvp->v_mount) | |
1223 | || (tvp && (fvp->v_mount != tvp->v_mount))) { | |
1224 | error = EXDEV; | |
1225 | abortit: | |
1226 | if (tdvp == tvp) | |
1227 | vrele(tdvp); | |
1228 | else | |
1229 | vput(tdvp); | |
1230 | if (tvp) | |
1231 | vput(tvp); | |
1232 | vrele(fdvp); | |
1233 | vrele(fvp); | |
1234 | return (error); | |
1235 | } | |
1236 | /* | |
1237 | * if fvp == tvp, we're just removing one name of a pair of | |
1238 | * directory entries for the same element. convert call into rename. | |
1239 | ( (pinched from FreeBSD 4.4's ufs_rename()) | |
1240 | ||
1241 | */ | |
1242 | if (fvp == tvp) { | |
1243 | if (fvp->v_type == VDIR) { | |
1244 | error = EINVAL; | |
1245 | goto abortit; | |
1246 | } | |
1247 | ||
1248 | /* Release destination completely. */ | |
1249 | vput(tdvp); | |
1250 | vput(tvp); | |
1251 | ||
1252 | /* Delete source. */ | |
1253 | vrele(fdvp); | |
1254 | vrele(fvp); | |
1255 | fcnp->cn_flags &= ~MODMASK; | |
1256 | fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; | |
1257 | if ((fcnp->cn_flags & SAVESTART) == 0) | |
1258 | panic("afs_rename: lost from startdir"); | |
1259 | fcnp->cn_nameiop = DELETE; | |
1260 | VREF(fdvp); | |
1261 | error = relookup(fdvp, &fvp, fcnp); | |
1262 | if (error == 0) | |
1263 | vrele(fdvp); | |
1264 | if (fvp == NULL) { | |
1265 | return (ENOENT); | |
1266 | } | |
1267 | ||
1268 | error = VOP_REMOVE(fdvp, fvp, fcnp); | |
1269 | if (fdvp == fvp) | |
1270 | vrele(fdvp); | |
1271 | else | |
1272 | vput(fdvp); | |
1273 | vput(fvp); | |
1274 | return (error); | |
1275 | } | |
1276 | if ((error = ma_vn_lock(fvp, LK_EXCLUSIVE, p)) != 0) | |
1277 | goto abortit; | |
1278 | ||
1279 | MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK); | |
1280 | memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen); | |
1281 | fname[fcnp->cn_namelen] = '\0'; | |
1282 | MALLOC(tname, char *, tcnp->cn_namelen + 1, M_TEMP, M_WAITOK); | |
1283 | memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen); | |
1284 | tname[tcnp->cn_namelen] = '\0'; | |
1285 | ||
1286 | ||
1287 | AFS_GLOCK(); | |
1288 | /* XXX use "from" or "to" creds? NFS uses "to" creds */ | |
1289 | error = | |
1290 | afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred); | |
1291 | AFS_GUNLOCK(); | |
1292 | ||
1293 | FREE(fname, M_TEMP); | |
1294 | FREE(tname, M_TEMP); | |
1295 | if (tdvp == tvp) | |
1296 | vrele(tdvp); | |
1297 | else | |
1298 | vput(tdvp); | |
1299 | if (tvp) | |
1300 | vput(tvp); | |
1301 | vrele(fdvp); | |
1302 | vput(fvp); | |
1303 | return error; | |
1304 | } | |
1305 | ||
1306 | int | |
1307 | afs_vop_mkdir(ap) | |
1308 | struct vop_mkdir_args /* { | |
1309 | * struct vnode *a_dvp; | |
1310 | * struct vnode **a_vpp; | |
1311 | * struct componentname *a_cnp; | |
1312 | * struct vattr *a_vap; | |
1313 | * } */ *ap; | |
1314 | { | |
1315 | struct vnode *dvp = ap->a_dvp; | |
1316 | struct vattr *vap = ap->a_vap; | |
1317 | int error = 0; | |
1318 | struct vcache *vcp; | |
1319 | #ifndef AFS_FBSD80_ENV | |
1320 | struct thread *p = ap->a_cnp->cn_thread; | |
1321 | #endif | |
1322 | ||
1323 | GETNAME(); | |
1324 | #ifdef DIAGNOSTIC | |
1325 | if ((cnp->cn_flags & HASBUF) == 0) | |
1326 | panic("afs_vop_mkdir: no name"); | |
1327 | #endif | |
1328 | AFS_GLOCK(); | |
1329 | error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred); | |
1330 | AFS_GUNLOCK(); | |
1331 | if (error) { | |
1332 | DROPNAME(); | |
1333 | return (error); | |
1334 | } | |
1335 | if (vcp) { | |
1336 | *ap->a_vpp = AFSTOV(vcp); | |
1337 | ma_vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY, p); | |
1338 | } else | |
1339 | *ap->a_vpp = 0; | |
1340 | DROPNAME(); | |
1341 | return error; | |
1342 | } | |
1343 | ||
1344 | int | |
1345 | afs_vop_rmdir(ap) | |
1346 | struct vop_rmdir_args /* { | |
1347 | * struct vnode *a_dvp; | |
1348 | * struct vnode *a_vp; | |
1349 | * struct componentname *a_cnp; | |
1350 | * } */ *ap; | |
1351 | { | |
1352 | int error = 0; | |
1353 | struct vnode *dvp = ap->a_dvp; | |
1354 | ||
1355 | GETNAME(); | |
1356 | AFS_GLOCK(); | |
1357 | error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred); | |
1358 | AFS_GUNLOCK(); | |
1359 | DROPNAME(); | |
1360 | return error; | |
1361 | } | |
1362 | ||
1363 | /* struct vop_symlink_args { | |
1364 | * struct vnode *a_dvp; | |
1365 | * struct vnode **a_vpp; | |
1366 | * struct componentname *a_cnp; | |
1367 | * struct vattr *a_vap; | |
1368 | * char *a_target; | |
1369 | * }; | |
1370 | */ | |
1371 | int | |
1372 | afs_vop_symlink(struct vop_symlink_args *ap) | |
1373 | { | |
1374 | struct vnode *dvp; | |
1375 | struct vnode *newvp; | |
1376 | struct vcache *vcp; | |
1377 | int error; | |
1378 | ||
1379 | GETNAME(); | |
1380 | AFS_GLOCK(); | |
1381 | ||
1382 | dvp = ap->a_dvp; | |
1383 | newvp = NULL; | |
1384 | ||
1385 | error = | |
1386 | afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, NULL, | |
1387 | cnp->cn_cred); | |
1388 | if (error == 0) { | |
1389 | error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred); | |
1390 | if (error == 0) { | |
1391 | newvp = AFSTOV(vcp); | |
1392 | ma_vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_thread); | |
1393 | } | |
1394 | } | |
1395 | AFS_GUNLOCK(); | |
1396 | DROPNAME(); | |
1397 | *(ap->a_vpp) = newvp; | |
1398 | return error; | |
1399 | } | |
1400 | ||
1401 | int | |
1402 | afs_vop_readdir(ap) | |
1403 | struct vop_readdir_args /* { | |
1404 | * struct vnode *a_vp; | |
1405 | * struct uio *a_uio; | |
1406 | * struct ucred *a_cred; | |
1407 | * int *a_eofflag; | |
1408 | * u_long *a_cookies; | |
1409 | * int ncookies; | |
1410 | * } */ *ap; | |
1411 | { | |
1412 | int error; | |
1413 | off_t off; | |
1414 | /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies, | |
1415 | ap->a_ncookies); */ | |
1416 | off = ap->a_uio->uio_offset; | |
1417 | AFS_GLOCK(); | |
1418 | error = | |
1419 | afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag); | |
1420 | AFS_GUNLOCK(); | |
1421 | if (!error && ap->a_ncookies != NULL) { | |
1422 | struct uio *uio = ap->a_uio; | |
1423 | const struct dirent *dp, *dp_start, *dp_end; | |
1424 | int ncookies; | |
1425 | u_long *cookies, *cookiep; | |
1426 | ||
1427 | if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) | |
1428 | panic("afs_readdir: burned cookies"); | |
1429 | dp = (const struct dirent *) | |
1430 | ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off)); | |
1431 | ||
1432 | dp_end = (const struct dirent *)uio->uio_iov->iov_base; | |
1433 | for (dp_start = dp, ncookies = 0; dp < dp_end; | |
1434 | dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) | |
1435 | ncookies++; | |
1436 | ||
1437 | MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, | |
1438 | M_WAITOK); | |
1439 | for (dp = dp_start, cookiep = cookies; dp < dp_end; | |
1440 | dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) { | |
1441 | off += dp->d_reclen; | |
1442 | *cookiep++ = off; | |
1443 | } | |
1444 | *ap->a_cookies = cookies; | |
1445 | *ap->a_ncookies = ncookies; | |
1446 | } | |
1447 | ||
1448 | return error; | |
1449 | } | |
1450 | ||
1451 | int | |
1452 | afs_vop_readlink(ap) | |
1453 | struct vop_readlink_args /* { | |
1454 | * struct vnode *a_vp; | |
1455 | * struct uio *a_uio; | |
1456 | * struct ucred *a_cred; | |
1457 | * } */ *ap; | |
1458 | { | |
1459 | int error; | |
1460 | /* printf("readlink %x\n", ap->a_vp);*/ | |
1461 | AFS_GLOCK(); | |
1462 | error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred); | |
1463 | AFS_GUNLOCK(); | |
1464 | return error; | |
1465 | } | |
1466 | ||
1467 | int | |
1468 | afs_vop_inactive(ap) | |
1469 | struct vop_inactive_args /* { | |
1470 | * struct vnode *a_vp; | |
1471 | * struct thread *td; | |
1472 | * } */ *ap; | |
1473 | { | |
1474 | struct vnode *vp = ap->a_vp; | |
1475 | ||
1476 | AFS_GLOCK(); | |
1477 | afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */ | |
1478 | AFS_GUNLOCK(); | |
1479 | #ifndef AFS_FBSD60_ENV | |
1480 | MA_VOP_UNLOCK(vp, 0, ap->a_td); | |
1481 | #endif | |
1482 | return 0; | |
1483 | } | |
1484 | ||
1485 | /* | |
1486 | * struct vop_reclaim_args { | |
1487 | * struct vnode *a_vp; | |
1488 | * }; | |
1489 | */ | |
1490 | int | |
1491 | afs_vop_reclaim(struct vop_reclaim_args *ap) | |
1492 | { | |
1493 | /* copied from ../OBSD/osi_vnodeops.c:afs_nbsd_reclaim() */ | |
1494 | int code, slept; | |
1495 | struct vnode *vp = ap->a_vp; | |
1496 | struct vcache *avc = VTOAFS(vp); | |
1497 | int haveGlock = ISAFS_GLOCK(); | |
1498 | int haveVlock = CheckLock(&afs_xvcache); | |
1499 | ||
1500 | if (!haveGlock) | |
1501 | AFS_GLOCK(); | |
1502 | if (!haveVlock) | |
1503 | ObtainWriteLock(&afs_xvcache, 901); | |
1504 | /* reclaim the vnode and the in-memory vcache, but keep the on-disk vcache */ | |
1505 | code = afs_FlushVCache(avc, &slept); | |
1506 | ||
1507 | if (avc->f.states & CVInit) { | |
1508 | avc->f.states &= ~CVInit; | |
1509 | afs_osi_Wakeup(&avc->f.states); | |
1510 | } | |
1511 | ||
1512 | if (!haveVlock) | |
1513 | ReleaseWriteLock(&afs_xvcache); | |
1514 | if (!haveGlock) | |
1515 | AFS_GUNLOCK(); | |
1516 | ||
1517 | if (code) { | |
1518 | afs_warn("afs_vop_reclaim: afs_FlushVCache failed code %d vnode\n", code); | |
1519 | VOP_PRINT(vp); | |
1520 | } | |
1521 | ||
1522 | /* basically, it must not fail */ | |
1523 | vnode_destroy_vobject(vp); | |
1524 | vp->v_data = 0; | |
1525 | ||
1526 | return 0; | |
1527 | } | |
1528 | ||
1529 | #ifndef AFS_FBSD60_ENV | |
1530 | int | |
1531 | afs_vop_bmap(ap) | |
1532 | struct vop_bmap_args /* { | |
1533 | * struct vnode *a_vp; | |
1534 | * daddr_t a_bn; | |
1535 | * struct vnode **a_vpp; | |
1536 | * daddr_t *a_bnp; | |
1537 | * int *a_runp; | |
1538 | * int *a_runb; | |
1539 | * } */ *ap; | |
1540 | { | |
1541 | if (ap->a_bnp) { | |
1542 | *ap->a_bnp = ap->a_bn * (PAGE_SIZE / DEV_BSIZE); | |
1543 | } | |
1544 | if (ap->a_vpp) { | |
1545 | *ap->a_vpp = ap->a_vp; | |
1546 | } | |
1547 | if (ap->a_runp != NULL) | |
1548 | *ap->a_runp = 0; | |
1549 | if (ap->a_runb != NULL) | |
1550 | *ap->a_runb = 0; | |
1551 | ||
1552 | return 0; | |
1553 | } | |
1554 | #endif | |
1555 | ||
1556 | int | |
1557 | afs_vop_strategy(ap) | |
1558 | struct vop_strategy_args /* { | |
1559 | * struct buf *a_bp; | |
1560 | * } */ *ap; | |
1561 | { | |
1562 | int error; | |
1563 | AFS_GLOCK(); | |
1564 | error = afs_ustrategy(ap->a_bp, osi_curcred()); | |
1565 | AFS_GUNLOCK(); | |
1566 | return error; | |
1567 | } | |
1568 | ||
1569 | int | |
1570 | afs_vop_print(ap) | |
1571 | struct vop_print_args /* { | |
1572 | * struct vnode *a_vp; | |
1573 | * } */ *ap; | |
1574 | { | |
1575 | struct vnode *vp = ap->a_vp; | |
1576 | struct vcache *vc = VTOAFS(ap->a_vp); | |
1577 | int s = vc->f.states; | |
1578 | ||
1579 | printf("vc %p vp %p tag %s, fid: %d.%d.%d.%d, opens %d, writers %d", vc, vp, vp->v_tag, | |
1580 | (int)vc->f.fid.Cell, (u_int) vc->f.fid.Fid.Volume, | |
1581 | (u_int) vc->f.fid.Fid.Vnode, (u_int) vc->f.fid.Fid.Unique, vc->opens, | |
1582 | vc->execsOrWriters); | |
1583 | printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "", | |
1584 | (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "", | |
1585 | (s & CMAPPED) ? " mapped" : "", | |
1586 | (s & CVFlushed) ? " flush in progress" : ""); | |
1587 | printf("\n"); | |
1588 | return 0; | |
1589 | } | |
1590 | ||
1591 | /* | |
1592 | * Advisory record locking support (fcntl() POSIX style) | |
1593 | */ | |
1594 | int | |
1595 | afs_vop_advlock(ap) | |
1596 | struct vop_advlock_args /* { | |
1597 | * struct vnode *a_vp; | |
1598 | * caddr_t a_id; | |
1599 | * int a_op; | |
1600 | * struct flock *a_fl; | |
1601 | * int a_flags; | |
1602 | * } */ *ap; | |
1603 | { | |
1604 | int error; | |
1605 | struct ucred cr = *osi_curcred(); | |
1606 | ||
1607 | AFS_GLOCK(); | |
1608 | error = | |
1609 | afs_lockctl(VTOAFS(ap->a_vp), | |
1610 | ap->a_fl, | |
1611 | ap->a_op, &cr, | |
1612 | (int)(intptr_t)ap->a_id); /* XXX: no longer unique! */ | |
1613 | AFS_GUNLOCK(); | |
1614 | return error; | |
1615 | } |