xref: /netbsd-src/lib/libperfuse/ops.c (revision cc2f98ece2d1ccd5f65934a5f9c972840382081c)
1 /*  $NetBSD: ops.c,v 1.46 2011/11/17 02:28:21 manu Exp $ */
2 
3 /*-
4  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions
8  *  are met:
9  *  1. Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16  *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19  *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <libgen.h>
32 #include <errno.h>
33 #include <err.h>
34 #include <sysexits.h>
35 #include <syslog.h>
36 #include <puffs.h>
37 #include <sys/socket.h>
38 #include <sys/socket.h>
39 #include <sys/extattr.h>
40 #include <machine/vmparam.h>
41 
42 #include "perfuse_priv.h"
43 #include "fuse.h"
44 
45 extern int perfuse_diagflags;
46 
47 static void set_expire(puffs_cookie_t, struct fuse_entry_out *,
48    struct fuse_attr_out *);
49 static int attr_expired(puffs_cookie_t);
50 static int entry_expired(puffs_cookie_t);
51 static int xchg_msg(struct puffs_usermount *, puffs_cookie_t,
52     perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply);
53 static int mode_access(puffs_cookie_t, const struct puffs_cred *, mode_t);
54 static int sticky_access(struct puffs_node *, const struct puffs_cred *);
55 static void fuse_attr_to_vap(struct perfuse_state *,
56     struct vattr *, struct fuse_attr *);
57 static int node_lookup_dir_nodot(struct puffs_usermount *,
58     puffs_cookie_t, char *, size_t, struct puffs_node **);
59 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,
60     const char *, const struct puffs_cred *, struct puffs_node **);
61 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
62     struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *);
63 static int node_mk_common_final(struct puffs_usermount *, puffs_cookie_t,
64     struct puffs_node *, const struct puffs_cn *pcn);
65 static uint64_t readdir_last_cookie(struct fuse_dirent *, size_t);
66 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
67     struct fuse_dirent *, size_t);
68 static int readdir_buffered(puffs_cookie_t, struct dirent *, off_t *,
69     size_t *);
70 static void requeue_request(struct puffs_usermount *,
71     puffs_cookie_t opc, enum perfuse_qtype);
72 static int dequeue_requests(struct perfuse_state *,
73     puffs_cookie_t opc, enum perfuse_qtype, int);
74 #define DEQUEUE_ALL 0
75 
76 /*
77  *  From <sys/vnode>, inside #ifdef _KERNEL section
78  */
79 #define IO_SYNC		(0x40|IO_DSYNC)
80 #define IO_DSYNC	0x00200
81 #define IO_DIRECT	0x02000
82 
83 /*
84  *  From <fcntl>, inside #ifdef _KERNEL section
85  */
86 #define F_WAIT		0x010
87 #define F_FLOCK		0x020
88 #define OFLAGS(fflags)  ((fflags) - 1)
89 
90 /*
91  * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h
92  */
93 const enum vtype iftovt_tab[16] = {
94 	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
95         VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
96 };
97 const int vttoif_tab[9] = {
98 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
99         S_IFSOCK, S_IFIFO, S_IFMT,
100 };
101 
102 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
103 #define VTTOIF(indx) (vttoif_tab[(int)(indx)])
104 
105 int
106 perfuse_node_close_common(pu, opc, mode)
107 	struct puffs_usermount *pu;
108 	puffs_cookie_t opc;
109 	int mode;
110 {
111 	struct perfuse_state *ps;
112 	perfuse_msg_t *pm;
113 	int op;
114 	uint64_t fh;
115 	struct fuse_release_in *fri;
116 	struct perfuse_node_data *pnd;
117 	struct puffs_node *pn;
118 	int error;
119 
120 	ps = puffs_getspecific(pu);
121 	pn = (struct puffs_node *)opc;
122 	pnd = PERFUSE_NODE_DATA(pn);
123 
124 	if (puffs_pn_getvap(pn)->va_type == VDIR) {
125 		op = FUSE_RELEASEDIR;
126 		mode = FREAD;
127 	} else {
128 		op = FUSE_RELEASE;
129 	}
130 
131 	/*
132 	 * Destroy the filehandle before sending the
133 	 * request to the FUSE filesystem, otherwise
134 	 * we may get a second close() while we wait
135 	 * for the reply, and we would end up closing
136 	 * the same fh twice instead of closng both.
137 	 */
138 	fh = perfuse_get_fh(opc, mode);
139 	perfuse_destroy_fh(pn, fh);
140 
141 	/*
142 	 * release_flags may be set to FUSE_RELEASE_FLUSH
143 	 * to flush locks. lock_owner must be set in that case
144 	 *
145 	 * ps_new_msg() is called with NULL creds, which will
146 	 * be interpreted as FUSE superuser. We come here from the
147 	 * inactive method, which provides no creds, but obviously
148 	 * runs with kernel privilege.
149 	 */
150 	pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL);
151 	fri = GET_INPAYLOAD(ps, pm, fuse_release_in);
152 	fri->fh = fh;
153 	fri->flags = 0;
154 	fri->release_flags = 0;
155 	fri->lock_owner = pnd->pnd_lock_owner;
156 	fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0;
157 
158 #ifdef PERFUSE_DEBUG
159 	if (perfuse_diagflags & PDF_FH)
160 		DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
161 			 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh);
162 #endif
163 
164 	if ((error = xchg_msg(pu, opc, pm,
165 			      NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
166 		goto out;
167 
168 	ps->ps_destroy_msg(pm);
169 
170 	error = 0;
171 
172 out:
173 	if (error != 0)
174 		DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem "
175 		      "returned error = %d", __func__, fh, error);
176 
177 	return error;
178 }
179 
180 /* ARGSUSED1 */
181 static int
182 xchg_msg(pu, opc, pm, len, wait)
183 	struct puffs_usermount *pu;
184 	puffs_cookie_t opc;
185 	perfuse_msg_t *pm;
186 	size_t len;
187      	enum perfuse_xchg_pb_reply wait;
188 {
189 	struct perfuse_state *ps;
190 	struct perfuse_node_data *pnd;
191 	int error;
192 
193 	ps = puffs_getspecific(pu);
194 	pnd = NULL;
195 	if ((struct puffs_node *)opc != NULL)
196 		pnd = PERFUSE_NODE_DATA(opc);
197 
198 #ifdef PERFUSE_DEBUG
199 	if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0))
200 		DPRINTF("file = \"%s\", ino = %"PRIu64" flags = 0x%x\n",
201 			perfuse_node_path(opc),
202 			((struct puffs_node *)opc)->pn_va.va_fileid,
203 			PERFUSE_NODE_DATA(opc)->pnd_flags);
204 #endif
205 	if (pnd)
206 		pnd->pnd_flags |= PND_INXCHG;
207 
208 	error = ps->ps_xchg_msg(pu, pm, len, wait);
209 
210 	if (pnd) {
211 		pnd->pnd_flags &= ~PND_INXCHG;
212 		(void)dequeue_requests(ps, opc, PCQ_AFTERXCHG, DEQUEUE_ALL);
213 	}
214 
215 	return error;
216 }
217 
218 static int
219 mode_access(opc, pcr, mode)
220 	puffs_cookie_t opc;
221 	const struct puffs_cred *pcr;
222 	mode_t mode;
223 {
224 	struct puffs_node *pn;
225 	struct vattr *va;
226 
227 	/*
228 	 * pcr is NULL for self open through fsync or readdir.
229 	 * In both case, access control is useless, as it was
230 	 * done before, at open time.
231 	 */
232 	if (pcr == NULL)
233 		return 0;
234 
235 	pn = (struct puffs_node *)opc;
236 	va = puffs_pn_getvap(pn);
237 	return puffs_access(va->va_type, va->va_mode,
238 			    va->va_uid, va->va_gid,
239 			    mode, pcr);
240 }
241 
242 static int
243 sticky_access(targ, pcr)
244 	struct puffs_node *targ;
245 	const struct puffs_cred *pcr;
246 {
247 	uid_t uid;
248 	struct puffs_node *tdir;
249 	int sticky, owner;
250 
251 	tdir = PERFUSE_NODE_DATA(targ)->pnd_parent;
252 
253 	/*
254 	 * This covers the case where the kernel requests a DELETE
255 	 * or RENAME on its own, and where puffs_cred_getuid would
256 	 * return -1. While such a situation should not happen,
257 	 * we allow it here.
258 	 *
259 	 * This also allows root to tamper with other users' files
260 	 * that have the sticky bit.
261 	 */
262 	if (puffs_cred_isjuggernaut(pcr))
263 		return 0;
264 
265 	if (puffs_cred_getuid(pcr, &uid) != 0)
266 		DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__);
267 
268 	sticky = puffs_pn_getvap(tdir)->va_mode & S_ISTXT;
269 	owner = puffs_pn_getvap(targ)->va_uid == uid;
270 
271 	if (sticky && !owner)
272 		return EACCES;
273 
274 	return 0;
275 }
276 
277 
278 static void
279 fuse_attr_to_vap(ps, vap, fa)
280 	struct perfuse_state *ps;
281 	struct vattr *vap;
282 	struct fuse_attr *fa;
283 {
284 	vap->va_type = IFTOVT(fa->mode);
285 	vap->va_mode = fa->mode & ALLPERMS;
286 	vap->va_nlink = fa->nlink;
287 	vap->va_uid = fa->uid;
288 	vap->va_gid = fa->gid;
289 	vap->va_fsid = (long)ps->ps_fsid;
290 	vap->va_fileid = fa->ino;
291 	vap->va_size = fa->size;
292 	vap->va_blocksize = fa->blksize;
293 	vap->va_atime.tv_sec = (time_t)fa->atime;
294 	vap->va_atime.tv_nsec = (long) fa->atimensec;
295 	vap->va_mtime.tv_sec = (time_t)fa->mtime;
296 	vap->va_mtime.tv_nsec = (long)fa->mtimensec;
297 	vap->va_ctime.tv_sec = (time_t)fa->ctime;
298 	vap->va_ctime.tv_nsec = (long)fa->ctimensec;
299 	vap->va_birthtime.tv_sec = 0;
300 	vap->va_birthtime.tv_nsec = 0;
301 	vap->va_gen = 0;
302 	vap->va_flags = 0;
303 	vap->va_rdev = fa->rdev;
304 	vap->va_bytes = fa->size;
305 	vap->va_filerev = (u_quad_t)PUFFS_VNOVAL;
306 	vap->va_vaflags = 0;
307 
308 	if (vap->va_blocksize == 0)
309 		vap->va_blocksize = DEV_BSIZE;
310 
311 	if (vap->va_size == (size_t)PUFFS_VNOVAL) /* XXX */
312 		vap->va_size = 0;
313 
314 	return;
315 }
316 
317 static void
318 set_expire(opc, feo, fao)
319 	puffs_cookie_t opc;
320 	struct fuse_entry_out *feo;
321 	struct fuse_attr_out *fao;
322 {
323 	struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
324 	struct timespec entry_ts;
325 	struct timespec attr_ts;
326 	struct timespec now;
327 
328 	if ((feo == NULL) && (fao == NULL))
329 		DERRX(EX_SOFTWARE, "%s: feo and fao NULL", __func__);
330 
331 	if ((feo != NULL) && (fao != NULL))
332 		DERRX(EX_SOFTWARE, "%s: feo and fao != NULL", __func__);
333 
334 	if (clock_gettime(CLOCK_REALTIME, &now) != 0)
335 		DERR(EX_OSERR, "clock_gettime failed");
336 
337 	if (feo != NULL) {
338 		entry_ts.tv_sec = (time_t)feo->entry_valid;
339 		entry_ts.tv_nsec = (long)feo->entry_valid_nsec;
340 
341 		timespecadd(&now, &entry_ts, &pnd->pnd_entry_expire);
342 
343 		attr_ts.tv_sec = (time_t)feo->attr_valid;
344 		attr_ts.tv_nsec = (long)feo->attr_valid_nsec;
345 
346 		timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire);
347 	}
348 
349 	if (fao != NULL) {
350 		attr_ts.tv_sec = (time_t)fao->attr_valid;
351 		attr_ts.tv_nsec = (long)fao->attr_valid_nsec;
352 
353 		timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire);
354 	}
355 
356 	return;
357 }
358 
359 static int
360 attr_expired(opc)
361 	puffs_cookie_t opc;
362 {
363 	struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
364 	struct timespec now;
365 
366 	if (clock_gettime(CLOCK_REALTIME, &now) != 0)
367 		DERR(EX_OSERR, "clock_gettime failed");
368 
369 	return timespeccmp(&pnd->pnd_attr_expire, &now, <);
370 }
371 
372 static int
373 entry_expired(opc)
374 	puffs_cookie_t opc;
375 {
376 	struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
377 	struct timespec expire = pnd->pnd_entry_expire;
378 	struct timespec now;
379 
380 	if (clock_gettime(CLOCK_REALTIME, &now) != 0)
381 		DERR(EX_OSERR, "clock_gettime failed");
382 
383 	return timespeccmp(&expire, &now, <);
384 }
385 
386 
387 /*
388  * Lookup name in directory opc
389  * We take special care of name being . or ..
390  * These are returned by readdir and deserve tweaks.
391  */
392 static int
393 node_lookup_dir_nodot(pu, opc, name, namelen, pnp)
394 	struct puffs_usermount *pu;
395 	puffs_cookie_t opc;
396 	char *name;
397 	size_t namelen;
398 	struct puffs_node **pnp;
399 {
400 	/*
401 	 * "dot" is easy as we already know it
402 	 */
403 	if (strncmp(name, ".", namelen) == 0) {
404 		*pnp = (struct puffs_node *)opc;
405 		return 0;
406 	}
407 
408 	/*
409 	 * "dotdot" is also known
410 	 */
411 	if (strncmp(name, "..", namelen) == 0) {
412 		*pnp = PERFUSE_NODE_DATA(opc)->pnd_parent;
413 		return 0;
414 	}
415 
416 	return node_lookup_common(pu, opc, name, NULL, pnp);
417 }
418 
419 static int
420 node_lookup_common(pu, opc, path, pcr, pnp)
421 	struct puffs_usermount *pu;
422 	puffs_cookie_t opc;
423 	const char *path;
424 	const struct puffs_cred *pcr;
425 	struct puffs_node **pnp;
426 {
427 	struct perfuse_state *ps;
428 	struct perfuse_node_data *oldpnd;
429 	perfuse_msg_t *pm;
430 	struct fuse_entry_out *feo;
431 	struct puffs_node *pn;
432 	size_t len;
433 	int error;
434 
435 	if (pnp == NULL)
436 		DERRX(EX_SOFTWARE, "pnp must be != NULL");
437 
438 	ps = puffs_getspecific(pu);
439 
440 #ifdef PERFUSE_DEBUG
441 	if (perfuse_diagflags & PDF_FILENAME)
442 		DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n",
443 			__func__, (void *)opc, perfuse_node_path(opc), path);
444 #endif
445 	/*
446 	 * Is the node already known?
447 	 */
448 	TAILQ_FOREACH(oldpnd, &PERFUSE_NODE_DATA(opc)->pnd_children, pnd_next) {
449 		if ((oldpnd->pnd_flags & PND_REMOVED) ||
450 		    (strcmp(oldpnd->pnd_name, path) != 0))
451 			continue;
452 
453 #ifdef PERFUSE_DEBUG
454 		if (perfuse_diagflags & PDF_FILENAME)
455 			DPRINTF("%s: opc = %p, file = \"%s\" found "
456 				"cookie = %p, nodeid = 0x%"PRIx64" for \"%s\"\n",
457 				__func__, (void *)opc, perfuse_node_path(opc),
458 				(void *)oldpnd->pnd_pn, oldpnd->pnd_nodeid,
459 				path);
460 #endif
461 		break;
462 	}
463 
464 	/*
465 	 * Check for cached name
466 	 */
467 	if ((oldpnd != NULL) && !entry_expired(oldpnd->pnd_pn)) {
468 		*pnp = oldpnd->pnd_pn;
469 		return 0;
470 	}
471 
472 	len = strlen(path) + 1;
473 
474 	pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, pcr);
475 	(void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len);
476 
477 	error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply);
478 
479 	switch (error) {
480 	case 0:
481 		break;
482 	case ENOENT:
483 		if (oldpnd != NULL) {
484 			oldpnd->pnd_flags |= PND_REMOVED;
485 #ifdef PERFUSE_DEBUG
486 			if (perfuse_diagflags & PDF_FILENAME)
487 				DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" "
488 					"file = \"%s\" removed\n", __func__,
489 					oldpnd->pnd_pn, oldpnd->pnd_nodeid,
490 					oldpnd->pnd_name);
491 #endif
492 		}
493 		/* FALLTHROUGH */
494 	default:
495 		goto out;
496 		/* NOTREACHED */
497 		break;
498 	}
499 
500 	feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
501 
502 	if (oldpnd != NULL) {
503 		if (oldpnd->pnd_nodeid == feo->nodeid) {
504 			oldpnd->pnd_nlookup++;
505 			*pnp = oldpnd->pnd_pn;
506 			goto out;
507 		} else {
508 			oldpnd->pnd_flags |= PND_REMOVED;
509 #ifdef PERFUSE_DEBUG
510 			if (perfuse_diagflags & PDF_FILENAME)
511 				DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" "
512 					"file = \"%s\" replaced\n", __func__,
513 					oldpnd->pnd_pn, oldpnd->pnd_nodeid,
514 					oldpnd->pnd_name);
515 #endif
516 		}
517 	}
518 
519 	pn = perfuse_new_pn(pu, path, opc);
520 	PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid;
521 
522 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
523 	pn->pn_va.va_gen = (u_long)(feo->generation);
524 	set_expire((puffs_cookie_t)pn, feo, NULL);
525 
526 	*pnp = pn;
527 
528 #ifdef PERFUSE_DEBUG
529 	if (perfuse_diagflags & PDF_FILENAME)
530 		DPRINTF("%s: opc = %p, looked up opc = %p, "
531 			"nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__,
532 			(void *)opc, pn, feo->nodeid, path);
533 #endif
534 
535 out:
536 	ps->ps_destroy_msg(pm);
537 
538 	return error;
539 }
540 
541 
542 /*
543  * Common code for methods that create objects:
544  * perfuse_node_mkdir
545  * perfuse_node_mknod
546  * perfuse_node_symlink
547  */
548 static int
549 node_mk_common(pu, opc, pni, pcn, pm)
550 	struct puffs_usermount *pu;
551 	puffs_cookie_t opc;
552 	struct puffs_newinfo *pni;
553 	const struct puffs_cn *pcn;
554 	perfuse_msg_t *pm;
555 {
556 	struct perfuse_state *ps;
557 	struct puffs_node *pn;
558 	struct fuse_entry_out *feo;
559 	int error;
560 
561 	ps =  puffs_getspecific(pu);
562 
563 	if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0)
564 		goto out;
565 
566 	feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
567 	if (feo->nodeid == PERFUSE_UNKNOWN_NODEID)
568 		DERRX(EX_SOFTWARE, "%s: no nodeid", __func__);
569 
570 	pn = perfuse_new_pn(pu, pcn->pcn_name, opc);
571 	PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid;
572 
573 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
574 	pn->pn_va.va_gen = (u_long)(feo->generation);
575 	set_expire((puffs_cookie_t)pn, feo, NULL);
576 
577 	puffs_newinfo_setcookie(pni, pn);
578 
579 #ifdef PERFUSE_DEBUG
580 	if (perfuse_diagflags & PDF_FILENAME)
581 		DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
582 			"nodeid = 0x%"PRIx64"\n",
583 			__func__, (void *)pn, pcn->pcn_name,
584 			PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid);
585 #endif
586 	ps->ps_destroy_msg(pm);
587 
588 	return node_mk_common_final(pu, opc, pn, pcn);
589 
590 out:
591 	ps->ps_destroy_msg(pm);
592 
593 	return error;
594 }
595 
596 /*
597  * Common final code for methods that create objects:
598  * perfuse_node_mkdir via node_mk_common
599  * perfuse_node_mknod via node_mk_common
600  * perfuse_node_symlink via node_mk_common
601  * perfuse_node_create
602  */
603 static int
604 node_mk_common_final(pu, opc, pn, pcn)
605 	struct puffs_usermount *pu;
606 	puffs_cookie_t opc;
607 	struct puffs_node *pn;
608 	const struct puffs_cn *pcn;
609 {
610 	struct perfuse_state *ps;
611 	perfuse_msg_t *pm;
612 	struct fuse_setattr_in *fsi;
613 	struct fuse_attr_out *fao;
614 	int error;
615 
616 	ps =  puffs_getspecific(pu);
617 
618 	/*
619 	 * Set owner and group. The kernel cannot create a file
620 	 * on its own (puffs_cred_getuid would return -1), right?
621 	 */
622 	if (puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid) != 0)
623 		DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__);
624 	if (puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid) != 0)
625 		DERRX(EX_SOFTWARE, "puffs_cred_getgid fails in %s", __func__);
626 
627 	pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn,
628 			    FUSE_SETATTR, sizeof(*fsi), pcn->pcn_cred);
629 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
630 	fsi->uid = pn->pn_va.va_uid;
631 	fsi->gid = pn->pn_va.va_gid;
632 	fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID;
633 
634 	if ((error = xchg_msg(pu, (puffs_cookie_t)pn, pm,
635 			      sizeof(*fao), wait_reply)) != 0)
636 		goto out;
637 
638 	fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
639 	fuse_attr_to_vap(ps, &pn->pn_va, &fao->attr);
640 	set_expire((puffs_cookie_t)pn, NULL, fao);
641 
642 	/*
643 	 * The parent directory needs a sync
644 	 */
645 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
646 
647 out:
648 	if (pm != NULL)
649 		ps->ps_destroy_msg(pm);
650 
651 	return error;
652 }
653 
654 static uint64_t
655 readdir_last_cookie(fd, fd_len)
656 	struct fuse_dirent *fd;
657 	size_t fd_len;
658 {
659 	size_t len;
660 	size_t seen = 0;
661 	char *ndp;
662 
663 	do {
664 		len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
665 		seen += len;
666 
667 		if (seen >= fd_len)
668 			break;
669 
670 		ndp = (char *)(void *)fd + (size_t)len;
671 		fd = (struct fuse_dirent *)(void *)ndp;
672 	} while (1 /* CONSTCOND */);
673 
674 	return fd->off;
675 }
676 
677 static ssize_t
678 fuse_to_dirent(pu, opc, fd, fd_len)
679 	struct puffs_usermount *pu;
680 	puffs_cookie_t opc;
681 	struct fuse_dirent *fd;
682 	size_t fd_len;
683 {
684 	struct dirent *dents;
685 	size_t dents_len;
686 	ssize_t written;
687 	uint64_t fd_offset;
688 	struct fuse_dirent *fd_base;
689 	size_t len;
690 
691 	fd_base = fd;
692 	fd_offset = 0;
693 	written = 0;
694 	dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
695 	dents_len = (size_t)PERFUSE_NODE_DATA(opc)->pnd_dirent_len;
696 
697 	do {
698 		char *ndp;
699 		size_t reclen;
700 
701 		reclen = _DIRENT_RECLEN(dents, fd->namelen);
702 
703 		/*
704 		 * Check we do not overflow the output buffer
705 		 * struct fuse_dirent is bigger than struct dirent,
706 		 * so we should always use fd_len and never reallocate
707 		 * later.
708 		 * If we have to reallocate,try to double the buffer
709 		 * each time so that we do not have to do it too often.
710 		 */
711 		if (written + reclen > dents_len) {
712 			if (dents_len == 0)
713 				dents_len = fd_len;
714 			else
715 				dents_len =
716 				   MAX(2 * dents_len, written + reclen);
717 
718 			dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
719 			if ((dents = realloc(dents, dents_len)) == NULL)
720 				DERR(EX_OSERR, "%s: malloc failed", __func__);
721 
722 			PERFUSE_NODE_DATA(opc)->pnd_dirent = dents;
723 			PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len;
724 
725 			/*
726 			 * (void *) for delint
727 			 */
728 			ndp = (char *)(void *)dents + written;
729 			dents = (struct dirent *)(void *)ndp;
730 		}
731 
732 		/*
733 		 * Filesystem was mounted without -o use_ino
734 		 * Perform a lookup to find it.
735 		 */
736 		if (fd->ino == PERFUSE_UNKNOWN_INO) {
737 			struct puffs_node *pn;
738 
739 			if (node_lookup_dir_nodot(pu, opc, fd->name,
740 						  fd->namelen, &pn) != 0) {
741 				DWARNX("node_lookup_dir_nodot failed");
742 			} else {
743 				fd->ino = pn->pn_va.va_fileid;
744 			}
745 		}
746 
747 		dents->d_fileno = fd->ino;
748 		dents->d_reclen = (unsigned short)reclen;
749 		dents->d_namlen = fd->namelen;
750 		dents->d_type = fd->type;
751 		strlcpy(dents->d_name, fd->name, fd->namelen + 1);
752 
753 #ifdef PERFUSE_DEBUG
754 		if (perfuse_diagflags & PDF_READDIR)
755 			DPRINTF("%s: translated \"%s\" ino = %"PRIu64"\n",
756 				__func__, dents->d_name, dents->d_fileno);
757 #endif
758 
759 		dents = _DIRENT_NEXT(dents);
760 		written += reclen;
761 
762 		/*
763 		 * Move to the next record.
764 		 * fd->off is not the offset, it is an opaque cookie
765 		 * given by the filesystem to keep state across multiple
766 		 * readdir() operation.
767 		 * Use record alignement instead.
768 		 */
769 		len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
770 #ifdef PERFUSE_DEBUG
771 		if (perfuse_diagflags & PDF_READDIR)
772 			DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" "
773 				"length = %zd/0x%zx. "
774 				"next record at %"PRId64"/0x%"PRIx64" "
775 				"max %zd/0x%zx\n",
776 				__func__, fd_offset, fd_offset, len, len,
777 				fd_offset + len, fd_offset + len,
778 				fd_len, fd_len);
779 #endif
780 		fd_offset += len;
781 
782 		/*
783 		 * Check if next record is still within the packet
784 		 * If it is not, we reached the end of the buffer.
785 		 */
786 		if (fd_offset >= fd_len)
787 			break;
788 
789 		/*
790 		 * (void *) for delint
791 		 */
792 		ndp = (char *)(void *)fd_base + (size_t)fd_offset;
793 		fd = (struct fuse_dirent *)(void *)ndp;
794 
795 	} while (1 /* CONSTCOND */);
796 
797 	/*
798 	 * Adjust the dirent output length
799 	 */
800 	if (written != -1)
801 		PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written;
802 
803 	return written;
804 }
805 
806 static int
807 readdir_buffered(opc, dent, readoff, reslen)
808 	puffs_cookie_t opc;
809 	struct dirent *dent;
810 	off_t *readoff;
811 	size_t *reslen;
812 {
813 	struct dirent *fromdent;
814 	struct perfuse_node_data *pnd;
815 	char *ndp;
816 
817 	pnd = PERFUSE_NODE_DATA(opc);
818 
819 	while (*readoff < pnd->pnd_dirent_len) {
820 		/*
821 		 * (void *) for delint
822 		 */
823 		ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff;
824 		fromdent = (struct dirent *)(void *)ndp;
825 
826 		if (*reslen < _DIRENT_SIZE(fromdent))
827 			break;
828 
829 		memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
830 		*readoff += _DIRENT_SIZE(fromdent);
831 		*reslen -= _DIRENT_SIZE(fromdent);
832 
833 		dent = _DIRENT_NEXT(dent);
834 	}
835 
836 #ifdef PERFUSE_DEBUG
837 	if (perfuse_diagflags & PDF_READDIR)
838 		DPRINTF("%s: readoff = %"PRId64",  "
839 			"pnd->pnd_dirent_len = %"PRId64"\n",
840 			__func__, *readoff, pnd->pnd_dirent_len);
841 #endif
842 	if (*readoff >=  pnd->pnd_dirent_len) {
843 		free(pnd->pnd_dirent);
844 		pnd->pnd_dirent = NULL;
845 		pnd->pnd_dirent_len = 0;
846 	}
847 
848 	return 0;
849 }
850 
851 static void
852 requeue_request(pu, opc, type)
853 	struct puffs_usermount *pu;
854 	puffs_cookie_t opc;
855 	enum perfuse_qtype type;
856 {
857 	struct perfuse_cc_queue pcq;
858 	struct perfuse_node_data *pnd;
859 #ifdef PERFUSE_DEBUG
860 	struct perfuse_state *ps;
861 
862 	ps = perfuse_getspecific(pu);
863 #endif
864 
865 	pnd = PERFUSE_NODE_DATA(opc);
866 	pcq.pcq_type = type;
867 	pcq.pcq_cc = puffs_cc_getcc(pu);
868 	TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next);
869 
870 #ifdef PERFUSE_DEBUG
871 	if (perfuse_diagflags & PDF_REQUEUE)
872 		DPRINTF("%s: REQUEUE opc = %p, pcc = %p (%s)\n",
873 		        __func__, (void *)opc, pcq.pcq_cc,
874 			perfuse_qtypestr[type]);
875 #endif
876 
877 	puffs_cc_yield(pcq.pcq_cc);
878 	TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next);
879 
880 #ifdef PERFUSE_DEBUG
881 	if (perfuse_diagflags & PDF_REQUEUE)
882 		DPRINTF("%s: RESUME opc = %p, pcc = %p (%s)\n",
883 		        __func__, (void *)opc, pcq.pcq_cc,
884 			perfuse_qtypestr[type]);
885 #endif
886 
887 	return;
888 }
889 
890 /* ARGSUSED0 */
891 static int
892 dequeue_requests(ps, opc, type, max)
893 	struct perfuse_state *ps;
894 	puffs_cookie_t opc;
895 	enum perfuse_qtype type;
896 	int max;
897 {
898 	struct perfuse_cc_queue *pcq;
899 	struct perfuse_node_data *pnd;
900 	int dequeued;
901 
902 	pnd = PERFUSE_NODE_DATA(opc);
903 	dequeued = 0;
904 	TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) {
905 		if (pcq->pcq_type != type)
906 			continue;
907 
908 #ifdef PERFUSE_DEBUG
909 		if (perfuse_diagflags & PDF_REQUEUE)
910 			DPRINTF("%s: SCHEDULE opc = %p, pcc = %p (%s)\n",
911 				__func__, (void *)opc, pcq->pcq_cc,
912 				 perfuse_qtypestr[type]);
913 #endif
914 		puffs_cc_schedule(pcq->pcq_cc);
915 
916 		if (++dequeued == max)
917 			break;
918 	}
919 
920 #ifdef PERFUSE_DEBUG
921 	if (perfuse_diagflags & PDF_REQUEUE)
922 		DPRINTF("%s: DONE  opc = %p\n", __func__, (void *)opc);
923 #endif
924 
925 	return dequeued;
926 }
927 
928 void
929 perfuse_fs_init(pu)
930 	struct puffs_usermount *pu;
931 {
932 	struct perfuse_state *ps;
933 	perfuse_msg_t *pm;
934 	struct fuse_init_in *fii;
935 	struct fuse_init_out *fio;
936 	int error;
937 
938 	ps = puffs_getspecific(pu);
939 
940         if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0)
941                 DERR(EX_OSERR, "%s: puffs_mount failed", __func__);
942 
943 	/*
944 	 * Linux 2.6.34.1 sends theses flags:
945 	 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC
946 	 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK
947 	 *
948 	 * Linux also sets max_readahead at 32 pages (128 kB)
949 	 *
950 	 * ps_new_msg() is called with NULL creds, which will
951 	 * be interpreted as FUSE superuser.
952 	 */
953 	pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL);
954 	fii = GET_INPAYLOAD(ps, pm, fuse_init_in);
955 	fii->major = FUSE_KERNEL_VERSION;
956 	fii->minor = FUSE_KERNEL_MINOR_VERSION;
957 	fii->max_readahead = (unsigned int)(32 * sysconf(_SC_PAGESIZE));
958 	fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC);
959 
960 	if ((error = xchg_msg(pu, 0, pm, sizeof(*fio), wait_reply)) != 0)
961 		DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error);
962 
963 	fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out);
964 	ps->ps_max_readahead = fio->max_readahead;
965 	ps->ps_max_write = fio->max_write;
966 
967 	ps->ps_destroy_msg(pm);
968 
969 	return;
970 }
971 
972 int
973 perfuse_fs_unmount(pu, flags)
974 	struct puffs_usermount *pu;
975 	int flags;
976 {
977 	perfuse_msg_t *pm;
978 	struct perfuse_state *ps;
979 	puffs_cookie_t opc;
980 	int error;
981 
982 	ps = puffs_getspecific(pu);
983 	opc = (puffs_cookie_t)puffs_getroot(pu);
984 
985 	/*
986 	 * ps_new_msg() is called with NULL creds, which will
987 	 * be interpreted as FUSE superuser.
988 	 */
989 	pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL);
990 
991 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0){
992 		DWARN("unmount %s", ps->ps_target);
993 		if (!(flags & MNT_FORCE))
994 			goto out;
995 	}
996 
997 	ps->ps_umount(pu);
998 
999 	if (perfuse_diagflags & PDF_MISC)
1000 		DPRINTF("%s unmounted, exit\n", ps->ps_target);
1001 
1002 	return 0;
1003 out:
1004 	ps->ps_destroy_msg(pm);
1005 
1006 	return error;
1007 }
1008 
1009 int
1010 perfuse_fs_statvfs(pu, svfsb)
1011 	struct puffs_usermount *pu;
1012 	struct statvfs *svfsb;
1013 {
1014 	struct perfuse_state *ps;
1015 	perfuse_msg_t *pm;
1016 	puffs_cookie_t opc;
1017 	struct fuse_statfs_out *fso;
1018 	int error;
1019 
1020 	ps = puffs_getspecific(pu);
1021 	opc = (puffs_cookie_t)puffs_getroot(pu);
1022 
1023 	/*
1024 	 * ps_new_msg() is called with NULL creds, which will
1025 	 * be interpreted as FUSE superuser.
1026 	 */
1027 	pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL);
1028 
1029 	if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0)
1030 		goto out;
1031 
1032 	fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out);
1033 	svfsb->f_flag = ps->ps_mountflags;
1034 	svfsb->f_bsize = fso->st.bsize;
1035 	svfsb->f_frsize = fso->st.frsize;
1036 	svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize;
1037 	svfsb->f_blocks = fso->st.blocks;
1038 	svfsb->f_bfree = fso->st.bfree;
1039 	svfsb->f_bavail = fso->st.bavail;
1040 	svfsb->f_bresvd = fso->st.bfree - fso->st.bavail;
1041 	svfsb->f_files = fso->st.files;
1042 	svfsb->f_ffree = fso->st.ffree;
1043 	svfsb->f_favail = fso->st.ffree;/* files not reserved for root */
1044 	svfsb->f_fresvd = 0;		/* files reserved for root */
1045 
1046 	svfsb->f_syncreads = ps->ps_syncreads;
1047 	svfsb->f_syncwrites = ps->ps_syncwrites;
1048 
1049 	svfsb->f_asyncreads = ps->ps_asyncreads;
1050 	svfsb->f_asyncwrites = ps->ps_asyncwrites;
1051 
1052 	(void)memcpy(&svfsb->f_fsidx, &ps->ps_fsid, sizeof(ps->ps_fsid));
1053 	svfsb->f_fsid = (unsigned long)ps->ps_fsid;
1054 	svfsb->f_namemax = MAXPATHLEN;	/* XXX */
1055 	svfsb->f_owner = ps->ps_owner_uid;
1056 
1057 	(void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN);
1058 
1059 	if (ps->ps_filesystemtype != NULL)
1060 		(void)strlcpy(svfsb->f_fstypename,
1061 			      ps->ps_filesystemtype, _VFS_NAMELEN);
1062 	else
1063 		(void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN);
1064 
1065 	if (ps->ps_source != NULL)
1066 		strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN);
1067 	else
1068 		strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN);
1069 out:
1070 	ps->ps_destroy_msg(pm);
1071 
1072 	return error;
1073 }
1074 
1075 int
1076 perfuse_fs_sync(pu, waitfor, pcr)
1077 	struct puffs_usermount *pu;
1078 	int waitfor;
1079 	const struct puffs_cred *pcr;
1080 {
1081 	/*
1082 	 * FUSE does not seem to have a FS sync callback.
1083 	 * Maybe do not even register this callback
1084 	 */
1085 	return puffs_fsnop_sync(pu, waitfor, pcr);
1086 }
1087 
1088 /* ARGSUSED0 */
1089 int
1090 perfuse_fs_fhtonode(pu, fid, fidsize, pni)
1091 	struct puffs_usermount *pu;
1092 	void *fid;
1093 	size_t fidsize;
1094 	struct puffs_newinfo *pni;
1095 {
1096 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1097 	return 0;
1098 }
1099 
1100 /* ARGSUSED0 */
1101 int
1102 perfuse_fs_nodetofh(pu, cookie, fid, fidsize)
1103 	struct puffs_usermount *pu;
1104 	puffs_cookie_t cookie;
1105 	void *fid;
1106 	size_t *fidsize;
1107 {
1108 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1109 	return 0;
1110 }
1111 
1112 #if 0
1113 /* ARGSUSED0 */
1114 void
1115 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname)
1116 	struct puffs_usermount *pu;
1117 	int cmd,
1118 	puffs_cookie_t *cookie;
1119 	int flags;
1120 	int namespace;
1121 	const char *attrname;
1122 {
1123 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1124 	return 0;
1125 }
1126 #endif /* 0 */
1127 
1128 /* ARGSUSED0 */
1129 void
1130 perfuse_fs_suspend(pu, status)
1131 	struct puffs_usermount *pu;
1132 	int status;
1133 {
1134 	return;
1135 }
1136 
1137 
1138 
1139 int
1140 perfuse_node_lookup(pu, opc, pni, pcn)
1141 	struct puffs_usermount *pu;
1142 	puffs_cookie_t opc;
1143 	struct puffs_newinfo *pni;
1144 	const struct puffs_cn *pcn;
1145 {
1146 	struct puffs_node *pn;
1147 	mode_t mode;
1148 	int error;
1149 
1150 	/*
1151 	 * Check permissions
1152 	 */
1153 	switch(pcn->pcn_nameiop) {
1154 	case NAMEI_DELETE: /* FALLTHROUGH */
1155 	case NAMEI_RENAME: /* FALLTHROUGH */
1156 	case NAMEI_CREATE:
1157 		if (pcn->pcn_flags & NAMEI_ISLASTCN)
1158 			mode = PUFFS_VEXEC|PUFFS_VWRITE;
1159 		else
1160 			mode = PUFFS_VEXEC;
1161 		break;
1162 	case NAMEI_LOOKUP: /* FALLTHROUGH */
1163 	default:
1164 		mode = PUFFS_VEXEC;
1165 		break;
1166 	}
1167 
1168 	if ((error = mode_access(opc, pcn->pcn_cred, mode)) != 0)
1169 		return error;
1170 
1171 	/*
1172 	 * Special case for ..
1173 	 */
1174 	if (strcmp(pcn->pcn_name, "..") == 0)
1175 		pn = PERFUSE_NODE_DATA(opc)->pnd_parent;
1176 	else
1177 		error = node_lookup_common(pu, (puffs_cookie_t)opc,
1178 					   pcn->pcn_name, pcn->pcn_cred, &pn);
1179 	if (error != 0)
1180 		return error;
1181 
1182 	/*
1183 	 * Removed node
1184 	 */
1185 	if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED)
1186 		return ENOENT;
1187 
1188 	/*
1189 	 * Check for sticky bit. Unfortunately there is no way to
1190 	 * do this before creating the puffs_node, since we require
1191 	 * this operation to get the node owner.
1192 	 */
1193 	switch (pcn->pcn_nameiop) {
1194 	case NAMEI_DELETE: /* FALLTHROUGH */
1195 	case NAMEI_RENAME:
1196 		error = sticky_access(pn, pcn->pcn_cred);
1197 		if (error != 0) {
1198 			/*
1199 			 * kernel will never know about it and will
1200 			 * not reclaim it. The filesystem needs to
1201 			 * clean it up anyway, therefore mimick a forget.
1202 			 */
1203 			PERFUSE_NODE_DATA(pn)->pnd_flags |= PND_RECLAIMED;
1204 			(void)perfuse_node_reclaim(pu, (puffs_cookie_t)pn);
1205 			return error;
1206 		}
1207 		break;
1208 	default:
1209 		break;
1210 	}
1211 
1212 	/*
1213 	 * If that node had a pending reclaim, wipe it out.
1214 	 */
1215 	PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED;
1216 
1217 	puffs_newinfo_setcookie(pni, pn);
1218 	puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
1219 	puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size);
1220 	puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev);
1221 
1222 	return error;
1223 }
1224 
1225 int
1226 perfuse_node_create(pu, opc, pni, pcn, vap)
1227 	struct puffs_usermount *pu;
1228 	puffs_cookie_t opc;
1229 	struct puffs_newinfo *pni;
1230 	const struct puffs_cn *pcn;
1231 	const struct vattr *vap;
1232 {
1233 	perfuse_msg_t *pm;
1234 	struct perfuse_state *ps;
1235 	struct fuse_create_in *fci;
1236 	struct fuse_entry_out *feo;
1237 	struct fuse_open_out *foo;
1238 	struct puffs_node *pn;
1239 	const char *name;
1240 	size_t namelen;
1241 	size_t len;
1242 	int error;
1243 
1244 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1245 		return ENOENT;
1246 
1247 	/*
1248 	 * If create is unimplemented: Check that it does not
1249 	 * already exists, and if not, do mknod and open
1250 	 */
1251 	ps = puffs_getspecific(pu);
1252 	if (ps->ps_flags & PS_NO_CREAT) {
1253 		error = node_lookup_common(pu, opc, pcn->pcn_name,
1254 					   pcn->pcn_cred, &pn);
1255 		if (error == 0)
1256 			return EEXIST;
1257 
1258 		error = perfuse_node_mknod(pu, opc, pni, pcn, vap);
1259 		if (error != 0)
1260 			return error;
1261 
1262 		error = node_lookup_common(pu, opc, pcn->pcn_name,
1263 					   pcn->pcn_cred, &pn);
1264 		if (error != 0)
1265 			return error;
1266 
1267 		/*
1268 		 * FUSE does the open at create time, while
1269 		 * NetBSD will open in a subsequent operation.
1270 		 * We need to open now, in order to retain FUSE
1271 		 * semantics. The calling process will not get
1272 		 * a file descriptor before the kernel sends
1273 		 * the open operation.
1274 		 */
1275 		opc = (puffs_cookie_t)pn;
1276 		error = perfuse_node_open(pu, opc, FWRITE, pcn->pcn_cred);
1277 		if (error != 0)
1278 			return error;
1279 
1280 		return 0;
1281 	}
1282 
1283 	name = pcn->pcn_name;
1284 	namelen = pcn->pcn_namelen + 1;
1285 	len = sizeof(*fci) + namelen;
1286 
1287 	/*
1288 	 * flags should use O_WRONLY instead of O_RDWR, but it
1289 	 * breaks when the caller tries to read from file.
1290 	 *
1291 	 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type)
1292 	 */
1293 	pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred);
1294 	fci = GET_INPAYLOAD(ps, pm, fuse_create_in);
1295 	fci->flags = O_CREAT | O_TRUNC | O_RDWR;
1296 	fci->mode = vap->va_mode | VTTOIF(vap->va_type);
1297 	fci->umask = 0; 	/* Seems unused by libfuse */
1298 	(void)strlcpy((char*)(void *)(fci + 1), name, namelen);
1299 
1300 	len = sizeof(*feo) + sizeof(*foo);
1301 	if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0)
1302 		goto out;
1303 
1304 	feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
1305 	foo = (struct fuse_open_out *)(void *)(feo + 1);
1306 	if (feo->nodeid == PERFUSE_UNKNOWN_NODEID)
1307 		DERRX(EX_SOFTWARE, "%s: no nodeid", __func__);
1308 
1309 	/*
1310 	 * Save the file handle and inode in node private data
1311 	 * so that we can reuse it later
1312 	 */
1313 	pn = perfuse_new_pn(pu, name, opc);
1314 	perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE);
1315 	PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid;
1316 
1317 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
1318 	pn->pn_va.va_gen = (u_long)(feo->generation);
1319 	set_expire((puffs_cookie_t)pn, feo, NULL);
1320 
1321 	puffs_newinfo_setcookie(pni, pn);
1322 
1323 #ifdef PERFUSE_DEBUG
1324 	if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1325 		DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
1326 			"nodeid = 0x%"PRIx64", wfh = 0x%"PRIx64"\n",
1327 			__func__, (void *)pn, pcn->pcn_name,
1328 			PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid,
1329 			foo->fh);
1330 #endif
1331 
1332 	ps->ps_destroy_msg(pm);
1333 
1334 	return node_mk_common_final(pu, opc, pn, pcn);
1335 
1336 out:
1337 	ps->ps_destroy_msg(pm);
1338 
1339 	/*
1340 	 * create is unimplmented, remember it for later,
1341 	 * and start over using mknod and open instead.
1342 	 */
1343 	if (error == ENOSYS) {
1344 		ps->ps_flags |= PS_NO_CREAT;
1345 		return perfuse_node_create(pu, opc, pni, pcn, vap);
1346 	}
1347 
1348 	return error;
1349 }
1350 
1351 
1352 int
1353 perfuse_node_mknod(pu, opc, pni, pcn, vap)
1354 	struct puffs_usermount *pu;
1355 	puffs_cookie_t opc;
1356 	struct puffs_newinfo *pni;
1357 	const struct puffs_cn *pcn;
1358 	const struct vattr *vap;
1359 {
1360 	struct perfuse_state *ps;
1361 	perfuse_msg_t *pm;
1362 	struct fuse_mknod_in *fmi;
1363 	const char* path;
1364 	size_t len;
1365 
1366 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1367 		return ENOENT;
1368 
1369 	/*
1370 	 * Only superuser can mknod objects other than
1371 	 * directories, files, socks, fifo and links.
1372 	 *
1373 	 * Create an object require -WX permission in the parent directory
1374 	 */
1375 	switch (vap->va_type) {
1376 	case VDIR:	/* FALLTHROUGH */
1377 	case VREG:	/* FALLTHROUGH */
1378 	case VFIFO:	/* FALLTHROUGH */
1379 	case VSOCK:
1380 		break;
1381 	default:	/* VNON, VBLK, VCHR, VBAD */
1382 		if (!puffs_cred_isjuggernaut(pcn->pcn_cred))
1383 			return EACCES;
1384 		break;
1385 	}
1386 
1387 
1388 	ps = puffs_getspecific(pu);
1389 	path = pcn->pcn_name;
1390 	len = sizeof(*fmi) + pcn->pcn_namelen + 1;
1391 
1392 	/*
1393 	 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type)
1394 	 */
1395 	pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred);
1396 	fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in);
1397 	fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
1398 	fmi->rdev = (uint32_t)vap->va_rdev;
1399 	fmi->umask = 0; 	/* Seems unused bu libfuse */
1400 	(void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
1401 
1402 	return node_mk_common(pu, opc, pni, pcn, pm);
1403 }
1404 
1405 
1406 int
1407 perfuse_node_open(pu, opc, mode, pcr)
1408 	struct puffs_usermount *pu;
1409 	puffs_cookie_t opc;
1410 	int mode;
1411 	const struct puffs_cred *pcr;
1412 {
1413 	struct perfuse_state *ps;
1414 	struct perfuse_node_data *pnd;
1415 	perfuse_msg_t *pm;
1416 	mode_t fmode;
1417 	int op;
1418 	struct fuse_open_in *foi;
1419 	struct fuse_open_out *foo;
1420 	struct puffs_node *pn;
1421 	int error;
1422 
1423 	ps = puffs_getspecific(pu);
1424 	pn = (struct puffs_node *)opc;
1425 	pnd = PERFUSE_NODE_DATA(opc);
1426 	pm = NULL;
1427 	error = 0;
1428 
1429 	if (pnd->pnd_flags & PND_REMOVED)
1430 		return ENOENT;
1431 
1432 	if (puffs_pn_getvap(pn)->va_type == VDIR)
1433 		op = FUSE_OPENDIR;
1434 	else
1435 		op = FUSE_OPEN;
1436 
1437 	/*
1438 	 * libfuse docs says
1439 	 * - O_CREAT and O_EXCL should never be set.
1440 	 * - O_TRUNC may be used if mount option atomic_o_trunc is used XXX
1441 	 *
1442 	 * O_APPEND makes no sense since FUSE always sends
1443 	 * the file offset for write operations. If the
1444 	 * filesystem uses pwrite(), O_APPEND would cause
1445 	 * the offset to be ignored and cause file corruption.
1446 	 */
1447 	mode &= ~(O_CREAT|O_EXCL|O_APPEND);
1448 
1449 	/*
1450 	 * Do not open twice, and do not reopen for reading
1451 	 * if we already have write handle.
1452 	 */
1453 	if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) ||
1454 	    ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) ||
1455 	    ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))) {
1456 		error = 0;
1457 		goto out;
1458 	}
1459 
1460 	/*
1461 	 * Queue open on a node so that we do not open
1462 	 * twice. This would be better with read and
1463 	 * write distinguished.
1464 	 */
1465 	while (pnd->pnd_flags & PND_INOPEN)
1466 		requeue_request(pu, opc, PCQ_OPEN);
1467 	pnd->pnd_flags |= PND_INOPEN;
1468 
1469 	/*
1470 	 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE
1471 	 * to O_RDONLY/O_WRONLY while perserving the other options.
1472 	 */
1473 	fmode = mode & ~(FREAD|FWRITE);
1474 	fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY;
1475 
1476 	pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr);
1477 	foi = GET_INPAYLOAD(ps, pm, fuse_open_in);
1478 	foi->flags = fmode;
1479 	foi->unused = 0;
1480 
1481 	if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0)
1482 		goto out;
1483 
1484 	foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out);
1485 
1486 	/*
1487 	 * Save the file handle in node private data
1488 	 * so that we can reuse it later
1489 	 */
1490 	perfuse_new_fh(opc, foo->fh, mode);
1491 
1492 #ifdef PERFUSE_DEBUG
1493 	if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1494 		DPRINTF("%s: opc = %p, file = \"%s\", "
1495 			"nodeid = 0x%"PRIx64", %s%sfh = 0x%"PRIx64"\n",
1496 			__func__, (void *)opc, perfuse_node_path(opc),
1497 			pnd->pnd_nodeid, mode & FREAD ? "r" : "",
1498 			mode & FWRITE ? "w" : "", foo->fh);
1499 #endif
1500 
1501 out:
1502 	if (pm != NULL)
1503 		ps->ps_destroy_msg(pm);
1504 
1505 	pnd->pnd_flags &= ~PND_INOPEN;
1506 	(void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
1507 
1508 	return error;
1509 }
1510 
1511 /* ARGSUSED0 */
1512 int
1513 perfuse_node_close(pu, opc, flags, pcr)
1514 	struct puffs_usermount *pu;
1515 	puffs_cookie_t opc;
1516 	int flags;
1517 	const struct puffs_cred *pcr;
1518 {
1519 	struct perfuse_node_data *pnd;
1520 
1521 	pnd = PERFUSE_NODE_DATA(opc);
1522 
1523 	if (!(pnd->pnd_flags & PND_OPEN))
1524 		return EBADF;
1525 
1526 	/*
1527 	 * Actual close is postponed at inactive time.
1528 	 */
1529 	return 0;
1530 }
1531 
1532 int
1533 perfuse_node_access(pu, opc, mode, pcr)
1534 	struct puffs_usermount *pu;
1535 	puffs_cookie_t opc;
1536 	int mode;
1537 	const struct puffs_cred *pcr;
1538 {
1539 	perfuse_msg_t *pm;
1540 	struct perfuse_state *ps;
1541 	struct fuse_access_in *fai;
1542 	int error;
1543 
1544 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1545 		return ENOENT;
1546 
1547 	/*
1548 	 * If we previously detected the filesystem does not
1549 	 * implement access(), short-circuit the call and skip
1550 	 * to libpuffs access() emulation.
1551 	 */
1552 	ps = puffs_getspecific(pu);
1553 	if (ps->ps_flags & PS_NO_ACCESS) {
1554 		const struct vattr *vap;
1555 
1556 		vap = puffs_pn_getvap((struct puffs_node *)opc);
1557 
1558 		error = puffs_access(IFTOVT(vap->va_mode),
1559 				     vap->va_mode & ACCESSPERMS,
1560 				     vap->va_uid, vap->va_gid,
1561 				     (mode_t)mode, pcr);
1562 		return error;
1563 	}
1564 
1565 	/*
1566 	 * Plain access call
1567 	 */
1568 	pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr);
1569 	fai = GET_INPAYLOAD(ps, pm, fuse_access_in);
1570 	fai->mask = 0;
1571 	fai->mask |= (mode & PUFFS_VREAD) ? R_OK : 0;
1572 	fai->mask |= (mode & PUFFS_VWRITE) ? W_OK : 0;
1573 	fai->mask |= (mode & PUFFS_VEXEC) ? X_OK : 0;
1574 
1575 	error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
1576 
1577 	ps->ps_destroy_msg(pm);
1578 
1579 	/*
1580 	 * If unimplemented, start over with emulation
1581 	 */
1582 	if (error == ENOSYS) {
1583 		ps->ps_flags |= PS_NO_ACCESS;
1584 		return perfuse_node_access(pu, opc, mode, pcr);
1585 	}
1586 
1587 	return error;
1588 }
1589 
1590 int
1591 perfuse_node_getattr(pu, opc, vap, pcr)
1592 	struct puffs_usermount *pu;
1593 	puffs_cookie_t opc;
1594 	struct vattr *vap;
1595 	const struct puffs_cred *pcr;
1596 {
1597 	perfuse_msg_t *pm = NULL;
1598 	struct perfuse_state *ps;
1599 	struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
1600 	struct fuse_getattr_in *fgi;
1601 	struct fuse_attr_out *fao;
1602 	int error = 0;
1603 
1604 	if (pnd->pnd_flags & PND_REMOVED)
1605 		return ENOENT;
1606 
1607 	/*
1608 	 * Serialize size access, see comment in perfuse_node_setattr().
1609 	 */
1610 	while (pnd->pnd_flags & PND_INRESIZE)
1611 		requeue_request(pu, opc, PCQ_RESIZE);
1612 	pnd->pnd_flags |= PND_INRESIZE;
1613 
1614 	ps = puffs_getspecific(pu);
1615 
1616 	/*
1617 	 * Check for cached attributes
1618 	 * This still require serialized access to size.
1619 	 */
1620 	if (!attr_expired(opc)) {
1621 		(void)memcpy(vap, puffs_pn_getvap((struct puffs_node *)opc),
1622 			     sizeof(*vap));
1623 		goto out;
1624 	}
1625 
1626 	/*
1627 	 * FUSE_GETATTR_FH must be set in fgi->flags
1628 	 * if we use for fgi->fh
1629 	 */
1630 	pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr);
1631 	fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1632 	fgi->getattr_flags = 0;
1633 	fgi->dummy = 0;
1634 	fgi->fh = 0;
1635 
1636 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) {
1637 		fgi->fh = perfuse_get_fh(opc, FREAD);
1638 		fgi->getattr_flags |= FUSE_GETATTR_FH;
1639 	}
1640 
1641 #ifdef PERFUSE_DEBUG
1642 	if (perfuse_diagflags & PDF_RESIZE)
1643 		DPRINTF(">> %s %p %" PRIu64 "\n", __func__, (void *)opc,
1644 		    vap->va_size);
1645 #endif
1646 
1647 	if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
1648 		goto out;
1649 
1650 	fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1651 
1652 #ifdef PERFUSE_DEBUG
1653 	if (perfuse_diagflags & PDF_RESIZE)
1654 		DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1655 		    (void *)opc, vap->va_size, fao->attr.size);
1656 #endif
1657 
1658 	/*
1659 	 * We set birthtime, flags, filerev,vaflags to 0.
1660 	 * This seems the best bet, since the information is
1661 	 * not available from filesystem.
1662 	 */
1663 	fuse_attr_to_vap(ps, vap, &fao->attr);
1664 	set_expire(opc, NULL, fao);
1665 
1666 out:
1667 	if (pm != NULL)
1668 		ps->ps_destroy_msg(pm);
1669 
1670 	pnd->pnd_flags &= ~PND_INRESIZE;
1671 	(void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
1672 
1673 	return error;
1674 }
1675 
1676 int
1677 perfuse_node_setattr(pu, opc, vap, pcr)
1678 	struct puffs_usermount *pu;
1679 	puffs_cookie_t opc;
1680 	const struct vattr *vap;
1681 	const struct puffs_cred *pcr;
1682 {
1683 	perfuse_msg_t *pm;
1684 	uint64_t fh;
1685 	struct perfuse_state *ps;
1686 	struct perfuse_node_data *pnd;
1687 	struct fuse_setattr_in *fsi;
1688 	struct fuse_attr_out *fao;
1689 	struct vattr *old_va;
1690 	int error;
1691 #ifdef PERFUSE_DEBUG
1692 	struct vattr *old_vap;
1693 	int resize_debug = 0;
1694 #endif
1695 
1696 	ps = puffs_getspecific(pu);
1697 	pnd = PERFUSE_NODE_DATA(opc);
1698 	pm = NULL;
1699 
1700 	/*
1701 	 * The only operation we can do once the file is removed
1702 	 * is to resize it, and we can do it only if it is open.
1703 	 * Do not even send the operation to the filesystem: the
1704 	 * file is not there anymore.
1705 	 */
1706 	if (pnd->pnd_flags & PND_REMOVED) {
1707 		if (!(pnd->pnd_flags & PND_OPEN))
1708 			return ENOENT;
1709 
1710 		error = 0;
1711 		goto out;
1712 	}
1713 
1714 	old_va = puffs_pn_getvap((struct puffs_node *)opc);
1715 
1716 	/*
1717 	 * Check for permission to change size
1718 	 */
1719 	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
1720 	    (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0)
1721 		return error;
1722 
1723 	/*
1724 	 * Check for permission to change dates
1725 	 */
1726 	if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
1727 	     (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
1728 	    (puffs_access_times(old_va->va_uid, old_va->va_gid,
1729 				old_va->va_mode, 0, pcr) != 0))
1730 		return EACCES;
1731 
1732 	/*
1733 	 * Check for permission to change owner and group
1734 	 */
1735 	if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
1736 	     (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
1737 	    (puffs_access_chown(old_va->va_uid, old_va->va_gid,
1738 				vap->va_uid, vap->va_gid, pcr)) != 0)
1739 		return EACCES;
1740 
1741 	/*
1742 	 * Check for permission to change permissions
1743 	 */
1744 	if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
1745 	    (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
1746 				old_va->va_type, vap->va_mode, pcr)) != 0)
1747 		return EACCES;
1748 
1749 	pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
1750 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
1751 	fsi->valid = 0;
1752 
1753 	/*
1754 	 * Get a fh if the node is open for writing
1755 	 */
1756 	if (pnd->pnd_flags & PND_WFH) {
1757 		fh = perfuse_get_fh(opc, FWRITE);
1758 		fsi->fh = fh;
1759 		fsi->valid |= FUSE_FATTR_FH;
1760 	}
1761 
1762 	if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
1763 		fsi->size = vap->va_size;
1764 		fsi->valid |= FUSE_FATTR_SIZE;
1765 
1766 		/*
1767 		 * Serialize anything that can touch file size
1768 		 * to avoid reordered GETATTR and SETATTR.
1769 		 * Out of order SETATTR can report stale size,
1770 		 * which will cause the kernel to truncate the file.
1771 		 */
1772 		while (pnd->pnd_flags & PND_INRESIZE)
1773 			requeue_request(pu, opc, PCQ_RESIZE);
1774 		pnd->pnd_flags |= PND_INRESIZE;
1775 	}
1776 
1777 	/*
1778  	 * Setting mtime without atime or vice versa leads to
1779 	 * dates being reset to Epoch on glusterfs. If one
1780 	 * is missing, use the old value.
1781  	 */
1782 	if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) ||
1783 	    (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) {
1784 
1785 		if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
1786 			fsi->atime = vap->va_atime.tv_sec;
1787 			fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;
1788 		} else {
1789 			fsi->atime = old_va->va_atime.tv_sec;
1790 			fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec;
1791 		}
1792 
1793 		if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
1794 			fsi->mtime = vap->va_mtime.tv_sec;
1795 			fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec;
1796 		} else {
1797 			fsi->mtime = old_va->va_mtime.tv_sec;
1798 			fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec;
1799 		}
1800 
1801 		fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME);
1802 	}
1803 
1804 	if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
1805 		fsi->mode = vap->va_mode;
1806 		fsi->valid |= FUSE_FATTR_MODE;
1807 	}
1808 
1809 	if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
1810 		fsi->uid = vap->va_uid;
1811 		fsi->valid |= FUSE_FATTR_UID;
1812 	}
1813 
1814 	if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
1815 		fsi->gid = vap->va_gid;
1816 		fsi->valid |= FUSE_FATTR_GID;
1817 	}
1818 
1819 	if (pnd->pnd_lock_owner != 0) {
1820 		fsi->lock_owner = pnd->pnd_lock_owner;
1821 		fsi->valid |= FUSE_FATTR_LOCKOWNER;
1822 	}
1823 
1824 	/*
1825 	 * ftruncate() sends only va_size, and metadata cache
1826 	 * flush adds va_atime and va_mtime. Some FUSE
1827 	 * filesystems will attempt to detect ftruncate by
1828 	 * checking for FATTR_SIZE being set without
1829 	 * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE
1830 	 *
1831 	 * Try to adapt and remove FATTR_ATIME|FATTR_MTIME
1832 	 * if we suspect a ftruncate().
1833 	 */
1834 	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
1835 	    ((vap->va_mode == (mode_t)PUFFS_VNOVAL) &&
1836 	     (vap->va_uid == (uid_t)PUFFS_VNOVAL) &&
1837 	     (vap->va_gid == (gid_t)PUFFS_VNOVAL))) {
1838 		fsi->atime = 0;
1839 		fsi->atimensec = 0;
1840 		fsi->mtime = 0;
1841 		fsi->mtimensec = 0;
1842 		fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME);
1843 	}
1844 
1845 	/*
1846 	 * If nothing remain, discard the operation.
1847 	 */
1848 	if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
1849 			    FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
1850 		error = 0;
1851 		goto out;
1852 	}
1853 
1854 #ifdef PERFUSE_DEBUG
1855 	old_vap = puffs_pn_getvap((struct puffs_node *)opc);
1856 
1857 	if ((perfuse_diagflags & PDF_RESIZE) &&
1858 	    (old_vap->va_size != (u_quad_t)PUFFS_VNOVAL)) {
1859 		resize_debug = 1;
1860 
1861 		DPRINTF(">> %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1862 		    (void *)opc,
1863 		    puffs_pn_getvap((struct puffs_node *)opc)->va_size,
1864 		    fsi->size);
1865 	}
1866 #endif
1867 
1868 	if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
1869 		goto out;
1870 
1871 	/*
1872 	 * Copy back the new values
1873 	 */
1874 	fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1875 
1876 #ifdef PERFUSE_DEBUG
1877 	if (resize_debug)
1878 		DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1879 		    (void *)opc, old_vap->va_size, fao->attr.size);
1880 #endif
1881 
1882 	fuse_attr_to_vap(ps, old_va, &fao->attr);
1883 	set_expire(opc, NULL, fao);
1884 
1885 out:
1886 	if (pm != NULL)
1887 		ps->ps_destroy_msg(pm);
1888 
1889 	if (pnd->pnd_flags & PND_INRESIZE) {
1890 		pnd->pnd_flags &= ~PND_INRESIZE;
1891 		(void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
1892 	}
1893 
1894 	return error;
1895 }
1896 
1897 int
1898 perfuse_node_poll(pu, opc, events)
1899 	struct puffs_usermount *pu;
1900 	puffs_cookie_t opc;
1901 	int *events;
1902 {
1903 	struct perfuse_state *ps;
1904 	perfuse_msg_t *pm;
1905 	struct fuse_poll_in *fpi;
1906 	struct fuse_poll_out *fpo;
1907 	int error;
1908 
1909 	ps = puffs_getspecific(pu);
1910 	/*
1911 	 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
1912 	 *
1913 	 * XXX ps_new_msg() is called with NULL creds, which will
1914 	 * be interpreted as FUSE superuser. We have no way to
1915 	 * know the requesting process' credential, but since poll
1916 	 * is supposed to operate on a file that has been open,
1917 	 * permission should have already been checked at open time.
1918 	 * That still may breaks on filesystems that provides odd
1919 	 * semantics.
1920  	 */
1921 	pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
1922 	fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
1923 	fpi->fh = perfuse_get_fh(opc, FREAD);
1924 	fpi->kh = 0;
1925 	fpi->flags = 0;
1926 
1927 #ifdef PERFUSE_DEBUG
1928 	if (perfuse_diagflags & PDF_FH)
1929 		DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
1930 			__func__, (void *)opc,
1931 			PERFUSE_NODE_DATA(opc)->pnd_nodeid, fpi->fh);
1932 #endif
1933 	if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0)
1934 		goto out;
1935 
1936 	fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
1937 	*events = fpo->revents;
1938 out:
1939 	ps->ps_destroy_msg(pm);
1940 
1941 	return error;
1942 }
1943 
1944 /* ARGSUSED0 */
1945 int
1946 perfuse_node_mmap(pu, opc, flags, pcr)
1947 	struct puffs_usermount *pu;
1948 	puffs_cookie_t opc;
1949 	int flags;
1950 	const struct puffs_cred *pcr;
1951 {
1952 	/*
1953 	 * Not implemented anymore in libfuse
1954 	 */
1955 	return ENOSYS;
1956 }
1957 
1958 /* ARGSUSED2 */
1959 int
1960 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi)
1961 	struct puffs_usermount *pu;
1962 	puffs_cookie_t opc;
1963 	const struct puffs_cred *pcr;
1964 	int flags;
1965 	off_t offlo;
1966 	off_t offhi;
1967 {
1968 	int op;
1969 	perfuse_msg_t *pm;
1970 	struct perfuse_state *ps;
1971 	struct perfuse_node_data *pnd;
1972 	struct fuse_fsync_in *ffi;
1973 	uint64_t fh;
1974 	int error;
1975 
1976 	pm = NULL;
1977 	ps = puffs_getspecific(pu);
1978 	pnd = PERFUSE_NODE_DATA(opc);
1979 
1980 	/*
1981 	 * No need to sync a removed node
1982 	 */
1983 	if (pnd->pnd_flags & PND_REMOVED)
1984 		return 0;
1985 
1986 	/*
1987 	 * We do not sync closed files. They have been
1988 	 * sync at inactive time already.
1989 	 */
1990 	if (!(pnd->pnd_flags & PND_OPEN))
1991 		return 0;
1992 
1993 	if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
1994 		op = FUSE_FSYNCDIR;
1995 	else 		/* VREG but also other types such as VLNK */
1996 		op = FUSE_FSYNC;
1997 
1998 	/*
1999 	 * Do not sync if there are no change to sync
2000 	 * XXX remove that test on files if we implement mmap
2001 	 */
2002 #ifdef PERFUSE_DEBUG
2003 	if (perfuse_diagflags & PDF_SYNC)
2004 		DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",
2005 			__func__, (void*)opc, perfuse_node_path(opc),
2006 			pnd->pnd_flags & PND_DIRTY ? "" : "not ");
2007 #endif
2008 	if (!(pnd->pnd_flags & PND_DIRTY))
2009 		return 0;
2010 
2011 	/*
2012 	 * It seems NetBSD can call fsync without open first
2013 	 * glusterfs complain in such a situation:
2014 	 * "FSYNC() ERR => -1 (Invalid argument)"
2015 	 * The file will be closed at inactive time.
2016 	 *
2017 	 * We open the directory for reading in order to sync.
2018 	 * This sounds rather counterintuitive, but it works.
2019 	 */
2020 	if (!(pnd->pnd_flags & PND_WFH)) {
2021 		if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2022 			goto out;
2023 	}
2024 
2025 	if (op == FUSE_FSYNCDIR)
2026 		fh = perfuse_get_fh(opc, FREAD);
2027 	else
2028 		fh = perfuse_get_fh(opc, FWRITE);
2029 
2030 	/*
2031 	 * If fsync_flags  is set, meta data should not be flushed.
2032 	 */
2033 	pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), pcr);
2034 	ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
2035 	ffi->fh = fh;
2036 	ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
2037 
2038 #ifdef PERFUSE_DEBUG
2039 	if (perfuse_diagflags & PDF_FH)
2040 		DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2041 			__func__, (void *)opc,
2042 			PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh);
2043 #endif
2044 
2045 	if ((error = xchg_msg(pu, opc, pm,
2046 			      NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
2047 		goto out;
2048 
2049 	/*
2050 	 * No reply beyond fuse_out_header: nothing to do on success
2051 	 * just clear the dirty flag
2052 	 */
2053 	pnd->pnd_flags &= ~PND_DIRTY;
2054 
2055 #ifdef PERFUSE_DEBUG
2056 	if (perfuse_diagflags & PDF_SYNC)
2057 		DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
2058 			__func__, (void*)opc, perfuse_node_path(opc));
2059 #endif
2060 
2061 out:
2062 	/*
2063 	 * ENOSYS is not returned to kernel,
2064 	 */
2065 	if (error == ENOSYS)
2066 		error = 0;
2067 
2068 	if (pm != NULL)
2069 		ps->ps_destroy_msg(pm);
2070 
2071 	return error;
2072 }
2073 
2074 /* ARGSUSED0 */
2075 int
2076 perfuse_node_seek(pu, opc, oldoff, newoff,  pcr)
2077 	struct puffs_usermount *pu;
2078 	puffs_cookie_t opc;
2079 	off_t oldoff;
2080 	off_t newoff;
2081 	const struct puffs_cred *pcr;
2082 {
2083 	return 0;
2084 }
2085 
2086 int
2087 perfuse_node_remove(pu, opc, targ, pcn)
2088 	struct puffs_usermount *pu;
2089 	puffs_cookie_t opc;
2090 	puffs_cookie_t targ;
2091 	const struct puffs_cn *pcn;
2092 {
2093 	struct perfuse_state *ps;
2094 	struct perfuse_node_data *pnd;
2095 	perfuse_msg_t *pm;
2096 	char *path;
2097 	const char *name;
2098 	size_t len;
2099 	int error;
2100 
2101 	pnd = PERFUSE_NODE_DATA(opc);
2102 
2103 	if ((pnd->pnd_flags & PND_REMOVED) ||
2104 	    (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED))
2105 		return ENOENT;
2106 
2107 #ifdef PERFUSE_DEBUG
2108 	if (targ == NULL)
2109 		DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
2110 
2111 	if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
2112 		DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n",
2113 			__func__, (void *)opc, (void *)targ, pcn->pcn_name);
2114 #endif
2115 	/*
2116 	 * Await for all operations on the deleted node to drain,
2117 	 * as the filesystem may be confused to have it deleted
2118 	 * during a getattr
2119 	 */
2120 	while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2121 		requeue_request(pu, targ, PCQ_AFTERXCHG);
2122 
2123 	ps = puffs_getspecific(pu);
2124 	pnd = PERFUSE_NODE_DATA(opc);
2125 	name = pcn->pcn_name;
2126 	len = pcn->pcn_namelen + 1;
2127 
2128 	pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
2129 	path = _GET_INPAYLOAD(ps, pm, char *);
2130 	(void)strlcpy(path, name, len);
2131 
2132 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2133 		goto out;
2134 
2135 	PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2136 	if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2137 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2138 
2139 	/*
2140 	 * The parent directory needs a sync
2141 	 */
2142 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2143 
2144 #ifdef PERFUSE_DEBUG
2145 	if (perfuse_diagflags & PDF_FILENAME)
2146 		DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2147 			__func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2148 			pcn->pcn_name);
2149 #endif
2150 out:
2151 	ps->ps_destroy_msg(pm);
2152 
2153 	return error;
2154 }
2155 
2156 int
2157 perfuse_node_link(pu, opc, targ, pcn)
2158 	struct puffs_usermount *pu;
2159 	puffs_cookie_t opc;
2160 	puffs_cookie_t targ;
2161 	const struct puffs_cn *pcn;
2162 {
2163 	struct perfuse_state *ps;
2164 	perfuse_msg_t *pm;
2165 	const char *name;
2166 	size_t len;
2167 	struct puffs_node *pn;
2168 	struct fuse_link_in *fli;
2169 	int error;
2170 
2171 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2172 		return ENOENT;
2173 
2174 	ps = puffs_getspecific(pu);
2175 	pn = (struct puffs_node *)targ;
2176 	name = pcn->pcn_name;
2177 	len =  sizeof(*fli) + pcn->pcn_namelen + 1;
2178 
2179 	pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred);
2180 	fli = GET_INPAYLOAD(ps, pm, fuse_link_in);
2181 	fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_nodeid;
2182 	(void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli));
2183 
2184 	error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
2185 
2186 	ps->ps_destroy_msg(pm);
2187 
2188 	return error;
2189 }
2190 
2191 int
2192 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ)
2193 	struct puffs_usermount *pu;
2194 	puffs_cookie_t opc;
2195 	puffs_cookie_t src;
2196 	const struct puffs_cn *pcn_src;
2197 	puffs_cookie_t targ_dir;
2198 	puffs_cookie_t targ;
2199 	const struct puffs_cn *pcn_targ;
2200 {
2201 	struct perfuse_state *ps;
2202 	perfuse_msg_t *pm;
2203 	struct fuse_rename_in *fri;
2204 	const char *newname;
2205 	const char *oldname;
2206 	char *np;
2207 	int error;
2208 	size_t len;
2209 	size_t newname_len;
2210 	size_t oldname_len;
2211 
2212 	if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) ||
2213 	    (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) ||
2214 	    (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED))
2215 		return ENOENT;
2216 
2217 	/*
2218 	 * Await for all operations on the deleted node to drain,
2219 	 * as the filesystem may be confused to have it deleted
2220 	 * during a getattr
2221 	 */
2222 	if ((struct puffs_node *)targ != NULL) {
2223 		while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2224 			requeue_request(pu, targ, PCQ_AFTERXCHG);
2225 	} else {
2226 		while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG)
2227 			requeue_request(pu, src, PCQ_AFTERXCHG);
2228 	}
2229 
2230 	ps = puffs_getspecific(pu);
2231 	newname =  pcn_targ->pcn_name;
2232 	newname_len = pcn_targ->pcn_namelen + 1;
2233 	oldname =  pcn_src->pcn_name;
2234 	oldname_len = pcn_src->pcn_namelen + 1;
2235 
2236 	len = sizeof(*fri) + oldname_len + newname_len;
2237 	pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_targ->pcn_cred);
2238 	fri = GET_INPAYLOAD(ps, pm, fuse_rename_in);
2239 	fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid;
2240 	np = (char *)(void *)(fri + 1);
2241 	(void)strlcpy(np, oldname, oldname_len);
2242 	np += oldname_len;
2243 	(void)strlcpy(np, newname, newname_len);
2244 
2245 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2246 		goto out;
2247 
2248 	if (opc != targ_dir) {
2249 		struct perfuse_node_data *srcdir_pnd;
2250 		struct perfuse_node_data *dstdir_pnd;
2251 		struct perfuse_node_data *src_pnd;
2252 
2253 		srcdir_pnd = PERFUSE_NODE_DATA(opc);
2254 		dstdir_pnd = PERFUSE_NODE_DATA(targ_dir);
2255 		src_pnd = PERFUSE_NODE_DATA(src);
2256 
2257 		TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next);
2258 		TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next);
2259 
2260 		srcdir_pnd->pnd_childcount--;
2261 		dstdir_pnd->pnd_childcount++;
2262 
2263 		src_pnd->pnd_parent = targ_dir;
2264 
2265 		PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY;
2266 	}
2267 
2268 	(void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN);
2269 
2270 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2271 
2272 	if ((struct puffs_node *)targ != NULL)
2273 		PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2274 
2275 #ifdef PERFUSE_DEBUG
2276 	if (perfuse_diagflags & PDF_FILENAME)
2277 		DPRINTF("%s: nodeid = 0x%"PRIx64" file = \"%s\" renamed \"%s\" "
2278 			"nodeid = 0x%"PRIx64" -> nodeid = 0x%"PRIx64" \"%s\"\n",
2279 	 		__func__, PERFUSE_NODE_DATA(src)->pnd_nodeid,
2280 			pcn_src->pcn_name, pcn_targ->pcn_name,
2281 			PERFUSE_NODE_DATA(opc)->pnd_nodeid,
2282 			PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid,
2283 			perfuse_node_path(targ_dir));
2284 #endif
2285 
2286 out:
2287 	if (pm != NULL)
2288 		ps->ps_destroy_msg(pm);
2289 
2290 	return error;
2291 }
2292 
2293 int
2294 perfuse_node_mkdir(pu, opc, pni, pcn, vap)
2295 	struct puffs_usermount *pu;
2296 	puffs_cookie_t opc;
2297 	struct puffs_newinfo *pni;
2298 	const struct puffs_cn *pcn;
2299 	const struct vattr *vap;
2300 {
2301 	struct perfuse_state *ps;
2302 	perfuse_msg_t *pm;
2303 	struct fuse_mkdir_in *fmi;
2304 	const char *path;
2305 	size_t len;
2306 
2307 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2308 		return ENOENT;
2309 
2310 	ps = puffs_getspecific(pu);
2311 	path = pcn->pcn_name;
2312 	len = sizeof(*fmi) + pcn->pcn_namelen + 1;
2313 
2314 	pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred);
2315 	fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in);
2316 	fmi->mode = vap->va_mode;
2317 	fmi->umask = 0; 	/* Seems unused by libfuse? */
2318 	(void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
2319 
2320 	return node_mk_common(pu, opc, pni, pcn, pm);
2321 }
2322 
2323 
2324 int
2325 perfuse_node_rmdir(pu, opc, targ, pcn)
2326 	struct puffs_usermount *pu;
2327 	puffs_cookie_t opc;
2328 	puffs_cookie_t targ;
2329 	const struct puffs_cn *pcn;
2330 {
2331 	struct perfuse_state *ps;
2332 	struct perfuse_node_data *pnd;
2333 	perfuse_msg_t *pm;
2334 	char *path;
2335 	const char *name;
2336 	size_t len;
2337 	int error;
2338 
2339 	pnd = PERFUSE_NODE_DATA(opc);
2340 	if (pnd->pnd_flags & PND_REMOVED)
2341 		return ENOENT;
2342 
2343 	/*
2344 	 * Await for all operations on the deleted node to drain,
2345 	 * as the filesystem may be confused to have it deleted
2346 	 * during a getattr
2347 	 */
2348 	while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2349 		requeue_request(pu, targ, PCQ_AFTERXCHG);
2350 
2351 	ps = puffs_getspecific(pu);
2352 	name = pcn->pcn_name;
2353 	len = pcn->pcn_namelen + 1;
2354 
2355 	pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
2356 	path = _GET_INPAYLOAD(ps, pm, char *);
2357 	(void)strlcpy(path, name, len);
2358 
2359 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2360 		goto out;
2361 
2362 	PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2363 	if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2364 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2365 
2366 	/*
2367 	 * The parent directory needs a sync
2368 	 */
2369 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2370 
2371 #ifdef PERFUSE_DEBUG
2372 	if (perfuse_diagflags & PDF_FILENAME)
2373 		DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2374 			__func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2375 			perfuse_node_path(targ));
2376 #endif
2377 out:
2378 	ps->ps_destroy_msg(pm);
2379 
2380 	return error;
2381 }
2382 
2383 /* vap is unused */
2384 /* ARGSUSED4 */
2385 int
2386 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target)
2387 	struct puffs_usermount *pu;
2388 	puffs_cookie_t opc;
2389 	struct puffs_newinfo *pni;
2390 	const struct puffs_cn *pcn_src;
2391 	const struct vattr *vap;
2392 	const char *link_target;
2393 {
2394 	struct perfuse_state *ps;
2395 	perfuse_msg_t *pm;
2396 	char *np;
2397 	const char *path;
2398 	size_t path_len;
2399 	size_t linkname_len;
2400 	size_t len;
2401 
2402 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2403 		return ENOENT;
2404 
2405 	ps = puffs_getspecific(pu);
2406 	path = pcn_src->pcn_name;
2407 	path_len = pcn_src->pcn_namelen + 1;
2408 	linkname_len = strlen(link_target) + 1;
2409 	len = path_len + linkname_len;
2410 
2411 	pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred);
2412 	np = _GET_INPAYLOAD(ps, pm, char *);
2413 	(void)strlcpy(np, path, path_len);
2414 	np += path_len;
2415 	(void)strlcpy(np, link_target, linkname_len);
2416 
2417 	return node_mk_common(pu, opc, pni, pcn_src, pm);
2418 }
2419 
2420 /* ARGSUSED4 */
2421 int
2422 perfuse_node_readdir(pu, opc, dent, readoff,
2423 		     reslen, pcr, eofflag, cookies, ncookies)
2424 	struct puffs_usermount *pu;
2425 	puffs_cookie_t opc;
2426 	struct dirent *dent;
2427 	off_t *readoff;
2428 	size_t *reslen;
2429 	const struct puffs_cred *pcr;
2430 	int *eofflag;
2431 	off_t *cookies;
2432 	size_t *ncookies;
2433 {
2434 	perfuse_msg_t *pm;
2435 	uint64_t fh;
2436 	struct perfuse_state *ps;
2437 	struct perfuse_node_data *pnd;
2438 	struct fuse_read_in *fri;
2439 	struct fuse_out_header *foh;
2440 	struct fuse_dirent *fd;
2441 	size_t foh_len;
2442 	int error;
2443 	size_t fd_maxlen;
2444 
2445 	pm = NULL;
2446 	error = 0;
2447 	ps = puffs_getspecific(pu);
2448 
2449 	/*
2450 	 * readdir state is kept at node level, and several readdir
2451 	 * requests can be issued at the same time on the same node.
2452 	 * We need to queue requests so that only one is in readdir
2453 	 * code at the same time.
2454 	 */
2455 	pnd = PERFUSE_NODE_DATA(opc);
2456 	while (pnd->pnd_flags & PND_INREADDIR)
2457 		requeue_request(pu, opc, PCQ_READDIR);
2458 	pnd->pnd_flags |= PND_INREADDIR;
2459 
2460 #ifdef PERFUSE_DEBUG
2461 	if (perfuse_diagflags & PDF_READDIR)
2462 		DPRINTF("%s: READDIR opc = %p enter critical section\n",
2463 			__func__, (void *)opc);
2464 #endif
2465 	/*
2466 	 * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node
2467 	 */
2468 	if (*readoff == 0)
2469 		pnd->pnd_fd_cookie = 0;
2470 
2471 	/*
2472 	 * Do we already have the data bufered?
2473 	 */
2474 	if (pnd->pnd_dirent != NULL)
2475 		goto out;
2476 	pnd->pnd_dirent_len = 0;
2477 
2478 	/*
2479 	 * It seems NetBSD can call readdir without open first
2480 	 * libfuse will crash if it is done that way, hence open first.
2481 	 */
2482 	if (!(pnd->pnd_flags & PND_OPEN)) {
2483 		if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2484 			goto out;
2485 	}
2486 
2487 	fh = perfuse_get_fh(opc, FREAD);
2488 
2489 #ifdef PERFUSE_DEBUG
2490 	if (perfuse_diagflags & PDF_FH)
2491 		DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", rfh = 0x%"PRIx64"\n",
2492 			__func__, (void *)opc,
2493 			PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh);
2494 #endif
2495 
2496 	pnd->pnd_all_fd = NULL;
2497 	pnd->pnd_all_fd_len = 0;
2498 	fd_maxlen = ps->ps_max_readahead - sizeof(*foh);
2499 
2500 	do {
2501 		size_t fd_len;
2502 		char *afdp;
2503 
2504 		pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
2505 
2506 		/*
2507 		 * read_flags, lock_owner and flags are unused in libfuse
2508 		 */
2509 		fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2510 		fri->fh = fh;
2511 		fri->offset = pnd->pnd_fd_cookie;
2512 		fri->size = (uint32_t)fd_maxlen;
2513 		fri->read_flags = 0;
2514 		fri->lock_owner = 0;
2515 		fri->flags = 0;
2516 
2517 		if ((error = xchg_msg(pu, opc, pm,
2518 				      UNSPEC_REPLY_LEN, wait_reply)) != 0)
2519 			goto out;
2520 
2521 		/*
2522 		 * There are many puffs_framebufs calls later,
2523 		 * therefore foh will not be valid for a long time.
2524 		 * Just get the length and forget it.
2525 		 */
2526 		foh = GET_OUTHDR(ps, pm);
2527 		foh_len = foh->len;
2528 
2529 		/*
2530 		 * Empty read: we reached the end of the buffer.
2531 		 */
2532 		if (foh_len == sizeof(*foh)) {
2533 			*eofflag = 1;
2534 			break;
2535 		}
2536 
2537 		/*
2538 		 * Check for corrupted message.
2539 		 */
2540 		if (foh_len < sizeof(*foh) + sizeof(*fd)) {
2541 			DWARNX("readdir reply too short");
2542 			error = EIO;
2543 			goto out;
2544 		}
2545 
2546 
2547 		fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
2548 		fd_len = foh_len - sizeof(*foh);
2549 
2550 		pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
2551 					  pnd->pnd_all_fd_len + fd_len);
2552 		if (pnd->pnd_all_fd  == NULL)
2553 			DERR(EX_OSERR, "%s: malloc failed", __func__);
2554 
2555 		afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
2556 		(void)memcpy(afdp, fd, fd_len);
2557 
2558 		pnd->pnd_all_fd_len += fd_len;
2559 
2560 		/*
2561 		 * The fd->off field is used as a cookie for
2562 		 * resuming the next readdir() where this one was left.
2563 	 	 */
2564 		pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len);
2565 
2566 		ps->ps_destroy_msg(pm);
2567 		pm = NULL;
2568 	} while (1 /* CONSTCOND */);
2569 
2570 	if (pnd->pnd_all_fd != NULL) {
2571 		if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd,
2572 				   pnd->pnd_all_fd_len) == -1)
2573 			error = EIO;
2574 	}
2575 
2576 out:
2577 	if (pnd->pnd_all_fd != NULL) {
2578 		free(pnd->pnd_all_fd);
2579 		pnd->pnd_all_fd = NULL;
2580 		pnd->pnd_all_fd_len = 0;
2581 	}
2582 
2583 	if (pm != NULL)
2584 		ps->ps_destroy_msg(pm);
2585 
2586 	if (error == 0)
2587 		error = readdir_buffered(opc, dent, readoff, reslen);
2588 
2589 	/*
2590 	 * Schedule queued readdir requests
2591 	 */
2592 	pnd->pnd_flags &= ~PND_INREADDIR;
2593 	(void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
2594 
2595 #ifdef PERFUSE_DEBUG
2596 	if (perfuse_diagflags & PDF_READDIR)
2597 		DPRINTF("%s: READDIR opc = %p exit critical section\n",
2598 			__func__, (void *)opc);
2599 #endif
2600 
2601 	return error;
2602 }
2603 
2604 int
2605 perfuse_node_readlink(pu, opc, pcr, linkname, linklen)
2606 	struct puffs_usermount *pu;
2607 	puffs_cookie_t opc;
2608 	const struct puffs_cred *pcr;
2609 	char *linkname;
2610 	size_t *linklen;
2611 {
2612 	struct perfuse_state *ps;
2613 	perfuse_msg_t *pm;
2614 	int error;
2615 	size_t len;
2616 	struct fuse_out_header *foh;
2617 
2618 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2619 		return ENOENT;
2620 
2621 	ps = puffs_getspecific(pu);
2622 
2623 	pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
2624 
2625 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2626 		goto out;
2627 
2628 	foh = GET_OUTHDR(ps, pm);
2629 	len = foh->len - sizeof(*foh);
2630 	if (len > *linklen)
2631 		DERRX(EX_PROTOCOL, "path len = %zd too long", len);
2632 	if (len == 0)
2633 		DERRX(EX_PROTOCOL, "path len = %zd too short", len);
2634 
2635 	/*
2636 	 * FUSE filesystems return a NUL terminated string, we
2637 	 * do not want to trailing \0
2638 	 */
2639 	*linklen = len - 1;
2640 	(void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
2641 out:
2642 	ps->ps_destroy_msg(pm);
2643 
2644 	return error;
2645 }
2646 
2647 int
2648 perfuse_node_reclaim(pu, opc)
2649 	struct puffs_usermount *pu;
2650 	puffs_cookie_t opc;
2651 {
2652 	struct perfuse_state *ps;
2653 	perfuse_msg_t *pm;
2654 	struct perfuse_node_data *pnd;
2655 	struct fuse_forget_in *ffi;
2656 	struct puffs_node *pn;
2657 	struct puffs_node *pn_root;
2658 
2659 	ps = puffs_getspecific(pu);
2660 	pnd = PERFUSE_NODE_DATA(opc);
2661 
2662 	/*
2663 	 * Never forget the root.
2664 	 */
2665 	if (pnd->pnd_nodeid == FUSE_ROOT_ID)
2666 		return 0;
2667 
2668 	pnd->pnd_flags |= PND_RECLAIMED;
2669 
2670 #ifdef PERFUSE_DEBUG
2671 	if (perfuse_diagflags & PDF_RECLAIM)
2672 		DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
2673 			perfuse_node_path(opc), pnd->pnd_nodeid);
2674 #endif
2675 
2676 	pn_root = puffs_getroot(pu);
2677 	pn = (struct puffs_node *)opc;
2678 	while (pn != pn_root) {
2679 		struct puffs_node *parent_pn;
2680 
2681 		pnd = PERFUSE_NODE_DATA(pn);
2682 
2683 #ifdef PERFUSE_DEBUG
2684 	if (perfuse_diagflags & PDF_RECLAIM)
2685 		DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, "
2686 			"has childcount %d %s%s%s%s, pending ops:%s%s%s\n",
2687 		        perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_nodeid,
2688 		        pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
2689 		        pnd->pnd_childcount,
2690 			pnd->pnd_flags & PND_OPEN ? "open " : "not open",
2691 			pnd->pnd_flags & PND_RFH ? "r" : "",
2692 			pnd->pnd_flags & PND_WFH ? "w" : "",
2693 			pnd->pnd_flags & PND_BUSY ? "" : " none",
2694 			pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
2695 			pnd->pnd_flags & PND_INWRITE ? " write" : "",
2696 			pnd->pnd_flags & PND_INOPEN ? " open" : "");
2697 #endif
2698 
2699 		if (!(pnd->pnd_flags & PND_RECLAIMED) ||
2700 		    (pnd->pnd_childcount != 0))
2701 			return 0;
2702 
2703 #ifdef PERFUSE_DEBUG
2704 		if ((pnd->pnd_flags & PND_OPEN) ||
2705 		       !TAILQ_EMPTY(&pnd->pnd_pcq))
2706 			DERRX(EX_SOFTWARE, "%s: opc = %p: still open",
2707 			      __func__, (void *)opc);
2708 
2709 		if ((pnd->pnd_flags & PND_BUSY) ||
2710 		       !TAILQ_EMPTY(&pnd->pnd_pcq))
2711 			DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
2712 			      __func__, (void *)opc);
2713 #endif
2714 
2715 		/*
2716 		 * Send the FORGET message
2717 		 *
2718 		 * ps_new_msg() is called with NULL creds, which will
2719 		 * be interpreted as FUSE superuser. This is obviously
2720 		 * fine since we operate with kernel creds here.
2721 		 */
2722 		pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
2723 			      sizeof(*ffi), NULL);
2724 		ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
2725 		ffi->nlookup = pnd->pnd_nlookup;
2726 
2727 		/*
2728 		 * No reply is expected, pm is freed in xchg_msg
2729 		 */
2730 		(void)xchg_msg(pu, (puffs_cookie_t)pn,
2731 			       pm, UNSPEC_REPLY_LEN, no_reply);
2732 
2733 		parent_pn = pnd->pnd_parent;
2734 
2735 		perfuse_destroy_pn(pn);
2736 
2737 		pn = parent_pn;
2738 	}
2739 
2740 	return 0;
2741 }
2742 
2743 int
2744 perfuse_node_inactive(pu, opc)
2745 	struct puffs_usermount *pu;
2746 	puffs_cookie_t opc;
2747 {
2748 	struct perfuse_state *ps;
2749 	struct perfuse_node_data *pnd;
2750 
2751 	ps = puffs_getspecific(pu);
2752 	pnd = PERFUSE_NODE_DATA(opc);
2753 
2754 	if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED)))
2755 		return 0;
2756 
2757 	/*
2758 	 * Make sure all operation are finished
2759 	 * There can be an ongoing write. Other
2760 	 * operation wait for all data before
2761 	 * the close/inactive.
2762 	 */
2763 	while (pnd->pnd_flags & PND_INWRITE)
2764 		requeue_request(pu, opc, PCQ_AFTERWRITE);
2765 
2766 	/*
2767 	 * The inactive operation may be cancelled.
2768 	 * If no open is in progress, set PND_INOPEN
2769 	 * so that a new open will be queued.
2770 	 */
2771 	if (pnd->pnd_flags & PND_INOPEN)
2772 		return 0;
2773 
2774 	pnd->pnd_flags |= PND_INOPEN;
2775 
2776 	/*
2777 	 * Sync data
2778 	 */
2779 	if (pnd->pnd_flags & PND_DIRTY)
2780 		(void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0);
2781 
2782 	/*
2783 	 * Close handles
2784 	 */
2785 	if (pnd->pnd_flags & PND_WFH)
2786 		(void)perfuse_node_close_common(pu, opc, FWRITE);
2787 
2788 	if (pnd->pnd_flags & PND_RFH)
2789 		(void)perfuse_node_close_common(pu, opc, FREAD);
2790 
2791 	/*
2792 	 * This will cause a reclaim to be sent
2793 	 */
2794 	if (pnd->pnd_flags & PND_REMOVED)
2795 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
2796 
2797 	/*
2798 	 * Schedule awaiting operations
2799 	 */
2800 	pnd->pnd_flags &= ~PND_INOPEN;
2801 	(void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
2802 
2803 	return 0;
2804 }
2805 
2806 
2807 /* ARGSUSED0 */
2808 int
2809 perfuse_node_print(pu, opc)
2810 	struct puffs_usermount *pu;
2811 	puffs_cookie_t opc;
2812 {
2813 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2814 	return 0;
2815 }
2816 
2817 /* ARGSUSED0 */
2818 int
2819 perfuse_node_pathconf(pu, opc, name, retval)
2820 	struct puffs_usermount *pu;
2821 	puffs_cookie_t opc;
2822 	int name;
2823 	int *retval;
2824 {
2825 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2826 	return 0;
2827 }
2828 
2829 int
2830 perfuse_node_advlock(pu, opc, id, op, fl, flags)
2831 	struct puffs_usermount *pu;
2832 	puffs_cookie_t opc;
2833 	void *id;
2834 	int op;
2835 	struct flock *fl;
2836 	int flags;
2837 {
2838 	struct perfuse_state *ps;
2839 	int fop;
2840 	perfuse_msg_t *pm;
2841 	uint64_t fh;
2842 	struct fuse_lk_in *fli;
2843 	struct fuse_out_header *foh;
2844 	struct fuse_lk_out *flo;
2845 	uint32_t owner;
2846 	size_t len;
2847 	int error;
2848 
2849 	/*
2850 	 * Make sure we do have a filehandle, as the FUSE filesystem
2851 	 * expect one. E.g.: if we provide none, GlusterFS logs an error
2852 	 * "0-glusterfs-fuse: xl is NULL"
2853 	 *
2854 	 * We need the read file handle if the file is open read only,
2855 	 * in order to support shared locks on read-only files.
2856 	 * NB: The kernel always sends advlock for read-only
2857 	 * files at exit time when the process used lock, see
2858 	 * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK
2859 	 */
2860 	if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH)
2861 		return EBADF;
2862 
2863 	ps = puffs_getspecific(pu);
2864 
2865 	if (op == F_GETLK)
2866 		fop = FUSE_GETLK;
2867 	else
2868 		fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
2869 
2870 	/*
2871 	 * XXX ps_new_msg() is called with NULL creds, which will
2872 	 * be interpreted as FUSE superuser. We have no way to
2873 	 * know the requesting process' credential, but since advlock()
2874 	 * is supposed to operate on a file that has been open(),
2875 	 * permission should have already been checked at open() time.
2876 	 */
2877 	pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
2878 	fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
2879 	fli->fh = fh;
2880 	fli->owner = (uint64_t)(vaddr_t)id;
2881 	fli->lk.start = fl->l_start;
2882 	fli->lk.end = fl->l_start + fl->l_len;
2883 	fli->lk.type = fl->l_type;
2884 	fli->lk.pid = fl->l_pid;
2885 	fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
2886 
2887 	owner = (uint64_t)(vaddr_t)id;
2888 
2889 #ifdef PERFUSE_DEBUG
2890 	if (perfuse_diagflags & PDF_FH)
2891 		DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2892 			__func__, (void *)opc,
2893 			PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh);
2894 #endif
2895 
2896 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2897 		goto out;
2898 
2899 	foh = GET_OUTHDR(ps, pm);
2900 	len = foh->len - sizeof(*foh);
2901 
2902 	/*
2903 	 * Save or clear the lock
2904 	 */
2905 	switch (op) {
2906 	case F_GETLK:
2907 		if (len != sizeof(*flo))
2908 			DERRX(EX_SOFTWARE,
2909 			      "%s: Unexpected lock reply len %zd",
2910 			      __func__, len);
2911 
2912 		flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
2913 		fl->l_start = flo->lk.start;
2914 		fl->l_len = flo->lk.end - flo->lk.start;
2915 		fl->l_pid = flo->lk.pid;
2916 		fl->l_type = flo->lk.type;
2917 		fl->l_whence = SEEK_SET;	/* libfuse hardcodes it */
2918 
2919 		PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
2920 		break;
2921 	case F_UNLCK:
2922 		owner = 0;
2923 		/* FALLTHROUGH */
2924 	case F_SETLK:
2925 		/* FALLTHROUGH */
2926 	case F_SETLKW:
2927 		if (error != 0)
2928 			PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner;
2929 
2930 		if (len != 0)
2931 			DERRX(EX_SOFTWARE,
2932 			      "%s: Unexpected unlock reply len %zd",
2933 			      __func__, len);
2934 
2935 		break;
2936 	default:
2937 		DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op);
2938 		break;
2939 	}
2940 
2941 out:
2942 	ps->ps_destroy_msg(pm);
2943 
2944 	return error;
2945 }
2946 
2947 int
2948 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag)
2949 	struct puffs_usermount *pu;
2950 	puffs_cookie_t opc;
2951 	uint8_t *buf;
2952 	off_t offset;
2953 	size_t *resid;
2954 	const struct puffs_cred *pcr;
2955 	int ioflag;
2956 {
2957 	struct perfuse_state *ps;
2958 	struct perfuse_node_data *pnd;
2959 	const struct vattr *vap;
2960 	perfuse_msg_t *pm;
2961 	struct fuse_read_in *fri;
2962 	struct fuse_out_header *foh;
2963 	size_t readen;
2964 	int error;
2965 
2966 	ps = puffs_getspecific(pu);
2967 	pnd = PERFUSE_NODE_DATA(opc);
2968 	vap = puffs_pn_getvap((struct puffs_node *)opc);
2969 	pm = NULL;
2970 
2971 	/*
2972 	 * NetBSD turns that into a getdents(2) output
2973 	 * We just do a EISDIR as this feature is of little use.
2974 	 */
2975 	if (vap->va_type == VDIR)
2976 		return EISDIR;
2977 
2978 	if ((u_quad_t)offset + *resid > vap->va_size)
2979 		DWARNX("%s %p read %lld@%zu beyond EOF %" PRIu64 "\n",
2980 		       __func__, (void *)opc, (long long)offset,
2981 		       *resid, vap->va_size);
2982 
2983 	do {
2984 		size_t max_read;
2985 
2986 		max_read = ps->ps_max_readahead - sizeof(*foh);
2987 		/*
2988 		 * flags may be set to FUSE_READ_LOCKOWNER
2989 		 * if lock_owner is provided.
2990 		 */
2991 		pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
2992 		fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2993 		fri->fh = perfuse_get_fh(opc, FREAD);
2994 		fri->offset = offset;
2995 		fri->size = (uint32_t)MIN(*resid, max_read);
2996 		fri->read_flags = 0; /* XXX Unused by libfuse? */
2997 		fri->lock_owner = pnd->pnd_lock_owner;
2998 		fri->flags = 0;
2999 		fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
3000 
3001 #ifdef PERFUSE_DEBUG
3002 	if (perfuse_diagflags & PDF_FH)
3003 		DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
3004 			__func__, (void *)opc, pnd->pnd_nodeid, fri->fh);
3005 #endif
3006 		error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
3007 
3008 		if (error  != 0)
3009 			goto out;
3010 
3011 		foh = GET_OUTHDR(ps, pm);
3012 		readen = foh->len - sizeof(*foh);
3013 
3014 #ifdef PERFUSE_DEBUG
3015 		if (readen > *resid)
3016 			DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd",
3017 			      __func__, readen);
3018 #endif
3019 
3020 		(void)memcpy(buf,  _GET_OUTPAYLOAD(ps, pm, char *), readen);
3021 
3022 		buf += readen;
3023 		offset += readen;
3024 		*resid -= readen;
3025 
3026 		ps->ps_destroy_msg(pm);
3027 		pm = NULL;
3028 	} while ((*resid != 0) && (readen != 0));
3029 
3030 	if (ioflag & (IO_SYNC|IO_DSYNC))
3031 		ps->ps_syncreads++;
3032 	else
3033 		ps->ps_asyncreads++;
3034 
3035 out:
3036 	if (pm != NULL)
3037 		ps->ps_destroy_msg(pm);
3038 
3039 	return error;
3040 }
3041 
3042 int
3043 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag)
3044 	struct puffs_usermount *pu;
3045 	puffs_cookie_t opc;
3046 	uint8_t *buf;
3047 	off_t offset;
3048 	size_t *resid;
3049 	const struct puffs_cred *pcr;
3050 	int ioflag;
3051 {
3052 	struct perfuse_state *ps;
3053 	struct perfuse_node_data *pnd;
3054 	struct vattr *vap;
3055 	perfuse_msg_t *pm;
3056 	struct fuse_write_in *fwi;
3057 	struct fuse_write_out *fwo;
3058 	size_t data_len;
3059 	size_t payload_len;
3060 	size_t written;
3061 	int inresize;
3062 	int error;
3063 
3064 	ps = puffs_getspecific(pu);
3065 	pnd = PERFUSE_NODE_DATA(opc);
3066 	vap = puffs_pn_getvap((struct puffs_node *)opc);
3067 	written = 0;
3068 	inresize = 0;
3069 	pm = NULL;
3070 
3071 	if (vap->va_type == VDIR)
3072 		return EISDIR;
3073 
3074 	/*
3075 	 * We need to queue write requests in order to avoid
3076 	 * dequeueing PCQ_AFTERWRITE when there are pending writes.
3077 	 */
3078 	while (pnd->pnd_flags & PND_INWRITE)
3079 		requeue_request(pu, opc, PCQ_WRITE);
3080 	pnd->pnd_flags |= PND_INWRITE;
3081 
3082 	/*
3083 	 * Serialize size access, see comment in perfuse_node_setattr().
3084 	 */
3085 	if ((u_quad_t)offset + *resid > vap->va_size) {
3086 		while (pnd->pnd_flags & PND_INRESIZE)
3087 			requeue_request(pu, opc, PCQ_RESIZE);
3088 		pnd->pnd_flags |= PND_INRESIZE;
3089 		inresize = 1;
3090 	}
3091 
3092 	/*
3093 	 * append flag: re-read the file size so that
3094 	 * we get the latest value.
3095 	 */
3096 	if (ioflag & PUFFS_IO_APPEND) {
3097 		DWARNX("%s: PUFFS_IO_APPEND set, untested code", __func__);
3098 
3099 		if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0)
3100 			goto out;
3101 
3102 		offset = vap->va_size;
3103 	}
3104 
3105 	pm = NULL;
3106 
3107 #ifdef PERFUSE_DEBUG
3108 	if (perfuse_diagflags & PDF_RESIZE)
3109 		DPRINTF(">> %s %p %" PRIu64 "\n", __func__,
3110 			(void *)opc, vap->va_size);
3111 #endif
3112 
3113 	do {
3114 		size_t max_write;
3115 		/*
3116 		 * There is a writepage flag when data
3117 		 * is aligned to page size. Use it for
3118 		 * everything but the data after the last
3119 		 * page boundary.
3120 		 */
3121 		max_write = ps->ps_max_write - sizeof(*fwi);
3122 
3123 		data_len = MIN(*resid, max_write);
3124 		if (data_len > (size_t)sysconf(_SC_PAGESIZE))
3125 			data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1);
3126 
3127 		payload_len = data_len + sizeof(*fwi);
3128 
3129 		/*
3130 		 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
3131 		 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
3132 		 * write_flags is set to 1 for writepage.
3133 		 */
3134 		pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
3135 		fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
3136 		fwi->fh = perfuse_get_fh(opc, FWRITE);
3137 		fwi->offset = offset;
3138 		fwi->size = (uint32_t)data_len;
3139 		fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1;
3140 		fwi->lock_owner = pnd->pnd_lock_owner;
3141 		fwi->flags = 0;
3142 		fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
3143 		fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
3144 		(void)memcpy((fwi + 1), buf, data_len);
3145 
3146 
3147 #ifdef PERFUSE_DEBUG
3148 		if (perfuse_diagflags & PDF_FH)
3149 			DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
3150 				"fh = 0x%"PRIx64"\n", __func__,
3151 				(void *)opc, pnd->pnd_nodeid, fwi->fh);
3152 #endif
3153 		if ((error = xchg_msg(pu, opc, pm,
3154 				      sizeof(*fwo), wait_reply)) != 0)
3155 			goto out;
3156 
3157 		fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
3158 		written = fwo->size;
3159 #ifdef PERFUSE_DEBUG
3160 		if (written > *resid)
3161 			DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd",
3162 			      __func__, written);
3163 #endif
3164 		*resid -= written;
3165 		offset += written;
3166 		buf += written;
3167 
3168 		ps->ps_destroy_msg(pm);
3169 		pm = NULL;
3170 	} while (*resid != 0);
3171 
3172 	/*
3173 	 * puffs_ops(3) says
3174 	 *  "everything must be written or an error will be generated"
3175 	 */
3176 	if (*resid != 0)
3177 		error = EFBIG;
3178 
3179 #ifdef PERFUSE_DEBUG
3180 	if (perfuse_diagflags & PDF_RESIZE) {
3181 		if (offset > (off_t)vap->va_size)
3182 			DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__,
3183 				(void *)opc, vap->va_size, (long long)offset);
3184 		else
3185 			DPRINTF("<< %s %p \n", __func__, (void *)opc);
3186 	}
3187 #endif
3188 
3189 	/*
3190 	 * Update file size if we wrote beyond the end
3191 	 */
3192 	if (offset > (off_t)vap->va_size)
3193 		vap->va_size = offset;
3194 
3195 	if (inresize) {
3196 #ifdef PERFUSE_DEBUG
3197 		if (!(pnd->pnd_flags & PND_INRESIZE))
3198 			DERRX(EX_SOFTWARE, "file write grow without resize");
3199 #endif
3200 		pnd->pnd_flags &= ~PND_INRESIZE;
3201 		(void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
3202 	}
3203 
3204 
3205 	/*
3206 	 * Statistics
3207 	 */
3208 	if (ioflag & (IO_SYNC|IO_DSYNC))
3209 		ps->ps_syncwrites++;
3210 	else
3211 		ps->ps_asyncwrites++;
3212 
3213 	/*
3214 	 * Remember to sync the file
3215 	 */
3216 	pnd->pnd_flags |= PND_DIRTY;
3217 
3218 #ifdef PERFUSE_DEBUG
3219 	if (perfuse_diagflags & PDF_SYNC)
3220 		DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
3221 			__func__, (void*)opc, perfuse_node_path(opc));
3222 #endif
3223 out:
3224 	if (pm != NULL)
3225 		ps->ps_destroy_msg(pm);
3226 
3227 	/*
3228 	 * If there are no more queued write, we can resume
3229 	 * an operation awaiting write completion.
3230 	 */
3231 	pnd->pnd_flags &= ~PND_INWRITE;
3232 	if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0)
3233 		(void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL);
3234 
3235 	return error;
3236 }
3237 
3238 /* ARGSUSED0 */
3239 void
3240 perfuse_cache_write(pu, opc, size, runs)
3241 	struct puffs_usermount *pu;
3242 	puffs_cookie_t opc;
3243 	size_t size;
3244 	struct puffs_cacherun *runs;
3245 {
3246 	return;
3247 }
3248 
3249 /* ARGSUSED4 */
3250 int
3251 perfuse_node_getextattr(pu, opc, attrns, attrname, attrsize, attr, resid, pcr)
3252 	struct puffs_usermount *pu;
3253 	puffs_cookie_t opc;
3254 	int attrns;
3255 	const char *attrname;
3256 	size_t *attrsize;
3257 	uint8_t *attr;
3258 	size_t *resid;
3259 	const struct puffs_cred *pcr;
3260 {
3261 	struct perfuse_state *ps;
3262 	char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3263 	perfuse_msg_t *pm;
3264 	struct fuse_getxattr_in *fgi;
3265 	struct fuse_getxattr_out *fgo;
3266 	struct fuse_out_header *foh;
3267 	size_t attrnamelen;
3268 	size_t len;
3269 	char *np;
3270 	int error;
3271 
3272 	ps = puffs_getspecific(pu);
3273 	attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3274 	attrnamelen = strlen(attrname) + 1;
3275 	len = sizeof(*fgi) + attrnamelen;
3276 
3277 	pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr);
3278 	fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3279 	fgi->size = (unsigned int)((resid != NULL) ? *resid : 0);
3280 	np = (char *)(void *)(fgi + 1);
3281 	(void)strlcpy(np, attrname, attrnamelen);
3282 
3283 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3284 		goto out;
3285 
3286 	/*
3287 	 * We just get fuse_getattr_out with list size if we requested
3288 	 * a null size.
3289 	 */
3290 	if (resid == NULL) {
3291 		fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3292 
3293 		if (attrsize != NULL)
3294 			*attrsize = fgo->size;
3295 
3296 		goto out;
3297 	}
3298 
3299 	/*
3300 	 * And with a non null requested size, we get the list just
3301 	 * after the header
3302 	 */
3303 	foh = GET_OUTHDR(ps, pm);
3304 	np = (char *)(void *)(foh + 1);
3305 
3306 	if (resid != NULL) {
3307 		len = MAX(foh->len - sizeof(*foh), *resid);
3308 		(void)memcpy(attr, np, len);
3309 		*resid -= len;
3310 	}
3311 
3312 out:
3313 	ps->ps_destroy_msg(pm);
3314 
3315 	return error;
3316 }
3317 
3318 int
3319 perfuse_node_setextattr(pu, opc, attrns, attrname, attr, resid, pcr)
3320 	struct puffs_usermount *pu;
3321 	puffs_cookie_t opc;
3322 	int attrns;
3323 	const char *attrname;
3324 	uint8_t *attr;
3325 	size_t *resid;
3326 	const struct puffs_cred *pcr;
3327 {
3328 	struct perfuse_state *ps;
3329 	char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3330 	perfuse_msg_t *pm;
3331 	struct fuse_setxattr_in *fsi;
3332 	size_t attrnamelen;
3333 	size_t len;
3334 	char *np;
3335 	int error;
3336 
3337 	ps = puffs_getspecific(pu);
3338 	attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3339 	attrnamelen = strlen(attrname) + 1;
3340 	len = sizeof(*fsi) + attrnamelen + *resid;
3341 
3342 	pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr);
3343 	fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in);
3344 	fsi->size = (unsigned int)*resid;
3345 	fsi->flags = 0;
3346 	np = (char *)(void *)(fsi + 1);
3347 	(void)strlcpy(np, attrname, attrnamelen);
3348 	np += attrnamelen;
3349 	(void)memcpy(np, (char *)attr, *resid);
3350 
3351 	if ((error = xchg_msg(pu, opc, pm,
3352 			      NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
3353 		goto out;
3354 
3355 	*resid = 0;
3356 out:
3357 	ps->ps_destroy_msg(pm);
3358 
3359 	return error;
3360 }
3361 
3362 /* ARGSUSED2 */
3363 int
3364 perfuse_node_listextattr(pu, opc, attrns, attrsize, attrs, resid, flag, pcr)
3365 	struct puffs_usermount *pu;
3366 	puffs_cookie_t opc;
3367 	int attrns;
3368 	size_t *attrsize;
3369 	uint8_t *attrs;
3370 	size_t *resid;
3371 	int flag;
3372 	const struct puffs_cred *pcr;
3373 {
3374 	struct perfuse_state *ps;
3375 	perfuse_msg_t *pm;
3376 	struct fuse_getxattr_in *fgi;
3377 	struct fuse_getxattr_out *fgo;
3378 	struct fuse_out_header *foh;
3379 	char *np;
3380 	size_t len, puffs_len;
3381 	int error;
3382 
3383 	ps = puffs_getspecific(pu);
3384 	len = sizeof(*fgi);
3385 
3386 	pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr);
3387 	fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3388 	if (resid != NULL)
3389 		fgi->size = (unsigned int)*resid;
3390 	else
3391 		fgi->size = 0;
3392 
3393 	if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3394 		goto out;
3395 
3396 	/*
3397 	 * We just get fuse_getattr_out with list size if we requested
3398 	 * a null size.
3399 	 */
3400 	if (resid == NULL) {
3401 		fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3402 
3403 		if (attrsize != NULL)
3404 			*attrsize = fgo->size;
3405 
3406 		goto out;
3407 	}
3408 
3409 	/*
3410 	 * And with a non null requested size, we get the list just
3411 	 * after the header
3412 	 */
3413 	foh = GET_OUTHDR(ps, pm);
3414 	np = (char *)(void *)(foh + 1);
3415 	puffs_len = foh->len - sizeof(*foh);
3416 
3417 	if (attrs != NULL) {
3418 #ifdef PUFFS_EXTATTR_LIST_LENPREFIX
3419 		/*
3420 		 * Convert the FUSE reply to length prefixed strings
3421 		 * if this is what the kernel wants.
3422 		 */
3423 		if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) {
3424 			size_t i, attrlen;
3425 
3426 			for (i = 0; i < puffs_len; i += attrlen + 1) {
3427 				attrlen = strlen(np + i);
3428 				(void)memmove(np + i + 1, np + i, attrlen);
3429 				*(np + i) = (uint8_t)attrlen;
3430 			}
3431 		}
3432 #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */
3433 		(void)memcpy(attrs, np, puffs_len);
3434 		*resid -= puffs_len;
3435 	}
3436 
3437 	if (attrsize != NULL)
3438 		*attrsize = puffs_len;
3439 
3440 out:
3441 	ps->ps_destroy_msg(pm);
3442 
3443 	return error;
3444 }
3445 
3446 int
3447 perfuse_node_deleteextattr(pu, opc, attrns, attrname, pcr)
3448 	struct puffs_usermount *pu;
3449 	puffs_cookie_t opc;
3450 	int attrns;
3451 	const char *attrname;
3452 	const struct puffs_cred *pcr;
3453 {
3454 	struct perfuse_state *ps;
3455 	char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3456 	perfuse_msg_t *pm;
3457 	size_t attrnamelen;
3458 	char *np;
3459 	int error;
3460 
3461 	ps = puffs_getspecific(pu);
3462 	attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3463 	attrnamelen = strlen(attrname) + 1;
3464 
3465 	pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr);
3466 	np = _GET_INPAYLOAD(ps, pm, char *);
3467 	(void)strlcpy(np, attrname, attrnamelen);
3468 
3469 	error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
3470 
3471 	ps->ps_destroy_msg(pm);
3472 
3473 	return error;
3474 }
3475