puffs_vnops.c revision 1.4 1 /* $NetBSD: puffs_vnops.c,v 1.4 2006/10/26 13:42:21 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the company nor the name of the author may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.4 2006/10/26 13:42:21 pooka Exp $");
37
38 #include <sys/param.h>
39 #include <sys/vnode.h>
40 #include <sys/mount.h>
41 #include <sys/malloc.h>
42 #include <sys/namei.h>
43
44 #include <fs/puffs/puffs_msgif.h>
45 #include <fs/puffs/puffs_sys.h>
46
47 #include <miscfs/genfs/genfs.h>
48
49 int puffs_lookup(void *);
50 int puffs_create(void *);
51 int puffs_access(void *);
52 int puffs_mknod(void *);
53 int puffs_open(void *);
54 int puffs_close(void *);
55 int puffs_getattr(void *);
56 int puffs_setattr(void *);
57 int puffs_revoke(void *);
58 int puffs_reclaim(void *);
59 int puffs_readdir(void *);
60 int puffs_poll(void *);
61 int puffs_fsync(void *);
62 int puffs_seek(void *);
63 int puffs_remove(void *);
64 int puffs_mkdir(void *);
65 int puffs_rmdir(void *);
66 int puffs_link(void *);
67 int puffs_readlink(void *);
68 int puffs_symlink(void *);
69 int puffs_rename(void *);
70 int puffs_read(void *);
71 int puffs_write(void *);
72 int puffs_fcntl(void *);
73 int puffs_ioctl(void *);
74 int puffs_inactive(void *);
75 int puffs_print(void *);
76 int puffs_pathconf(void *);
77 int puffs_advlock(void *);
78
79
80 /* Need to support */
81 #define puffs_putpages puffs_generic
82 #define puffs_getpages puffs_generic
83
84 /* VOP_LEASE() not included */
85
86 int puffs_generic(void *);
87
88 #if 0
89 #define puffs_lock genfs_lock
90 #define puffs_unlock genfs_unlock
91 #define puffs_islocked genfs_islocked
92 #else
93 int puffs_lock(void *);
94 int puffs_unlock(void *);
95 int puffs_islocked(void *);
96 #endif
97
98 int (**puffs_vnodeop_p)(void *);
99 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
100 { &vop_default_desc, vn_default_error },
101 { &vop_lookup_desc, puffs_lookup }, /* lookup */
102 { &vop_create_desc, puffs_create }, /* create */
103 { &vop_mknod_desc, puffs_mknod }, /* mknod */
104 { &vop_open_desc, puffs_open }, /* open */
105 { &vop_close_desc, puffs_close }, /* close */
106 { &vop_access_desc, puffs_access }, /* access */
107 { &vop_getattr_desc, puffs_getattr }, /* getattr */
108 { &vop_setattr_desc, puffs_setattr }, /* setattr */
109 { &vop_read_desc, puffs_read }, /* read */
110 { &vop_write_desc, puffs_write }, /* write */
111 { &vop_fcntl_desc, puffs_fcntl }, /* fcntl */
112 { &vop_ioctl_desc, puffs_ioctl }, /* ioctl */
113 { &vop_revoke_desc, puffs_revoke }, /* revoke */
114 { &vop_fsync_desc, puffs_fsync }, /* fsync */
115 { &vop_seek_desc, puffs_seek }, /* seek */
116 { &vop_remove_desc, puffs_remove }, /* remove */
117 { &vop_link_desc, puffs_link }, /* link */
118 { &vop_rename_desc, puffs_rename }, /* rename */
119 { &vop_mkdir_desc, puffs_mkdir }, /* mkdir */
120 { &vop_rmdir_desc, puffs_rmdir }, /* rmdir */
121 { &vop_symlink_desc, puffs_symlink }, /* symlink */
122 { &vop_readdir_desc, puffs_readdir }, /* readdir */
123 { &vop_readlink_desc, puffs_readlink }, /* readlink */
124 { &vop_abortop_desc, genfs_abortop }, /* abortop */
125 { &vop_inactive_desc, puffs_inactive }, /* inactive */
126 { &vop_reclaim_desc, puffs_reclaim }, /* reclaim */
127 { &vop_lock_desc, puffs_lock }, /* lock */
128 { &vop_unlock_desc, puffs_unlock }, /* unlock */
129 { &vop_bmap_desc, genfs_eopnotsupp }, /* bmap */
130 { &vop_strategy_desc, genfs_eopnotsupp }, /* strategy */
131 { &vop_print_desc, puffs_print }, /* print */
132 { &vop_islocked_desc, puffs_islocked }, /* islocked */
133 { &vop_pathconf_desc, puffs_pathconf }, /* pathconf */
134 { &vop_advlock_desc, puffs_advlock }, /* advlock */
135 { &vop_bwrite_desc, genfs_nullop }, /* bwrite */
136 #if 0
137 { &vop_getpages_desc, puffs_getpages }, /* getpages */
138 #endif
139 { &vop_putpages_desc, genfs_null_putpages }, /* putpages */
140
141 { &vop_poll_desc, genfs_eopnotsupp }, /* poll XXX */
142 { &vop_poll_desc, genfs_eopnotsupp }, /* kqfilter XXX */
143 { &vop_mmap_desc, genfs_eopnotsupp }, /* mmap XXX */
144 { NULL, NULL }
145 };
146 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
147 { &puffs_vnodeop_p, puffs_vnodeop_entries };
148
149 #define LOCKEDVP(a) (VOP_ISLOCKED(a) ? (a) : NULL)
150
151
152 int
153 puffs_lookup(void *v)
154 {
155 struct vop_lookup_args /* {
156 struct vnode * a_dvp;
157 struct vnode ** a_vpp;
158 struct componentname * a_cnp;
159 } */ *ap = v;
160 struct puffs_mount *pmp;
161 struct componentname *cnp;
162 struct vnode *vp, *dvp;
163 int wantpunlock, isdot;
164 int error;
165
166 PUFFS_VNREQ(lookup);
167
168 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
169 cnp = ap->a_cnp;
170 dvp = ap->a_dvp;
171 *ap->a_vpp = NULL;
172
173 /* first things first: check access */
174 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_lwp);
175 if (error)
176 return error;
177
178 wantpunlock = ~cnp->cn_flags & (LOCKPARENT | ISLASTCN);
179 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
180
181 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %lx\n",
182 cnp->cn_nameptr, dvp, cnp->cn_nameiop));
183
184 /*
185 * Do sanity checks we can do without consulting userland.
186 */
187
188 /*
189 * last component check & ro fs
190 *
191 * hmmm... why doesn't this check for create?
192 */
193 if ((cnp->cn_flags & ISLASTCN)
194 && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY)
195 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
196 DPRINTF(("puffs_lookup: write lookup for read-only fs!\n"));
197 return EROFS;
198 }
199
200 /*
201 * Check if someone fed it into the cache
202 */
203 error = cache_lookup(dvp, ap->a_vpp, cnp);
204 if (error >= 0)
205 return error;
206
207 if (isdot) {
208 vp = ap->a_dvp;
209 vref(vp);
210 *ap->a_vpp = vp;
211 return 0;
212 }
213
214 puffs_makecn(&lookup_arg.pvnr_cn, cnp);
215
216 if (cnp->cn_flags & ISDOTDOT)
217 VOP_UNLOCK(dvp, 0);
218
219 error = puffs_vntouser(pmp, PUFFS_VN_LOOKUP,
220 &lookup_arg, sizeof(lookup_arg), VPTOPNC(dvp), LOCKEDVP(dvp), NULL);
221 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
222
223 /*
224 * In case of error, leave parent locked. There is no new
225 * vnode to play with, so be happy with the NULL value given
226 * to vpp in the beginning.
227 */
228 if (error) {
229 if (error == -1) {
230 if ((cnp->cn_flags & ISLASTCN)
231 && (cnp->cn_nameiop == CREATE
232 || cnp->cn_nameiop == RENAME)) {
233 cnp->cn_flags |= SAVENAME;
234 error = EJUSTRETURN;
235 } else
236 /* userspace is on crack */
237 error = ENOENT;
238 }
239 *ap->a_vpp = NULL;
240 if (cnp->cn_flags & ISDOTDOT)
241 if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0)
242 cnp->cn_flags |= PDIRUNLOCK;
243 return error;
244 }
245
246 vp = puffs_pnode2vnode(pmp, lookup_arg.pvnr_newnode);
247 if (!vp) {
248 error = puffs_getvnode(dvp->v_mount,
249 lookup_arg.pvnr_newnode, &vp);
250 if (error) {
251 if (cnp->cn_flags & ISDOTDOT)
252 if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0)
253 cnp->cn_flags |= PDIRUNLOCK;
254 return error;
255 }
256 vp->v_type = lookup_arg.pvnr_vtype;
257 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
258 }
259
260 if (cnp->cn_flags & ISDOTDOT) {
261 if (cnp->cn_flags & LOCKPARENT &&
262 cnp->cn_flags & ISLASTCN) {
263 if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0) {
264 cnp->cn_flags |= PDIRUNLOCK;
265 }
266 }
267 } else {
268 if (wantpunlock) {
269 VOP_UNLOCK(dvp, 0);
270 cnp->cn_flags |= PDIRUNLOCK;
271 }
272 }
273
274 if (cnp->cn_flags & MAKEENTRY)
275 cache_enter(dvp, vp, cnp);
276 *ap->a_vpp = vp;
277
278 return 0;
279 }
280
281 int
282 puffs_create(void *v)
283 {
284 struct vop_create_args /* {
285 const struct vnodeop_desc *a_desc;
286 struct vnode *a_dvp;
287 struct vnode **a_vpp;
288 struct componentname *a_cnp;
289 struct vattr *a_vap;
290 } */ *ap = v;
291 int error;
292
293 PUFFS_VNREQ(create);
294
295 puffs_makecn(&create_arg.pvnr_cn, ap->a_cnp);
296 create_arg.pvnr_va = *ap->a_vap;
297
298 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_CREATE,
299 &create_arg, sizeof(create_arg), VPTOPNC(ap->a_dvp),
300 ap->a_dvp, NULL);
301 if (error)
302 goto out;
303
304 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
305 create_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type);
306
307 out:
308 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
309 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
310 vput(ap->a_dvp);
311 return error;
312 }
313
314 int
315 puffs_mknod(void *v)
316 {
317 struct vop_mknod_args /* {
318 const struct vnodeop_desc *a_desc;
319 struct vnode *a_dvp;
320 struct vnode **a_vpp;
321 struct componentname *a_cnp;
322 struct vattr *a_vap;
323 } */ *ap = v;
324 int error;
325
326 PUFFS_VNREQ(mknod);
327
328 puffs_makecn(&mknod_arg.pvnr_cn, ap->a_cnp);
329 mknod_arg.pvnr_va = *ap->a_vap;
330
331 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_MKNOD,
332 &mknod_arg, sizeof(mknod_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
333 if (error)
334 goto out;
335
336 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
337 mknod_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type);
338
339 out:
340 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
341 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
342 vput(ap->a_dvp);
343 return error;
344 }
345
346 int
347 puffs_open(void *v)
348 {
349 struct vop_open_args /* {
350 const struct vnodeop_desc *a_desc;
351 struct vnode *a_vp;
352 int a_mode;
353 kauth_cred_t a_cred;
354 struct lwp *a_l;
355 } */ *ap = v;
356
357 PUFFS_VNREQ(open);
358
359 open_arg.pvnr_mode = ap->a_mode;
360 puffs_credcvt(&open_arg.pvnr_cred, ap->a_cred);
361 open_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
362
363 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_OPEN,
364 &open_arg, sizeof(open_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
365 }
366
367 int
368 puffs_close(void *v)
369 {
370 struct vop_close_args /* {
371 const struct vnodeop_desc *a_desc;
372 struct vnode *a_vp;
373 int a_fflag;
374 kauth_cred_t a_cred;
375 struct lwp *a_l;
376 } */ *ap = v;
377
378 PUFFS_VNREQ(close);
379
380 close_arg.pvnr_fflag = ap->a_fflag;
381 puffs_credcvt(&close_arg.pvnr_cred, ap->a_cred);
382 close_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
383
384 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_CLOSE,
385 &close_arg, sizeof(close_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
386 }
387
388 int
389 puffs_access(void *v)
390 {
391 struct vop_access_args /* {
392 const struct vnodeop_desc *a_desc;
393 struct vnode *a_vp;
394 int a_mode;
395 kauth_cred_t a_cred;
396 struct lwp *a_l;
397 } */ *ap = v;
398 int error;
399
400 PUFFS_VNREQ(access);
401
402 access_arg.pvnr_mode = ap->a_mode;
403 access_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
404 puffs_credcvt(&access_arg.pvnr_cred, ap->a_cred);
405
406 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ACCESS,
407 &access_arg, sizeof(access_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
408 if (error)
409 return error;
410
411 /*
412 * XXXtothepeople: no execute permissions yet. Otherwise
413 * all hell will break loose if we try to execute a file
414 * without VOP_GETPAGES support. It is forthcoming, just
415 * not there yet ...
416 */
417 if (ap->a_mode == VEXEC && ap->a_vp->v_type != VDIR)
418 return EACCES;
419
420 return 0;
421 }
422
423 int
424 puffs_getattr(void *v)
425 {
426 struct vop_getattr_args /* {
427 const struct vnodeop_desc *a_desc;
428 struct vnode *a_vp;
429 struct vattr *a_vap;
430 kauth_cred_t a_cred;
431 struct lwp *a_l;
432 } */ *ap = v;
433 int error;
434
435 PUFFS_VNREQ(getattr);
436
437 vattr_null(&getattr_arg.pvnr_va);
438 puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred);
439 getattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
440
441 /*
442 * XXX + XX (dos equis): this can't go through the unlock/lock
443 * cycle, since it can be called from uvn_attach(), which fiddles
444 * around with VXLOCK and therefore breaks vn_lock(). Proper
445 * fix pending.
446 */
447 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_GETATTR,
448 &getattr_arg, sizeof(getattr_arg), VPTOPNC(ap->a_vp),
449 NULL /* XXXseeabove: should be LOCKEDVP(ap->a_vp) */, NULL);
450 if (error)
451 return error;
452
453 (void)memcpy(ap->a_vap, &getattr_arg.pvnr_va, sizeof(struct vattr));
454
455 /*
456 * XXXtothepeople: adjust the return value so that we don't
457 * advertise execute bits. Otherwise all hell will break
458 * loose if we try to execute a file without VOP_GETPAGES
459 * support. It is forthcoming, just not there yet ...
460 */
461 if (ap->a_vp->v_type != VDIR)
462 ap->a_vap->va_mode &= ~0111;
463
464 return 0;
465 }
466
467 int
468 puffs_setattr(void *v)
469 {
470 struct vop_getattr_args /* {
471 const struct vnodeop_desc *a_desc;
472 struct vnode *a_vp;
473 struct vattr *a_vap;
474 kauth_cred_t a_cred;
475 struct lwp *a_l;
476 } */ *ap = v;
477
478 PUFFS_VNREQ(setattr);
479
480 (void)memcpy(&setattr_arg.pvnr_va, ap->a_vap, sizeof(struct vattr));
481 puffs_credcvt(&setattr_arg.pvnr_cred, ap->a_cred);
482 setattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
483
484 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SETATTR,
485 &setattr_arg, sizeof(setattr_arg), VPTOPNC(ap->a_vp),
486 ap->a_vp, NULL);
487 }
488
489 int
490 puffs_revoke(void *v)
491 {
492 struct vop_revoke_args /* {
493 const struct vnodeop_desc *a_desc;
494 struct vnode *a_vp;
495 int a_flags;
496 } */ *ap = v;
497 PUFFS_VNREQ(revoke);
498
499 revoke_arg.pvnr_flags = ap->a_flags;
500
501 /* don't really care if userspace doesn't want to play along */
502 puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_REVOKE,
503 &revoke_arg, sizeof(revoke_arg), VPTOPNC(ap->a_vp), NULL, NULL);
504
505 return genfs_revoke(v);
506 }
507
508 int
509 puffs_inactive(void *v)
510 {
511 struct vop_inactive_args /* {
512 const struct vnodeop_desc *a_desc;
513 struct vnode *a_vp;
514 struct lwp *a_l;
515 } */ *ap = v;
516 struct puffs_node *pnode;
517 int rv, vnrefs;
518
519 PUFFS_VNREQ(inactive);
520
521 /*
522 * XXX: think about this after we really start unlocking
523 * when going to userspace
524 */
525 pnode = ap->a_vp->v_data;
526 pnode->pn_stat |= PNODE_INACTIVE;
527
528 inactive_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
529
530 rv = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_INACTIVE,
531 &inactive_arg, sizeof(inactive_arg), VPTOPNC(ap->a_vp),
532 ap->a_vp, NULL);
533
534 /* can't trust userspace return value? simulate safe answer */
535 if (rv)
536 vnrefs = 1;
537 else
538 vnrefs = inactive_arg.pvnr_backendrefs;
539
540 VOP_UNLOCK(ap->a_vp, 0);
541
542 /*
543 * user server thinks it's gone? then don't be afraid care,
544 * node's life was already all it would ever be
545 */
546 if (vnrefs == 0)
547 vrecycle(ap->a_vp, NULL, ap->a_l);
548
549 return 0;
550 }
551
552 int
553 puffs_reclaim(void *v)
554 {
555 struct vop_reclaim_args /* {
556 const struct vnodeop_desc *a_desc;
557 struct vnode *a_vp;
558 struct lwp *a_l;
559 } */ *ap = v;
560 struct puffs_mount *pmp;
561 int error;
562
563 PUFFS_VNREQ(reclaim);
564
565 /*
566 * first things first: check if someone is trying to reclaim the
567 * root vnode. do not allow that to travel to userspace.
568 * Note that we don't need to take the lock similarly to
569 * puffs_root(), since there is only one of us.
570 */
571 if (ap->a_vp->v_flag & VROOT) {
572 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
573 #ifdef DIAGNOSTIC
574 simple_lock(&pmp->pmp_lock);
575 if (pmp->pmp_root == NULL)
576 panic("puffs_reclaim: releasing root vnode (%p) twice",
577 ap->a_vp);
578 simple_unlock(&pmp->pmp_lock);
579 #endif
580 pmp->pmp_root = NULL;
581 puffs_putvnode(ap->a_vp);
582 return 0;
583 }
584
585 reclaim_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
586
587 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_RECLAIM,
588 &reclaim_arg, sizeof(reclaim_arg), VPTOPNC(ap->a_vp), NULL, NULL);
589 #if 0
590 /*
591 * XXX: if reclaim fails for any other reason than the userspace
592 * being dead, we should consider unmounting the filesystem, since
593 * we can't trust it to be in a consistent state anymore. But for
594 * now, just ignore all errors.
595 */
596 if (error)
597 return error;
598 #endif
599
600 puffs_putvnode(ap->a_vp);
601
602 return 0;
603 }
604
605 int
606 puffs_readdir(void *v)
607 {
608 struct vop_readdir_args /* {
609 const struct vnodeop_desc *a_desc;
610 struct vnode *a_vp;
611 struct uio *a_uio;
612 kauth_cred_t a_cred;
613 int *a_eofflag;
614 off_t **a_cookies;
615 int *a_ncookies;
616 } */ *ap = v;
617 struct puffs_vnreq_readdir *readdir_argp;
618 size_t argsize;
619 struct uio *uio = ap->a_uio;
620 size_t howmuch;
621 int error;
622
623 /* worry about these later */
624 if (!(ap->a_cookies == NULL && ap->a_ncookies == NULL))
625 return EOPNOTSUPP;
626
627 argsize = sizeof(struct puffs_vnreq_readdir);
628 readdir_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
629
630 puffs_credcvt(&readdir_argp->pvnr_cred, ap->a_cred);
631 readdir_argp->pvnr_offset = uio->uio_offset;
632 readdir_argp->pvnr_resid = uio->uio_resid;
633
634 error = puffs_vntouser_adjbuf(MPTOPUFFSMP(ap->a_vp->v_mount),
635 PUFFS_VN_READDIR, (void **)&readdir_argp, &argsize,
636 sizeof(struct puffs_vnreq_readdir),
637 VPTOPNC(ap->a_vp), ap->a_vp, NULL);
638 if (error)
639 goto out;
640
641 /* userspace is cheating? */
642 if (readdir_argp->pvnr_resid > uio->uio_resid) {
643 error = EINVAL;
644 goto out;
645 }
646
647 /* bouncy-wouncy with the directory data */
648 howmuch = uio->uio_resid - readdir_argp->pvnr_resid;
649 error = uiomove(readdir_argp->pvnr_dent, howmuch, uio);
650 if (error)
651 goto out;
652 uio->uio_offset = readdir_argp->pvnr_offset;
653
654 out:
655 free(readdir_argp, M_PUFFS);
656 return error;
657 }
658
659 int
660 puffs_poll(void *v)
661 {
662 struct vop_poll_args /* {
663 const struct vnodeop_desc *a_desc;
664 struct vnode *a_vp;
665 int a_events;
666 struct lwp *a_l;
667 }*/ *ap = v;
668
669 PUFFS_VNREQ(poll);
670
671 poll_arg.pvnr_events = ap->a_events;
672 poll_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
673
674 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_POLL,
675 &poll_arg, sizeof(poll_arg), VPTOPNC(ap->a_vp), NULL, NULL);
676 }
677
678 int
679 puffs_fsync(void *v)
680 {
681 struct vop_fsync_args /* {
682 const struct vnodeop_desc *a_desc;
683 struct vnode *a_vp;
684 kauth_cred_t a_cred;
685 int a_flags;
686 off_t a_offlo;
687 off_t a_offhi;
688 struct lwp *a_l;
689 } */ *ap = v;
690
691 PUFFS_VNREQ(fsync);
692
693 puffs_credcvt(&fsync_arg.pvnr_cred, ap->a_cred);
694 fsync_arg.pvnr_flags = ap->a_flags;
695 fsync_arg.pvnr_offlo = ap->a_offlo;
696 fsync_arg.pvnr_offhi = ap->a_offhi;
697 fsync_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
698
699 /*
700 * XXX: see comment at puffs_getattr about locking
701 */
702 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_FSYNC,
703 &fsync_arg, sizeof(fsync_arg), VPTOPNC(ap->a_vp),
704 NULL /* XXXshouldbe: ap->a_vp */, NULL);
705 }
706
707 int
708 puffs_seek(void *v)
709 {
710 struct vop_seek_args /* {
711 const struct vnodeop_desc *a_desc;
712 struct vnode *a_vp;
713 off_t a_oldoff;
714 off_t a_newoff;
715 kauth_cred_t a_cred;
716 } */ *ap = v;
717
718 PUFFS_VNREQ(seek);
719
720 seek_arg.pvnr_oldoff = ap->a_oldoff;
721 seek_arg.pvnr_newoff = ap->a_newoff;
722 puffs_credcvt(&seek_arg.pvnr_cred, ap->a_cred);
723
724 /*
725 * XXX: seems like seek is called with an unlocked vp, but
726 * it can't hurt to play safe
727 */
728 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SEEK,
729 &seek_arg, sizeof(seek_arg), VPTOPNC(ap->a_vp),
730 LOCKEDVP(ap->a_vp), NULL);
731 }
732
733 int
734 puffs_remove(void *v)
735 {
736 struct vop_remove_args /* {
737 const struct vnodeop_desc *a_desc;
738 struct vnode *a_dvp;
739 struct vnode *a_vp;
740 struct componentname *a_cnp;
741 } */ *ap = v;
742 int error;
743
744 PUFFS_VNREQ(remove);
745
746 remove_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
747 puffs_makecn(&remove_arg.pvnr_cn, ap->a_cnp);
748
749 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_REMOVE,
750 &remove_arg, sizeof(remove_arg), VPTOPNC(ap->a_dvp),
751 ap->a_dvp, ap->a_vp);
752
753 vput(ap->a_vp);
754 vput(ap->a_dvp);
755
756 return error;
757 }
758
759 int
760 puffs_mkdir(void *v)
761 {
762 struct vop_mkdir_args /* {
763 const struct vnodeop_desc *a_desc;
764 struct vnode *a_dvp;
765 struct vnode **a_vpp;
766 struct componentname *a_cnp;
767 struct vattr *a_vap;
768 } */ *ap = v;
769 int error;
770
771 PUFFS_VNREQ(mkdir);
772
773 puffs_makecn(&mkdir_arg.pvnr_cn, ap->a_cnp);
774 mkdir_arg.pvnr_va = *ap->a_vap;
775
776 /* XXX: wouldn't need to relock dvp, but that's life */
777 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_MKDIR,
778 &mkdir_arg, sizeof(mkdir_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
779 if (error)
780 goto out;
781
782 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
783 mkdir_arg.pvnr_newnode, ap->a_cnp, VDIR);
784
785 out:
786 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
787 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
788 vput(ap->a_dvp);
789 return error;
790 }
791
792 int
793 puffs_rmdir(void *v)
794 {
795 struct vop_rmdir_args /* {
796 const struct vnodeop_desc *a_desc;
797 struct vnode *a_dvp;
798 struct vnode *a_vp;
799 struct componentname *a_cnp;
800 } */ *ap = v;
801 int error;
802
803 PUFFS_VNREQ(rmdir);
804
805 rmdir_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
806 puffs_makecn(&rmdir_arg.pvnr_cn, ap->a_cnp);
807
808 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_RMDIR,
809 &rmdir_arg, sizeof(rmdir_arg), VPTOPNC(ap->a_dvp),
810 ap->a_dvp, ap->a_vp);
811
812 vput(ap->a_dvp);
813 vput(ap->a_vp);
814
815 return error;
816 }
817
818 int
819 puffs_link(void *v)
820 {
821 struct vop_link_args /* {
822 const struct vnodeop_desc *a_desc;
823 struct vnode *a_dvp;
824 struct vnode *a_vp;
825 struct componentname *a_cnp;
826 }*/ *ap = v;
827 int error;
828
829 PUFFS_VNREQ(link);
830
831 link_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
832 puffs_makecn(&link_arg.pvnr_cn, ap->a_cnp);
833
834 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_LINK,
835 &link_arg, sizeof(link_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
836
837 vput(ap->a_dvp);
838
839 return error;
840 }
841
842 int
843 puffs_symlink(void *v)
844 {
845 struct vop_symlink_args /* {
846 const struct vnodeop_desc *a_desc;
847 struct vnode *a_dvp;
848 struct vnode **a_vpp;
849 struct componentname *a_cnp;
850 struct vattr *a_vap;
851 char *a_target;
852 }*/ *ap = v;
853 int error;
854
855 PUFFS_VNREQ(symlink); /* XXX: large structure */
856
857 *ap->a_vpp = NULL;
858
859 puffs_makecn(&symlink_arg.pvnr_cn, ap->a_cnp);
860 symlink_arg.pvnr_va = *ap->a_vap;
861 (void)strlcpy(symlink_arg.pvnr_link, ap->a_target,
862 sizeof(symlink_arg.pvnr_link));
863
864 /* XXX: don't need to relock parent */
865 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount),
866 PUFFS_VN_SYMLINK, &symlink_arg, sizeof(symlink_arg),
867 VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
868 if (error)
869 goto out;
870
871 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
872 symlink_arg.pvnr_newnode, ap->a_cnp, VLNK);
873
874 out:
875 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
876 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
877 vput(ap->a_dvp);
878 return error;
879 }
880
881 int
882 puffs_readlink(void *v)
883 {
884 struct vop_readlink_args /* {
885 const struct vnodeop_desc *a_desc;
886 struct vnode *a_vp;
887 struct uio *a_uio;
888 kauth_cred_t a_cred;
889 } */ *ap = v;
890 int error;
891
892 PUFFS_VNREQ(readlink);
893
894 puffs_credcvt(&readlink_arg.pvnr_cred, ap->a_cred);
895 readlink_arg.pvnr_linklen = sizeof(readlink_arg.pvnr_link);
896
897 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
898 PUFFS_VN_READLINK, &readlink_arg, sizeof(readlink_arg),
899 VPTOPNC(ap->a_vp), ap->a_vp, NULL);
900 if (error)
901 return error;
902
903 readlink_arg.pvnr_link[readlink_arg.pvnr_linklen] = '\0';
904 return uiomove(&readlink_arg.pvnr_link, readlink_arg.pvnr_linklen,
905 ap->a_uio);
906 }
907
908 /* XXXXXXX: think about locking & userspace op delocking... */
909 int
910 puffs_rename(void *v)
911 {
912 struct vop_rename_args /* {
913 const struct vnodeop_desc *a_desc;
914 struct vnode *a_fdvp;
915 struct vnode *a_fvp;
916 struct componentname *a_fcnp;
917 struct vnode *a_tdvp;
918 struct vnode *a_tvp;
919 struct componentname *a_tcnp;
920 }*/ *ap = v;
921 int error;
922
923 PUFFS_VNREQ(rename);
924
925 /*
926 * participate in the duck hunt
927 * (I could do with some canard a la presse, so hopefully
928 * this is succesful)
929 */
930 KASSERT(ap->a_tdvp != ap->a_tvp);
931
932 if (ap->a_fvp->v_mount != ap->a_tdvp->v_mount) {
933 error = EXDEV;
934 goto out;
935 }
936
937 rename_arg.pvnr_cookie_src = VPTOPNC(ap->a_fvp);
938 rename_arg.pvnr_cookie_targdir = VPTOPNC(ap->a_tdvp);
939 if (ap->a_tvp)
940 rename_arg.pvnr_cookie_targ = VPTOPNC(ap->a_tvp);
941 else
942 rename_arg.pvnr_cookie_targ = NULL;
943 puffs_makecn(&rename_arg.pvnr_cn_src, ap->a_fcnp);
944 puffs_makecn(&rename_arg.pvnr_cn_targ, ap->a_tcnp);
945
946 error = puffs_vntouser(MPTOPUFFSMP(ap->a_fdvp->v_mount),
947 PUFFS_VN_RENAME, &rename_arg, sizeof(rename_arg),
948 VPTOPNC(ap->a_fdvp), NULL, NULL);
949
950 out:
951 vput(ap->a_tdvp);
952 if (ap->a_tvp != NULL)
953 vput(ap->a_tvp);
954
955 vrele(ap->a_fdvp);
956 vrele(ap->a_fvp);
957
958 return error;
959 }
960
961 int
962 puffs_read(void *v)
963 {
964 struct vop_read_args /* {
965 const struct vnodeop_desc *a_desc;
966 struct vnode *a_vp;
967 struct uio *a_uio;
968 int a_ioflag;
969 kauth_cred_t a_cred;
970 } */ *ap = v;
971 struct puffs_vnreq_read *read_argp;
972 struct puffs_mount *pmp;
973 struct uio *uio;
974 size_t tomove, argsize;
975 int error;
976
977 uio = ap->a_uio;
978
979 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
980 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
981 argsize = sizeof(struct puffs_vnreq_read);
982 read_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
983
984 error = 0;
985 while (uio->uio_resid > 0) {
986 read_argp->pvnr_ioflag = ap->a_ioflag;
987 read_argp->pvnr_resid = tomove;
988 read_argp->pvnr_offset = uio->uio_offset;
989 puffs_credcvt(&read_argp->pvnr_cred, ap->a_cred);
990
991 argsize = sizeof(struct puffs_vnreq_read);
992 error = puffs_vntouser_adjbuf(pmp, PUFFS_VN_READ,
993 (void **)&read_argp, &argsize,
994 sizeof(struct puffs_vnreq_read), VPTOPNC(ap->a_vp),
995 ap->a_vp, NULL);
996 if (error)
997 goto out;
998
999 if (read_argp->pvnr_resid > tomove) {
1000 error = EINVAL;
1001 goto out;
1002 }
1003
1004 error = uiomove(read_argp->pvnr_data,
1005 tomove - read_argp->pvnr_resid, uio);
1006
1007 /*
1008 * in case the file is out of juice, resid from userspace
1009 * is != 0. and the error-case is quite obvious
1010 */
1011 if (error || read_argp->pvnr_resid)
1012 goto out;
1013
1014 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1015 }
1016
1017 out:
1018 free(read_argp, M_PUFFS);
1019 return error;
1020 }
1021
1022 int
1023 puffs_write(void *v)
1024 {
1025 struct vop_write_args /* {
1026 const struct vnodeop_desc *a_desc;
1027 struct vnode *a_vp;
1028 struct uio *a_uio;
1029 int a_ioflag;
1030 kauth_cred_t a_cred;
1031 }*/ *ap = v;
1032 struct puffs_vnreq_write *write_argp;
1033 struct puffs_mount *pmp;
1034 struct uio *uio;
1035 size_t tomove, argsize;
1036 int error;
1037
1038 uio = ap->a_uio;
1039
1040 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1041 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1042 argsize = sizeof(struct puffs_vnreq_write) + tomove;
1043 write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
1044
1045 error = 0;
1046 while (uio->uio_resid > 0) {
1047 write_argp->pvnr_ioflag = ap->a_ioflag;
1048 write_argp->pvnr_resid = tomove;
1049 write_argp->pvnr_offset = uio->uio_offset;
1050 puffs_credcvt(&write_argp->pvnr_cred, ap->a_cred);
1051 error = uiomove(write_argp->pvnr_data, tomove, ap->a_uio);
1052 if (error)
1053 goto out;
1054
1055 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
1056 PUFFS_VN_WRITE, write_argp, argsize, VPTOPNC(ap->a_vp),
1057 ap->a_vp, NULL);
1058 if (error) {
1059 /* restore uiomove */
1060 uio->uio_resid += tomove;
1061 uio->uio_offset -= tomove;
1062 goto out;
1063 }
1064 if (write_argp->pvnr_resid > tomove) {
1065 error = EINVAL;
1066 goto out;
1067 }
1068
1069 /* didn't move everything? bad userspace. bail */
1070 if (write_argp->pvnr_resid != 0) {
1071 uio->uio_resid += write_argp->pvnr_resid;
1072 uio->uio_offset -= write_argp->pvnr_resid;
1073 error = EIO;
1074 break;
1075 }
1076
1077 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1078 }
1079
1080 out:
1081 free(write_argp, M_PUFFS);
1082 return error;
1083 }
1084
1085 static int puffs_fcnioctl(struct vop_ioctl_args * /*XXX*/, int);
1086
1087 #define FCNIOCTL_ARG_MAX 1<<16
1088 int
1089 puffs_fcnioctl(struct vop_ioctl_args *ap, int puffsop)
1090 {
1091 /* struct vop_ioctl_args {
1092 const struct vnodeop_desc *a_desc;
1093 struct vnode *a_vp;
1094 u_long a_command;
1095 void *a_data;
1096 int a_fflag;
1097 kauth_cred_t a_cred;
1098 struct lwp *a_l;
1099 }*ap = v; */
1100 struct puffs_mount *pmp;
1101 struct puffs_sizepark pspark;
1102 void *kernbuf;
1103 size_t copylen;
1104 int error;
1105
1106 PUFFS_VNREQ(fcnioctl);
1107
1108 /*
1109 * Since this op gives the filesystem (almost) complete control on
1110 * how much it is allowed to copy from the calling process
1111 * address space, do not enable it by default, since it would
1112 * be a whopping security hole.
1113 */
1114 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1115 if ((pmp->pmp_args.pa_flags & PUFFS_FLAG_ALLOWCTL) == 0)
1116 return EINVAL; /* only shoe that fits */
1117
1118 /* fill in sizereq and store it */
1119 pspark.pkso_reqid = puffs_getreqid(pmp);
1120 pspark.pkso_reqtype = PUFFS_SIZEOPREQ_BUF_IN;
1121 pspark.pkso_copybuf = ap->a_data;
1122 pspark.pkso_bufsize = FCNIOCTL_ARG_MAX;
1123 TAILQ_INSERT_TAIL(&pmp->pmp_req_sizepark, &pspark, pkso_entries);
1124
1125 /* then fill in actual request and shoot it off */
1126 fcnioctl_arg.pvnr_command = ap->a_command;
1127 fcnioctl_arg.pvnr_fflag = ap->a_fflag;
1128 puffs_credcvt(&fcnioctl_arg.pvnr_cred, ap->a_cred);
1129 fcnioctl_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
1130
1131 error = puffs_vntouser_req(MPTOPUFFSMP(ap->a_vp->v_mount), puffsop,
1132 &fcnioctl_arg, sizeof(fcnioctl_arg), VPTOPNC(ap->a_vp),
1133 pspark.pkso_reqid, NULL, NULL);
1134
1135 /* if we don't need to copy data, we're done */
1136 if (error || !fcnioctl_arg.pvnr_copyback)
1137 return error;
1138
1139 copylen = MIN(FCNIOCTL_ARG_MAX, fcnioctl_arg.pvnr_datalen);
1140 kernbuf = malloc(copylen, M_PUFFS, M_WAITOK);
1141 error = copyin(fcnioctl_arg.pvnr_data, kernbuf, copylen);
1142 if (error)
1143 goto out;
1144 error = copyout(kernbuf, ap->a_data, copylen);
1145
1146 out:
1147 free(kernbuf, M_PUFFS);
1148 return error;
1149 }
1150
1151 int
1152 puffs_ioctl(void *v)
1153 {
1154
1155 return puffs_fcnioctl(v, PUFFS_VN_IOCTL);
1156 }
1157
1158 int
1159 puffs_fcntl(void *v)
1160 {
1161
1162 return puffs_fcnioctl(v, PUFFS_VN_FCNTL);
1163 }
1164
1165 int
1166 puffs_print(void *v)
1167 {
1168 struct vop_print_args /* {
1169 struct vnode *a_vp;
1170 } */ *ap = v;
1171 struct vnode *vp = ap->a_vp;
1172 struct puffs_node *pn = vp->v_data;
1173
1174 PUFFS_VNREQ(print);
1175
1176 /* kernel portion */
1177 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1178 " userspace cookie: %p\n", vp, pn, pn->pn_cookie);
1179 lockmgr_printinfo(&vp->v_lock);
1180
1181 /* userspace portion */
1182 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_PRINT,
1183 &print_arg, sizeof(print_arg), VPTOPNC(ap->a_vp),
1184 LOCKEDVP(ap->a_vp), NULL);
1185 }
1186
1187 int
1188 puffs_pathconf(void *v)
1189 {
1190 struct vop_pathconf_args /* {
1191 const struct vnodeop_desc *a_desc;
1192 struct vnode *a_vp;
1193 int a_name;
1194 register_t *a_retval;
1195 } */ *ap = v;
1196 int error;
1197
1198 PUFFS_VNREQ(pathconf);
1199
1200 pathconf_arg.pvnr_name = ap->a_name;
1201
1202 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
1203 PUFFS_VN_PATHCONF, &pathconf_arg, sizeof(pathconf_arg),
1204 VPTOPNC(ap->a_vp), ap->a_vp, NULL);
1205 if (error)
1206 return error;
1207
1208 *ap->a_retval = pathconf_arg.pvnr_retval;
1209
1210 return 0;
1211 }
1212
1213 int
1214 puffs_advlock(void *v)
1215 {
1216 struct vop_advlock_args /* {
1217 const struct vnodeop_desc *a_desc;
1218 struct vnode *a_vp;
1219 void *a_id;
1220 int a_op;
1221 struct flock *a_fl;
1222 int a_flags;
1223 } */ *ap = v;
1224 int error;
1225
1226 PUFFS_VNREQ(advlock);
1227
1228 error = copyin(ap->a_fl, &advlock_arg.pvnr_fl, sizeof(struct flock));
1229 if (error)
1230 return error;
1231 advlock_arg.pvnr_id = ap->a_id;
1232 advlock_arg.pvnr_op = ap->a_op;
1233 advlock_arg.pvnr_flags = ap->a_flags;
1234
1235 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ADVLOCK,
1236 &advlock_arg, sizeof(advlock_arg), VPTOPNC(ap->a_vp), NULL, NULL);
1237 }
1238
1239 /*
1240 * The rest don't get a free trip to userspace and back, they
1241 * have to stay within the kernel.
1242 */
1243
1244 /*
1245 * moreXXX: yes, todo
1246 */
1247 int
1248 puffs_lock(void *v)
1249 {
1250 struct vop_lock_args /* {
1251 struct vnode *a_vp;
1252 int a_flags;
1253 }*/ *ap = v;
1254 struct vnode *vp = ap->a_vp;
1255
1256 #if 0
1257 DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
1258 #endif
1259
1260 return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
1261 }
1262
1263 int
1264 puffs_unlock(void *v)
1265 {
1266 struct vop_unlock_args /* {
1267 struct vnode *a_vp;
1268 int a_flags;
1269 } */ *ap = v;
1270 struct vnode *vp = ap->a_vp;
1271
1272 #if 0
1273 DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
1274 #endif
1275
1276 return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
1277 }
1278
1279 int
1280 puffs_islocked(void *v)
1281 {
1282 struct vop_islocked_args *ap = v;
1283 int rv;
1284
1285 rv = lockstatus(&ap->a_vp->v_lock);
1286 return rv;
1287 }
1288
1289 #if 0
1290 int
1291 puffs_getpages(void *v)
1292 {
1293 struct vop_getpages_args /* {
1294 const struct vnodeop_desc *a_desc;
1295 struct vnode *a_vp;
1296 voff_t a_offset;
1297 struct vm_page **a_m;
1298 int *a_count;
1299 int a_centeridx;
1300 vm_prot_t a_access_type;
1301 int a_advice;
1302 int a_flags;
1303 } */ *ap = v;
1304
1305
1306 }
1307 #endif
1308
1309 int
1310 puffs_generic(void *v)
1311 {
1312 struct vop_generic_args *ap = v;
1313
1314 (void)ap;
1315 DPRINTF(("puffs_generic: ap->a_desc = %s\n", ap->a_desc->vdesc_name));
1316
1317 return EOPNOTSUPP;
1318 }
1319