xref: /netbsd-src/sys/fs/puffs/puffs_vnops.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: puffs_vnops.c,v 1.161 2011/10/30 13:24:13 hannken 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.161 2011/10/30 13:24:13 hannken 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 },	/* 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 	/*
843 	 * A lock is required so that we do not race with
844 	 * setattr, write and fsync when changing vp->v_size.
845 	 * This is critical, since setting a stall smaler value
846 	 * triggers a file truncate in uvm_vnp_setsize(), which
847 	 * most of the time means data corruption (a chunk of
848 	 * data is replaced by zeroes). This can be removed if
849 	 * we decide one day that VOP_GETATTR must operate on
850 	 * a locked vnode.
851 	 *
852 	 * XXX Should be useless now that VOP_GETATTR has been
853 	 *     fixed to always require a shared lock at least.
854 	 */
855 	mutex_enter(&pn->pn_sizemtx);
856 
857 	REFPN(pn);
858 	vap = ap->a_vap;
859 
860 	PUFFS_MSG_ALLOC(vn, getattr);
861 	vattr_null(&getattr_msg->pvnr_va);
862 	puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred);
863 	puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
864 	    PUFFS_VN_GETATTR, VPTOPNC(vp));
865 
866 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
867 	error = checkerr(pmp, error, __func__);
868 	if (error)
869 		goto out;
870 
871 	rvap = &getattr_msg->pvnr_va;
872 	/*
873 	 * Don't listen to the file server regarding special device
874 	 * size info, the file server doesn't know anything about them.
875 	 */
876 	if (vp->v_type == VBLK || vp->v_type == VCHR)
877 		rvap->va_size = vp->v_size;
878 
879 	/* Ditto for blocksize (ufs comment: this doesn't belong here) */
880 	if (vp->v_type == VBLK)
881 		rvap->va_blocksize = BLKDEV_IOSIZE;
882 	else if (vp->v_type == VCHR)
883 		rvap->va_blocksize = MAXBSIZE;
884 
885 	(void) memcpy(vap, rvap, sizeof(struct vattr));
886 	vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
887 
888 	if (pn->pn_stat & PNODE_METACACHE_ATIME)
889 		vap->va_atime = pn->pn_mc_atime;
890 	if (pn->pn_stat & PNODE_METACACHE_CTIME)
891 		vap->va_ctime = pn->pn_mc_ctime;
892 	if (pn->pn_stat & PNODE_METACACHE_MTIME)
893 		vap->va_mtime = pn->pn_mc_mtime;
894 	if (pn->pn_stat & PNODE_METACACHE_SIZE) {
895 		vap->va_size = pn->pn_mc_size;
896 	} else {
897 		if (rvap->va_size != VNOVAL
898 		    && vp->v_type != VBLK && vp->v_type != VCHR) {
899 			uvm_vnp_setsize(vp, rvap->va_size);
900 			pn->pn_serversize = rvap->va_size;
901 		}
902 	}
903 
904  out:
905 	puffs_releasenode(pn);
906 	PUFFS_MSG_RELEASE(getattr);
907 
908 	mutex_exit(&pn->pn_sizemtx);
909 
910 	return error;
911 }
912 
913 #define SETATTR_CHSIZE	0x01
914 #define SETATTR_ASYNC	0x02
915 static int
916 dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags)
917 {
918 	PUFFS_MSG_VARS(vn, setattr);
919 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
920 	struct puffs_node *pn = vp->v_data;
921 	int error = 0;
922 
923 	KASSERT(!(flags & SETATTR_CHSIZE) || mutex_owned(&pn->pn_sizemtx));
924 
925 	if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
926 	    (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
927 	    || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
928 	    || vap->va_mode != (mode_t)VNOVAL))
929 		return EROFS;
930 
931 	if ((vp->v_mount->mnt_flag & MNT_RDONLY)
932 	    && vp->v_type == VREG && vap->va_size != VNOVAL)
933 		return EROFS;
934 
935 	/*
936 	 * Flush metacache first.  If we are called with some explicit
937 	 * parameters, treat them as information overriding metacache
938 	 * information.
939 	 */
940 	if (pn->pn_stat & PNODE_METACACHE_MASK) {
941 		if ((pn->pn_stat & PNODE_METACACHE_ATIME)
942 		    && vap->va_atime.tv_sec == VNOVAL)
943 			vap->va_atime = pn->pn_mc_atime;
944 		if ((pn->pn_stat & PNODE_METACACHE_CTIME)
945 		    && vap->va_ctime.tv_sec == VNOVAL)
946 			vap->va_ctime = pn->pn_mc_ctime;
947 		if ((pn->pn_stat & PNODE_METACACHE_MTIME)
948 		    && vap->va_mtime.tv_sec == VNOVAL)
949 			vap->va_mtime = pn->pn_mc_mtime;
950 		if ((pn->pn_stat & PNODE_METACACHE_SIZE)
951 		    && vap->va_size == VNOVAL)
952 			vap->va_size = pn->pn_mc_size;
953 
954 		pn->pn_stat &= ~PNODE_METACACHE_MASK;
955 	}
956 
957 	PUFFS_MSG_ALLOC(vn, setattr);
958 	(void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
959 	puffs_credcvt(&setattr_msg->pvnr_cred, cred);
960 	puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
961 	    PUFFS_VN_SETATTR, VPTOPNC(vp));
962 	if (flags & SETATTR_ASYNC)
963 		puffs_msg_setfaf(park_setattr);
964 
965 	puffs_msg_enqueue(pmp, park_setattr);
966 	if ((flags & SETATTR_ASYNC) == 0)
967 		error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
968 	PUFFS_MSG_RELEASE(setattr);
969 	if ((flags & SETATTR_ASYNC) == 0) {
970 		error = checkerr(pmp, error, __func__);
971 		if (error)
972 			return error;
973 	} else {
974 		error = 0;
975 	}
976 
977 	if (vap->va_size != VNOVAL) {
978 		pn->pn_serversize = vap->va_size;
979 		if (flags & SETATTR_CHSIZE)
980 			uvm_vnp_setsize(vp, vap->va_size);
981 	}
982 
983 	return 0;
984 }
985 
986 int
987 puffs_vnop_setattr(void *v)
988 {
989 	struct vop_getattr_args /* {
990 		const struct vnodeop_desc *a_desc;
991 		struct vnode *a_vp;
992 		struct vattr *a_vap;
993 		kauth_cred_t a_cred;
994 	} */ *ap = v;
995 	struct puffs_node *pn = ap->a_vp->v_data;
996 	int error;
997 
998 	mutex_enter(&pn->pn_sizemtx);
999 	error = dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE);
1000 	mutex_exit(&pn->pn_sizemtx);
1001 
1002 	return error;
1003 }
1004 
1005 static __inline int
1006 doinact(struct puffs_mount *pmp, int iaflag)
1007 {
1008 
1009 	if (EXISTSOP(pmp, INACTIVE))
1010 		if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
1011 			if (iaflag || ALLOPS(pmp))
1012 				return 1;
1013 			else
1014 				return 0;
1015 		else
1016 			return 1;
1017 	else
1018 		return 0;
1019 }
1020 
1021 static void
1022 callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
1023 {
1024 	int error;
1025 	PUFFS_MSG_VARS(vn, inactive);
1026 
1027 	if (doinact(pmp, iaflag)) {
1028 		PUFFS_MSG_ALLOC(vn, inactive);
1029 		puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1030 		    PUFFS_VN_INACTIVE, ck);
1031 
1032 		PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error);
1033 		PUFFS_MSG_RELEASE(inactive);
1034 	}
1035 }
1036 
1037 /* XXX: callinactive can't setback */
1038 int
1039 puffs_vnop_inactive(void *v)
1040 {
1041 	struct vop_inactive_args /* {
1042 		const struct vnodeop_desc *a_desc;
1043 		struct vnode *a_vp;
1044 	} */ *ap = v;
1045 	PUFFS_MSG_VARS(vn, inactive);
1046 	struct vnode *vp = ap->a_vp;
1047 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1048 	struct puffs_node *pnode;
1049 	int error;
1050 
1051 	pnode = vp->v_data;
1052 	mutex_enter(&pnode->pn_sizemtx);
1053 
1054 	if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
1055 		flushvncache(vp, 0, 0, false);
1056 		PUFFS_MSG_ALLOC(vn, inactive);
1057 		puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1058 		    PUFFS_VN_INACTIVE, VPTOPNC(vp));
1059 
1060 		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_inactive, vp->v_data,
1061 		    NULL, error);
1062 		PUFFS_MSG_RELEASE(inactive);
1063 	}
1064 	pnode->pn_stat &= ~PNODE_DOINACT;
1065 
1066 	/*
1067 	 * file server thinks it's gone?  then don't be afraid care,
1068 	 * node's life was already all it would ever be
1069 	 */
1070 	if (pnode->pn_stat & PNODE_NOREFS) {
1071 		pnode->pn_stat |= PNODE_DYING;
1072 		*ap->a_recycle = true;
1073 	}
1074 
1075 	mutex_exit(&pnode->pn_sizemtx);
1076 	VOP_UNLOCK(vp);
1077 
1078 	return 0;
1079 }
1080 
1081 static void
1082 callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck)
1083 {
1084 	PUFFS_MSG_VARS(vn, reclaim);
1085 
1086 	if (!EXISTSOP(pmp, RECLAIM))
1087 		return;
1088 
1089 	PUFFS_MSG_ALLOC(vn, reclaim);
1090 	puffs_msg_setfaf(park_reclaim);
1091 	puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);
1092 
1093 	puffs_msg_enqueue(pmp, park_reclaim);
1094 	PUFFS_MSG_RELEASE(reclaim);
1095 }
1096 
1097 /*
1098  * always FAF, we don't really care if the server wants to fail to
1099  * reclaim the node or not
1100  */
1101 int
1102 puffs_vnop_reclaim(void *v)
1103 {
1104 	struct vop_reclaim_args /* {
1105 		const struct vnodeop_desc *a_desc;
1106 		struct vnode *a_vp;
1107 	} */ *ap = v;
1108 	struct vnode *vp = ap->a_vp;
1109 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1110 	struct puffs_node *pnode = vp->v_data;
1111 	bool notifyserver = true;
1112 
1113 	/*
1114 	 * first things first: check if someone is trying to reclaim the
1115 	 * root vnode.  do not allow that to travel to userspace.
1116 	 * Note that we don't need to take the lock similarly to
1117 	 * puffs_root(), since there is only one of us.
1118 	 */
1119 	if (vp->v_vflag & VV_ROOT) {
1120 		mutex_enter(&pmp->pmp_lock);
1121 		KASSERT(pmp->pmp_root != NULL);
1122 		pmp->pmp_root = NULL;
1123 		mutex_exit(&pmp->pmp_lock);
1124 		notifyserver = false;
1125 	}
1126 
1127 	/*
1128 	 * purge info from kernel before issueing FAF, since we
1129 	 * don't really know when we'll get around to it after
1130 	 * that and someone might race us into node creation
1131 	 */
1132 	mutex_enter(&pmp->pmp_lock);
1133 	LIST_REMOVE(pnode, pn_hashent);
1134 	mutex_exit(&pmp->pmp_lock);
1135 
1136 	if (notifyserver)
1137 		callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp));
1138 
1139 	puffs_putvnode(vp);
1140 	vp->v_data = NULL;
1141 
1142 	return 0;
1143 }
1144 
1145 #define CSIZE sizeof(**ap->a_cookies)
1146 int
1147 puffs_vnop_readdir(void *v)
1148 {
1149 	struct vop_readdir_args /* {
1150 		const struct vnodeop_desc *a_desc;
1151 		struct vnode *a_vp;
1152 		struct uio *a_uio;
1153 		kauth_cred_t a_cred;
1154 		int *a_eofflag;
1155 		off_t **a_cookies;
1156 		int *a_ncookies;
1157 	} */ *ap = v;
1158 	PUFFS_MSG_VARS(vn, readdir);
1159 	struct vnode *vp = ap->a_vp;
1160 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1161 	size_t argsize, tomove, cookiemem, cookiesmax;
1162 	struct uio *uio = ap->a_uio;
1163 	size_t howmuch, resid;
1164 	int error;
1165 
1166 	/*
1167 	 * ok, so we need: resid + cookiemem = maxreq
1168 	 * => resid + cookiesize * (resid/minsize) = maxreq
1169 	 * => resid + cookiesize/minsize * resid = maxreq
1170 	 * => (cookiesize/minsize + 1) * resid = maxreq
1171 	 * => resid = maxreq / (cookiesize/minsize + 1)
1172 	 *
1173 	 * Since cookiesize <= minsize and we're not very big on floats,
1174 	 * we approximate that to be 1.  Therefore:
1175 	 *
1176 	 * resid = maxreq / 2;
1177 	 *
1178 	 * Well, at least we didn't have to use differential equations
1179 	 * or the Gram-Schmidt process.
1180 	 *
1181 	 * (yes, I'm very afraid of this)
1182 	 */
1183 	KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1184 
1185 	if (ap->a_cookies) {
1186 		KASSERT(ap->a_ncookies != NULL);
1187 		if (pmp->pmp_args.pa_fhsize == 0)
1188 			return EOPNOTSUPP;
1189 		resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1190 		cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1191 		cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1192 	} else {
1193 		resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1194 		cookiesmax = 0;
1195 		cookiemem = 0;
1196 	}
1197 
1198 	argsize = sizeof(struct puffs_vnmsg_readdir);
1199 	tomove = resid + cookiemem;
1200 	puffs_msgmem_alloc(argsize + tomove, &park_readdir,
1201 	    (void *)&readdir_msg, 1);
1202 
1203 	puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
1204 	readdir_msg->pvnr_offset = uio->uio_offset;
1205 	readdir_msg->pvnr_resid = resid;
1206 	readdir_msg->pvnr_ncookies = cookiesmax;
1207 	readdir_msg->pvnr_eofflag = 0;
1208 	readdir_msg->pvnr_dentoff = cookiemem;
1209 	puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
1210 	    PUFFS_VN_READDIR, VPTOPNC(vp));
1211 	puffs_msg_setdelta(park_readdir, tomove);
1212 
1213 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
1214 	error = checkerr(pmp, error, __func__);
1215 	if (error)
1216 		goto out;
1217 
1218 	/* userspace is cheating? */
1219 	if (readdir_msg->pvnr_resid > resid) {
1220 		puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1221 		    "resid grew", VPTOPNC(vp));
1222 		ERROUT(EPROTO);
1223 	}
1224 	if (readdir_msg->pvnr_ncookies > cookiesmax) {
1225 		puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1226 		    "too many cookies", VPTOPNC(vp));
1227 		ERROUT(EPROTO);
1228 	}
1229 
1230 	/* check eof */
1231 	if (readdir_msg->pvnr_eofflag)
1232 		*ap->a_eofflag = 1;
1233 
1234 	/* bouncy-wouncy with the directory data */
1235 	howmuch = resid - readdir_msg->pvnr_resid;
1236 
1237 	/* force eof if no data was returned (getcwd() needs this) */
1238 	if (howmuch == 0) {
1239 		*ap->a_eofflag = 1;
1240 		goto out;
1241 	}
1242 
1243 	error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
1244 	if (error)
1245 		goto out;
1246 
1247 	/* provide cookies to caller if so desired */
1248 	if (ap->a_cookies) {
1249 		KASSERT(curlwp != uvm.pagedaemon_lwp);
1250 		*ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE,
1251 		    M_TEMP, M_WAITOK);
1252 		*ap->a_ncookies = readdir_msg->pvnr_ncookies;
1253 		memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
1254 		    *ap->a_ncookies*CSIZE);
1255 	}
1256 
1257 	/* next readdir starts here */
1258 	uio->uio_offset = readdir_msg->pvnr_offset;
1259 
1260  out:
1261 	puffs_msgmem_release(park_readdir);
1262 	return error;
1263 }
1264 #undef CSIZE
1265 
1266 /*
1267  * poll works by consuming the bitmask in pn_revents.  If there are
1268  * events available, poll returns immediately.  If not, it issues a
1269  * poll to userspace, selrecords itself and returns with no available
1270  * events.  When the file server returns, it executes puffs_parkdone_poll(),
1271  * where available events are added to the bitmask.  selnotify() is
1272  * then also executed by that function causing us to enter here again
1273  * and hopefully find the missing bits (unless someone got them first,
1274  * in which case it starts all over again).
1275  */
1276 int
1277 puffs_vnop_poll(void *v)
1278 {
1279 	struct vop_poll_args /* {
1280 		const struct vnodeop_desc *a_desc;
1281 		struct vnode *a_vp;
1282 		int a_events;
1283 	} */ *ap = v;
1284 	PUFFS_MSG_VARS(vn, poll);
1285 	struct vnode *vp = ap->a_vp;
1286 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1287 	struct puffs_node *pn = vp->v_data;
1288 	int events, error;
1289 
1290 	if (EXISTSOP(pmp, POLL)) {
1291 		mutex_enter(&pn->pn_mtx);
1292 		events = pn->pn_revents & ap->a_events;
1293 		if (events & ap->a_events) {
1294 			pn->pn_revents &= ~ap->a_events;
1295 			mutex_exit(&pn->pn_mtx);
1296 
1297 			return events;
1298 		} else {
1299 			puffs_referencenode(pn);
1300 			mutex_exit(&pn->pn_mtx);
1301 
1302 			PUFFS_MSG_ALLOC(vn, poll);
1303 			poll_msg->pvnr_events = ap->a_events;
1304 			puffs_msg_setinfo(park_poll, PUFFSOP_VN,
1305 			    PUFFS_VN_POLL, VPTOPNC(vp));
1306 			puffs_msg_setcall(park_poll, puffs_parkdone_poll, pn);
1307 			selrecord(curlwp, &pn->pn_sel);
1308 
1309 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_poll, vp->v_data,
1310 			    NULL, error);
1311 			PUFFS_MSG_RELEASE(poll);
1312 
1313 			return 0;
1314 		}
1315 	} else {
1316 		return genfs_poll(v);
1317 	}
1318 }
1319 
1320 static int
1321 flushvncache(struct vnode *vp, off_t offlo, off_t offhi, bool wait)
1322 {
1323 	struct puffs_node *pn = VPTOPP(vp);
1324 	struct vattr va;
1325 	int pflags, error;
1326 
1327 	/* flush out information from our metacache, see vop_setattr */
1328 	if (pn->pn_stat & PNODE_METACACHE_MASK
1329 	    && (pn->pn_stat & PNODE_DYING) == 0) {
1330 		vattr_null(&va);
1331 		error = dosetattr(vp, &va, FSCRED,
1332 		    SETATTR_CHSIZE | (wait ? 0 : SETATTR_ASYNC));
1333 		if (error)
1334 			return error;
1335 	}
1336 
1337 	/*
1338 	 * flush pages to avoid being overly dirty
1339 	 */
1340 	pflags = PGO_CLEANIT;
1341 	if (wait)
1342 		pflags |= PGO_SYNCIO;
1343 	mutex_enter(vp->v_interlock);
1344 	return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags);
1345 }
1346 
1347 int
1348 puffs_vnop_fsync(void *v)
1349 {
1350 	struct vop_fsync_args /* {
1351 		const struct vnodeop_desc *a_desc;
1352 		struct vnode *a_vp;
1353 		kauth_cred_t a_cred;
1354 		int a_flags;
1355 		off_t a_offlo;
1356 		off_t a_offhi;
1357 	} */ *ap = v;
1358 	PUFFS_MSG_VARS(vn, fsync);
1359 	struct vnode *vp = ap->a_vp;
1360 	struct puffs_node *pn = VPTOPP(vp);
1361 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1362 	int error, dofaf;
1363 
1364 	if (ap->a_flags & FSYNC_WAIT) {
1365 		mutex_enter(&pn->pn_sizemtx);
1366 	} else {
1367 		if (mutex_tryenter(&pn->pn_sizemtx) == 0)
1368 			return EDEADLK;
1369 	}
1370 
1371 	error = flushvncache(vp, ap->a_offlo, ap->a_offhi,
1372 	    (ap->a_flags & FSYNC_WAIT) == FSYNC_WAIT);
1373 	if (error)
1374 		goto out;
1375 
1376 	/*
1377 	 * HELLO!  We exit already here if the user server does not
1378 	 * support fsync OR if we should call fsync for a node which
1379 	 * has references neither in the kernel or the fs server.
1380 	 * Otherwise we continue to issue fsync() forward.
1381 	 */
1382 	error = 0;
1383 	if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1384 		goto out;
1385 
1386 	dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1387 	/*
1388 	 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1389 	 * only FAFs for those.  Otherwise there's a danger of deadlock,
1390 	 * since the execution context here might be the user server
1391 	 * doing some operation on another fs, which in turn caused a
1392 	 * vnode to be reclaimed from the freelist for this fs.
1393 	 */
1394 	if (dofaf == 0) {
1395 		mutex_enter(vp->v_interlock);
1396 		if (vp->v_iflag & VI_XLOCK)
1397 			dofaf = 1;
1398 		mutex_exit(vp->v_interlock);
1399 	}
1400 
1401 	PUFFS_MSG_ALLOC(vn, fsync);
1402 	if (dofaf)
1403 		puffs_msg_setfaf(park_fsync);
1404 
1405 	puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred);
1406 	fsync_msg->pvnr_flags = ap->a_flags;
1407 	fsync_msg->pvnr_offlo = ap->a_offlo;
1408 	fsync_msg->pvnr_offhi = ap->a_offhi;
1409 	puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
1410 	    PUFFS_VN_FSYNC, VPTOPNC(vp));
1411 
1412 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
1413 	PUFFS_MSG_RELEASE(fsync);
1414 
1415 	error = checkerr(pmp, error, __func__);
1416 
1417 out:
1418 	mutex_exit(&pn->pn_sizemtx);
1419 	return error;
1420 }
1421 
1422 int
1423 puffs_vnop_seek(void *v)
1424 {
1425 	struct vop_seek_args /* {
1426 		const struct vnodeop_desc *a_desc;
1427 		struct vnode *a_vp;
1428 		off_t a_oldoff;
1429 		off_t a_newoff;
1430 		kauth_cred_t a_cred;
1431 	} */ *ap = v;
1432 	PUFFS_MSG_VARS(vn, seek);
1433 	struct vnode *vp = ap->a_vp;
1434 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1435 	int error;
1436 
1437 	PUFFS_MSG_ALLOC(vn, seek);
1438 	seek_msg->pvnr_oldoff = ap->a_oldoff;
1439 	seek_msg->pvnr_newoff = ap->a_newoff;
1440 	puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred);
1441 	puffs_msg_setinfo(park_seek, PUFFSOP_VN,
1442 	    PUFFS_VN_SEEK, VPTOPNC(vp));
1443 
1444 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_seek, vp->v_data, NULL, error);
1445 	PUFFS_MSG_RELEASE(seek);
1446 	return checkerr(pmp, error, __func__);
1447 }
1448 
1449 static int
1450 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1451 	struct componentname *cnp)
1452 {
1453 	PUFFS_MSG_VARS(vn, remove);
1454 	int error;
1455 
1456 	PUFFS_MSG_ALLOC(vn, remove);
1457 	remove_msg->pvnr_cookie_targ = ck;
1458 	puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1459 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1460 	puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);
1461 
1462 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
1463 	PUFFS_MSG_RELEASE(remove);
1464 
1465 	return checkerr(pmp, error, __func__);
1466 }
1467 
1468 /*
1469  * XXX: can't use callremove now because can't catch setbacks with
1470  * it due to lack of a pnode argument.
1471  */
1472 int
1473 puffs_vnop_remove(void *v)
1474 {
1475 	struct vop_remove_args /* {
1476 		const struct vnodeop_desc *a_desc;
1477 		struct vnode *a_dvp;
1478 		struct vnode *a_vp;
1479 		struct componentname *a_cnp;
1480 	} */ *ap = v;
1481 	PUFFS_MSG_VARS(vn, remove);
1482 	struct vnode *dvp = ap->a_dvp;
1483 	struct vnode *vp = ap->a_vp;
1484 	struct puffs_node *dpn = VPTOPP(dvp);
1485 	struct puffs_node *pn = VPTOPP(vp);
1486 	struct componentname *cnp = ap->a_cnp;
1487 	struct mount *mp = dvp->v_mount;
1488 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1489 	int error;
1490 
1491 	PUFFS_MSG_ALLOC(vn, remove);
1492 	remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
1493 	puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1494 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1495 	puffs_msg_setinfo(park_remove, PUFFSOP_VN,
1496 	    PUFFS_VN_REMOVE, VPTOPNC(dvp));
1497 
1498 	puffs_msg_enqueue(pmp, park_remove);
1499 	REFPN_AND_UNLOCKVP(dvp, dpn);
1500 	if (dvp == vp)
1501 		REFPN(pn);
1502 	else
1503 		REFPN_AND_UNLOCKVP(vp, pn);
1504 	error = puffs_msg_wait2(pmp, park_remove, dpn, pn);
1505 
1506 	PUFFS_MSG_RELEASE(remove);
1507 
1508 	RELEPN_AND_VP(dvp, dpn);
1509 	RELEPN_AND_VP(vp, pn);
1510 
1511 	error = checkerr(pmp, error, __func__);
1512 	return error;
1513 }
1514 
1515 int
1516 puffs_vnop_mkdir(void *v)
1517 {
1518 	struct vop_mkdir_args /* {
1519 		const struct vnodeop_desc *a_desc;
1520 		struct vnode *a_dvp;
1521 		struct vnode **a_vpp;
1522 		struct componentname *a_cnp;
1523 		struct vattr *a_vap;
1524 	} */ *ap = v;
1525 	PUFFS_MSG_VARS(vn, mkdir);
1526 	struct vnode *dvp = ap->a_dvp;
1527 	struct puffs_node *dpn = VPTOPP(dvp);
1528 	struct componentname *cnp = ap->a_cnp;
1529 	struct mount *mp = dvp->v_mount;
1530 	struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1531 	int error;
1532 
1533 	PUFFS_MSG_ALLOC(vn, mkdir);
1534 	puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1535 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1536 	mkdir_msg->pvnr_va = *ap->a_vap;
1537 	puffs_msg_setinfo(park_mkdir, PUFFSOP_VN,
1538 	    PUFFS_VN_MKDIR, VPTOPNC(dvp));
1539 
1540 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error);
1541 
1542 	error = checkerr(pmp, error, __func__);
1543 	if (error)
1544 		goto out;
1545 
1546 	error = puffs_newnode(mp, dvp, ap->a_vpp,
1547 	    mkdir_msg->pvnr_newnode, cnp, VDIR, 0);
1548 	if (error)
1549 		puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie,
1550 		    mkdir_msg->pvnr_newnode, cnp);
1551 
1552  out:
1553 	vput(dvp);
1554 	PUFFS_MSG_RELEASE(mkdir);
1555 	return error;
1556 }
1557 
1558 static int
1559 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1560 	struct componentname *cnp)
1561 {
1562 	PUFFS_MSG_VARS(vn, rmdir);
1563 	int error;
1564 
1565 	PUFFS_MSG_ALLOC(vn, rmdir);
1566 	rmdir_msg->pvnr_cookie_targ = ck;
1567 	puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1568 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1569 	puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck);
1570 
1571 	PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error);
1572 	PUFFS_MSG_RELEASE(rmdir);
1573 
1574 	return checkerr(pmp, error, __func__);
1575 }
1576 
1577 int
1578 puffs_vnop_rmdir(void *v)
1579 {
1580 	struct vop_rmdir_args /* {
1581 		const struct vnodeop_desc *a_desc;
1582 		struct vnode *a_dvp;
1583 		struct vnode *a_vp;
1584 		struct componentname *a_cnp;
1585 	} */ *ap = v;
1586 	PUFFS_MSG_VARS(vn, rmdir);
1587 	struct vnode *dvp = ap->a_dvp;
1588 	struct vnode *vp = ap->a_vp;
1589 	struct puffs_node *dpn = VPTOPP(dvp);
1590 	struct puffs_node *pn = VPTOPP(vp);
1591 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1592 	struct componentname *cnp = ap->a_cnp;
1593 	int error;
1594 
1595 	PUFFS_MSG_ALLOC(vn, rmdir);
1596 	rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1597 	puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1598 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1599 	puffs_msg_setinfo(park_rmdir, PUFFSOP_VN,
1600 	    PUFFS_VN_RMDIR, VPTOPNC(dvp));
1601 
1602 	puffs_msg_enqueue(pmp, park_rmdir);
1603 	REFPN_AND_UNLOCKVP(dvp, dpn);
1604 	REFPN_AND_UNLOCKVP(vp, pn);
1605 	error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn);
1606 
1607 	PUFFS_MSG_RELEASE(rmdir);
1608 
1609 	/* XXX: some call cache_purge() *for both vnodes* here, investigate */
1610 	RELEPN_AND_VP(dvp, dpn);
1611 	RELEPN_AND_VP(vp, pn);
1612 
1613 	return error;
1614 }
1615 
1616 int
1617 puffs_vnop_link(void *v)
1618 {
1619 	struct vop_link_args /* {
1620 		const struct vnodeop_desc *a_desc;
1621 		struct vnode *a_dvp;
1622 		struct vnode *a_vp;
1623 		struct componentname *a_cnp;
1624 	} */ *ap = v;
1625 	PUFFS_MSG_VARS(vn, link);
1626 	struct vnode *dvp = ap->a_dvp;
1627 	struct vnode *vp = ap->a_vp;
1628 	struct puffs_node *dpn = VPTOPP(dvp);
1629 	struct puffs_node *pn = VPTOPP(vp);
1630 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1631 	struct componentname *cnp = ap->a_cnp;
1632 	int error;
1633 
1634 	PUFFS_MSG_ALLOC(vn, link);
1635 	link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1636 	puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1637 	    cnp, PUFFS_USE_FULLPNBUF(pmp));
1638 	puffs_msg_setinfo(park_link, PUFFSOP_VN,
1639 	    PUFFS_VN_LINK, VPTOPNC(dvp));
1640 
1641 	puffs_msg_enqueue(pmp, park_link);
1642 	REFPN_AND_UNLOCKVP(dvp, dpn);
1643 	REFPN(pn);
1644 	error = puffs_msg_wait2(pmp, park_link, dpn, pn);
1645 
1646 	PUFFS_MSG_RELEASE(link);
1647 
1648 	error = checkerr(pmp, error, __func__);
1649 
1650 	/*
1651 	 * XXX: stay in touch with the cache.  I don't like this, but
1652 	 * don't have a better solution either.  See also puffs_rename().
1653 	 */
1654 	if (error == 0)
1655 		puffs_updatenode(pn, PUFFS_UPDATECTIME, 0);
1656 
1657 	RELEPN_AND_VP(dvp, dpn);
1658 	puffs_releasenode(pn);
1659 
1660 	return error;
1661 }
1662 
1663 int
1664 puffs_vnop_symlink(void *v)
1665 {
1666 	struct vop_symlink_args /* {
1667 		const struct vnodeop_desc *a_desc;
1668 		struct vnode *a_dvp;
1669 		struct vnode **a_vpp;
1670 		struct componentname *a_cnp;
1671 		struct vattr *a_vap;
1672 		char *a_target;
1673 	} */ *ap = v;
1674 	PUFFS_MSG_VARS(vn, symlink);
1675 	struct vnode *dvp = ap->a_dvp;
1676 	struct puffs_node *dpn = VPTOPP(dvp);
1677 	struct mount *mp = dvp->v_mount;
1678 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1679 	struct componentname *cnp = ap->a_cnp;
1680 	int error;
1681 
1682 	*ap->a_vpp = NULL;
1683 
1684 	PUFFS_MSG_ALLOC(vn, symlink);
1685 	puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1686 		cnp, PUFFS_USE_FULLPNBUF(pmp));
1687 	symlink_msg->pvnr_va = *ap->a_vap;
1688 	(void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1689 	    sizeof(symlink_msg->pvnr_link));
1690 	puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
1691 	    PUFFS_VN_SYMLINK, VPTOPNC(dvp));
1692 
1693 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);
1694 
1695 	error = checkerr(pmp, error, __func__);
1696 	if (error)
1697 		goto out;
1698 
1699 	error = puffs_newnode(mp, dvp, ap->a_vpp,
1700 	    symlink_msg->pvnr_newnode, cnp, VLNK, 0);
1701 	if (error)
1702 		puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
1703 		    symlink_msg->pvnr_newnode, cnp);
1704 
1705  out:
1706 	vput(dvp);
1707 	PUFFS_MSG_RELEASE(symlink);
1708 
1709 	return error;
1710 }
1711 
1712 int
1713 puffs_vnop_readlink(void *v)
1714 {
1715 	struct vop_readlink_args /* {
1716 		const struct vnodeop_desc *a_desc;
1717 		struct vnode *a_vp;
1718 		struct uio *a_uio;
1719 		kauth_cred_t a_cred;
1720 	} */ *ap = v;
1721 	PUFFS_MSG_VARS(vn, readlink);
1722 	struct vnode *vp = ap->a_vp;
1723 	struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1724 	size_t linklen;
1725 	int error;
1726 
1727 	PUFFS_MSG_ALLOC(vn, readlink);
1728 	puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1729 	linklen = sizeof(readlink_msg->pvnr_link);
1730 	readlink_msg->pvnr_linklen = linklen;
1731 	puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
1732 	    PUFFS_VN_READLINK, VPTOPNC(vp));
1733 
1734 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
1735 	error = checkerr(pmp, error, __func__);
1736 	if (error)
1737 		goto out;
1738 
1739 	/* bad bad user file server */
1740 	if (readlink_msg->pvnr_linklen > linklen) {
1741 		puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
1742 		    "linklen too big", VPTOPNC(ap->a_vp));
1743 		error = EPROTO;
1744 		goto out;
1745 	}
1746 
1747 	error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
1748 	    ap->a_uio);
1749  out:
1750 	PUFFS_MSG_RELEASE(readlink);
1751 	return error;
1752 }
1753 
1754 int
1755 puffs_vnop_rename(void *v)
1756 {
1757 	struct vop_rename_args /* {
1758 		const struct vnodeop_desc *a_desc;
1759 		struct vnode *a_fdvp;
1760 		struct vnode *a_fvp;
1761 		struct componentname *a_fcnp;
1762 		struct vnode *a_tdvp;
1763 		struct vnode *a_tvp;
1764 		struct componentname *a_tcnp;
1765 	} */ *ap = v;
1766 	PUFFS_MSG_VARS(vn, rename);
1767 	struct vnode *fdvp = ap->a_fdvp, *fvp = ap->a_fvp;
1768 	struct vnode *tdvp = ap->a_tdvp, *tvp = ap->a_tvp;
1769 	struct puffs_node *fpn = ap->a_fvp->v_data;
1770 	struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
1771 	int error;
1772 	bool doabort = true;
1773 
1774 	if ((fvp->v_mount != tdvp->v_mount) ||
1775 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
1776 		ERROUT(EXDEV);
1777 	}
1778 
1779 	PUFFS_MSG_ALLOC(vn, rename);
1780 	rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
1781 	rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
1782 	if (tvp)
1783 		rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
1784 	else
1785 		rename_msg->pvnr_cookie_targ = NULL;
1786 	puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
1787 	    ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
1788 	puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
1789 	    ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
1790 	puffs_msg_setinfo(park_rename, PUFFSOP_VN,
1791 	    PUFFS_VN_RENAME, VPTOPNC(fdvp));
1792 
1793 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
1794 	doabort = false;
1795 	PUFFS_MSG_RELEASE(rename);
1796 	error = checkerr(pmp, error, __func__);
1797 
1798 	/*
1799 	 * XXX: stay in touch with the cache.  I don't like this, but
1800 	 * don't have a better solution either.  See also puffs_link().
1801 	 */
1802 	if (error == 0)
1803 		puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0);
1804 
1805  out:
1806 	if (doabort)
1807 		VOP_ABORTOP(tdvp, ap->a_tcnp);
1808 	if (tvp != NULL)
1809 		vput(tvp);
1810 	if (tdvp == tvp)
1811 		vrele(tdvp);
1812 	else
1813 		vput(tdvp);
1814 
1815 	if (doabort)
1816 		VOP_ABORTOP(fdvp, ap->a_fcnp);
1817 	vrele(fdvp);
1818 	vrele(fvp);
1819 
1820 	return error;
1821 }
1822 
1823 #define RWARGS(cont, iofl, move, offset, creds)				\
1824 	(cont)->pvnr_ioflag = (iofl);					\
1825 	(cont)->pvnr_resid = (move);					\
1826 	(cont)->pvnr_offset = (offset);					\
1827 	puffs_credcvt(&(cont)->pvnr_cred, creds)
1828 
1829 int
1830 puffs_vnop_read(void *v)
1831 {
1832 	struct vop_read_args /* {
1833 		const struct vnodeop_desc *a_desc;
1834 		struct vnode *a_vp;
1835 		struct uio *a_uio;
1836 		int a_ioflag;
1837 		kauth_cred_t a_cred;
1838 	} */ *ap = v;
1839 	PUFFS_MSG_VARS(vn, read);
1840 	struct vnode *vp = ap->a_vp;
1841 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1842 	struct uio *uio = ap->a_uio;
1843 	size_t tomove, argsize;
1844 	vsize_t bytelen;
1845 	int error;
1846 
1847 	read_msg = NULL;
1848 	error = 0;
1849 
1850 	/* std sanity */
1851 	if (uio->uio_resid == 0)
1852 		return 0;
1853 	if (uio->uio_offset < 0)
1854 		return EINVAL;
1855 
1856 	if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1857 		const int advice = IO_ADV_DECODE(ap->a_ioflag);
1858 
1859 		while (uio->uio_resid > 0) {
1860 			bytelen = MIN(uio->uio_resid,
1861 			    vp->v_size - uio->uio_offset);
1862 			if (bytelen == 0)
1863 				break;
1864 
1865 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
1866 			    UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
1867 			if (error)
1868 				break;
1869 		}
1870 
1871 		if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1872 			puffs_updatenode(VPTOPP(vp), PUFFS_UPDATEATIME, 0);
1873 	} else {
1874 		/*
1875 		 * in case it's not a regular file or we're operating
1876 		 * uncached, do read in the old-fashioned style,
1877 		 * i.e. explicit read operations
1878 		 */
1879 
1880 		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1881 		argsize = sizeof(struct puffs_vnmsg_read);
1882 		puffs_msgmem_alloc(argsize + tomove, &park_read,
1883 		    (void *)&read_msg, 1);
1884 
1885 		error = 0;
1886 		while (uio->uio_resid > 0) {
1887 			tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1888 			memset(read_msg, 0, argsize); /* XXX: touser KASSERT */
1889 			RWARGS(read_msg, ap->a_ioflag, tomove,
1890 			    uio->uio_offset, ap->a_cred);
1891 			puffs_msg_setinfo(park_read, PUFFSOP_VN,
1892 			    PUFFS_VN_READ, VPTOPNC(vp));
1893 			puffs_msg_setdelta(park_read, tomove);
1894 
1895 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data,
1896 			    NULL, error);
1897 			error = checkerr(pmp, error, __func__);
1898 			if (error)
1899 				break;
1900 
1901 			if (read_msg->pvnr_resid > tomove) {
1902 				puffs_senderr(pmp, PUFFS_ERR_READ,
1903 				    E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1904 				error = EPROTO;
1905 				break;
1906 			}
1907 
1908 			error = uiomove(read_msg->pvnr_data,
1909 			    tomove - read_msg->pvnr_resid, uio);
1910 
1911 			/*
1912 			 * in case the file is out of juice, resid from
1913 			 * userspace is != 0.  and the error-case is
1914 			 * quite obvious
1915 			 */
1916 			if (error || read_msg->pvnr_resid)
1917 				break;
1918 		}
1919 
1920 		puffs_msgmem_release(park_read);
1921 	}
1922 
1923 	return error;
1924 }
1925 
1926 /*
1927  * XXX: in case of a failure, this leaves uio in a bad state.
1928  * We could theoretically copy the uio and iovecs and "replay"
1929  * them the right amount after the userspace trip, but don't
1930  * bother for now.
1931  */
1932 int
1933 puffs_vnop_write(void *v)
1934 {
1935 	struct vop_write_args /* {
1936 		const struct vnodeop_desc *a_desc;
1937 		struct vnode *a_vp;
1938 		struct uio *a_uio;
1939 		int a_ioflag;
1940 		kauth_cred_t a_cred;
1941 	} */ *ap = v;
1942 	PUFFS_MSG_VARS(vn, write);
1943 	struct vnode *vp = ap->a_vp;
1944 	struct puffs_node *pn = VPTOPP(vp);
1945 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1946 	struct uio *uio = ap->a_uio;
1947 	size_t tomove, argsize;
1948 	off_t oldoff, newoff, origoff;
1949 	vsize_t bytelen;
1950 	int error, uflags;
1951 	int ubcflags;
1952 
1953 	error = uflags = 0;
1954 	write_msg = NULL;
1955 
1956 	mutex_enter(&pn->pn_sizemtx);
1957 
1958 	if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1959 		ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp);
1960 
1961 		/*
1962 		 * userspace *should* be allowed to control this,
1963 		 * but with UBC it's a bit unclear how to handle it
1964 		 */
1965 		if (ap->a_ioflag & IO_APPEND)
1966 			uio->uio_offset = vp->v_size;
1967 
1968 		origoff = uio->uio_offset;
1969 		while (uio->uio_resid > 0) {
1970 			uflags |= PUFFS_UPDATECTIME;
1971 			uflags |= PUFFS_UPDATEMTIME;
1972 			oldoff = uio->uio_offset;
1973 			bytelen = uio->uio_resid;
1974 
1975 			newoff = oldoff + bytelen;
1976 			if (vp->v_size < newoff) {
1977 				uvm_vnp_setwritesize(vp, newoff);
1978 			}
1979 			error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
1980 			    UVM_ADV_RANDOM, ubcflags);
1981 
1982 			/*
1983 			 * In case of a ubc_uiomove() error,
1984 			 * opt to not extend the file at all and
1985 			 * return an error.  Otherwise, if we attempt
1986 			 * to clear the memory we couldn't fault to,
1987 			 * we might generate a kernel page fault.
1988 			 */
1989 			if (vp->v_size < newoff) {
1990 				if (error == 0) {
1991 					uflags |= PUFFS_UPDATESIZE;
1992 					uvm_vnp_setsize(vp, newoff);
1993 				} else {
1994 					uvm_vnp_setwritesize(vp, vp->v_size);
1995 				}
1996 			}
1997 			if (error)
1998 				break;
1999 
2000 			/*
2001 			 * If we're writing large files, flush to file server
2002 			 * every 64k.  Otherwise we can very easily exhaust
2003 			 * kernel and user memory, as the file server cannot
2004 			 * really keep up with our writing speed.
2005 			 *
2006 			 * Note: this does *NOT* honor MNT_ASYNC, because
2007 			 * that gives userland too much say in the kernel.
2008 			 */
2009 			if (oldoff >> 16 != uio->uio_offset >> 16) {
2010 				mutex_enter(vp->v_interlock);
2011 				error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
2012 				    uio->uio_offset & ~0xffff,
2013 				    PGO_CLEANIT | PGO_SYNCIO);
2014 				if (error)
2015 					break;
2016 			}
2017 		}
2018 
2019 		/* synchronous I/O? */
2020 		if (error == 0 && ap->a_ioflag & IO_SYNC) {
2021 			mutex_enter(vp->v_interlock);
2022 			error = VOP_PUTPAGES(vp, trunc_page(origoff),
2023 			    round_page(uio->uio_offset),
2024 			    PGO_CLEANIT | PGO_SYNCIO);
2025 
2026 		/* write through page cache? */
2027 		} else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
2028 			mutex_enter(vp->v_interlock);
2029 			error = VOP_PUTPAGES(vp, trunc_page(origoff),
2030 			    round_page(uio->uio_offset), PGO_CLEANIT);
2031 		}
2032 
2033 		puffs_updatenode(VPTOPP(vp), uflags, vp->v_size);
2034 	} else {
2035 		/* tomove is non-increasing */
2036 		tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2037 		argsize = sizeof(struct puffs_vnmsg_write) + tomove;
2038 		puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1);
2039 
2040 		while (uio->uio_resid > 0) {
2041 			/* move data to buffer */
2042 			tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2043 			memset(write_msg, 0, argsize); /* XXX: touser KASSERT */
2044 			RWARGS(write_msg, ap->a_ioflag, tomove,
2045 			    uio->uio_offset, ap->a_cred);
2046 			error = uiomove(write_msg->pvnr_data, tomove, uio);
2047 			if (error)
2048 				break;
2049 
2050 			/* move buffer to userspace */
2051 			puffs_msg_setinfo(park_write, PUFFSOP_VN,
2052 			    PUFFS_VN_WRITE, VPTOPNC(vp));
2053 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data,
2054 			    NULL, error);
2055 			error = checkerr(pmp, error, __func__);
2056 			if (error)
2057 				break;
2058 
2059 			if (write_msg->pvnr_resid > tomove) {
2060 				puffs_senderr(pmp, PUFFS_ERR_WRITE,
2061 				    E2BIG, "resid grew", VPTOPNC(ap->a_vp));
2062 				error = EPROTO;
2063 				break;
2064 			}
2065 
2066 			/* adjust file size */
2067 			if (vp->v_size < uio->uio_offset)
2068 				uvm_vnp_setsize(vp, uio->uio_offset);
2069 
2070 			/* didn't move everything?  bad userspace.  bail */
2071 			if (write_msg->pvnr_resid != 0) {
2072 				error = EIO;
2073 				break;
2074 			}
2075 		}
2076 		puffs_msgmem_release(park_write);
2077 	}
2078 
2079 	mutex_exit(&pn->pn_sizemtx);
2080 	return error;
2081 }
2082 
2083 int
2084 puffs_vnop_print(void *v)
2085 {
2086 	struct vop_print_args /* {
2087 		struct vnode *a_vp;
2088 	} */ *ap = v;
2089 	PUFFS_MSG_VARS(vn, print);
2090 	struct vnode *vp = ap->a_vp;
2091 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2092 	struct puffs_node *pn = vp->v_data;
2093 	int error;
2094 
2095 	/* kernel portion */
2096 	printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
2097 	    "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
2098 	if (vp->v_type == VFIFO)
2099 		VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
2100 	printf("\n");
2101 
2102 	/* userspace portion */
2103 	if (EXISTSOP(pmp, PRINT)) {
2104 		PUFFS_MSG_ALLOC(vn, print);
2105 		puffs_msg_setinfo(park_print, PUFFSOP_VN,
2106 		    PUFFS_VN_PRINT, VPTOPNC(vp));
2107 		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
2108 		    NULL, error);
2109 		PUFFS_MSG_RELEASE(print);
2110 	}
2111 
2112 	return 0;
2113 }
2114 
2115 int
2116 puffs_vnop_pathconf(void *v)
2117 {
2118 	struct vop_pathconf_args /* {
2119 		const struct vnodeop_desc *a_desc;
2120 		struct vnode *a_vp;
2121 		int a_name;
2122 		register_t *a_retval;
2123 	} */ *ap = v;
2124 	PUFFS_MSG_VARS(vn, pathconf);
2125 	struct vnode *vp = ap->a_vp;
2126 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2127 	int error;
2128 
2129 	PUFFS_MSG_ALLOC(vn, pathconf);
2130 	pathconf_msg->pvnr_name = ap->a_name;
2131 	puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
2132 	    PUFFS_VN_PATHCONF, VPTOPNC(vp));
2133 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
2134 	error = checkerr(pmp, error, __func__);
2135 	if (!error)
2136 		*ap->a_retval = pathconf_msg->pvnr_retval;
2137 	PUFFS_MSG_RELEASE(pathconf);
2138 
2139 	return error;
2140 }
2141 
2142 int
2143 puffs_vnop_advlock(void *v)
2144 {
2145 	struct vop_advlock_args /* {
2146 		const struct vnodeop_desc *a_desc;
2147 		struct vnode *a_vp;
2148 		void *a_id;
2149 		int a_op;
2150 		struct flock *a_fl;
2151 		int a_flags;
2152 	} */ *ap = v;
2153 	PUFFS_MSG_VARS(vn, advlock);
2154 	struct vnode *vp = ap->a_vp;
2155 	struct puffs_node *pn = VPTOPP(vp);
2156 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2157 	int error;
2158 
2159 	if (!EXISTSOP(pmp, ADVLOCK))
2160 		return lf_advlock(ap, &pn->pn_lockf, vp->v_size);
2161 
2162 	PUFFS_MSG_ALLOC(vn, advlock);
2163 	(void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
2164 		     sizeof(advlock_msg->pvnr_fl));
2165 	advlock_msg->pvnr_id = ap->a_id;
2166 	advlock_msg->pvnr_op = ap->a_op;
2167 	advlock_msg->pvnr_flags = ap->a_flags;
2168 	puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
2169 	    PUFFS_VN_ADVLOCK, VPTOPNC(vp));
2170 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
2171 	error = checkerr(pmp, error, __func__);
2172 	PUFFS_MSG_RELEASE(advlock);
2173 
2174 	return error;
2175 }
2176 
2177 int
2178 puffs_vnop_abortop(void *v)
2179 {
2180 	struct vop_abortop_args /* {
2181 		struct vnode *a_dvp;
2182 		struct componentname *a_cnp;
2183 	}; */ *ap = v;
2184 	PUFFS_MSG_VARS(vn, abortop);
2185 	struct vnode *dvp = ap->a_dvp;
2186 	struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
2187 	struct componentname *cnp = ap->a_cnp;
2188 
2189 	if (EXISTSOP(pmp, ABORTOP)) {
2190 		PUFFS_MSG_ALLOC(vn, abortop);
2191 		puffs_makecn(&abortop_msg->pvnr_cn, &abortop_msg->pvnr_cn_cred,
2192 		    cnp, PUFFS_USE_FULLPNBUF(pmp));
2193 		puffs_msg_setfaf(park_abortop);
2194 		puffs_msg_setinfo(park_abortop, PUFFSOP_VN,
2195 		    PUFFS_VN_ABORTOP, VPTOPNC(dvp));
2196 
2197 		puffs_msg_enqueue(pmp, park_abortop);
2198 		PUFFS_MSG_RELEASE(abortop);
2199 	}
2200 
2201 	return genfs_abortop(v);
2202 }
2203 
2204 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
2205 
2206 /*
2207  * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
2208  */
2209 int
2210 puffs_vnop_strategy(void *v)
2211 {
2212 	struct vop_strategy_args /* {
2213 		const struct vnodeop_desc *a_desc;
2214 		struct vnode *a_vp;
2215 		struct buf *a_bp;
2216 	} */ *ap = v;
2217 	PUFFS_MSG_VARS(vn, rw);
2218 	struct vnode *vp = ap->a_vp;
2219 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2220 	struct puffs_node *pn;
2221 	struct buf *bp;
2222 	size_t argsize;
2223 	size_t tomove, moved;
2224 	int error, dofaf, cansleep, dobiodone;
2225 
2226 	pmp = MPTOPUFFSMP(vp->v_mount);
2227 	bp = ap->a_bp;
2228 	error = 0;
2229 	dofaf = 0;
2230 	cansleep = 0;
2231 	pn = VPTOPP(vp);
2232 	park_rw = NULL; /* explicit */
2233 	dobiodone = 1;
2234 
2235 	if ((BUF_ISREAD(bp) && !EXISTSOP(pmp, READ))
2236 	    || (BUF_ISWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2237 		ERROUT(EOPNOTSUPP);
2238 
2239 	/*
2240 	 * Short-circuit optimization: don't flush buffer in between
2241 	 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2242 	 */
2243 	if (pn->pn_stat & PNODE_DYING) {
2244 		KASSERT(BUF_ISWRITE(bp));
2245 		bp->b_resid = 0;
2246 		goto out;
2247 	}
2248 
2249 #ifdef DIAGNOSTIC
2250 	if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX)
2251 		panic("puffs_strategy: wildly inappropriate buf bcount %d",
2252 		    bp->b_bcount);
2253 #endif
2254 
2255 	/*
2256 	 * See explanation for the necessity of a FAF in puffs_fsync.
2257 	 *
2258 	 * Also, do FAF in case we're suspending.
2259 	 * See puffs_vfsops.c:pageflush()
2260 	 */
2261 	if (BUF_ISWRITE(bp)) {
2262 		mutex_enter(vp->v_interlock);
2263 		if (vp->v_iflag & VI_XLOCK)
2264 			dofaf = 1;
2265 		if (pn->pn_stat & PNODE_FAF)
2266 			dofaf = 1;
2267 		mutex_exit(vp->v_interlock);
2268 	}
2269 
2270 	cansleep = (curlwp == uvm.pagedaemon_lwp || dofaf) ? 0 : 1;
2271 
2272 	KASSERT(curlwp != uvm.pagedaemon_lwp || dofaf || BIOASYNC(bp));
2273 
2274 	/* allocate transport structure */
2275 	tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2276 	argsize = sizeof(struct puffs_vnmsg_rw);
2277 	error = puffs_msgmem_alloc(argsize + tomove, &park_rw,
2278 	    (void *)&rw_msg, cansleep);
2279 	if (error)
2280 		goto out;
2281 	RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2282 
2283 	/* 2x2 cases: read/write, faf/nofaf */
2284 	if (BUF_ISREAD(bp)) {
2285 		puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2286 		    PUFFS_VN_READ, VPTOPNC(vp));
2287 		puffs_msg_setdelta(park_rw, tomove);
2288 		if (BIOASYNC(bp)) {
2289 			puffs_msg_setcall(park_rw,
2290 			    puffs_parkdone_asyncbioread, bp);
2291 			puffs_msg_enqueue(pmp, park_rw);
2292 			dobiodone = 0;
2293 		} else {
2294 			PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data,
2295 			    NULL, error);
2296 			error = checkerr(pmp, error, __func__);
2297 			if (error)
2298 				goto out;
2299 
2300 			if (rw_msg->pvnr_resid > tomove) {
2301 				puffs_senderr(pmp, PUFFS_ERR_READ,
2302 				    E2BIG, "resid grew", VPTOPNC(vp));
2303 				ERROUT(EPROTO);
2304 			}
2305 
2306 			moved = tomove - rw_msg->pvnr_resid;
2307 
2308 			(void)memcpy(bp->b_data, rw_msg->pvnr_data, moved);
2309 			bp->b_resid = bp->b_bcount - moved;
2310 		}
2311 	} else {
2312 		puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2313 		    PUFFS_VN_WRITE, VPTOPNC(vp));
2314 		/*
2315 		 * make pages read-only before we write them if we want
2316 		 * write caching info
2317 		 */
2318 		if (PUFFS_WCACHEINFO(pmp)) {
2319 			struct uvm_object *uobj = &vp->v_uobj;
2320 			int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2321 			struct vm_page *vmp;
2322 			int i;
2323 
2324 			for (i = 0; i < npages; i++) {
2325 				vmp= uvm_pageratop((vaddr_t)bp->b_data
2326 				    + (i << PAGE_SHIFT));
2327 				DPRINTF(("puffs_strategy: write-protecting "
2328 				    "vp %p page %p, offset %" PRId64"\n",
2329 				    vp, vmp, vmp->offset));
2330 				mutex_enter(uobj->vmobjlock);
2331 				vmp->flags |= PG_RDONLY;
2332 				pmap_page_protect(vmp, VM_PROT_READ);
2333 				mutex_exit(uobj->vmobjlock);
2334 			}
2335 		}
2336 
2337 		(void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove);
2338 		if (dofaf) {
2339 			puffs_msg_setfaf(park_rw);
2340 		} else if (BIOASYNC(bp)) {
2341 			puffs_msg_setcall(park_rw,
2342 			    puffs_parkdone_asyncbiowrite, bp);
2343 			dobiodone = 0;
2344 		}
2345 
2346 		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, NULL, error);
2347 
2348 		if (dobiodone == 0)
2349 			goto out;
2350 
2351 		/*
2352 		 * XXXXXXXX: wrong, but kernel can't survive strategy
2353 		 * failure currently.  Here, have one more X: X.
2354 		 */
2355 		if (error != ENOMEM)
2356 			error = 0;
2357 
2358 		error = checkerr(pmp, error, __func__);
2359 		if (error)
2360 			goto out;
2361 
2362 		if (rw_msg->pvnr_resid > tomove) {
2363 			puffs_senderr(pmp, PUFFS_ERR_WRITE,
2364 			    E2BIG, "resid grew", VPTOPNC(vp));
2365 			ERROUT(EPROTO);
2366 		}
2367 
2368 		/*
2369 		 * FAF moved everything.  Frankly, we don't
2370 		 * really have a choice.
2371 		 */
2372 		if (dofaf && error == 0)
2373 			moved = tomove;
2374 		else
2375 			moved = tomove - rw_msg->pvnr_resid;
2376 
2377 		bp->b_resid = bp->b_bcount - moved;
2378 		if (bp->b_resid != 0) {
2379 			ERROUT(EIO);
2380 		}
2381 	}
2382 
2383  out:
2384 	if (park_rw)
2385 		puffs_msgmem_release(park_rw);
2386 
2387 	if (error)
2388 		bp->b_error = error;
2389 
2390 	if (error || dobiodone)
2391 		biodone(bp);
2392 
2393 	return error;
2394 }
2395 
2396 int
2397 puffs_vnop_mmap(void *v)
2398 {
2399 	struct vop_mmap_args /* {
2400 		const struct vnodeop_desc *a_desc;
2401 		struct vnode *a_vp;
2402 		vm_prot_t a_prot;
2403 		kauth_cred_t a_cred;
2404 	} */ *ap = v;
2405 	PUFFS_MSG_VARS(vn, mmap);
2406 	struct vnode *vp = ap->a_vp;
2407 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2408 	int error;
2409 
2410 	if (!PUFFS_USE_PAGECACHE(pmp))
2411 		return genfs_eopnotsupp(v);
2412 
2413 	if (EXISTSOP(pmp, MMAP)) {
2414 		PUFFS_MSG_ALLOC(vn, mmap);
2415 		mmap_msg->pvnr_prot = ap->a_prot;
2416 		puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred);
2417 		puffs_msg_setinfo(park_mmap, PUFFSOP_VN,
2418 		    PUFFS_VN_MMAP, VPTOPNC(vp));
2419 
2420 		PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mmap, vp->v_data, NULL, error);
2421 		error = checkerr(pmp, error, __func__);
2422 		PUFFS_MSG_RELEASE(mmap);
2423 	} else {
2424 		error = genfs_mmap(v);
2425 	}
2426 
2427 	return error;
2428 }
2429 
2430 
2431 /*
2432  * The rest don't get a free trip to userspace and back, they
2433  * have to stay within the kernel.
2434  */
2435 
2436 /*
2437  * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2438  * well, maybe somehow, somewhere, some day ....
2439  */
2440 int
2441 puffs_vnop_bmap(void *v)
2442 {
2443 	struct vop_bmap_args /* {
2444 		const struct vnodeop_desc *a_desc;
2445 		struct vnode *a_vp;
2446 		daddr_t a_bn;
2447 		struct vnode **a_vpp;
2448 		daddr_t *a_bnp;
2449 		int *a_runp;
2450 	} */ *ap = v;
2451 	struct puffs_mount *pmp;
2452 
2453 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2454 
2455 	if (ap->a_vpp)
2456 		*ap->a_vpp = ap->a_vp;
2457 	if (ap->a_bnp)
2458 		*ap->a_bnp = ap->a_bn;
2459 	if (ap->a_runp)
2460 		*ap->a_runp
2461 		    = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1;
2462 
2463 	return 0;
2464 }
2465 
2466 /*
2467  * Handle getpages faults in puffs.  We let genfs_getpages() do most
2468  * of the dirty work, but we come in this route to do accounting tasks.
2469  * If the user server has specified functions for cache notifications
2470  * about reads and/or writes, we record which type of operation we got,
2471  * for which page range, and proceed to issue a FAF notification to the
2472  * server about it.
2473  */
2474 int
2475 puffs_vnop_getpages(void *v)
2476 {
2477 	struct vop_getpages_args /* {
2478 		const struct vnodeop_desc *a_desc;
2479 		struct vnode *a_vp;
2480 		voff_t a_offset;
2481 		struct vm_page **a_m;
2482 		int *a_count;
2483 		int a_centeridx;
2484 		vm_prot_t a_access_type;
2485 		int a_advice;
2486 		int a_flags;
2487 	} */ *ap = v;
2488 	struct puffs_mount *pmp;
2489 	struct puffs_node *pn;
2490 	struct vnode *vp;
2491 	struct vm_page **pgs;
2492 	struct puffs_cacheinfo *pcinfo = NULL;
2493 	struct puffs_cacherun *pcrun;
2494 	void *parkmem = NULL;
2495 	size_t runsizes;
2496 	int i, npages, si, streakon;
2497 	int error, locked, write;
2498 
2499 	pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2500 	npages = *ap->a_count;
2501 	pgs = ap->a_m;
2502 	vp = ap->a_vp;
2503 	pn = vp->v_data;
2504 	locked = (ap->a_flags & PGO_LOCKED) != 0;
2505 	write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2506 
2507 	/* ccg xnaht - gets Wuninitialized wrong */
2508 	pcrun = NULL;
2509 	runsizes = 0;
2510 
2511 	/*
2512 	 * Check that we aren't trying to fault in pages which our file
2513 	 * server doesn't know about.  This happens if we extend a file by
2514 	 * skipping some pages and later try to fault in pages which
2515 	 * are between pn_serversize and vp_size.  This check optimizes
2516 	 * away the common case where a file is being extended.
2517 	 */
2518 	if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2519 		struct vattr va;
2520 
2521 		/* try again later when we can block */
2522 		if (locked)
2523 			ERROUT(EBUSY);
2524 
2525 		mutex_exit(vp->v_interlock);
2526 		vattr_null(&va);
2527 		va.va_size = vp->v_size;
2528 		error = dosetattr(vp, &va, FSCRED, 0);
2529 		if (error)
2530 			ERROUT(error);
2531 		mutex_enter(vp->v_interlock);
2532 	}
2533 
2534 	if (write && PUFFS_WCACHEINFO(pmp)) {
2535 #ifdef notnowjohn
2536 		/* allocate worst-case memory */
2537 		runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2538 		KASSERT(curlwp != uvm.pagedaemon_lwp || locked);
2539 		pcinfo = kmem_zalloc(sizeof(struct puffs_cacheinfo) + runsize,
2540 		    locked ? KM_NOSLEEP : KM_SLEEP);
2541 
2542 		/*
2543 		 * can't block if we're locked and can't mess up caching
2544 		 * information for fs server.  so come back later, please
2545 		 */
2546 		if (pcinfo == NULL)
2547 			ERROUT(ENOMEM);
2548 
2549 		parkmem = puffs_park_alloc(locked == 0);
2550 		if (parkmem == NULL)
2551 			ERROUT(ENOMEM);
2552 
2553 		pcrun = pcinfo->pcache_runs;
2554 #else
2555 		(void)parkmem;
2556 #endif
2557 	}
2558 
2559 	error = genfs_getpages(v);
2560 	if (error)
2561 		goto out;
2562 
2563 	if (PUFFS_WCACHEINFO(pmp) == 0)
2564 		goto out;
2565 
2566 	/*
2567 	 * Let's see whose fault it was and inform the user server of
2568 	 * possibly read/written pages.  Map pages from read faults
2569 	 * strictly read-only, since otherwise we might miss info on
2570 	 * when the page is actually write-faulted to.
2571 	 */
2572 	if (!locked)
2573 		mutex_enter(vp->v_uobj.vmobjlock);
2574 	for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2575 		if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2576 			if (streakon && write) {
2577 				streakon = 0;
2578 				pcrun[si].pcache_runend
2579 				    = trunc_page(pgs[i]->offset) + PAGE_MASK;
2580 				si++;
2581 			}
2582 			continue;
2583 		}
2584 		if (streakon == 0 && write) {
2585 			streakon = 1;
2586 			pcrun[si].pcache_runstart = pgs[i]->offset;
2587 		}
2588 
2589 		if (!write)
2590 			pgs[i]->flags |= PG_RDONLY;
2591 	}
2592 	/* was the last page part of our streak? */
2593 	if (streakon) {
2594 		pcrun[si].pcache_runend
2595 		    = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2596 		si++;
2597 	}
2598 	if (!locked)
2599 		mutex_exit(vp->v_uobj.vmobjlock);
2600 
2601 	KASSERT(si <= (npages / 2) + 1);
2602 
2603 #ifdef notnowjohn
2604 	/* send results to userspace */
2605 	if (write)
2606 		puffs_cacheop(pmp, parkmem, pcinfo,
2607 		    sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2608 #endif
2609 
2610  out:
2611 	if (error) {
2612 		if (pcinfo != NULL)
2613 			kmem_free(pcinfo,
2614 			    sizeof(struct puffs_cacheinfo) + runsizes);
2615 #ifdef notnowjohn
2616 		if (parkmem != NULL)
2617 			puffs_park_release(parkmem, 1);
2618 #endif
2619 	}
2620 
2621 	return error;
2622 }
2623 
2624 /*
2625  * Extended attribute support.
2626  */
2627 
2628 int
2629 puffs_vnop_getextattr(void *v)
2630 {
2631 	struct vop_getextattr_args /*
2632 		struct vnode *a_vp;
2633 		int a_attrnamespace;
2634 		const char *a_name;
2635 		struct uio *a_uio;
2636 		size_t *a_size;
2637 		kauth_cred_t a_cred;
2638 	}; */ *ap = v;
2639 	PUFFS_MSG_VARS(vn, getextattr);
2640 	struct vnode *vp = ap->a_vp;
2641 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2642 	int attrnamespace = ap->a_attrnamespace;
2643 	const char *name = ap->a_name;
2644 	struct uio *uio = ap->a_uio;
2645 	size_t *sizep = ap->a_size;
2646 	size_t tomove, resid;
2647 	int error;
2648 
2649 	if (uio)
2650 		resid = uio->uio_resid;
2651 	else
2652 		resid = 0;
2653 
2654 	tomove = PUFFS_TOMOVE(resid, pmp);
2655 	if (tomove != resid) {
2656 		error = E2BIG;
2657 		goto out;
2658 	}
2659 
2660 	puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_getextattr) + tomove,
2661 	    &park_getextattr, (void *)&getextattr_msg, 1);
2662 
2663 	getextattr_msg->pvnr_attrnamespace = attrnamespace;
2664 	strlcpy(getextattr_msg->pvnr_attrname, name,
2665 	    sizeof(getextattr_msg->pvnr_attrname));
2666 	puffs_credcvt(&getextattr_msg->pvnr_cred, ap->a_cred);
2667 	if (sizep)
2668 		getextattr_msg->pvnr_datasize = 1;
2669 	getextattr_msg->pvnr_resid = tomove;
2670 
2671 	puffs_msg_setinfo(park_getextattr,
2672 	    PUFFSOP_VN, PUFFS_VN_GETEXTATTR, VPTOPNC(vp));
2673 	puffs_msg_setdelta(park_getextattr, tomove);
2674 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getextattr, vp->v_data, NULL, error);
2675 
2676 	error = checkerr(pmp, error, __func__);
2677 	if (error)
2678 		goto out;
2679 
2680 	resid = getextattr_msg->pvnr_resid;
2681 	if (resid > tomove) {
2682 		puffs_senderr(pmp, PUFFS_ERR_GETEXTATTR, E2BIG,
2683 		    "resid grew", VPTOPNC(vp));
2684 		error = EPROTO;
2685 		goto out;
2686 	}
2687 
2688 	if (sizep)
2689 		*sizep = getextattr_msg->pvnr_datasize;
2690 	if (uio)
2691 		error = uiomove(getextattr_msg->pvnr_data, tomove - resid, uio);
2692 
2693  out:
2694 	PUFFS_MSG_RELEASE(getextattr);
2695 	return error;
2696 }
2697 
2698 int
2699 puffs_vnop_setextattr(void *v)
2700 {
2701 	struct vop_setextattr_args /* {
2702 		struct vnode *a_vp;
2703 		int a_attrnamespace;
2704 		const char *a_name;
2705 		struct uio *a_uio;
2706 		kauth_cred_t a_cred;
2707 	}; */ *ap = v;
2708 	PUFFS_MSG_VARS(vn, setextattr);
2709 	struct vnode *vp = ap->a_vp;
2710 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2711 	int attrnamespace = ap->a_attrnamespace;
2712 	const char *name = ap->a_name;
2713 	struct uio *uio = ap->a_uio;
2714 	size_t tomove, resid;
2715 	int error;
2716 
2717 	if (uio)
2718 		resid = uio->uio_resid;
2719 	else
2720 		resid = 0;
2721 
2722 	tomove = PUFFS_TOMOVE(resid, pmp);
2723 	if (tomove != resid) {
2724 		error = E2BIG;
2725 		goto out;
2726 	}
2727 
2728 	puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_setextattr) + tomove,
2729 	    &park_setextattr, (void *)&setextattr_msg, 1);
2730 
2731 	setextattr_msg->pvnr_attrnamespace = attrnamespace;
2732 	strlcpy(setextattr_msg->pvnr_attrname, name,
2733 	    sizeof(setextattr_msg->pvnr_attrname));
2734 	puffs_credcvt(&setextattr_msg->pvnr_cred, ap->a_cred);
2735 	setextattr_msg->pvnr_resid = tomove;
2736 
2737 	if (uio) {
2738 		error = uiomove(setextattr_msg->pvnr_data, tomove, uio);
2739 		if (error)
2740 			goto out;
2741 	}
2742 
2743 	puffs_msg_setinfo(park_setextattr,
2744 	    PUFFSOP_VN, PUFFS_VN_SETEXTATTR, VPTOPNC(vp));
2745 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_setextattr, vp->v_data, NULL, error);
2746 
2747 	error = checkerr(pmp, error, __func__);
2748 	if (error)
2749 		goto out;
2750 
2751 	if (setextattr_msg->pvnr_resid != 0)
2752 		error = EIO;
2753 
2754  out:
2755 	PUFFS_MSG_RELEASE(setextattr);
2756 
2757 	return error;
2758 }
2759 
2760 int
2761 puffs_vnop_listextattr(void *v)
2762 {
2763 	struct vop_listextattr_args /* {
2764 		struct vnode *a_vp;
2765 		int a_attrnamespace;
2766 		struct uio *a_uio;
2767 		size_t *a_size;
2768 		int a_flag,
2769 		kauth_cred_t a_cred;
2770 	}; */ *ap = v;
2771 	PUFFS_MSG_VARS(vn, listextattr);
2772 	struct vnode *vp = ap->a_vp;
2773 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2774 	int attrnamespace = ap->a_attrnamespace;
2775 	struct uio *uio = ap->a_uio;
2776 	size_t *sizep = ap->a_size;
2777 	int flag = ap->a_flag;
2778 	size_t tomove, resid;
2779 	int error;
2780 
2781 	if (uio)
2782 		resid = uio->uio_resid;
2783 	else
2784 		resid = 0;
2785 
2786 	tomove = PUFFS_TOMOVE(resid, pmp);
2787 	if (tomove != resid) {
2788 		error = E2BIG;
2789 		goto out;
2790 	}
2791 
2792 	puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_listextattr) + tomove,
2793 	    &park_listextattr, (void *)&listextattr_msg, 1);
2794 
2795 	listextattr_msg->pvnr_attrnamespace = attrnamespace;
2796 	listextattr_msg->pvnr_flag = flag;
2797 	puffs_credcvt(&listextattr_msg->pvnr_cred, ap->a_cred);
2798 	listextattr_msg->pvnr_resid = tomove;
2799 	if (sizep)
2800 		listextattr_msg->pvnr_datasize = 1;
2801 
2802 	puffs_msg_setinfo(park_listextattr,
2803 	    PUFFSOP_VN, PUFFS_VN_LISTEXTATTR, VPTOPNC(vp));
2804 	puffs_msg_setdelta(park_listextattr, tomove);
2805 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_listextattr, vp->v_data, NULL, error);
2806 
2807 	error = checkerr(pmp, error, __func__);
2808 	if (error)
2809 		goto out;
2810 
2811 	resid = listextattr_msg->pvnr_resid;
2812 	if (resid > tomove) {
2813 		puffs_senderr(pmp, PUFFS_ERR_LISTEXTATTR, E2BIG,
2814 		    "resid grew", VPTOPNC(vp));
2815 		error = EPROTO;
2816 		goto out;
2817 	}
2818 
2819 	if (sizep)
2820 		*sizep = listextattr_msg->pvnr_datasize;
2821 	if (uio)
2822 		error = uiomove(listextattr_msg->pvnr_data, tomove-resid, uio);
2823 
2824  out:
2825 	PUFFS_MSG_RELEASE(listextattr);
2826 	return error;
2827 }
2828 
2829 int
2830 puffs_vnop_deleteextattr(void *v)
2831 {
2832 	struct vop_deleteextattr_args /* {
2833 		struct vnode *a_vp;
2834 		int a_attrnamespace;
2835 		const char *a_name;
2836 		kauth_cred_t a_cred;
2837 	}; */ *ap = v;
2838 	PUFFS_MSG_VARS(vn, deleteextattr);
2839 	struct vnode *vp = ap->a_vp;
2840 	struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2841 	int attrnamespace = ap->a_attrnamespace;
2842 	const char *name = ap->a_name;
2843 	int error;
2844 
2845 	PUFFS_MSG_ALLOC(vn, deleteextattr);
2846 	deleteextattr_msg->pvnr_attrnamespace = attrnamespace;
2847 	strlcpy(deleteextattr_msg->pvnr_attrname, name,
2848 	    sizeof(deleteextattr_msg->pvnr_attrname));
2849 	puffs_credcvt(&deleteextattr_msg->pvnr_cred, ap->a_cred);
2850 
2851 	puffs_msg_setinfo(park_deleteextattr,
2852 	    PUFFSOP_VN, PUFFS_VN_DELETEEXTATTR, VPTOPNC(vp));
2853 	PUFFS_MSG_ENQUEUEWAIT2(pmp, park_deleteextattr,
2854 	    vp->v_data, NULL, error);
2855 
2856 	error = checkerr(pmp, error, __func__);
2857 
2858 	PUFFS_MSG_RELEASE(deleteextattr);
2859 	return error;
2860 }
2861 
2862 /*
2863  * spec & fifo.  These call the miscfs spec and fifo vectors, but issue
2864  * FAF update information for the puffs node first.
2865  */
2866 int
2867 puffs_vnop_spec_read(void *v)
2868 {
2869 	struct vop_read_args /* {
2870 		const struct vnodeop_desc *a_desc;
2871 		struct vnode *a_vp;
2872 		struct uio *a_uio;
2873 		int a_ioflag;
2874 		kauth_cred_t a_cred;
2875 	} */ *ap = v;
2876 
2877 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
2878 	return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
2879 }
2880 
2881 int
2882 puffs_vnop_spec_write(void *v)
2883 {
2884 	struct vop_write_args /* {
2885 		const struct vnodeop_desc *a_desc;
2886 		struct vnode *a_vp;
2887 		struct uio *a_uio;
2888 		int a_ioflag;
2889 		kauth_cred_t a_cred;
2890 	} */ *ap = v;
2891 
2892 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
2893 	return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
2894 }
2895 
2896 int
2897 puffs_vnop_fifo_read(void *v)
2898 {
2899 	struct vop_read_args /* {
2900 		const struct vnodeop_desc *a_desc;
2901 		struct vnode *a_vp;
2902 		struct uio *a_uio;
2903 		int a_ioflag;
2904 		kauth_cred_t a_cred;
2905 	} */ *ap = v;
2906 
2907 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
2908 	return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
2909 }
2910 
2911 int
2912 puffs_vnop_fifo_write(void *v)
2913 {
2914 	struct vop_write_args /* {
2915 		const struct vnodeop_desc *a_desc;
2916 		struct vnode *a_vp;
2917 		struct uio *a_uio;
2918 		int a_ioflag;
2919 		kauth_cred_t a_cred;
2920 	} */ *ap = v;
2921 
2922 	puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
2923 	return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
2924 }
2925