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