puffs_vnops.c revision 1.2 1 /* $NetBSD: puffs_vnops.c,v 1.2 2006/10/23 12:21:39 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.2 2006/10/23 12:21:39 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 /* we don't really need to set this? */
271 cnp->cn_flags |= PDIRUNLOCK;
272 }
273 }
274
275 if (cnp->cn_flags & MAKEENTRY)
276 cache_enter(dvp, vp, cnp);
277 *ap->a_vpp = vp;
278
279 return 0;
280 }
281
282 int
283 puffs_create(void *v)
284 {
285 struct vop_create_args /* {
286 const struct vnodeop_desc *a_desc;
287 struct vnode *a_dvp;
288 struct vnode **a_vpp;
289 struct componentname *a_cnp;
290 struct vattr *a_vap;
291 } */ *ap = v;
292 int error;
293
294 PUFFS_VNREQ(create);
295
296 puffs_makecn(&create_arg.pvnr_cn, ap->a_cnp);
297 create_arg.pvnr_va = *ap->a_vap;
298
299 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_CREATE,
300 &create_arg, sizeof(create_arg), VPTOPNC(ap->a_dvp),
301 ap->a_dvp, NULL);
302 if (error)
303 return error;
304
305 return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
306 create_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type);
307 }
308
309 int
310 puffs_mknod(void *v)
311 {
312 struct vop_mknod_args /* {
313 const struct vnodeop_desc *a_desc;
314 struct vnode *a_dvp;
315 struct vnode **a_vpp;
316 struct componentname *a_cnp;
317 struct vattr *a_vap;
318 } */ *ap = v;
319 int error;
320
321 PUFFS_VNREQ(mknod);
322
323 puffs_makecn(&mknod_arg.pvnr_cn, ap->a_cnp);
324 mknod_arg.pvnr_va = *ap->a_vap;
325
326 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_MKNOD,
327 &mknod_arg, sizeof(mknod_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
328 if (error)
329 return error;
330
331 return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
332 mknod_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type);
333 }
334
335 int
336 puffs_open(void *v)
337 {
338 struct vop_open_args /* {
339 const struct vnodeop_desc *a_desc;
340 struct vnode *a_vp;
341 int a_mode;
342 kauth_cred_t a_cred;
343 struct lwp *a_l;
344 } */ *ap = v;
345
346 PUFFS_VNREQ(open);
347
348 open_arg.pvnr_mode = ap->a_mode;
349 puffs_credcvt(&open_arg.pvnr_cred, ap->a_cred);
350 open_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
351
352 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_OPEN,
353 &open_arg, sizeof(open_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
354 }
355
356 int
357 puffs_close(void *v)
358 {
359 struct vop_close_args /* {
360 const struct vnodeop_desc *a_desc;
361 struct vnode *a_vp;
362 int a_fflag;
363 kauth_cred_t a_cred;
364 struct lwp *a_l;
365 } */ *ap = v;
366
367 PUFFS_VNREQ(close);
368
369 close_arg.pvnr_fflag = ap->a_fflag;
370 puffs_credcvt(&close_arg.pvnr_cred, ap->a_cred);
371 close_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
372
373 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_CLOSE,
374 &close_arg, sizeof(close_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
375 }
376
377 int
378 puffs_access(void *v)
379 {
380 struct vop_access_args /* {
381 const struct vnodeop_desc *a_desc;
382 struct vnode *a_vp;
383 int a_mode;
384 kauth_cred_t a_cred;
385 struct lwp *a_l;
386 } */ *ap = v;
387 int error;
388
389 PUFFS_VNREQ(access);
390
391 access_arg.pvnr_mode = ap->a_mode;
392 access_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
393 puffs_credcvt(&access_arg.pvnr_cred, ap->a_cred);
394
395 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ACCESS,
396 &access_arg, sizeof(access_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
397 if (error)
398 return error;
399
400 /*
401 * XXXtothepeople: no execute permissions yet. Otherwise
402 * all hell will break loose if we try to execute a file
403 * without VOP_GETPAGES support. It is forthcoming, just
404 * not there yet ...
405 */
406 if (ap->a_mode == VEXEC && ap->a_vp->v_type != VDIR)
407 return EACCES;
408
409 return 0;
410 }
411
412 int
413 puffs_getattr(void *v)
414 {
415 struct vop_getattr_args /* {
416 const struct vnodeop_desc *a_desc;
417 struct vnode *a_vp;
418 struct vattr *a_vap;
419 kauth_cred_t a_cred;
420 struct lwp *a_l;
421 } */ *ap = v;
422 int error;
423
424 PUFFS_VNREQ(getattr);
425
426 vattr_null(&getattr_arg.pvnr_va);
427 puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred);
428 getattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
429
430 /*
431 * XXX + XX (dos equis): this can't go through the unlock/lock
432 * cycle, since it can be called from uvn_attach(), which fiddles
433 * around with VXLOCK and therefore breaks vn_lock(). Proper
434 * fix pending.
435 */
436 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_GETATTR,
437 &getattr_arg, sizeof(getattr_arg), VPTOPNC(ap->a_vp),
438 NULL /* XXXseeabove: should be LOCKEDVP(ap->a_vp) */, NULL);
439 if (error)
440 return error;
441
442 (void)memcpy(ap->a_vap, &getattr_arg.pvnr_va, sizeof(struct vattr));
443
444 /*
445 * XXXtothepeople: adjust the return value so that we don't
446 * advertise execute bits. Otherwise all hell will break
447 * loose if we try to execute a file without VOP_GETPAGES
448 * support. It is forthcoming, just not there yet ...
449 */
450 if (ap->a_vp->v_type != VDIR)
451 ap->a_vap->va_mode &= ~0111;
452
453 return 0;
454 }
455
456 int
457 puffs_setattr(void *v)
458 {
459 struct vop_getattr_args /* {
460 const struct vnodeop_desc *a_desc;
461 struct vnode *a_vp;
462 struct vattr *a_vap;
463 kauth_cred_t a_cred;
464 struct lwp *a_l;
465 } */ *ap = v;
466
467 PUFFS_VNREQ(setattr);
468
469 (void)memcpy(&setattr_arg.pvnr_va, ap->a_vap, sizeof(struct vattr));
470 puffs_credcvt(&setattr_arg.pvnr_cred, ap->a_cred);
471 setattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
472
473 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SETATTR,
474 &setattr_arg, sizeof(setattr_arg), VPTOPNC(ap->a_vp),
475 ap->a_vp, NULL);
476 }
477
478 int
479 puffs_revoke(void *v)
480 {
481 struct vop_revoke_args /* {
482 const struct vnodeop_desc *a_desc;
483 struct vnode *a_vp;
484 int a_flags;
485 } */ *ap = v;
486 PUFFS_VNREQ(revoke);
487
488 revoke_arg.pvnr_flags = ap->a_flags;
489
490 /* don't really care if userspace doesn't want to play along */
491 puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_REVOKE,
492 &revoke_arg, sizeof(revoke_arg), VPTOPNC(ap->a_vp), NULL, NULL);
493
494 return genfs_revoke(v);
495 }
496
497 int
498 puffs_reclaim(void *v)
499 {
500 struct vop_reclaim_args /* {
501 const struct vnodeop_desc *a_desc;
502 struct vnode *a_vp;
503 struct lwp *a_l;
504 } */ *ap = v;
505 struct puffs_mount *pmp;
506 int error;
507
508 PUFFS_VNREQ(reclaim);
509
510 /*
511 * first things first: check if someone is trying to reclaim the
512 * root vnode. do not allow that to travel to userspace.
513 * Note that we don't need to take the lock similarly to
514 * puffs_root(), since there is only one of us.
515 */
516 if (ap->a_vp->v_flag & VROOT) {
517 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
518 #ifdef DIAGNOSTIC
519 simple_lock(&pmp->pmp_lock);
520 if (pmp->pmp_root == NULL)
521 panic("puffs_reclaim: releasing root vnode (%p) twice",
522 ap->a_vp);
523 simple_unlock(&pmp->pmp_lock);
524 #endif
525 pmp->pmp_root = NULL;
526 puffs_putvnode(ap->a_vp);
527 return 0;
528 }
529
530 reclaim_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
531
532 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_RECLAIM,
533 &reclaim_arg, sizeof(reclaim_arg), VPTOPNC(ap->a_vp), NULL, NULL);
534 #if 0
535 /*
536 * XXX: if reclaim fails for any other reason than the userspace
537 * being dead, we should consider unmounting the filesystem, since
538 * we can't trust it to be in a consistent state anymore. But for
539 * now, just ignore all errors.
540 */
541 if (error)
542 return error;
543 #endif
544
545 puffs_putvnode(ap->a_vp);
546
547 return 0;
548 }
549
550 int
551 puffs_readdir(void *v)
552 {
553 struct vop_readdir_args /* {
554 const struct vnodeop_desc *a_desc;
555 struct vnode *a_vp;
556 struct uio *a_uio;
557 kauth_cred_t a_cred;
558 int *a_eofflag;
559 off_t **a_cookies;
560 int *a_ncookies;
561 } */ *ap = v;
562 struct puffs_vnreq_readdir *readdir_argp;
563 size_t argsize;
564 struct uio *uio = ap->a_uio;
565 size_t howmuch;
566 int error;
567
568 /* worry about these later */
569 if (!(ap->a_cookies == NULL && ap->a_ncookies == NULL))
570 return EOPNOTSUPP;
571
572 argsize = sizeof(struct puffs_vnreq_readdir);
573 readdir_argp = malloc(argsize, M_PUFFS, M_ZERO | M_WAITOK);
574
575 puffs_credcvt(&readdir_argp->pvnr_cred, ap->a_cred);
576 readdir_argp->pvnr_offset = uio->uio_offset;
577 readdir_argp->pvnr_resid = uio->uio_resid;
578
579 error = puffs_vntouser_adjbuf(MPTOPUFFSMP(ap->a_vp->v_mount),
580 PUFFS_VN_READDIR, (void **)&readdir_argp, &argsize,
581 sizeof(struct puffs_vnreq_readdir),
582 VPTOPNC(ap->a_vp), ap->a_vp, NULL);
583 if (error)
584 goto out;
585
586 /* userspace is cheating? */
587 if (readdir_argp->pvnr_resid > uio->uio_resid) {
588 error = EINVAL;
589 goto out;
590 }
591
592 /* bouncy-wouncy with the directory data */
593 howmuch = uio->uio_resid - readdir_argp->pvnr_resid;
594 error = uiomove(readdir_argp->pvnr_dent, howmuch, uio);
595 if (error)
596 goto out;
597 uio->uio_offset = readdir_argp->pvnr_offset;
598
599 out:
600 free(readdir_argp, M_PUFFS);
601 return error;
602 }
603
604 int
605 puffs_poll(void *v)
606 {
607 struct vop_poll_args /* {
608 const struct vnodeop_desc *a_desc;
609 struct vnode *a_vp;
610 int a_events;
611 struct lwp *a_l;
612 }*/ *ap = v;
613
614 PUFFS_VNREQ(poll);
615
616 poll_arg.pvnr_events = ap->a_events;
617 poll_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
618
619 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_POLL,
620 &poll_arg, sizeof(poll_arg), VPTOPNC(ap->a_vp), NULL, NULL);
621 }
622
623 int
624 puffs_fsync(void *v)
625 {
626 struct vop_fsync_args /* {
627 const struct vnodeop_desc *a_desc;
628 struct vnode *a_vp;
629 kauth_cred_t a_cred;
630 int a_flags;
631 off_t a_offlo;
632 off_t a_offhi;
633 struct lwp *a_l;
634 } */ *ap = v;
635
636 PUFFS_VNREQ(fsync);
637
638 puffs_credcvt(&fsync_arg.pvnr_cred, ap->a_cred);
639 fsync_arg.pvnr_flags = ap->a_flags;
640 fsync_arg.pvnr_offlo = ap->a_offlo;
641 fsync_arg.pvnr_offhi = ap->a_offhi;
642 fsync_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
643
644 /*
645 * XXX: see comment at puffs_getattr about locking
646 */
647 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_FSYNC,
648 &fsync_arg, sizeof(fsync_arg), VPTOPNC(ap->a_vp),
649 NULL /* XXXshouldbe: ap->a_vp */, NULL);
650 }
651
652 int
653 puffs_seek(void *v)
654 {
655 struct vop_seek_args /* {
656 const struct vnodeop_desc *a_desc;
657 struct vnode *a_vp;
658 off_t a_oldoff;
659 off_t a_newoff;
660 kauth_cred_t a_cred;
661 } */ *ap = v;
662
663 PUFFS_VNREQ(seek);
664
665 seek_arg.pvnr_oldoff = ap->a_oldoff;
666 seek_arg.pvnr_newoff = ap->a_newoff;
667 puffs_credcvt(&seek_arg.pvnr_cred, ap->a_cred);
668
669 /*
670 * XXX: seems like seek is called with an unlocked vp, but
671 * it can't hurt to play safe
672 */
673 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SEEK,
674 &seek_arg, sizeof(seek_arg), VPTOPNC(ap->a_vp),
675 LOCKEDVP(ap->a_vp), NULL);
676 }
677
678 int
679 puffs_remove(void *v)
680 {
681 struct vop_remove_args /* {
682 const struct vnodeop_desc *a_desc;
683 struct vnode *a_dvp;
684 struct vnode *a_vp;
685 struct componentname *a_cnp;
686 } */ *ap = v;
687 int error;
688
689 PUFFS_VNREQ(remove);
690
691 remove_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
692 puffs_makecn(&remove_arg.pvnr_cn, ap->a_cnp);
693
694 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_REMOVE,
695 &remove_arg, sizeof(remove_arg), VPTOPNC(ap->a_dvp),
696 ap->a_dvp, ap->a_vp);
697
698 vput(ap->a_vp);
699 vput(ap->a_dvp);
700
701 return error;
702 }
703
704 int
705 puffs_mkdir(void *v)
706 {
707 struct vop_mkdir_args /* {
708 const struct vnodeop_desc *a_desc;
709 struct vnode *a_dvp;
710 struct vnode **a_vpp;
711 struct componentname *a_cnp;
712 struct vattr *a_vap;
713 } */ *ap = v;
714 int error;
715
716 PUFFS_VNREQ(mkdir);
717
718 puffs_makecn(&mkdir_arg.pvnr_cn, ap->a_cnp);
719 mkdir_arg.pvnr_va = *ap->a_vap;
720
721 /* XXX: wouldn't need to relock dvp, but that's life */
722 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_MKDIR,
723 &mkdir_arg, sizeof(mkdir_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
724 if (error)
725 return error;
726
727 return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
728 mkdir_arg.pvnr_newnode, ap->a_cnp, VDIR);
729 }
730
731 int
732 puffs_rmdir(void *v)
733 {
734 struct vop_rmdir_args /* {
735 const struct vnodeop_desc *a_desc;
736 struct vnode *a_dvp;
737 struct vnode *a_vp;
738 struct componentname *a_cnp;
739 } */ *ap = v;
740 int error;
741
742 PUFFS_VNREQ(rmdir);
743
744 rmdir_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
745 puffs_makecn(&rmdir_arg.pvnr_cn, ap->a_cnp);
746
747 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_RMDIR,
748 &rmdir_arg, sizeof(rmdir_arg), VPTOPNC(ap->a_dvp),
749 ap->a_dvp, ap->a_vp);
750
751 vput(ap->a_dvp);
752 vput(ap->a_vp);
753
754 return error;
755 }
756
757 int
758 puffs_link(void *v)
759 {
760 struct vop_link_args /* {
761 const struct vnodeop_desc *a_desc;
762 struct vnode *a_dvp;
763 struct vnode *a_vp;
764 struct componentname *a_cnp;
765 }*/ *ap = v;
766 int error;
767
768 PUFFS_VNREQ(link);
769
770 link_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
771 puffs_makecn(&link_arg.pvnr_cn, ap->a_cnp);
772
773 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_LINK,
774 &link_arg, sizeof(link_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
775
776 vput(ap->a_dvp);
777
778 return error;
779 }
780
781 int
782 puffs_symlink(void *v)
783 {
784 struct vop_symlink_args /* {
785 const struct vnodeop_desc *a_desc;
786 struct vnode *a_dvp;
787 struct vnode **a_vpp;
788 struct componentname *a_cnp;
789 struct vattr *a_vap;
790 char *a_target;
791 }*/ *ap = v;
792 int error;
793
794 PUFFS_VNREQ(symlink); /* XXX: large structure */
795
796 *ap->a_vpp = NULL;
797
798 puffs_makecn(&symlink_arg.pvnr_cn, ap->a_cnp);
799 symlink_arg.pvnr_va = *ap->a_vap;
800 (void)strlcpy(symlink_arg.pvnr_link, ap->a_target,
801 sizeof(symlink_arg.pvnr_link));
802
803 /* XXX: don't need to relock parent */
804 error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount),
805 PUFFS_VN_SYMLINK, &symlink_arg, sizeof(symlink_arg),
806 VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
807 if (error)
808 return error;
809
810 return puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
811 symlink_arg.pvnr_newnode, ap->a_cnp, VLNK);
812 }
813
814 int
815 puffs_readlink(void *v)
816 {
817 struct vop_readlink_args /* {
818 const struct vnodeop_desc *a_desc;
819 struct vnode *a_vp;
820 struct uio *a_uio;
821 kauth_cred_t a_cred;
822 } */ *ap = v;
823 int error;
824
825 PUFFS_VNREQ(readlink);
826
827 puffs_credcvt(&readlink_arg.pvnr_cred, ap->a_cred);
828 readlink_arg.pvnr_linklen = sizeof(readlink_arg.pvnr_link);
829
830 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
831 PUFFS_VN_READLINK, &readlink_arg, sizeof(readlink_arg),
832 VPTOPNC(ap->a_vp), ap->a_vp, NULL);
833 if (error)
834 return error;
835
836 readlink_arg.pvnr_link[readlink_arg.pvnr_linklen] = '\0';
837 return uiomove(&readlink_arg.pvnr_link, readlink_arg.pvnr_linklen,
838 ap->a_uio);
839 }
840
841 /* XXXXXXX: think about locking & userspace op delocking... */
842 int
843 puffs_rename(void *v)
844 {
845 struct vop_rename_args /* {
846 const struct vnodeop_desc *a_desc;
847 struct vnode *a_fdvp;
848 struct vnode *a_fvp;
849 struct componentname *a_fcnp;
850 struct vnode *a_tdvp;
851 struct vnode *a_tvp;
852 struct componentname *a_tcnp;
853 }*/ *ap = v;
854 int error;
855
856 PUFFS_VNREQ(rename);
857
858 /*
859 * participate in the duck hunt
860 * (I could do with some canard a la presse, so hopefully
861 * this is succesful)
862 */
863 KASSERT(ap->a_tdvp != ap->a_tvp);
864
865 if (ap->a_fvp->v_mount != ap->a_tdvp->v_mount) {
866 error = EXDEV;
867 goto out;
868 }
869
870 rename_arg.pvnr_cookie_src = VPTOPNC(ap->a_fvp);
871 rename_arg.pvnr_cookie_targdir = VPTOPNC(ap->a_tdvp);
872 if (ap->a_tvp)
873 rename_arg.pvnr_cookie_targ = VPTOPNC(ap->a_tvp);
874 else
875 rename_arg.pvnr_cookie_targ = NULL;
876 puffs_makecn(&rename_arg.pvnr_cn_src, ap->a_fcnp);
877 puffs_makecn(&rename_arg.pvnr_cn_targ, ap->a_tcnp);
878
879 error = puffs_vntouser(MPTOPUFFSMP(ap->a_fdvp->v_mount),
880 PUFFS_VN_RENAME, &rename_arg, sizeof(rename_arg),
881 VPTOPNC(ap->a_fdvp), NULL, NULL);
882
883 out:
884 vput(ap->a_tdvp);
885 if (ap->a_tvp != NULL)
886 vput(ap->a_tvp);
887
888 vrele(ap->a_fdvp);
889 vrele(ap->a_fvp);
890
891 return error;
892 }
893
894 int
895 puffs_read(void *v)
896 {
897 struct vop_read_args /* {
898 const struct vnodeop_desc *a_desc;
899 struct vnode *a_vp;
900 struct uio *a_uio;
901 int a_ioflag;
902 kauth_cred_t a_cred;
903 } */ *ap = v;
904 struct puffs_vnreq_read *read_argp;
905 struct puffs_mount *pmp;
906 struct uio *uio;
907 size_t tomove, argsize;
908 int error;
909
910 uio = ap->a_uio;
911
912 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
913 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
914 argsize = sizeof(struct puffs_vnreq_read);
915 read_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
916
917 error = 0;
918 while (uio->uio_resid > 0) {
919 read_argp->pvnr_ioflag = ap->a_ioflag;
920 read_argp->pvnr_resid = tomove;
921 read_argp->pvnr_offset = uio->uio_offset;
922 puffs_credcvt(&read_argp->pvnr_cred, ap->a_cred);
923
924 argsize = sizeof(struct puffs_vnreq_read);
925 error = puffs_vntouser_adjbuf(pmp, PUFFS_VN_READ,
926 (void **)&read_argp, &argsize,
927 sizeof(struct puffs_vnreq_read), VPTOPNC(ap->a_vp),
928 ap->a_vp, NULL);
929 if (error)
930 goto out;
931
932 if (read_argp->pvnr_resid > tomove) {
933 error = EINVAL;
934 goto out;
935 }
936
937 error = uiomove(read_argp->pvnr_data,
938 tomove - read_argp->pvnr_resid, uio);
939
940 /*
941 * in case the file is out of juice, resid from userspace
942 * is != 0. and the error-case is quite obvious
943 */
944 if (error || read_argp->pvnr_resid)
945 goto out;
946
947 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
948 }
949
950 out:
951 free(read_argp, M_PUFFS);
952 return error;
953 }
954
955 int
956 puffs_write(void *v)
957 {
958 struct vop_write_args /* {
959 const struct vnodeop_desc *a_desc;
960 struct vnode *a_vp;
961 struct uio *a_uio;
962 int a_ioflag;
963 kauth_cred_t a_cred;
964 }*/ *ap = v;
965 struct puffs_vnreq_write *write_argp;
966 struct puffs_mount *pmp;
967 struct uio *uio;
968 size_t tomove, argsize;
969 int error;
970
971 uio = ap->a_uio;
972
973 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
974 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
975 argsize = sizeof(struct puffs_vnreq_write) + tomove;
976 write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
977
978 error = 0;
979 while (uio->uio_resid > 0) {
980 write_argp->pvnr_ioflag = ap->a_ioflag;
981 write_argp->pvnr_resid = tomove;
982 write_argp->pvnr_offset = uio->uio_offset;
983 puffs_credcvt(&write_argp->pvnr_cred, ap->a_cred);
984 error = uiomove(write_argp->pvnr_data, tomove, ap->a_uio);
985 if (error)
986 goto out;
987
988 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
989 PUFFS_VN_WRITE, write_argp, argsize, VPTOPNC(ap->a_vp),
990 ap->a_vp, NULL);
991 if (error) {
992 /* restore uiomove */
993 uio->uio_resid += tomove;
994 uio->uio_offset -= tomove;
995 goto out;
996 }
997 if (write_argp->pvnr_resid > tomove) {
998 error = EINVAL;
999 goto out;
1000 }
1001
1002 /* didn't move everything? bad userspace. bail */
1003 if (write_argp->pvnr_resid != 0) {
1004 uio->uio_resid += write_argp->pvnr_resid;
1005 uio->uio_offset -= write_argp->pvnr_resid;
1006 error = EIO;
1007 break;
1008 }
1009
1010 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1011 }
1012
1013 out:
1014 free(write_argp, M_PUFFS);
1015 return error;
1016 }
1017
1018 static int puffs_fcnioctl(struct vop_ioctl_args * /*XXX*/, int);
1019
1020 #define FCNIOCTL_ARG_MAX 1<<16
1021 int
1022 puffs_fcnioctl(struct vop_ioctl_args *ap, int puffsop)
1023 {
1024 /* struct vop_ioctl_args {
1025 const struct vnodeop_desc *a_desc;
1026 struct vnode *a_vp;
1027 u_long a_command;
1028 void *a_data;
1029 int a_fflag;
1030 kauth_cred_t a_cred;
1031 struct lwp *a_l;
1032 }*ap = v; */
1033 struct puffs_mount *pmp;
1034 struct puffs_sizepark pspark;
1035 void *kernbuf;
1036 size_t copylen;
1037 int error;
1038
1039 PUFFS_VNREQ(fcnioctl);
1040
1041 /*
1042 * Since this op gives the filesystem (almost) complete control on
1043 * how much it is allowed to copy from the calling process
1044 * address space, do not enable it by default, since it would
1045 * be a whopping security hole.
1046 */
1047 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1048 if ((pmp->pmp_args.pa_flags & PUFFS_FLAG_ALLOWCTL) == 0)
1049 return EINVAL; /* only shoe that fits */
1050
1051 /* fill in sizereq and store it */
1052 pspark.pkso_reqid = puffs_getreqid(pmp);
1053 pspark.pkso_reqtype = PUFFS_SIZEOPREQ_BUF_IN;
1054 pspark.pkso_copybuf = ap->a_data;
1055 pspark.pkso_bufsize = FCNIOCTL_ARG_MAX;
1056 TAILQ_INSERT_TAIL(&pmp->pmp_req_sizepark, &pspark, pkso_entries);
1057
1058 /* then fill in actual request and shoot it off */
1059 fcnioctl_arg.pvnr_command = ap->a_command;
1060 fcnioctl_arg.pvnr_fflag = ap->a_fflag;
1061 puffs_credcvt(&fcnioctl_arg.pvnr_cred, ap->a_cred);
1062 fcnioctl_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
1063
1064 error = puffs_vntouser_req(MPTOPUFFSMP(ap->a_vp->v_mount), puffsop,
1065 &fcnioctl_arg, sizeof(fcnioctl_arg), VPTOPNC(ap->a_vp),
1066 pspark.pkso_reqid, NULL, NULL);
1067
1068 /* if we don't need to copy data, we're done */
1069 if (error || !fcnioctl_arg.pvnr_copyback)
1070 return error;
1071
1072 copylen = MIN(FCNIOCTL_ARG_MAX, fcnioctl_arg.pvnr_datalen);
1073 kernbuf = malloc(copylen, M_PUFFS, M_WAITOK);
1074 error = copyin(fcnioctl_arg.pvnr_data, kernbuf, copylen);
1075 if (error)
1076 goto out;
1077 error = copyout(kernbuf, ap->a_data, copylen);
1078
1079 out:
1080 free(kernbuf, M_PUFFS);
1081 return error;
1082 }
1083
1084 int
1085 puffs_ioctl(void *v)
1086 {
1087
1088 return puffs_fcnioctl(v, PUFFS_VN_IOCTL);
1089 }
1090
1091 int
1092 puffs_fcntl(void *v)
1093 {
1094
1095 return puffs_fcnioctl(v, PUFFS_VN_FCNTL);
1096 }
1097
1098 int
1099 puffs_print(void *v)
1100 {
1101 struct vop_print_args /* {
1102 struct vnode *a_vp;
1103 } */ *ap = v;
1104 struct vnode *vp = ap->a_vp;
1105 struct puffs_node *pn = vp->v_data;
1106
1107 PUFFS_VNREQ(print);
1108
1109 /* kernel portion */
1110 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1111 " userspace cookie: %p\n", vp, pn, pn->pn_cookie);
1112 lockmgr_printinfo(&vp->v_lock);
1113
1114 /* userspace portion */
1115 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_PRINT,
1116 &print_arg, sizeof(print_arg), VPTOPNC(ap->a_vp),
1117 LOCKEDVP(ap->a_vp), NULL);
1118 }
1119
1120 int
1121 puffs_pathconf(void *v)
1122 {
1123 struct vop_pathconf_args /* {
1124 const struct vnodeop_desc *a_desc;
1125 struct vnode *a_vp;
1126 int a_name;
1127 register_t *a_retval;
1128 } */ *ap = v;
1129 int error;
1130
1131 PUFFS_VNREQ(pathconf);
1132
1133 pathconf_arg.pvnr_name = ap->a_name;
1134
1135 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
1136 PUFFS_VN_PATHCONF, &pathconf_arg, sizeof(pathconf_arg),
1137 VPTOPNC(ap->a_vp), ap->a_vp, NULL);
1138 if (error)
1139 return error;
1140
1141 *ap->a_retval = pathconf_arg.pvnr_retval;
1142
1143 return 0;
1144 }
1145
1146 int
1147 puffs_advlock(void *v)
1148 {
1149 struct vop_advlock_args /* {
1150 const struct vnodeop_desc *a_desc;
1151 struct vnode *a_vp;
1152 void *a_id;
1153 int a_op;
1154 struct flock *a_fl;
1155 int a_flags;
1156 } */ *ap = v;
1157 int error;
1158
1159 PUFFS_VNREQ(advlock);
1160
1161 error = copyin(ap->a_fl, &advlock_arg.pvnr_fl, sizeof(struct flock));
1162 if (error)
1163 return error;
1164 advlock_arg.pvnr_id = ap->a_id;
1165 advlock_arg.pvnr_op = ap->a_op;
1166 advlock_arg.pvnr_flags = ap->a_flags;
1167
1168 return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ADVLOCK,
1169 &advlock_arg, sizeof(advlock_arg), VPTOPNC(ap->a_vp), NULL, NULL);
1170 }
1171
1172 /*
1173 * The rest don't get a free trip to userspace and back, they
1174 * have to stay within the kernel.
1175 */
1176
1177 /*
1178 * We don't want to do anything in userspace about this now, we'll
1179 * simply nuke everything when we reclaim the vnode.
1180 */
1181 int
1182 puffs_inactive(void *v)
1183 {
1184 struct vop_inactive_args /* {
1185 const struct vnodeop_desc *a_desc;
1186 struct vnode *a_vp;
1187 struct lwp *a_l;
1188 } */ *ap = v;
1189 struct puffs_node *pnode;
1190
1191 pnode = ap->a_vp->v_data;
1192 pnode->pn_stat |= PNODE_INACTIVE;
1193 VOP_UNLOCK(ap->a_vp, 0);
1194
1195 return 0;
1196 }
1197
1198 /*
1199 * moreXXX: yes, todo
1200 */
1201 int
1202 puffs_lock(void *v)
1203 {
1204 struct vop_lock_args /* {
1205 struct vnode *a_vp;
1206 int a_flags;
1207 }*/ *ap = v;
1208 struct vnode *vp = ap->a_vp;
1209
1210 #if 0
1211 DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
1212 #endif
1213
1214 return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
1215 }
1216
1217 int
1218 puffs_unlock(void *v)
1219 {
1220 struct vop_unlock_args /* {
1221 struct vnode *a_vp;
1222 int a_flags;
1223 } */ *ap = v;
1224 struct vnode *vp = ap->a_vp;
1225
1226 #if 0
1227 DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
1228 #endif
1229
1230 return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
1231 }
1232
1233 int
1234 puffs_islocked(void *v)
1235 {
1236 struct vop_islocked_args *ap = v;
1237 int rv;
1238
1239 rv = lockstatus(&ap->a_vp->v_lock);
1240 return rv;
1241 }
1242
1243 #if 0
1244 int
1245 puffs_getpages(void *v)
1246 {
1247 struct vop_getpages_args /* {
1248 const struct vnodeop_desc *a_desc;
1249 struct vnode *a_vp;
1250 voff_t a_offset;
1251 struct vm_page **a_m;
1252 int *a_count;
1253 int a_centeridx;
1254 vm_prot_t a_access_type;
1255 int a_advice;
1256 int a_flags;
1257 } */ *ap = v;
1258
1259
1260 }
1261 #endif
1262
1263 int
1264 puffs_generic(void *v)
1265 {
1266 struct vop_generic_args *ap = v;
1267
1268 (void)ap;
1269 DPRINTF(("puffs_generic: ap->a_desc = %s\n", ap->a_desc->vdesc_name));
1270
1271 return EOPNOTSUPP;
1272 }
1273