puffs.c revision 1.31
1/*	$NetBSD: puffs.c,v 1.31 2007/02/18 17:36:48 pooka Exp $	*/
2
3/*
4 * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. The name of the company nor the name of the author may be used to
19 *    endorse or promote products derived from this software without specific
20 *    prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#if !defined(lint)
37__RCSID("$NetBSD: puffs.c,v 1.31 2007/02/18 17:36:48 pooka Exp $");
38#endif /* !lint */
39
40#include <sys/param.h>
41#include <sys/mount.h>
42
43#include <assert.h>
44#include <err.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <mntopts.h>
48#include <puffs.h>
49#include <puffsdump.h>
50#include <stdarg.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <syslog.h>
55#include <unistd.h>
56
57#include "puffs_priv.h"
58
59/* Most file systems want this for opts, so just give it to them */
60const struct mntopt puffsmopts[] = {
61	MOPT_STDOPTS,
62	PUFFSMOPT_STD,
63	MOPT_NULL,
64};
65
66#define FILLOP(lower, upper)						\
67do {									\
68	if (pops->puffs_node_##lower)					\
69		opmask[PUFFS_VN_##upper] = 1;				\
70} while (/*CONSTCOND*/0)
71static void
72fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
73{
74
75	memset(opmask, 0, PUFFS_VN_MAX);
76
77	FILLOP(create,   CREATE);
78	FILLOP(mknod,    MKNOD);
79	FILLOP(open,     OPEN);
80	FILLOP(close,    CLOSE);
81	FILLOP(access,   ACCESS);
82	FILLOP(getattr,  GETATTR);
83	FILLOP(setattr,  SETATTR);
84	FILLOP(poll,     POLL); /* XXX: not ready in kernel */
85	FILLOP(mmap,     MMAP);
86	FILLOP(fsync,    FSYNC);
87	FILLOP(seek,     SEEK);
88	FILLOP(remove,   REMOVE);
89	FILLOP(link,     LINK);
90	FILLOP(rename,   RENAME);
91	FILLOP(mkdir,    MKDIR);
92	FILLOP(rmdir,    RMDIR);
93	FILLOP(symlink,  SYMLINK);
94	FILLOP(readdir,  READDIR);
95	FILLOP(readlink, READLINK);
96	FILLOP(reclaim,  RECLAIM);
97	FILLOP(inactive, INACTIVE);
98	FILLOP(print,    PRINT);
99	FILLOP(read,     READ);
100	FILLOP(write,    WRITE);
101
102	/* XXX: not implemented in the kernel */
103	FILLOP(getextattr, GETEXTATTR);
104	FILLOP(setextattr, SETEXTATTR);
105	FILLOP(listextattr, LISTEXTATTR);
106}
107#undef FILLOP
108
109int
110puffs_getselectable(struct puffs_usermount *pu)
111{
112
113	return pu->pu_fd;
114}
115
116int
117puffs_setblockingmode(struct puffs_usermount *pu, int mode)
118{
119	int x;
120
121	x = mode;
122	return ioctl(pu->pu_fd, FIONBIO, &x);
123}
124
125int
126puffs_getstate(struct puffs_usermount *pu)
127{
128
129	return pu->pu_state;
130}
131
132void
133puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
134{
135
136	pu->pu_cc_stacksize = ss;
137}
138
139struct puffs_pathobj *
140puffs_getrootpathobj(struct puffs_usermount *pu)
141{
142	struct puffs_node *pnr;
143
144	pnr = pu->pu_pn_root;
145	if (pnr == NULL) {
146		errno = ENOENT;
147		return NULL;
148	}
149
150	return &pnr->pn_po;
151}
152
153
154void
155puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
156{
157
158	pu->pu_pathbuild = fn;
159}
160
161void
162puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
163{
164
165	pu->pu_pathtransform = fn;
166}
167
168void
169puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
170{
171
172	pu->pu_pathcmp = fn;
173}
174
175void
176puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
177{
178
179	pu->pu_pathfree = fn;
180}
181
182void
183puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
184{
185
186	pu->pu_namemod = fn;
187}
188
189enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
190
191struct puffs_usermount *
192_puffs_mount(int develv, struct puffs_ops *pops, const char *dir, int mntflags,
193	const char *puffsname, void *priv, uint32_t pflags, size_t maxreqlen)
194{
195	struct puffs_args pargs;
196	struct puffs_usermount *pu;
197	int fd = 0;
198
199	if (develv != PUFFS_DEVEL_LIBVERSION) {
200		warnx("puffs_mount: mounting with lib version %d, need %d",
201		    develv, PUFFS_DEVEL_LIBVERSION);
202		errno = EINVAL;
203		return NULL;
204	}
205
206	fd = open("/dev/puffs", O_RDONLY);
207	if (fd == -1)
208		return NULL;
209	if (fd <= 2)
210		warnx("puffs_mount: device fd %d (<= 2), sure this is "
211		    "what you want?", fd);
212
213	pargs.pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
214	pargs.pa_flags = PUFFS_FLAG_KERN(pflags);
215	pargs.pa_fd = fd;
216	pargs.pa_maxreqlen = maxreqlen;
217	fillvnopmask(pops, pargs.pa_vnopmask);
218	(void)strlcpy(pargs.pa_name, puffsname, sizeof(pargs.pa_name));
219
220	pu = malloc(sizeof(struct puffs_usermount));
221	if (!pu)
222		return NULL;
223
224	pu->pu_flags = pflags;
225	pu->pu_ops = *pops;
226	free(pops); /* XXX */
227	pu->pu_fd = fd;
228	pu->pu_privdata = priv;
229	pu->pu_cc_stacksize = PUFFS_CC_STACKSIZE_DEFAULT;
230	LIST_INIT(&pu->pu_pnodelst);
231
232	/* defaults for some user-settable translation functions */
233	pu->pu_cmap = NULL; /* identity translation */
234
235	pu->pu_pathbuild = puffs_stdpath_buildpath;
236	pu->pu_pathfree = puffs_stdpath_freepath;
237	pu->pu_pathcmp = puffs_stdpath_cmppath;
238	pu->pu_pathtransform = NULL;
239	pu->pu_namemod = NULL;
240
241	pu->pu_state = PUFFS_STATE_MOUNTING;
242	if (mount(MOUNT_PUFFS, dir, mntflags, &pargs) == -1)
243		goto failfree;
244	pu->pu_maxreqlen = pargs.pa_maxreqlen;
245
246	return pu;
247
248 failfree:
249	/* can't unmount() from here for obvious reasons */
250	if (fd)
251		close(fd);
252	free(pu);
253	return NULL;
254}
255
256int
257puffs_start(struct puffs_usermount *pu, void *rootcookie, struct statvfs *sbp)
258{
259	struct puffs_startreq sreq;
260
261	memset(&sreq, 0, sizeof(struct puffs_startreq));
262	sreq.psr_cookie = rootcookie;
263	sreq.psr_sb = *sbp;
264
265	/* tell kernel we're flying */
266	if (ioctl(pu->pu_fd, PUFFSSTARTOP, &sreq) == -1)
267		return -1;
268
269	pu->pu_state = PUFFS_STATE_RUNNING;
270
271	return 0;
272}
273
274/*
275 * XXX: there's currently no clean way to request unmount from
276 * within the user server, so be very brutal about it.
277 */
278/*ARGSUSED*/
279int
280puffs_exit(struct puffs_usermount *pu, int force)
281{
282	struct puffs_node *pn, *pn_next;
283
284	force = 1; /* currently */
285
286	if (pu->pu_fd)
287		close(pu->pu_fd);
288
289	pn = LIST_FIRST(&pu->pu_pnodelst);
290	while (pn) {
291		pn_next = LIST_NEXT(pn, pn_entries);
292		puffs_pn_put(pn);
293		pn = pn_next;
294	}
295	free(pu);
296
297	return 0; /* always succesful for now, WILL CHANGE */
298}
299
300int
301puffs_mainloop(struct puffs_usermount *pu, int flags)
302{
303	struct puffs_getreq *pgr;
304	struct puffs_putreq *ppr;
305	int rv;
306
307	rv = -1;
308	pgr = puffs_req_makeget(pu, pu->pu_maxreqlen, 0);
309	if (pgr == NULL)
310		return -1;
311
312	ppr = puffs_req_makeput(pu);
313	if (ppr == NULL) {
314		puffs_req_destroyget(pgr);
315		return -1;
316	}
317
318	if ((flags & PUFFSLOOP_NODAEMON) == 0)
319		if (daemon(1, 0) == -1)
320			goto out;
321
322	/* XXX: should be a bit more robust with errors here */
323	while (puffs_getstate(pu) == PUFFS_STATE_RUNNING
324	    || puffs_getstate(pu) == PUFFS_STATE_UNMOUNTING) {
325		puffs_req_resetput(ppr);
326
327		if (puffs_req_handle(pu, pgr, ppr, 0) == -1) {
328			rv = -1;
329			break;
330		}
331		if (puffs_req_putput(ppr) == -1) {
332			rv = -1;
333			break;
334		}
335	}
336
337 out:
338	puffs_req_destroyput(ppr);
339	puffs_req_destroyget(pgr);
340	return rv;
341}
342
343int
344puffs_dopreq(struct puffs_usermount *pu, struct puffs_req *preq,
345	struct puffs_putreq *ppr)
346{
347	struct puffs_cc *pcc;
348	int rv;
349
350	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
351		puffsdump_req(preq);
352
353	pcc = puffs_cc_create(pu);
354
355	/* XXX: temporary kludging */
356	pcc->pcc_preq = malloc(preq->preq_buflen);
357	if (pcc->pcc_preq == NULL)
358		return -1;
359	(void) memcpy(pcc->pcc_preq, preq, preq->preq_buflen);
360
361	rv = puffs_docc(pcc, ppr);
362
363	if ((pcc->pcc_flags & PCC_DONE) == 0)
364		return 0;
365
366	return rv;
367}
368
369int
370puffs_docc(struct puffs_cc *pcc, struct puffs_putreq *ppr)
371{
372	struct puffs_usermount *pu = pcc->pcc_pu;
373	int rv;
374
375	assert((pcc->pcc_flags & PCC_DONE) == 0);
376
377	puffs_cc_continue(pcc);
378	rv = pcc->pcc_rv;
379
380	if ((pcc->pcc_flags & PCC_DONE) == 0)
381		rv = PUFFCALL_AGAIN;
382
383	/* check if we need to store this reply */
384	switch (rv) {
385	case PUFFCALL_ANSWER:
386		if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
387			puffsdump_rv(pcc->pcc_preq);
388
389		puffs_req_putcc(ppr, pcc);
390		break;
391	case PUFFCALL_IGNORE:
392		puffs_cc_destroy(pcc);
393		break;
394	case PUFFCALL_AGAIN:
395		break;
396	default:
397		assert(/*CONSTCOND*/0);
398	}
399
400	return 0;
401}
402
403/* library private, but linked from callcontext.c */
404
405void
406puffs_calldispatcher(struct puffs_cc *pcc)
407{
408	struct puffs_usermount *pu = pcc->pcc_pu;
409	struct puffs_ops *pops = &pu->pu_ops;
410	struct puffs_req *preq = pcc->pcc_preq;
411	void *auxbuf = preq; /* help with typecasting */
412	int error, rv, buildpath;
413
414	assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
415
416	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
417		rv = PUFFCALL_ANSWER;
418	else
419		rv = PUFFCALL_IGNORE;
420
421	buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
422
423	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
424		switch (preq->preq_optype) {
425		case PUFFS_VFS_UNMOUNT:
426		{
427			struct puffs_vfsreq_unmount *auxt = auxbuf;
428
429			pu->pu_state = PUFFS_STATE_UNMOUNTING;
430			error = pops->puffs_fs_unmount(pcc,
431			    auxt->pvfsr_flags, auxt->pvfsr_pid);
432			if (!error)
433				pu->pu_state = PUFFS_STATE_UNMOUNTED;
434			else
435				pu->pu_state = PUFFS_STATE_RUNNING;
436			break;
437		}
438		case PUFFS_VFS_STATVFS:
439		{
440			struct puffs_vfsreq_statvfs *auxt = auxbuf;
441
442			error = pops->puffs_fs_statvfs(pcc,
443			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
444			break;
445		}
446		case PUFFS_VFS_SYNC:
447		{
448			struct puffs_vfsreq_sync *auxt = auxbuf;
449
450			error = pops->puffs_fs_sync(pcc,
451			    auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
452			    auxt->pvfsr_pid);
453			break;
454		}
455		case PUFFS_VFS_SUSPEND:
456		{
457			struct puffs_vfsreq_suspend *auxt = auxbuf;
458
459			error = 0;
460			if (pops->puffs_fs_suspend == NULL)
461				break;
462
463			pops->puffs_fs_suspend(pcc, auxt->pvfsr_status);
464			break;
465		}
466
467		default:
468			/*
469			 * I guess the kernel sees this one coming
470			 */
471			error = EINVAL;
472			break;
473		}
474
475	/* XXX: audit return values */
476	/* XXX: sync with kernel */
477	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
478		switch (preq->preq_optype) {
479		case PUFFS_VN_LOOKUP:
480		{
481			struct puffs_vnreq_lookup *auxt = auxbuf;
482			struct puffs_cn pcn;
483
484			pcn.pcn_pkcnp = &auxt->pvnr_cn;
485			if (buildpath) {
486				error = puffs_path_pcnbuild(pu, &pcn,
487				    preq->preq_cookie);
488				if (error)
489					break;
490			}
491
492			/* lookup *must* be present */
493			error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
494			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
495			    &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
496
497			if (buildpath) {
498				if (error) {
499					pu->pu_pathfree(pu, &pcn.pcn_po_full);
500				} else {
501					struct puffs_node *pn;
502
503					/*
504					 * did we get a new node or a
505					 * recycled node?
506					 */
507					pn = PU_CMAP(pu, auxt->pvnr_newnode);
508					if (pn->pn_po.po_path == NULL)
509						pn->pn_po = pcn.pcn_po_full;
510					else
511						pu->pu_pathfree(pu,
512						    &pcn.pcn_po_full);
513				}
514			}
515
516			break;
517		}
518
519		case PUFFS_VN_CREATE:
520		{
521			struct puffs_vnreq_create *auxt = auxbuf;
522			struct puffs_cn pcn;
523			if (pops->puffs_node_create == NULL) {
524				error = 0;
525				break;
526			}
527
528			pcn.pcn_pkcnp = &auxt->pvnr_cn;
529			if (buildpath) {
530				error = puffs_path_pcnbuild(pu, &pcn,
531				    preq->preq_cookie);
532				if (error)
533					break;
534			}
535
536			error = pops->puffs_node_create(pcc,
537			    preq->preq_cookie, &auxt->pvnr_newnode,
538			    &pcn, &auxt->pvnr_va);
539
540			if (buildpath) {
541				if (error) {
542					pu->pu_pathfree(pu, &pcn.pcn_po_full);
543				} else {
544					struct puffs_node *pn;
545
546					pn = PU_CMAP(pu, auxt->pvnr_newnode);
547					pn->pn_po = pcn.pcn_po_full;
548				}
549			}
550
551			break;
552		}
553
554		case PUFFS_VN_MKNOD:
555		{
556			struct puffs_vnreq_mknod *auxt = auxbuf;
557			struct puffs_cn pcn;
558			if (pops->puffs_node_mknod == NULL) {
559				error = 0;
560				break;
561			}
562
563			pcn.pcn_pkcnp = &auxt->pvnr_cn;
564			if (buildpath) {
565				error = puffs_path_pcnbuild(pu, &pcn,
566				    preq->preq_cookie);
567				if (error)
568					break;
569			}
570
571			error = pops->puffs_node_mknod(pcc,
572			    preq->preq_cookie, &auxt->pvnr_newnode,
573			    &pcn, &auxt->pvnr_va);
574
575			if (buildpath) {
576				if (error) {
577					pu->pu_pathfree(pu, &pcn.pcn_po_full);
578				} else {
579					struct puffs_node *pn;
580
581					pn = PU_CMAP(pu, auxt->pvnr_newnode);
582					pn->pn_po = pcn.pcn_po_full;
583				}
584			}
585
586			break;
587		}
588
589		case PUFFS_VN_OPEN:
590		{
591			struct puffs_vnreq_open *auxt = auxbuf;
592			if (pops->puffs_node_open == NULL) {
593				error = 0;
594				break;
595			}
596
597			error = pops->puffs_node_open(pcc,
598			    preq->preq_cookie, auxt->pvnr_mode,
599			    &auxt->pvnr_cred, auxt->pvnr_pid);
600			break;
601		}
602
603		case PUFFS_VN_CLOSE:
604		{
605			struct puffs_vnreq_close *auxt = auxbuf;
606			if (pops->puffs_node_close == NULL) {
607				error = 0;
608				break;
609			}
610
611			error = pops->puffs_node_close(pcc,
612			    preq->preq_cookie, auxt->pvnr_fflag,
613			    &auxt->pvnr_cred, auxt->pvnr_pid);
614			break;
615		}
616
617		case PUFFS_VN_ACCESS:
618		{
619			struct puffs_vnreq_access *auxt = auxbuf;
620			if (pops->puffs_node_access == NULL) {
621				error = 0;
622				break;
623			}
624
625			error = pops->puffs_node_access(pcc,
626			    preq->preq_cookie, auxt->pvnr_mode,
627			    &auxt->pvnr_cred, auxt->pvnr_pid);
628			break;
629		}
630
631		case PUFFS_VN_GETATTR:
632		{
633			struct puffs_vnreq_getattr *auxt = auxbuf;
634			if (pops->puffs_node_getattr == NULL) {
635				error = EOPNOTSUPP;
636				break;
637			}
638
639			error = pops->puffs_node_getattr(pcc,
640			    preq->preq_cookie, &auxt->pvnr_va,
641			    &auxt->pvnr_cred, auxt->pvnr_pid);
642			break;
643		}
644
645		case PUFFS_VN_SETATTR:
646		{
647			struct puffs_vnreq_setattr *auxt = auxbuf;
648			if (pops->puffs_node_setattr == NULL) {
649				error = EOPNOTSUPP;
650				break;
651			}
652
653			error = pops->puffs_node_setattr(pcc,
654			    preq->preq_cookie, &auxt->pvnr_va,
655			    &auxt->pvnr_cred, auxt->pvnr_pid);
656			break;
657		}
658
659		case PUFFS_VN_MMAP:
660		{
661			struct puffs_vnreq_mmap *auxt = auxbuf;
662			if (pops->puffs_node_mmap == NULL) {
663				error = 0;
664				break;
665			}
666
667			error = pops->puffs_node_mmap(pcc,
668			    preq->preq_cookie, auxt->pvnr_fflags,
669			    &auxt->pvnr_cred, auxt->pvnr_pid);
670			break;
671		}
672
673		case PUFFS_VN_FSYNC:
674		{
675			struct puffs_vnreq_fsync *auxt = auxbuf;
676			if (pops->puffs_node_fsync == NULL) {
677				error = 0;
678				break;
679			}
680
681			error = pops->puffs_node_fsync(pcc,
682			    preq->preq_cookie, &auxt->pvnr_cred,
683			    auxt->pvnr_flags, auxt->pvnr_offlo,
684			    auxt->pvnr_offhi, auxt->pvnr_pid);
685			break;
686		}
687
688		case PUFFS_VN_SEEK:
689		{
690			struct puffs_vnreq_seek *auxt = auxbuf;
691			if (pops->puffs_node_seek == NULL) {
692				error = 0;
693				break;
694			}
695
696			error = pops->puffs_node_seek(pcc,
697			    preq->preq_cookie, auxt->pvnr_oldoff,
698			    auxt->pvnr_newoff, &auxt->pvnr_cred);
699			break;
700		}
701
702		case PUFFS_VN_REMOVE:
703		{
704			struct puffs_vnreq_remove *auxt = auxbuf;
705			struct puffs_cn pcn;
706			if (pops->puffs_node_remove == NULL) {
707				error = 0;
708				break;
709			}
710
711			pcn.pcn_pkcnp = &auxt->pvnr_cn;
712
713			error = pops->puffs_node_remove(pcc,
714			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
715			break;
716		}
717
718		case PUFFS_VN_LINK:
719		{
720			struct puffs_vnreq_link *auxt = auxbuf;
721			struct puffs_cn pcn;
722			if (pops->puffs_node_link == NULL) {
723				error = 0;
724				break;
725			}
726
727			pcn.pcn_pkcnp = &auxt->pvnr_cn;
728			if (buildpath) {
729				error = puffs_path_pcnbuild(pu, &pcn,
730				    preq->preq_cookie);
731				if (error)
732					break;
733			}
734
735			error = pops->puffs_node_link(pcc,
736			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
737			if (buildpath)
738				pu->pu_pathfree(pu, &pcn.pcn_po_full);
739
740			break;
741		}
742
743		case PUFFS_VN_RENAME:
744		{
745			struct puffs_vnreq_rename *auxt = auxbuf;
746			struct puffs_cn pcn_src, pcn_targ;
747			struct puffs_node *pn_src;
748
749			if (pops->puffs_node_rename == NULL) {
750				error = 0;
751				break;
752			}
753
754			pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
755			pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
756			if (buildpath) {
757				pn_src = auxt->pvnr_cookie_src;
758				pcn_src.pcn_po_full = pn_src->pn_po;
759
760				error = puffs_path_pcnbuild(pu, &pcn_targ,
761				    auxt->pvnr_cookie_targdir);
762				if (error)
763					break;
764			}
765
766			error = pops->puffs_node_rename(pcc,
767			    preq->preq_cookie, auxt->pvnr_cookie_src,
768			    &pcn_src, auxt->pvnr_cookie_targdir,
769			    auxt->pvnr_cookie_targ, &pcn_targ);
770
771			if (buildpath) {
772				if (error) {
773					pu->pu_pathfree(pu,
774					    &pcn_targ.pcn_po_full);
775				} else {
776					struct puffs_pathinfo pi;
777					struct puffs_pathobj po_old;
778
779					/* handle this node */
780					po_old = pn_src->pn_po;
781					pn_src->pn_po = pcn_targ.pcn_po_full;
782
783					if (pn_src->pn_va.va_type != VDIR) {
784						pu->pu_pathfree(pu, &po_old);
785						break;
786					}
787
788					/* handle all child nodes for DIRs */
789					pi.pi_old = &pcn_src.pcn_po_full;
790					pi.pi_new = &pcn_targ.pcn_po_full;
791
792					if (puffs_pn_nodewalk(pu,
793					    puffs_path_prefixadj, &pi) != NULL)
794						error = ENOMEM;
795					pu->pu_pathfree(pu, &po_old);
796				}
797			}
798			break;
799		}
800
801		case PUFFS_VN_MKDIR:
802		{
803			struct puffs_vnreq_mkdir *auxt = auxbuf;
804			struct puffs_cn pcn;
805			if (pops->puffs_node_mkdir == NULL) {
806				error = 0;
807				break;
808			}
809
810			pcn.pcn_pkcnp = &auxt->pvnr_cn;
811			if (buildpath) {
812				error = puffs_path_pcnbuild(pu, &pcn,
813				    preq->preq_cookie);
814				if (error)
815					break;
816			}
817
818			error = pops->puffs_node_mkdir(pcc,
819			    preq->preq_cookie, &auxt->pvnr_newnode,
820			    &pcn, &auxt->pvnr_va);
821
822			if (buildpath) {
823				if (error) {
824					pu->pu_pathfree(pu, &pcn.pcn_po_full);
825				} else {
826					struct puffs_node *pn;
827
828					pn = PU_CMAP(pu, auxt->pvnr_newnode);
829					pn->pn_po = pcn.pcn_po_full;
830				}
831			}
832
833			break;
834		}
835
836		case PUFFS_VN_RMDIR:
837		{
838			struct puffs_vnreq_rmdir *auxt = auxbuf;
839			struct puffs_cn pcn;
840			if (pops->puffs_node_rmdir == NULL) {
841				error = 0;
842				break;
843			}
844
845			pcn.pcn_pkcnp = &auxt->pvnr_cn;
846
847			error = pops->puffs_node_rmdir(pcc,
848			    preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
849			break;
850		}
851
852		case PUFFS_VN_SYMLINK:
853		{
854			struct puffs_vnreq_symlink *auxt = auxbuf;
855			struct puffs_cn pcn;
856			if (pops->puffs_node_symlink == NULL) {
857				error = 0;
858				break;
859			}
860
861			pcn.pcn_pkcnp = &auxt->pvnr_cn;
862			if (buildpath) {
863				error = puffs_path_pcnbuild(pu, &pcn,
864				    preq->preq_cookie);
865				if (error)
866					break;
867			}
868
869			error = pops->puffs_node_symlink(pcc,
870			    preq->preq_cookie, &auxt->pvnr_newnode,
871			    &pcn, &auxt->pvnr_va, auxt->pvnr_link);
872
873			if (buildpath) {
874				if (error) {
875					pu->pu_pathfree(pu, &pcn.pcn_po_full);
876				} else {
877					struct puffs_node *pn;
878
879					pn = PU_CMAP(pu, auxt->pvnr_newnode);
880					pn->pn_po = pcn.pcn_po_full;
881				}
882			}
883
884			break;
885		}
886
887		case PUFFS_VN_READDIR:
888		{
889			struct puffs_vnreq_readdir *auxt = auxbuf;
890			size_t res;
891
892			if (pops->puffs_node_readdir == NULL) {
893				error = 0;
894				break;
895			}
896
897			res = auxt->pvnr_resid;
898			error = pops->puffs_node_readdir(pcc,
899			    preq->preq_cookie, auxt->pvnr_dent,
900			    &auxt->pvnr_cred, &auxt->pvnr_offset,
901			    &auxt->pvnr_resid);
902
903			/* need to move a bit more */
904			preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
905			    + (res - auxt->pvnr_resid);
906			break;
907		}
908
909		case PUFFS_VN_READLINK:
910		{
911			struct puffs_vnreq_readlink *auxt = auxbuf;
912			if (pops->puffs_node_readlink == NULL) {
913				error = EOPNOTSUPP;
914				break;
915			}
916
917			error = pops->puffs_node_readlink(pcc,
918			    preq->preq_cookie, &auxt->pvnr_cred,
919			    auxt->pvnr_link, &auxt->pvnr_linklen);
920			break;
921		}
922
923		case PUFFS_VN_RECLAIM:
924		{
925			struct puffs_vnreq_reclaim *auxt = auxbuf;
926			if (pops->puffs_node_reclaim == NULL) {
927				error = 0;
928				break;
929			}
930
931			error = pops->puffs_node_reclaim(pcc,
932			    preq->preq_cookie, auxt->pvnr_pid);
933			break;
934		}
935
936		case PUFFS_VN_INACTIVE:
937		{
938			struct puffs_vnreq_inactive *auxt = auxbuf;
939			if (pops->puffs_node_inactive == NULL) {
940				error = EOPNOTSUPP;
941				break;
942			}
943
944			error = pops->puffs_node_inactive(pcc,
945			    preq->preq_cookie, auxt->pvnr_pid,
946			    &auxt->pvnr_backendrefs);
947			break;
948		}
949
950		case PUFFS_VN_PATHCONF:
951		{
952			struct puffs_vnreq_pathconf *auxt = auxbuf;
953			if (pops->puffs_node_pathconf == NULL) {
954				error = 0;
955				break;
956			}
957
958			error = pops->puffs_node_pathconf(pcc,
959			    preq->preq_cookie, auxt->pvnr_name,
960			    &auxt->pvnr_retval);
961			break;
962		}
963
964		case PUFFS_VN_ADVLOCK:
965		{
966			struct puffs_vnreq_advlock *auxt = auxbuf;
967			if (pops->puffs_node_advlock == NULL) {
968				error = 0;
969				break;
970			}
971
972			error = pops->puffs_node_advlock(pcc,
973			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
974			    &auxt->pvnr_fl, auxt->pvnr_flags);
975			break;
976		}
977
978		case PUFFS_VN_PRINT:
979		{
980			if (pops->puffs_node_print == NULL) {
981				error = 0;
982				break;
983			}
984
985			error = pops->puffs_node_print(pcc,
986			    preq->preq_cookie);
987			break;
988		}
989
990		case PUFFS_VN_READ:
991		{
992			struct puffs_vnreq_read *auxt = auxbuf;
993			size_t res;
994
995			if (pops->puffs_node_read == NULL) {
996				error = EIO;
997				break;
998			}
999
1000			res = auxt->pvnr_resid;
1001			error = pops->puffs_node_read(pcc,
1002			    preq->preq_cookie, auxt->pvnr_data,
1003			    auxt->pvnr_offset, &auxt->pvnr_resid,
1004			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
1005
1006			/* need to move a bit more */
1007			preq->preq_buflen = sizeof(struct puffs_vnreq_read)
1008			    + (res - auxt->pvnr_resid);
1009			break;
1010		}
1011
1012		case PUFFS_VN_WRITE:
1013		{
1014			struct puffs_vnreq_write *auxt = auxbuf;
1015
1016			if (pops->puffs_node_write == NULL) {
1017				error = EIO;
1018				break;
1019			}
1020
1021			error = pops->puffs_node_write(pcc,
1022			    preq->preq_cookie, auxt->pvnr_data,
1023			    auxt->pvnr_offset, &auxt->pvnr_resid,
1024			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
1025
1026			/* don't need to move data back to the kernel */
1027			preq->preq_buflen = sizeof(struct puffs_vnreq_write);
1028			break;
1029		}
1030
1031/* holy bitrot, ryydman! */
1032#if 0
1033		case PUFFS_VN_IOCTL:
1034			error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
1035			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1036			if (error != 0)
1037				break;
1038			pop.pso_reqid = preq->preq_id;
1039
1040			/* let the kernel do it's intermediate duty */
1041			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
1042			/*
1043			 * XXX: I don't actually know what the correct
1044			 * thing to do in case of an error is, so I'll
1045			 * just ignore it for the time being.
1046			 */
1047			error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
1048			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1049			break;
1050
1051		case PUFFS_VN_FCNTL:
1052			error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
1053			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1054			if (error != 0)
1055				break;
1056			pop.pso_reqid = preq->preq_id;
1057
1058			/* let the kernel do it's intermediate duty */
1059			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
1060			/*
1061			 * XXX: I don't actually know what the correct
1062			 * thing to do in case of an error is, so I'll
1063			 * just ignore it for the time being.
1064			 */
1065			error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
1066			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1067			break;
1068#endif
1069
1070		default:
1071			printf("inval op %d\n", preq->preq_optype);
1072			error = EINVAL;
1073			break;
1074		}
1075	} else {
1076		/*
1077		 * this one also
1078		 */
1079		error = EINVAL;
1080	}
1081
1082	preq->preq_rv = error;
1083
1084	pcc->pcc_rv = rv;
1085	pcc->pcc_flags |= PCC_DONE;
1086}
1087
1088
1089#if 0
1090		case PUFFS_VN_POLL:
1091		{
1092			struct puffs_vnreq_poll *auxt = auxbuf;
1093			if (pops->puffs_node_poll == NULL) {
1094				error = 0;
1095				break;
1096			}
1097
1098			error = pops->puffs_node_poll(pcc,
1099			    preq->preq_cookie, preq-);
1100			break;
1101		}
1102
1103		case PUFFS_VN_KQFILTER:
1104		{
1105			struct puffs_vnreq_kqfilter *auxt = auxbuf;
1106			if (pops->puffs_node_kqfilter == NULL) {
1107				error = 0;
1108				break;
1109			}
1110
1111			error = pops->puffs_node_kqfilter(pcc,
1112			    preq->preq_cookie, );
1113			break;
1114		}
1115
1116		case PUFFS_VN_CLOSEEXTATTR:
1117		{
1118			struct puffs_vnreq_closeextattr *auxt = auxbuf;
1119			if (pops->puffs_closeextattr == NULL) {
1120				error = 0;
1121				break;
1122			}
1123
1124			error = pops->puffs_closeextattr(pcc,
1125			    preq->preq_cookie, );
1126			break;
1127		}
1128
1129		case PUFFS_VN_GETEXTATTR:
1130		{
1131			struct puffs_vnreq_getextattr *auxt = auxbuf;
1132			if (pops->puffs_getextattr == NULL) {
1133				error = 0;
1134				break;
1135			}
1136
1137			error = pops->puffs_getextattr(pcc,
1138			    preq->preq_cookie, );
1139			break;
1140		}
1141
1142		case PUFFS_VN_LISTEXTATTR:
1143		{
1144			struct puffs_vnreq_listextattr *auxt = auxbuf;
1145			if (pops->puffs_listextattr == NULL) {
1146				error = 0;
1147				break;
1148			}
1149
1150			error = pops->puffs_listextattr(pcc,
1151			    preq->preq_cookie, );
1152			break;
1153		}
1154
1155		case PUFFS_VN_OPENEXTATTR:
1156		{
1157			struct puffs_vnreq_openextattr *auxt = auxbuf;
1158			if (pops->puffs_openextattr == NULL) {
1159				error = 0;
1160				break;
1161			}
1162
1163			error = pops->puffs_openextattr(pcc,
1164			    preq->preq_cookie, );
1165			break;
1166		}
1167
1168		case PUFFS_VN_DELETEEXTATTR:
1169		{
1170			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
1171			if (pops->puffs_deleteextattr == NULL) {
1172				error = 0;
1173				break;
1174			}
1175
1176			error = pops->puffs_deleteextattr(pcc,
1177			    preq->preq_cookie, );
1178			break;
1179		}
1180
1181		case PUFFS_VN_SETEXTATTR:
1182		{
1183			struct puffs_vnreq_setextattr *auxt = auxbuf;
1184			if (pops->puffs_setextattr == NULL) {
1185				error = 0;
1186				break;
1187			}
1188
1189			error = pops->puffs_setextattr(pcc,
1190			    preq->preq_cookie, );
1191			break;
1192		}
1193
1194#endif
1195