Annotation of src/lib/libpuffs/puffs.c, Revision 1.92.4.3
1.92.4.3! sborrill 1: /* $NetBSD: puffs.c,v 1.92.4.2 2009/10/16 12:10:54 sborrill Exp $ */
1.1 pooka 2:
3: /*
1.44 pooka 4: * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
1.1 pooka 5: *
6: * Development of this software was supported by the
7: * Google Summer of Code program and the Ulla Tuominen Foundation.
8: * The Google SoC project was mentored by Bill Studenmund.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h>
33: #if !defined(lint)
1.92.4.3! sborrill 34: __RCSID("$NetBSD: puffs.c,v 1.92.4.2 2009/10/16 12:10:54 sborrill Exp $");
1.1 pooka 35: #endif /* !lint */
36:
37: #include <sys/param.h>
38: #include <sys/mount.h>
39:
1.9 pooka 40: #include <assert.h>
1.12 pooka 41: #include <err.h>
1.1 pooka 42: #include <errno.h>
43: #include <fcntl.h>
1.21 pooka 44: #include <mntopts.h>
1.58 pooka 45: #include <paths.h>
1.1 pooka 46: #include <puffs.h>
47: #include <stdio.h>
48: #include <stdlib.h>
49: #include <string.h>
50: #include <syslog.h>
51: #include <unistd.h>
52:
1.19 pooka 53: #include "puffs_priv.h"
54:
1.21 pooka 55: /* Most file systems want this for opts, so just give it to them */
56: const struct mntopt puffsmopts[] = {
57: MOPT_STDOPTS,
58: PUFFSMOPT_STD,
59: MOPT_NULL,
60: };
61:
1.72 pooka 62: #ifdef PUFFS_WITH_THREADS
63: #include <pthread.h>
64: pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
65: #endif
66:
1.10 pooka 67: #define FILLOP(lower, upper) \
68: do { \
1.13 pooka 69: if (pops->puffs_node_##lower) \
1.10 pooka 70: opmask[PUFFS_VN_##upper] = 1; \
71: } while (/*CONSTCOND*/0)
72: static void
1.13 pooka 73: fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
1.10 pooka 74: {
75:
76: memset(opmask, 0, PUFFS_VN_MAX);
77:
78: FILLOP(create, CREATE);
79: FILLOP(mknod, MKNOD);
80: FILLOP(open, OPEN);
81: FILLOP(close, CLOSE);
82: FILLOP(access, ACCESS);
83: FILLOP(getattr, GETATTR);
84: FILLOP(setattr, SETATTR);
85: FILLOP(poll, POLL); /* XXX: not ready in kernel */
1.16 pooka 86: FILLOP(mmap, MMAP);
1.10 pooka 87: FILLOP(fsync, FSYNC);
88: FILLOP(seek, SEEK);
89: FILLOP(remove, REMOVE);
90: FILLOP(link, LINK);
91: FILLOP(rename, RENAME);
92: FILLOP(mkdir, MKDIR);
93: FILLOP(rmdir, RMDIR);
94: FILLOP(symlink, SYMLINK);
95: FILLOP(readdir, READDIR);
96: FILLOP(readlink, READLINK);
97: FILLOP(reclaim, RECLAIM);
98: FILLOP(inactive, INACTIVE);
99: FILLOP(print, PRINT);
100: FILLOP(read, READ);
101: FILLOP(write, WRITE);
1.92.4.3! sborrill 102: FILLOP(abortop, ABORTOP);
1.19 pooka 103: }
104: #undef FILLOP
105:
1.79 pooka 106: /*
107: * Go over all framev entries and write everything we can. This is
108: * mostly for the benefit of delivering "unmount" to the kernel.
109: */
110: static void
111: finalpush(struct puffs_usermount *pu)
112: {
113: struct puffs_fctrl_io *fio;
114:
115: LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
116: if (fio->stat & FIO_WRGONE)
117: continue;
118:
1.89 pooka 119: puffs__framev_output(pu, fio->fctrl, fio);
1.79 pooka 120: }
121: }
122:
1.64 pooka 123: /*ARGSUSED*/
1.63 pooka 124: static void
125: puffs_defaulterror(struct puffs_usermount *pu, uint8_t type,
1.92 pooka 126: int error, const char *str, puffs_cookie_t cookie)
1.63 pooka 127: {
128:
1.77 pooka 129: fprintf(stderr, "abort: type %d, error %d, cookie %p (%s)\n",
130: type, error, cookie, str);
1.63 pooka 131: abort();
132: }
133:
1.19 pooka 134: int
135: puffs_getselectable(struct puffs_usermount *pu)
136: {
1.10 pooka 137:
1.60 pooka 138: return pu->pu_fd;
1.10 pooka 139: }
1.19 pooka 140:
1.80 pooka 141: uint64_t
142: puffs__nextreq(struct puffs_usermount *pu)
143: {
144: uint64_t rv;
145:
146: PU_LOCK();
147: rv = pu->pu_nextreq++;
148: PU_UNLOCK();
149:
150: return rv;
151: }
152:
1.19 pooka 153: int
154: puffs_setblockingmode(struct puffs_usermount *pu, int mode)
155: {
1.46 pooka 156: int rv, x;
157:
1.74 pooka 158: assert(puffs_getstate(pu) == PUFFS_STATE_RUNNING);
159:
1.46 pooka 160: if (mode != PUFFSDEV_BLOCK && mode != PUFFSDEV_NONBLOCK) {
161: errno = EINVAL;
162: return -1;
163: }
1.19 pooka 164:
165: x = mode;
1.60 pooka 166: rv = ioctl(pu->pu_fd, FIONBIO, &x);
1.46 pooka 167:
168: if (rv == 0) {
169: if (mode == PUFFSDEV_BLOCK)
170: pu->pu_state &= ~PU_ASYNCFD;
171: else
172: pu->pu_state |= PU_ASYNCFD;
173: }
174:
175: return rv;
1.19 pooka 176: }
177:
178: int
179: puffs_getstate(struct puffs_usermount *pu)
180: {
181:
1.44 pooka 182: return pu->pu_state & PU_STATEMASK;
1.19 pooka 183: }
184:
185: void
186: puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
187: {
1.86 pooka 188: long psize, minsize;
1.69 pooka 189: int stackshift;
1.87 pooka 190: int bonus;
1.78 pooka 191:
1.86 pooka 192: assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT);
193:
1.78 pooka 194: psize = sysconf(_SC_PAGESIZE);
1.87 pooka 195: minsize = 4*psize;
1.86 pooka 196: if (ss < minsize || ss == PUFFS_STACKSIZE_MIN) {
197: if (ss != PUFFS_STACKSIZE_MIN)
198: fprintf(stderr, "puffs_setstacksize: adjusting "
199: "stacksize to minimum %ld\n", minsize);
1.87 pooka 200: ss = 4*psize;
1.78 pooka 201: }
1.69 pooka 202:
203: stackshift = -1;
1.87 pooka 204: bonus = 0;
1.69 pooka 205: while (ss) {
1.87 pooka 206: if (ss & 0x1)
207: bonus++;
1.69 pooka 208: ss >>= 1;
209: stackshift++;
210: }
1.87 pooka 211: if (bonus > 1) {
212: stackshift++;
213: fprintf(stderr, "puffs_setstacksize: using next power of two: "
1.88 pooka 214: "%d\n", 1<<stackshift);
1.87 pooka 215: }
216:
1.69 pooka 217: pu->pu_cc_stackshift = stackshift;
1.19 pooka 218: }
219:
1.24 pooka 220: struct puffs_pathobj *
221: puffs_getrootpathobj(struct puffs_usermount *pu)
1.19 pooka 222: {
223: struct puffs_node *pnr;
224:
225: pnr = pu->pu_pn_root;
226: if (pnr == NULL) {
227: errno = ENOENT;
1.24 pooka 228: return NULL;
1.19 pooka 229: }
230:
1.24 pooka 231: return &pnr->pn_po;
232: }
233:
1.35 pooka 234: void
235: puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
236: {
237:
238: pu->pu_pn_root = pn;
239: }
240:
241: struct puffs_node *
242: puffs_getroot(struct puffs_usermount *pu)
243: {
244:
245: return pu->pu_pn_root;
246: }
247:
1.49 pooka 248: void
249: puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt,
250: vsize_t vsize, dev_t rdev)
251: {
1.60 pooka 252: struct puffs_kargs *pargs = pu->pu_kargp;
1.49 pooka 253:
1.60 pooka 254: if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) {
1.49 pooka 255: warnx("puffs_setrootinfo: call has effect only "
256: "before mount\n");
1.60 pooka 257: return;
258: }
1.49 pooka 259:
260: pargs->pa_root_vtype = vt;
261: pargs->pa_root_vsize = vsize;
262: pargs->pa_root_rdev = rdev;
263: }
264:
1.35 pooka 265: void *
266: puffs_getspecific(struct puffs_usermount *pu)
267: {
268:
269: return pu->pu_privdata;
270: }
271:
1.92.4.1 sborrill 272: void
273: puffs_setspecific(struct puffs_usermount *pu, void *privdata)
274: {
275:
276: pu->pu_privdata = privdata;
277: }
278:
1.35 pooka 279: size_t
280: puffs_getmaxreqlen(struct puffs_usermount *pu)
281: {
282:
1.60 pooka 283: return pu->pu_maxreqlen;
1.35 pooka 284: }
1.24 pooka 285:
286: void
1.37 pooka 287: puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen)
288: {
289:
1.44 pooka 290: if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
1.37 pooka 291: warnx("puffs_setmaxreqlen: call has effect only "
292: "before mount\n");
293:
1.66 pooka 294: pu->pu_kargp->pa_maxmsglen = reqlen;
1.37 pooka 295: }
296:
297: void
1.38 pooka 298: puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags)
1.37 pooka 299: {
300:
1.44 pooka 301: if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
1.37 pooka 302: warnx("puffs_setfhsize: call has effect only before mount\n");
303:
1.60 pooka 304: pu->pu_kargp->pa_fhsize = fhsize;
305: pu->pu_kargp->pa_fhflags = flags;
1.37 pooka 306: }
307:
308: void
309: puffs_setncookiehash(struct puffs_usermount *pu, int nhash)
310: {
311:
1.44 pooka 312: if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
1.37 pooka 313: warnx("puffs_setfhsize: call has effect only before mount\n");
314:
1.60 pooka 315: pu->pu_kargp->pa_nhashbuckets = nhash;
1.37 pooka 316: }
317:
318: void
1.24 pooka 319: puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
320: {
321:
322: pu->pu_pathbuild = fn;
323: }
324:
325: void
326: puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
327: {
328:
329: pu->pu_pathtransform = fn;
330: }
331:
332: void
333: puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
334: {
335:
336: pu->pu_pathcmp = fn;
337: }
338:
339: void
340: puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
341: {
1.19 pooka 342:
1.24 pooka 343: pu->pu_pathfree = fn;
1.19 pooka 344: }
345:
1.24 pooka 346: void
347: puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
348: {
349:
350: pu->pu_namemod = fn;
351: }
1.19 pooka 352:
1.40 pooka 353: void
1.63 pooka 354: puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn)
355: {
356:
357: pu->pu_errnotify = fn;
358: }
359:
360: void
1.81 pooka 361: puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn)
362: {
363:
364: pu->pu_cmap = fn;
365: }
366:
367: void
1.46 pooka 368: puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn)
369: {
370:
371: pu->pu_ml_lfn = lfn;
372: }
373:
374: void
375: puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts)
376: {
377:
378: if (ts == NULL) {
379: pu->pu_ml_timep = NULL;
380: } else {
381: pu->pu_ml_timeout = *ts;
382: pu->pu_ml_timep = &pu->pu_ml_timeout;
383: }
384: }
385:
386: void
1.71 pooka 387: puffs_set_prepost(struct puffs_usermount *pu,
388: pu_prepost_fn pre, pu_prepost_fn pst)
389: {
390:
391: pu->pu_oppre = pre;
392: pu->pu_oppost = pst;
393: }
394:
395: void
1.40 pooka 396: puffs_setback(struct puffs_cc *pcc, int whatback)
397: {
1.79 pooka 398: struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
1.40 pooka 399:
400: assert(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && (
401: preq->preq_optype == PUFFS_VN_OPEN ||
402: preq->preq_optype == PUFFS_VN_MMAP ||
403: preq->preq_optype == PUFFS_VN_REMOVE ||
1.54 pooka 404: preq->preq_optype == PUFFS_VN_RMDIR ||
405: preq->preq_optype == PUFFS_VN_INACTIVE));
1.40 pooka 406:
407: preq->preq_setbacks |= whatback & PUFFS_SETBACK_MASK;
408: }
409:
1.36 pooka 410: int
1.75 pooka 411: puffs_daemon(struct puffs_usermount *pu, int nochdir, int noclose)
412: {
413: ssize_t n;
414: int parent, value, fd;
415:
416: if (pipe(pu->pu_dpipe) == -1)
417: return -1;
418:
419: switch (fork()) {
420: case -1:
421: return -1;
422: case 0:
423: parent = 0;
424: break;
425: default:
426: parent = 1;
427: break;
428: }
429: pu->pu_state |= PU_PUFFSDAEMON;
430:
431: if (parent) {
432: n = read(pu->pu_dpipe[0], &value, sizeof(int));
433: if (n == -1)
434: err(1, "puffs_daemon");
435: assert(n == sizeof(value));
436: if (value) {
437: errno = value;
438: err(1, "puffs_daemon");
439: }
440: exit(0);
441: } else {
442: if (setsid() == -1)
443: goto fail;
444:
445: if (!nochdir)
446: chdir("/");
447:
448: if (!noclose) {
449: fd = open(_PATH_DEVNULL, O_RDWR, 0);
450: if (fd == -1)
451: goto fail;
452: dup2(fd, STDIN_FILENO);
453: dup2(fd, STDOUT_FILENO);
454: dup2(fd, STDERR_FILENO);
455: if (fd > STDERR_FILENO)
456: close(fd);
457: }
458: return 0;
459: }
460:
461: fail:
462: n = write(pu->pu_dpipe[1], &errno, sizeof(int));
463: assert(n == 4);
464: return -1;
465: }
466:
1.92.4.2 sborrill 467: static void
468: shutdaemon(struct puffs_usermount *pu, int error)
469: {
470: ssize_t n;
471:
472: n = write(pu->pu_dpipe[1], &error, sizeof(int));
473: assert(n == 4);
474: close(pu->pu_dpipe[0]);
475: close(pu->pu_dpipe[1]);
476: pu->pu_state &= ~PU_PUFFSDAEMON;
477: }
478:
1.75 pooka 479: int
1.49 pooka 480: puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
1.92 pooka 481: puffs_cookie_t cookie)
1.36 pooka 482: {
1.62 pooka 483: char rp[MAXPATHLEN];
1.75 pooka 484: int rv, fd, sverrno;
1.82 pooka 485: char *comfd;
486:
487: pu->pu_kargp->pa_root_cookie = cookie;
1.36 pooka 488:
489: /* XXXkludgehere */
490: /* kauth doesn't provide this service any longer */
491: if (geteuid() != 0)
492: mntflags |= MNT_NOSUID | MNT_NODEV;
493:
1.76 pooka 494: if (realpath(dir, rp) == NULL) {
495: rv = -1;
496: goto out;
497: }
1.62 pooka 498:
499: if (strcmp(dir, rp) != 0) {
500: warnx("puffs_mount: \"%s\" is a relative path.", dir);
501: warnx("puffs_mount: using \"%s\" instead.", rp);
502: }
503:
1.82 pooka 504: /*
505: * Undocumented... Well, documented only here.
506: *
507: * This is used for imaginative purposes. If the env variable is
508: * set, puffs_mount() doesn't do the regular mount procedure.
509: * Rather, it crams the mount data down the comfd and sets comfd as
510: * the puffs descriptor.
511: *
512: * This shouldn't be used unless you can read my mind ( ... or write
513: * it, not to mention execute it, but that's starting to get silly).
514: */
515: if ((comfd = getenv("PUFFS_COMFD")) != NULL) {
516: size_t len;
517:
518: if (sscanf(comfd, "%d", &pu->pu_fd) != 1) {
519: errno = EINVAL;
520: rv = -1;
521: goto out;
522: }
523: /* check that what we got at least resembles an fd */
524: if (fcntl(pu->pu_fd, F_GETFL) == -1) {
525: rv = -1;
526: goto out;
527: }
528:
529: len = strlen(dir)+1;
530:
531: #define allwrite(buf, len) \
532: do { \
533: ssize_t al_rv; \
534: al_rv = write(pu->pu_fd, buf, len); \
535: if (al_rv != len) { \
536: if (al_rv != -1) \
537: errno = EIO; \
538: rv = -1; \
539: abort();\
540: goto out; \
541: } \
542: } while (/*CONSTCOND*/0)
543: allwrite(&len, sizeof(len));
544: allwrite(dir, len);
1.84 pooka 545: len = strlen(pu->pu_kargp->pa_mntfromname)+1;
1.83 pooka 546: allwrite(&len, sizeof(len));
547: allwrite(pu->pu_kargp->pa_mntfromname, len);
1.82 pooka 548: allwrite(&mntflags, sizeof(mntflags));
549: allwrite(pu->pu_kargp, sizeof(*pu->pu_kargp));
550: allwrite(&pu->pu_flags, sizeof(pu->pu_flags));
551: #undef allwrite
552:
553: rv = 0;
554: } else {
555: fd = open(_PATH_PUFFS, O_RDWR);
556: if (fd == -1) {
557: warnx("puffs_mount: cannot open %s", _PATH_PUFFS);
558: rv = -1;
559: goto out;
560: }
561: if (fd <= 2)
562: warnx("puffs_mount: device fd %d (<= 2), sure this is "
563: "what you want?", fd);
564:
565: pu->pu_kargp->pa_fd = pu->pu_fd = fd;
566: if ((rv = mount(MOUNT_PUFFS, rp, mntflags,
567: pu->pu_kargp, sizeof(struct puffs_kargs))) == -1)
568: goto out;
1.74 pooka 569: }
570:
1.49 pooka 571: PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
1.36 pooka 572:
1.60 pooka 573: out:
1.76 pooka 574: if (rv != 0)
575: sverrno = errno;
576: else
577: sverrno = 0;
1.60 pooka 578: free(pu->pu_kargp);
579: pu->pu_kargp = NULL;
580:
1.92.4.2 sborrill 581: if (pu->pu_state & PU_PUFFSDAEMON)
582: shutdaemon(pu, sverrno);
1.75 pooka 583:
584: errno = sverrno;
1.60 pooka 585: return rv;
1.36 pooka 586: }
1.10 pooka 587:
1.92.4.3! sborrill 588: /*ARGSUSED*/
1.1 pooka 589: struct puffs_usermount *
1.92.4.3! sborrill 590: _puffs_init(int dummy, struct puffs_ops *pops, const char *mntfromname,
1.58 pooka 591: const char *puffsname, void *priv, uint32_t pflags)
1.1 pooka 592: {
593: struct puffs_usermount *pu;
1.36 pooka 594: struct puffs_kargs *pargs;
1.74 pooka 595: int sverrno;
1.1 pooka 596:
1.36 pooka 597: pu = malloc(sizeof(struct puffs_usermount));
598: if (pu == NULL)
599: goto failfree;
1.47 pooka 600: memset(pu, 0, sizeof(struct puffs_usermount));
1.1 pooka 601:
1.60 pooka 602: pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs));
603: if (pargs == NULL)
604: goto failfree;
605: memset(pargs, 0, sizeof(struct puffs_kargs));
606:
1.36 pooka 607: pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
608: pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
609: fillvnopmask(pops, pargs->pa_vnopmask);
1.58 pooka 610: (void)strlcpy(pargs->pa_typename, puffsname,
611: sizeof(pargs->pa_typename));
612: (void)strlcpy(pargs->pa_mntfromname, mntfromname,
613: sizeof(pargs->pa_mntfromname));
1.1 pooka 614:
1.49 pooka 615: puffs_zerostatvfs(&pargs->pa_svfsb);
616: pargs->pa_root_cookie = NULL;
617: pargs->pa_root_vtype = VDIR;
618: pargs->pa_root_vsize = 0;
619: pargs->pa_root_rdev = 0;
1.66 pooka 620: pargs->pa_maxmsglen = 0;
1.49 pooka 621:
1.1 pooka 622: pu->pu_flags = pflags;
1.13 pooka 623: pu->pu_ops = *pops;
1.21 pooka 624: free(pops); /* XXX */
1.36 pooka 625:
1.19 pooka 626: pu->pu_privdata = priv;
1.69 pooka 627: pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT;
1.1 pooka 628: LIST_INIT(&pu->pu_pnodelst);
1.79 pooka 629: LIST_INIT(&pu->pu_ios);
630: LIST_INIT(&pu->pu_ios_rmlist);
1.88 pooka 631: LIST_INIT(&pu->pu_ccmagazin);
1.67 pooka 632: TAILQ_INIT(&pu->pu_sched);
1.1 pooka 633:
1.89 pooka 634: pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs__fsframe_read;
635: pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs__fsframe_write;
636: pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs__fsframe_cmp;
637: pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs__fsframe_gotframe;
1.79 pooka 638: pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose;
639:
1.24 pooka 640: /* defaults for some user-settable translation functions */
641: pu->pu_cmap = NULL; /* identity translation */
642:
1.30 pooka 643: pu->pu_pathbuild = puffs_stdpath_buildpath;
644: pu->pu_pathfree = puffs_stdpath_freepath;
645: pu->pu_pathcmp = puffs_stdpath_cmppath;
1.24 pooka 646: pu->pu_pathtransform = NULL;
647: pu->pu_namemod = NULL;
648:
1.63 pooka 649: pu->pu_errnotify = puffs_defaulterror;
650:
1.44 pooka 651: PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT);
1.1 pooka 652:
653: return pu;
1.6 pooka 654:
1.1 pooka 655: failfree:
1.6 pooka 656: /* can't unmount() from here for obvious reasons */
1.60 pooka 657: sverrno = errno;
1.1 pooka 658: free(pu);
1.60 pooka 659: errno = sverrno;
1.1 pooka 660: return NULL;
661: }
662:
1.92.4.2 sborrill 663: void
664: puffs_cancel(struct puffs_usermount *pu, int error)
665: {
666:
667: assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING);
668: shutdaemon(pu, error);
669: free(pu);
670: }
671:
1.21 pooka 672: /*
673: * XXX: there's currently no clean way to request unmount from
674: * within the user server, so be very brutal about it.
675: */
1.36 pooka 676: /*ARGSUSED1*/
1.21 pooka 677: int
678: puffs_exit(struct puffs_usermount *pu, int force)
679: {
1.44 pooka 680: struct puffs_node *pn;
1.21 pooka 681:
682: force = 1; /* currently */
1.92.4.2 sborrill 683: assert((pu->pu_state & PU_PUFFSDAEMON) == 0);
1.21 pooka 684:
1.60 pooka 685: if (pu->pu_fd)
686: close(pu->pu_fd);
1.21 pooka 687:
1.44 pooka 688: while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL)
1.24 pooka 689: puffs_pn_put(pn);
1.44 pooka 690:
1.79 pooka 691: finalpush(pu);
1.89 pooka 692: puffs__framev_exit(pu);
1.91 pooka 693: puffs__cc_exit(pu);
1.68 pooka 694: if (pu->pu_state & PU_HASKQ)
1.44 pooka 695: close(pu->pu_kq);
1.21 pooka 696: free(pu);
697:
698: return 0; /* always succesful for now, WILL CHANGE */
699: }
700:
1.89 pooka 701: /*
702: * Actual mainloop. This is called from a context which can block.
703: * It is called either from puffs_mainloop (indirectly, via
704: * puffs_cc_continue() or from puffs_cc_yield()).
705: */
706: void
707: puffs__theloop(struct puffs_cc *pcc)
1.1 pooka 708: {
1.89 pooka 709: struct puffs_usermount *pu = pcc->pcc_pu;
1.79 pooka 710: struct puffs_framectrl *pfctrl;
1.44 pooka 711: struct puffs_fctrl_io *fio;
1.79 pooka 712: struct kevent *curev;
1.44 pooka 713: size_t nchanges;
1.89 pooka 714: int ndone;
1.44 pooka 715:
1.89 pooka 716: while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
717: /*
718: * Schedule existing requests.
719: */
720: while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
721: TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
722: puffs__goto(pcc);
723: }
1.19 pooka 724:
1.46 pooka 725: if (pu->pu_ml_lfn)
726: pu->pu_ml_lfn(pu);
727:
1.79 pooka 728: /* XXX: can we still do these optimizations? */
729: #if 0
1.55 pooka 730: /*
731: * Do this here, because:
732: * a) loopfunc might generate some results
733: * b) it's still "after" event handling (except for round 1)
734: */
735: if (puffs_req_putput(ppr) == -1)
736: goto out;
737: puffs_req_resetput(ppr);
738:
1.46 pooka 739: /* micro optimization: skip kevent syscall if possible */
1.79 pooka 740: if (pu->pu_nfds == 1 && pu->pu_ml_timep == NULL
1.46 pooka 741: && (pu->pu_state & PU_ASYNCFD) == 0) {
1.79 pooka 742: pfctrl = XXX->fctrl;
743: puffs_framev_input(pu, pfctrl, XXX);
1.46 pooka 744: continue;
745: }
1.79 pooka 746: #endif
1.55 pooka 747:
1.46 pooka 748: /* else: do full processing */
1.79 pooka 749: /* Don't bother worrying about O(n) for now */
750: LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
1.46 pooka 751: if (fio->stat & FIO_WRGONE)
752: continue;
753:
1.79 pooka 754: pfctrl = fio->fctrl;
755:
1.44 pooka 756: /*
757: * Try to write out everything to avoid the
758: * need for enabling EVFILT_WRITE. The likely
759: * case is that we can fit everything into the
760: * socket buffer.
761: */
1.89 pooka 762: puffs__framev_output(pu, pfctrl, fio);
1.79 pooka 763: }
764:
765: /*
766: * Build list of which to enable/disable in writecheck.
767: */
1.80 pooka 768: nchanges = 0;
1.79 pooka 769: LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
770: if (fio->stat & FIO_WRGONE)
771: continue;
1.19 pooka 772:
1.46 pooka 773: /* en/disable write checks for kqueue as needed */
1.44 pooka 774: assert((FIO_EN_WRITE(fio) && FIO_RM_WRITE(fio)) == 0);
775: if (FIO_EN_WRITE(fio)) {
1.79 pooka 776: EV_SET(&pu->pu_evs[nchanges], fio->io_fd,
1.44 pooka 777: EVFILT_WRITE, EV_ENABLE, 0, 0,
778: (uintptr_t)fio);
1.46 pooka 779: fio->stat |= FIO_WR;
1.44 pooka 780: nchanges++;
781: }
782: if (FIO_RM_WRITE(fio)) {
1.79 pooka 783: EV_SET(&pu->pu_evs[nchanges], fio->io_fd,
1.44 pooka 784: EVFILT_WRITE, EV_DISABLE, 0, 0,
785: (uintptr_t)fio);
1.46 pooka 786: fio->stat &= ~FIO_WR;
1.44 pooka 787: nchanges++;
788: }
1.79 pooka 789: assert(nchanges <= pu->pu_nfds);
1.19 pooka 790: }
1.44 pooka 791:
1.79 pooka 792: ndone = kevent(pu->pu_kq, pu->pu_evs, nchanges,
793: pu->pu_evs, 2*pu->pu_nfds, pu->pu_ml_timep);
1.50 pooka 794:
795: if (ndone == -1) {
796: if (errno != EINTR)
1.89 pooka 797: break;
1.50 pooka 798: else
799: continue;
800: }
801:
802: /* uoptimize */
1.46 pooka 803: if (ndone == 0)
804: continue;
1.44 pooka 805:
806: /* iterate over the results */
1.79 pooka 807: for (curev = pu->pu_evs; ndone--; curev++) {
1.61 pooka 808: int what;
809:
1.79 pooka 810: #if 0
1.44 pooka 811: /* get & possibly dispatch events from kernel */
812: if (curev->ident == puffsfd) {
813: if (puffs_req_handle(pgr, ppr, 0) == -1)
814: goto out;
815: continue;
816: }
1.79 pooka 817: #endif
1.44 pooka 818:
1.46 pooka 819: fio = (void *)curev->udata;
1.79 pooka 820: pfctrl = fio->fctrl;
1.46 pooka 821: if (curev->flags & EV_ERROR) {
822: assert(curev->filter == EVFILT_WRITE);
823: fio->stat &= ~FIO_WR;
824:
825: /* XXX: how to know if it's a transient error */
1.89 pooka 826: puffs__framev_writeclose(pu, fio,
1.46 pooka 827: (int)curev->data);
1.89 pooka 828: puffs__framev_notify(fio, PUFFS_FBIO_ERROR);
1.46 pooka 829: continue;
1.44 pooka 830: }
831:
1.61 pooka 832: what = 0;
833: if (curev->filter == EVFILT_READ) {
1.89 pooka 834: puffs__framev_input(pu, pfctrl, fio);
1.61 pooka 835: what |= PUFFS_FBIO_READ;
836: }
1.56 pooka 837:
1.61 pooka 838: else if (curev->filter == EVFILT_WRITE) {
1.89 pooka 839: puffs__framev_output(pu, pfctrl, fio);
1.61 pooka 840: what |= PUFFS_FBIO_WRITE;
841: }
842: if (what)
1.89 pooka 843: puffs__framev_notify(fio, what);
1.67 pooka 844: }
845:
846: /*
1.46 pooka 847: * Really free fd's now that we don't have references
848: * to them.
849: */
1.79 pooka 850: while ((fio = LIST_FIRST(&pu->pu_ios_rmlist)) != NULL) {
1.46 pooka 851: LIST_REMOVE(fio, fio_entries);
852: free(fio);
853: }
1.18 alc 854: }
1.90 pooka 855:
856: if (puffs__cc_restoremain(pu) == -1)
857: warn("cannot restore main context. impending doom");
1.89 pooka 858: }
859:
860: int
861: puffs_mainloop(struct puffs_usermount *pu)
862: {
863: struct puffs_fctrl_io *fio;
864: struct puffs_cc *pcc;
865: struct kevent *curev;
1.90 pooka 866: int sverrno;
1.89 pooka 867:
868: assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
869:
870: pu->pu_kq = kqueue();
871: if (pu->pu_kq == -1)
872: goto out;
873: pu->pu_state |= PU_HASKQ;
874:
875: puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK);
876: if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu),
877: PUFFS_FBIO_READ | PUFFS_FBIO_WRITE,
878: &pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1)
879: goto out;
880:
881: curev = realloc(pu->pu_evs, (2*pu->pu_nfds)*sizeof(struct kevent));
882: if (curev == NULL)
883: goto out;
884: pu->pu_evs = curev;
885:
886: LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
887: EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD,
888: 0, 0, (uintptr_t)fio);
889: curev++;
890: EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE,
891: 0, 0, (uintptr_t)fio);
892: curev++;
893: }
894: if (kevent(pu->pu_kq, pu->pu_evs, 2*pu->pu_nfds, NULL, 0, NULL) == -1)
895: goto out;
896:
897: pu->pu_state |= PU_INLOOP;
898:
1.90 pooka 899: /*
900: * Create alternate execution context and jump to it. Note
901: * that we come "out" of savemain twice. Where we come out
902: * of it depends on the architecture. If the return address is
903: * stored on the stack, we jump out from puffs_cc_continue(),
904: * for a register return address from puffs__cc_savemain().
905: * PU_MAINRESTORE makes sure we DTRT in both cases.
906: */
907: if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) {
1.89 pooka 908: goto out;
1.90 pooka 909: }
910: if (puffs__cc_savemain(pu) == -1) {
911: goto out;
912: }
913: if ((pu->pu_state & PU_MAINRESTORE) == 0)
914: puffs_cc_continue(pcc);
1.89 pooka 915:
1.79 pooka 916: finalpush(pu);
1.44 pooka 917: errno = 0;
1.18 alc 918:
1.19 pooka 919: out:
1.44 pooka 920: /* store the real error for a while */
921: sverrno = errno;
922:
923: errno = sverrno;
924: if (errno)
925: return -1;
926: else
927: return 0;
1.1 pooka 928: }
CVSweb <webmaster@jp.NetBSD.org>