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