Home | History | Annotate | Line # | Download | only in libperfuse
ops.c revision 1.6
      1 /*  $NetBSD: ops.c,v 1.6 2010/09/02 08:58:06 manu Exp $ */
      2 
      3 /*-
      4  *  Copyright (c) 2010 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/vnode.h>
     38 #include <sys/socket.h>
     39 #include <machine/vmparam.h>
     40 
     41 #include "perfuse_priv.h"
     42 #include "fuse.h"
     43 
     44 static int no_access(puffs_cookie_t, const struct puffs_cred *, mode_t);
     45 static void fuse_attr_to_vap(struct perfuse_state *,
     46     struct vattr *, struct fuse_attr *);
     47 static int node_lookup_dir_nodot(struct puffs_usermount *,
     48     puffs_cookie_t, char *, size_t, struct puffs_node **);
     49 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,
     50     const char*, struct puffs_node **);
     51 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
     52     struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *);
     53 static const char *basename_r(const char *);
     54 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
     55     struct fuse_dirent *, size_t);
     56 static int readdir_buffered(struct perfuse_state *, puffs_cookie_t,
     57     struct dirent *, off_t *, size_t *, const struct puffs_cred *,
     58     int *, off_t *, size_t *);
     59 static void requeue_request(struct puffs_usermount *,
     60     puffs_cookie_t opc, enum perfuse_qtype);
     61 static void dequeue_requests(struct perfuse_state *,
     62      puffs_cookie_t opc, enum perfuse_qtype, int);
     63 #define DEQUEUE_ALL 0
     64 
     65 /*
     66  *  From <sys/vnode>, inside #ifdef _KERNEL section
     67  */
     68 #define IO_SYNC		(0x40|IO_DSYNC)
     69 #define IO_DSYNC	0x00200
     70 #define IO_DIRECT	0x02000
     71 
     72 /*
     73  *  From <fcntl>, inside #ifdef _KERNEL section
     74  */
     75 #define F_WAIT		0x010
     76 #define F_FLOCK		0x020
     77 
     78 /*
     79  * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h
     80  */
     81 const enum vtype iftovt_tab[16] = {
     82 	VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
     83         VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
     84 };
     85 const int vttoif_tab[9] = {
     86 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
     87         S_IFSOCK, S_IFIFO, S_IFMT,
     88 };
     89 
     90 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
     91 #define VTTOIF(indx) (vttoif_tab[(int)(indx)])
     92 
     93 
     94 static int
     95 no_access(opc, pcr, mode)
     96 	puffs_cookie_t opc;
     97 	const struct puffs_cred *pcr;
     98 	mode_t mode;
     99 {
    100 	struct puffs_node *pn;
    101 	struct vattr *va;
    102 
    103 	pn = (struct puffs_node *)opc;
    104 	va = puffs_pn_getvap(pn);
    105 
    106 	return puffs_access(va->va_type, va->va_mode,
    107 			    va->va_uid, va->va_gid,
    108 			    mode, pcr);
    109 }
    110 
    111 static void
    112 fuse_attr_to_vap(ps, vap, fa)
    113 	struct perfuse_state *ps;
    114 	struct vattr *vap;
    115 	struct fuse_attr *fa;
    116 {
    117 	vap->va_type = IFTOVT(fa->mode);
    118 	vap->va_mode = fa->mode;
    119 	vap->va_nlink = fa->nlink;
    120 	vap->va_uid = fa->uid;
    121 	vap->va_gid = fa->gid;
    122 	vap->va_fsid = ps->ps_fsid;
    123 	vap->va_fileid = fa->ino;
    124 	vap->va_size = fa->size;
    125 	vap->va_blocksize = fa->blksize;
    126 	vap->va_atime.tv_sec = (time_t)fa->atime;
    127 	vap->va_atime.tv_nsec = (long) fa->atimensec;
    128 	vap->va_mtime.tv_sec = (time_t)fa->mtime;
    129 	vap->va_mtime.tv_nsec = (long)fa->mtimensec;
    130 	vap->va_ctime.tv_sec = (time_t)fa->ctime;
    131 	vap->va_ctime.tv_nsec = (long)fa->ctimensec;
    132 	vap->va_birthtime.tv_sec = 0;
    133 	vap->va_birthtime.tv_nsec = 0;
    134 	vap->va_gen = 0;
    135 	vap->va_flags = 0;
    136 	vap->va_rdev = fa->rdev;
    137 	vap->va_bytes = fa->size;
    138 	vap->va_filerev = 0;
    139 	vap->va_vaflags = 0;
    140 
    141 	if (vap->va_blocksize == 0)
    142 		vap->va_blocksize = DEV_BSIZE;
    143 
    144 	if (vap->va_size == (size_t)-1) /* XXX */
    145 		vap->va_size = 0;
    146 
    147 	return;
    148 }
    149 
    150 
    151 /*
    152  * Lookup name in directory opc
    153  * We take special care of name being . or ..
    154  * These are returned by readdir and deserve tweaks.
    155  */
    156 static int
    157 node_lookup_dir_nodot(pu, opc, name, namelen, pnp)
    158 	struct puffs_usermount *pu;
    159 	puffs_cookie_t opc;
    160 	char *name;
    161 	size_t namelen;
    162 	struct puffs_node **pnp;
    163 {
    164 	char *path;
    165 	struct puffs_node *dpn = (struct puffs_node *)opc;
    166 	int error;
    167 
    168 	/*
    169 	 *  is easy as we already know it
    170 	 */
    171 	if (strncmp(name, ".", namelen) == 0) {
    172 		*pnp = (struct puffs_node *)opc;
    173 		return 0;
    174 	}
    175 
    176 	/*
    177 	 * For .. we just forget the name part
    178 	 */
    179 	if (strncmp(name, "..", namelen) == 0)
    180 		namelen = 0;
    181 
    182 	namelen = PNPLEN(dpn) + 1 + namelen + 1;
    183 	if ((path = malloc(namelen)) == NULL)
    184 		DERR(EX_OSERR, "malloc failed");
    185 	(void)snprintf(path, namelen, "%s/%s", (char *)PNPATH(dpn), name);
    186 
    187 	error = node_lookup_common(pu, opc, path, pnp);
    188 
    189 	free(path);
    190 
    191 	return error;
    192 }
    193 
    194 static int
    195 node_lookup_common(pu, opc, path, pnp)
    196 	struct puffs_usermount *pu;
    197 	puffs_cookie_t opc;
    198 	const char *path;
    199 	struct puffs_node **pnp;
    200 {
    201 	struct perfuse_state *ps;
    202 	perfuse_msg_t *pm;
    203 	struct fuse_entry_out *feo;
    204 	struct puffs_node *pn;
    205 	size_t len;
    206 	int error;
    207 
    208 	ps = puffs_getspecific(pu);
    209 
    210 	path = basename_r(path);
    211 	len = strlen(path) + 1;
    212 
    213 	pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, NULL);
    214 	(void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len);
    215 
    216 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*feo))) != 0)
    217 		goto out;
    218 
    219 	feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
    220 
    221 	pn = perfuse_new_pn(pu, opc);
    222 	PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
    223 
    224 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
    225 
    226 	if (pnp != NULL)
    227 		*pnp = pn;
    228 
    229 out:
    230 	ps->ps_destroy_msg(pm);
    231 
    232 	return error;
    233 }
    234 
    235 
    236 /*
    237  * Common final code for methods that create objects:
    238  * perfuse_node_mkdir
    239  * perfuse_node_mknod
    240  * perfuse_node_symlink
    241  */
    242 static int
    243 node_mk_common(pu, opc, pni, pcn, pm)
    244 	struct puffs_usermount *pu;
    245 	puffs_cookie_t opc;
    246 	struct puffs_newinfo *pni;
    247 	const struct puffs_cn *pcn;
    248 	perfuse_msg_t *pm;
    249 {
    250 	struct perfuse_state *ps;
    251 	struct puffs_node *pn;
    252 	struct fuse_entry_out *feo;
    253 	struct fuse_setattr_in *fsi;
    254 	int error;
    255 
    256 	ps =  puffs_getspecific(pu);
    257 
    258 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*feo))) != 0)
    259 		goto out;
    260 
    261 	feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
    262 	if (feo->nodeid == PERFUSE_UNKNOWN_INO)
    263 		DERRX(EX_SOFTWARE, "%s: no ino", __func__);
    264 
    265 	pn = perfuse_new_pn(pu, opc);
    266 	PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
    267 
    268 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
    269 	puffs_newinfo_setcookie(pni, pn);
    270 	ps->ps_destroy_msg(pm);
    271 
    272 	/*
    273 	 * Set owner and group
    274 	 */
    275 	(void)puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid);
    276 	(void)puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid);
    277 
    278 	pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn,
    279 			    FUSE_SETATTR, sizeof(*fsi), NULL);
    280 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
    281 	fsi->uid = pn->pn_va.va_uid;
    282 	fsi->gid = pn->pn_va.va_gid;
    283 	fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID;
    284 
    285 	/*
    286 	 * A fuse_attr_out is returned, but we ignore it.
    287 	 */
    288 	error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out));
    289 
    290 out:
    291 	ps->ps_destroy_msg(pm);
    292 
    293 	return error;
    294 }
    295 
    296 static const char *
    297 basename_r(string)
    298 	const char *string;
    299 {
    300 	char *result;
    301 
    302 	if ((result = rindex(string, '/')) == NULL)
    303 		return string;
    304 
    305 	/*
    306 	 * We are finished if this is not a trailing /
    307 	 */
    308 	if (result[1] != '\0')
    309 		return result + 1;
    310 
    311 
    312 	/*
    313 	 * Go back until we found something else than a /
    314 	 */
    315 	while (result != string) {
    316 		result--;
    317 		if (result[0] != '/')
    318 			break;
    319 	}
    320 
    321 	if (result == string)
    322 		return string;
    323 
    324 	if ((result = rindex(string, '/')) == NULL)
    325 		return string;
    326 
    327 	return result + 1;
    328 
    329 }
    330 
    331 static ssize_t
    332 fuse_to_dirent(pu, opc, fd, fd_len)
    333 	struct puffs_usermount *pu;
    334 	puffs_cookie_t opc;
    335 	struct fuse_dirent *fd;
    336 	size_t fd_len;
    337 {
    338 	struct dirent *dents;
    339 	size_t dents_len;
    340 	ssize_t written;
    341 	uint64_t fd_offset;
    342 	struct fuse_dirent *fd_base;
    343 	size_t len;
    344 
    345 	fd_base = fd;
    346 	fd_offset = 0;
    347 	written = 0;
    348 	dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
    349 	dents_len = PERFUSE_NODE_DATA(opc)->pnd_dirent_len;
    350 
    351 	do {
    352 		char *ndp;
    353 		size_t reclen;
    354 
    355 		reclen = _DIRENT_RECLEN(dents, fd->namelen);
    356 
    357 		/*
    358 		 * Check we do not overflow the output buffer
    359 		 * struct fuse_dirent is bigger than struct dirent,
    360 		 * so we should always use fd_len and never reallocate
    361 		 * later.
    362 		 * If we have to reallocate,try to double the buffer
    363 		 * each time so that we do not have to do it too often.
    364 		 */
    365 		if (written + reclen > dents_len) {
    366 			if (dents_len == 0)
    367 				dents_len = fd_len;
    368 			else
    369 				dents_len =
    370 				   MAX(2 * dents_len, written + reclen);
    371 
    372 			dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
    373 			if ((dents = realloc(dents, dents_len)) == NULL)
    374 				DERR(EX_OSERR, "malloc failed");
    375 
    376 			PERFUSE_NODE_DATA(opc)->pnd_dirent = dents;
    377 			PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len;
    378 
    379 			/*
    380 			 * (void *) for delint
    381 			 */
    382 			ndp = (char *)(void *)dents + written;
    383 			dents = (struct dirent *)(void *)ndp;
    384 		}
    385 
    386 
    387 
    388 		/*
    389 		 * Filesystem was mounted without -o use_ino
    390 		 * Perform a lookup to find it.
    391 		 * XXX still broken
    392 		 */
    393 		if (fd->ino == PERFUSE_UNKNOWN_INO) {
    394 			struct puffs_node *pn;
    395 
    396 			if (node_lookup_dir_nodot(pu, opc, fd->name,
    397 						  fd->namelen, &pn) != 0)
    398 				DERRX(EX_SOFTWARE,
    399 				     "node_lookup_dir_nodot failed");
    400 
    401 			fd->ino = PERFUSE_NODE_DATA(pn)->pnd_ino;
    402 		}
    403 
    404 		dents->d_fileno = fd->ino;
    405 		dents->d_reclen = (unsigned short)reclen;
    406 		dents->d_namlen = fd->namelen;
    407 		dents->d_type = fd->type;
    408 		strlcpy(dents->d_name, fd->name, fd->namelen + 1);
    409 
    410 #ifdef PERFUSE_DEBUG
    411 		if (perfuse_diagflags & PDF_READDIR)
    412 			DPRINTF("%s: translated \"%s\" ino = %"PRId64"\n",
    413 				__func__, dents->d_name, dents->d_fileno);
    414 #endif
    415 
    416 		dents = _DIRENT_NEXT(dents);
    417 		written += reclen;
    418 
    419 		/*
    420 		 * Move to the next record.
    421 		 * fd->off seems unreliable, for instance, flusterfs
    422 		 * does not clear the unused bits, and we get
    423 		 * 0xffffffffb9b95040 instead of just 0x40. Use
    424 		 * record alignement instead.
    425 		 */
    426 		len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
    427 #ifdef PERFUSE_DEBUG
    428 		if (perfuse_diagflags & PDF_READDIR)
    429 			DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" "
    430 				"length = %zd/0x%zx. "
    431 				"next record at %"PRId64"/0x%"PRIx64" "
    432 				"max %zd/0x%zx\n",
    433 				__func__, fd_offset, fd_offset, len, len,
    434 				fd_offset + len, fd_offset + len,
    435 				fd_len, fd_len);
    436 #endif
    437 		fd_offset += len;
    438 
    439 		/*
    440 		 * Check if next record is still within the packet
    441 		 * If it is not, we reached the end of the buffer.
    442 		 */
    443 		if (fd_offset >= fd_len)
    444 			break;
    445 
    446 		/*
    447 		 * (void *) for delint
    448 		 */
    449 		ndp = (char *)(void *)fd_base + (size_t)fd_offset;
    450 		fd = (struct fuse_dirent *)(void *)ndp;
    451 
    452 	} while (1 /* CONSTCOND */);
    453 
    454 	/*
    455 	 * Adjust the dirent output length
    456 	 */
    457 	if (written != -1)
    458 		PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written;
    459 
    460 	return written;
    461 }
    462 
    463 /* ARGSUSED0 */
    464 static int
    465 readdir_buffered(ps, opc, dent, readoff,
    466 		     reslen, pcr, eofflag, cookies, ncookies)
    467 	struct perfuse_state *ps;
    468 	puffs_cookie_t opc;
    469 	struct dirent *dent;
    470 	off_t *readoff;
    471 	size_t *reslen;
    472 	const struct puffs_cred *pcr;
    473 	int *eofflag;
    474 	off_t *cookies;
    475 	size_t *ncookies;
    476 {
    477 	struct dirent *fromdent;
    478 	struct perfuse_node_data *pnd;
    479 	char *ndp;
    480 
    481 	pnd = PERFUSE_NODE_DATA(opc);
    482 
    483 	while (*readoff < pnd->pnd_dirent_len) {
    484 		/*
    485 		 * (void *) for delint
    486 		 */
    487 		ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff;
    488 		fromdent = (struct dirent *)(void *)ndp;
    489 
    490 		if (*reslen < _DIRENT_SIZE(fromdent))
    491 			break;
    492 
    493 		memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
    494 		*readoff += _DIRENT_SIZE(fromdent);
    495 		*reslen -= _DIRENT_SIZE(fromdent);
    496 
    497 		dent = _DIRENT_NEXT(dent);
    498 	}
    499 
    500 #ifdef PERFUSE_DEBUG
    501 	if (perfuse_diagflags & PDF_READDIR)
    502 		DPRINTF("%s: readoff = %"PRId64",  pnd->pnd_dirent_len = %zd\n",
    503 			__func__, *readoff, pnd->pnd_dirent_len);
    504 #endif
    505 	if (*readoff >=  pnd->pnd_dirent_len) {
    506 		free(pnd->pnd_dirent);
    507 		pnd->pnd_dirent = NULL;
    508 		pnd->pnd_dirent_len = 0;
    509 		*eofflag = 1;
    510 	}
    511 
    512 	return 0;
    513 }
    514 
    515 /* ARGSUSED0 */
    516 static void
    517 requeue_request(pu, opc, type)
    518 	struct puffs_usermount *pu;
    519 	puffs_cookie_t opc;
    520 	enum perfuse_qtype type;
    521 {
    522 	struct perfuse_cc_queue pcq;
    523 	struct perfuse_node_data *pnd;
    524 #ifdef PERFUSE_DEBUG
    525 	struct perfuse_state *ps;
    526 
    527 	ps = perfuse_getspecific(pu);
    528 #endif
    529 
    530 	/*
    531 	 * XXX Add a lock he day we go multithreaded
    532 	 */
    533 	pnd = PERFUSE_NODE_DATA(opc);
    534 	pcq.pcq_type = type;
    535 	pcq.pcq_cc = puffs_cc_getcc(pu);
    536 	TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next);
    537 
    538 #ifdef PERFUSE_DEBUG
    539 
    540 	if (perfuse_diagflags & PDF_REQUEUE)
    541 		DPRINTF("%s: REQUEUE opc = %p, pcc = %p\n",
    542 		       __func__, (void *)opc, pcq.pcq_cc);
    543 #endif
    544 
    545 	puffs_cc_yield(pcq.pcq_cc);
    546 	TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next);
    547 
    548 #ifdef PERFUSE_DEBUG
    549 	if (perfuse_diagflags & PDF_REQUEUE)
    550 		DPRINTF("%s: RESUME opc = %p, pcc = %p\n",
    551 		        __func__, (void *)opc, pcq.pcq_cc);
    552 #endif
    553 
    554 	return;
    555 }
    556 
    557 /* ARGSUSED0 */
    558 static void
    559 dequeue_requests(ps, opc, type, max)
    560 	struct perfuse_state *ps;
    561 	puffs_cookie_t opc;
    562 	enum perfuse_qtype type;
    563 	int max;
    564 {
    565 	struct perfuse_cc_queue *pcq;
    566 	struct perfuse_node_data *pnd;
    567 	int dequeued;
    568 
    569 	/*
    570 	 * XXX Add a lock he day we go multithreaded
    571 	 */
    572 	pnd = PERFUSE_NODE_DATA(opc);
    573 	dequeued = 0;
    574 	TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) {
    575 		if (pcq->pcq_type != type)
    576 			continue;
    577 
    578 #ifdef PERFUSE_DEBUG
    579 		if (perfuse_diagflags & PDF_REQUEUE)
    580 			DPRINTF("%s: SCHEDULE opc = %p, pcc = %p\n",
    581 				__func__, (void *)opc, pcq->pcq_cc);
    582 #endif
    583 		puffs_cc_schedule(pcq->pcq_cc);
    584 
    585 		if (++dequeued == max)
    586 			break;
    587 	}
    588 
    589 #ifdef PERFUSE_DEBUG
    590 	if (perfuse_diagflags & PDF_REQUEUE)
    591 		DPRINTF("%s: DONE  opc = %p\n", __func__, (void *)opc);
    592 #endif
    593 
    594 	return;
    595 }
    596 
    597 void
    598 perfuse_fs_init(pu)
    599 	struct puffs_usermount *pu;
    600 {
    601 	struct perfuse_state *ps;
    602 	perfuse_msg_t *pm;
    603 	struct fuse_init_in *fii;
    604 	struct fuse_init_out *fio;
    605 	int error;
    606 
    607 	ps = puffs_getspecific(pu);
    608 
    609         if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0)
    610                 DERR(EX_OSERR, "puffs_mount failed");
    611 
    612 	/*
    613 	 * Linux 2.6.34.1 sends theses flags:
    614 	 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC
    615 	 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK
    616 	 *
    617 	 * Linux also sets max_readahead at 32 pages (128 kB)
    618 	 */
    619 	pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL);
    620 	fii = GET_INPAYLOAD(ps, pm, fuse_init_in);
    621 	fii->major = FUSE_KERNEL_VERSION;
    622 	fii->minor = FUSE_KERNEL_MINOR_VERSION;
    623 	fii->max_readahead = 32 * PAGE_SIZE;
    624 	fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC);
    625 
    626 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fio))) != 0)
    627 		DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error);
    628 
    629 	fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out);
    630 	ps->ps_max_readahead = fio->max_readahead;
    631 	ps->ps_max_write = fio->max_write;
    632 
    633 	ps->ps_destroy_msg(pm);
    634 
    635 	return;
    636 }
    637 
    638 int
    639 perfuse_fs_unmount(pu, flags)
    640 	struct puffs_usermount *pu;
    641 	int flags;
    642 {
    643 	perfuse_msg_t *pm;
    644 	struct perfuse_state *ps;
    645 	puffs_cookie_t opc;
    646 	int error;
    647 
    648 	ps = puffs_getspecific(pu);
    649 
    650 	opc = (puffs_cookie_t)puffs_getroot(pu);
    651 	pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL);
    652 
    653 	if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) {
    654 		DWARN("unmount %s", ps->ps_target);
    655 		if (!(flags & MNT_FORCE))
    656 			goto out;
    657 	}
    658 
    659 	DPRINTF("%s unmounted, exit\n", ps->ps_target);
    660 
    661 	exit(0);
    662 out:
    663 	ps->ps_destroy_msg(pm);
    664 
    665 	return error;
    666 }
    667 
    668 int
    669 perfuse_fs_statvfs(pu, svfsb)
    670 	struct puffs_usermount *pu;
    671 	struct statvfs *svfsb;
    672 {
    673 	struct perfuse_state *ps;
    674 	perfuse_msg_t *pm;
    675 	puffs_cookie_t opc;
    676 	struct fuse_statfs_out *fso;
    677 	int error;
    678 
    679 	ps = puffs_getspecific(pu);
    680 	opc = (puffs_cookie_t)puffs_getroot(pu);
    681 	pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL);
    682 
    683 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fso))) != 0)
    684 		goto out;
    685 
    686 	fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out);
    687 	svfsb->f_flag = ps->ps_mountflags;
    688 	svfsb->f_bsize = fso->st.bsize;
    689 	svfsb->f_frsize = fso->st.frsize;
    690 	svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize;
    691 	svfsb->f_blocks = fso->st.blocks;
    692 	svfsb->f_bfree = fso->st.bfree;
    693 	svfsb->f_bavail = fso->st.bavail;
    694 	svfsb->f_bresvd = fso->st.bfree - fso->st.bavail;
    695 	svfsb->f_files = fso->st.files;
    696 	svfsb->f_ffree = fso->st.ffree;
    697 	svfsb->f_favail = fso->st.ffree;/* files not reserved for root */
    698 	svfsb->f_fresvd = 0;		/* files reserved for root */
    699 
    700 	svfsb->f_syncreads = ps->ps_syncreads;
    701 	svfsb->f_syncwrites = ps->ps_syncwrites;
    702 
    703 	svfsb->f_asyncreads = ps->ps_asyncreads;
    704 	svfsb->f_asyncwrites = ps->ps_asyncwrites;
    705 
    706 	svfsb->f_fsidx.__fsid_val[0] = (int32_t)ps->ps_fsid;
    707 	svfsb->f_fsidx.__fsid_val[1] = 0;
    708 	svfsb->f_fsid = ps->ps_fsid;
    709 	svfsb->f_namemax = MAXPATHLEN;	/* XXX */
    710 	svfsb->f_owner = ps->ps_owner_uid;
    711 
    712 	(void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN);
    713 
    714 	if (ps->ps_filesystemtype != NULL)
    715 		(void)strlcpy(svfsb->f_fstypename,
    716 			      ps->ps_filesystemtype, _VFS_NAMELEN);
    717 	else
    718 		(void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN);
    719 
    720 	if (ps->ps_source != NULL)
    721 		strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN);
    722 	else
    723 		strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN);
    724 out:
    725 	ps->ps_destroy_msg(pm);
    726 
    727 	return error;
    728 }
    729 
    730 int
    731 perfuse_fs_sync(pu, waitfor, pcr)
    732 	struct puffs_usermount *pu;
    733 	int waitfor;
    734 	const struct puffs_cred *pcr;
    735 {
    736 	/*
    737 	 * FUSE does not seem to have a FS sync callback.
    738 	 * Maybe do not even register this callback
    739 	 */
    740 	return puffs_fsnop_sync(pu, waitfor, pcr);
    741 }
    742 
    743 /* ARGSUSED0 */
    744 int
    745 perfuse_fs_fhtonode(pu, fid, fidsize, pni)
    746 	struct puffs_usermount *pu;
    747 	void *fid;
    748 	size_t fidsize;
    749 	struct puffs_newinfo *pni;
    750 {
    751 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
    752 	return 0;
    753 }
    754 
    755 /* ARGSUSED0 */
    756 int
    757 perfuse_fs_nodetofh(pu, cookie, fid, fidsize)
    758 	struct puffs_usermount *pu;
    759 	puffs_cookie_t cookie;
    760 	void *fid;
    761 	size_t *fidsize;
    762 {
    763 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
    764 	return 0;
    765 }
    766 
    767 #if 0
    768 /* ARGSUSED0 */
    769 void
    770 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname)
    771 	struct puffs_usermount *pu;
    772 	int cmd,
    773 	puffs_cookie_t *cookie;
    774 	int flags;
    775 	int namespace;
    776 	const char *attrname;
    777 {
    778 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
    779 	return 0;
    780 }
    781 #endif /* 0 */
    782 
    783 /* ARGSUSED0 */
    784 void
    785 perfuse_fs_suspend(pu, status)
    786 	struct puffs_usermount *pu;
    787 	int status;
    788 {
    789 	return;
    790 }
    791 
    792 
    793 
    794 int
    795 perfuse_node_lookup(pu, opc, pni, pcn)
    796 	struct puffs_usermount *pu;
    797 	puffs_cookie_t opc;
    798 	struct puffs_newinfo *pni;
    799 	const struct puffs_cn *pcn;
    800 {
    801 	struct puffs_node *pn;
    802 	int error;
    803 
    804 	/*
    805 	 * XXX This is borrowed from librefuse,
    806 	 * and __UNCONST is said to be fixed.
    807 	 */
    808         pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
    809         		       __UNCONST(&pcn->pcn_po_full));
    810 
    811 	if (pn == NULL) {
    812 		error = node_lookup_common(pu, opc, (char *)PCNPATH(pcn), &pn);
    813 		if (error != 0)
    814 			return error;
    815 	}
    816 
    817 	/*
    818 	 * If that node had a pending reclaim, wipe it out.
    819 	 */
    820 	PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED;
    821 
    822 	puffs_newinfo_setcookie(pni, pn);
    823 	puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
    824 	puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size);
    825 	puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev);
    826 
    827 	return 0;
    828 }
    829 
    830 int
    831 perfuse_node_create(pu, opc, pni, pcn, vap)
    832 	struct puffs_usermount *pu;
    833 	puffs_cookie_t opc;
    834 	struct puffs_newinfo *pni;
    835 	const struct puffs_cn *pcn;
    836 	const struct vattr *vap;
    837 {
    838 	perfuse_msg_t *pm;
    839 	struct perfuse_state *ps;
    840 	struct fuse_create_in *fci;
    841 	struct fuse_entry_out *feo;
    842 	struct fuse_open_out *foo;
    843 	struct puffs_node *pn;
    844 	const char *name;
    845 	size_t namelen;
    846 	size_t len;
    847 	int error;
    848 
    849 	/*
    850 	 * Create an object require -WX permission in the parent directory
    851 	 */
    852 	if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
    853 		return EACCES;
    854 
    855 	/*
    856 	 * If create is unimplemented: Check that it does not
    857 	 * already exists, and if not, do mknod and open
    858 	 */
    859 	ps = puffs_getspecific(pu);
    860 	if (ps->ps_flags & PS_NO_CREAT) {
    861 		error = node_lookup_common(pu, opc, (char*)PCNPATH(pcn), &pn);
    862 		if (error == 0)
    863 			return EEXIST;
    864 
    865 		error = perfuse_node_mknod(pu, opc, pni, pcn, vap);
    866 		if (error != 0)
    867 			return error;
    868 
    869 		error = perfuse_node_open(pu, opc, FREAD|FWRITE, pcn->pcn_cred);
    870 		if (error != 0)
    871 			return error;
    872 
    873 		return 0;
    874 	}
    875 
    876 	name = basename_r((char *)PCNPATH(pcn));
    877 	namelen = strlen(name) + 1;
    878 	len = sizeof(*fci) + namelen;
    879 
    880 	pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred);
    881 	fci = GET_INPAYLOAD(ps, pm, fuse_create_in);
    882 	fci->flags = 0; 	/* No flags seems available */
    883 	fci->mode = vap->va_mode;
    884 	fci->umask = 0; 	/* Seems unused bu libfuse */
    885 	(void)strlcpy((char*)(void *)(fci + 1), name, namelen);
    886 
    887 	len = sizeof(*feo) + sizeof(*foo);
    888 	if ((error = XCHG_MSG(ps, pu, pm, len)) != 0)
    889 		goto out;
    890 
    891 	feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
    892 	foo = (struct fuse_open_out *)(void *)(feo + 1);
    893 	if (feo->nodeid == PERFUSE_UNKNOWN_INO)
    894 		DERRX(EX_SOFTWARE, "%s: no ino", __func__);
    895 
    896 	/*
    897 	 * Save the file handle and inode in node private data
    898 	 * so that we can reuse it later
    899 	 */
    900 	pn = perfuse_new_pn(pu, opc);
    901 	perfuse_new_fh((puffs_cookie_t)pn, foo->fh);
    902 	PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
    903 
    904 	fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
    905 	puffs_newinfo_setcookie(pni, pn);
    906 
    907 out:
    908 	ps->ps_destroy_msg(pm);
    909 
    910 	/*
    911 	 * create is unimplmented, remember it for later,
    912 	 * and start over using mknod and open instead.
    913 	 */
    914 	if (error == ENOSYS) {
    915 		ps->ps_flags |= PS_NO_CREAT;
    916 		return perfuse_node_create(pu, opc, pni, pcn, vap);
    917 	}
    918 
    919 	return error;
    920 }
    921 
    922 
    923 int
    924 perfuse_node_mknod(pu, opc, pni, pcn, vap)
    925 	struct puffs_usermount *pu;
    926 	puffs_cookie_t opc;
    927 	struct puffs_newinfo *pni;
    928 	const struct puffs_cn *pcn;
    929 	const struct vattr *vap;
    930 {
    931 	struct perfuse_state *ps;
    932 	perfuse_msg_t *pm;
    933 	struct fuse_mknod_in *fmi;
    934 	const char* path;
    935 	size_t len;
    936 
    937 	/*
    938 	 * Only superuser can mknod objects other than
    939 	 * directories, files, socks, fifo and links.
    940 	 *
    941 	 * Create an object require -WX permission in the parent directory
    942 	 */
    943 	switch (vap->va_type) {
    944 	case VDIR:	/* FALLTHROUGH */
    945 	case VREG:	/* FALLTHROUGH */
    946 	case VFIFO:	/* FALLTHROUGH */
    947 	case VSOCK:	/* FALLTHROUGH */
    948 	case VLNK:
    949 		if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
    950 			return EACCES;
    951 		break;
    952 	default:	/* VNON, VBLK, VCHR, VBAD */
    953 		if (!puffs_cred_isjuggernaut(pcn->pcn_cred))
    954 			return EACCES;
    955 		break;
    956 	}
    957 
    958 
    959 	ps = puffs_getspecific(pu);
    960 	path = basename_r((char *)PCNPATH(pcn));
    961 	len = sizeof(*fmi) + strlen(path) + 1;
    962 
    963 	pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred);
    964 	fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in);
    965 	fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
    966 	fmi->rdev = vap->va_rdev;
    967 	fmi->umask = 0; 	/* Seems unused bu libfuse */
    968 	(void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
    969 
    970 	return node_mk_common(pu, opc, pni, pcn, pm);
    971 }
    972 
    973 
    974 int
    975 perfuse_node_open(pu, opc, mode, pcr)
    976 	struct puffs_usermount *pu;
    977 	puffs_cookie_t opc;
    978 	int mode;
    979 	const struct puffs_cred *pcr;
    980 {
    981 	struct perfuse_state *ps;
    982 	perfuse_msg_t *pm;
    983 	mode_t pmode;
    984 	int op;
    985 	struct fuse_open_in *foi;
    986 	struct fuse_open_out *foo;
    987 	struct puffs_node *pn;
    988 	int error;
    989 
    990 	ps = puffs_getspecific(pu);
    991 
    992 	pn = (struct puffs_node *)opc;
    993 	if (puffs_pn_getvap(pn)->va_type == VDIR) {
    994 		op = FUSE_OPENDIR;
    995 		pmode = PUFFS_VREAD|PUFFS_VEXEC;
    996 	} else {
    997 		op = FUSE_OPEN;
    998 		if (mode & (O_RDWR|O_WRONLY))
    999 			pmode = PUFFS_VWRITE;
   1000 		else
   1001 			pmode = PUFFS_VREAD;
   1002 	}
   1003 
   1004 	/*
   1005 	 * Opening a directory require R-X on the directory
   1006 	 * Opening a file requires R-- for reading, -W- for writing
   1007 	 * In both cases, --X is required on the parent.
   1008 	 */
   1009 	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
   1010 	    pcr, PUFFS_VEXEC))
   1011 		return EACCES;
   1012 
   1013 	if (no_access(opc, pcr, pmode))
   1014 		return EACCES;
   1015 
   1016 	/*
   1017 	 * libfuse docs say O_CREAT should not be set.
   1018 	 */
   1019 	mode &= ~O_CREAT;
   1020 
   1021 	pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr);
   1022 	foi = GET_INPAYLOAD(ps, pm, fuse_open_in);
   1023 	foi->flags = mode & ~O_ACCMODE;
   1024 	switch (mode & (FREAD|FWRITE)) {
   1025 	case FREAD|FWRITE:
   1026 		foi->flags |= O_RDWR;
   1027 		break;
   1028 	case FREAD:
   1029 		foi->flags |= O_RDONLY;
   1030 		break;
   1031 	case FWRITE:
   1032 		foi->flags |= O_WRONLY;
   1033 		break;
   1034 	default:
   1035 		break;
   1036 	}
   1037 	foi->unused = 0;
   1038 
   1039 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*foo))) != 0)
   1040 		goto out;
   1041 
   1042 	foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out);
   1043 
   1044 	/*
   1045 	 * Save the file handle in node private data
   1046 	 * so that we can reuse it later
   1047 	 */
   1048 	perfuse_new_fh((puffs_cookie_t)pn, foo->fh);
   1049 
   1050 #ifdef PERFUSE_DEBUG
   1051 	if (perfuse_diagflags & PDF_FH)
   1052 		DPRINTF("%s: opc = %p, file = \"%s\", "
   1053 			"ino = %"PRId64", fh = 0x%"PRIx64"\n",
   1054 			__func__, (void *)opc,
   1055 			(char *)PNPATH((struct puffs_node *)opc),
   1056 			PERFUSE_NODE_DATA(opc)->pnd_ino, foo->fh);
   1057 #endif
   1058 out:
   1059 	ps->ps_destroy_msg(pm);
   1060 
   1061 	return error;
   1062 }
   1063 
   1064 /* ARGSUSED2 */
   1065 int
   1066 perfuse_node_close(pu, opc, flags, pcr)
   1067 	struct puffs_usermount *pu;
   1068 	puffs_cookie_t opc;
   1069 	int flags;
   1070 	const struct puffs_cred *pcr;
   1071 {
   1072 	struct perfuse_state *ps;
   1073 	perfuse_msg_t *pm;
   1074 	int op;
   1075 	uint64_t fh;
   1076 	struct perfuse_node_data *pnd;
   1077 	struct fuse_release_in *fri;
   1078 	struct puffs_node *pn;
   1079 	int error;
   1080 
   1081 	ps = puffs_getspecific(pu);
   1082 	pn = (struct puffs_node *)opc;
   1083 	pnd = PERFUSE_NODE_DATA(pn);
   1084 
   1085 	if (puffs_pn_getvap(pn)->va_type == VDIR)
   1086 		op = FUSE_RELEASEDIR;
   1087 	else
   1088 		op = FUSE_RELEASE;
   1089 
   1090 	if (!(pnd->pnd_flags & PND_OPEN))
   1091 		return EBADF;
   1092 
   1093 	fh = perfuse_get_fh(opc);
   1094 
   1095 	/*
   1096 	 * Sync before close for files
   1097 	 */
   1098 	if ((op == FUSE_RELEASE) && (pnd->pnd_flags & PND_DIRTY)) {
   1099 #ifdef PERFUSE_DEBUG
   1100 		if (perfuse_diagflags & PDF_SYNC)
   1101 			DPRINTF("%s: SYNC opc = %p, file = \"%s\"\n",
   1102 				__func__, (void*)opc, (char *)PNPATH(pn));
   1103 #endif
   1104 		if ((error = perfuse_node_fsync(pu, opc, pcr, 0, 0, 0)) != 0)
   1105 			return error;
   1106 
   1107 		pnd->pnd_flags &= ~PND_DIRTY;
   1108 
   1109 #ifdef PERFUSE_DEBUG
   1110 		if (perfuse_diagflags & PDF_SYNC)
   1111 			DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
   1112 				__func__, (void*)opc, (char *)PNPATH((pn)));
   1113 #endif
   1114 	}
   1115 
   1116 	/*
   1117 	 * Destroy the filehandle before sending the
   1118 	 * request to the FUSE filesystem, otherwise
   1119 	 * we may get a second close() while we wait
   1120 	 * for the reply, and we would end up closing
   1121 	 * the same fh twice instead of closng both.
   1122 	 */
   1123 	perfuse_destroy_fh(pn, fh);
   1124 
   1125 #ifdef PERFUSE_DEBUG
   1126 	if (perfuse_diagflags & PDF_FH)
   1127 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   1128 			__func__, (void *)opc, pnd->pnd_ino, fh);
   1129 #endif
   1130 
   1131 	/*
   1132 	 * release_flags may be set to FUSE_RELEASE_FLUSH
   1133 	 * to flush locks. lock_owner must be set in that case
   1134 	 */
   1135 	pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL);
   1136 	fri = GET_INPAYLOAD(ps, pm, fuse_release_in);
   1137 	fri->fh = fh;
   1138 	fri->flags = 0;
   1139 	fri->release_flags = 0;
   1140 	fri->lock_owner = PERFUSE_NODE_DATA(pn)->pnd_lock_owner;
   1141 	fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0;
   1142 
   1143 #ifdef PERFUSE_DEBUG
   1144 	if (perfuse_diagflags & PDF_FH)
   1145 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   1146 			 __func__, (void *)opc, pnd->pnd_ino, fri->fh);
   1147 #endif
   1148 
   1149 	if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0)
   1150 		goto out;
   1151 
   1152 out:
   1153 	if (error != 0)
   1154 		DWARNX("%s: freed fh = 0x%"PRIx64" but filesystem "
   1155 		       "returned error = %d",
   1156 		       __func__, fh, error);
   1157 
   1158 	ps->ps_destroy_msg(pm);
   1159 
   1160 	return error;
   1161 }
   1162 
   1163 int
   1164 perfuse_node_access(pu, opc, mode, pcr)
   1165 	struct puffs_usermount *pu;
   1166 	puffs_cookie_t opc;
   1167 	int mode;
   1168 	const struct puffs_cred *pcr;
   1169 {
   1170 	perfuse_msg_t *pm;
   1171 	struct perfuse_state *ps;
   1172 	struct fuse_access_in *fai;
   1173 	int error;
   1174 
   1175 	/*
   1176 	 * If we previously detected the filesystem does not
   1177 	 * implement access(), short-circuit the call and skip
   1178 	 * to libpffs access() emulation.
   1179 	 */
   1180 	ps = puffs_getspecific(pu);
   1181 	if (ps->ps_flags & PS_NO_ACCESS) {
   1182 		error = ENOSYS;
   1183 	} else {
   1184 		pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr);
   1185 		fai = GET_INPAYLOAD(ps, pm, fuse_access_in);
   1186 		fai->mask = mode;
   1187 
   1188 		error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN);
   1189 		ps->ps_destroy_msg(pm);
   1190 	}
   1191 
   1192 	if (error == ENOSYS) {
   1193 		struct fuse_getattr_in *fgi;
   1194 		struct fuse_attr_out *fao;
   1195 
   1196 		ps->ps_flags |= PS_NO_ACCESS;
   1197 
   1198 		pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR,
   1199 			      sizeof(*fgi), NULL);
   1200 		fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
   1201 		fgi->getattr_flags = 0;
   1202 		fgi->dummy = 0;
   1203 		fgi->fh = perfuse_get_fh(opc);
   1204 
   1205 #ifdef PERFUSE_DEBUG
   1206 		if (perfuse_diagflags & PDF_FH)
   1207 			DPRINTF("%s: opc = %p, ino = %"PRId64", "
   1208 				"fh = 0x%"PRIx64"\n", __func__, (void *)opc,
   1209 				PERFUSE_NODE_DATA(opc)->pnd_ino, fgi->fh);
   1210 #endif
   1211 		if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0) {
   1212 			ps->ps_destroy_msg(pm);
   1213 			goto out;
   1214 		}
   1215 
   1216 		fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
   1217 
   1218 		error = puffs_access(VREG, fao->attr.mode, fao->attr.uid,
   1219 				     fao->attr.gid, (mode_t)mode, pcr);
   1220 
   1221 		ps->ps_destroy_msg(pm);
   1222 	}
   1223 
   1224 out:
   1225 	return error;
   1226 }
   1227 
   1228 int
   1229 perfuse_node_getattr(pu, opc, vap, pcr)
   1230 	struct puffs_usermount *pu;
   1231 	puffs_cookie_t opc;
   1232 	struct vattr *vap;
   1233 	const struct puffs_cred *pcr;
   1234 {
   1235 	perfuse_msg_t *pm;
   1236 	struct perfuse_state *ps;
   1237 	struct fuse_getattr_in *fgi;
   1238 	struct fuse_attr_out *fao;
   1239 	int error;
   1240 
   1241 	/*
   1242 	 * getattr requires --X on the parent directory
   1243 	 */
   1244 	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
   1245 	    pcr, PUFFS_VEXEC))
   1246 		return EACCES;
   1247 
   1248 	ps = puffs_getspecific(pu);
   1249 
   1250 	/*
   1251 	 * FUSE_GETATTR_FH must be set in fgi->flags
   1252 	 * if we use for fgi->fh, but we do not.
   1253 	 */
   1254 	pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr);
   1255 	fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
   1256 	fgi->getattr_flags = 0;
   1257 	fgi->dummy = 0;
   1258 	fgi->fh = 0;
   1259 
   1260 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0)
   1261 		goto out;
   1262 
   1263 	fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
   1264 
   1265 	/*
   1266 	 * The message from filesystem has a cache timeout
   1267 	 * XXX this is ignored yet, is that right?
   1268 	 *
   1269 	 * We also set birthtime, flags, filerev,vaflags to 0.
   1270 	 * This seems the best bet, since the information is
   1271 	 * not available from filesystem.
   1272 	 */
   1273 	fuse_attr_to_vap(ps, vap, &fao->attr);
   1274 
   1275 out:
   1276 	ps->ps_destroy_msg(pm);
   1277 
   1278 	return error;
   1279 }
   1280 
   1281 int
   1282 perfuse_node_setattr(pu, opc, vap, pcr)
   1283 	struct puffs_usermount *pu;
   1284 	puffs_cookie_t opc;
   1285 	const struct vattr *vap;
   1286 	const struct puffs_cred *pcr;
   1287 {
   1288 	perfuse_msg_t *pm;
   1289 	uint64_t fh;
   1290 	struct perfuse_state *ps;
   1291 	struct fuse_setattr_in *fsi;
   1292 	int error;
   1293 	struct vattr *old_va;
   1294 
   1295 	/*
   1296 	 * setattr requires --X on the parent directory
   1297 	 */
   1298 	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
   1299 	    pcr, PUFFS_VEXEC))
   1300 		return EACCES;
   1301 
   1302 	old_va = puffs_pn_getvap((struct puffs_node *)opc);
   1303 
   1304 	/*
   1305 	 * Check for permission to change size
   1306 	 */
   1307 	if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
   1308 	    no_access(opc, pcr, PUFFS_VWRITE))
   1309 		return EACCES;
   1310 
   1311 	/*
   1312 	 * Check for permission to change dates
   1313 	 */
   1314 	if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
   1315 	     (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
   1316 	    (puffs_access_times(old_va->va_uid, old_va->va_gid,
   1317 				old_va->va_mode, 0, pcr) != 0))
   1318 		return EACCES;
   1319 
   1320 	/*
   1321 	 * Check for permission to change owner and group
   1322 	 */
   1323 	if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
   1324 	     (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
   1325 	    (puffs_access_chown(old_va->va_uid, old_va->va_gid,
   1326 				vap->va_uid, vap->va_gid, pcr)) != 0)
   1327 		return EACCES;
   1328 
   1329 	/*
   1330 	 * Check for permission to change permissions
   1331 	 */
   1332 	if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
   1333 	    (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
   1334 				 old_va->va_type, vap->va_mode, pcr)) != 0)
   1335 		return EACCES;
   1336 
   1337 
   1338 	ps = puffs_getspecific(pu);
   1339 
   1340 	pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
   1341 	fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
   1342 	fsi->valid = 0;
   1343 
   1344 	if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) {
   1345 		fh = perfuse_get_fh(opc);
   1346 		fsi->fh = fh;
   1347 		if (fh != FUSE_UNKNOWN_FH)
   1348 			fsi->valid |= FUSE_FATTR_FH;
   1349 	}
   1350 
   1351 	if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
   1352 		fsi->size = vap->va_size;
   1353 		fsi->valid |= FUSE_FATTR_SIZE;
   1354 	}
   1355 
   1356 	if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
   1357 		fsi->atime = vap->va_atime.tv_sec;;
   1358 		fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;;
   1359 		fsi->valid |= (FUSE_FATTR_ATIME|FUSE_FATTR_ATIME_NOW);
   1360 	}
   1361 
   1362 	if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
   1363 		fsi->mtime = vap->va_mtime.tv_sec;;
   1364 		fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec;;
   1365 		fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_MTIME_NOW);
   1366 	}
   1367 
   1368 	if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
   1369 		fsi->mode = vap->va_mode;
   1370 		fsi->valid |= FUSE_FATTR_MODE;
   1371 	}
   1372 
   1373 	if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
   1374 		fsi->uid = vap->va_uid;
   1375 		fsi->valid |= FUSE_FATTR_UID;
   1376 	}
   1377 
   1378 	if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
   1379 		fsi->gid = vap->va_gid;
   1380 		fsi->valid |= FUSE_FATTR_GID;
   1381 	}
   1382 
   1383 	if (PERFUSE_NODE_DATA(opc)->pnd_lock_owner != 0) {
   1384 		fsi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner;
   1385 		fsi->valid |= FUSE_FATTR_LOCKOWNER;
   1386 	}
   1387 
   1388 	/*
   1389 	 * A fuse_attr_out is returned, but we ignore it.
   1390 	 */
   1391 	error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out));
   1392 
   1393 	ps->ps_destroy_msg(pm);
   1394 
   1395 	return error;
   1396 }
   1397 
   1398 int
   1399 perfuse_node_poll(pu, opc, events)
   1400 	struct puffs_usermount *pu;
   1401 	puffs_cookie_t opc;
   1402 	int *events;
   1403 {
   1404 	struct perfuse_state *ps;
   1405 	perfuse_msg_t *pm;
   1406 	struct fuse_poll_in *fpi;
   1407 	struct fuse_poll_out *fpo;
   1408 	int error;
   1409 
   1410 	ps = puffs_getspecific(pu);
   1411 	/*
   1412 	 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
   1413  	 */
   1414 	pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
   1415 	fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
   1416 	fpi->fh = perfuse_get_fh(opc);
   1417 	fpi->kh = 0;
   1418 	fpi->flags = 0;
   1419 
   1420 #ifdef PERFUSE_DEBUG
   1421 	if (perfuse_diagflags & PDF_FH)
   1422 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   1423 			__func__, (void *)opc,
   1424 			PERFUSE_NODE_DATA(opc)->pnd_ino, fpi->fh);
   1425 #endif
   1426 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fpo))) != 0)
   1427 		goto out;
   1428 
   1429 	fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
   1430 	*events = fpo->revents;
   1431 out:
   1432 	ps->ps_destroy_msg(pm);
   1433 
   1434 	return error;
   1435 }
   1436 
   1437 /* ARGSUSED0 */
   1438 int
   1439 perfuse_node_mmap(pu, opc, flags, pcr)
   1440 	struct puffs_usermount *pu;
   1441 	puffs_cookie_t opc;
   1442 	int flags;
   1443 	const struct puffs_cred *pcr;
   1444 {
   1445 	/*
   1446 	 * Not implemented anymore in libfuse
   1447 	 */
   1448 	return ENOSYS;
   1449 }
   1450 
   1451 /* ARGSUSED2 */
   1452 int
   1453 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi)
   1454 	struct puffs_usermount *pu;
   1455 	puffs_cookie_t opc;
   1456 	const struct puffs_cred *pcr;
   1457 	int flags;
   1458 	off_t offlo;
   1459 	off_t offhi;
   1460 {
   1461 	perfuse_msg_t *pm;
   1462 	struct perfuse_state *ps;
   1463 	struct perfuse_node_data *pnd;
   1464 	struct fuse_fsync_in *ffi;
   1465 	uint64_t fh;
   1466 	int open_self;
   1467 	int error;
   1468 
   1469 	pm = NULL;
   1470 	open_self = 0;
   1471 
   1472 	/*
   1473 	 * If we previously detected it as unimplemented,
   1474 	 * skip the call to the filesystem.
   1475 	 */
   1476 	ps = puffs_getspecific(pu);
   1477 	if (ps->ps_flags == PS_NO_FSYNC)
   1478 		return ENOSYS;
   1479 
   1480 	/*
   1481 	 * Do not sync if there are no change to sync
   1482 	 * XXX remove that testif we implement mmap
   1483 	 */
   1484 	pnd = PERFUSE_NODE_DATA(opc);
   1485 #ifdef PERFUSE_DEBUG
   1486 	if (perfuse_diagflags & PDF_SYNC)
   1487 		DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",
   1488 			__func__, (void*)opc,
   1489 			(char *)PNPATH((struct puffs_node *)opc),
   1490 			pnd->pnd_flags & PND_DIRTY ? "" : "not ");
   1491 #endif
   1492 	if (!(pnd->pnd_flags & PND_DIRTY))
   1493 		return 0;
   1494 
   1495 	/*
   1496 	 * It seems NetBSD can call fsync without open first
   1497 	 * glusterfs complain in such a situation:
   1498 	 * "FSYNC() ERR => -1 (Invalid argument)"
   1499 	 */
   1500 	if (!(pnd->pnd_flags & PND_OPEN)) {
   1501 		if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
   1502 			goto out;
   1503 		open_self = 1;
   1504 	}
   1505 
   1506 	fh = perfuse_get_fh(opc);
   1507 
   1508 	/*
   1509 	 * If fsync_flags  is set, meta data should not be flushed.
   1510 	 */
   1511 	pm = ps->ps_new_msg(pu, opc, FUSE_FSYNC, sizeof(*ffi), NULL);
   1512 	ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
   1513 	ffi->fh = fh;
   1514 	ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
   1515 
   1516 #ifdef PERFUSE_DEBUG
   1517 	if (perfuse_diagflags & PDF_FH)
   1518 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   1519 			__func__, (void *)opc,
   1520 			PERFUSE_NODE_DATA(opc)->pnd_ino, ffi->fh);
   1521 #endif
   1522 
   1523 	if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0)
   1524 		goto out;
   1525 
   1526 	/*
   1527 	 * No reply beyond fuse_out_header: nothing to do on success
   1528 	 * just clear the dirty flag
   1529 	 */
   1530 	pnd->pnd_flags &= ~PND_DIRTY;
   1531 
   1532 #ifdef PERFUSE_DEBUG
   1533 	if (perfuse_diagflags & PDF_SYNC)
   1534 		DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
   1535 			__func__, (void*)opc,
   1536 			(char *)PNPATH((struct puffs_node *)opc));
   1537 #endif
   1538 
   1539 out:
   1540 	if (error == ENOSYS)
   1541 		ps->ps_flags |= PS_NO_FSYNC;
   1542 
   1543 	if (pm != NULL)
   1544 		ps->ps_destroy_msg(pm);
   1545 
   1546 	if (open_self)
   1547 		(void)perfuse_node_close(pu, opc, 0, pcr);
   1548 
   1549 	return error;
   1550 }
   1551 
   1552 /* ARGSUSED0 */
   1553 int
   1554 perfuse_node_seek(pu, opc, oldoff, newoff,  pcr)
   1555 	struct puffs_usermount *pu;
   1556 	puffs_cookie_t opc;
   1557 	off_t oldoff;
   1558 	off_t newoff;
   1559 	const struct puffs_cred *pcr;
   1560 {
   1561 	/*
   1562 	 * XXX what should I do with oldoff?
   1563 	 * XXX where is the newoffset returned?
   1564 	 * XXX the held seek pointer seems just unused
   1565 	 */
   1566 	PERFUSE_NODE_DATA(opc)->pnd_offset = newoff;
   1567 
   1568 	return 0;
   1569 }
   1570 
   1571 int
   1572 perfuse_node_remove(pu, opc, targ, pcn)
   1573 	struct puffs_usermount *pu;
   1574 	puffs_cookie_t opc;
   1575 	puffs_cookie_t targ;
   1576 	const struct puffs_cn *pcn;
   1577 {
   1578 	struct perfuse_state *ps;
   1579 	perfuse_msg_t *pm;
   1580 	struct puffs_node *pn;
   1581 	char *path;
   1582 	const char *name;
   1583 	size_t len;
   1584 	int error;
   1585 
   1586 	/*
   1587 	 * remove requires -WX on the parent directory
   1588 	 * no right required on the object.
   1589 	 */
   1590 	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
   1591 	    pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
   1592 		return EACCES;
   1593 
   1594 	ps = puffs_getspecific(pu);
   1595 
   1596 	if (targ == NULL)
   1597 		DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
   1598 
   1599 	pn = (struct puffs_node *)targ;
   1600 	name = basename_r((char *)PNPATH(pn));
   1601 	len = strlen(name) + 1;
   1602 
   1603 	pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
   1604 	path = _GET_INPAYLOAD(ps, pm, char *);
   1605 	(void)strlcpy(path, name, len);
   1606 
   1607 	if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
   1608 		goto out;
   1609 
   1610 	if (puffs_inval_namecache_dir(pu, opc) != 0)
   1611 		DERR(EX_OSERR, "puffs_inval_namecache_dir failed");
   1612 
   1613 	if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0)
   1614 		DERR(EX_OSERR, "puffs_inval_namecache_node failed");
   1615 
   1616 	puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
   1617 
   1618 	/*
   1619 	 * Reclaim should take care of decreasing pnd_childcount
   1620 	 */
   1621 out:
   1622 	ps->ps_destroy_msg(pm);
   1623 
   1624 	return error;
   1625 }
   1626 
   1627 int
   1628 perfuse_node_link(pu, opc, targ, pcn)
   1629 	struct puffs_usermount *pu;
   1630 	puffs_cookie_t opc;
   1631 	puffs_cookie_t targ;
   1632 	const struct puffs_cn *pcn;
   1633 {
   1634 	struct perfuse_state *ps;
   1635 	perfuse_msg_t *pm;
   1636 	const char *name;
   1637 	size_t len;
   1638 	struct puffs_node *pn;
   1639 	struct fuse_link_in *fli;
   1640 	int error;
   1641 
   1642 	/*
   1643 	 * Create an object require -WX permission in the parent directory
   1644 	 */
   1645 	if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
   1646 		return EACCES;
   1647 
   1648 
   1649 	ps = puffs_getspecific(pu);
   1650 	pn = (struct puffs_node *)targ;
   1651 	name = basename_r((char *)PCNPATH(pcn));
   1652 	len =  sizeof(*fli) + strlen(name) + 1;
   1653 
   1654 	pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred);
   1655 	fli = GET_INPAYLOAD(ps, pm, fuse_link_in);
   1656 	fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_ino;
   1657 	(void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli));
   1658 
   1659 	error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN);
   1660 
   1661 	ps->ps_destroy_msg(pm);
   1662 
   1663 	return error;
   1664 }
   1665 
   1666 /* targ is unused since the name is in pcn_targ */
   1667 /* ARGSUSED5 */
   1668 int
   1669 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ)
   1670 	struct puffs_usermount *pu;
   1671 	puffs_cookie_t opc;
   1672 	puffs_cookie_t src;
   1673 	const struct puffs_cn *pcn_src;
   1674 	puffs_cookie_t targ_dir;
   1675 	puffs_cookie_t targ;
   1676 	const struct puffs_cn *pcn_targ;
   1677 {
   1678 	struct perfuse_state *ps;
   1679 	perfuse_msg_t *pm;
   1680 	struct fuse_rename_in *fri;
   1681 	const char *newname;
   1682 	const char *oldname;
   1683 	char *np;
   1684 	int error;
   1685 	size_t len;
   1686 	size_t newname_len;
   1687 	size_t oldname_len;
   1688 
   1689 	/*
   1690 	 * move requires -WX on source and destination directory
   1691 	 */
   1692 	if (no_access(src, pcn_src->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC) ||
   1693 	    no_access(targ,  pcn_targ->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
   1694 		return EACCES;
   1695 
   1696 	ps = puffs_getspecific(pu);
   1697 	newname =  basename_r((char *)PCNPATH(pcn_targ));
   1698 	newname_len = strlen(newname) + 1;
   1699 	oldname =  basename_r((char *)PCNPATH(pcn_src));
   1700 	oldname_len = strlen(oldname) + 1;
   1701 
   1702 	len = sizeof(*fri) + oldname_len + newname_len;
   1703 	pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_src->pcn_cred);
   1704 	fri = GET_INPAYLOAD(ps, pm, fuse_rename_in);
   1705 	fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_ino;
   1706 	np = (char *)(void *)(fri + 1);
   1707 	(void)strlcpy(np, oldname, oldname_len);
   1708 	np += oldname_len;
   1709 	(void)strlcpy(np, newname, newname_len);
   1710 
   1711 	if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
   1712 		goto out;
   1713 
   1714 	/*
   1715 	 * Update source and destination directories child count
   1716 	 * Update moved object parent directory
   1717 	 */
   1718 	PERFUSE_NODE_DATA(opc)->pnd_childcount--;
   1719 	PERFUSE_NODE_DATA(targ_dir)->pnd_childcount++;
   1720 	PERFUSE_NODE_DATA(src)->pnd_parent = targ_dir;
   1721 
   1722 out:
   1723 	ps->ps_destroy_msg(pm);
   1724 
   1725 	return error;
   1726 }
   1727 
   1728 int
   1729 perfuse_node_mkdir(pu, opc, pni, pcn, vap)
   1730 	struct puffs_usermount *pu;
   1731 	puffs_cookie_t opc;
   1732 	struct puffs_newinfo *pni;
   1733 	const struct puffs_cn *pcn;
   1734 	const struct vattr *vap;
   1735 {
   1736 	struct perfuse_state *ps;
   1737 	perfuse_msg_t *pm;
   1738 	struct fuse_mkdir_in *fmi;
   1739 	const char *path;
   1740 	size_t len;
   1741 
   1742 	/*
   1743 	 * Create an object require -WX permission in the parent directory
   1744 	 */
   1745 	if (no_access(opc, pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
   1746 		return EACCES;
   1747 
   1748 	ps = puffs_getspecific(pu);
   1749 	path = basename_r((char *)PCNPATH(pcn));
   1750 	len = sizeof(*fmi) + strlen(path) + 1;
   1751 
   1752 	pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred);
   1753 	fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in);
   1754 	fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
   1755 	fmi->umask = 0; 	/* Seems unused bu libfuse? */
   1756 	(void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
   1757 
   1758 	return node_mk_common(pu, opc, pni, pcn, pm);
   1759 }
   1760 
   1761 
   1762 int
   1763 perfuse_node_rmdir(pu, opc, targ, pcn)
   1764 	struct puffs_usermount *pu;
   1765 	puffs_cookie_t opc;
   1766 	puffs_cookie_t targ;
   1767 	const struct puffs_cn *pcn;
   1768 {
   1769 	struct perfuse_state *ps;
   1770 	perfuse_msg_t *pm;
   1771 	struct puffs_node *pn;
   1772 	char *path;
   1773 	const char *name;
   1774 	size_t len;
   1775 	int error;
   1776 
   1777 	/*
   1778 	 * remove requires -WX on the parent directory
   1779 	 * no right required on the object.
   1780 	 */
   1781 	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
   1782 	    pcn->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
   1783 		return EACCES;
   1784 
   1785 	ps = puffs_getspecific(pu);
   1786 	pn = (struct puffs_node *)targ;
   1787 	name = basename_r((char *)PNPATH(pn));
   1788 	len = strlen(name) + 1;
   1789 
   1790 	pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
   1791 	path = _GET_INPAYLOAD(ps, pm, char *);
   1792 	(void)strlcpy(path, name, len);
   1793 
   1794 	if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
   1795 		goto out;
   1796 
   1797 	if (puffs_inval_namecache_dir(pu, opc) != 0)
   1798 		DERR(EX_OSERR, "puffs_inval_namecache_dir failed");
   1799 
   1800 	if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0)
   1801 		DERR(EX_OSERR, "puffs_inval_namecache_node failed");
   1802 
   1803 	puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
   1804 
   1805 out:
   1806 	ps->ps_destroy_msg(pm);
   1807 
   1808 	return error;
   1809 }
   1810 
   1811 /* vap is unused */
   1812 /* ARGSUSED4 */
   1813 int
   1814 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target)
   1815 	struct puffs_usermount *pu;
   1816 	puffs_cookie_t opc;
   1817 	struct puffs_newinfo *pni;
   1818 	const struct puffs_cn *pcn_src;
   1819 	const struct vattr *vap;
   1820 	const char *link_target;
   1821 {
   1822 	struct perfuse_state *ps;
   1823 	perfuse_msg_t *pm;
   1824 	char *np;
   1825 	const char *path;
   1826 	size_t path_len;
   1827 	size_t linkname_len;
   1828 	size_t len;
   1829 
   1830 	/*
   1831 	 * Create an object require -WX permission in the parent directory
   1832 	 */
   1833 	if (no_access(opc, pcn_src->pcn_cred, PUFFS_VWRITE|PUFFS_VEXEC))
   1834 		return EACCES;
   1835 
   1836 	ps = puffs_getspecific(pu);
   1837 	path = basename_r((char *)PCNPATH(pcn_src));
   1838 	path_len = strlen(path) + 1;
   1839 	linkname_len = strlen(link_target) + 1;
   1840 	len = path_len + linkname_len;
   1841 
   1842 	pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred);
   1843 	np = _GET_INPAYLOAD(ps, pm, char *);
   1844 	(void)strlcpy(np, path, path_len);
   1845 	np += path_len;
   1846 	(void)strlcpy(np, link_target, linkname_len);
   1847 
   1848 	return node_mk_common(pu, opc, pni, pcn_src, pm);
   1849 }
   1850 
   1851 int
   1852 perfuse_node_readdir(pu, opc, dent, readoff,
   1853 		     reslen, pcr, eofflag, cookies, ncookies)
   1854 	struct puffs_usermount *pu;
   1855 	puffs_cookie_t opc;
   1856 	struct dirent *dent;
   1857 	off_t *readoff;
   1858 	size_t *reslen;
   1859 	const struct puffs_cred *pcr;
   1860 	int *eofflag;
   1861 	off_t *cookies;
   1862 	size_t *ncookies;
   1863 {
   1864 	perfuse_msg_t *pm;
   1865 	uint64_t fh;
   1866 	struct perfuse_state *ps;
   1867 	struct perfuse_node_data *pnd;
   1868 	struct fuse_read_in *fri;
   1869 	struct fuse_out_header *foh;
   1870 	struct fuse_dirent *fd;
   1871 	size_t foh_len;
   1872 	int error;
   1873 	int open_self;
   1874 	uint64_t fd_offset;
   1875 
   1876 	pm = NULL;
   1877 	error = 0;
   1878 	open_self = 0;
   1879 	ps = puffs_getspecific(pu);
   1880 
   1881 	/*
   1882 	 * readdir state is kept at node level, and several readdir
   1883 	 * requests can be issued at the same time on the same node.
   1884 	 * We need to queue requests so that only one is in readdir
   1885 	 * code at the same time.
   1886 	 */
   1887 	pnd = PERFUSE_NODE_DATA(opc);
   1888 	while (pnd->pnd_flags & PND_INREADDIR)
   1889 		requeue_request(pu, opc, PCQ_READDIR);
   1890 	pnd->pnd_flags |= PND_INREADDIR;
   1891 
   1892 #ifdef PERFUSE_DEBUG
   1893 	if (perfuse_diagflags & PDF_READDIR)
   1894 		DPRINTF("%s: READDIR opc = %p enter critical section\n",
   1895 			__func__, (void *)opc);
   1896 #endif
   1897 	/*
   1898 	 * Do we already have the data bufered?
   1899 	 */
   1900 	if (pnd->pnd_dirent != NULL)
   1901 		goto out;
   1902 	pnd->pnd_dirent_len = 0;
   1903 
   1904 	/*
   1905 	 * It seems NetBSD can call readdir without open first
   1906 	 * libfuse will crash if it is done that way, hence open first.
   1907 	 */
   1908 	if (!(PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN)) {
   1909 		if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
   1910 			goto out;
   1911 		open_self = 1;
   1912 	}
   1913 
   1914 	fh = perfuse_get_fh(opc);
   1915 
   1916 #ifdef PERFUSE_DEBUG
   1917 	if (perfuse_diagflags & PDF_FH)
   1918 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   1919 			__func__, (void *)opc,
   1920 			PERFUSE_NODE_DATA(opc)->pnd_ino, fh);
   1921 #endif
   1922 
   1923 	pnd->pnd_all_fd = NULL;
   1924 	pnd->pnd_all_fd_len = 0;
   1925 	fd_offset = 0;
   1926 
   1927 	do {
   1928 		size_t fd_len;
   1929 		char *afdp;
   1930 
   1931 		pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
   1932 
   1933 		/*
   1934 		 * read_flags, lock_owner and flags are unused in libfuse
   1935 		 *
   1936 		 * XXX if fri->size is too big (bigger than PAGE_SIZE?), 			 * we get strange bugs. ktrace shows 16 bytes or garbage
   1937 		 * at the end of sent frames, but perfused does not receive
   1938 		 * that data. The data length is hoverver the same, which
   1939 		 * cause perfused to use the last 16 bytes of the frame
   1940 		 * as the frame header of the next frame.
   1941 		 *
   1942 		 * This may be a kernel bug.
   1943 		 */
   1944 		fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
   1945 		fri->fh = fh;
   1946 		fri->offset = fd_offset;
   1947 		fri->size = PAGE_SIZE - sizeof(struct fuse_out_header);
   1948 		fri->read_flags = 0;
   1949 		fri->lock_owner = 0;
   1950 		fri->flags = 0;
   1951 
   1952 		if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
   1953 			goto out;
   1954 
   1955 		/*
   1956 		 * There are many puffs_framebufs calls later,
   1957 		 * therefore foh will not be valid for a long time.
   1958 		 * Just get the length and forget it.
   1959 		 */
   1960 		foh = GET_OUTHDR(ps, pm);
   1961 		foh_len = foh->len;
   1962 
   1963 		/*
   1964 		 * It seems that the only way to discover the end
   1965 		 * of the buffer is to get an empty read
   1966 		 */
   1967 		if (foh_len == sizeof(*foh))
   1968 			break;
   1969 
   1970 		/*
   1971 		 * Corrupted message.
   1972 		 */
   1973 		if (foh_len < sizeof(*foh) + sizeof(*fd)) {
   1974 			DWARNX("readdir reply too short");
   1975 			error = EIO;
   1976 			goto out;
   1977 		}
   1978 
   1979 
   1980 		fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
   1981 		fd_len = foh_len - sizeof(*foh);
   1982 
   1983 		pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
   1984 					  pnd->pnd_all_fd_len + fd_len);
   1985 		if (pnd->pnd_all_fd  == NULL)
   1986 			DERR(EX_OSERR, "malloc failed");
   1987 
   1988 		afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
   1989 		(void)memcpy(afdp, fd, fd_len);
   1990 
   1991 		pnd->pnd_all_fd_len += fd_len;
   1992 		fd_offset += fd_len;
   1993 
   1994 		ps->ps_destroy_msg(pm);
   1995 		pm = NULL;
   1996 	} while (1 /* CONSTCOND */);
   1997 
   1998 	if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, pnd->pnd_all_fd_len) == -1)
   1999 		error = EIO;
   2000 
   2001 out:
   2002 	if (pnd->pnd_all_fd != NULL) {
   2003 		free(pnd->pnd_all_fd);
   2004 		pnd->pnd_all_fd = NULL;
   2005 		pnd->pnd_all_fd_len = 0;
   2006 	}
   2007 
   2008 	if (pm != NULL)
   2009 		ps->ps_destroy_msg(pm);
   2010 
   2011 	/*
   2012 	 * If we opened the directory ourselves, close now
   2013 	 * errors are ignored.
   2014 	 */
   2015 	if (open_self)
   2016 		(void)perfuse_node_close(pu, opc, 0, pcr);
   2017 
   2018 	if (error == 0)
   2019 		error = readdir_buffered(ps, opc, dent, readoff,
   2020 			reslen, pcr, eofflag, cookies, ncookies);
   2021 
   2022 	/*
   2023 	 * Schedule queued readdir requests
   2024 	 */
   2025 	dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
   2026 	pnd->pnd_flags &= ~PND_INREADDIR;
   2027 
   2028 #ifdef PERFUSE_DEBUG
   2029 	if (perfuse_diagflags & PDF_READDIR)
   2030 		DPRINTF("%s: READDIR opc = %p exit critical section\n",
   2031 			__func__, (void *)opc);
   2032 #endif
   2033 
   2034 	return error;
   2035 }
   2036 
   2037 int
   2038 perfuse_node_readlink(pu, opc, pcr, linkname, linklen)
   2039 	struct puffs_usermount *pu;
   2040 	puffs_cookie_t opc;
   2041 	const struct puffs_cred *pcr;
   2042 	char *linkname;
   2043 	size_t *linklen;
   2044 {
   2045 	struct perfuse_state *ps;
   2046 	perfuse_msg_t *pm;
   2047 	int error;
   2048 	size_t len;
   2049 	struct fuse_out_header *foh;
   2050 
   2051 	/*
   2052 	 * --X required on parent, R-- required on link
   2053 	 */
   2054 	if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
   2055 	    pcr, PUFFS_VEXEC) ||
   2056 	   no_access(opc, pcr, PUFFS_VREAD))
   2057 		return EACCES;
   2058 
   2059 	ps = puffs_getspecific(pu);
   2060 
   2061 	pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
   2062 
   2063 	if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
   2064 		goto out;
   2065 
   2066 	foh = GET_OUTHDR(ps, pm);
   2067 	len = foh->len - sizeof(*foh) + 1;
   2068 	if (len > *linklen)
   2069 		DERRX(EX_PROTOCOL, "path len = %zd too long", len);
   2070 
   2071 	*linklen = len;
   2072 	(void)strlcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
   2073 out:
   2074 	ps->ps_destroy_msg(pm);
   2075 
   2076 	return error;
   2077 }
   2078 
   2079 int
   2080 perfuse_node_reclaim(pu, opc)
   2081 	struct puffs_usermount *pu;
   2082 	puffs_cookie_t opc;
   2083 {
   2084 	struct perfuse_state *ps;
   2085 	perfuse_msg_t *pm;
   2086 	struct perfuse_node_data *pnd;
   2087 	struct fuse_forget_in *ffi;
   2088 	struct puffs_node *pn;
   2089 	struct puffs_node *pn_root;
   2090 
   2091 	ps = puffs_getspecific(pu);
   2092 	pnd = PERFUSE_NODE_DATA(opc);
   2093 
   2094 	/*
   2095 	 * Make sure open files are properly closed when reclaimed.
   2096 	 */
   2097 	while (pnd->pnd_flags & PND_OPEN)
   2098 		(void)perfuse_node_close(pu, opc, 0, NULL);
   2099 
   2100 	/*
   2101 	 * Never forget the root.
   2102 	 */
   2103 	if (pnd->pnd_ino == FUSE_ROOT_ID)
   2104 		return 0;
   2105 
   2106 	pnd->pnd_flags |= PND_RECLAIMED;
   2107 
   2108 #ifdef PERFUSE_DEBUG
   2109 	if (perfuse_diagflags & PDF_RECLAIM)
   2110 		DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
   2111 		       (char *)PNPATH((struct puffs_node *)opc), pnd->pnd_ino);
   2112 #endif
   2113 
   2114 	pn_root = puffs_getroot(pu);
   2115 	pn = (struct puffs_node *)opc;
   2116 	while (pn != pn_root) {
   2117 		struct puffs_node *parent_pn;
   2118 
   2119 		pnd = PERFUSE_NODE_DATA(pn);
   2120 
   2121 #ifdef PERFUSE_DEBUG
   2122 	if (perfuse_diagflags & PDF_RECLAIM)
   2123 		DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, "
   2124 			"has childcount %d, %sopen\n",
   2125 		        (char *)PNPATH(pn), pnd->pnd_ino,
   2126 		        pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
   2127 		        pnd->pnd_childcount,
   2128 			pnd->pnd_flags & PND_OPEN ? "" : "not ");
   2129 
   2130 	if (pnd->pnd_flags & PND_OPEN)
   2131 		DWARNX("%s: (nodeid %"PRId64") %s is still open",
   2132 		       __func__, pnd->pnd_ino, (char *)PNPATH(pn));
   2133 #endif
   2134 
   2135 		if (!(pnd->pnd_flags & PND_RECLAIMED) ||
   2136 		    (pnd->pnd_childcount != 0))
   2137 			return 0;
   2138 
   2139 		/*
   2140 		 * If the file is still open, close all file handles
   2141 		 * XXX no pcr arguement to send.
   2142 		 */
   2143 		while(pnd->pnd_flags & PND_OPEN)
   2144 			(void)perfuse_node_close(pu, opc, 0, NULL);
   2145 
   2146 		pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
   2147 			      sizeof(*ffi), NULL);
   2148 		ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
   2149 		ffi->nlookup = pnd->pnd_nlookup;
   2150 
   2151 		/*
   2152 		 * No reply is expected, pm is freed in XCHG_MSG
   2153 		 */
   2154 		(void)XCHG_MSG_NOREPLY(ps, pu, pm, UNSPEC_REPLY_LEN);
   2155 
   2156 		parent_pn = pnd->pnd_parent;
   2157 
   2158 		perfuse_destroy_pn(pn);
   2159 		puffs_pn_put(pn);
   2160 
   2161 		pn = parent_pn;
   2162 	}
   2163 
   2164 	return 0;
   2165 }
   2166 
   2167 /* ARGSUSED0 */
   2168 int
   2169 perfuse_node_inactive(pu, opc)
   2170 	struct puffs_usermount *pu;
   2171 	puffs_cookie_t opc;
   2172 {
   2173 	return 0;
   2174 }
   2175 
   2176 
   2177 /* ARGSUSED0 */
   2178 int
   2179 perfuse_node_print(pu, opc)
   2180 	struct puffs_usermount *pu;
   2181 	puffs_cookie_t opc;
   2182 {
   2183 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
   2184 	return 0;
   2185 }
   2186 
   2187 /* ARGSUSED0 */
   2188 int
   2189 perfuse_node_pathconf(pu, opc, name, retval)
   2190 	struct puffs_usermount *pu;
   2191 	puffs_cookie_t opc;
   2192 	int name;
   2193 	int *retval;
   2194 {
   2195 	DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
   2196 	return 0;
   2197 }
   2198 
   2199 /* id is unused */
   2200 /* ARGSUSED2 */
   2201 int
   2202 perfuse_node_advlock(pu, opc, id, op, fl, flags)
   2203 	struct puffs_usermount *pu;
   2204 	puffs_cookie_t opc;
   2205 	void *id;
   2206 	int op;
   2207 	struct flock *fl;
   2208 	int flags;
   2209 {
   2210 	struct perfuse_state *ps;
   2211 	int fop;
   2212 	perfuse_msg_t *pm;
   2213 	struct fuse_lk_in *fli;
   2214 	struct fuse_lk_out *flo;
   2215 	int error;
   2216 
   2217 	ps = puffs_getspecific(pu);
   2218 
   2219 	if (op == F_GETLK)
   2220 		fop = FUSE_GETLK;
   2221 	else
   2222 		fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
   2223 
   2224 	pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
   2225 	fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
   2226 	fli->fh = perfuse_get_fh(opc);
   2227 	fli->owner = fl->l_pid;
   2228 	fli->lk.start = fl->l_start;
   2229 	fli->lk.end = fl->l_start + fl->l_len;
   2230 	fli->lk.type = fl->l_type;
   2231 	fli->lk.pid = fl->l_pid;
   2232 	fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
   2233 
   2234 #ifdef PERFUSE_DEBUG
   2235 	if (perfuse_diagflags & PDF_FH)
   2236 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   2237 			__func__, (void *)opc,
   2238 			PERFUSE_NODE_DATA(opc)->pnd_ino, fli->fh);
   2239 #endif
   2240 
   2241 	if ((error = XCHG_MSG(ps, pu, pm, sizeof(*flo))) != 0)
   2242 		goto out;
   2243 
   2244 	flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
   2245 	fl->l_start = flo->lk.start;
   2246 	fl->l_len = flo->lk.end - flo->lk.start;
   2247 	fl->l_pid = flo->lk.pid;
   2248 	fl->l_type = flo->lk.type;
   2249 	fl->l_whence = SEEK_SET;	/* libfuse hardcodes it */
   2250 
   2251 	/*
   2252 	 * Save or clear the lock
   2253 	 */
   2254 	switch (op) {
   2255 	case F_SETLK:
   2256 		PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
   2257 		break;
   2258 	case F_UNLCK:
   2259 		PERFUSE_NODE_DATA(opc)->pnd_lock_owner = 0;
   2260 		break;
   2261 	default:
   2262 		break;
   2263 	}
   2264 
   2265 out:
   2266 	ps->ps_destroy_msg(pm);
   2267 
   2268 	return error;
   2269 }
   2270 
   2271 int
   2272 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag)
   2273 	struct puffs_usermount *pu;
   2274 	puffs_cookie_t opc;
   2275 	uint8_t *buf;
   2276 	off_t offset;
   2277 	size_t *resid;
   2278 	const struct puffs_cred *pcr;
   2279 	int ioflag;
   2280 {
   2281 	struct perfuse_state *ps;
   2282 	perfuse_msg_t *pm;
   2283 	struct fuse_read_in *fri;
   2284 	struct fuse_out_header *foh;
   2285 	size_t readen;
   2286 	size_t requested;
   2287 	int error;
   2288 
   2289 	ps = puffs_getspecific(pu);
   2290 	pm = NULL;
   2291 
   2292 	requested = *resid;
   2293 	if ((ps->ps_readahead + requested) > ps->ps_max_readahead) {
   2294 		if (perfuse_diagflags & PDF_REQUEUE)
   2295 			DPRINTF("readahead = %zd\n", ps->ps_readahead);
   2296 		requeue_request(pu, opc, PCQ_READ);
   2297 	}
   2298 	ps->ps_readahead += requested;
   2299 
   2300 	do {
   2301 		/*
   2302 		 * flags may be set to FUSE_READ_LOCKOWNER
   2303 		 * if lock_owner is provided.
   2304 		 *
   2305 		 * XXX See comment about fri->size in perfuse_node_readdir
   2306 		 * We encounter the same bug here.
   2307 		 */
   2308 		pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
   2309 		fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
   2310 		fri->fh = perfuse_get_fh(opc);
   2311 		fri->offset = offset;
   2312 		fri->size = (uint32_t)MIN(*resid, PAGE_SIZE - sizeof(*foh));
   2313 		fri->read_flags = 0; /* XXX Unused by libfuse? */
   2314 		fri->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner;
   2315 		fri->flags = 0;
   2316 		fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
   2317 
   2318 #ifdef PERFUSE_DEBUG
   2319 	if (perfuse_diagflags & PDF_FH)
   2320 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   2321 			__func__, (void *)opc,
   2322 			PERFUSE_NODE_DATA(opc)->pnd_ino, fri->fh);
   2323 #endif
   2324 		error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN);
   2325 
   2326 		if (error  != 0)
   2327 			goto out;
   2328 
   2329 		foh = GET_OUTHDR(ps, pm);
   2330 		readen = foh->len - sizeof(*foh);
   2331 
   2332 		(void)memcpy(buf,  _GET_OUTPAYLOAD(ps, pm, char *), readen);
   2333 
   2334 		buf += readen;
   2335 		offset += readen;
   2336 		*resid -= readen;
   2337 
   2338 		ps->ps_destroy_msg(pm);
   2339 		pm = NULL;
   2340 	} while ((*resid != 0) && (readen != 0));
   2341 
   2342 	if (ioflag & (IO_SYNC|IO_DSYNC))
   2343 		ps->ps_syncreads++;
   2344 	else
   2345 		ps->ps_asyncreads++;
   2346 
   2347 out:
   2348 	if (pm != NULL)
   2349 		ps->ps_destroy_msg(pm);
   2350 
   2351 	ps->ps_readahead -= requested;
   2352 	dequeue_requests(ps, opc, PCQ_READ, 1);
   2353 
   2354 	return error;
   2355 }
   2356 
   2357 int
   2358 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag)
   2359 	struct puffs_usermount *pu;
   2360 	puffs_cookie_t opc;
   2361 	uint8_t *buf;
   2362 	off_t offset;
   2363 	size_t *resid;
   2364 	const struct puffs_cred *pcr;
   2365 	int ioflag;
   2366 {
   2367 	struct perfuse_state *ps;
   2368 	perfuse_msg_t *pm;
   2369 	struct fuse_write_in *fwi;
   2370 	struct fuse_write_out *fwo;
   2371 	size_t data_len;
   2372 	size_t payload_len;
   2373 	size_t written;
   2374 	size_t requested;
   2375 	int error;
   2376 
   2377 	ps = puffs_getspecific(pu);
   2378 	pm = NULL;
   2379 	written = 0;
   2380 
   2381 	requested = *resid;
   2382 	if ((ps->ps_write + requested) > ps->ps_max_write) {
   2383 		if (perfuse_diagflags & PDF_REQUEUE)
   2384 			DPRINTF("write = %zd\n", ps->ps_write);
   2385 		requeue_request(pu, opc, PCQ_WRITE);
   2386 	}
   2387 	ps->ps_write += requested;
   2388 
   2389 	do {
   2390 		/*
   2391 		 * It seems libfuse does not expects big chunks, so
   2392 		 * send it page per page. The writepage feature is
   2393 		 * probably there to minmize data movement.
   2394 		 * XXX use ps->ps_maxwrite?
   2395 		 */
   2396 		data_len = MIN(*resid, PAGE_SIZE);
   2397 		payload_len = data_len + sizeof(*fwi);
   2398 
   2399 		/*
   2400 		 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
   2401 		 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
   2402 		 * write_flags is set to 1 for writepage.
   2403 		 */
   2404 		pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
   2405 		fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
   2406 		fwi->fh = perfuse_get_fh(opc);
   2407 		fwi->offset = offset;
   2408 		fwi->size = (uint32_t)data_len;
   2409 		fwi->write_flags = (fwi->size % PAGE_SIZE) ? 0 : 1;
   2410 		fwi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner;
   2411 		fwi->flags = 0;
   2412 		fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
   2413 		fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
   2414 		(void)memcpy((fwi + 1), buf + written, data_len);
   2415 
   2416 #ifdef PERFUSE_DEBUG
   2417 	if (perfuse_diagflags & PDF_FH)
   2418 		DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
   2419 			__func__, (void *)opc,
   2420 			PERFUSE_NODE_DATA(opc)->pnd_ino, fwi->fh);
   2421 #endif
   2422 		if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fwo))) != 0)
   2423 			goto out;
   2424 
   2425 		fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
   2426 		written = fwo->size;
   2427 		*resid -= written;
   2428 		offset += written;
   2429 		buf += written;
   2430 
   2431 		ps->ps_destroy_msg(pm);
   2432 		pm = NULL;
   2433 	} while (*resid != 0);
   2434 
   2435 	/*
   2436 	 * puffs_ops(3) says
   2437 	 *  "everything must be written or an error will be generated"
   2438 	 */
   2439 	if (*resid != 0)
   2440 		error = EFBIG;
   2441 
   2442 	if (ioflag & (IO_SYNC|IO_DSYNC))
   2443 		ps->ps_syncwrites++;
   2444 	else
   2445 		ps->ps_asyncwrites++;
   2446 
   2447 	/*
   2448 	 * Remember to sync the file
   2449 	 */
   2450 	PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
   2451 
   2452 #ifdef PERFUSE_DEBUG
   2453 	if (perfuse_diagflags & PDF_SYNC)
   2454 		DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
   2455 			__func__, (void*)opc,
   2456 			(char *)PNPATH((struct puffs_node *)opc));
   2457 #endif
   2458 out:
   2459 	if (pm != NULL)
   2460 		ps->ps_destroy_msg(pm);
   2461 
   2462 	ps->ps_write -= requested;
   2463 	dequeue_requests(ps, opc, PCQ_WRITE, 1);
   2464 
   2465 	return error;
   2466 }
   2467 
   2468 /* ARGSUSED0 */
   2469 void
   2470 perfuse_cache_write(pu, opc, size, runs)
   2471 	struct puffs_usermount *pu;
   2472 	puffs_cookie_t opc;
   2473 	size_t size;
   2474 	struct puffs_cacherun *runs;
   2475 {
   2476 	return;
   2477 }
   2478 
   2479