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