xref: /netbsd-src/sys/fs/puffs/puffs_vnops.c (revision 80d9064ac03cbb6a4174695f0d5b237c8766d3d0)
1 /*	$NetBSD: puffs_vnops.c,v 1.186 2014/09/11 07:59:14 manu 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.186 2014/09/11 07:59:14 manu Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/buf.h>
37 #include <sys/lockf.h>
38 #include <sys/malloc.h>
39 #include <sys/mount.h>
40 #include <sys/namei.h>
41 #include <sys/vnode.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h> /* For hz, hardclock_ticks */
44 
45 #include <uvm/uvm.h>
46 
47 #include <fs/puffs/puffs_msgif.h>
48 #include <fs/puffs/puffs_sys.h>
49 
50 #include <miscfs/fifofs/fifo.h>
51 #include <miscfs/genfs/genfs.h>
52 #include <miscfs/specfs/specdev.h>
53 
54 int	puffs_vnop_lookup(void *);
55 int	puffs_vnop_create(void *);
56 int	puffs_vnop_access(void *);
57 int	puffs_vnop_mknod(void *);
58 int	puffs_vnop_open(void *);
59 int	puffs_vnop_close(void *);
60 int	puffs_vnop_getattr(void *);
61 int	puffs_vnop_setattr(void *);
62 int	puffs_vnop_reclaim(void *);
63 int	puffs_vnop_readdir(void *);
64 int	puffs_vnop_poll(void *);
65 int	puffs_vnop_fsync(void *);
66 int	puffs_vnop_seek(void *);
67 int	puffs_vnop_remove(void *);
68 int	puffs_vnop_mkdir(void *);
69 int	puffs_vnop_rmdir(void *);
70 int	puffs_vnop_link(void *);
71 int	puffs_vnop_readlink(void *);
72 int	puffs_vnop_symlink(void *);
73 int	puffs_vnop_rename(void *);
74 int	puffs_vnop_read(void *);
75 int	puffs_vnop_write(void *);
76 int	puffs_vnop_fcntl(void *);
77 int	puffs_vnop_ioctl(void *);
78 int	puffs_vnop_inactive(void *);
79 int	puffs_vnop_print(void *);
80 int	puffs_vnop_pathconf(void *);
81 int	puffs_vnop_advlock(void *);
82 int	puffs_vnop_strategy(void *);
83 int	puffs_vnop_bmap(void *);
84 int	puffs_vnop_mmap(void *);
85 int	puffs_vnop_getpages(void *);
86 int	puffs_vnop_abortop(void *);
87 int	puffs_vnop_getextattr(void *);
88 int	puffs_vnop_setextattr(void *);
89 int	puffs_vnop_listextattr(void *);
90 int	puffs_vnop_deleteextattr(void *);
91 
92 int	puffs_vnop_spec_read(void *);
93 int	puffs_vnop_spec_write(void *);
94 int	puffs_vnop_fifo_read(void *);
95 int	puffs_vnop_fifo_write(void *);
96 
97 int	puffs_vnop_checkop(void *);
98 
99 #define puffs_vnop_lock genfs_lock
100 #define puffs_vnop_unlock genfs_unlock
101 #define puffs_vnop_islocked genfs_islocked
102 
103 int (**puffs_vnodeop_p)(void *);
104 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
105 	{ &vop_default_desc, vn_default_error },
106 	{ &vop_lookup_desc, puffs_vnop_lookup },	/* REAL lookup */
107 	{ &vop_create_desc, puffs_vnop_checkop },	/* create */
108         { &vop_mknod_desc, puffs_vnop_checkop },	/* mknod */
109         { &vop_open_desc, puffs_vnop_open },		/* REAL open */
110         { &vop_close_desc, puffs_vnop_checkop },	/* close */
111         { &vop_access_desc, puffs_vnop_access },	/* REAL access */
112         { &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
113         { &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
114         { &vop_read_desc, puffs_vnop_checkop },		/* read */
115         { &vop_write_desc, puffs_vnop_checkop },	/* write */
116 	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
117 	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
118         { &vop_fsync_desc, puffs_vnop_fsync },		/* REAL fsync */
119         { &vop_seek_desc, puffs_vnop_checkop },		/* seek */
120         { &vop_remove_desc, puffs_vnop_checkop },	/* remove */
121         { &vop_link_desc, puffs_vnop_checkop },		/* link */
122         { &vop_rename_desc, puffs_vnop_checkop },	/* rename */
123         { &vop_mkdir_desc, puffs_vnop_checkop },	/* mkdir */
124         { &vop_rmdir_desc, puffs_vnop_checkop },	/* rmdir */
125         { &vop_symlink_desc, puffs_vnop_checkop },	/* symlink */
126         { &vop_readdir_desc, puffs_vnop_checkop },	/* readdir */
127         { &vop_readlink_desc, puffs_vnop_checkop },	/* readlink */
128         { &vop_getpages_desc, puffs_vnop_checkop },	/* getpages */
129         { &vop_putpages_desc, genfs_putpages },		/* REAL putpages */
130         { &vop_pathconf_desc, puffs_vnop_checkop },	/* pathconf */
131         { &vop_advlock_desc, puffs_vnop_advlock },	/* advlock */
132         { &vop_strategy_desc, puffs_vnop_strategy },	/* REAL strategy */
133         { &vop_revoke_desc, genfs_revoke },		/* REAL revoke */
134         { &vop_abortop_desc, puffs_vnop_abortop },	/* REAL abortop */
135         { &vop_inactive_desc, puffs_vnop_inactive },	/* REAL inactive */
136         { &vop_reclaim_desc, puffs_vnop_reclaim },	/* REAL reclaim */
137         { &vop_lock_desc, puffs_vnop_lock },		/* REAL lock */
138         { &vop_unlock_desc, puffs_vnop_unlock },	/* REAL unlock */
139         { &vop_bmap_desc, puffs_vnop_bmap },		/* REAL bmap */
140         { &vop_print_desc, puffs_vnop_print },		/* REAL print */
141         { &vop_islocked_desc, puffs_vnop_islocked },	/* REAL islocked */
142         { &vop_bwrite_desc, genfs_nullop },		/* REAL bwrite */
143         { &vop_mmap_desc, puffs_vnop_mmap },		/* REAL mmap */
144         { &vop_poll_desc, puffs_vnop_poll },		/* REAL poll */
145 	{ &vop_getextattr_desc, puffs_vnop_getextattr },	/* getextattr */
146 	{ &vop_setextattr_desc, puffs_vnop_setextattr },	/* setextattr */
147 	{ &vop_listextattr_desc, puffs_vnop_listextattr },	/* listextattr */
148 	{ &vop_deleteextattr_desc, puffs_vnop_deleteextattr },/* deleteextattr */
149 #if 0
150 	{ &vop_openextattr_desc, puffs_vnop_checkop },	/* openextattr */
151 	{ &vop_closeextattr_desc, puffs_vnop_checkop },	/* closeextattr */
152 #endif
153         { &vop_kqfilter_desc, genfs_eopnotsupp },	/* kqfilter XXX */
154 	{ NULL, NULL }
155 };
156 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
157 	{ &puffs_vnodeop_p, puffs_vnodeop_entries };
158 
159 
160 int (**puffs_specop_p)(void *);
161 const struct vnodeopv_entry_desc puffs_specop_entries[] = {
162 	{ &vop_default_desc, vn_default_error },
163 	{ &vop_lookup_desc, spec_lookup },		/* lookup, ENOTDIR */
164 	{ &vop_create_desc, spec_create },		/* genfs_badop */
165 	{ &vop_mknod_desc, spec_mknod },		/* genfs_badop */
166 	{ &vop_open_desc, spec_open },			/* spec_open */
167 	{ &vop_close_desc, spec_close },		/* spec_close */
168 	{ &vop_access_desc, puffs_vnop_checkop },	/* access */
169 	{ &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
170 	{ &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
171 	{ &vop_read_desc, puffs_vnop_spec_read },	/* update, read */
172 	{ &vop_write_desc, puffs_vnop_spec_write },	/* update, write */
173 	{ &vop_fallocate_desc, spec_fallocate },	/* fallocate */
174 	{ &vop_fdiscard_desc, spec_fdiscard },		/* fdiscard */
175 	{ &vop_ioctl_desc, spec_ioctl },		/* spec_ioctl */
176 	{ &vop_fcntl_desc, genfs_fcntl },		/* dummy */
177 	{ &vop_poll_desc, spec_poll },			/* spec_poll */
178 	{ &vop_kqfilter_desc, spec_kqfilter },		/* spec_kqfilter */
179 	{ &vop_revoke_desc, spec_revoke },		/* genfs_revoke */
180 	{ &vop_mmap_desc, spec_mmap },			/* spec_mmap */
181 	{ &vop_fsync_desc, spec_fsync },		/* vflushbuf */
182 	{ &vop_seek_desc, spec_seek },			/* genfs_nullop */
183 	{ &vop_remove_desc, spec_remove },		/* genfs_badop */
184 	{ &vop_link_desc, spec_link },			/* genfs_badop */
185 	{ &vop_rename_desc, spec_rename },		/* genfs_badop */
186 	{ &vop_mkdir_desc, spec_mkdir },		/* genfs_badop */
187 	{ &vop_rmdir_desc, spec_rmdir },		/* genfs_badop */
188 	{ &vop_symlink_desc, spec_symlink },		/* genfs_badop */
189 	{ &vop_readdir_desc, spec_readdir },		/* genfs_badop */
190 	{ &vop_readlink_desc, spec_readlink },		/* genfs_badop */
191 	{ &vop_abortop_desc, spec_abortop },		/* genfs_badop */
192 	{ &vop_inactive_desc, puffs_vnop_inactive },	/* REAL inactive */
193 	{ &vop_reclaim_desc, puffs_vnop_reclaim },	/* REAL reclaim */
194 	{ &vop_lock_desc, puffs_vnop_lock },		/* REAL lock */
195 	{ &vop_unlock_desc, puffs_vnop_unlock },	/* REAL unlock */
196 	{ &vop_bmap_desc, spec_bmap },			/* dummy */
197 	{ &vop_strategy_desc, spec_strategy },		/* dev strategy */
198 	{ &vop_print_desc, puffs_vnop_print },		/* REAL print */
199 	{ &vop_islocked_desc, puffs_vnop_islocked },	/* REAL islocked */
200 	{ &vop_pathconf_desc, spec_pathconf },		/* pathconf */
201 	{ &vop_advlock_desc, spec_advlock },		/* lf_advlock */
202 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
203 	{ &vop_getpages_desc, spec_getpages },		/* genfs_getpages */
204 	{ &vop_putpages_desc, spec_putpages },		/* genfs_putpages */
205 	{ &vop_getextattr_desc, puffs_vnop_checkop },	/* getextattr */
206 	{ &vop_setextattr_desc, puffs_vnop_checkop },	/* setextattr */
207 	{ &vop_listextattr_desc, puffs_vnop_checkop },	/* listextattr */
208 	{ &vop_deleteextattr_desc, puffs_vnop_checkop },/* deleteextattr */
209 #if 0
210 	{ &vop_openextattr_desc, _openextattr },	/* openextattr */
211 	{ &vop_closeextattr_desc, _closeextattr },	/* closeextattr */
212 #endif
213 	{ NULL, NULL }
214 };
215 const struct vnodeopv_desc puffs_specop_opv_desc =
216 	{ &puffs_specop_p, puffs_specop_entries };
217 
218 
219 int (**puffs_fifoop_p)(void *);
220 const struct vnodeopv_entry_desc puffs_fifoop_entries[] = {
221 	{ &vop_default_desc, vn_default_error },
222 	{ &vop_lookup_desc, vn_fifo_bypass },		/* lookup, ENOTDIR */
223 	{ &vop_create_desc, vn_fifo_bypass },		/* genfs_badop */
224 	{ &vop_mknod_desc, vn_fifo_bypass },		/* genfs_badop */
225 	{ &vop_open_desc, vn_fifo_bypass },		/* open */
226 	{ &vop_close_desc, vn_fifo_bypass },		/* close */
227 	{ &vop_access_desc, puffs_vnop_checkop },	/* access */
228 	{ &vop_getattr_desc, puffs_vnop_checkop },	/* getattr */
229 	{ &vop_setattr_desc, puffs_vnop_checkop },	/* setattr */
230 	{ &vop_read_desc, puffs_vnop_fifo_read },	/* read, update */
231 	{ &vop_write_desc, puffs_vnop_fifo_write },	/* write, update */
232 	{ &vop_fallocate_desc, vn_fifo_bypass },	/* fallocate */
233 	{ &vop_fdiscard_desc, vn_fifo_bypass },		/* fdiscard */
234 	{ &vop_ioctl_desc, vn_fifo_bypass },		/* ioctl */
235 	{ &vop_fcntl_desc, genfs_fcntl },		/* dummy */
236 	{ &vop_poll_desc, vn_fifo_bypass },		/* poll */
237 	{ &vop_kqfilter_desc, vn_fifo_bypass },		/* kqfilter */
238 	{ &vop_revoke_desc, vn_fifo_bypass },		/* genfs_revoke */
239 	{ &vop_mmap_desc, vn_fifo_bypass },		/* genfs_badop */
240 	{ &vop_fsync_desc, vn_fifo_bypass },		/* genfs_nullop*/
241 	{ &vop_seek_desc, vn_fifo_bypass },		/* genfs_badop */
242 	{ &vop_remove_desc, vn_fifo_bypass },		/* genfs_badop */
243 	{ &vop_link_desc, vn_fifo_bypass },		/* genfs_badop */
244 	{ &vop_rename_desc, vn_fifo_bypass },		/* genfs_badop */
245 	{ &vop_mkdir_desc, vn_fifo_bypass },		/* genfs_badop */
246 	{ &vop_rmdir_desc, vn_fifo_bypass },		/* genfs_badop */
247 	{ &vop_symlink_desc, vn_fifo_bypass },		/* genfs_badop */
248 	{ &vop_readdir_desc, vn_fifo_bypass },		/* genfs_badop */
249 	{ &vop_readlink_desc, vn_fifo_bypass },		/* genfs_badop */
250 	{ &vop_abortop_desc, vn_fifo_bypass },		/* genfs_badop */
251 	{ &vop_inactive_desc, puffs_vnop_inactive },	/* REAL inactive */
252 	{ &vop_reclaim_desc, puffs_vnop_reclaim },	/* REAL reclaim */
253 	{ &vop_lock_desc, puffs_vnop_lock },		/* REAL lock */
254 	{ &vop_unlock_desc, puffs_vnop_unlock },	/* REAL unlock */
255 	{ &vop_bmap_desc, vn_fifo_bypass },		/* dummy */
256 	{ &vop_strategy_desc, vn_fifo_bypass },		/* genfs_badop */
257 	{ &vop_print_desc, puffs_vnop_print },		/* REAL print */
258 	{ &vop_islocked_desc, puffs_vnop_islocked },	/* REAL islocked */
259 	{ &vop_pathconf_desc, vn_fifo_bypass },		/* pathconf */
260 	{ &vop_advlock_desc, vn_fifo_bypass },		/* genfs_einval */
261 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
262 	{ &vop_putpages_desc, vn_fifo_bypass }, 	/* genfs_null_putpages*/
263 #if 0
264 	{ &vop_openextattr_desc, _openextattr },	/* openextattr */
265 	{ &vop_closeextattr_desc, _closeextattr },	/* closeextattr */
266 #endif
267 	{ &vop_getextattr_desc, puffs_vnop_checkop },		/* getextattr */
268 	{ &vop_setextattr_desc, puffs_vnop_checkop },		/* setextattr */
269 	{ &vop_listextattr_desc, puffs_vnop_checkop },	/* listextattr */
270 	{ &vop_deleteextattr_desc, puffs_vnop_checkop },	/* deleteextattr */
271 	{ NULL, NULL }
272 };
273 const struct vnodeopv_desc puffs_fifoop_opv_desc =
274 	{ &puffs_fifoop_p, puffs_fifoop_entries };
275 
276 
277 /* "real" vnode operations */
278 int (**puffs_msgop_p)(void *);
279 const struct vnodeopv_entry_desc puffs_msgop_entries[] = {
280 	{ &vop_default_desc, vn_default_error },
281 	{ &vop_create_desc, puffs_vnop_create },	/* create */
282         { &vop_mknod_desc, puffs_vnop_mknod },		/* mknod */
283         { &vop_open_desc, puffs_vnop_open },		/* open */
284         { &vop_close_desc, puffs_vnop_close },		/* close */
285         { &vop_access_desc, puffs_vnop_access },	/* access */
286         { &vop_getattr_desc, puffs_vnop_getattr },	/* getattr */
287         { &vop_setattr_desc, puffs_vnop_setattr },	/* setattr */
288         { &vop_read_desc, puffs_vnop_read },		/* read */
289         { &vop_write_desc, puffs_vnop_write },		/* write */
290         { &vop_seek_desc, puffs_vnop_seek },		/* seek */
291         { &vop_remove_desc, puffs_vnop_remove },	/* remove */
292         { &vop_link_desc, puffs_vnop_link },		/* link */
293         { &vop_rename_desc, puffs_vnop_rename },	/* rename */
294         { &vop_mkdir_desc, puffs_vnop_mkdir },		/* mkdir */
295         { &vop_rmdir_desc, puffs_vnop_rmdir },		/* rmdir */
296         { &vop_symlink_desc, puffs_vnop_symlink },	/* symlink */
297         { &vop_readdir_desc, puffs_vnop_readdir },	/* readdir */
298         { &vop_readlink_desc, puffs_vnop_readlink },	/* readlink */
299         { &vop_print_desc, puffs_vnop_print },		/* print */
300         { &vop_islocked_desc, puffs_vnop_islocked },	/* islocked */
301         { &vop_pathconf_desc, puffs_vnop_pathconf },	/* pathconf */
302         { &vop_getpages_desc, puffs_vnop_getpages },	/* getpages */
303 	{ NULL, NULL }
304 };
305 const struct vnodeopv_desc puffs_msgop_opv_desc =
306 	{ &puffs_msgop_p, puffs_msgop_entries };
307 
308 /*
309  * for dosetattr / update_va
310  */
311 #define SETATTR_CHSIZE	0x01
312 #define SETATTR_ASYNC	0x02
313 
314 #define ERROUT(err)							\
315 do {									\
316 	error = err;							\
317 	goto out;							\
318 } while (/*CONSTCOND*/0)
319 
320 /*
321  * This is a generic vnode operation handler.  It checks if the necessary
322  * operations for the called vnode operation are implemented by userspace
323  * and either returns a dummy return value or proceeds to call the real
324  * vnode operation from puffs_msgop_v.
325  *
326  * XXX: this should described elsewhere and autogenerated, the complexity
327  * of the vnode operations vectors and their interrelationships is also
328  * getting a bit out of hand.  Another problem is that we need this same
329  * information in the fs server code, so keeping the two in sync manually
330  * is not a viable (long term) plan.
331  */
332 
333 /* not supported, handle locking protocol */
334 #define CHECKOP_NOTSUPP(op)						\
335 case VOP_##op##_DESCOFFSET:						\
336 	if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0)			\
337 		return genfs_eopnotsupp(v);				\
338 	break
339 
340 /* always succeed, no locking */
341 #define CHECKOP_SUCCESS(op)						\
342 case VOP_##op##_DESCOFFSET:						\
343 	if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0)			\
344 		return 0;						\
345 	break
346 
347 int
348 puffs_vnop_checkop(void *v)
349 {
350 	struct vop_generic_args /* {
351 		struct vnodeop_desc *a_desc;
352 		spooky mystery contents;
353 	} */ *ap = v;
354 	struct vnodeop_desc *desc = ap->a_desc;
355 	struct puffs_mount *pmp;
356 	struct vnode *vp;
357 	int offset, rv;
358 
359 	offset = ap->a_desc->vdesc_vp_offsets[0];
360 #ifdef DIAGNOSTIC
361 	if (offset == VDESC_NO_OFFSET)
362 		panic("puffs_checkop: no vnode, why did you call me?");
363 #endif
364 	vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
365 	pmp = MPTOPUFFSMP(vp->v_mount);
366 
367 	DPRINTF_VERBOSE(("checkop call %s (%d), vp %p\n",
368 	    ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp));
369 
370 	if (!ALLOPS(pmp)) {
371 		switch (desc->vdesc_offset) {
372 			CHECKOP_NOTSUPP(CREATE);
373 			CHECKOP_NOTSUPP(MKNOD);
374 			CHECKOP_NOTSUPP(GETATTR);
375 			CHECKOP_NOTSUPP(SETATTR);
376 			CHECKOP_NOTSUPP(READ);
377 			CHECKOP_NOTSUPP(WRITE);
378 			CHECKOP_NOTSUPP(FCNTL);
379 			CHECKOP_NOTSUPP(IOCTL);
380 			CHECKOP_NOTSUPP(REMOVE);
381 			CHECKOP_NOTSUPP(LINK);
382 			CHECKOP_NOTSUPP(RENAME);
383 			CHECKOP_NOTSUPP(MKDIR);
384 			CHECKOP_NOTSUPP(RMDIR);
385 			CHECKOP_NOTSUPP(SYMLINK);
386 			CHECKOP_NOTSUPP(READDIR);
387 			CHECKOP_NOTSUPP(READLINK);
388 			CHECKOP_NOTSUPP(PRINT);
389 			CHECKOP_NOTSUPP(PATHCONF);
390 			CHECKOP_NOTSUPP(GETEXTATTR);
391 			CHECKOP_NOTSUPP(SETEXTATTR);
392 			CHECKOP_NOTSUPP(LISTEXTATTR);
393 			CHECKOP_NOTSUPP(DELETEEXTATTR);
394 
395 			CHECKOP_SUCCESS(ACCESS);
396 			CHECKOP_SUCCESS(CLOSE);
397 			CHECKOP_SUCCESS(SEEK);
398 
399 		case VOP_GETPAGES_DESCOFFSET:
400 			if (!EXISTSOP(pmp, READ))
401 				return genfs_eopnotsupp(v);
402 			break;
403 
404 		default:
405 			panic("puffs_checkop: unhandled vnop %d",
406 			    desc->vdesc_offset);
407 		}
408 	}
409 
410 	rv = VOCALL(puffs_msgop_p, ap->a_desc->vdesc_offset, v);
411 
412 	DPRINTF_VERBOSE(("checkop return %s (%d), vp %p: %d\n",
413 	    ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp, rv));
414 
415 	return rv;
416 }
417 
418 static int callremove(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
419 			    struct componentname *);
420 static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
421 			   struct componentname *);
422 static void callinactive(struct puffs_mount *, puffs_cookie_t, int);
423 static void callreclaim(struct puffs_mount *, puffs_cookie_t, int);
424 static int  flushvncache(struct vnode *, off_t, off_t, bool);
425 static void update_va(struct vnode *, struct vattr *, struct vattr *,
426 		      struct timespec *, struct timespec *, int);
427 static void update_parent(struct vnode *, struct vnode *);
428 
429 
430 #define PUFFS_ABORT_LOOKUP	1
431 #define PUFFS_ABORT_CREATE	2
432 #define PUFFS_ABORT_MKNOD	3
433 #define PUFFS_ABORT_MKDIR	4
434 #define PUFFS_ABORT_SYMLINK	5
435 
436 /*
437  * Press the pani^Wabort button!  Kernel resource allocation failed.
438  */
439 static void
440 puffs_abortbutton(struct puffs_mount *pmp, int what,
441 	puffs_cookie_t dck, puffs_cookie_t ck, struct componentname *cnp)
442 {
443 
444 	switch (what) {
445 	case PUFFS_ABORT_CREATE:
446 	case PUFFS_ABORT_MKNOD:
447 	case PUFFS_ABORT_SYMLINK:
448 		callremove(pmp, dck, ck, cnp);
449 		break;
450 	case PUFFS_ABORT_MKDIR:
451 		callrmdir(pmp, dck, ck, cnp);
452 		break;
453 	}
454 
455 	callinactive(pmp, ck, 0);
456 	callreclaim(pmp, ck, 1);
457 }
458 
459 /*
460  * Begin vnode operations.
461  *
462  * A word from the keymaster about locks: generally we don't want
463  * to use the vnode locks at all: it creates an ugly dependency between
464  * the userlandia file server and the kernel.  But we'll play along with
465  * the kernel vnode locks for now.  However, even currently we attempt
466  * to release locks as early as possible.  This is possible for some
467  * operations which a) don't need a locked vnode after the userspace op
468  * and b) return with the vnode unlocked.  Theoretically we could
469  * unlock-do op-lock for others and order the graph in userspace, but I
470  * don't want to think of the consequences for the time being.
471  */
472 
473 #define TTL_TO_TIMEOUT(ts) \
474     (hardclock_ticks + (ts->tv_sec * hz) + (ts->tv_nsec * hz / 1000000000))
475 #define TTL_VALID(ts) \
476     ((ts != NULL) && !((ts->tv_sec == 0) && (ts->tv_nsec == 0)))
477 #define TIMED_OUT(expire) \
478     ((int)((unsigned int)hardclock_ticks - (unsigned int)expire) > 0)
479 int
480 puffs_vnop_lookup(void *v)
481 {
482         struct vop_lookup_v2_args /* {
483 		const struct vnodeop_desc *a_desc;
484 		struct vnode *a_dvp;
485 		struct vnode **a_vpp;
486 		struct componentname *a_cnp;
487         } */ *ap = v;
488 	PUFFS_MSG_VARS(vn, lookup);
489 	struct puffs_mount *pmp;
490 	struct componentname *cnp;
491 	struct vnode *vp, *dvp, *cvp;
492 	struct puffs_node *dpn, *cpn;
493 	int isdot;
494 	int error;
495 
496 	pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
497 	cnp = ap->a_cnp;
498 	dvp = ap->a_dvp;
499 	cvp = NULL;
500 	cpn = NULL;
501 	*ap->a_vpp = NULL;
502 
503 	/* r/o fs?  we check create later to handle EEXIST */
504 	if ((cnp->cn_flags & ISLASTCN)
505 	    && (dvp->v_mount->mnt_flag & MNT_RDONLY)
506 	    && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
507 		return EROFS;
508 
509 	isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
510 
511 	DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n",
512 	    cnp->cn_nameptr, dvp, cnp->cn_nameiop));
513 
514 	/*
515 	 * If dotdot cache is enabled, add reference to .. and return.
516 	 */
517 	if (PUFFS_USE_DOTDOTCACHE(pmp) && (cnp->cn_flags & ISDOTDOT)) {
518 		vp = VPTOPP(ap->a_dvp)->pn_parent;
519 		vref(vp);
520 
521 		*ap->a_vpp = vp;
522 		return 0;
523 	}
524 
525 	/*
526 	 * Check if someone fed it into the cache
527 	 */
528 	if (!isdot && PUFFS_USE_NAMECACHE(pmp)) {
529 		int found, iswhiteout;
530 
531 		found = cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
532 				     cnp->cn_nameiop, cnp->cn_flags,
533 				     &iswhiteout, ap->a_vpp);
534 		if (iswhiteout) {
535 			cnp->cn_flags |= ISWHITEOUT;
536 		}
537 
538 		if (found && *ap->a_vpp != NULLVP && PUFFS_USE_FS_TTL(pmp)) {
539 			cvp = *ap->a_vpp;
540 			cpn = VPTOPP(cvp);
541 
542 			if (TIMED_OUT(cpn->pn_cn_timeout)) {
543 				cache_purge(cvp);
544 				/*
545 				 * cached vnode (cvp) is still referenced
546 				 * so that we can reuse it upon a new
547 				 * successful lookup.
548 				 */
549 				*ap->a_vpp = NULL;
550 				found = 0;
551 			}
552 		}
553 
554 		/*
555 		 * Do not use negative caching, since the filesystem
556 		 * provides no TTL for it.
557 		 */
558 		if (found && *ap->a_vpp == NULLVP && PUFFS_USE_FS_TTL(pmp))
559 			found = 0;
560 
561 		if (found) {
562 			return *ap->a_vpp == NULLVP ? ENOENT : 0;
563 		}
564 
565 		/*
566 		 * This is what would have been left in ERROR before
567 		 * the rearrangement of cache_lookup(). What with all
568 		 * the macros, I am not sure if this is a dead value
569 		 * below or not.
570 		 */
571 		error = -1;
572 	}
573 
574 	if (isdot) {
575 		/* deal with rename lookup semantics */
576 		if (cnp->cn_nameiop == RENAME && (cnp->cn_flags & ISLASTCN))
577 			return EISDIR;
578 
579 		vp = ap->a_dvp;
580 		vref(vp);
581 		*ap->a_vpp = vp;
582 		return 0;
583 	}
584 
585 	if (cvp != NULL) {
586 		if (vn_lock(cvp, LK_EXCLUSIVE) != 0) {
587 			vrele(cvp);
588 			cvp = NULL;
589 		} else
590 			mutex_enter(&cpn->pn_sizemtx);
591 	}
592 
593 	PUFFS_MSG_ALLOC(vn, lookup);
594 	puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
595 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
596 
597 	if (cnp->cn_flags & ISDOTDOT)
598 		VOP_UNLOCK(dvp);
599 
600 	puffs_msg_setinfo(park_lookup, PUFFSOP_VN,
601 	    PUFFS_VN_LOOKUP, VPTOPNC(dvp));
602 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error);
603 	DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
604 
605 	/*
606 	 * In case of error, there is no new vnode to play with, so be
607 	 * happy with the NULL value given to vpp in the beginning.
608 	 * Also, check if this really was an error or the target was not
609 	 * present.  Either treat it as a non-error for CREATE/RENAME or
610 	 * enter the component into the negative name cache (if desired).
611 	 */
612 	if (error) {
613 		error = checkerr(pmp, error, __func__);
614 		if (error == ENOENT) {
615 			/* don't allow to create files on r/o fs */
616 			if ((dvp->v_mount->mnt_flag & MNT_RDONLY)
617 			    && cnp->cn_nameiop == CREATE) {
618 				error = EROFS;
619 
620 			/* adjust values if we are creating */
621 			} else if ((cnp->cn_flags & ISLASTCN)
622 			    && (cnp->cn_nameiop == CREATE
623 			      || cnp->cn_nameiop == RENAME)) {
624 				error = EJUSTRETURN;
625 
626 			/* save negative cache entry */
627 			} else {
628 				if (PUFFS_USE_NAMECACHE(pmp) &&
629 				    !PUFFS_USE_FS_TTL(pmp))
630 					cache_enter(dvp, NULL, cnp->cn_nameptr,
631 						cnp->cn_namelen, cnp->cn_flags);
632 			}
633 		}
634 		goto out;
635 	}
636 
637 	/*
638 	 * Check that we don't get our parent node back, that would cause
639 	 * a pretty obvious deadlock.
640 	 */
641 	dpn = dvp->v_data;
642 	if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
643 		puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
644 		    "lookup produced parent cookie", lookup_msg->pvnr_newnode);
645 		error = EPROTO;
646 		goto out;
647 	}
648 
649 	/*
650 	 * Check if we looked up the cached vnode
651 	 */
652 	vp = NULL;
653 	if (cvp && (VPTOPP(cvp)->pn_cookie == lookup_msg->pvnr_newnode)) {
654 		int grace;
655 
656 		/*
657 		 * Bump grace time of this node so that it does not get
658 		 * reclaimed too fast. We try to increase a bit more the
659 		 * lifetime of busiest * nodes - with some limits.
660 		 */
661 		grace = 10 * puffs_sopreq_expire_timeout;
662 		cpn->pn_cn_grace = hardclock_ticks + grace;
663 		vp = cvp;
664 	}
665 
666 	/*
667 	 * No cached vnode available, or the cached vnode does not
668 	 * match the userland cookie anymore: is the node known?
669 	 */
670 	if (vp == NULL) {
671 		error = puffs_getvnode(dvp->v_mount,
672 		    lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
673 		    lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp);
674 		if (error) {
675 			puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP,
676 			    VPTOPNC(dvp), lookup_msg->pvnr_newnode,
677 			    ap->a_cnp);
678 			goto out;
679 		}
680 
681 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
682 	}
683 
684 	/*
685 	 * Update cache and TTL
686 	 */
687 	if (PUFFS_USE_FS_TTL(pmp)) {
688 		struct timespec *va_ttl = &lookup_msg->pvnr_va_ttl;
689 		struct timespec *cn_ttl = &lookup_msg->pvnr_cn_ttl;
690 		update_va(vp, NULL, &lookup_msg->pvnr_va,
691 			  va_ttl, cn_ttl, SETATTR_CHSIZE);
692 	}
693 
694 	KASSERT(lookup_msg->pvnr_newnode == VPTOPP(vp)->pn_cookie);
695 	*ap->a_vpp = vp;
696 
697 	if (PUFFS_USE_NAMECACHE(pmp))
698 		cache_enter(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen,
699 			    cnp->cn_flags);
700 
701 	/* XXX */
702 	if ((lookup_msg->pvnr_cn.pkcn_flags & REQUIREDIR) == 0)
703 		cnp->cn_flags &= ~REQUIREDIR;
704 	if (lookup_msg->pvnr_cn.pkcn_consume)
705 		cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume,
706 		    strlen(cnp->cn_nameptr) - cnp->cn_namelen);
707 
708 	VPTOPP(vp)->pn_nlookup++;
709 
710 	if (PUFFS_USE_DOTDOTCACHE(pmp) &&
711 	    (VPTOPP(vp)->pn_parent != dvp))
712 		update_parent(vp, dvp);
713 
714  out:
715 	if (cvp != NULL) {
716 		mutex_exit(&cpn->pn_sizemtx);
717 
718 		if (error || (cvp != vp))
719 			vput(cvp);
720 	}
721 	if (error == 0)
722 		VOP_UNLOCK(*ap->a_vpp);
723 
724 	if (cnp->cn_flags & ISDOTDOT)
725 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
726 
727 	DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp));
728 	PUFFS_MSG_RELEASE(lookup);
729 	return error;
730 }
731 
732 #define REFPN_AND_UNLOCKVP(a, b)					\
733 do {									\
734 	mutex_enter(&b->pn_mtx);					\
735 	puffs_referencenode(b);						\
736 	mutex_exit(&b->pn_mtx);						\
737 	VOP_UNLOCK(a);						\
738 } while (/*CONSTCOND*/0)
739 
740 #define REFPN(b)							\
741 do {									\
742 	mutex_enter(&b->pn_mtx);					\
743 	puffs_referencenode(b);						\
744 	mutex_exit(&b->pn_mtx);						\
745 } while (/*CONSTCOND*/0)
746 
747 #define RELEPN_AND_VP(a, b)						\
748 do {									\
749 	puffs_releasenode(b);						\
750 	vrele(a);							\
751 } while (/*CONSTCOND*/0)
752 
753 int
754 puffs_vnop_create(void *v)
755 {
756 	struct vop_create_v3_args /* {
757 		const struct vnodeop_desc *a_desc;
758 		struct vnode *a_dvp;
759 		struct vnode **a_vpp;
760 		struct componentname *a_cnp;
761 		struct vattr *a_vap;
762 	} */ *ap = v;
763 	PUFFS_MSG_VARS(vn, create);
764 	struct vnode *dvp = ap->a_dvp;
765 	struct puffs_node *dpn = VPTOPP(dvp);
766 	struct componentname *cnp = ap->a_cnp;
767 	struct mount *mp = dvp->v_mount;
768 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
769 	int error;
770 
771 	DPRINTF(("puffs_create: dvp %p, cnp: %s\n",
772 	    dvp, ap->a_cnp->cn_nameptr));
773 
774 	PUFFS_MSG_ALLOC(vn, create);
775 	puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred,
776 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
777 	create_msg->pvnr_va = *ap->a_vap;
778 	puffs_msg_setinfo(park_create, PUFFSOP_VN,
779 	    PUFFS_VN_CREATE, VPTOPNC(dvp));
780 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_create, dvp->v_data, NULL, error);
781 
782 	error = checkerr(pmp, error, __func__);
783 	if (error)
784 		goto out;
785 
786 	error = puffs_newnode(mp, dvp, ap->a_vpp,
787 	    create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0);
788 	if (error) {
789 		puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie,
790 		    create_msg->pvnr_newnode, cnp);
791 		goto out;
792 	}
793 
794 	if (PUFFS_USE_FS_TTL(pmp)) {
795 		struct timespec *va_ttl = &create_msg->pvnr_va_ttl;
796 		struct timespec *cn_ttl = &create_msg->pvnr_cn_ttl;
797 		struct vattr *rvap = &create_msg->pvnr_va;
798 
799 		update_va(*ap->a_vpp, NULL, rvap,
800 			  va_ttl, cn_ttl, SETATTR_CHSIZE);
801 	}
802 
803 	VPTOPP(*ap->a_vpp)->pn_nlookup++;
804 
805 	if (PUFFS_USE_DOTDOTCACHE(pmp) &&
806 	    (VPTOPP(*ap->a_vpp)->pn_parent != dvp))
807 		update_parent(*ap->a_vpp, dvp);
808 
809  out:
810 	DPRINTF(("puffs_create: return %d\n", error));
811 	PUFFS_MSG_RELEASE(create);
812 	return error;
813 }
814 
815 int
816 puffs_vnop_mknod(void *v)
817 {
818 	struct vop_mknod_v3_args /* {
819 		const struct vnodeop_desc *a_desc;
820 		struct vnode *a_dvp;
821 		struct vnode **a_vpp;
822 		struct componentname *a_cnp;
823 		struct vattr *a_vap;
824 	} */ *ap = v;
825 	PUFFS_MSG_VARS(vn, mknod);
826 	struct vnode *dvp = ap->a_dvp;
827 	struct puffs_node *dpn = VPTOPP(dvp);
828 	struct componentname *cnp = ap->a_cnp;
829 	struct mount *mp = dvp->v_mount;
830 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
831 	int error;
832 
833 	PUFFS_MSG_ALLOC(vn, mknod);
834 	puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
835 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
836 	mknod_msg->pvnr_va = *ap->a_vap;
837 	puffs_msg_setinfo(park_mknod, PUFFSOP_VN,
838 	    PUFFS_VN_MKNOD, VPTOPNC(dvp));
839 
840 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);
841 
842 	error = checkerr(pmp, error, __func__);
843 	if (error)
844 		goto out;
845 
846 	error = puffs_newnode(mp, dvp, ap->a_vpp,
847 	    mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type,
848 	    ap->a_vap->va_rdev);
849 	if (error) {
850 		puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie,
851 		    mknod_msg->pvnr_newnode, cnp);
852 		goto out;
853 	}
854 
855 	if (PUFFS_USE_FS_TTL(pmp)) {
856 		struct timespec *va_ttl = &mknod_msg->pvnr_va_ttl;
857 		struct timespec *cn_ttl = &mknod_msg->pvnr_cn_ttl;
858 		struct vattr *rvap = &mknod_msg->pvnr_va;
859 
860 		update_va(*ap->a_vpp, NULL, rvap,
861 			   va_ttl, cn_ttl, SETATTR_CHSIZE);
862 	}
863 
864 	VPTOPP(*ap->a_vpp)->pn_nlookup++;
865 
866 	if (PUFFS_USE_DOTDOTCACHE(pmp) &&
867 	    (VPTOPP(*ap->a_vpp)->pn_parent != dvp))
868 		update_parent(*ap->a_vpp, dvp);
869 
870  out:
871 	PUFFS_MSG_RELEASE(mknod);
872 	return error;
873 }
874 
875 int
876 puffs_vnop_open(void *v)
877 {
878 	struct vop_open_args /* {
879 		const struct vnodeop_desc *a_desc;
880 		struct vnode *a_vp;
881 		int a_mode;
882 		kauth_cred_t a_cred;
883 	} */ *ap = v;
884 	PUFFS_MSG_VARS(vn, open);
885 	struct vnode *vp = ap->a_vp;
886 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
887 	struct puffs_node *pn = VPTOPP(vp);
888 	int mode = ap->a_mode;
889 	int error;
890 
891 	DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
892 
893 	if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
894 		ERROUT(EROFS);
895 
896 	if (!EXISTSOP(pmp, OPEN))
897 		ERROUT(0);
898 
899 	PUFFS_MSG_ALLOC(vn, open);
900 	open_msg->pvnr_mode = mode;
901 	puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
902 	puffs_msg_setinfo(park_open, PUFFSOP_VN,
903 	    PUFFS_VN_OPEN, VPTOPNC(vp));
904 
905 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error);
906 	error = checkerr(pmp, error, __func__);
907 
908 	if (open_msg->pvnr_oflags & PUFFS_OPEN_IO_DIRECT) {
909 		if (mode & FREAD)
910 			pn->pn_stat |= PNODE_RDIRECT;
911 		if (mode & FWRITE)
912 			pn->pn_stat |= PNODE_WDIRECT;
913 	}
914  out:
915 	DPRINTF(("puffs_open: returning %d\n", error));
916 	PUFFS_MSG_RELEASE(open);
917 	return error;
918 }
919 
920 int
921 puffs_vnop_close(void *v)
922 {
923 	struct vop_close_args /* {
924 		const struct vnodeop_desc *a_desc;
925 		struct vnode *a_vp;
926 		int a_fflag;
927 		kauth_cred_t a_cred;
928 	} */ *ap = v;
929 	PUFFS_MSG_VARS(vn, close);
930 	struct vnode *vp = ap->a_vp;
931 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
932 
933 	PUFFS_MSG_ALLOC(vn, close);
934 	puffs_msg_setfaf(park_close);
935 	close_msg->pvnr_fflag = ap->a_fflag;
936 	puffs_credcvt(&close_msg->pvnr_cred, ap->a_cred);
937 	puffs_msg_setinfo(park_close, PUFFSOP_VN,
938 	    PUFFS_VN_CLOSE, VPTOPNC(vp));
939 
940 	puffs_msg_enqueue(pmp, park_close);
941 	PUFFS_MSG_RELEASE(close);
942 	return 0;
943 }
944 
945 int
946 puffs_vnop_access(void *v)
947 {
948 	struct vop_access_args /* {
949 		const struct vnodeop_desc *a_desc;
950 		struct vnode *a_vp;
951 		int a_mode;
952 		kauth_cred_t a_cred;
953 	} */ *ap = v;
954 	PUFFS_MSG_VARS(vn, access);
955 	struct vnode *vp = ap->a_vp;
956 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
957 	int mode = ap->a_mode;
958 	int error;
959 
960 	if (mode & VWRITE) {
961 		switch (vp->v_type) {
962 		case VDIR:
963 		case VLNK:
964 		case VREG:
965 			if ((vp->v_mount->mnt_flag & MNT_RDONLY)
966 			    || !EXISTSOP(pmp, WRITE))
967 				return EROFS;
968 			break;
969 		default:
970 			break;
971 		}
972 	}
973 
974 	if (!EXISTSOP(pmp, ACCESS))
975 		return 0;
976 
977 	PUFFS_MSG_ALLOC(vn, access);
978 	access_msg->pvnr_mode = ap->a_mode;
979 	puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
980 	puffs_msg_setinfo(park_access, PUFFSOP_VN,
981 	    PUFFS_VN_ACCESS, VPTOPNC(vp));
982 
983 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error);
984 	error = checkerr(pmp, error, __func__);
985 	PUFFS_MSG_RELEASE(access);
986 
987 	return error;
988 }
989 
990 static void
991 update_va(struct vnode *vp, struct vattr *vap, struct vattr *rvap,
992 	  struct timespec *va_ttl, struct timespec *cn_ttl, int flags)
993 {
994 	struct puffs_node *pn = VPTOPP(vp);
995 
996 	if (TTL_VALID(cn_ttl)) {
997 		pn->pn_cn_timeout = TTL_TO_TIMEOUT(cn_ttl);
998 		pn->pn_cn_grace = MAX(pn->pn_cn_timeout, pn->pn_cn_grace);
999 	}
1000 
1001 	/*
1002 	 * Don't listen to the file server regarding special device
1003 	 * size info, the file server doesn't know anything about them.
1004 	 */
1005 	if (vp->v_type == VBLK || vp->v_type == VCHR)
1006 		rvap->va_size = vp->v_size;
1007 
1008 	/* Ditto for blocksize (ufs comment: this doesn't belong here) */
1009 	if (vp->v_type == VBLK)
1010 		rvap->va_blocksize = BLKDEV_IOSIZE;
1011 	else if (vp->v_type == VCHR)
1012 		rvap->va_blocksize = MAXBSIZE;
1013 
1014 	if (vap != NULL) {
1015 		(void) memcpy(vap, rvap, sizeof(struct vattr));
1016 		vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1017 
1018 		if (pn->pn_stat & PNODE_METACACHE_ATIME)
1019 			vap->va_atime = pn->pn_mc_atime;
1020 		if (pn->pn_stat & PNODE_METACACHE_CTIME)
1021 			vap->va_ctime = pn->pn_mc_ctime;
1022 		if (pn->pn_stat & PNODE_METACACHE_MTIME)
1023 			vap->va_mtime = pn->pn_mc_mtime;
1024 		if (pn->pn_stat & PNODE_METACACHE_SIZE)
1025 			vap->va_size = pn->pn_mc_size;
1026 	}
1027 
1028 	if (!(pn->pn_stat & PNODE_METACACHE_SIZE) && (flags & SETATTR_CHSIZE)) {
1029 		if (rvap->va_size != VNOVAL
1030 		    && vp->v_type != VBLK && vp->v_type != VCHR) {
1031 			uvm_vnp_setsize(vp, rvap->va_size);
1032 			pn->pn_serversize = rvap->va_size;
1033 		}
1034 	}
1035 
1036 	if ((va_ttl != NULL) && TTL_VALID(va_ttl)) {
1037 		if (pn->pn_va_cache == NULL)
1038 			pn->pn_va_cache = pool_get(&puffs_vapool, PR_WAITOK);
1039 
1040 		(void)memcpy(pn->pn_va_cache, rvap, sizeof(*rvap));
1041 
1042 		pn->pn_va_timeout = TTL_TO_TIMEOUT(va_ttl);
1043 	}
1044 }
1045 
1046 static void
1047 update_parent(struct vnode *vp, struct vnode *dvp)
1048 {
1049 	struct puffs_node *pn = VPTOPP(vp);
1050 
1051 	if (pn->pn_parent != NULL) {
1052 		KASSERT(pn->pn_parent != dvp);
1053 		vrele(pn->pn_parent);
1054 	}
1055 
1056 	vref(dvp);
1057 	pn->pn_parent = dvp;
1058 }
1059 
1060 int
1061 puffs_vnop_getattr(void *v)
1062 {
1063 	struct vop_getattr_args /* {
1064 		const struct vnodeop_desc *a_desc;
1065 		struct vnode *a_vp;
1066 		struct vattr *a_vap;
1067 		kauth_cred_t a_cred;
1068 	} */ *ap = v;
1069 	PUFFS_MSG_VARS(vn, getattr);
1070 	struct vnode *vp = ap->a_vp;
1071 	struct mount *mp = vp->v_mount;
1072 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1073 	struct vattr *vap, *rvap;
1074 	struct puffs_node *pn = VPTOPP(vp);
1075 	struct timespec *va_ttl = NULL;
1076 	int error = 0;
1077 
1078 	/*
1079 	 * A lock is required so that we do not race with
1080 	 * setattr, write and fsync when changing vp->v_size.
1081 	 * This is critical, since setting a stall smaler value
1082 	 * triggers a file truncate in uvm_vnp_setsize(), which
1083 	 * most of the time means data corruption (a chunk of
1084 	 * data is replaced by zeroes). This can be removed if
1085 	 * we decide one day that VOP_GETATTR must operate on
1086 	 * a locked vnode.
1087 	 *
1088 	 * XXX Should be useless now that VOP_GETATTR has been
1089 	 *     fixed to always require a shared lock at least.
1090 	 */
1091 	mutex_enter(&pn->pn_sizemtx);
1092 
1093 	REFPN(pn);
1094 	vap = ap->a_vap;
1095 
1096 	if (PUFFS_USE_FS_TTL(pmp)) {
1097 		if (!TIMED_OUT(pn->pn_va_timeout)) {
1098 			update_va(vp, vap, pn->pn_va_cache,
1099 				  NULL, NULL, SETATTR_CHSIZE);
1100 			goto out2;
1101 		}
1102 	}
1103 
1104 	PUFFS_MSG_ALLOC(vn, getattr);
1105 	vattr_null(&getattr_msg->pvnr_va);
1106 	puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred);
1107 	puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
1108 	    PUFFS_VN_GETATTR, VPTOPNC(vp));
1109 
1110 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
1111 	error = checkerr(pmp, error, __func__);
1112 	if (error)
1113 		goto out;
1114 
1115 	rvap = &getattr_msg->pvnr_va;
1116 
1117 	if (PUFFS_USE_FS_TTL(pmp))
1118 		va_ttl = &getattr_msg->pvnr_va_ttl;
1119 
1120 	update_va(vp, vap, rvap, va_ttl, NULL, SETATTR_CHSIZE);
1121 
1122  out:
1123 	PUFFS_MSG_RELEASE(getattr);
1124 
1125  out2:
1126 	puffs_releasenode(pn);
1127 
1128 	mutex_exit(&pn->pn_sizemtx);
1129 
1130 	return error;
1131 }
1132 
1133 static int
1134 dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags)
1135 {
1136 	PUFFS_MSG_VARS(vn, setattr);
1137 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1138 	struct puffs_node *pn = vp->v_data;
1139 	int error = 0;
1140 
1141 	KASSERT(!(flags & SETATTR_CHSIZE) || mutex_owned(&pn->pn_sizemtx));
1142 
1143 	if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
1144 	    (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
1145 	    || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
1146 	    || vap->va_mode != (mode_t)VNOVAL))
1147 		return EROFS;
1148 
1149 	if ((vp->v_mount->mnt_flag & MNT_RDONLY)
1150 	    && vp->v_type == VREG && vap->va_size != VNOVAL)
1151 		return EROFS;
1152 
1153 	/*
1154 	 * Flush metacache first.  If we are called with some explicit
1155 	 * parameters, treat them as information overriding metacache
1156 	 * information.
1157 	 */
1158 	if (pn->pn_stat & PNODE_METACACHE_MASK) {
1159 		if ((pn->pn_stat & PNODE_METACACHE_ATIME)
1160 		    && vap->va_atime.tv_sec == VNOVAL)
1161 			vap->va_atime = pn->pn_mc_atime;
1162 		if ((pn->pn_stat & PNODE_METACACHE_CTIME)
1163 		    && vap->va_ctime.tv_sec == VNOVAL)
1164 			vap->va_ctime = pn->pn_mc_ctime;
1165 		if ((pn->pn_stat & PNODE_METACACHE_MTIME)
1166 		    && vap->va_mtime.tv_sec == VNOVAL)
1167 			vap->va_mtime = pn->pn_mc_mtime;
1168 		if ((pn->pn_stat & PNODE_METACACHE_SIZE)
1169 		    && vap->va_size == VNOVAL)
1170 			vap->va_size = pn->pn_mc_size;
1171 
1172 		pn->pn_stat &= ~PNODE_METACACHE_MASK;
1173 	}
1174 
1175 	/*
1176 	 * Flush attribute cache so that another thread do
1177 	 * not get a stale value during the operation.
1178 	 */
1179 	if (PUFFS_USE_FS_TTL(pmp))
1180 		pn->pn_va_timeout = 0;
1181 
1182 	PUFFS_MSG_ALLOC(vn, setattr);
1183 	(void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
1184 	puffs_credcvt(&setattr_msg->pvnr_cred, cred);
1185 	puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
1186 	    PUFFS_VN_SETATTR, VPTOPNC(vp));
1187 	if (flags & SETATTR_ASYNC)
1188 		puffs_msg_setfaf(park_setattr);
1189 
1190 	puffs_msg_enqueue(pmp, park_setattr);
1191 	if ((flags & SETATTR_ASYNC) == 0)
1192 		error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
1193 
1194 	if ((error == 0) && PUFFS_USE_FS_TTL(pmp)) {
1195 		struct timespec *va_ttl = &setattr_msg->pvnr_va_ttl;
1196 		struct vattr *rvap = &setattr_msg->pvnr_va;
1197 
1198 		update_va(vp, NULL, rvap, va_ttl, NULL, flags);
1199 	}
1200 
1201 	PUFFS_MSG_RELEASE(setattr);
1202 	if ((flags & SETATTR_ASYNC) == 0) {
1203 		error = checkerr(pmp, error, __func__);
1204 		if (error)
1205 			return error;
1206 	} else {
1207 		error = 0;
1208 	}
1209 
1210 	if (vap->va_size != VNOVAL) {
1211 		pn->pn_serversize = vap->va_size;
1212 		if (flags & SETATTR_CHSIZE)
1213 			uvm_vnp_setsize(vp, vap->va_size);
1214 	}
1215 
1216 	return 0;
1217 }
1218 
1219 int
1220 puffs_vnop_setattr(void *v)
1221 {
1222 	struct vop_getattr_args /* {
1223 		const struct vnodeop_desc *a_desc;
1224 		struct vnode *a_vp;
1225 		struct vattr *a_vap;
1226 		kauth_cred_t a_cred;
1227 	} */ *ap = v;
1228 	struct puffs_node *pn = ap->a_vp->v_data;
1229 	int error;
1230 
1231 	mutex_enter(&pn->pn_sizemtx);
1232 	error = dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE);
1233 	mutex_exit(&pn->pn_sizemtx);
1234 
1235 	return error;
1236 }
1237 
1238 static __inline int
1239 doinact(struct puffs_mount *pmp, int iaflag)
1240 {
1241 
1242 	if (EXISTSOP(pmp, INACTIVE))
1243 		if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
1244 			if (iaflag || ALLOPS(pmp))
1245 				return 1;
1246 			else
1247 				return 0;
1248 		else
1249 			return 1;
1250 	else
1251 		return 0;
1252 }
1253 
1254 static void
1255 callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
1256 {
1257 	PUFFS_MSG_VARS(vn, inactive);
1258 
1259 	if (doinact(pmp, iaflag)) {
1260 		PUFFS_MSG_ALLOC(vn, inactive);
1261 		puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1262 		    PUFFS_VN_INACTIVE, ck);
1263 		PUFFS_MSG_ENQUEUEWAIT_NOERROR(pmp, park_inactive);
1264 		PUFFS_MSG_RELEASE(inactive);
1265 	}
1266 }
1267 
1268 /* XXX: callinactive can't setback */
1269 int
1270 puffs_vnop_inactive(void *v)
1271 {
1272 	struct vop_inactive_args /* {
1273 		const struct vnodeop_desc *a_desc;
1274 		struct vnode *a_vp;
1275 	} */ *ap = v;
1276 	PUFFS_MSG_VARS(vn, inactive);
1277 	struct vnode *vp = ap->a_vp;
1278 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1279 	struct puffs_node *pnode;
1280 	bool recycle = false;
1281 
1282 	pnode = vp->v_data;
1283 	mutex_enter(&pnode->pn_sizemtx);
1284 
1285 	if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
1286 		flushvncache(vp, 0, 0, false);
1287 		PUFFS_MSG_ALLOC(vn, inactive);
1288 		puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1289 		    PUFFS_VN_INACTIVE, VPTOPNC(vp));
1290 		PUFFS_MSG_ENQUEUEWAIT2_NOERROR(pmp, park_inactive, vp->v_data,
1291 		    NULL);
1292 		PUFFS_MSG_RELEASE(inactive);
1293 	}
1294 	pnode->pn_stat &= ~PNODE_DOINACT;
1295 
1296 	/*
1297 	 * file server thinks it's gone?  then don't be afraid care,
1298 	 * node's life was already all it would ever be
1299 	 */
1300 	if (pnode->pn_stat & PNODE_NOREFS) {
1301 		pnode->pn_stat |= PNODE_DYING;
1302 		recycle = true;
1303 	}
1304 
1305 	/*
1306 	 * Handle node TTL.
1307 	 * If grace has already timed out, make it reclaimed.
1308 	 * Otherwise, we queue its expiration by sop thread, so
1309 	 * that it does not remain for ages in the freelist,
1310 	 * holding memory in userspace, while we will have
1311 	 * to look it up again anyway.
1312 	 */
1313 	if (PUFFS_USE_FS_TTL(pmp) && !(vp->v_vflag & VV_ROOT) && !recycle) {
1314 		bool incache = !TIMED_OUT(pnode->pn_cn_timeout);
1315 		bool ingrace = !TIMED_OUT(pnode->pn_cn_grace);
1316 		bool reclaimqueued = pnode->pn_stat & PNODE_SOPEXP;
1317 
1318 		if (!incache && !ingrace && !reclaimqueued) {
1319 			pnode->pn_stat |= PNODE_DYING;
1320 			recycle = true;
1321 		}
1322 
1323 		if (!recycle && !reclaimqueued) {
1324 			struct puffs_sopreq *psopr;
1325 			int at = MAX(pnode->pn_cn_grace, pnode->pn_cn_timeout);
1326 
1327 			KASSERT(curlwp != uvm.pagedaemon_lwp);
1328 			psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
1329 			psopr->psopr_ck = VPTOPNC(pnode->pn_vp);
1330 			psopr->psopr_sopreq = PUFFS_SOPREQ_EXPIRE;
1331 			psopr->psopr_at = at;
1332 
1333 			mutex_enter(&pmp->pmp_sopmtx);
1334 
1335 			/*
1336 			 * If thread has disapeared, just give up. The
1337 			 * fs is being unmounted and the node will be
1338 			 * be reclaimed anyway.
1339 			 *
1340 			 * Otherwise, we queue the request but do not
1341 			 * immediatly signal the thread, as the node
1342 			 * has not been expired yet.
1343 			 */
1344 			if (pmp->pmp_sopthrcount == 0) {
1345 				kmem_free(psopr, sizeof(*psopr));
1346 			} else {
1347 				TAILQ_INSERT_TAIL(&pmp->pmp_sopnodereqs,
1348 				    psopr, psopr_entries);
1349 				pnode->pn_stat |= PNODE_SOPEXP;
1350 			}
1351 
1352 			mutex_exit(&pmp->pmp_sopmtx);
1353 		}
1354 	}
1355 
1356 	*ap->a_recycle = recycle;
1357 
1358 	mutex_exit(&pnode->pn_sizemtx);
1359 	VOP_UNLOCK(vp);
1360 
1361 	return 0;
1362 }
1363 
1364 static void
1365 callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck, int nlookup)
1366 {
1367 	PUFFS_MSG_VARS(vn, reclaim);
1368 
1369 	if (!EXISTSOP(pmp, RECLAIM))
1370 		return;
1371 
1372 	PUFFS_MSG_ALLOC(vn, reclaim);
1373 	reclaim_msg->pvnr_nlookup = nlookup;
1374 	puffs_msg_setfaf(park_reclaim);
1375 	puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);
1376 
1377 	puffs_msg_enqueue(pmp, park_reclaim);
1378 	PUFFS_MSG_RELEASE(reclaim);
1379 	return;
1380 }
1381 
1382 /*
1383  * always FAF, we don't really care if the server wants to fail to
1384  * reclaim the node or not
1385  */
1386 int
1387 puffs_vnop_reclaim(void *v)
1388 {
1389 	struct vop_reclaim_args /* {
1390 		const struct vnodeop_desc *a_desc;
1391 		struct vnode *a_vp;
1392 	} */ *ap = v;
1393 	struct vnode *vp = ap->a_vp;
1394 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1395 	bool notifyserver = true;
1396 
1397 	/*
1398 	 * first things first: check if someone is trying to reclaim the
1399 	 * root vnode.  do not allow that to travel to userspace.
1400 	 * Note that we don't need to take the lock similarly to
1401 	 * puffs_root(), since there is only one of us.
1402 	 */
1403 	if (vp->v_vflag & VV_ROOT) {
1404 		mutex_enter(&pmp->pmp_lock);
1405 		KASSERT(pmp->pmp_root != NULL);
1406 		pmp->pmp_root = NULL;
1407 		mutex_exit(&pmp->pmp_lock);
1408 		notifyserver = false;
1409 	}
1410 
1411 	/*
1412 	 * purge info from kernel before issueing FAF, since we
1413 	 * don't really know when we'll get around to it after
1414 	 * that and someone might race us into node creation
1415 	 */
1416 	mutex_enter(&pmp->pmp_lock);
1417 	if (PUFFS_USE_NAMECACHE(pmp))
1418 		cache_purge(vp);
1419 	mutex_exit(&pmp->pmp_lock);
1420 
1421 	if (notifyserver) {
1422 		int nlookup = VPTOPP(vp)->pn_nlookup;
1423 
1424 		callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp), nlookup);
1425 	}
1426 
1427 	if (PUFFS_USE_DOTDOTCACHE(pmp)) {
1428 		if (__predict_true(VPTOPP(vp)->pn_parent != NULL))
1429 			vrele(VPTOPP(vp)->pn_parent);
1430 		else
1431 			KASSERT(vp->v_vflag & VV_ROOT);
1432 	}
1433 
1434 	puffs_putvnode(vp);
1435 
1436 	return 0;
1437 }
1438 
1439 #define CSIZE sizeof(**ap->a_cookies)
1440 int
1441 puffs_vnop_readdir(void *v)
1442 {
1443 	struct vop_readdir_args /* {
1444 		const struct vnodeop_desc *a_desc;
1445 		struct vnode *a_vp;
1446 		struct uio *a_uio;
1447 		kauth_cred_t a_cred;
1448 		int *a_eofflag;
1449 		off_t **a_cookies;
1450 		int *a_ncookies;
1451 	} */ *ap = v;
1452 	PUFFS_MSG_VARS(vn, readdir);
1453 	struct vnode *vp = ap->a_vp;
1454 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1455 	size_t argsize, tomove, cookiemem, cookiesmax;
1456 	struct uio *uio = ap->a_uio;
1457 	size_t howmuch, resid;
1458 	int error;
1459 
1460 	/*
1461 	 * ok, so we need: resid + cookiemem = maxreq
1462 	 * => resid + cookiesize * (resid/minsize) = maxreq
1463 	 * => resid + cookiesize/minsize * resid = maxreq
1464 	 * => (cookiesize/minsize + 1) * resid = maxreq
1465 	 * => resid = maxreq / (cookiesize/minsize + 1)
1466 	 *
1467 	 * Since cookiesize <= minsize and we're not very big on floats,
1468 	 * we approximate that to be 1.  Therefore:
1469 	 *
1470 	 * resid = maxreq / 2;
1471 	 *
1472 	 * Well, at least we didn't have to use differential equations
1473 	 * or the Gram-Schmidt process.
1474 	 *
1475 	 * (yes, I'm very afraid of this)
1476 	 */
1477 	KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1478 
1479 	if (ap->a_cookies) {
1480 		KASSERT(ap->a_ncookies != NULL);
1481 		if (pmp->pmp_args.pa_fhsize == 0)
1482 			return EOPNOTSUPP;
1483 		resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1484 		cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1485 		cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1486 	} else {
1487 		resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1488 		cookiesmax = 0;
1489 		cookiemem = 0;
1490 	}
1491 
1492 	argsize = sizeof(struct puffs_vnmsg_readdir);
1493 	tomove = resid + cookiemem;
1494 	puffs_msgmem_alloc(argsize + tomove, &park_readdir,
1495 	    (void *)&readdir_msg, 1);
1496 
1497 	puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
1498 	readdir_msg->pvnr_offset = uio->uio_offset;
1499 	readdir_msg->pvnr_resid = resid;
1500 	readdir_msg->pvnr_ncookies = cookiesmax;
1501 	readdir_msg->pvnr_eofflag = 0;
1502 	readdir_msg->pvnr_dentoff = cookiemem;
1503 	puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
1504 	    PUFFS_VN_READDIR, VPTOPNC(vp));
1505 	puffs_msg_setdelta(park_readdir, tomove);
1506 
1507 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
1508 	error = checkerr(pmp, error, __func__);
1509 	if (error)
1510 		goto out;
1511 
1512 	/* userspace is cheating? */
1513 	if (readdir_msg->pvnr_resid > resid) {
1514 		puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1515 		    "resid grew", VPTOPNC(vp));
1516 		ERROUT(EPROTO);
1517 	}
1518 	if (readdir_msg->pvnr_ncookies > cookiesmax) {
1519 		puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1520 		    "too many cookies", VPTOPNC(vp));
1521 		ERROUT(EPROTO);
1522 	}
1523 
1524 	/* check eof */
1525 	if (readdir_msg->pvnr_eofflag)
1526 		*ap->a_eofflag = 1;
1527 
1528 	/* bouncy-wouncy with the directory data */
1529 	howmuch = resid - readdir_msg->pvnr_resid;
1530 
1531 	/* force eof if no data was returned (getcwd() needs this) */
1532 	if (howmuch == 0) {
1533 		*ap->a_eofflag = 1;
1534 		goto out;
1535 	}
1536 
1537 	error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
1538 	if (error)
1539 		goto out;
1540 
1541 	/* provide cookies to caller if so desired */
1542 	if (ap->a_cookies) {
1543 		KASSERT(curlwp != uvm.pagedaemon_lwp);
1544 		*ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE,
1545 		    M_TEMP, M_WAITOK);
1546 		*ap->a_ncookies = readdir_msg->pvnr_ncookies;
1547 		memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
1548 		    *ap->a_ncookies*CSIZE);
1549 	}
1550 
1551 	/* next readdir starts here */
1552 	uio->uio_offset = readdir_msg->pvnr_offset;
1553 
1554  out:
1555 	puffs_msgmem_release(park_readdir);
1556 	return error;
1557 }
1558 #undef CSIZE
1559 
1560 /*
1561  * poll works by consuming the bitmask in pn_revents.  If there are
1562  * events available, poll returns immediately.  If not, it issues a
1563  * poll to userspace, selrecords itself and returns with no available
1564  * events.  When the file server returns, it executes puffs_parkdone_poll(),
1565  * where available events are added to the bitmask.  selnotify() is
1566  * then also executed by that function causing us to enter here again
1567  * and hopefully find the missing bits (unless someone got them first,
1568  * in which case it starts all over again).
1569  */
1570 int
1571 puffs_vnop_poll(void *v)
1572 {
1573 	struct vop_poll_args /* {
1574 		const struct vnodeop_desc *a_desc;
1575 		struct vnode *a_vp;
1576 		int a_events;
1577 	} */ *ap = v;
1578 	PUFFS_MSG_VARS(vn, poll);
1579 	struct vnode *vp = ap->a_vp;
1580 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1581 	struct puffs_node *pn = vp->v_data;
1582 	int events;
1583 
1584 	if (EXISTSOP(pmp, POLL)) {
1585 		mutex_enter(&pn->pn_mtx);
1586 		events = pn->pn_revents & ap->a_events;
1587 		if (events & ap->a_events) {
1588 			pn->pn_revents &= ~ap->a_events;
1589 			mutex_exit(&pn->pn_mtx);
1590 
1591 			return events;
1592 		} else {
1593 			puffs_referencenode(pn);
1594 			mutex_exit(&pn->pn_mtx);
1595 
1596 			PUFFS_MSG_ALLOC(vn, poll);
1597 			poll_msg->pvnr_events = ap->a_events;
1598 			puffs_msg_setinfo(park_poll, PUFFSOP_VN,
1599 			    PUFFS_VN_POLL, VPTOPNC(vp));
1600 			puffs_msg_setcall(park_poll, puffs_parkdone_poll, pn);
1601 			selrecord(curlwp, &pn->pn_sel);
1602 
1603 			PUFFS_MSG_ENQUEUEWAIT2_NOERROR(pmp, park_poll,
1604 			    vp->v_data, NULL);
1605 			PUFFS_MSG_RELEASE(poll);
1606 
1607 			return 0;
1608 		}
1609 	} else {
1610 		return genfs_poll(v);
1611 	}
1612 }
1613 
1614 static int
1615 flushvncache(struct vnode *vp, off_t offlo, off_t offhi, bool wait)
1616 {
1617 	struct puffs_node *pn = VPTOPP(vp);
1618 	struct vattr va;
1619 	int pflags, error;
1620 
1621 	/* flush out information from our metacache, see vop_setattr */
1622 	if (pn->pn_stat & PNODE_METACACHE_MASK
1623 	    && (pn->pn_stat & PNODE_DYING) == 0) {
1624 		vattr_null(&va);
1625 		error = dosetattr(vp, &va, FSCRED,
1626 		    SETATTR_CHSIZE | (wait ? 0 : SETATTR_ASYNC));
1627 		if (error)
1628 			return error;
1629 	}
1630 
1631 	/*
1632 	 * flush pages to avoid being overly dirty
1633 	 */
1634 	pflags = PGO_CLEANIT;
1635 	if (wait)
1636 		pflags |= PGO_SYNCIO;
1637 
1638 	mutex_enter(vp->v_interlock);
1639 	return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags);
1640 }
1641 
1642 int
1643 puffs_vnop_fsync(void *v)
1644 {
1645 	struct vop_fsync_args /* {
1646 		const struct vnodeop_desc *a_desc;
1647 		struct vnode *a_vp;
1648 		kauth_cred_t a_cred;
1649 		int a_flags;
1650 		off_t a_offlo;
1651 		off_t a_offhi;
1652 	} */ *ap = v;
1653 	PUFFS_MSG_VARS(vn, fsync);
1654 	struct vnode *vp;
1655 	struct puffs_node *pn;
1656 	struct puffs_mount *pmp;
1657 	int error, dofaf;
1658 
1659 	vp = ap->a_vp;
1660 	KASSERT(vp != NULL);
1661 	pn = VPTOPP(vp);
1662 	KASSERT(pn != NULL);
1663 	pmp = MPTOPUFFSMP(vp->v_mount);
1664 	if (ap->a_flags & FSYNC_WAIT) {
1665 		mutex_enter(&pn->pn_sizemtx);
1666 	} else {
1667 		if (mutex_tryenter(&pn->pn_sizemtx) == 0)
1668 			return EDEADLK;
1669 	}
1670 
1671 	error = flushvncache(vp, ap->a_offlo, ap->a_offhi,
1672 	    (ap->a_flags & FSYNC_WAIT) == FSYNC_WAIT);
1673 	if (error)
1674 		goto out;
1675 
1676 	/*
1677 	 * HELLO!  We exit already here if the user server does not
1678 	 * support fsync OR if we should call fsync for a node which
1679 	 * has references neither in the kernel or the fs server.
1680 	 * Otherwise we continue to issue fsync() forward.
1681 	 */
1682 	error = 0;
1683 	if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1684 		goto out;
1685 
1686 	dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1687 	/*
1688 	 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1689 	 * only FAFs for those.  Otherwise there's a danger of deadlock,
1690 	 * since the execution context here might be the user server
1691 	 * doing some operation on another fs, which in turn caused a
1692 	 * vnode to be reclaimed from the freelist for this fs.
1693 	 */
1694 	if (dofaf == 0) {
1695 		mutex_enter(vp->v_interlock);
1696 		if (vdead_check(vp, VDEAD_NOWAIT) != 0)
1697 			dofaf = 1;
1698 		mutex_exit(vp->v_interlock);
1699 	}
1700 
1701 	PUFFS_MSG_ALLOC(vn, fsync);
1702 	if (dofaf)
1703 		puffs_msg_setfaf(park_fsync);
1704 
1705 	puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred);
1706 	fsync_msg->pvnr_flags = ap->a_flags;
1707 	fsync_msg->pvnr_offlo = ap->a_offlo;
1708 	fsync_msg->pvnr_offhi = ap->a_offhi;
1709 	puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
1710 	    PUFFS_VN_FSYNC, VPTOPNC(vp));
1711 
1712 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
1713 	PUFFS_MSG_RELEASE(fsync);
1714 
1715 	error = checkerr(pmp, error, __func__);
1716 
1717 out:
1718 	mutex_exit(&pn->pn_sizemtx);
1719 	return error;
1720 }
1721 
1722 int
1723 puffs_vnop_seek(void *v)
1724 {
1725 	struct vop_seek_args /* {
1726 		const struct vnodeop_desc *a_desc;
1727 		struct vnode *a_vp;
1728 		off_t a_oldoff;
1729 		off_t a_newoff;
1730 		kauth_cred_t a_cred;
1731 	} */ *ap = v;
1732 	PUFFS_MSG_VARS(vn, seek);
1733 	struct vnode *vp = ap->a_vp;
1734 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1735 	int error;
1736 
1737 	PUFFS_MSG_ALLOC(vn, seek);
1738 	seek_msg->pvnr_oldoff = ap->a_oldoff;
1739 	seek_msg->pvnr_newoff = ap->a_newoff;
1740 	puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred);
1741 	puffs_msg_setinfo(park_seek, PUFFSOP_VN,
1742 	    PUFFS_VN_SEEK, VPTOPNC(vp));
1743 
1744 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_seek, vp->v_data, NULL, error);
1745 	PUFFS_MSG_RELEASE(seek);
1746 	return checkerr(pmp, error, __func__);
1747 }
1748 
1749 static int
1750 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1751 	struct componentname *cnp)
1752 {
1753 	PUFFS_MSG_VARS(vn, remove);
1754 	int error;
1755 
1756 	PUFFS_MSG_ALLOC(vn, remove);
1757 	remove_msg->pvnr_cookie_targ = ck;
1758 	puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1759 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1760 	puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);
1761 
1762 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
1763 	PUFFS_MSG_RELEASE(remove);
1764 
1765 	return checkerr(pmp, error, __func__);
1766 }
1767 
1768 /*
1769  * XXX: can't use callremove now because can't catch setbacks with
1770  * it due to lack of a pnode argument.
1771  */
1772 int
1773 puffs_vnop_remove(void *v)
1774 {
1775 	struct vop_remove_args /* {
1776 		const struct vnodeop_desc *a_desc;
1777 		struct vnode *a_dvp;
1778 		struct vnode *a_vp;
1779 		struct componentname *a_cnp;
1780 	} */ *ap = v;
1781 	PUFFS_MSG_VARS(vn, remove);
1782 	struct vnode *dvp = ap->a_dvp;
1783 	struct vnode *vp = ap->a_vp;
1784 	struct puffs_node *dpn = VPTOPP(dvp);
1785 	struct puffs_node *pn = VPTOPP(vp);
1786 	struct componentname *cnp = ap->a_cnp;
1787 	struct mount *mp = dvp->v_mount;
1788 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1789 	int error;
1790 
1791 	PUFFS_MSG_ALLOC(vn, remove);
1792 	remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
1793 	puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1794 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1795 	puffs_msg_setinfo(park_remove, PUFFSOP_VN,
1796 	    PUFFS_VN_REMOVE, VPTOPNC(dvp));
1797 
1798 	puffs_msg_enqueue(pmp, park_remove);
1799 	REFPN_AND_UNLOCKVP(dvp, dpn);
1800 	if (dvp == vp)
1801 		REFPN(pn);
1802 	else
1803 		REFPN_AND_UNLOCKVP(vp, pn);
1804 	error = puffs_msg_wait2(pmp, park_remove, dpn, pn);
1805 
1806 	PUFFS_MSG_RELEASE(remove);
1807 
1808 	puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0);
1809 
1810 	RELEPN_AND_VP(dvp, dpn);
1811 	RELEPN_AND_VP(vp, pn);
1812 
1813 	error = checkerr(pmp, error, __func__);
1814 	return error;
1815 }
1816 
1817 int
1818 puffs_vnop_mkdir(void *v)
1819 {
1820 	struct vop_mkdir_v3_args /* {
1821 		const struct vnodeop_desc *a_desc;
1822 		struct vnode *a_dvp;
1823 		struct vnode **a_vpp;
1824 		struct componentname *a_cnp;
1825 		struct vattr *a_vap;
1826 	} */ *ap = v;
1827 	PUFFS_MSG_VARS(vn, mkdir);
1828 	struct vnode *dvp = ap->a_dvp;
1829 	struct puffs_node *dpn = VPTOPP(dvp);
1830 	struct componentname *cnp = ap->a_cnp;
1831 	struct mount *mp = dvp->v_mount;
1832 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1833 	int error;
1834 
1835 	PUFFS_MSG_ALLOC(vn, mkdir);
1836 	puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1837 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1838 	mkdir_msg->pvnr_va = *ap->a_vap;
1839 	puffs_msg_setinfo(park_mkdir, PUFFSOP_VN,
1840 	    PUFFS_VN_MKDIR, VPTOPNC(dvp));
1841 
1842 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error);
1843 
1844 	error = checkerr(pmp, error, __func__);
1845 	if (error)
1846 		goto out;
1847 
1848 	error = puffs_newnode(mp, dvp, ap->a_vpp,
1849 	    mkdir_msg->pvnr_newnode, cnp, VDIR, 0);
1850 	if (error) {
1851 		puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie,
1852 		    mkdir_msg->pvnr_newnode, cnp);
1853 		goto out;
1854 	}
1855 
1856 	if (PUFFS_USE_FS_TTL(pmp)) {
1857 		struct timespec *va_ttl = &mkdir_msg->pvnr_va_ttl;
1858 		struct timespec *cn_ttl = &mkdir_msg->pvnr_cn_ttl;
1859 		struct vattr *rvap = &mkdir_msg->pvnr_va;
1860 
1861 		update_va(*ap->a_vpp, NULL, rvap,
1862 			  va_ttl, cn_ttl, SETATTR_CHSIZE);
1863 	}
1864 
1865 	VPTOPP(*ap->a_vpp)->pn_nlookup++;
1866 
1867 	if (PUFFS_USE_DOTDOTCACHE(pmp) &&
1868 	    (VPTOPP(*ap->a_vpp)->pn_parent != dvp))
1869 		update_parent(*ap->a_vpp, dvp);
1870 
1871  out:
1872 	PUFFS_MSG_RELEASE(mkdir);
1873 	return error;
1874 }
1875 
1876 static int
1877 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1878 	struct componentname *cnp)
1879 {
1880 	PUFFS_MSG_VARS(vn, rmdir);
1881 	int error;
1882 
1883 	PUFFS_MSG_ALLOC(vn, rmdir);
1884 	rmdir_msg->pvnr_cookie_targ = ck;
1885 	puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1886 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1887 	puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck);
1888 
1889 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error);
1890 	PUFFS_MSG_RELEASE(rmdir);
1891 
1892 	return checkerr(pmp, error, __func__);
1893 }
1894 
1895 int
1896 puffs_vnop_rmdir(void *v)
1897 {
1898 	struct vop_rmdir_args /* {
1899 		const struct vnodeop_desc *a_desc;
1900 		struct vnode *a_dvp;
1901 		struct vnode *a_vp;
1902 		struct componentname *a_cnp;
1903 	} */ *ap = v;
1904 	PUFFS_MSG_VARS(vn, rmdir);
1905 	struct vnode *dvp = ap->a_dvp;
1906 	struct vnode *vp = ap->a_vp;
1907 	struct puffs_node *dpn = VPTOPP(dvp);
1908 	struct puffs_node *pn = VPTOPP(vp);
1909 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1910 	struct componentname *cnp = ap->a_cnp;
1911 	int error;
1912 
1913 	PUFFS_MSG_ALLOC(vn, rmdir);
1914 	rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1915 	puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1916 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1917 	puffs_msg_setinfo(park_rmdir, PUFFSOP_VN,
1918 	    PUFFS_VN_RMDIR, VPTOPNC(dvp));
1919 
1920 	puffs_msg_enqueue(pmp, park_rmdir);
1921 	REFPN_AND_UNLOCKVP(dvp, dpn);
1922 	REFPN_AND_UNLOCKVP(vp, pn);
1923 	error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn);
1924 
1925 	PUFFS_MSG_RELEASE(rmdir);
1926 
1927 	puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0);
1928 
1929 	/* XXX: some call cache_purge() *for both vnodes* here, investigate */
1930 	RELEPN_AND_VP(dvp, dpn);
1931 	RELEPN_AND_VP(vp, pn);
1932 
1933 	return error;
1934 }
1935 
1936 int
1937 puffs_vnop_link(void *v)
1938 {
1939 	struct vop_link_args /* {
1940 		const struct vnodeop_desc *a_desc;
1941 		struct vnode *a_dvp;
1942 		struct vnode *a_vp;
1943 		struct componentname *a_cnp;
1944 	} */ *ap = v;
1945 	PUFFS_MSG_VARS(vn, link);
1946 	struct vnode *dvp = ap->a_dvp;
1947 	struct vnode *vp = ap->a_vp;
1948 	struct puffs_node *dpn = VPTOPP(dvp);
1949 	struct puffs_node *pn = VPTOPP(vp);
1950 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1951 	struct componentname *cnp = ap->a_cnp;
1952 	int error;
1953 
1954 	PUFFS_MSG_ALLOC(vn, link);
1955 	link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1956 	puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1957 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1958 	puffs_msg_setinfo(park_link, PUFFSOP_VN,
1959 	    PUFFS_VN_LINK, VPTOPNC(dvp));
1960 
1961 	puffs_msg_enqueue(pmp, park_link);
1962 	REFPN_AND_UNLOCKVP(dvp, dpn);
1963 	REFPN(pn);
1964 	error = puffs_msg_wait2(pmp, park_link, dpn, pn);
1965 
1966 	PUFFS_MSG_RELEASE(link);
1967 
1968 	error = checkerr(pmp, error, __func__);
1969 
1970 	/*
1971 	 * XXX: stay in touch with the cache.  I don't like this, but
1972 	 * don't have a better solution either.  See also puffs_rename().
1973 	 */
1974 	if (error == 0) {
1975 		puffs_updatenode(pn, PUFFS_UPDATECTIME, 0);
1976 		puffs_updatenode(VPTOPP(dvp),
1977 				 PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0);
1978 	}
1979 
1980 	RELEPN_AND_VP(dvp, dpn);
1981 	puffs_releasenode(pn);
1982 
1983 	return error;
1984 }
1985 
1986 int
1987 puffs_vnop_symlink(void *v)
1988 {
1989 	struct vop_symlink_v3_args /* {
1990 		const struct vnodeop_desc *a_desc;
1991 		struct vnode *a_dvp;
1992 		struct vnode **a_vpp;
1993 		struct componentname *a_cnp;
1994 		struct vattr *a_vap;
1995 		char *a_target;
1996 	} */ *ap = v;
1997 	PUFFS_MSG_VARS(vn, symlink);
1998 	struct vnode *dvp = ap->a_dvp;
1999 	struct puffs_node *dpn = VPTOPP(dvp);
2000 	struct mount *mp = dvp->v_mount;
2001 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
2002 	struct componentname *cnp = ap->a_cnp;
2003 	int error;
2004 
2005 	*ap->a_vpp = NULL;
2006 
2007 	PUFFS_MSG_ALLOC(vn, symlink);
2008 	puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
2009 		cnp, PUFFS_USE_FULLPNBUF(pmp));
2010 	symlink_msg->pvnr_va = *ap->a_vap;
2011 	(void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
2012 	    sizeof(symlink_msg->pvnr_link));
2013 	puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
2014 	    PUFFS_VN_SYMLINK, VPTOPNC(dvp));
2015 
2016 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);
2017 
2018 	error = checkerr(pmp, error, __func__);
2019 	if (error)
2020 		goto out;
2021 
2022 	error = puffs_newnode(mp, dvp, ap->a_vpp,
2023 	    symlink_msg->pvnr_newnode, cnp, VLNK, 0);
2024 	if (error) {
2025 		puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
2026 		    symlink_msg->pvnr_newnode, cnp);
2027 		goto out;
2028 	}
2029 
2030 	if (PUFFS_USE_FS_TTL(pmp)) {
2031 		struct timespec *va_ttl = &symlink_msg->pvnr_va_ttl;
2032 		struct timespec *cn_ttl = &symlink_msg->pvnr_cn_ttl;
2033 		struct vattr *rvap = &symlink_msg->pvnr_va;
2034 
2035 		update_va(*ap->a_vpp, NULL, rvap,
2036 			  va_ttl, cn_ttl, SETATTR_CHSIZE);
2037 	}
2038 
2039 	VPTOPP(*ap->a_vpp)->pn_nlookup++;
2040 
2041 	if (PUFFS_USE_DOTDOTCACHE(pmp) &&
2042 	    (VPTOPP(*ap->a_vpp)->pn_parent != dvp))
2043 		update_parent(*ap->a_vpp, dvp);
2044 
2045  out:
2046 	PUFFS_MSG_RELEASE(symlink);
2047 
2048 	return error;
2049 }
2050 
2051 int
2052 puffs_vnop_readlink(void *v)
2053 {
2054 	struct vop_readlink_args /* {
2055 		const struct vnodeop_desc *a_desc;
2056 		struct vnode *a_vp;
2057 		struct uio *a_uio;
2058 		kauth_cred_t a_cred;
2059 	} */ *ap = v;
2060 	PUFFS_MSG_VARS(vn, readlink);
2061 	struct vnode *vp = ap->a_vp;
2062 	struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2063 	size_t linklen;
2064 	int error;
2065 
2066 	PUFFS_MSG_ALLOC(vn, readlink);
2067 	puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
2068 	linklen = sizeof(readlink_msg->pvnr_link);
2069 	readlink_msg->pvnr_linklen = linklen;
2070 	puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
2071 	    PUFFS_VN_READLINK, VPTOPNC(vp));
2072 
2073 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
2074 	error = checkerr(pmp, error, __func__);
2075 	if (error)
2076 		goto out;
2077 
2078 	/* bad bad user file server */
2079 	if (readlink_msg->pvnr_linklen > linklen) {
2080 		puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
2081 		    "linklen too big", VPTOPNC(ap->a_vp));
2082 		error = EPROTO;
2083 		goto out;
2084 	}
2085 
2086 	error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
2087 	    ap->a_uio);
2088  out:
2089 	PUFFS_MSG_RELEASE(readlink);
2090 	return error;
2091 }
2092 
2093 int
2094 puffs_vnop_rename(void *v)
2095 {
2096 	struct vop_rename_args /* {
2097 		const struct vnodeop_desc *a_desc;
2098 		struct vnode *a_fdvp;
2099 		struct vnode *a_fvp;
2100 		struct componentname *a_fcnp;
2101 		struct vnode *a_tdvp;
2102 		struct vnode *a_tvp;
2103 		struct componentname *a_tcnp;
2104 	} */ *ap = v;
2105 	PUFFS_MSG_VARS(vn, rename);
2106 	struct vnode *fdvp = ap->a_fdvp, *fvp = ap->a_fvp;
2107 	struct vnode *tdvp = ap->a_tdvp, *tvp = ap->a_tvp;
2108 	struct puffs_node *fpn = ap->a_fvp->v_data;
2109 	struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
2110 	int error;
2111 	bool doabort = true;
2112 
2113 	if ((fvp->v_mount != tdvp->v_mount) ||
2114 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
2115 		ERROUT(EXDEV);
2116 	}
2117 
2118 	PUFFS_MSG_ALLOC(vn, rename);
2119 	rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
2120 	rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
2121 	if (tvp)
2122 		rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
2123 	else
2124 		rename_msg->pvnr_cookie_targ = NULL;
2125 	puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
2126 	    ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
2127 	puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
2128 	    ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
2129 	puffs_msg_setinfo(park_rename, PUFFSOP_VN,
2130 	    PUFFS_VN_RENAME, VPTOPNC(fdvp));
2131 
2132 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
2133 	doabort = false;
2134 	PUFFS_MSG_RELEASE(rename);
2135 	error = checkerr(pmp, error, __func__);
2136 
2137 	/*
2138 	 * XXX: stay in touch with the cache.  I don't like this, but
2139 	 * don't have a better solution either.  See also puffs_link().
2140 	 */
2141 	if (error == 0) {
2142 		puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0);
2143 		puffs_updatenode(VPTOPP(fdvp),
2144 				 PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0);
2145 		if (fdvp != tdvp)
2146 			puffs_updatenode(VPTOPP(tdvp),
2147 					 PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME,
2148 					 0);
2149 
2150 		if (PUFFS_USE_DOTDOTCACHE(pmp) &&
2151 		    (VPTOPP(fvp)->pn_parent != tdvp))
2152 			update_parent(fvp, tdvp);
2153 	}
2154 
2155 
2156  out:
2157 	if (doabort)
2158 		VOP_ABORTOP(tdvp, ap->a_tcnp);
2159 	if (tvp != NULL)
2160 		vput(tvp);
2161 	if (tdvp == tvp)
2162 		vrele(tdvp);
2163 	else
2164 		vput(tdvp);
2165 
2166 	if (doabort)
2167 		VOP_ABORTOP(fdvp, ap->a_fcnp);
2168 	vrele(fdvp);
2169 	vrele(fvp);
2170 
2171 	return error;
2172 }
2173 
2174 #define RWARGS(cont, iofl, move, offset, creds)				\
2175 	(cont)->pvnr_ioflag = (iofl);					\
2176 	(cont)->pvnr_resid = (move);					\
2177 	(cont)->pvnr_offset = (offset);					\
2178 	puffs_credcvt(&(cont)->pvnr_cred, creds)
2179 
2180 int
2181 puffs_vnop_read(void *v)
2182 {
2183 	struct vop_read_args /* {
2184 		const struct vnodeop_desc *a_desc;
2185 		struct vnode *a_vp;
2186 		struct uio *a_uio;
2187 		int a_ioflag;
2188 		kauth_cred_t a_cred;
2189 	} */ *ap = v;
2190 	PUFFS_MSG_VARS(vn, read);
2191 	struct vnode *vp = ap->a_vp;
2192 	struct puffs_node *pn = VPTOPP(vp);
2193 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2194 	struct uio *uio = ap->a_uio;
2195 	size_t tomove, argsize;
2196 	vsize_t bytelen;
2197 	int error;
2198 
2199 	read_msg = NULL;
2200 	error = 0;
2201 
2202 	/* std sanity */
2203 	if (uio->uio_resid == 0)
2204 		return 0;
2205 	if (uio->uio_offset < 0)
2206 		return EFBIG;
2207 
2208 	if (vp->v_type == VREG &&
2209 	    PUFFS_USE_PAGECACHE(pmp) &&
2210 	    !(pn->pn_stat & PNODE_RDIRECT)) {
2211 		const int advice = IO_ADV_DECODE(ap->a_ioflag);
2212 
2213 		while (uio->uio_resid > 0) {
2214 			if (vp->v_size <= uio->uio_offset) {
2215 				break;
2216 			}
2217 			bytelen = MIN(uio->uio_resid,
2218 			    vp->v_size - uio->uio_offset);
2219 			if (bytelen == 0)
2220 				break;
2221 
2222 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
2223 			    UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
2224 			if (error)
2225 				break;
2226 		}
2227 
2228 		if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
2229 			puffs_updatenode(VPTOPP(vp), PUFFS_UPDATEATIME, 0);
2230 	} else {
2231 		/*
2232 		 * in case it's not a regular file or we're operating
2233 		 * uncached, do read in the old-fashioned style,
2234 		 * i.e. explicit read operations
2235 		 */
2236 
2237 		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2238 		argsize = sizeof(struct puffs_vnmsg_read);
2239 		puffs_msgmem_alloc(argsize + tomove, &park_read,
2240 		    (void *)&read_msg, 1);
2241 
2242 		error = 0;
2243 		while (uio->uio_resid > 0) {
2244 			tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2245 			memset(read_msg, 0, argsize); /* XXX: touser KASSERT */
2246 			RWARGS(read_msg, ap->a_ioflag, tomove,
2247 			    uio->uio_offset, ap->a_cred);
2248 			puffs_msg_setinfo(park_read, PUFFSOP_VN,
2249 			    PUFFS_VN_READ, VPTOPNC(vp));
2250 			puffs_msg_setdelta(park_read, tomove);
2251 
2252 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data,
2253 			    NULL, error);
2254 			error = checkerr(pmp, error, __func__);
2255 			if (error)
2256 				break;
2257 
2258 			if (read_msg->pvnr_resid > tomove) {
2259 				puffs_senderr(pmp, PUFFS_ERR_READ,
2260 				    E2BIG, "resid grew", VPTOPNC(ap->a_vp));
2261 				error = EPROTO;
2262 				break;
2263 			}
2264 
2265 			error = uiomove(read_msg->pvnr_data,
2266 			    tomove - read_msg->pvnr_resid, uio);
2267 
2268 			/*
2269 			 * in case the file is out of juice, resid from
2270 			 * userspace is != 0.  and the error-case is
2271 			 * quite obvious
2272 			 */
2273 			if (error || read_msg->pvnr_resid)
2274 				break;
2275 		}
2276 
2277 		puffs_msgmem_release(park_read);
2278 	}
2279 
2280 	return error;
2281 }
2282 
2283 /*
2284  * XXX: in case of a failure, this leaves uio in a bad state.
2285  * We could theoretically copy the uio and iovecs and "replay"
2286  * them the right amount after the userspace trip, but don't
2287  * bother for now.
2288  */
2289 int
2290 puffs_vnop_write(void *v)
2291 {
2292 	struct vop_write_args /* {
2293 		const struct vnodeop_desc *a_desc;
2294 		struct vnode *a_vp;
2295 		struct uio *a_uio;
2296 		int a_ioflag;
2297 		kauth_cred_t a_cred;
2298 	} */ *ap = v;
2299 	PUFFS_MSG_VARS(vn, write);
2300 	struct vnode *vp = ap->a_vp;
2301 	struct puffs_node *pn = VPTOPP(vp);
2302 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2303 	struct uio *uio = ap->a_uio;
2304 	size_t tomove, argsize;
2305 	off_t oldoff, newoff, origoff;
2306 	vsize_t bytelen;
2307 	int error, uflags;
2308 	int ubcflags;
2309 
2310 	error = uflags = 0;
2311 	write_msg = NULL;
2312 
2313 	/* std sanity */
2314 	if (uio->uio_resid == 0)
2315 		return 0;
2316 	if (uio->uio_offset < 0)
2317 		return EFBIG;
2318 
2319 	mutex_enter(&pn->pn_sizemtx);
2320 
2321 	if (vp->v_type == VREG &&
2322 	    PUFFS_USE_PAGECACHE(pmp) &&
2323 	    !(pn->pn_stat & PNODE_WDIRECT)) {
2324 		ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp);
2325 
2326 		/*
2327 		 * userspace *should* be allowed to control this,
2328 		 * but with UBC it's a bit unclear how to handle it
2329 		 */
2330 		if (ap->a_ioflag & IO_APPEND)
2331 			uio->uio_offset = vp->v_size;
2332 
2333 		origoff = uio->uio_offset;
2334 		while (uio->uio_resid > 0) {
2335 			oldoff = uio->uio_offset;
2336 			bytelen = uio->uio_resid;
2337 
2338 			newoff = oldoff + bytelen;
2339 			if (vp->v_size < newoff) {
2340 				uvm_vnp_setwritesize(vp, newoff);
2341 			}
2342 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
2343 			    UVM_ADV_RANDOM, ubcflags);
2344 
2345 			/*
2346 			 * In case of a ubc_uiomove() error,
2347 			 * opt to not extend the file at all and
2348 			 * return an error.  Otherwise, if we attempt
2349 			 * to clear the memory we couldn't fault to,
2350 			 * we might generate a kernel page fault.
2351 			 */
2352 			if (vp->v_size < newoff) {
2353 				if (error == 0) {
2354 					uflags |= PUFFS_UPDATESIZE;
2355 					uvm_vnp_setsize(vp, newoff);
2356 				} else {
2357 					uvm_vnp_setwritesize(vp, vp->v_size);
2358 				}
2359 			}
2360 			if (error)
2361 				break;
2362 
2363 			/*
2364 			 * If we're writing large files, flush to file server
2365 			 * every 64k.  Otherwise we can very easily exhaust
2366 			 * kernel and user memory, as the file server cannot
2367 			 * really keep up with our writing speed.
2368 			 *
2369 			 * Note: this does *NOT* honor MNT_ASYNC, because
2370 			 * that gives userland too much say in the kernel.
2371 			 */
2372 			if (oldoff >> 16 != uio->uio_offset >> 16) {
2373 				mutex_enter(vp->v_interlock);
2374 				error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
2375 				    uio->uio_offset & ~0xffff,
2376 				    PGO_CLEANIT | PGO_SYNCIO);
2377 				if (error)
2378 					break;
2379 			}
2380 		}
2381 
2382 		/* synchronous I/O? */
2383 		if (error == 0 && ap->a_ioflag & IO_SYNC) {
2384 			mutex_enter(vp->v_interlock);
2385 			error = VOP_PUTPAGES(vp, trunc_page(origoff),
2386 			    round_page(uio->uio_offset),
2387 			    PGO_CLEANIT | PGO_SYNCIO);
2388 
2389 		/* write through page cache? */
2390 		} else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
2391 			mutex_enter(vp->v_interlock);
2392 			error = VOP_PUTPAGES(vp, trunc_page(origoff),
2393 			    round_page(uio->uio_offset), PGO_CLEANIT);
2394 		}
2395 	} else {
2396 		/* tomove is non-increasing */
2397 		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2398 		argsize = sizeof(struct puffs_vnmsg_write) + tomove;
2399 		puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1);
2400 
2401 		while (uio->uio_resid > 0) {
2402 			/* move data to buffer */
2403 			tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2404 			memset(write_msg, 0, argsize); /* XXX: touser KASSERT */
2405 			RWARGS(write_msg, ap->a_ioflag, tomove,
2406 			    uio->uio_offset, ap->a_cred);
2407 			error = uiomove(write_msg->pvnr_data, tomove, uio);
2408 			if (error)
2409 				break;
2410 
2411 			/* move buffer to userspace */
2412 			puffs_msg_setinfo(park_write, PUFFSOP_VN,
2413 			    PUFFS_VN_WRITE, VPTOPNC(vp));
2414 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data,
2415 			    NULL, error);
2416 			error = checkerr(pmp, error, __func__);
2417 			if (error)
2418 				break;
2419 
2420 			if (write_msg->pvnr_resid > tomove) {
2421 				puffs_senderr(pmp, PUFFS_ERR_WRITE,
2422 				    E2BIG, "resid grew", VPTOPNC(ap->a_vp));
2423 				error = EPROTO;
2424 				break;
2425 			}
2426 
2427 			/* adjust file size */
2428 			if (vp->v_size < uio->uio_offset) {
2429 				uflags |= PUFFS_UPDATESIZE;
2430 				uvm_vnp_setsize(vp, uio->uio_offset);
2431 			}
2432 
2433 			/* didn't move everything?  bad userspace.  bail */
2434 			if (write_msg->pvnr_resid != 0) {
2435 				error = EIO;
2436 				break;
2437 			}
2438 		}
2439 		puffs_msgmem_release(park_write);
2440 	}
2441 
2442 	if (vp->v_mount->mnt_flag & MNT_RELATIME)
2443 		uflags |= PUFFS_UPDATEATIME;
2444 	uflags |= PUFFS_UPDATECTIME;
2445 	uflags |= PUFFS_UPDATEMTIME;
2446 	puffs_updatenode(VPTOPP(vp), uflags, vp->v_size);
2447 
2448 	mutex_exit(&pn->pn_sizemtx);
2449 	return error;
2450 }
2451 
2452 int
2453 puffs_vnop_print(void *v)
2454 {
2455 	struct vop_print_args /* {
2456 		struct vnode *a_vp;
2457 	} */ *ap = v;
2458 	PUFFS_MSG_VARS(vn, print);
2459 	struct vnode *vp = ap->a_vp;
2460 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2461 	struct puffs_node *pn = vp->v_data;
2462 
2463 	/* kernel portion */
2464 	printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
2465 	    "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
2466 	if (vp->v_type == VFIFO)
2467 		VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
2468 	printf("\n");
2469 
2470 	/* userspace portion */
2471 	if (EXISTSOP(pmp, PRINT)) {
2472 		PUFFS_MSG_ALLOC(vn, print);
2473 		puffs_msg_setinfo(park_print, PUFFSOP_VN,
2474 		    PUFFS_VN_PRINT, VPTOPNC(vp));
2475 		PUFFS_MSG_ENQUEUEWAIT2_NOERROR(pmp, park_print, vp->v_data,
2476 		    NULL);
2477 		PUFFS_MSG_RELEASE(print);
2478 	}
2479 
2480 	return 0;
2481 }
2482 
2483 int
2484 puffs_vnop_pathconf(void *v)
2485 {
2486 	struct vop_pathconf_args /* {
2487 		const struct vnodeop_desc *a_desc;
2488 		struct vnode *a_vp;
2489 		int a_name;
2490 		register_t *a_retval;
2491 	} */ *ap = v;
2492 	PUFFS_MSG_VARS(vn, pathconf);
2493 	struct vnode *vp = ap->a_vp;
2494 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2495 	int error;
2496 
2497 	PUFFS_MSG_ALLOC(vn, pathconf);
2498 	pathconf_msg->pvnr_name = ap->a_name;
2499 	puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
2500 	    PUFFS_VN_PATHCONF, VPTOPNC(vp));
2501 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
2502 	error = checkerr(pmp, error, __func__);
2503 	if (!error)
2504 		*ap->a_retval = pathconf_msg->pvnr_retval;
2505 	PUFFS_MSG_RELEASE(pathconf);
2506 
2507 	return error;
2508 }
2509 
2510 int
2511 puffs_vnop_advlock(void *v)
2512 {
2513 	struct vop_advlock_args /* {
2514 		const struct vnodeop_desc *a_desc;
2515 		struct vnode *a_vp;
2516 		void *a_id;
2517 		int a_op;
2518 		struct flock *a_fl;
2519 		int a_flags;
2520 	} */ *ap = v;
2521 	PUFFS_MSG_VARS(vn, advlock);
2522 	struct vnode *vp = ap->a_vp;
2523 	struct puffs_node *pn = VPTOPP(vp);
2524 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2525 	int error;
2526 
2527 	if (!EXISTSOP(pmp, ADVLOCK))
2528 		return lf_advlock(ap, &pn->pn_lockf, vp->v_size);
2529 
2530 	PUFFS_MSG_ALLOC(vn, advlock);
2531 	(void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
2532 		     sizeof(advlock_msg->pvnr_fl));
2533 	advlock_msg->pvnr_id = ap->a_id;
2534 	advlock_msg->pvnr_op = ap->a_op;
2535 	advlock_msg->pvnr_flags = ap->a_flags;
2536 	puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
2537 	    PUFFS_VN_ADVLOCK, VPTOPNC(vp));
2538 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
2539 	error = checkerr(pmp, error, __func__);
2540 	PUFFS_MSG_RELEASE(advlock);
2541 
2542 	return error;
2543 }
2544 
2545 int
2546 puffs_vnop_abortop(void *v)
2547 {
2548 	struct vop_abortop_args /* {
2549 		struct vnode *a_dvp;
2550 		struct componentname *a_cnp;
2551 	}; */ *ap = v;
2552 	PUFFS_MSG_VARS(vn, abortop);
2553 	struct vnode *dvp = ap->a_dvp;
2554 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
2555 	struct componentname *cnp = ap->a_cnp;
2556 
2557 	if (EXISTSOP(pmp, ABORTOP)) {
2558 		PUFFS_MSG_ALLOC(vn, abortop);
2559 		puffs_makecn(&abortop_msg->pvnr_cn, &abortop_msg->pvnr_cn_cred,
2560 		    cnp, PUFFS_USE_FULLPNBUF(pmp));
2561 		puffs_msg_setfaf(park_abortop);
2562 		puffs_msg_setinfo(park_abortop, PUFFSOP_VN,
2563 		    PUFFS_VN_ABORTOP, VPTOPNC(dvp));
2564 
2565 		puffs_msg_enqueue(pmp, park_abortop);
2566 		PUFFS_MSG_RELEASE(abortop);
2567 	}
2568 
2569 	return genfs_abortop(v);
2570 }
2571 
2572 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
2573 
2574 /*
2575  * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
2576  */
2577 int
2578 puffs_vnop_strategy(void *v)
2579 {
2580 	struct vop_strategy_args /* {
2581 		const struct vnodeop_desc *a_desc;
2582 		struct vnode *a_vp;
2583 		struct buf *a_bp;
2584 	} */ *ap = v;
2585 	PUFFS_MSG_VARS(vn, rw);
2586 	struct vnode *vp = ap->a_vp;
2587 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2588 	struct puffs_node *pn;
2589 	struct buf *bp;
2590 	size_t argsize;
2591 	size_t tomove, moved;
2592 	int error, dofaf, cansleep, dobiodone;
2593 
2594 	pmp = MPTOPUFFSMP(vp->v_mount);
2595 	bp = ap->a_bp;
2596 	error = 0;
2597 	dofaf = 0;
2598 	cansleep = 0;
2599 	pn = VPTOPP(vp);
2600 	park_rw = NULL; /* explicit */
2601 	dobiodone = 1;
2602 
2603 	if ((BUF_ISREAD(bp) && !EXISTSOP(pmp, READ))
2604 	    || (BUF_ISWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2605 		ERROUT(EOPNOTSUPP);
2606 
2607 	/*
2608 	 * Short-circuit optimization: don't flush buffer in between
2609 	 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2610 	 */
2611 	if (pn->pn_stat & PNODE_DYING) {
2612 		KASSERT(BUF_ISWRITE(bp));
2613 		bp->b_resid = 0;
2614 		goto out;
2615 	}
2616 
2617 #ifdef DIAGNOSTIC
2618 	if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX)
2619 		panic("puffs_strategy: wildly inappropriate buf bcount %d",
2620 		    bp->b_bcount);
2621 #endif
2622 
2623 	/*
2624 	 * See explanation for the necessity of a FAF in puffs_fsync.
2625 	 *
2626 	 * Also, do FAF in case we're suspending.
2627 	 * See puffs_vfsops.c:pageflush()
2628 	 */
2629 	if (BUF_ISWRITE(bp)) {
2630 		mutex_enter(vp->v_interlock);
2631 		if (vdead_check(vp, VDEAD_NOWAIT) != 0)
2632 			dofaf = 1;
2633 		if (pn->pn_stat & PNODE_FAF)
2634 			dofaf = 1;
2635 		mutex_exit(vp->v_interlock);
2636 	}
2637 
2638 	cansleep = (curlwp == uvm.pagedaemon_lwp || dofaf) ? 0 : 1;
2639 
2640 	KASSERT(curlwp != uvm.pagedaemon_lwp || dofaf || BIOASYNC(bp));
2641 
2642 	/* allocate transport structure */
2643 	tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2644 	argsize = sizeof(struct puffs_vnmsg_rw);
2645 	error = puffs_msgmem_alloc(argsize + tomove, &park_rw,
2646 	    (void *)&rw_msg, cansleep);
2647 	if (error)
2648 		goto out;
2649 	RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2650 
2651 	/* 2x2 cases: read/write, faf/nofaf */
2652 	if (BUF_ISREAD(bp)) {
2653 		puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2654 		    PUFFS_VN_READ, VPTOPNC(vp));
2655 		puffs_msg_setdelta(park_rw, tomove);
2656 		if (BIOASYNC(bp)) {
2657 			puffs_msg_setcall(park_rw,
2658 			    puffs_parkdone_asyncbioread, bp);
2659 			puffs_msg_enqueue(pmp, park_rw);
2660 			dobiodone = 0;
2661 		} else {
2662 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data,
2663 			    NULL, error);
2664 			error = checkerr(pmp, error, __func__);
2665 			if (error)
2666 				goto out;
2667 
2668 			if (rw_msg->pvnr_resid > tomove) {
2669 				puffs_senderr(pmp, PUFFS_ERR_READ,
2670 				    E2BIG, "resid grew", VPTOPNC(vp));
2671 				ERROUT(EPROTO);
2672 			}
2673 
2674 			moved = tomove - rw_msg->pvnr_resid;
2675 
2676 			(void)memcpy(bp->b_data, rw_msg->pvnr_data, moved);
2677 			bp->b_resid = bp->b_bcount - moved;
2678 		}
2679 	} else {
2680 		puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2681 		    PUFFS_VN_WRITE, VPTOPNC(vp));
2682 		/*
2683 		 * make pages read-only before we write them if we want
2684 		 * write caching info
2685 		 */
2686 		if (PUFFS_WCACHEINFO(pmp)) {
2687 			struct uvm_object *uobj = &vp->v_uobj;
2688 			int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2689 			struct vm_page *vmp;
2690 			int i;
2691 
2692 			for (i = 0; i < npages; i++) {
2693 				vmp= uvm_pageratop((vaddr_t)bp->b_data
2694 				    + (i << PAGE_SHIFT));
2695 				DPRINTF(("puffs_strategy: write-protecting "
2696 				    "vp %p page %p, offset %" PRId64"\n",
2697 				    vp, vmp, vmp->offset));
2698 				mutex_enter(uobj->vmobjlock);
2699 				vmp->flags |= PG_RDONLY;
2700 				pmap_page_protect(vmp, VM_PROT_READ);
2701 				mutex_exit(uobj->vmobjlock);
2702 			}
2703 		}
2704 
2705 		(void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove);
2706 		if (dofaf) {
2707 			puffs_msg_setfaf(park_rw);
2708 		} else if (BIOASYNC(bp)) {
2709 			puffs_msg_setcall(park_rw,
2710 			    puffs_parkdone_asyncbiowrite, bp);
2711 			dobiodone = 0;
2712 		}
2713 
2714 		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, NULL, error);
2715 
2716 		if (dobiodone == 0)
2717 			goto out;
2718 
2719 		/*
2720 		 * XXXXXXXX: wrong, but kernel can't survive strategy
2721 		 * failure currently.  Here, have one more X: X.
2722 		 */
2723 		if (error != ENOMEM)
2724 			error = 0;
2725 
2726 		error = checkerr(pmp, error, __func__);
2727 		if (error)
2728 			goto out;
2729 
2730 		if (rw_msg->pvnr_resid > tomove) {
2731 			puffs_senderr(pmp, PUFFS_ERR_WRITE,
2732 			    E2BIG, "resid grew", VPTOPNC(vp));
2733 			ERROUT(EPROTO);
2734 		}
2735 
2736 		/*
2737 		 * FAF moved everything.  Frankly, we don't
2738 		 * really have a choice.
2739 		 */
2740 		if (dofaf && error == 0)
2741 			moved = tomove;
2742 		else
2743 			moved = tomove - rw_msg->pvnr_resid;
2744 
2745 		bp->b_resid = bp->b_bcount - moved;
2746 		if (bp->b_resid != 0) {
2747 			ERROUT(EIO);
2748 		}
2749 	}
2750 
2751  out:
2752 	if (park_rw)
2753 		puffs_msgmem_release(park_rw);
2754 
2755 	if (error)
2756 		bp->b_error = error;
2757 
2758 	if (error || dobiodone)
2759 		biodone(bp);
2760 
2761 	return error;
2762 }
2763 
2764 int
2765 puffs_vnop_mmap(void *v)
2766 {
2767 	struct vop_mmap_args /* {
2768 		const struct vnodeop_desc *a_desc;
2769 		struct vnode *a_vp;
2770 		vm_prot_t a_prot;
2771 		kauth_cred_t a_cred;
2772 	} */ *ap = v;
2773 	PUFFS_MSG_VARS(vn, mmap);
2774 	struct vnode *vp = ap->a_vp;
2775 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2776 	int error;
2777 
2778 	if (!PUFFS_USE_PAGECACHE(pmp))
2779 		return genfs_eopnotsupp(v);
2780 
2781 	if (EXISTSOP(pmp, MMAP)) {
2782 		PUFFS_MSG_ALLOC(vn, mmap);
2783 		mmap_msg->pvnr_prot = ap->a_prot;
2784 		puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred);
2785 		puffs_msg_setinfo(park_mmap, PUFFSOP_VN,
2786 		    PUFFS_VN_MMAP, VPTOPNC(vp));
2787 
2788 		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mmap, vp->v_data, NULL, error);
2789 		error = checkerr(pmp, error, __func__);
2790 		PUFFS_MSG_RELEASE(mmap);
2791 	} else {
2792 		error = genfs_mmap(v);
2793 	}
2794 
2795 	return error;
2796 }
2797 
2798 
2799 /*
2800  * The rest don't get a free trip to userspace and back, they
2801  * have to stay within the kernel.
2802  */
2803 
2804 /*
2805  * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2806  * well, maybe somehow, somewhere, some day ....
2807  */
2808 int
2809 puffs_vnop_bmap(void *v)
2810 {
2811 	struct vop_bmap_args /* {
2812 		const struct vnodeop_desc *a_desc;
2813 		struct vnode *a_vp;
2814 		daddr_t a_bn;
2815 		struct vnode **a_vpp;
2816 		daddr_t *a_bnp;
2817 		int *a_runp;
2818 	} */ *ap = v;
2819 	struct puffs_mount *pmp;
2820 
2821 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2822 
2823 	if (ap->a_vpp)
2824 		*ap->a_vpp = ap->a_vp;
2825 	if (ap->a_bnp)
2826 		*ap->a_bnp = ap->a_bn;
2827 	if (ap->a_runp)
2828 		*ap->a_runp
2829 		    = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1;
2830 
2831 	return 0;
2832 }
2833 
2834 /*
2835  * Handle getpages faults in puffs.  We let genfs_getpages() do most
2836  * of the dirty work, but we come in this route to do accounting tasks.
2837  * If the user server has specified functions for cache notifications
2838  * about reads and/or writes, we record which type of operation we got,
2839  * for which page range, and proceed to issue a FAF notification to the
2840  * server about it.
2841  */
2842 int
2843 puffs_vnop_getpages(void *v)
2844 {
2845 	struct vop_getpages_args /* {
2846 		const struct vnodeop_desc *a_desc;
2847 		struct vnode *a_vp;
2848 		voff_t a_offset;
2849 		struct vm_page **a_m;
2850 		int *a_count;
2851 		int a_centeridx;
2852 		vm_prot_t a_access_type;
2853 		int a_advice;
2854 		int a_flags;
2855 	} */ *ap = v;
2856 	struct puffs_mount *pmp;
2857 	struct puffs_node *pn;
2858 	struct vnode *vp;
2859 	struct vm_page **pgs;
2860 	struct puffs_cacheinfo *pcinfo = NULL;
2861 	struct puffs_cacherun *pcrun;
2862 	void *parkmem = NULL;
2863 	size_t runsizes;
2864 	int i, npages, si, streakon;
2865 	int error, locked, write;
2866 
2867 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2868 	npages = *ap->a_count;
2869 	pgs = ap->a_m;
2870 	vp = ap->a_vp;
2871 	pn = vp->v_data;
2872 	locked = (ap->a_flags & PGO_LOCKED) != 0;
2873 	write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2874 
2875 	/* ccg xnaht - gets Wuninitialized wrong */
2876 	pcrun = NULL;
2877 	runsizes = 0;
2878 
2879 	/*
2880 	 * Check that we aren't trying to fault in pages which our file
2881 	 * server doesn't know about.  This happens if we extend a file by
2882 	 * skipping some pages and later try to fault in pages which
2883 	 * are between pn_serversize and vp_size.  This check optimizes
2884 	 * away the common case where a file is being extended.
2885 	 */
2886 	if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2887 		struct vattr va;
2888 
2889 		/* try again later when we can block */
2890 		if (locked)
2891 			ERROUT(EBUSY);
2892 
2893 		mutex_exit(vp->v_interlock);
2894 		vattr_null(&va);
2895 		va.va_size = vp->v_size;
2896 		error = dosetattr(vp, &va, FSCRED, 0);
2897 		if (error)
2898 			ERROUT(error);
2899 		mutex_enter(vp->v_interlock);
2900 	}
2901 
2902 	if (write && PUFFS_WCACHEINFO(pmp)) {
2903 #ifdef notnowjohn
2904 		/* allocate worst-case memory */
2905 		runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2906 		KASSERT(curlwp != uvm.pagedaemon_lwp || locked);
2907 		pcinfo = kmem_zalloc(sizeof(struct puffs_cacheinfo) + runsize,
2908 		    locked ? KM_NOSLEEP : KM_SLEEP);
2909 
2910 		/*
2911 		 * can't block if we're locked and can't mess up caching
2912 		 * information for fs server.  so come back later, please
2913 		 */
2914 		if (pcinfo == NULL)
2915 			ERROUT(ENOMEM);
2916 
2917 		parkmem = puffs_park_alloc(locked == 0);
2918 		if (parkmem == NULL)
2919 			ERROUT(ENOMEM);
2920 
2921 		pcrun = pcinfo->pcache_runs;
2922 #else
2923 		(void)parkmem;
2924 #endif
2925 	}
2926 
2927 	error = genfs_getpages(v);
2928 	if (error)
2929 		goto out;
2930 
2931 	if (PUFFS_WCACHEINFO(pmp) == 0)
2932 		goto out;
2933 
2934 	/*
2935 	 * Let's see whose fault it was and inform the user server of
2936 	 * possibly read/written pages.  Map pages from read faults
2937 	 * strictly read-only, since otherwise we might miss info on
2938 	 * when the page is actually write-faulted to.
2939 	 */
2940 	if (!locked)
2941 		mutex_enter(vp->v_uobj.vmobjlock);
2942 	for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2943 		if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2944 			if (streakon && write) {
2945 				streakon = 0;
2946 				pcrun[si].pcache_runend
2947 				    = trunc_page(pgs[i]->offset) + PAGE_MASK;
2948 				si++;
2949 			}
2950 			continue;
2951 		}
2952 		if (streakon == 0 && write) {
2953 			streakon = 1;
2954 			pcrun[si].pcache_runstart = pgs[i]->offset;
2955 		}
2956 
2957 		if (!write)
2958 			pgs[i]->flags |= PG_RDONLY;
2959 	}
2960 	/* was the last page part of our streak? */
2961 	if (streakon) {
2962 		pcrun[si].pcache_runend
2963 		    = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2964 		si++;
2965 	}
2966 	if (!locked)
2967 		mutex_exit(vp->v_uobj.vmobjlock);
2968 
2969 	KASSERT(si <= (npages / 2) + 1);
2970 
2971 #ifdef notnowjohn
2972 	/* send results to userspace */
2973 	if (write)
2974 		puffs_cacheop(pmp, parkmem, pcinfo,
2975 		    sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2976 #endif
2977 
2978  out:
2979 	if (error) {
2980 		if (pcinfo != NULL)
2981 			kmem_free(pcinfo,
2982 			    sizeof(struct puffs_cacheinfo) + runsizes);
2983 #ifdef notnowjohn
2984 		if (parkmem != NULL)
2985 			puffs_park_release(parkmem, 1);
2986 #endif
2987 	}
2988 
2989 	return error;
2990 }
2991 
2992 /*
2993  * Extended attribute support.
2994  */
2995 
2996 int
2997 puffs_vnop_getextattr(void *v)
2998 {
2999 	struct vop_getextattr_args /*
3000 		struct vnode *a_vp;
3001 		int a_attrnamespace;
3002 		const char *a_name;
3003 		struct uio *a_uio;
3004 		size_t *a_size;
3005 		kauth_cred_t a_cred;
3006 	}; */ *ap = v;
3007 	PUFFS_MSG_VARS(vn, getextattr);
3008 	struct vnode *vp = ap->a_vp;
3009 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
3010 	int attrnamespace = ap->a_attrnamespace;
3011 	const char *name = ap->a_name;
3012 	struct uio *uio = ap->a_uio;
3013 	size_t *sizep = ap->a_size;
3014 	size_t tomove, resid;
3015 	int error;
3016 
3017 	if (uio)
3018 		resid = uio->uio_resid;
3019 	else
3020 		resid = 0;
3021 
3022 	tomove = PUFFS_TOMOVE(resid, pmp);
3023 	if (tomove != resid) {
3024 		error = E2BIG;
3025 		goto out;
3026 	}
3027 
3028 	puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_getextattr) + tomove,
3029 	    &park_getextattr, (void *)&getextattr_msg, 1);
3030 
3031 	getextattr_msg->pvnr_attrnamespace = attrnamespace;
3032 	strlcpy(getextattr_msg->pvnr_attrname, name,
3033 	    sizeof(getextattr_msg->pvnr_attrname));
3034 	puffs_credcvt(&getextattr_msg->pvnr_cred, ap->a_cred);
3035 	if (sizep)
3036 		getextattr_msg->pvnr_datasize = 1;
3037 	getextattr_msg->pvnr_resid = tomove;
3038 
3039 	puffs_msg_setinfo(park_getextattr,
3040 	    PUFFSOP_VN, PUFFS_VN_GETEXTATTR, VPTOPNC(vp));
3041 	puffs_msg_setdelta(park_getextattr, tomove);
3042 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getextattr, vp->v_data, NULL, error);
3043 
3044 	error = checkerr(pmp, error, __func__);
3045 	if (error)
3046 		goto out;
3047 
3048 	resid = getextattr_msg->pvnr_resid;
3049 	if (resid > tomove) {
3050 		puffs_senderr(pmp, PUFFS_ERR_GETEXTATTR, E2BIG,
3051 		    "resid grew", VPTOPNC(vp));
3052 		error = EPROTO;
3053 		goto out;
3054 	}
3055 
3056 	if (sizep)
3057 		*sizep = getextattr_msg->pvnr_datasize;
3058 	if (uio)
3059 		error = uiomove(getextattr_msg->pvnr_data, tomove - resid, uio);
3060 
3061  out:
3062 	PUFFS_MSG_RELEASE(getextattr);
3063 	return error;
3064 }
3065 
3066 int
3067 puffs_vnop_setextattr(void *v)
3068 {
3069 	struct vop_setextattr_args /* {
3070 		struct vnode *a_vp;
3071 		int a_attrnamespace;
3072 		const char *a_name;
3073 		struct uio *a_uio;
3074 		kauth_cred_t a_cred;
3075 	}; */ *ap = v;
3076 	PUFFS_MSG_VARS(vn, setextattr);
3077 	struct vnode *vp = ap->a_vp;
3078 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
3079 	int attrnamespace = ap->a_attrnamespace;
3080 	const char *name = ap->a_name;
3081 	struct uio *uio = ap->a_uio;
3082 	size_t tomove, resid;
3083 	int error;
3084 
3085 	if (uio)
3086 		resid = uio->uio_resid;
3087 	else
3088 		resid = 0;
3089 
3090 	tomove = PUFFS_TOMOVE(resid, pmp);
3091 	if (tomove != resid) {
3092 		error = E2BIG;
3093 		goto out;
3094 	}
3095 
3096 	puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_setextattr) + tomove,
3097 	    &park_setextattr, (void *)&setextattr_msg, 1);
3098 
3099 	setextattr_msg->pvnr_attrnamespace = attrnamespace;
3100 	strlcpy(setextattr_msg->pvnr_attrname, name,
3101 	    sizeof(setextattr_msg->pvnr_attrname));
3102 	puffs_credcvt(&setextattr_msg->pvnr_cred, ap->a_cred);
3103 	setextattr_msg->pvnr_resid = tomove;
3104 
3105 	if (uio) {
3106 		error = uiomove(setextattr_msg->pvnr_data, tomove, uio);
3107 		if (error)
3108 			goto out;
3109 	}
3110 
3111 	puffs_msg_setinfo(park_setextattr,
3112 	    PUFFSOP_VN, PUFFS_VN_SETEXTATTR, VPTOPNC(vp));
3113 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_setextattr, vp->v_data, NULL, error);
3114 
3115 	error = checkerr(pmp, error, __func__);
3116 	if (error)
3117 		goto out;
3118 
3119 	if (setextattr_msg->pvnr_resid != 0)
3120 		error = EIO;
3121 
3122  out:
3123 	PUFFS_MSG_RELEASE(setextattr);
3124 
3125 	return error;
3126 }
3127 
3128 int
3129 puffs_vnop_listextattr(void *v)
3130 {
3131 	struct vop_listextattr_args /* {
3132 		struct vnode *a_vp;
3133 		int a_attrnamespace;
3134 		struct uio *a_uio;
3135 		size_t *a_size;
3136 		int a_flag,
3137 		kauth_cred_t a_cred;
3138 	}; */ *ap = v;
3139 	PUFFS_MSG_VARS(vn, listextattr);
3140 	struct vnode *vp = ap->a_vp;
3141 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
3142 	int attrnamespace = ap->a_attrnamespace;
3143 	struct uio *uio = ap->a_uio;
3144 	size_t *sizep = ap->a_size;
3145 	int flag = ap->a_flag;
3146 	size_t tomove, resid;
3147 	int error;
3148 
3149 	if (uio)
3150 		resid = uio->uio_resid;
3151 	else
3152 		resid = 0;
3153 
3154 	tomove = PUFFS_TOMOVE(resid, pmp);
3155 	if (tomove != resid) {
3156 		error = E2BIG;
3157 		goto out;
3158 	}
3159 
3160 	puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_listextattr) + tomove,
3161 	    &park_listextattr, (void *)&listextattr_msg, 1);
3162 
3163 	listextattr_msg->pvnr_attrnamespace = attrnamespace;
3164 	listextattr_msg->pvnr_flag = flag;
3165 	puffs_credcvt(&listextattr_msg->pvnr_cred, ap->a_cred);
3166 	listextattr_msg->pvnr_resid = tomove;
3167 	if (sizep)
3168 		listextattr_msg->pvnr_datasize = 1;
3169 
3170 	puffs_msg_setinfo(park_listextattr,
3171 	    PUFFSOP_VN, PUFFS_VN_LISTEXTATTR, VPTOPNC(vp));
3172 	puffs_msg_setdelta(park_listextattr, tomove);
3173 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_listextattr, vp->v_data, NULL, error);
3174 
3175 	error = checkerr(pmp, error, __func__);
3176 	if (error)
3177 		goto out;
3178 
3179 	resid = listextattr_msg->pvnr_resid;
3180 	if (resid > tomove) {
3181 		puffs_senderr(pmp, PUFFS_ERR_LISTEXTATTR, E2BIG,
3182 		    "resid grew", VPTOPNC(vp));
3183 		error = EPROTO;
3184 		goto out;
3185 	}
3186 
3187 	if (sizep)
3188 		*sizep = listextattr_msg->pvnr_datasize;
3189 	if (uio)
3190 		error = uiomove(listextattr_msg->pvnr_data, tomove-resid, uio);
3191 
3192  out:
3193 	PUFFS_MSG_RELEASE(listextattr);
3194 	return error;
3195 }
3196 
3197 int
3198 puffs_vnop_deleteextattr(void *v)
3199 {
3200 	struct vop_deleteextattr_args /* {
3201 		struct vnode *a_vp;
3202 		int a_attrnamespace;
3203 		const char *a_name;
3204 		kauth_cred_t a_cred;
3205 	}; */ *ap = v;
3206 	PUFFS_MSG_VARS(vn, deleteextattr);
3207 	struct vnode *vp = ap->a_vp;
3208 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
3209 	int attrnamespace = ap->a_attrnamespace;
3210 	const char *name = ap->a_name;
3211 	int error;
3212 
3213 	PUFFS_MSG_ALLOC(vn, deleteextattr);
3214 	deleteextattr_msg->pvnr_attrnamespace = attrnamespace;
3215 	strlcpy(deleteextattr_msg->pvnr_attrname, name,
3216 	    sizeof(deleteextattr_msg->pvnr_attrname));
3217 	puffs_credcvt(&deleteextattr_msg->pvnr_cred, ap->a_cred);
3218 
3219 	puffs_msg_setinfo(park_deleteextattr,
3220 	    PUFFSOP_VN, PUFFS_VN_DELETEEXTATTR, VPTOPNC(vp));
3221 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_deleteextattr,
3222 	    vp->v_data, NULL, error);
3223 
3224 	error = checkerr(pmp, error, __func__);
3225 
3226 	PUFFS_MSG_RELEASE(deleteextattr);
3227 	return error;
3228 }
3229 
3230 /*
3231  * spec & fifo.  These call the miscfs spec and fifo vectors, but issue
3232  * FAF update information for the puffs node first.
3233  */
3234 int
3235 puffs_vnop_spec_read(void *v)
3236 {
3237 	struct vop_read_args /* {
3238 		const struct vnodeop_desc *a_desc;
3239 		struct vnode *a_vp;
3240 		struct uio *a_uio;
3241 		int a_ioflag;
3242 		kauth_cred_t a_cred;
3243 	} */ *ap = v;
3244 
3245 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
3246 	return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
3247 }
3248 
3249 int
3250 puffs_vnop_spec_write(void *v)
3251 {
3252 	struct vop_write_args /* {
3253 		const struct vnodeop_desc *a_desc;
3254 		struct vnode *a_vp;
3255 		struct uio *a_uio;
3256 		int a_ioflag;
3257 		kauth_cred_t a_cred;
3258 	} */ *ap = v;
3259 
3260 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
3261 	return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
3262 }
3263 
3264 int
3265 puffs_vnop_fifo_read(void *v)
3266 {
3267 	struct vop_read_args /* {
3268 		const struct vnodeop_desc *a_desc;
3269 		struct vnode *a_vp;
3270 		struct uio *a_uio;
3271 		int a_ioflag;
3272 		kauth_cred_t a_cred;
3273 	} */ *ap = v;
3274 
3275 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
3276 	return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
3277 }
3278 
3279 int
3280 puffs_vnop_fifo_write(void *v)
3281 {
3282 	struct vop_write_args /* {
3283 		const struct vnodeop_desc *a_desc;
3284 		struct vnode *a_vp;
3285 		struct uio *a_uio;
3286 		int a_ioflag;
3287 		kauth_cred_t a_cred;
3288 	} */ *ap = v;
3289 
3290 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
3291 	return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
3292 }
3293