puffs_vnops.c revision 1.107 1 /* $NetBSD: puffs_vnops.c,v 1.107 2007/10/11 19:41:14 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006, 2007 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 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.107 2007/10/11 19:41:14 pooka Exp $");
34
35 #include <sys/param.h>
36 #include <sys/fstrans.h>
37 #include <sys/malloc.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/vnode.h>
41 #include <sys/proc.h>
42
43 #include <uvm/uvm.h>
44
45 #include <fs/puffs/puffs_msgif.h>
46 #include <fs/puffs/puffs_sys.h>
47
48 #include <miscfs/fifofs/fifo.h>
49 #include <miscfs/genfs/genfs.h>
50 #include <miscfs/specfs/specdev.h>
51
52 int puffs_lookup(void *);
53 int puffs_create(void *);
54 int puffs_access(void *);
55 int puffs_mknod(void *);
56 int puffs_open(void *);
57 int puffs_close(void *);
58 int puffs_getattr(void *);
59 int puffs_setattr(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 int puffs_strategy(void *);
81 int puffs_bmap(void *);
82 int puffs_mmap(void *);
83 int puffs_getpages(void *);
84
85 int puffs_spec_read(void *);
86 int puffs_spec_write(void *);
87 int puffs_fifo_read(void *);
88 int puffs_fifo_write(void *);
89
90 int puffs_checkop(void *);
91
92
93 /* VOP_LEASE() not included */
94
95 int puffs_generic(void *);
96
97 #if 0
98 #define puffs_lock genfs_lock
99 #define puffs_unlock genfs_unlock
100 #define puffs_islocked genfs_islocked
101 #else
102 int puffs_lock(void *);
103 int puffs_unlock(void *);
104 int puffs_islocked(void *);
105 #endif
106
107 int (**puffs_vnodeop_p)(void *);
108 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
109 { &vop_default_desc, vn_default_error },
110 { &vop_lookup_desc, puffs_lookup }, /* REAL lookup */
111 { &vop_create_desc, puffs_checkop }, /* create */
112 { &vop_mknod_desc, puffs_checkop }, /* mknod */
113 { &vop_open_desc, puffs_open }, /* REAL open */
114 { &vop_close_desc, puffs_checkop }, /* close */
115 { &vop_access_desc, puffs_access }, /* REAL access */
116 { &vop_getattr_desc, puffs_checkop }, /* getattr */
117 { &vop_setattr_desc, puffs_checkop }, /* setattr */
118 { &vop_read_desc, puffs_checkop }, /* read */
119 { &vop_write_desc, puffs_checkop }, /* write */
120 { &vop_fsync_desc, puffs_fsync }, /* REAL fsync */
121 { &vop_seek_desc, puffs_checkop }, /* seek */
122 { &vop_remove_desc, puffs_checkop }, /* remove */
123 { &vop_link_desc, puffs_checkop }, /* link */
124 { &vop_rename_desc, puffs_checkop }, /* rename */
125 { &vop_mkdir_desc, puffs_checkop }, /* mkdir */
126 { &vop_rmdir_desc, puffs_checkop }, /* rmdir */
127 { &vop_symlink_desc, puffs_checkop }, /* symlink */
128 { &vop_readdir_desc, puffs_checkop }, /* readdir */
129 { &vop_readlink_desc, puffs_checkop }, /* readlink */
130 { &vop_getpages_desc, puffs_checkop }, /* getpages */
131 { &vop_putpages_desc, genfs_putpages }, /* REAL putpages */
132 { &vop_pathconf_desc, puffs_checkop }, /* pathconf */
133 { &vop_advlock_desc, puffs_checkop }, /* advlock */
134 { &vop_strategy_desc, puffs_strategy }, /* REAL strategy */
135 { &vop_revoke_desc, genfs_revoke }, /* REAL revoke */
136 { &vop_abortop_desc, genfs_abortop }, /* REAL abortop */
137 { &vop_inactive_desc, puffs_inactive }, /* REAL inactive */
138 { &vop_reclaim_desc, puffs_reclaim }, /* REAL reclaim */
139 { &vop_lock_desc, puffs_lock }, /* REAL lock */
140 { &vop_unlock_desc, puffs_unlock }, /* REAL unlock */
141 { &vop_bmap_desc, puffs_bmap }, /* REAL bmap */
142 { &vop_print_desc, puffs_print }, /* REAL print */
143 { &vop_islocked_desc, puffs_islocked }, /* REAL islocked */
144 { &vop_bwrite_desc, genfs_nullop }, /* REAL bwrite */
145 { &vop_mmap_desc, puffs_mmap }, /* REAL mmap */
146 { &vop_poll_desc, puffs_poll }, /* REAL poll */
147
148 { &vop_kqfilter_desc, genfs_eopnotsupp }, /* kqfilter XXX */
149 { NULL, NULL }
150 };
151 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
152 { &puffs_vnodeop_p, puffs_vnodeop_entries };
153
154
155 int (**puffs_specop_p)(void *);
156 const struct vnodeopv_entry_desc puffs_specop_entries[] = {
157 { &vop_default_desc, vn_default_error },
158 { &vop_lookup_desc, spec_lookup }, /* lookup, ENOTDIR */
159 { &vop_create_desc, spec_create }, /* genfs_badop */
160 { &vop_mknod_desc, spec_mknod }, /* genfs_badop */
161 { &vop_open_desc, spec_open }, /* spec_open */
162 { &vop_close_desc, spec_close }, /* spec_close */
163 { &vop_access_desc, puffs_checkop }, /* access */
164 { &vop_getattr_desc, puffs_checkop }, /* getattr */
165 { &vop_setattr_desc, puffs_checkop }, /* setattr */
166 { &vop_read_desc, puffs_spec_read }, /* update, read */
167 { &vop_write_desc, puffs_spec_write }, /* update, write */
168 { &vop_lease_desc, spec_lease_check }, /* genfs_nullop */
169 { &vop_ioctl_desc, spec_ioctl }, /* spec_ioctl */
170 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
171 { &vop_poll_desc, spec_poll }, /* spec_poll */
172 { &vop_kqfilter_desc, spec_kqfilter }, /* spec_kqfilter */
173 { &vop_revoke_desc, spec_revoke }, /* genfs_revoke */
174 { &vop_mmap_desc, spec_mmap }, /* spec_mmap */
175 { &vop_fsync_desc, spec_fsync }, /* vflushbuf */
176 { &vop_seek_desc, spec_seek }, /* genfs_nullop */
177 { &vop_remove_desc, spec_remove }, /* genfs_badop */
178 { &vop_link_desc, spec_link }, /* genfs_badop */
179 { &vop_rename_desc, spec_rename }, /* genfs_badop */
180 { &vop_mkdir_desc, spec_mkdir }, /* genfs_badop */
181 { &vop_rmdir_desc, spec_rmdir }, /* genfs_badop */
182 { &vop_symlink_desc, spec_symlink }, /* genfs_badop */
183 { &vop_readdir_desc, spec_readdir }, /* genfs_badop */
184 { &vop_readlink_desc, spec_readlink }, /* genfs_badop */
185 { &vop_abortop_desc, spec_abortop }, /* genfs_badop */
186 { &vop_inactive_desc, puffs_inactive }, /* REAL inactive */
187 { &vop_reclaim_desc, puffs_reclaim }, /* REAL reclaim */
188 { &vop_lock_desc, puffs_lock }, /* REAL lock */
189 { &vop_unlock_desc, puffs_unlock }, /* REAL unlock */
190 { &vop_bmap_desc, spec_bmap }, /* dummy */
191 { &vop_strategy_desc, spec_strategy }, /* dev strategy */
192 { &vop_print_desc, puffs_print }, /* REAL print */
193 { &vop_islocked_desc, puffs_islocked }, /* REAL islocked */
194 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
195 { &vop_advlock_desc, spec_advlock }, /* lf_advlock */
196 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
197 { &vop_getpages_desc, spec_getpages }, /* genfs_getpages */
198 { &vop_putpages_desc, spec_putpages }, /* genfs_putpages */
199 #if 0
200 { &vop_openextattr_desc, _openextattr }, /* openextattr */
201 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
202 { &vop_getextattr_desc, _getextattr }, /* getextattr */
203 { &vop_setextattr_desc, _setextattr }, /* setextattr */
204 { &vop_listextattr_desc, _listextattr }, /* listextattr */
205 { &vop_deleteextattr_desc, _deleteextattr }, /* deleteextattr */
206 #endif
207 { NULL, NULL }
208 };
209 const struct vnodeopv_desc puffs_specop_opv_desc =
210 { &puffs_specop_p, puffs_specop_entries };
211
212
213 int (**puffs_fifoop_p)(void *);
214 const struct vnodeopv_entry_desc puffs_fifoop_entries[] = {
215 { &vop_default_desc, vn_default_error },
216 { &vop_lookup_desc, fifo_lookup }, /* lookup, ENOTDIR */
217 { &vop_create_desc, fifo_create }, /* genfs_badop */
218 { &vop_mknod_desc, fifo_mknod }, /* genfs_badop */
219 { &vop_open_desc, fifo_open }, /* open */
220 { &vop_close_desc, fifo_close }, /* close */
221 { &vop_access_desc, puffs_checkop }, /* access */
222 { &vop_getattr_desc, puffs_checkop }, /* getattr */
223 { &vop_setattr_desc, puffs_checkop }, /* setattr */
224 { &vop_read_desc, puffs_fifo_read }, /* read, update */
225 { &vop_write_desc, puffs_fifo_write }, /* write, update */
226 { &vop_lease_desc, fifo_lease_check }, /* genfs_nullop */
227 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
228 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
229 { &vop_poll_desc, fifo_poll }, /* poll */
230 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
231 { &vop_revoke_desc, fifo_revoke }, /* genfs_revoke */
232 { &vop_mmap_desc, fifo_mmap }, /* genfs_badop */
233 { &vop_fsync_desc, fifo_fsync }, /* genfs_nullop*/
234 { &vop_seek_desc, fifo_seek }, /* genfs_badop */
235 { &vop_remove_desc, fifo_remove }, /* genfs_badop */
236 { &vop_link_desc, fifo_link }, /* genfs_badop */
237 { &vop_rename_desc, fifo_rename }, /* genfs_badop */
238 { &vop_mkdir_desc, fifo_mkdir }, /* genfs_badop */
239 { &vop_rmdir_desc, fifo_rmdir }, /* genfs_badop */
240 { &vop_symlink_desc, fifo_symlink }, /* genfs_badop */
241 { &vop_readdir_desc, fifo_readdir }, /* genfs_badop */
242 { &vop_readlink_desc, fifo_readlink }, /* genfs_badop */
243 { &vop_abortop_desc, fifo_abortop }, /* genfs_badop */
244 { &vop_inactive_desc, puffs_inactive }, /* REAL inactive */
245 { &vop_reclaim_desc, puffs_reclaim }, /* REAL reclaim */
246 { &vop_lock_desc, puffs_lock }, /* REAL lock */
247 { &vop_unlock_desc, puffs_unlock }, /* REAL unlock */
248 { &vop_bmap_desc, fifo_bmap }, /* dummy */
249 { &vop_strategy_desc, fifo_strategy }, /* genfs_badop */
250 { &vop_print_desc, puffs_print }, /* REAL print */
251 { &vop_islocked_desc, puffs_islocked }, /* REAL islocked */
252 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
253 { &vop_advlock_desc, fifo_advlock }, /* genfs_einval */
254 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
255 { &vop_putpages_desc, fifo_putpages }, /* genfs_null_putpages*/
256 #if 0
257 { &vop_openextattr_desc, _openextattr }, /* openextattr */
258 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
259 { &vop_getextattr_desc, _getextattr }, /* getextattr */
260 { &vop_setextattr_desc, _setextattr }, /* setextattr */
261 { &vop_listextattr_desc, _listextattr }, /* listextattr */
262 { &vop_deleteextattr_desc, _deleteextattr }, /* deleteextattr */
263 #endif
264 { NULL, NULL }
265 };
266 const struct vnodeopv_desc puffs_fifoop_opv_desc =
267 { &puffs_fifoop_p, puffs_fifoop_entries };
268
269
270 /* "real" vnode operations */
271 int (**puffs_msgop_p)(void *);
272 const struct vnodeopv_entry_desc puffs_msgop_entries[] = {
273 { &vop_default_desc, vn_default_error },
274 { &vop_create_desc, puffs_create }, /* create */
275 { &vop_mknod_desc, puffs_mknod }, /* mknod */
276 { &vop_open_desc, puffs_open }, /* open */
277 { &vop_close_desc, puffs_close }, /* close */
278 { &vop_access_desc, puffs_access }, /* access */
279 { &vop_getattr_desc, puffs_getattr }, /* getattr */
280 { &vop_setattr_desc, puffs_setattr }, /* setattr */
281 { &vop_read_desc, puffs_read }, /* read */
282 { &vop_write_desc, puffs_write }, /* write */
283 { &vop_seek_desc, puffs_seek }, /* seek */
284 { &vop_remove_desc, puffs_remove }, /* remove */
285 { &vop_link_desc, puffs_link }, /* link */
286 { &vop_rename_desc, puffs_rename }, /* rename */
287 { &vop_mkdir_desc, puffs_mkdir }, /* mkdir */
288 { &vop_rmdir_desc, puffs_rmdir }, /* rmdir */
289 { &vop_symlink_desc, puffs_symlink }, /* symlink */
290 { &vop_readdir_desc, puffs_readdir }, /* readdir */
291 { &vop_readlink_desc, puffs_readlink }, /* readlink */
292 { &vop_print_desc, puffs_print }, /* print */
293 { &vop_islocked_desc, puffs_islocked }, /* islocked */
294 { &vop_pathconf_desc, puffs_pathconf }, /* pathconf */
295 { &vop_advlock_desc, puffs_advlock }, /* advlock */
296 { &vop_getpages_desc, puffs_getpages }, /* getpages */
297 { NULL, NULL }
298 };
299 const struct vnodeopv_desc puffs_msgop_opv_desc =
300 { &puffs_msgop_p, puffs_msgop_entries };
301
302
303 #define ERROUT(err) \
304 do { \
305 error = err; \
306 goto out; \
307 } while (/*CONSTCOND*/0)
308
309 /*
310 * This is a generic vnode operation handler. It checks if the necessary
311 * operations for the called vnode operation are implemented by userspace
312 * and either returns a dummy return value or proceeds to call the real
313 * vnode operation from puffs_msgop_v.
314 *
315 * XXX: this should described elsewhere and autogenerated, the complexity
316 * of the vnode operations vectors and their interrelationships is also
317 * getting a bit out of hand. Another problem is that we need this same
318 * information in the fs server code, so keeping the two in sync manually
319 * is not a viable (long term) plan.
320 */
321
322 /* not supported, handle locking protocol */
323 #define CHECKOP_NOTSUPP(op) \
324 case VOP_##op##_DESCOFFSET: \
325 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
326 return genfs_eopnotsupp(v); \
327 break
328
329 /* always succeed, no locking */
330 #define CHECKOP_SUCCESS(op) \
331 case VOP_##op##_DESCOFFSET: \
332 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
333 return 0; \
334 break
335
336 int
337 puffs_checkop(void *v)
338 {
339 struct vop_generic_args /* {
340 struct vnodeop_desc *a_desc;
341 spooky mystery contents;
342 } */ *ap = v;
343 struct vnodeop_desc *desc = ap->a_desc;
344 struct puffs_mount *pmp;
345 struct vnode *vp;
346 int offset, rv;
347
348 offset = ap->a_desc->vdesc_vp_offsets[0];
349 #ifdef DIAGNOSTIC
350 if (offset == VDESC_NO_OFFSET)
351 panic("puffs_checkop: no vnode, why did you call me?");
352 #endif
353 vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
354 pmp = MPTOPUFFSMP(vp->v_mount);
355
356 DPRINTF_VERBOSE(("checkop call %s (%d), vp %p\n",
357 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp));
358
359 if (!ALLOPS(pmp)) {
360 switch (desc->vdesc_offset) {
361 CHECKOP_NOTSUPP(CREATE);
362 CHECKOP_NOTSUPP(MKNOD);
363 CHECKOP_NOTSUPP(GETATTR);
364 CHECKOP_NOTSUPP(SETATTR);
365 CHECKOP_NOTSUPP(READ);
366 CHECKOP_NOTSUPP(WRITE);
367 CHECKOP_NOTSUPP(FCNTL);
368 CHECKOP_NOTSUPP(IOCTL);
369 CHECKOP_NOTSUPP(REMOVE);
370 CHECKOP_NOTSUPP(LINK);
371 CHECKOP_NOTSUPP(RENAME);
372 CHECKOP_NOTSUPP(MKDIR);
373 CHECKOP_NOTSUPP(RMDIR);
374 CHECKOP_NOTSUPP(SYMLINK);
375 CHECKOP_NOTSUPP(READDIR);
376 CHECKOP_NOTSUPP(READLINK);
377 CHECKOP_NOTSUPP(PRINT);
378 CHECKOP_NOTSUPP(PATHCONF);
379 CHECKOP_NOTSUPP(ADVLOCK);
380
381 CHECKOP_SUCCESS(ACCESS);
382 CHECKOP_SUCCESS(CLOSE);
383 CHECKOP_SUCCESS(SEEK);
384
385 case VOP_GETPAGES_DESCOFFSET:
386 if (!EXISTSOP(pmp, READ))
387 return genfs_eopnotsupp(v);
388 break;
389
390 default:
391 panic("puffs_checkop: unhandled vnop %d",
392 desc->vdesc_offset);
393 }
394 }
395
396 rv = VOCALL(puffs_msgop_p, ap->a_desc->vdesc_offset, v);
397
398 DPRINTF_VERBOSE(("checkop return %s (%d), vp %p: %d\n",
399 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp, rv));
400
401 return rv;
402 }
403
404 static int puffs_callremove(struct puffs_mount *, void *, void *,
405 struct componentname *);
406 static int puffs_callrmdir(struct puffs_mount *, void *, void *,
407 struct componentname *);
408 static void puffs_callinactive(struct puffs_mount *, void *, int, struct lwp *);
409 static void puffs_callreclaim(struct puffs_mount *, void *, struct lwp *);
410
411 #define PUFFS_ABORT_LOOKUP 1
412 #define PUFFS_ABORT_CREATE 2
413 #define PUFFS_ABORT_MKNOD 3
414 #define PUFFS_ABORT_MKDIR 4
415 #define PUFFS_ABORT_SYMLINK 5
416
417 /*
418 * Press the pani^Wabort button! Kernel resource allocation failed.
419 */
420 static void
421 puffs_abortbutton(struct puffs_mount *pmp, int what,
422 void *dcookie, void *cookie, struct componentname *cnp)
423 {
424
425 switch (what) {
426 case PUFFS_ABORT_CREATE:
427 case PUFFS_ABORT_MKNOD:
428 case PUFFS_ABORT_SYMLINK:
429 puffs_callremove(pmp, dcookie, cookie, cnp);
430 break;
431 case PUFFS_ABORT_MKDIR:
432 puffs_callrmdir(pmp, dcookie, cookie, cnp);
433 break;
434 }
435
436 puffs_callinactive(pmp, cookie, 0, cnp->cn_lwp);
437 puffs_callreclaim(pmp, cookie, cnp->cn_lwp);
438 }
439
440 int
441 puffs_lookup(void *v)
442 {
443 struct vop_lookup_args /* {
444 const struct vnodeop_desc *a_desc;
445 struct vnode *a_dvp;
446 struct vnode **a_vpp;
447 struct componentname *a_cnp;
448 } */ *ap = v;
449 PUFFS_MSG_VARS(vn, lookup);
450 struct puffs_mount *pmp;
451 struct componentname *cnp;
452 struct vnode *vp, *dvp;
453 struct puffs_node *dpn;
454 int isdot;
455 int error;
456
457 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
458 cnp = ap->a_cnp;
459 dvp = ap->a_dvp;
460 *ap->a_vpp = NULL;
461
462 /* r/o fs? we check create later to handle EEXIST */
463 if ((cnp->cn_flags & ISLASTCN)
464 && (dvp->v_mount->mnt_flag & MNT_RDONLY)
465 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
466 return EROFS;
467
468 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
469
470 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n",
471 cnp->cn_nameptr, dvp, cnp->cn_nameiop));
472
473 /*
474 * Check if someone fed it into the cache
475 */
476 if (PUFFS_USE_NAMECACHE(pmp)) {
477 error = cache_lookup(dvp, ap->a_vpp, cnp);
478
479 if (error >= 0)
480 return error;
481 }
482
483 if (isdot) {
484 vp = ap->a_dvp;
485 vref(vp);
486 *ap->a_vpp = vp;
487 return 0;
488 }
489
490 PUFFS_MSG_ALLOC(vn, lookup);
491 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
492 &lookup_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
493
494 if (cnp->cn_flags & ISDOTDOT)
495 VOP_UNLOCK(dvp, 0);
496
497 error = puffs_msg_vn(pmp, park_lookup, 0, PUFFS_VN_LOOKUP, dvp, NULL);
498 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
499
500 /*
501 * In case of error, there is no new vnode to play with, so be
502 * happy with the NULL value given to vpp in the beginning.
503 * Also, check if this really was an error or the target was not
504 * present. Either treat it as a non-error for CREATE/RENAME or
505 * enter the component into the negative name cache (if desired).
506 */
507 if (error) {
508 error = checkerr(pmp, error, __func__);
509 if (error == ENOENT) {
510 /* don't allow to create files on r/o fs */
511 if ((dvp->v_mount->mnt_flag & MNT_RDONLY)
512 && cnp->cn_nameiop == CREATE) {
513 error = EROFS;
514
515 /* adjust values if we are creating */
516 } else if ((cnp->cn_flags & ISLASTCN)
517 && (cnp->cn_nameiop == CREATE
518 || cnp->cn_nameiop == RENAME)) {
519 cnp->cn_flags |= SAVENAME;
520 error = EJUSTRETURN;
521
522 /* save negative cache entry */
523 } else {
524 if ((cnp->cn_flags & MAKEENTRY)
525 && PUFFS_USE_NAMECACHE(pmp))
526 cache_enter(dvp, NULL, cnp);
527 }
528 }
529 goto out;
530 }
531
532 /*
533 * Check that we don't get our parent node back, that would cause
534 * a pretty obvious deadlock.
535 */
536 dpn = dvp->v_data;
537 if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
538 puffs_msg_errnotify(pmp, PUFFS_ERR_LOOKUP, EINVAL,
539 "lookup produced parent cookie", lookup_msg->pvnr_newnode);
540 error = EPROTO;
541 goto out;
542 }
543
544 error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, 1, &vp);
545 if (error == PUFFS_NOSUCHCOOKIE) {
546 error = puffs_getvnode(dvp->v_mount,
547 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
548 lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp);
549 if (error) {
550 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
551 lookup_msg->pvnr_newnode, ap->a_cnp);
552 goto out;
553 }
554 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
555 } else if (error) {
556 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
557 lookup_msg->pvnr_newnode, ap->a_cnp);
558 goto out;
559 }
560
561 *ap->a_vpp = vp;
562
563 if ((cnp->cn_flags & MAKEENTRY) != 0 && PUFFS_USE_NAMECACHE(pmp))
564 cache_enter(dvp, vp, cnp);
565
566 /* XXX */
567 if ((lookup_msg->pvnr_cn.pkcn_flags & REQUIREDIR) == 0)
568 cnp->cn_flags &= ~REQUIREDIR;
569 if (lookup_msg->pvnr_cn.pkcn_consume)
570 cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume,
571 strlen(cnp->cn_nameptr) - cnp->cn_namelen);
572
573 out:
574 if (cnp->cn_flags & ISDOTDOT)
575 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
576
577 DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp));
578 PUFFS_MSG_RELEASE(lookup);
579 return error;
580 }
581
582 int
583 puffs_create(void *v)
584 {
585 struct vop_create_args /* {
586 const struct vnodeop_desc *a_desc;
587 struct vnode *a_dvp;
588 struct vnode **a_vpp;
589 struct componentname *a_cnp;
590 struct vattr *a_vap;
591 } */ *ap = v;
592 PUFFS_MSG_VARS(vn, create);
593 struct vnode *dvp = ap->a_dvp;
594 struct componentname *cnp = ap->a_cnp;
595 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
596 int error;
597
598 DPRINTF(("puffs_create: dvp %p, cnp: %s\n",
599 dvp, ap->a_cnp->cn_nameptr));
600
601 PUFFS_MSG_ALLOC(vn, create);
602 puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred,
603 &create_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
604 create_msg->pvnr_va = *ap->a_vap;
605
606 error = puffs_msg_vn(pmp, park_create, PUFFS_VN_CREATE, 0, dvp, NULL);
607 error = checkerr(pmp, error, __func__);
608 if (error)
609 goto out;
610
611 error = puffs_newnode(dvp->v_mount, dvp, ap->a_vpp,
612 create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0);
613 if (error)
614 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, VPTOPNC(dvp),
615 create_msg->pvnr_newnode, cnp);
616
617 out:
618 if (error || (cnp->cn_flags & SAVESTART) == 0)
619 PNBUF_PUT(cnp->cn_pnbuf);
620 vput(dvp);
621
622 DPRINTF(("puffs_create: return %d\n", error));
623 PUFFS_MSG_RELEASE(create);
624 return error;
625 }
626
627 int
628 puffs_mknod(void *v)
629 {
630 struct vop_mknod_args /* {
631 const struct vnodeop_desc *a_desc;
632 struct vnode *a_dvp;
633 struct vnode **a_vpp;
634 struct componentname *a_cnp;
635 struct vattr *a_vap;
636 } */ *ap = v;
637 PUFFS_MSG_VARS(vn, mknod);
638 struct vnode *dvp = ap->a_dvp;
639 struct componentname *cnp = ap->a_cnp;
640 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
641 int error;
642
643 PUFFS_MSG_ALLOC(vn, mknod);
644 puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
645 &mknod_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
646 mknod_msg->pvnr_va = *ap->a_vap;
647
648 error = puffs_msg_vn(pmp, park_mknod, PUFFS_VN_MKNOD, 0, dvp, NULL);
649 error = checkerr(pmp, error, __func__);
650 if (error)
651 goto out;
652
653 error = puffs_newnode(dvp->v_mount, dvp, ap->a_vpp,
654 mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type,
655 ap->a_vap->va_rdev);
656 if (error)
657 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, VPTOPNC(dvp),
658 mknod_msg->pvnr_newnode, cnp);
659
660 out:
661 PUFFS_MSG_RELEASE(mknod);
662 if (error || (cnp->cn_flags & SAVESTART) == 0)
663 PNBUF_PUT(cnp->cn_pnbuf);
664 vput(dvp);
665 return error;
666 }
667
668 int
669 puffs_open(void *v)
670 {
671 struct vop_open_args /* {
672 const struct vnodeop_desc *a_desc;
673 struct vnode *a_vp;
674 int a_mode;
675 kauth_cred_t a_cred;
676 struct lwp *a_l;
677 } */ *ap = v;
678 PUFFS_MSG_VARS(vn, open);
679 struct vnode *vp = ap->a_vp;
680 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
681 int mode = ap->a_mode;
682 int error;
683
684 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
685
686 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
687 ERROUT(EROFS);
688
689 if (!EXISTSOP(pmp, OPEN))
690 ERROUT(0);
691
692 PUFFS_MSG_ALLOC(vn, open);
693 open_msg->pvnr_mode = mode;
694 puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
695 puffs_cidcvt(&open_msg->pvnr_cid, ap->a_l);
696
697 error = puffs_msg_vn(pmp, park_open, PUFFS_VN_OPEN, 0, vp, NULL);
698 error = checkerr(pmp, error, __func__);
699
700 out:
701 DPRINTF(("puffs_open: returning %d\n", error));
702 PUFFS_MSG_RELEASE(open);
703 return error;
704 }
705
706 int
707 puffs_close(void *v)
708 {
709 struct vop_close_args /* {
710 const struct vnodeop_desc *a_desc;
711 struct vnode *a_vp;
712 int a_fflag;
713 kauth_cred_t a_cred;
714 struct lwp *a_l;
715 } */ *ap = v;
716 PUFFS_MSG_VARS(vn, close);
717 struct vnode *vp = ap->a_vp;
718 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
719
720 PUFFS_MSG_ALLOC(vn, close);
721 puffs_msg_setfaf(park_close);
722 close_msg->pvnr_fflag = ap->a_fflag;
723 puffs_credcvt(&close_msg->pvnr_cred, ap->a_cred);
724 puffs_cidcvt(&close_msg->pvnr_cid, ap->a_l);
725
726 puffs_msg_vn(pmp, park_close, PUFFS_VN_CLOSE, 0, vp, NULL);
727
728 PUFFS_MSG_RELEASE(close);
729 return 0;
730 }
731
732 int
733 puffs_access(void *v)
734 {
735 struct vop_access_args /* {
736 const struct vnodeop_desc *a_desc;
737 struct vnode *a_vp;
738 int a_mode;
739 kauth_cred_t a_cred;
740 struct lwp *a_l;
741 } */ *ap = v;
742 PUFFS_MSG_VARS(vn, access);
743 struct vnode *vp = ap->a_vp;
744 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
745 int mode = ap->a_mode;
746 int error;
747
748 if (mode & VWRITE) {
749 switch (vp->v_type) {
750 case VDIR:
751 case VLNK:
752 case VREG:
753 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
754 || !EXISTSOP(pmp, WRITE))
755 return EROFS;
756 break;
757 default:
758 break;
759 }
760 }
761
762 if (!EXISTSOP(pmp, ACCESS))
763 return 0;
764
765 PUFFS_MSG_ALLOC(vn, access);
766 access_msg->pvnr_mode = ap->a_mode;
767 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
768 puffs_cidcvt(&access_msg->pvnr_cid, ap->a_l);
769
770 error = puffs_msg_vn(pmp, park_access, PUFFS_VN_ACCESS, 0, vp, NULL);
771 error = checkerr(pmp, error, __func__);
772 PUFFS_MSG_RELEASE(access);
773
774 return error;
775 }
776
777 int
778 puffs_getattr(void *v)
779 {
780 struct vop_getattr_args /* {
781 const struct vnodeop_desc *a_desc;
782 struct vnode *a_vp;
783 struct vattr *a_vap;
784 kauth_cred_t a_cred;
785 struct lwp *a_l;
786 } */ *ap = v;
787 PUFFS_MSG_VARS(vn, getattr);
788 struct vnode *vp = ap->a_vp;
789 struct mount *mp = vp->v_mount;
790 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
791 struct vattr *vap, *rvap;
792 struct puffs_node *pn;
793 int error = 0;
794
795 vap = ap->a_vap;
796
797 PUFFS_MSG_ALLOC(vn, getattr);
798 vattr_null(&getattr_msg->pvnr_va);
799 puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred);
800 puffs_cidcvt(&getattr_msg->pvnr_cid, ap->a_l);
801
802 error = puffs_msg_vn(pmp, park_getattr, PUFFS_VN_GETATTR, 0, vp, NULL);
803 error = checkerr(pmp, error, __func__);
804 if (error)
805 goto out;
806
807 rvap = &getattr_msg->pvnr_va;
808 /*
809 * Don't listen to the file server regarding special device
810 * size info, the file server doesn't know anything about them.
811 */
812 if (vp->v_type == VBLK || vp->v_type == VCHR)
813 rvap->va_size = vp->v_size;
814
815 /* Ditto for blocksize (ufs comment: this doesn't belong here) */
816 if (vp->v_type == VBLK)
817 rvap->va_blocksize = BLKDEV_IOSIZE;
818 else if (vp->v_type == VCHR)
819 rvap->va_blocksize = MAXBSIZE;
820
821 (void) memcpy(vap, rvap, sizeof(struct vattr));
822 vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
823
824 pn = VPTOPP(vp);
825 if (pn->pn_stat & PNODE_METACACHE_ATIME)
826 vap->va_atime = pn->pn_mc_atime;
827 if (pn->pn_stat & PNODE_METACACHE_CTIME)
828 vap->va_ctime = pn->pn_mc_ctime;
829 if (pn->pn_stat & PNODE_METACACHE_MTIME)
830 vap->va_mtime = pn->pn_mc_mtime;
831 if (pn->pn_stat & PNODE_METACACHE_SIZE) {
832 vap->va_size = pn->pn_mc_size;
833 } else {
834 if (rvap->va_size != VNOVAL
835 && vp->v_type != VBLK && vp->v_type != VCHR) {
836 uvm_vnp_setsize(vp, rvap->va_size);
837 pn->pn_serversize = rvap->va_size;
838 }
839 }
840
841 out:
842 PUFFS_MSG_RELEASE(getattr);
843 return error;
844 }
845
846 static int
847 puffs_dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred,
848 struct lwp *l, int chsize)
849 {
850 PUFFS_MSG_VARS(vn, setattr);
851 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
852 struct puffs_node *pn = vp->v_data;
853 int error;
854
855 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
856 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
857 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
858 || vap->va_mode != (mode_t)VNOVAL))
859 return EROFS;
860
861 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
862 && vp->v_type == VREG && vap->va_size != VNOVAL)
863 return EROFS;
864
865 /*
866 * Flush metacache first. If we are called with some explicit
867 * parameters, treat them as information overriding metacache
868 * information.
869 */
870 if (pn->pn_stat & PNODE_METACACHE_MASK) {
871 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
872 && vap->va_atime.tv_sec == VNOVAL)
873 vap->va_atime = pn->pn_mc_atime;
874 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
875 && vap->va_ctime.tv_sec == VNOVAL)
876 vap->va_ctime = pn->pn_mc_ctime;
877 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
878 && vap->va_mtime.tv_sec == VNOVAL)
879 vap->va_mtime = pn->pn_mc_mtime;
880 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
881 && vap->va_size == VNOVAL)
882 vap->va_size = pn->pn_mc_size;
883
884 pn->pn_stat &= ~PNODE_METACACHE_MASK;
885 }
886
887 PUFFS_MSG_ALLOC(vn, setattr);
888 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
889 puffs_credcvt(&setattr_msg->pvnr_cred, cred);
890 puffs_cidcvt(&setattr_msg->pvnr_cid, l);
891
892 error = puffs_msg_vn(pmp, park_setattr, PUFFS_VN_SETATTR, 0, vp, NULL);
893 PUFFS_MSG_RELEASE(setattr);
894
895 error = checkerr(pmp, error, __func__);
896 if (error)
897 return error;
898
899 if (vap->va_size != VNOVAL) {
900 pn->pn_serversize = vap->va_size;
901 if (chsize)
902 uvm_vnp_setsize(vp, vap->va_size);
903 }
904
905 return 0;
906 }
907
908 int
909 puffs_setattr(void *v)
910 {
911 struct vop_getattr_args /* {
912 const struct vnodeop_desc *a_desc;
913 struct vnode *a_vp;
914 struct vattr *a_vap;
915 kauth_cred_t a_cred;
916 struct lwp *a_l;
917 } */ *ap = v;
918
919 return puffs_dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, ap->a_l, 1);
920 }
921
922 static __inline int
923 doinact(struct puffs_mount *pmp, int iaflag)
924 {
925
926 if (EXISTSOP(pmp, INACTIVE))
927 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
928 if (iaflag || ALLOPS(pmp))
929 return 1;
930 else
931 return 0;
932 else
933 return 1;
934 else
935 return 0;
936 }
937
938 static void
939 puffs_callinactive(struct puffs_mount *pmp, void *cookie, int iaflag,
940 struct lwp *l)
941 {
942 PUFFS_MSG_VARS(vn, inactive);
943
944 if (doinact(pmp, iaflag)) {
945 struct puffs_req *preq;
946
947 PUFFS_MSG_ALLOC(vn, inactive);
948 puffs_cidcvt(&inactive_msg->pvnr_cid, l);
949 preq = (struct puffs_req *)inactive_msg;
950 preq->preq_cookie = cookie;
951 preq->preq_opclass = PUFFSOP_VN;
952 preq->preq_optype = PUFFS_VN_INACTIVE;
953
954 puffs_msg_raw(pmp, park_inactive);
955 PUFFS_MSG_RELEASE(inactive);
956 }
957 }
958
959 /* XXX: callinactive can't setback */
960 int
961 puffs_inactive(void *v)
962 {
963 struct vop_inactive_args /* {
964 const struct vnodeop_desc *a_desc;
965 struct vnode *a_vp;
966 struct lwp *a_l;
967 } */ *ap = v;
968 PUFFS_MSG_VARS(vn, inactive);
969 struct vnode *vp = ap->a_vp;
970 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
971 struct puffs_node *pnode;
972
973 pnode = vp->v_data;
974
975 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
976 PUFFS_MSG_ALLOC(vn, inactive);
977 puffs_cidcvt(&inactive_msg->pvnr_cid, ap->a_l);
978 puffs_msg_vn(pmp, park_inactive, PUFFS_VN_INACTIVE, 0, vp,NULL);
979 PUFFS_MSG_RELEASE(inactive);
980 }
981 pnode->pn_stat &= ~PNODE_DOINACT;
982
983 VOP_UNLOCK(vp, 0);
984
985 /*
986 * file server thinks it's gone? then don't be afraid care,
987 * node's life was already all it would ever be
988 */
989 if (pnode->pn_stat & PNODE_NOREFS) {
990 pnode->pn_stat |= PNODE_DYING;
991 vrecycle(vp, NULL, ap->a_l);
992 }
993
994 return 0;
995 }
996
997 static void
998 puffs_callreclaim(struct puffs_mount *pmp, void *cookie, struct lwp *l)
999 {
1000 PUFFS_MSG_VARS(vn, reclaim);
1001 struct puffs_req *preq;
1002
1003 if (!EXISTSOP(pmp, RECLAIM))
1004 return;
1005
1006 PUFFS_MSG_ALLOC(vn, reclaim);
1007 puffs_msg_setfaf(park_reclaim);
1008 puffs_cidcvt(&reclaim_msg->pvnr_cid, l);
1009
1010 preq = (struct puffs_req *)reclaim_msg;
1011 preq->preq_cookie = cookie;
1012 preq->preq_opclass = PUFFSOP_VN;
1013 preq->preq_optype = PUFFS_VN_RECLAIM;
1014
1015 puffs_msg_raw(pmp, park_reclaim);
1016 PUFFS_MSG_RELEASE(reclaim);
1017 }
1018
1019 /*
1020 * always FAF, we don't really care if the server wants to fail to
1021 * reclaim the node or not
1022 */
1023 int
1024 puffs_reclaim(void *v)
1025 {
1026 struct vop_reclaim_args /* {
1027 const struct vnodeop_desc *a_desc;
1028 struct vnode *a_vp;
1029 struct lwp *a_l;
1030 } */ *ap = v;
1031 struct vnode *vp = ap->a_vp;
1032 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1033
1034 /*
1035 * first things first: check if someone is trying to reclaim the
1036 * root vnode. do not allow that to travel to userspace.
1037 * Note that we don't need to take the lock similarly to
1038 * puffs_root(), since there is only one of us.
1039 */
1040 if (vp->v_vflag & VV_ROOT) {
1041 mutex_enter(&pmp->pmp_lock);
1042 KASSERT(pmp->pmp_root != NULL);
1043 pmp->pmp_root = NULL;
1044 mutex_exit(&pmp->pmp_lock);
1045 goto out;
1046 }
1047
1048 puffs_callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp), ap->a_l);
1049
1050 out:
1051 if (PUFFS_USE_NAMECACHE(pmp))
1052 cache_purge(vp);
1053 puffs_putvnode(vp);
1054
1055 return 0;
1056 }
1057
1058 #define CSIZE sizeof(**ap->a_cookies)
1059 int
1060 puffs_readdir(void *v)
1061 {
1062 struct vop_readdir_args /* {
1063 const struct vnodeop_desc *a_desc;
1064 struct vnode *a_vp;
1065 struct uio *a_uio;
1066 kauth_cred_t a_cred;
1067 int *a_eofflag;
1068 off_t **a_cookies;
1069 int *a_ncookies;
1070 } */ *ap = v;
1071 PUFFS_MSG_VARS(vn, readdir);
1072 struct vnode *vp = ap->a_vp;
1073 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1074 size_t argsize, tomove, cookiemem, cookiesmax;
1075 struct uio *uio = ap->a_uio;
1076 size_t howmuch, resid;
1077 int error;
1078
1079 /*
1080 * ok, so we need: resid + cookiemem = maxreq
1081 * => resid + cookiesize * (resid/minsize) = maxreq
1082 * => resid + cookiesize/minsize * resid = maxreq
1083 * => (cookiesize/minsize + 1) * resid = maxreq
1084 * => resid = maxreq / (cookiesize/minsize + 1)
1085 *
1086 * Since cookiesize <= minsize and we're not very big on floats,
1087 * we approximate that to be 1. Therefore:
1088 *
1089 * resid = maxreq / 2;
1090 *
1091 * Well, at least we didn't have to use differential equations
1092 * or the Gram-Schmidt process.
1093 *
1094 * (yes, I'm very afraid of this)
1095 */
1096 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1097
1098 if (ap->a_cookies) {
1099 KASSERT(ap->a_ncookies != NULL);
1100 if (pmp->pmp_args.pa_fhsize == 0)
1101 return EOPNOTSUPP;
1102 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1103 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1104 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1105 } else {
1106 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1107 cookiesmax = 0;
1108 cookiemem = 0;
1109 }
1110
1111 argsize = sizeof(struct puffs_vnmsg_readdir);
1112 tomove = resid + cookiemem;
1113 puffs_msgmem_alloc(argsize + tomove, &park_readdir,
1114 (void **)&readdir_msg, 1);
1115
1116 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
1117 readdir_msg->pvnr_offset = uio->uio_offset;
1118 readdir_msg->pvnr_resid = resid;
1119 readdir_msg->pvnr_ncookies = cookiesmax;
1120 readdir_msg->pvnr_eofflag = 0;
1121 readdir_msg->pvnr_dentoff = cookiemem;
1122
1123 error = puffs_msg_vn(pmp, park_readdir, PUFFS_VN_READDIR,
1124 0, vp, NULL);
1125 error = checkerr(pmp, error, __func__);
1126 if (error)
1127 goto out;
1128
1129 /* userspace is cheating? */
1130 if (readdir_msg->pvnr_resid > resid) {
1131 puffs_msg_errnotify(pmp, PUFFS_ERR_READDIR, E2BIG,
1132 "resid grew", VPTOPNC(vp));
1133 ERROUT(EPROTO);
1134 }
1135 if (readdir_msg->pvnr_ncookies > cookiesmax) {
1136 puffs_msg_errnotify(pmp, PUFFS_ERR_READDIR, E2BIG,
1137 "too many cookies", VPTOPNC(vp));
1138 ERROUT(EPROTO);
1139 }
1140
1141 /* check eof */
1142 if (readdir_msg->pvnr_eofflag)
1143 *ap->a_eofflag = 1;
1144
1145 /* bouncy-wouncy with the directory data */
1146 howmuch = resid - readdir_msg->pvnr_resid;
1147
1148 /* force eof if no data was returned (getcwd() needs this) */
1149 if (howmuch == 0) {
1150 *ap->a_eofflag = 1;
1151 goto out;
1152 }
1153
1154 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
1155 if (error)
1156 goto out;
1157
1158 /* provide cookies to caller if so desired */
1159 if (ap->a_cookies) {
1160 *ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE,
1161 M_TEMP, M_WAITOK);
1162 *ap->a_ncookies = readdir_msg->pvnr_ncookies;
1163 memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
1164 *ap->a_ncookies*CSIZE);
1165 }
1166
1167 /* next readdir starts here */
1168 uio->uio_offset = readdir_msg->pvnr_offset;
1169
1170 out:
1171 puffs_msgmem_release(park_readdir);
1172 return error;
1173 }
1174 #undef CSIZE
1175
1176 /*
1177 * poll works by consuming the bitmask in pn_revents. If there are
1178 * events available, poll returns immediately. If not, it issues a
1179 * poll to userspace, selrecords itself and returns with no available
1180 * events. When the file server returns, it executes puffs_parkdone_poll(),
1181 * where available events are added to the bitmask. selnotify() is
1182 * then also executed by that function causing us to enter here again
1183 * and hopefully find the missing bits (unless someone got them first,
1184 * in which case it starts all over again).
1185 */
1186 int
1187 puffs_poll(void *v)
1188 {
1189 struct vop_poll_args /* {
1190 const struct vnodeop_desc *a_desc;
1191 struct vnode *a_vp;
1192 int a_events;
1193 struct lwp *a_l;
1194 }*/ *ap = v;
1195 PUFFS_MSG_VARS(vn, poll);
1196 struct vnode *vp = ap->a_vp;
1197 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1198 struct puffs_node *pn = vp->v_data;
1199 int events;
1200
1201 if (EXISTSOP(pmp, POLL)) {
1202 mutex_enter(&pn->pn_mtx);
1203 events = pn->pn_revents & ap->a_events;
1204 if (events & ap->a_events) {
1205 pn->pn_revents &= ~ap->a_events;
1206 mutex_exit(&pn->pn_mtx);
1207
1208 return events;
1209 } else {
1210 puffs_referencenode(pn);
1211 mutex_exit(&pn->pn_mtx);
1212
1213 PUFFS_MSG_ALLOC(vn, poll);
1214 poll_msg->pvnr_events = ap->a_events;
1215 puffs_cidcvt(&poll_msg->pvnr_cid, ap->a_l);
1216
1217 selrecord(ap->a_l, &pn->pn_sel);
1218 puffs_msg_vncall(pmp, park_poll, PUFFS_VN_POLL, 0,
1219 puffs_parkdone_poll, pn, vp);
1220 PUFFS_MSG_RELEASE(poll);
1221
1222 return 0;
1223 }
1224 } else {
1225 return genfs_poll(v);
1226 }
1227 }
1228
1229 int
1230 puffs_fsync(void *v)
1231 {
1232 struct vop_fsync_args /* {
1233 const struct vnodeop_desc *a_desc;
1234 struct vnode *a_vp;
1235 kauth_cred_t a_cred;
1236 int a_flags;
1237 off_t a_offlo;
1238 off_t a_offhi;
1239 struct lwp *a_l;
1240 } */ *ap = v;
1241 PUFFS_MSG_VARS(vn, fsync);
1242 struct vnode *vp = ap->a_vp;
1243 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1244 struct puffs_node *pn;
1245 struct vattr va;
1246 int pflags, error, dofaf;
1247
1248 pn = VPTOPP(vp);
1249
1250 /* flush out information from our metacache, see vop_setattr */
1251 if (pn->pn_stat & PNODE_METACACHE_MASK
1252 && (pn->pn_stat & PNODE_DYING) == 0) {
1253 vattr_null(&va);
1254 error = VOP_SETATTR(vp, &va, FSCRED, NULL);
1255 if (error)
1256 return error;
1257 }
1258
1259 /*
1260 * flush pages to avoid being overly dirty
1261 */
1262 pflags = PGO_CLEANIT;
1263 if (ap->a_flags & FSYNC_WAIT)
1264 pflags |= PGO_SYNCIO;
1265 simple_lock(&vp->v_interlock);
1266 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
1267 round_page(ap->a_offhi), pflags);
1268 if (error)
1269 return error;
1270
1271 /*
1272 * HELLO! We exit already here if the user server does not
1273 * support fsync OR if we should call fsync for a node which
1274 * has references neither in the kernel or the fs server.
1275 * Otherwise we continue to issue fsync() forward.
1276 */
1277 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1278 return 0;
1279
1280 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1281 /*
1282 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1283 * only FAFs for those. Otherwise there's a danger of deadlock,
1284 * since the execution context here might be the user server
1285 * doing some operation on another fs, which in turn caused a
1286 * vnode to be reclaimed from the freelist for this fs.
1287 */
1288 if (dofaf == 0) {
1289 simple_lock(&vp->v_interlock);
1290 if (vp->v_iflag & VI_XLOCK)
1291 dofaf = 1;
1292 simple_unlock(&vp->v_interlock);
1293 }
1294
1295 PUFFS_MSG_ALLOC(vn, fsync);
1296 if (dofaf)
1297 puffs_msg_setfaf(park_fsync);
1298
1299 puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred);
1300 fsync_msg->pvnr_flags = ap->a_flags;
1301 fsync_msg->pvnr_offlo = ap->a_offlo;
1302 fsync_msg->pvnr_offhi = ap->a_offhi;
1303 puffs_cidcvt(&fsync_msg->pvnr_cid, ap->a_l);
1304
1305 error = puffs_msg_vn(pmp, park_fsync, PUFFS_VN_FSYNC, 0, vp, NULL);
1306 PUFFS_MSG_RELEASE(fsync);
1307
1308 error = checkerr(pmp, error, __func__);
1309
1310 return error;
1311 }
1312
1313 int
1314 puffs_seek(void *v)
1315 {
1316 struct vop_seek_args /* {
1317 const struct vnodeop_desc *a_desc;
1318 struct vnode *a_vp;
1319 off_t a_oldoff;
1320 off_t a_newoff;
1321 kauth_cred_t a_cred;
1322 } */ *ap = v;
1323 PUFFS_MSG_VARS(vn, seek);
1324 struct vnode *vp = ap->a_vp;
1325 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1326 int error;
1327
1328 PUFFS_MSG_ALLOC(vn, seek);
1329 seek_msg->pvnr_oldoff = ap->a_oldoff;
1330 seek_msg->pvnr_newoff = ap->a_newoff;
1331 puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred);
1332
1333 error = puffs_msg_vn(pmp, park_seek, PUFFS_VN_SEEK, 0, vp, NULL);
1334 PUFFS_MSG_RELEASE(seek);
1335 return checkerr(pmp, error, __func__);
1336 }
1337
1338 static int
1339 puffs_callremove(struct puffs_mount *pmp, void *dcookie, void *cookie,
1340 struct componentname *cnp)
1341 {
1342 PUFFS_MSG_VARS(vn, remove);
1343 struct puffs_req *preq;
1344 int error;
1345
1346 PUFFS_MSG_ALLOC(vn, remove);
1347 remove_msg->pvnr_cookie_targ = cookie;
1348 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1349 &remove_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1350
1351 /* XXX: uh, this is wrong because we don't get setbacks with raw */
1352 preq = (struct puffs_req *)remove_msg;
1353 preq->preq_cookie = dcookie;
1354 preq->preq_opclass = PUFFSOP_VN;
1355 preq->preq_optype = PUFFS_VN_REMOVE;
1356
1357 error = puffs_msg_raw(pmp, park_remove);
1358 PUFFS_MSG_RELEASE(remove);
1359
1360 return checkerr(pmp, error, __func__);
1361 }
1362
1363 /*
1364 * XXX: can't use callremove now because can't catch setbacks with
1365 * it due to lack of a vnode argument.
1366 */
1367 int
1368 puffs_remove(void *v)
1369 {
1370 struct vop_remove_args /* {
1371 const struct vnodeop_desc *a_desc;
1372 struct vnode *a_dvp;
1373 struct vnode *a_vp;
1374 struct componentname *a_cnp;
1375 } */ *ap = v;
1376 PUFFS_MSG_VARS(vn, remove);
1377 struct vnode *dvp = ap->a_dvp;
1378 struct vnode *vp = ap->a_vp;
1379 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1380 struct componentname *cnp = ap->a_cnp;
1381 int error;
1382
1383 PUFFS_MSG_ALLOC(vn, remove);
1384 remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
1385 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1386 &remove_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1387
1388 error = puffs_msg_vn(pmp, park_remove, PUFFS_VN_REMOVE, 0, dvp, vp);
1389 PUFFS_MSG_RELEASE(remove);
1390
1391 error = checkerr(pmp, error, __func__);
1392 vput(vp);
1393 if (dvp == vp)
1394 vrele(dvp);
1395 else
1396 vput(dvp);
1397
1398 return error;
1399 }
1400
1401 int
1402 puffs_mkdir(void *v)
1403 {
1404 struct vop_mkdir_args /* {
1405 const struct vnodeop_desc *a_desc;
1406 struct vnode *a_dvp;
1407 struct vnode **a_vpp;
1408 struct componentname *a_cnp;
1409 struct vattr *a_vap;
1410 } */ *ap = v;
1411 PUFFS_MSG_VARS(vn, mkdir);
1412 struct vnode *dvp = ap->a_dvp;
1413 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1414 int error;
1415
1416 PUFFS_MSG_ALLOC(vn, mkdir);
1417 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1418 &mkdir_msg->pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1419 mkdir_msg->pvnr_va = *ap->a_vap;
1420
1421 error = puffs_msg_vn(pmp, park_mkdir, PUFFS_VN_MKDIR, 0, dvp, NULL);
1422 error = checkerr(pmp, error, __func__);
1423 if (error)
1424 goto out;
1425
1426 error = puffs_newnode(dvp->v_mount, dvp, ap->a_vpp,
1427 mkdir_msg->pvnr_newnode, ap->a_cnp, VDIR, 0);
1428 if (error)
1429 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, VPTOPNC(ap->a_dvp),
1430 mkdir_msg->pvnr_newnode, ap->a_cnp);
1431
1432 out:
1433 PUFFS_MSG_RELEASE(mkdir);
1434 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
1435 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
1436 vput(ap->a_dvp);
1437 return error;
1438 }
1439
1440 static int
1441 puffs_callrmdir(struct puffs_mount *pmp, void *dcookie, void *cookie,
1442 struct componentname *cnp)
1443 {
1444 PUFFS_MSG_VARS(vn, rmdir);
1445 struct puffs_req *preq;
1446 int error;
1447
1448 PUFFS_MSG_ALLOC(vn, rmdir);
1449 rmdir_msg->pvnr_cookie_targ = cookie;
1450 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1451 &rmdir_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1452
1453 /* XXX: uh, this is wrong because we don't get setbacks with raw */
1454 preq = (struct puffs_req *)rmdir_msg;
1455 preq->preq_cookie = dcookie;
1456 preq->preq_opclass = PUFFSOP_VN;
1457 preq->preq_optype = PUFFS_VN_RMDIR;
1458
1459 error = puffs_msg_raw(pmp, park_rmdir);
1460 PUFFS_MSG_RELEASE(rmdir);
1461
1462 return checkerr(pmp, error, __func__);
1463 }
1464
1465 int
1466 puffs_rmdir(void *v)
1467 {
1468 struct vop_rmdir_args /* {
1469 const struct vnodeop_desc *a_desc;
1470 struct vnode *a_dvp;
1471 struct vnode *a_vp;
1472 struct componentname *a_cnp;
1473 } */ *ap = v;
1474 PUFFS_MSG_VARS(vn, rmdir);
1475 struct vnode *dvp = ap->a_dvp;
1476 struct vnode *vp = ap->a_vp;
1477 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1478 struct componentname *cnp = ap->a_cnp;
1479 int error;
1480
1481 PUFFS_MSG_ALLOC(vn, rmdir);
1482 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1483 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1484 &rmdir_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1485
1486 error = puffs_msg_vn(pmp, park_rmdir, PUFFS_VN_RMDIR, 0, dvp, vp);
1487 PUFFS_MSG_RELEASE(rmdir);
1488
1489 /* XXX: some call cache_purge() *for both vnodes* here, investigate */
1490 vput(dvp);
1491 vput(vp);
1492
1493 return error;
1494 }
1495
1496 int
1497 puffs_link(void *v)
1498 {
1499 struct vop_link_args /* {
1500 const struct vnodeop_desc *a_desc;
1501 struct vnode *a_dvp;
1502 struct vnode *a_vp;
1503 struct componentname *a_cnp;
1504 }*/ *ap = v;
1505 PUFFS_MSG_VARS(vn, link);
1506 struct vnode *dvp = ap->a_dvp;
1507 struct vnode *vp = ap->a_vp;
1508 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1509 int error;
1510
1511 PUFFS_MSG_ALLOC(vn, link);
1512 link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1513 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1514 &link_msg->pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1515
1516 error = puffs_msg_vn(pmp, park_link, PUFFS_VN_LINK, 0, dvp, NULL);
1517 PUFFS_MSG_RELEASE(link);
1518
1519 error = checkerr(pmp, error, __func__);
1520
1521 /*
1522 * XXX: stay in touch with the cache. I don't like this, but
1523 * don't have a better solution either. See also puffs_rename().
1524 */
1525 if (error == 0)
1526 puffs_updatenode(vp, PUFFS_UPDATECTIME);
1527
1528 vput(dvp);
1529
1530 return error;
1531 }
1532
1533 int
1534 puffs_symlink(void *v)
1535 {
1536 struct vop_symlink_args /* {
1537 const struct vnodeop_desc *a_desc;
1538 struct vnode *a_dvp;
1539 struct vnode **a_vpp;
1540 struct componentname *a_cnp;
1541 struct vattr *a_vap;
1542 char *a_target;
1543 }*/ *ap = v;
1544 PUFFS_MSG_VARS(vn, symlink);
1545 struct vnode *dvp = ap->a_dvp;
1546 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1547 int error;
1548
1549 *ap->a_vpp = NULL;
1550
1551 PUFFS_MSG_ALLOC(vn, symlink);
1552 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1553 &symlink_msg->pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1554 symlink_msg->pvnr_va = *ap->a_vap;
1555 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1556 sizeof(symlink_msg->pvnr_link));
1557
1558 error = puffs_msg_vn(pmp, park_symlink, PUFFS_VN_SYMLINK, 0, dvp,NULL);
1559 error = checkerr(pmp, error, __func__);
1560 if (error)
1561 goto out;
1562
1563 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
1564 symlink_msg->pvnr_newnode, ap->a_cnp, VLNK, 0);
1565 if (error)
1566 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, VPTOPNC(ap->a_dvp),
1567 symlink_msg->pvnr_newnode, ap->a_cnp);
1568
1569 out:
1570 PUFFS_MSG_RELEASE(symlink);
1571 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
1572 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
1573 vput(ap->a_dvp);
1574
1575 return error;
1576 }
1577
1578 int
1579 puffs_readlink(void *v)
1580 {
1581 struct vop_readlink_args /* {
1582 const struct vnodeop_desc *a_desc;
1583 struct vnode *a_vp;
1584 struct uio *a_uio;
1585 kauth_cred_t a_cred;
1586 } */ *ap = v;
1587 PUFFS_MSG_VARS(vn, readlink);
1588 struct vnode *vp = ap->a_vp;
1589 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1590 size_t linklen;
1591 int error;
1592
1593 PUFFS_MSG_ALLOC(vn, readlink);
1594 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1595 linklen = sizeof(readlink_msg->pvnr_link);
1596 readlink_msg->pvnr_linklen = linklen;
1597
1598 error = puffs_msg_vn(pmp, park_readlink, PUFFS_VN_READLINK, 0, vp,NULL);
1599 error = checkerr(pmp, error, __func__);
1600 if (error)
1601 goto out;
1602
1603 /* bad bad user file server */
1604 if (readlink_msg->pvnr_linklen > linklen) {
1605 puffs_msg_errnotify(pmp, PUFFS_ERR_READLINK, E2BIG,
1606 "linklen too big", VPTOPNC(ap->a_vp));
1607 error = EPROTO;
1608 goto out;
1609 }
1610
1611 error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
1612 ap->a_uio);
1613 out:
1614 PUFFS_MSG_RELEASE(readlink);
1615 return error;
1616 }
1617
1618 int
1619 puffs_rename(void *v)
1620 {
1621 struct vop_rename_args /* {
1622 const struct vnodeop_desc *a_desc;
1623 struct vnode *a_fdvp;
1624 struct vnode *a_fvp;
1625 struct componentname *a_fcnp;
1626 struct vnode *a_tdvp;
1627 struct vnode *a_tvp;
1628 struct componentname *a_tcnp;
1629 }*/ *ap = v;
1630 PUFFS_MSG_VARS(vn, rename);
1631 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_fdvp->v_mount);
1632 int error;
1633
1634 if (ap->a_fvp->v_mount != ap->a_tdvp->v_mount)
1635 ERROUT(EXDEV);
1636
1637 PUFFS_MSG_ALLOC(vn, rename);
1638 rename_msg->pvnr_cookie_src = VPTOPNC(ap->a_fvp);
1639 rename_msg->pvnr_cookie_targdir = VPTOPNC(ap->a_tdvp);
1640 if (ap->a_tvp)
1641 rename_msg->pvnr_cookie_targ = VPTOPNC(ap->a_tvp);
1642 else
1643 rename_msg->pvnr_cookie_targ = NULL;
1644 puffs_makecn(&rename_msg->pvnr_cn_src,
1645 &rename_msg->pvnr_cn_src_cred, &rename_msg->pvnr_cn_src_cid,
1646 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
1647 puffs_makecn(&rename_msg->pvnr_cn_targ,
1648 &rename_msg->pvnr_cn_targ_cred, &rename_msg->pvnr_cn_targ_cid,
1649 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
1650
1651 error = puffs_msg_vn(pmp, park_rename, PUFFS_VN_RENAME,
1652 0, ap->a_fdvp, NULL); /* XXX: missing vnodes */
1653 error = checkerr(pmp, error, __func__);
1654
1655 /*
1656 * XXX: stay in touch with the cache. I don't like this, but
1657 * don't have a better solution either. See also puffs_link().
1658 */
1659 if (error == 0)
1660 puffs_updatenode(ap->a_fvp, PUFFS_UPDATECTIME);
1661
1662 out:
1663 PUFFS_MSG_RELEASE(rename);
1664 if (ap->a_tvp != NULL)
1665 vput(ap->a_tvp);
1666 if (ap->a_tdvp == ap->a_tvp)
1667 vrele(ap->a_tdvp);
1668 else
1669 vput(ap->a_tdvp);
1670
1671 vrele(ap->a_fdvp);
1672 vrele(ap->a_fvp);
1673
1674 return error;
1675 }
1676
1677 #define RWARGS(cont, iofl, move, offset, creds) \
1678 (cont)->pvnr_ioflag = (iofl); \
1679 (cont)->pvnr_resid = (move); \
1680 (cont)->pvnr_offset = (offset); \
1681 puffs_credcvt(&(cont)->pvnr_cred, creds)
1682
1683 int
1684 puffs_read(void *v)
1685 {
1686 struct vop_read_args /* {
1687 const struct vnodeop_desc *a_desc;
1688 struct vnode *a_vp;
1689 struct uio *a_uio;
1690 int a_ioflag;
1691 kauth_cred_t a_cred;
1692 } */ *ap = v;
1693 PUFFS_MSG_VARS(vn, read);
1694 struct vnode *vp = ap->a_vp;
1695 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1696 struct uio *uio = ap->a_uio;
1697 void *win;
1698 size_t tomove, argsize;
1699 vsize_t bytelen;
1700 int error, ubcflags;
1701
1702 read_msg = NULL;
1703 error = 0;
1704
1705 /* std sanity */
1706 if (uio->uio_resid == 0)
1707 return 0;
1708 if (uio->uio_offset < 0)
1709 return EINVAL;
1710
1711 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1712 const int advice = IO_ADV_DECODE(ap->a_ioflag);
1713
1714 ubcflags = 0;
1715 if (UBC_WANT_UNMAP(vp))
1716 ubcflags = UBC_UNMAP;
1717
1718 while (uio->uio_resid > 0) {
1719 bytelen = MIN(uio->uio_resid,
1720 vp->v_size - uio->uio_offset);
1721 if (bytelen == 0)
1722 break;
1723
1724 win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
1725 &bytelen, advice, UBC_READ);
1726 error = uiomove(win, bytelen, uio);
1727 ubc_release(win, ubcflags);
1728 if (error)
1729 break;
1730 }
1731
1732 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1733 puffs_updatenode(vp, PUFFS_UPDATEATIME);
1734 } else {
1735 /*
1736 * in case it's not a regular file or we're operating
1737 * uncached, do read in the old-fashioned style,
1738 * i.e. explicit read operations
1739 */
1740
1741 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1742 argsize = sizeof(struct puffs_vnmsg_read);
1743 puffs_msgmem_alloc(argsize + tomove, &park_read,
1744 (void **)&read_msg, 1);
1745
1746 error = 0;
1747 while (uio->uio_resid > 0) {
1748 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1749 RWARGS(read_msg, ap->a_ioflag, tomove,
1750 uio->uio_offset, ap->a_cred);
1751
1752 error = puffs_msg_vn(pmp, park_read, PUFFS_VN_READ,
1753 0, vp, NULL);
1754 error = checkerr(pmp, error, __func__);
1755 if (error)
1756 break;
1757
1758 if (read_msg->pvnr_resid > tomove) {
1759 puffs_msg_errnotify(pmp, PUFFS_ERR_READ,
1760 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1761 error = EPROTO;
1762 break;
1763 }
1764
1765 error = uiomove(read_msg->pvnr_data,
1766 tomove - read_msg->pvnr_resid, uio);
1767
1768 /*
1769 * in case the file is out of juice, resid from
1770 * userspace is != 0. and the error-case is
1771 * quite obvious
1772 */
1773 if (error || read_msg->pvnr_resid)
1774 break;
1775 }
1776
1777 puffs_msgmem_release(park_read);
1778 }
1779
1780 return error;
1781 }
1782
1783 /*
1784 * XXX: in case of a failure, this leaves uio in a bad state.
1785 * We could theoretically copy the uio and iovecs and "replay"
1786 * them the right amount after the userspace trip, but don't
1787 * bother for now.
1788 */
1789 int
1790 puffs_write(void *v)
1791 {
1792 struct vop_write_args /* {
1793 const struct vnodeop_desc *a_desc;
1794 struct vnode *a_vp;
1795 struct uio *a_uio;
1796 int a_ioflag;
1797 kauth_cred_t a_cred;
1798 } */ *ap = v;
1799 PUFFS_MSG_VARS(vn, write);
1800 struct vnode *vp = ap->a_vp;
1801 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1802 struct uio *uio = ap->a_uio;
1803 size_t tomove, argsize;
1804 off_t oldoff, newoff, origoff;
1805 vsize_t bytelen;
1806 int error, uflags;
1807 int ubcflags;
1808
1809 error = uflags = 0;
1810 write_msg = NULL;
1811
1812 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1813 ubcflags = UBC_WRITE | UBC_PARTIALOK;
1814 if (UBC_WANT_UNMAP(vp))
1815 ubcflags |= UBC_UNMAP;
1816
1817 /*
1818 * userspace *should* be allowed to control this,
1819 * but with UBC it's a bit unclear how to handle it
1820 */
1821 if (ap->a_ioflag & IO_APPEND)
1822 uio->uio_offset = vp->v_size;
1823
1824 origoff = uio->uio_offset;
1825 while (uio->uio_resid > 0) {
1826 uflags |= PUFFS_UPDATECTIME;
1827 uflags |= PUFFS_UPDATEMTIME;
1828 oldoff = uio->uio_offset;
1829 bytelen = uio->uio_resid;
1830
1831 newoff = oldoff + bytelen;
1832 if (vp->v_size < newoff) {
1833 uvm_vnp_setwritesize(vp, newoff);
1834 }
1835 error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
1836 UVM_ADV_RANDOM, ubcflags);
1837
1838 /*
1839 * In case of a ubc_uiomove() error,
1840 * opt to not extend the file at all and
1841 * return an error. Otherwise, if we attempt
1842 * to clear the memory we couldn't fault to,
1843 * we might generate a kernel page fault.
1844 */
1845 if (vp->v_size < newoff) {
1846 if (error == 0) {
1847 uflags |= PUFFS_UPDATESIZE;
1848 uvm_vnp_setsize(vp, newoff);
1849 } else {
1850 uvm_vnp_setwritesize(vp, vp->v_size);
1851 }
1852 }
1853 if (error)
1854 break;
1855
1856 /*
1857 * If we're writing large files, flush to file server
1858 * every 64k. Otherwise we can very easily exhaust
1859 * kernel and user memory, as the file server cannot
1860 * really keep up with our writing speed.
1861 *
1862 * Note: this does *NOT* honor MNT_ASYNC, because
1863 * that gives userland too much say in the kernel.
1864 */
1865 if (oldoff >> 16 != uio->uio_offset >> 16) {
1866 simple_lock(&vp->v_interlock);
1867 error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
1868 uio->uio_offset & ~0xffff,
1869 PGO_CLEANIT | PGO_SYNCIO);
1870 if (error)
1871 break;
1872 }
1873 }
1874
1875 /* synchronous I/O? */
1876 if (error == 0 && ap->a_ioflag & IO_SYNC) {
1877 simple_lock(&vp->v_interlock);
1878 error = VOP_PUTPAGES(vp, trunc_page(origoff),
1879 round_page(uio->uio_offset),
1880 PGO_CLEANIT | PGO_SYNCIO);
1881
1882 /* write through page cache? */
1883 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
1884 simple_lock(&vp->v_interlock);
1885 error = VOP_PUTPAGES(vp, trunc_page(origoff),
1886 round_page(uio->uio_offset), PGO_CLEANIT);
1887 }
1888
1889 puffs_updatenode(vp, uflags);
1890 } else {
1891 /* tomove is non-increasing */
1892 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1893 argsize = sizeof(struct puffs_vnmsg_write) + tomove;
1894 puffs_msgmem_alloc(argsize, &park_write, (void **)&write_msg,1);
1895
1896 while (uio->uio_resid > 0) {
1897 /* move data to buffer */
1898 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1899 RWARGS(write_msg, ap->a_ioflag, tomove,
1900 uio->uio_offset, ap->a_cred);
1901 error = uiomove(write_msg->pvnr_data, tomove, uio);
1902 if (error)
1903 break;
1904
1905 /* move buffer to userspace */
1906 error = puffs_msg_vn(pmp, park_write, PUFFS_VN_WRITE,
1907 0, vp, NULL);
1908 error = checkerr(pmp, error, __func__);
1909 if (error)
1910 break;
1911
1912 if (write_msg->pvnr_resid > tomove) {
1913 puffs_msg_errnotify(pmp, PUFFS_ERR_WRITE,
1914 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1915 error = EPROTO;
1916 break;
1917 }
1918
1919 /* adjust file size */
1920 if (vp->v_size < uio->uio_offset)
1921 uvm_vnp_setsize(vp, uio->uio_offset);
1922
1923 /* didn't move everything? bad userspace. bail */
1924 if (write_msg->pvnr_resid != 0) {
1925 error = EIO;
1926 break;
1927 }
1928 }
1929 puffs_msgmem_release(park_write);
1930 }
1931
1932 return error;
1933 }
1934
1935 int
1936 puffs_print(void *v)
1937 {
1938 struct vop_print_args /* {
1939 struct vnode *a_vp;
1940 } */ *ap = v;
1941 PUFFS_MSG_VARS(vn, print);
1942 struct vnode *vp = ap->a_vp;
1943 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1944 struct puffs_node *pn = vp->v_data;
1945
1946 /* kernel portion */
1947 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1948 " userspace cookie: %p\n", vp, pn, pn->pn_cookie);
1949 if (vp->v_type == VFIFO)
1950 fifo_printinfo(vp);
1951 lockmgr_printinfo(&vp->v_lock);
1952
1953 /* userspace portion */
1954 if (EXISTSOP(pmp, PRINT)) {
1955 PUFFS_MSG_ALLOC(vn, print);
1956 puffs_msg_vn(pmp, park_print, PUFFS_VN_PRINT, 0, vp, NULL);
1957 PUFFS_MSG_RELEASE(print);
1958 }
1959
1960 return 0;
1961 }
1962
1963 int
1964 puffs_pathconf(void *v)
1965 {
1966 struct vop_pathconf_args /* {
1967 const struct vnodeop_desc *a_desc;
1968 struct vnode *a_vp;
1969 int a_name;
1970 register_t *a_retval;
1971 } */ *ap = v;
1972 PUFFS_MSG_VARS(vn, pathconf);
1973 struct vnode *vp = ap->a_vp;
1974 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1975 int error;
1976
1977 PUFFS_MSG_ALLOC(vn, pathconf);
1978 pathconf_msg->pvnr_name = ap->a_name;
1979 error = puffs_msg_vn(pmp, park_pathconf, PUFFS_VN_PATHCONF, 0, vp,NULL);
1980 error = checkerr(pmp, error, __func__);
1981 if (!error)
1982 *ap->a_retval = pathconf_msg->pvnr_retval;
1983 PUFFS_MSG_RELEASE(pathconf);
1984
1985 return error;
1986 }
1987
1988 int
1989 puffs_advlock(void *v)
1990 {
1991 struct vop_advlock_args /* {
1992 const struct vnodeop_desc *a_desc;
1993 struct vnode *a_vp;
1994 void *a_id;
1995 int a_op;
1996 struct flock *a_fl;
1997 int a_flags;
1998 } */ *ap = v;
1999 PUFFS_MSG_VARS(vn, advlock);
2000 struct vnode *vp = ap->a_vp;
2001 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2002 int error;
2003
2004 PUFFS_MSG_ALLOC(vn, advlock);
2005 error = copyin(ap->a_fl, &advlock_msg->pvnr_fl, sizeof(struct flock));
2006 if (error)
2007 goto out;
2008 advlock_msg->pvnr_id = ap->a_id;
2009 advlock_msg->pvnr_op = ap->a_op;
2010 advlock_msg->pvnr_flags = ap->a_flags;
2011
2012 error = puffs_msg_vn(pmp, park_advlock, PUFFS_VN_ADVLOCK, 0, vp, NULL);
2013 error = checkerr(pmp, error, __func__);
2014
2015 out:
2016 PUFFS_MSG_RELEASE(advlock);
2017 return error;
2018 }
2019
2020 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
2021 #define BIOREAD(bp) (bp->b_flags & B_READ)
2022 #define BIOWRITE(bp) ((bp->b_flags & B_READ) == 0)
2023
2024 /*
2025 * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
2026 */
2027
2028 /* XXX: if this is called from interrupt context, we lose */
2029 int
2030 puffs_strategy(void *v)
2031 {
2032 struct vop_strategy_args /* {
2033 const struct vnodeop_desc *a_desc;
2034 struct vnode *a_vp;
2035 struct buf *a_bp;
2036 } */ *ap = v;
2037 PUFFS_MSG_VARS(vn, rw);
2038 struct vnode *vp = ap->a_vp;
2039 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2040 struct puffs_node *pn;
2041 struct buf *bp;
2042 size_t argsize;
2043 size_t tomove, moved;
2044 int error, dofaf;
2045
2046 pmp = MPTOPUFFSMP(vp->v_mount);
2047 bp = ap->a_bp;
2048 error = 0;
2049 dofaf = 0;
2050 pn = VPTOPP(vp);
2051 park_rw = NULL; /* explicit */
2052
2053 if ((BIOREAD(bp) && !EXISTSOP(pmp, READ))
2054 || (BIOWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2055 ERROUT(EOPNOTSUPP);
2056
2057 /*
2058 * Short-circuit optimization: don't flush buffer in between
2059 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2060 */
2061 if (pn->pn_stat & PNODE_DYING) {
2062 KASSERT(BIOWRITE(bp));
2063 bp->b_resid = 0;
2064 goto out;
2065 }
2066
2067 #ifdef DIAGNOSTIC
2068 if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX)
2069 panic("puffs_strategy: wildly inappropriate buf bcount %d",
2070 bp->b_bcount);
2071 #endif
2072
2073 /*
2074 * See explanation for the necessity of a FAF in puffs_fsync.
2075 *
2076 * Also, do FAF in case we're suspending.
2077 * See puffs_vfsops.c:pageflush()
2078 */
2079 if (BIOWRITE(bp)) {
2080 simple_lock(&vp->v_interlock);
2081 if (vp->v_iflag & VI_XLOCK)
2082 dofaf = 1;
2083 if (pn->pn_stat & PNODE_SUSPEND)
2084 dofaf = 1;
2085 simple_unlock(&vp->v_interlock);
2086 }
2087
2088 if (BIOASYNC(bp))
2089 dofaf = 1;
2090
2091 #ifdef DIAGNOSTIC
2092 if (curlwp == uvm.pagedaemon_lwp)
2093 KASSERT(dofaf);
2094 #endif
2095
2096 /* allocate transport structure */
2097 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2098 argsize = sizeof(struct puffs_vnmsg_rw);
2099 error = puffs_msgmem_alloc(argsize + tomove, &park_rw,
2100 (void **)&rw_msg, dofaf ? 0 : 1);
2101 if (error)
2102 goto out;
2103 RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2104
2105 /* 2x2 cases: read/write, faf/nofaf */
2106 if (BIOREAD(bp)) {
2107 if (dofaf) {
2108 puffs_msg_vncall(pmp, park_rw, PUFFS_VN_READ, 0,
2109 puffs_parkdone_asyncbioread, bp, vp);
2110 } else {
2111 error = puffs_msg_vn(pmp, park_rw, PUFFS_VN_READ,
2112 0, vp, NULL);
2113 error = checkerr(pmp, error, __func__);
2114 if (error)
2115 goto out;
2116
2117 if (rw_msg->pvnr_resid > tomove) {
2118 puffs_msg_errnotify(pmp, PUFFS_ERR_READ,
2119 E2BIG, "resid grew", VPTOPNC(vp));
2120 ERROUT(EPROTO);
2121 }
2122
2123 moved = tomove - rw_msg->pvnr_resid;
2124
2125 (void)memcpy(bp->b_data, rw_msg->pvnr_data, moved);
2126 bp->b_resid = bp->b_bcount - moved;
2127 }
2128 } else {
2129 /*
2130 * make pages read-only before we write them if we want
2131 * write caching info
2132 */
2133 if (PUFFS_WCACHEINFO(pmp)) {
2134 struct uvm_object *uobj = &vp->v_uobj;
2135 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2136 struct vm_page *vmp;
2137 int i;
2138
2139 for (i = 0; i < npages; i++) {
2140 vmp= uvm_pageratop((vaddr_t)bp->b_data
2141 + (i << PAGE_SHIFT));
2142 DPRINTF(("puffs_strategy: write-protecting "
2143 "vp %p page %p, offset %" PRId64"\n",
2144 vp, vmp, vmp->offset));
2145 simple_lock(&uobj->vmobjlock);
2146 vmp->flags |= PG_RDONLY;
2147 pmap_page_protect(vmp, VM_PROT_READ);
2148 simple_unlock(&uobj->vmobjlock);
2149 }
2150 }
2151
2152 (void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove);
2153 if (dofaf)
2154 puffs_msg_setfaf(park_rw);
2155 error = puffs_msg_vn(pmp, park_rw, PUFFS_VN_WRITE, 0, vp, NULL);
2156
2157 if (dofaf) {
2158 /*
2159 * FAF moves everything. Frankly, we don't
2160 * really have a choice.
2161 */
2162 KASSERT(error == 0);
2163 bp->b_resid = bp->b_bcount - tomove;
2164 } else {
2165 error = checkerr(pmp, error, __func__);
2166 if (error)
2167 goto out;
2168
2169 moved = tomove - rw_msg->pvnr_resid;
2170 if (rw_msg->pvnr_resid > tomove) {
2171 puffs_msg_errnotify(pmp, PUFFS_ERR_WRITE,
2172 E2BIG, "resid grew", VPTOPNC(vp));
2173 ERROUT(EPROTO);
2174 }
2175
2176 bp->b_resid = bp->b_bcount - moved;
2177 if (rw_msg->pvnr_resid != 0) {
2178 ERROUT(EIO);
2179 }
2180 }
2181 }
2182
2183 out:
2184 if (park_rw)
2185 puffs_msgmem_release(park_rw);
2186
2187 if (error)
2188 bp->b_error = error;
2189
2190 if (error || !(BIOREAD(bp) && BIOASYNC(bp)))
2191 biodone(bp);
2192
2193 return error;
2194 }
2195
2196 int
2197 puffs_mmap(void *v)
2198 {
2199 struct vop_mmap_args /* {
2200 const struct vnodeop_desc *a_desc;
2201 struct vnode *a_vp;
2202 vm_prot_t a_prot;
2203 kauth_cred_t a_cred;
2204 struct lwp *a_l;
2205 } */ *ap = v;
2206 PUFFS_MSG_VARS(vn, mmap);
2207 struct vnode *vp = ap->a_vp;
2208 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2209 int error;
2210
2211 if (!PUFFS_USE_PAGECACHE(pmp))
2212 return genfs_eopnotsupp(v);
2213
2214 if (EXISTSOP(pmp, MMAP)) {
2215 PUFFS_MSG_ALLOC(vn, mmap);
2216 mmap_msg->pvnr_prot = ap->a_prot;
2217 puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred);
2218 puffs_cidcvt(&mmap_msg->pvnr_cid, ap->a_l);
2219
2220 error = puffs_msg_vn(pmp, park_mmap, PUFFS_VN_MMAP,
2221 0, vp, NULL);
2222 error = checkerr(pmp, error, __func__);
2223 PUFFS_MSG_RELEASE(mmap);
2224 } else {
2225 error = genfs_mmap(v);
2226 }
2227
2228 return error;
2229 }
2230
2231
2232 /*
2233 * The rest don't get a free trip to userspace and back, they
2234 * have to stay within the kernel.
2235 */
2236
2237 /*
2238 * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2239 * well, maybe somehow, somewhere, some day ....
2240 */
2241 int
2242 puffs_bmap(void *v)
2243 {
2244 struct vop_bmap_args /* {
2245 const struct vnodeop_desc *a_desc;
2246 struct vnode *a_vp;
2247 daddr_t a_bn;
2248 struct vnode **a_vpp;
2249 daddr_t *a_bnp;
2250 int *a_runp;
2251 } */ *ap = v;
2252 struct puffs_mount *pmp;
2253
2254 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2255
2256 if (ap->a_vpp)
2257 *ap->a_vpp = ap->a_vp;
2258 if (ap->a_bnp)
2259 *ap->a_bnp = ap->a_bn;
2260 if (ap->a_runp)
2261 *ap->a_runp
2262 = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1;
2263
2264 return 0;
2265 }
2266
2267 /*
2268 * Handle getpages faults in puffs. We let genfs_getpages() do most
2269 * of the dirty work, but we come in this route to do accounting tasks.
2270 * If the user server has specified functions for cache notifications
2271 * about reads and/or writes, we record which type of operation we got,
2272 * for which page range, and proceed to issue a FAF notification to the
2273 * server about it.
2274 */
2275 int
2276 puffs_getpages(void *v)
2277 {
2278 struct vop_getpages_args /* {
2279 const struct vnodeop_desc *a_desc;
2280 struct vnode *a_vp;
2281 voff_t a_offset;
2282 struct vm_page **a_m;
2283 int *a_count;
2284 int a_centeridx;
2285 vm_prot_t a_access_type;
2286 int a_advice;
2287 int a_flags;
2288 } */ *ap = v;
2289 struct puffs_mount *pmp;
2290 struct puffs_node *pn;
2291 struct vnode *vp;
2292 struct vm_page **pgs;
2293 struct puffs_cacheinfo *pcinfo = NULL;
2294 struct puffs_cacherun *pcrun;
2295 void *parkmem = NULL;
2296 size_t runsizes;
2297 int i, npages, si, streakon;
2298 int error, locked, write;
2299
2300 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2301 npages = *ap->a_count;
2302 pgs = ap->a_m;
2303 vp = ap->a_vp;
2304 pn = vp->v_data;
2305 locked = (ap->a_flags & PGO_LOCKED) != 0;
2306 write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2307
2308 /* ccg xnaht - gets Wuninitialized wrong */
2309 pcrun = NULL;
2310 runsizes = 0;
2311
2312 /*
2313 * Check that we aren't trying to fault in pages which our file
2314 * server doesn't know about. This happens if we extend a file by
2315 * skipping some pages and later try to fault in pages which
2316 * are between pn_serversize and vp_size. This check optimizes
2317 * away the common case where a file is being extended.
2318 */
2319 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2320 struct vattr va;
2321
2322 /* try again later when we can block */
2323 if (locked)
2324 ERROUT(EBUSY);
2325
2326 simple_unlock(&vp->v_interlock);
2327 vattr_null(&va);
2328 va.va_size = vp->v_size;
2329 error = puffs_dosetattr(vp, &va, FSCRED, NULL, 0);
2330 if (error)
2331 ERROUT(error);
2332 simple_lock(&vp->v_interlock);
2333 }
2334
2335 if (write && PUFFS_WCACHEINFO(pmp)) {
2336 #ifdef notnowjohn
2337 /* allocate worst-case memory */
2338 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2339 pcinfo = malloc(sizeof(struct puffs_cacheinfo) + runsizes,
2340 M_PUFFS, M_ZERO | locked ? M_NOWAIT : M_WAITOK);
2341
2342 /*
2343 * can't block if we're locked and can't mess up caching
2344 * information for fs server. so come back later, please
2345 */
2346 if (pcinfo == NULL)
2347 ERROUT(ENOMEM);
2348
2349 parkmem = puffs_park_alloc(locked == 0);
2350 if (parkmem == NULL)
2351 ERROUT(ENOMEM);
2352
2353 pcrun = pcinfo->pcache_runs;
2354 #else
2355 (void)parkmem;
2356 #endif
2357 }
2358
2359 error = genfs_getpages(v);
2360 if (error)
2361 goto out;
2362
2363 if (PUFFS_WCACHEINFO(pmp) == 0)
2364 goto out;
2365
2366 /*
2367 * Let's see whose fault it was and inform the user server of
2368 * possibly read/written pages. Map pages from read faults
2369 * strictly read-only, since otherwise we might miss info on
2370 * when the page is actually write-faulted to.
2371 */
2372 if (!locked)
2373 simple_lock(&vp->v_uobj.vmobjlock);
2374 for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2375 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2376 if (streakon && write) {
2377 streakon = 0;
2378 pcrun[si].pcache_runend
2379 = trunc_page(pgs[i]->offset) + PAGE_MASK;
2380 si++;
2381 }
2382 continue;
2383 }
2384 if (streakon == 0 && write) {
2385 streakon = 1;
2386 pcrun[si].pcache_runstart = pgs[i]->offset;
2387 }
2388
2389 if (!write)
2390 pgs[i]->flags |= PG_RDONLY;
2391 }
2392 /* was the last page part of our streak? */
2393 if (streakon) {
2394 pcrun[si].pcache_runend
2395 = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2396 si++;
2397 }
2398 if (!locked)
2399 simple_unlock(&vp->v_uobj.vmobjlock);
2400
2401 KASSERT(si <= (npages / 2) + 1);
2402
2403 #ifdef notnowjohn
2404 /* send results to userspace */
2405 if (write)
2406 puffs_cacheop(pmp, parkmem, pcinfo,
2407 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2408 #endif
2409
2410 out:
2411 if (error) {
2412 if (pcinfo != NULL)
2413 free(pcinfo, M_PUFFS);
2414 #ifdef notnowjohn
2415 if (parkmem != NULL)
2416 puffs_park_release(parkmem, 1);
2417 #endif
2418 }
2419
2420 return error;
2421 }
2422
2423 int
2424 puffs_lock(void *v)
2425 {
2426 struct vop_lock_args /* {
2427 struct vnode *a_vp;
2428 int a_flags;
2429 }*/ *ap = v;
2430 struct vnode *vp = ap->a_vp;
2431 struct mount *mp = vp->v_mount;
2432
2433 #if 0
2434 DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
2435 #endif
2436
2437 /*
2438 * XXX: this avoids deadlocking when we're suspending.
2439 * e.g. some ops holding the vnode lock might be blocked for
2440 * the vfs transaction lock so we'd deadlock.
2441 *
2442 * Now once again this is skating on the thin ice of modern life,
2443 * since we are breaking the consistency guarantee provided
2444 * _to the user server_ by vnode locking. Hopefully this will
2445 * get fixed soon enough by getting rid of the dependency on
2446 * vnode locks alltogether.
2447 */
2448 if (fstrans_is_owner(mp) && fstrans_getstate(mp) == FSTRANS_SUSPENDING){
2449 if (ap->a_flags & LK_INTERLOCK)
2450 simple_unlock(&vp->v_interlock);
2451 return 0;
2452 }
2453
2454 return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
2455 }
2456
2457 int
2458 puffs_unlock(void *v)
2459 {
2460 struct vop_unlock_args /* {
2461 struct vnode *a_vp;
2462 int a_flags;
2463 } */ *ap = v;
2464 struct vnode *vp = ap->a_vp;
2465 struct mount *mp = vp->v_mount;
2466
2467 #if 0
2468 DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
2469 #endif
2470
2471 /* XXX: see puffs_lock() */
2472 if (fstrans_is_owner(mp) && fstrans_getstate(mp) == FSTRANS_SUSPENDING){
2473 if (ap->a_flags & LK_INTERLOCK)
2474 simple_unlock(&vp->v_interlock);
2475 return 0;
2476 }
2477
2478 return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
2479 }
2480
2481 int
2482 puffs_islocked(void *v)
2483 {
2484 struct vop_islocked_args *ap = v;
2485 int rv;
2486
2487 rv = lockstatus(&ap->a_vp->v_lock);
2488 return rv;
2489 }
2490
2491 int
2492 puffs_generic(void *v)
2493 {
2494 struct vop_generic_args *ap = v;
2495
2496 (void)ap;
2497 DPRINTF(("puffs_generic: ap->a_desc = %s\n", ap->a_desc->vdesc_name));
2498
2499 return EOPNOTSUPP;
2500 }
2501
2502
2503 /*
2504 * spec & fifo. These call the miscfs spec and fifo vectors, but issue
2505 * FAF update information for the puffs node first.
2506 */
2507 int
2508 puffs_spec_read(void *v)
2509 {
2510 struct vop_read_args /* {
2511 const struct vnodeop_desc *a_desc;
2512 struct vnode *a_vp;
2513 struct uio *a_uio;
2514 int a_ioflag;
2515 kauth_cred_t a_cred;
2516 } */ *ap = v;
2517
2518 puffs_updatenode(ap->a_vp, PUFFS_UPDATEATIME);
2519 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
2520 }
2521
2522 int
2523 puffs_spec_write(void *v)
2524 {
2525 struct vop_write_args /* {
2526 const struct vnodeop_desc *a_desc;
2527 struct vnode *a_vp;
2528 struct uio *a_uio;
2529 int a_ioflag;
2530 kauth_cred_t a_cred;
2531 }*/ *ap = v;
2532
2533 puffs_updatenode(ap->a_vp, PUFFS_UPDATEMTIME);
2534 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
2535 }
2536
2537 int
2538 puffs_fifo_read(void *v)
2539 {
2540 struct vop_read_args /* {
2541 const struct vnodeop_desc *a_desc;
2542 struct vnode *a_vp;
2543 struct uio *a_uio;
2544 int a_ioflag;
2545 kauth_cred_t a_cred;
2546 } */ *ap = v;
2547
2548 puffs_updatenode(ap->a_vp, PUFFS_UPDATEATIME);
2549 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
2550 }
2551
2552 int
2553 puffs_fifo_write(void *v)
2554 {
2555 struct vop_write_args /* {
2556 const struct vnodeop_desc *a_desc;
2557 struct vnode *a_vp;
2558 struct uio *a_uio;
2559 int a_ioflag;
2560 kauth_cred_t a_cred;
2561 }*/ *ap = v;
2562
2563 puffs_updatenode(ap->a_vp, PUFFS_UPDATEMTIME);
2564 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
2565 }
2566