Implement lazy contexts for file systems using puffs_mainloop().
Previously each request was executed on its own callcontext and switched to every time the request was being processed. Now requests borrow the mainloop context and switch only if/when they yield. This takes two context switches away from a file system request bringing down the typical amounts 2->0 (e.g. dtfs) and 4->2 (e.g. psshfs). The interfaces for manually executing requests changed a bit: puffs_dispatch_create() and puffs_dispatch_exec() must now be used. They are not tested, as nothing in-tree wants them and I doubt anyone else is really interested in them either. Also do some misc code cleanup related to execution contexts. The "work-in-progress checkpoint" committed over a year ago was starting to look slightly weed-infested.
This commit is contained in:
parent
f3b8aacb17
commit
d1d05d65b9
@ -1,7 +1,10 @@
|
||||
/* $NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $ */
|
||||
/* $NetBSD: callcontext.c,v 1.20 2008/01/28 18:35:49 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
|
||||
* Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Research Foundation of Helsinki University of Technology
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -27,7 +30,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $");
|
||||
__RCSID("$NetBSD: callcontext.c,v 1.20 2008/01/28 18:35:49 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -35,9 +38,6 @@ __RCSID("$NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $");
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#ifdef PUFFS_WITH_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <puffs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -47,29 +47,75 @@ __RCSID("$NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $");
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
/*
|
||||
* Set the following to 1 to not handle each request on a separate
|
||||
* stack. This is highly volatile kludge, therefore no external
|
||||
* interface.
|
||||
*/
|
||||
int puffs_fakecc;
|
||||
|
||||
/*
|
||||
* user stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
* So, we need to get back to where we came from. This can happen in two
|
||||
* different ways:
|
||||
* 1) PCC_MLCONT is set, in which case we need to go to the mainloop
|
||||
* 2) It is not set, and we simply jump to pcc_uc_ret.
|
||||
*/
|
||||
void
|
||||
puffs_cc_yield(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_cc *jumpcc;
|
||||
int rv;
|
||||
|
||||
assert(puffs_fakecc == 0);
|
||||
|
||||
assert(pcc->pcc_flags & PCC_REALCC);
|
||||
pcc->pcc_flags &= ~PCC_BORROWED;
|
||||
|
||||
/* romanes eunt domus */
|
||||
swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret);
|
||||
if ((pcc->pcc_flags & PCC_MLCONT) == 0) {
|
||||
swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret);
|
||||
} else {
|
||||
pcc->pcc_flags &= ~PCC_MLCONT;
|
||||
rv = puffs__cc_create(pcc->pcc_pu, puffs__theloop, &jumpcc);
|
||||
if (rv)
|
||||
abort(); /* p-p-p-pa-pa-panic (XXX: fixme) */
|
||||
swapcontext(&pcc->pcc_uc, &jumpcc->pcc_uc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal continue routine. This has slightly different semantics.
|
||||
* We simply make our cc available in the freelist and jump to the
|
||||
* indicated pcc.
|
||||
*/
|
||||
void
|
||||
puffs__cc_cont(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_cc *mycc;
|
||||
|
||||
mycc = puffs_cc_getcc(pcc->pcc_pu);
|
||||
|
||||
/*
|
||||
* XXX: race between setcontenxt() and recycle if
|
||||
* we go multithreaded
|
||||
*/
|
||||
puffs__cc_destroy(mycc, 1);
|
||||
pcc->pcc_flags |= PCC_MLCONT;
|
||||
setcontext(&pcc->pcc_uc);
|
||||
}
|
||||
|
||||
void
|
||||
puffs_cc_continue(struct puffs_cc *pcc)
|
||||
{
|
||||
|
||||
assert(pcc->pcc_flags & PCC_REALCC);
|
||||
|
||||
/* ramble on */
|
||||
swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc);
|
||||
if (puffs_fakecc)
|
||||
pcc->pcc_func(pcc->pcc_farg);
|
||||
else
|
||||
swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -80,10 +126,9 @@ puffs_cc_continue(struct puffs_cc *pcc)
|
||||
* yield again).
|
||||
*/
|
||||
void
|
||||
puffs_goto(struct puffs_cc *loanpcc)
|
||||
puffs__goto(struct puffs_cc *loanpcc)
|
||||
{
|
||||
|
||||
assert(loanpcc->pcc_flags & PCC_REALCC);
|
||||
loanpcc->pcc_flags |= PCC_BORROWED;
|
||||
|
||||
swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc);
|
||||
@ -114,126 +159,100 @@ puffs_cc_getcaller(struct puffs_cc *pcc, pid_t *pid, lwpid_t *lid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PUFFS_WITH_THREADS
|
||||
int pthread__stackid_setup(void *, size_t, pthread_t *);
|
||||
#endif
|
||||
|
||||
/* for fakecc-users, need only one */
|
||||
static struct puffs_cc fakecc;
|
||||
|
||||
int
|
||||
puffs_cc_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
int type, struct puffs_cc **pccp)
|
||||
static struct puffs_cc *
|
||||
slowccalloc(struct puffs_usermount *pu)
|
||||
{
|
||||
struct puffs_cc *volatile pcc;
|
||||
void *sp;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
long psize = sysconf(_SC_PAGESIZE);
|
||||
stack_t *st;
|
||||
void *volatile sp;
|
||||
|
||||
#ifdef PUFFS_WITH_THREADS
|
||||
extern size_t pthread__stacksize;
|
||||
stacksize = pthread__stacksize;
|
||||
#endif
|
||||
if (puffs_fakecc)
|
||||
return &fakecc;
|
||||
|
||||
sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift), -1, 0);
|
||||
if (sp == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
pcc = sp;
|
||||
memset(pcc, 0, sizeof(struct puffs_cc));
|
||||
|
||||
mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);
|
||||
|
||||
/* initialize both ucontext's */
|
||||
if (getcontext(&pcc->pcc_uc) == -1) {
|
||||
munmap(pcc, stacksize);
|
||||
return NULL;
|
||||
}
|
||||
if (getcontext(&pcc->pcc_uc_ret) == -1) {
|
||||
munmap(pcc, stacksize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pcc;
|
||||
}
|
||||
|
||||
int
|
||||
puffs__cc_create(struct puffs_usermount *pu, puffs_ccfunc func,
|
||||
struct puffs_cc **pccp)
|
||||
{
|
||||
struct puffs_cc *pcc;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
stack_t *st;
|
||||
|
||||
/* Do we have a cached copy? */
|
||||
if (pu->pu_cc_nstored) {
|
||||
if (pu->pu_cc_nstored == 0) {
|
||||
pcc = slowccalloc(pu);
|
||||
if (pcc == NULL)
|
||||
return -1;
|
||||
pcc->pcc_pu = pu;
|
||||
} else {
|
||||
pcc = LIST_FIRST(&pu->pu_ccmagazin);
|
||||
assert(pcc != NULL);
|
||||
|
||||
LIST_REMOVE(pcc, pcc_rope);
|
||||
pu->pu_cc_nstored--;
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are two paths and in the long run we don't have time to
|
||||
* change the one we're on. For non-real cc's, we just simply use
|
||||
* a static copy. For the other cases, we mmap the stack and
|
||||
* manually reserve a bit from the top for the data structure
|
||||
* (or, well, the bottom).
|
||||
*
|
||||
* XXX: threaded mode doesn't work very well now. Not that it's
|
||||
* supported anyhow.
|
||||
*/
|
||||
if (type == PCC_FAKECC) {
|
||||
pcc = &fakecc;
|
||||
sp = NULL;
|
||||
} else {
|
||||
sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift),
|
||||
-1, 0);
|
||||
if (sp == MAP_FAILED)
|
||||
return -1;
|
||||
|
||||
pcc = sp;
|
||||
mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);
|
||||
}
|
||||
|
||||
memset(pcc, 0, sizeof(struct puffs_cc));
|
||||
pcc->pcc_pu = pu;
|
||||
|
||||
/* Not a real cc? Don't need to init more */
|
||||
if (type != PCC_REALCC)
|
||||
goto out;
|
||||
|
||||
/* initialize both ucontext's */
|
||||
if (getcontext(&pcc->pcc_uc) == -1) {
|
||||
munmap(pcc, stacksize);
|
||||
return -1;
|
||||
}
|
||||
if (getcontext(&pcc->pcc_uc_ret) == -1) {
|
||||
munmap(pcc, stacksize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PUFFS_WITH_THREADS
|
||||
{
|
||||
pthread_t pt;
|
||||
extern int __isthreaded;
|
||||
if (__isthreaded)
|
||||
pthread__stackid_setup(sp, stacksize /* XXXb0rked */, &pt);
|
||||
}
|
||||
#endif
|
||||
|
||||
finalize:
|
||||
assert(pcc->pcc_pu == pu);
|
||||
|
||||
/* return here. it won't actually be "here" due to swapcontext() */
|
||||
pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
|
||||
if (puffs_fakecc) {
|
||||
pcc->pcc_func = func;
|
||||
pcc->pcc_farg = pcc;
|
||||
} else {
|
||||
/* link context */
|
||||
pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
|
||||
|
||||
/* setup stack
|
||||
*
|
||||
* XXX: I guess this should theoretically be preserved by
|
||||
* swapcontext(). However, it gets lost. So reinit it.
|
||||
*/
|
||||
st = &pcc->pcc_uc.uc_stack;
|
||||
st->ss_sp = pcc;
|
||||
st->ss_size = stacksize;
|
||||
st->ss_flags = 0;
|
||||
/* setup stack
|
||||
*
|
||||
* XXX: I guess this should theoretically be preserved by
|
||||
* swapcontext(). However, it gets lost. So reinit it.
|
||||
*/
|
||||
st = &pcc->pcc_uc.uc_stack;
|
||||
st->ss_sp = pcc;
|
||||
st->ss_size = stacksize;
|
||||
st->ss_flags = 0;
|
||||
|
||||
/*
|
||||
* Give us an initial context to jump to.
|
||||
*
|
||||
* XXX: Our manual page says that portable code shouldn't rely on
|
||||
* being able to pass pointers through makecontext(). kjk says
|
||||
* that NetBSD code doesn't need to worry about this. uwe says
|
||||
* it would be like putting a "keep away from children" sign on a
|
||||
* box of toys.
|
||||
*/
|
||||
makecontext(&pcc->pcc_uc, (void *)puffs_calldispatcher,
|
||||
1, (uintptr_t)pcc);
|
||||
|
||||
out:
|
||||
pcc->pcc_pb = pb;
|
||||
pcc->pcc_flags = type;
|
||||
/*
|
||||
* Give us an initial context to jump to.
|
||||
*
|
||||
* Our manual page says that portable code shouldn't
|
||||
* rely on being able to pass pointers through makecontext().
|
||||
* kjk says that NetBSD code doesn't need to worry about this.
|
||||
* uwe says it would be like putting a "keep away from
|
||||
* children" sign on a box of toys.
|
||||
*/
|
||||
makecontext(&pcc->pcc_uc, (void *)func, 1, (uintptr_t)pcc);
|
||||
}
|
||||
|
||||
*pccp = pcc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid)
|
||||
puffs__cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid)
|
||||
{
|
||||
|
||||
pcc->pcc_pid = pid;
|
||||
@ -242,44 +261,32 @@ puffs_cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid)
|
||||
}
|
||||
|
||||
void
|
||||
puffs_cc_destroy(struct puffs_cc *pcc)
|
||||
puffs__cc_destroy(struct puffs_cc *pcc, int nonuke)
|
||||
{
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
|
||||
/* not over limit? stuff away in the store */
|
||||
if (pu->pu_cc_nstored < PUFFS_CCMAXSTORE
|
||||
&& pcc->pcc_flags & PCC_REALCC) {
|
||||
pcc->pcc_flags &= ~PCC_DONE;
|
||||
assert(pcc->pcc_flags = 0);
|
||||
|
||||
/* not over limit? stuff away in the store, otherwise nuke */
|
||||
if (nonuke || pu->pu_cc_nstored < PUFFS_CCMAXSTORE) {
|
||||
pcc->pcc_pb = NULL;
|
||||
LIST_INSERT_HEAD(&pu->pu_ccmagazin, pcc, pcc_rope);
|
||||
pu->pu_cc_nstored++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* else: just dump it */
|
||||
|
||||
#ifdef PUFFS_WITH_THREADS
|
||||
extern size_t pthread__stacksize;
|
||||
stacksize = pthread__stacksize;
|
||||
#endif
|
||||
|
||||
if ((pcc->pcc_flags & PCC_FAKECC) == 0)
|
||||
} else {
|
||||
assert(!puffs_fakecc);
|
||||
munmap(pcc, stacksize);
|
||||
}
|
||||
}
|
||||
|
||||
struct puffs_cc *
|
||||
puffs_cc_getcc(struct puffs_usermount *pu)
|
||||
{
|
||||
extern int puffs_fakecc, puffs_usethreads;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
uintptr_t bottom;
|
||||
|
||||
if (puffs_fakecc)
|
||||
return &fakecc;
|
||||
#ifndef PUFFS_WITH_THREADS
|
||||
if (puffs_usethreads)
|
||||
return &fakecc;
|
||||
#endif
|
||||
|
||||
bottom = ((uintptr_t)&bottom) & ~(stacksize-1);
|
||||
return (struct puffs_cc *)bottom;
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* $NetBSD: dispatcher.c,v 1.29 2008/01/16 23:17:43 pooka Exp $ */
|
||||
/* $NetBSD: dispatcher.c,v 1.30 2008/01/28 18:35:50 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved.
|
||||
* Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Ulla Tuominen Foundation and the Finnish Cultural Foundation.
|
||||
* Ulla Tuominen Foundation, the Finnish Cultural Foundation and
|
||||
* Research Foundation of Helsinki University of Technology.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -30,7 +31,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: dispatcher.c,v 1.29 2008/01/16 23:17:43 pooka Exp $");
|
||||
__RCSID("$NetBSD: dispatcher.c,v 1.30 2008/01/28 18:35:50 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -49,15 +50,7 @@ __RCSID("$NetBSD: dispatcher.c,v 1.29 2008/01/16 23:17:43 pooka Exp $");
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
static void processresult(struct puffs_usermount *, int);
|
||||
|
||||
/*
|
||||
* Set the following to 1 to not handle each request on a separate
|
||||
* stack. This is highly volatile kludge, therefore no external
|
||||
* interface.
|
||||
*/
|
||||
int puffs_fakecc;
|
||||
|
||||
#if 0 /* me not worka now */
|
||||
/*
|
||||
* Set the following to 1 to handle each request in a separate pthread.
|
||||
* This is not exported as it should not be used yet unless having a
|
||||
@ -65,219 +58,100 @@ int puffs_fakecc;
|
||||
* threadsafe).
|
||||
*/
|
||||
int puffs_usethreads;
|
||||
#endif
|
||||
|
||||
static int
|
||||
dopufbuf2(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
static void dispatch(struct puffs_cc *);
|
||||
|
||||
/* for our eyes only */
|
||||
void
|
||||
puffs__ml_dispatch(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
{
|
||||
struct puffs_req *preq = puffs__framebuf_getdataptr(pb);
|
||||
struct puffs_cc *pcc;
|
||||
int type;
|
||||
struct puffs_cc *pcc = puffs_cc_getcc(pu);
|
||||
struct puffs_req *preq;
|
||||
|
||||
if (puffs_fakecc) {
|
||||
type = PCC_FAKECC;
|
||||
} else if (puffs_usethreads) {
|
||||
type = PCC_THREADED;
|
||||
#ifndef PUFFS_WITH_THREADS
|
||||
type = PCC_FAKECC;
|
||||
#endif
|
||||
pcc->pcc_pb = pb;
|
||||
pcc->pcc_flags |= PCC_MLCONT;
|
||||
dispatch(pcc);
|
||||
|
||||
/* Put result to kernel sendqueue if necessary */
|
||||
preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
||||
if (PUFFSOP_WANTREPLY(preq->preq_opclass)) {
|
||||
if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
|
||||
puffsdump_rv(preq);
|
||||
|
||||
puffs_framev_enqueue_justsend(pu, pu->pu_fd,
|
||||
pcc->pcc_pb, 0, 0);
|
||||
} else {
|
||||
type = PCC_REALCC;
|
||||
puffs_framebuf_destroy(pcc->pcc_pb);
|
||||
}
|
||||
|
||||
if (puffs_cc_create(pu, pb, type, &pcc) == -1)
|
||||
return errno;
|
||||
|
||||
puffs_cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
|
||||
|
||||
#ifdef PUFFS_WITH_THREADS
|
||||
if (puffs_usethreads) {
|
||||
pthread_attr_t pattr;
|
||||
pthread_t ptid;
|
||||
int rv;
|
||||
|
||||
pthread_attr_init(&pattr);
|
||||
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_destroy(&pattr);
|
||||
|
||||
ap->pwa_pcc = pcc;
|
||||
|
||||
rv = pthread_create(&ptid, &pattr, puffs_docc, pcc);
|
||||
|
||||
return rv;
|
||||
/* who needs information when you're living on borrowed time? */
|
||||
if (pcc->pcc_flags & PCC_BORROWED) {
|
||||
puffs_cc_yield(pcc); /* back to borrow source */
|
||||
}
|
||||
#endif
|
||||
puffs_docc(pcc);
|
||||
pcc->pcc_flags = 0;
|
||||
}
|
||||
|
||||
/* public, but not really tested and only semi-supported */
|
||||
int
|
||||
puffs_dispatch_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
struct puffs_cc **pccp)
|
||||
{
|
||||
struct puffs_cc *pcc;
|
||||
|
||||
if (puffs__cc_create(pu, dispatch, &pcc) == -1)
|
||||
return -1;
|
||||
|
||||
pcc->pcc_pb = pb;
|
||||
*pccp = pcc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* User-visible point to handle a request from.
|
||||
*
|
||||
* <insert text here>
|
||||
*/
|
||||
int
|
||||
puffs_dopufbuf(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
puffs_dispatch_exec(struct puffs_cc *pcc, struct puffs_framebuf **pbp)
|
||||
{
|
||||
struct puffs_req *preq = puffs__framebuf_getdataptr(pb);
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* XXX: the structure is currently a mess. anyway, trap
|
||||
* the cacheops here already, since they don't need a cc.
|
||||
* I really should get around to revamping the operation
|
||||
* dispatching code one of these days.
|
||||
*
|
||||
* Do the same for error notifications.
|
||||
*/
|
||||
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
|
||||
struct puffs_cacheinfo *pci = (void *)preq;
|
||||
puffs_cc_continue(pcc);
|
||||
|
||||
if (pu->pu_ops.puffs_cache_write == NULL)
|
||||
return 0;
|
||||
|
||||
pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
|
||||
pci->pcache_nruns, pci->pcache_runs);
|
||||
return 0;
|
||||
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
|
||||
struct puffs_error *perr = (void *)preq;
|
||||
|
||||
pu->pu_errnotify(pu, preq->preq_optype,
|
||||
perr->perr_error, perr->perr_str, preq->preq_cookie);
|
||||
return 0;
|
||||
if (pcc->pcc_flags & PCC_DONE) {
|
||||
rv = 1;
|
||||
*pbp = pcc->pcc_pb;
|
||||
pcc->pcc_flags = 0;
|
||||
puffs__cc_destroy(pcc, 0);
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
|
||||
puffsdump_req(preq);
|
||||
|
||||
#if 0
|
||||
XXX: we can't trust to hide preq in pufbuf
|
||||
|
||||
struct puffs_executor *pex;
|
||||
/*
|
||||
* Check if we are already processing an operation from the same
|
||||
* caller. If so, queue this operation until the previous one
|
||||
* finishes. This prevents us from executing certain operations
|
||||
* out-of-order (e.g. fsync and reclaim).
|
||||
*
|
||||
* Each preq will only remove its own pex from the tailq.
|
||||
* See puffs_docc() for the details on other-end removal
|
||||
* and dispatching.
|
||||
*/
|
||||
pex = malloc(sizeof(struct puffs_executor));
|
||||
pex->pex_pufbuf = pb;
|
||||
PU_LOCK();
|
||||
TAILQ_INSERT_TAIL(&pu->pu_exq, pex, pex_entries);
|
||||
TAILQ_FOREACH(pex, &pu->pu_exq, pex_entries) {
|
||||
struct puffs_req *pb_preq;
|
||||
|
||||
pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf);
|
||||
if (pb_preq->preq_pid == preq->preq_pid
|
||||
&& pb_preq->preq_lid == preq->preq_lid) {
|
||||
if (pb_preq != preq) {
|
||||
PU_UNLOCK();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
PU_UNLOCK();
|
||||
#endif
|
||||
|
||||
return dopufbuf2(pu, pb);
|
||||
return rv;
|
||||
}
|
||||
|
||||
enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
|
||||
|
||||
void *
|
||||
puffs_docc(void *arg)
|
||||
{
|
||||
struct puffs_cc *pcc = arg;
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
struct puffs_req *preq;
|
||||
struct puffs_cc *pcc_iter;
|
||||
|
||||
assert((pcc->pcc_flags & PCC_DONE) == 0);
|
||||
|
||||
if (pcc->pcc_flags & PCC_REALCC)
|
||||
puffs_cc_continue(pcc);
|
||||
else
|
||||
puffs_calldispatcher(pcc);
|
||||
|
||||
if ((pcc->pcc_flags & PCC_DONE) == 0) {
|
||||
assert(pcc->pcc_flags & PCC_REALCC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
||||
#if 0
|
||||
XXX: see above, needs more thought
|
||||
|
||||
struct puffs_executor *pex, *pex_n;
|
||||
int found;
|
||||
/* check if we need to schedule FAFs which were stalled */
|
||||
found = 0;
|
||||
PU_LOCK();
|
||||
for (pex = TAILQ_FIRST(&pu->pu_exq); pex; pex = pex_n) {
|
||||
struct puffs_req *pb_preq;
|
||||
|
||||
pb_preq = puffs__framebuf_getdataptr(pex->pex_pufbuf);
|
||||
pex_n = TAILQ_NEXT(pex, pex_entries);
|
||||
if (pb_preq->preq_pid == preq->preq_pid
|
||||
&& pb_preq->preq_lid == preq->preq_lid) {
|
||||
if (found == 0) {
|
||||
/* this is us */
|
||||
assert(pb_preq == preq);
|
||||
TAILQ_REMOVE(&pu->pu_exq, pex, pex_entries);
|
||||
free(pex);
|
||||
found = 1;
|
||||
} else {
|
||||
/* down at the mardi gras */
|
||||
PU_UNLOCK();
|
||||
dopufbuf2(pu, pex->pex_pufbuf);
|
||||
PU_LOCK();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!PUFFSOP_WANTREPLY(preq->preq_opclass))
|
||||
puffs_framebuf_destroy(pcc->pcc_pb);
|
||||
|
||||
/* can't do this above due to PCC_BORROWED */
|
||||
while ((pcc_iter = LIST_FIRST(&pu->pu_ccnukelst)) != NULL) {
|
||||
LIST_REMOVE(pcc_iter, pcc_rope);
|
||||
puffs_cc_destroy(pcc_iter);
|
||||
}
|
||||
PU_UNLOCK();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* library private, but linked from callcontext.c */
|
||||
|
||||
void
|
||||
puffs_calldispatcher(struct puffs_cc *pcc)
|
||||
static void
|
||||
dispatch(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
struct puffs_ops *pops = &pu->pu_ops;
|
||||
struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
||||
void *auxbuf = preq; /* help with typecasting */
|
||||
void *opcookie = preq->preq_cookie;
|
||||
int error, rv, buildpath;
|
||||
int error, buildpath;
|
||||
|
||||
assert(pcc->pcc_flags & (PCC_FAKECC | PCC_REALCC | PCC_THREADED));
|
||||
assert(pcc == puffs_cc_getcc(pu)); /* remove me soon */
|
||||
|
||||
if (PUFFSOP_WANTREPLY(preq->preq_opclass))
|
||||
rv = PUFFCALL_ANSWER;
|
||||
else
|
||||
rv = PUFFCALL_IGNORE;
|
||||
assert((pcc->pcc_flags & PCC_DONE) == 0);
|
||||
|
||||
buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
|
||||
preq->preq_setbacks = 0;
|
||||
|
||||
if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
|
||||
puffsdump_req(preq);
|
||||
|
||||
puffs__cc_setcaller(pcc, preq->preq_pid, preq->preq_lid);
|
||||
|
||||
/* pre-operation */
|
||||
if (pu->pu_oppre)
|
||||
pu->pu_oppre(pu);
|
||||
|
||||
/* Execute actual operation */
|
||||
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
|
||||
switch (preq->preq_optype) {
|
||||
case PUFFS_VFS_UNMOUNT:
|
||||
@ -1003,62 +877,32 @@ puffs_calldispatcher(struct puffs_cc *pcc)
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
|
||||
struct puffs_cacheinfo *pci = (void *)preq;
|
||||
|
||||
if (pu->pu_ops.puffs_cache_write) {
|
||||
pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
|
||||
pci->pcache_nruns, pci->pcache_runs);
|
||||
}
|
||||
error = 0;
|
||||
|
||||
} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_ERROR) {
|
||||
struct puffs_error *perr = (void *)preq;
|
||||
|
||||
pu->pu_errnotify(pu, preq->preq_optype,
|
||||
perr->perr_error, perr->perr_str, preq->preq_cookie);
|
||||
error = 0;
|
||||
} else {
|
||||
/*
|
||||
* this one also
|
||||
* I guess the kernel sees this one coming also
|
||||
*/
|
||||
error = EINVAL;
|
||||
}
|
||||
|
||||
preq->preq_rv = error;
|
||||
pcc->pcc_flags |= PCC_DONE;
|
||||
|
||||
if (pu->pu_oppost)
|
||||
pu->pu_oppost(pu);
|
||||
|
||||
/*
|
||||
* Note, we are calling this from here so that we can run it
|
||||
* off of the continuation stack. Otherwise puffs_goto() would
|
||||
* not work.
|
||||
*/
|
||||
processresult(pu, rv);
|
||||
}
|
||||
|
||||
static void
|
||||
processresult(struct puffs_usermount *pu, int how)
|
||||
{
|
||||
struct puffs_cc *pcc = puffs_cc_getcc(pu);
|
||||
struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
|
||||
int pccflags = pcc->pcc_flags;
|
||||
|
||||
/* check if we need to store this reply */
|
||||
switch (how) {
|
||||
case PUFFCALL_ANSWER:
|
||||
if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
|
||||
puffsdump_rv(preq);
|
||||
|
||||
puffs_framev_enqueue_justsend(pu, pu->pu_fd,
|
||||
pcc->pcc_pb, 0, 0);
|
||||
/*FALLTHROUGH*/
|
||||
|
||||
case PUFFCALL_IGNORE:
|
||||
PU_LOCK();
|
||||
LIST_INSERT_HEAD(&pu->pu_ccnukelst, pcc, pcc_rope);
|
||||
PU_UNLOCK();
|
||||
break;
|
||||
|
||||
case PUFFCALL_AGAIN:
|
||||
if ((pcc->pcc_flags & PCC_REALCC) == 0)
|
||||
assert(pcc->pcc_flags & PCC_DONE);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(/*CONSTCOND*/0);
|
||||
}
|
||||
|
||||
/* who needs information when you're living on borrowed time? */
|
||||
if (pccflags & PCC_BORROWED) {
|
||||
assert((pccflags & PCC_THREADED) == 0);
|
||||
puffs_cc_yield(pcc); /* back to borrow source */
|
||||
}
|
||||
pcc->pcc_flags |= PCC_DONE;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: framebuf.c,v 1.26 2007/12/16 20:02:57 pooka Exp $ */
|
||||
/* $NetBSD: framebuf.c,v 1.27 2008/01/28 18:35:50 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: framebuf.c,v 1.26 2007/12/16 20:02:57 pooka Exp $");
|
||||
__RCSID("$NetBSD: framebuf.c,v 1.27 2008/01/28 18:35:50 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -328,7 +328,7 @@ errnotify(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, int error)
|
||||
|
||||
pufbuf->rv = error;
|
||||
if (pufbuf->pcc) {
|
||||
puffs_goto(pufbuf->pcc);
|
||||
puffs__goto(pufbuf->pcc);
|
||||
} else if (pufbuf->fcb) {
|
||||
pufbuf->istat &= ~ISTAT_NODESTROY;
|
||||
pufbuf->fcb(pu, pufbuf, pufbuf->fcb_arg, error);
|
||||
@ -597,7 +597,7 @@ puffs_framev_enqueue_waitevent(struct puffs_cc *pcc, int fd, int *what)
|
||||
}
|
||||
|
||||
void
|
||||
puffs_framev_notify(struct puffs_fctrl_io *fio, int what)
|
||||
puffs__framev_notify(struct puffs_fctrl_io *fio, int what)
|
||||
{
|
||||
struct puffs_fbevent *fbevp;
|
||||
|
||||
@ -652,7 +652,7 @@ puffs__framebuf_moveinfo(struct puffs_framebuf *from, struct puffs_framebuf *to)
|
||||
}
|
||||
|
||||
void
|
||||
puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
puffs__framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
struct puffs_fctrl_io *fio)
|
||||
{
|
||||
struct puffs_framebuf *pufbuf, *appbuf;
|
||||
@ -672,7 +672,7 @@ puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
|
||||
/* error */
|
||||
if (rv) {
|
||||
puffs_framev_readclose(pu, fio, rv);
|
||||
puffs__framev_readclose(pu, fio, rv);
|
||||
fio->cur_in = NULL;
|
||||
if ((pufbuf->istat & ISTAT_DIRECT) == 0) {
|
||||
assert((pufbuf->istat & ISTAT_NODESTROY) == 0);
|
||||
@ -712,7 +712,7 @@ puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
appbuf->istat &= ~ISTAT_NODESTROY;
|
||||
|
||||
if (appbuf->pcc) {
|
||||
puffs_docc(appbuf->pcc);
|
||||
puffs__cc_cont(appbuf->pcc);
|
||||
} else if (appbuf->fcb) {
|
||||
appbuf->fcb(pu, appbuf, appbuf->fcb_arg, 0);
|
||||
} else {
|
||||
@ -724,7 +724,7 @@ puffs_framev_input(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
}
|
||||
|
||||
int
|
||||
puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
puffs__framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
struct puffs_fctrl_io *fio)
|
||||
{
|
||||
struct puffs_framebuf *pufbuf;
|
||||
@ -740,7 +740,7 @@ puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
rv = fctrl->wfb(pu, pufbuf, fio->io_fd, &complete);
|
||||
|
||||
if (rv) {
|
||||
puffs_framev_writeclose(pu, fio, rv);
|
||||
puffs__framev_writeclose(pu, fio, rv);
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
@ -758,8 +758,8 @@ puffs_framev_output(struct puffs_usermount *pu, struct puffs_framectrl *fctrl,
|
||||
done = 1;
|
||||
} else if ((pufbuf->istat & ISTAT_DIRECT)) {
|
||||
pufbuf->istat &= ~ISTAT_NODESTROY;
|
||||
puffs_docc(pufbuf->pcc);
|
||||
done = 1;
|
||||
puffs__cc_cont(pufbuf->pcc);
|
||||
} else if ((pufbuf->istat & ISTAT_NOREPLY) == 0) {
|
||||
TAILQ_INSERT_TAIL(&fio->res_qing, pufbuf,
|
||||
pfb_entries);
|
||||
@ -915,7 +915,7 @@ puffs_framev_disablefd(struct puffs_usermount *pu, int fd, int what)
|
||||
}
|
||||
|
||||
void
|
||||
puffs_framev_readclose(struct puffs_usermount *pu,
|
||||
puffs__framev_readclose(struct puffs_usermount *pu,
|
||||
struct puffs_fctrl_io *fio, int error)
|
||||
{
|
||||
struct puffs_framebuf *pufbuf;
|
||||
@ -952,7 +952,7 @@ puffs_framev_readclose(struct puffs_usermount *pu,
|
||||
}
|
||||
|
||||
void
|
||||
puffs_framev_writeclose(struct puffs_usermount *pu,
|
||||
puffs__framev_writeclose(struct puffs_usermount *pu,
|
||||
struct puffs_fctrl_io *fio, int error)
|
||||
{
|
||||
struct puffs_framebuf *pufbuf;
|
||||
@ -986,14 +986,14 @@ removefio(struct puffs_usermount *pu, struct puffs_fctrl_io *fio, int error)
|
||||
|
||||
LIST_REMOVE(fio, fio_entries);
|
||||
if (pu->pu_state & PU_INLOOP) {
|
||||
puffs_framev_readclose(pu, fio, error);
|
||||
puffs_framev_writeclose(pu, fio, error);
|
||||
puffs__framev_readclose(pu, fio, error);
|
||||
puffs__framev_writeclose(pu, fio, error);
|
||||
}
|
||||
|
||||
while ((fbevp = LIST_FIRST(&fio->ev_qing)) != NULL) {
|
||||
fbevp->rv = error;
|
||||
LIST_REMOVE(fbevp, pfe_entries);
|
||||
puffs_goto(fbevp->pcc);
|
||||
puffs__goto(fbevp->pcc);
|
||||
}
|
||||
|
||||
/* don't bother with realloc */
|
||||
@ -1056,7 +1056,7 @@ puffs_framev_init(struct puffs_usermount *pu,
|
||||
}
|
||||
|
||||
void
|
||||
puffs_framev_exit(struct puffs_usermount *pu)
|
||||
puffs__framev_exit(struct puffs_usermount *pu)
|
||||
{
|
||||
struct puffs_fctrl_io *fio;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: puffs.3,v 1.38 2008/01/14 13:57:26 pooka Exp $
|
||||
.\" $NetBSD: puffs.3,v 1.39 2008/01/28 18:35:50 pooka Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006, 2007, 2008 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
@ -23,7 +23,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd January 14, 2008
|
||||
.Dd January 28, 2008
|
||||
.Dt PUFFS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -80,7 +80,12 @@
|
||||
.Ft int
|
||||
.Fn puffs_mainloop "struct puffs_usermount *pu"
|
||||
.Ft int
|
||||
.Fn puffs_dopufbuf "struct puffs_usermount *pu" "struct puffs_framebuf *pb"
|
||||
.Fo puffs_dispatch_create
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pb"
|
||||
.Fa "struct puffs_cc **pccp"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn puffs_dispatch_exec .Fa "struct puffs_cc *pcc" "struct puffs_framebuf **pbp"
|
||||
.Sh DESCRIPTION
|
||||
.Em IMPORTANT NOTE!
|
||||
This document describes interfaces which are not yet guaranteed to be
|
||||
@ -434,13 +439,39 @@ In case
|
||||
.Xr puffs_framebuf 3
|
||||
has been initialized, I/O from the relevant descriptors is processed
|
||||
automatically by the eventloop.
|
||||
.It Fn puffs_dopufbuf pu pb
|
||||
Decode and dispatch the file system request in
|
||||
.Ar pb .
|
||||
The contents of
|
||||
.It Fn puffs_dispatch_create pu pb pccp
|
||||
.It Fn puffs_dispatch_exec pcc pbp
|
||||
In case the use of
|
||||
.Fn puffs_mainloop
|
||||
is not possible, requests may be dispatched manually.
|
||||
However, as this is less efficient than using the mainloop,
|
||||
it should never be the first preference.
|
||||
.Pp
|
||||
Calling
|
||||
.Fn puffs_dispatch_create
|
||||
creates a dispatch request.
|
||||
The argument
|
||||
.Ar pb
|
||||
must be of type
|
||||
.Vt "struct puffs_req" .
|
||||
should contains a valid request and upon success
|
||||
.Ar pccp
|
||||
will contain a valid request context.
|
||||
This context is passed to
|
||||
.Fn puffs_dispatch_exec
|
||||
to execute the request.
|
||||
If the request yielded before completing, the routine returns 0,
|
||||
otherwise 1.
|
||||
When the routine completes,
|
||||
.Ar pcc
|
||||
is made invalid and a pointer to the processed buffer is placed in
|
||||
.Ar pbp .
|
||||
It is the responsibility of the caller to send the response (if
|
||||
necessary) and destroy the buffer.
|
||||
.Pp
|
||||
See
|
||||
.Xr puffs_cc 3
|
||||
and
|
||||
.Xr puffs_framebuf 3
|
||||
for further information.
|
||||
.El
|
||||
.Ss Cookies
|
||||
Every file (regular file, directory, device node, ...) instance is
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: puffs.c,v 1.88 2008/01/16 21:30:00 pooka Exp $ */
|
||||
/* $NetBSD: puffs.c,v 1.89 2008/01/28 18:35:50 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: puffs.c,v 1.88 2008/01/16 21:30:00 pooka Exp $");
|
||||
__RCSID("$NetBSD: puffs.c,v 1.89 2008/01/28 18:35:50 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -115,7 +115,7 @@ finalpush(struct puffs_usermount *pu)
|
||||
if (fio->stat & FIO_WRGONE)
|
||||
continue;
|
||||
|
||||
puffs_framev_output(pu, fio->fctrl, fio);
|
||||
puffs__framev_output(pu, fio->fctrl, fio);
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,14 +620,12 @@ _puffs_init(int develv, struct puffs_ops *pops, const char *mntfromname,
|
||||
LIST_INIT(&pu->pu_ios);
|
||||
LIST_INIT(&pu->pu_ios_rmlist);
|
||||
LIST_INIT(&pu->pu_ccmagazin);
|
||||
LIST_INIT(&pu->pu_ccnukelst);
|
||||
TAILQ_INIT(&pu->pu_sched);
|
||||
TAILQ_INIT(&pu->pu_exq);
|
||||
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs_fsframe_read;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs_fsframe_write;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs_fsframe_cmp;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs_fsframe_gotframe;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs__fsframe_read;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs__fsframe_write;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs__fsframe_cmp;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs__fsframe_gotframe;
|
||||
pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose;
|
||||
|
||||
/* defaults for some user-settable translation functions */
|
||||
@ -672,7 +670,7 @@ puffs_exit(struct puffs_usermount *pu, int force)
|
||||
puffs_pn_put(pn);
|
||||
|
||||
finalpush(pu);
|
||||
puffs_framev_exit(pu);
|
||||
puffs__framev_exit(pu);
|
||||
if (pu->pu_state & PU_HASKQ)
|
||||
close(pu->pu_kq);
|
||||
free(pu);
|
||||
@ -680,48 +678,30 @@ puffs_exit(struct puffs_usermount *pu, int force)
|
||||
return 0; /* always succesful for now, WILL CHANGE */
|
||||
}
|
||||
|
||||
int
|
||||
puffs_mainloop(struct puffs_usermount *pu)
|
||||
/*
|
||||
* Actual mainloop. This is called from a context which can block.
|
||||
* It is called either from puffs_mainloop (indirectly, via
|
||||
* puffs_cc_continue() or from puffs_cc_yield()).
|
||||
*/
|
||||
void
|
||||
puffs__theloop(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
struct puffs_framectrl *pfctrl;
|
||||
struct puffs_fctrl_io *fio;
|
||||
struct puffs_cc *pcc;
|
||||
struct kevent *curev;
|
||||
size_t nchanges;
|
||||
int ndone, sverrno;
|
||||
|
||||
assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
|
||||
|
||||
pu->pu_kq = kqueue();
|
||||
if (pu->pu_kq == -1)
|
||||
goto out;
|
||||
pu->pu_state |= PU_HASKQ;
|
||||
|
||||
puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK);
|
||||
if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu),
|
||||
PUFFS_FBIO_READ | PUFFS_FBIO_WRITE,
|
||||
&pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1)
|
||||
goto out;
|
||||
|
||||
curev = realloc(pu->pu_evs, (2*pu->pu_nfds)*sizeof(struct kevent));
|
||||
if (curev == NULL)
|
||||
goto out;
|
||||
pu->pu_evs = curev;
|
||||
|
||||
LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
|
||||
EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD,
|
||||
0, 0, (uintptr_t)fio);
|
||||
curev++;
|
||||
EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE,
|
||||
0, 0, (uintptr_t)fio);
|
||||
curev++;
|
||||
}
|
||||
if (kevent(pu->pu_kq, pu->pu_evs, 2*pu->pu_nfds, NULL, 0, NULL) == -1)
|
||||
goto out;
|
||||
|
||||
pu->pu_state |= PU_INLOOP;
|
||||
int ndone;
|
||||
|
||||
while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
|
||||
/*
|
||||
* Schedule existing requests.
|
||||
*/
|
||||
while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
|
||||
TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
|
||||
puffs__goto(pcc);
|
||||
}
|
||||
|
||||
if (pu->pu_ml_lfn)
|
||||
pu->pu_ml_lfn(pu);
|
||||
|
||||
@ -759,7 +739,7 @@ puffs_mainloop(struct puffs_usermount *pu)
|
||||
* case is that we can fit everything into the
|
||||
* socket buffer.
|
||||
*/
|
||||
puffs_framev_output(pu, pfctrl, fio);
|
||||
puffs__framev_output(pu, pfctrl, fio);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -794,7 +774,7 @@ puffs_mainloop(struct puffs_usermount *pu)
|
||||
|
||||
if (ndone == -1) {
|
||||
if (errno != EINTR)
|
||||
goto out;
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
@ -823,32 +803,24 @@ puffs_mainloop(struct puffs_usermount *pu)
|
||||
fio->stat &= ~FIO_WR;
|
||||
|
||||
/* XXX: how to know if it's a transient error */
|
||||
puffs_framev_writeclose(pu, fio,
|
||||
puffs__framev_writeclose(pu, fio,
|
||||
(int)curev->data);
|
||||
puffs_framev_notify(fio, PUFFS_FBIO_ERROR);
|
||||
puffs__framev_notify(fio, PUFFS_FBIO_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
what = 0;
|
||||
if (curev->filter == EVFILT_READ) {
|
||||
puffs_framev_input(pu, pfctrl, fio);
|
||||
puffs__framev_input(pu, pfctrl, fio);
|
||||
what |= PUFFS_FBIO_READ;
|
||||
}
|
||||
|
||||
else if (curev->filter == EVFILT_WRITE) {
|
||||
puffs_framev_output(pu, pfctrl, fio);
|
||||
puffs__framev_output(pu, pfctrl, fio);
|
||||
what |= PUFFS_FBIO_WRITE;
|
||||
}
|
||||
if (what)
|
||||
puffs_framev_notify(fio, what);
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule continuations.
|
||||
*/
|
||||
while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
|
||||
TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
|
||||
puffs_goto(pcc);
|
||||
puffs__framev_notify(fio, what);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -860,6 +832,53 @@ puffs_mainloop(struct puffs_usermount *pu)
|
||||
free(fio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
puffs_mainloop(struct puffs_usermount *pu)
|
||||
{
|
||||
struct puffs_fctrl_io *fio;
|
||||
struct puffs_cc *pcc;
|
||||
struct kevent *curev;
|
||||
int sverrno, rv;
|
||||
|
||||
assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
|
||||
|
||||
pu->pu_kq = kqueue();
|
||||
if (pu->pu_kq == -1)
|
||||
goto out;
|
||||
pu->pu_state |= PU_HASKQ;
|
||||
|
||||
puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK);
|
||||
if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu),
|
||||
PUFFS_FBIO_READ | PUFFS_FBIO_WRITE,
|
||||
&pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1)
|
||||
goto out;
|
||||
|
||||
curev = realloc(pu->pu_evs, (2*pu->pu_nfds)*sizeof(struct kevent));
|
||||
if (curev == NULL)
|
||||
goto out;
|
||||
pu->pu_evs = curev;
|
||||
|
||||
LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
|
||||
EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD,
|
||||
0, 0, (uintptr_t)fio);
|
||||
curev++;
|
||||
EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE,
|
||||
0, 0, (uintptr_t)fio);
|
||||
curev++;
|
||||
}
|
||||
if (kevent(pu->pu_kq, pu->pu_evs, 2*pu->pu_nfds, NULL, 0, NULL) == -1)
|
||||
goto out;
|
||||
|
||||
pu->pu_state |= PU_INLOOP;
|
||||
|
||||
/* Create alternate execution context and jump to it */
|
||||
rv = puffs__cc_create(pu, puffs__theloop, &pcc);
|
||||
if (rv)
|
||||
goto out;
|
||||
puffs_cc_continue(pcc);
|
||||
|
||||
finalpush(pu);
|
||||
errno = 0;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: puffs.h,v 1.104 2008/01/14 13:57:27 pooka Exp $ */
|
||||
/* $NetBSD: puffs.h,v 1.105 2008/01/28 18:35:50 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -465,8 +465,11 @@ void puffs_vattr_null(struct vattr *);
|
||||
|
||||
void puffs_null_setops(struct puffs_ops *);
|
||||
|
||||
int puffs_dopufbuf(struct puffs_usermount *,
|
||||
struct puffs_framebuf *);
|
||||
int puffs_dispatch_create(struct puffs_usermount *,
|
||||
struct puffs_framebuf *,
|
||||
struct puffs_cc **);
|
||||
int puffs_dispatch_exec(struct puffs_cc *,
|
||||
struct puffs_framebuf **);
|
||||
|
||||
/*
|
||||
* generic/dummy routines applicable for some file systems
|
||||
@ -531,7 +534,6 @@ void puffs_cc_continue(struct puffs_cc *);
|
||||
void puffs_cc_schedule(struct puffs_cc *);
|
||||
int puffs_cc_getcaller(struct puffs_cc *,pid_t *,lwpid_t *);
|
||||
struct puffs_cc *puffs_cc_getcc(struct puffs_usermount *);
|
||||
void *puffs_docc(void *);
|
||||
|
||||
/*
|
||||
* Flushing / invalidation routines
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $NetBSD: puffs_cc.3,v 1.10 2007/12/15 20:08:06 pooka Exp $
|
||||
.\" $NetBSD: puffs_cc.3,v 1.11 2008/01/28 18:35:50 pooka Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\" Copyright (c) 2007, 2008 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
@ -23,7 +23,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd December 15, 2007
|
||||
.Dd January 28, 2008
|
||||
.Dt PUFFS_CC 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -41,8 +41,6 @@
|
||||
.Fn puffs_cc_schedule "struct puffs_cc *pcc"
|
||||
.Ft struct puffs_cc *
|
||||
.Fn puffs_cc_getcc "struct puffs_usermount *pu"
|
||||
.Ft void *
|
||||
.Fn puffs_docc "void *arg"
|
||||
.Sh DESCRIPTION
|
||||
.Em IMPORTANT NOTE!
|
||||
This document describes interfaces which are not yet guaranteed to be
|
||||
@ -61,17 +59,15 @@ in puffs.
|
||||
Suspend and save the current execution context and return control
|
||||
to the previous point.
|
||||
In practice, from the file system author perspective, control returns
|
||||
back to where either
|
||||
.Fn puffs_dopufbuf
|
||||
or
|
||||
.Fn puffs_docc
|
||||
was called.
|
||||
back to where either the mainloop or where
|
||||
.Fn puffs_dispatch_exec
|
||||
was called from.
|
||||
.It Fn puffs_cc_continue pcc
|
||||
Will suspend current execution and return control to where it was
|
||||
before before calling
|
||||
.Fn puffs_cc_yield .
|
||||
This is rarely called directly but rather through
|
||||
.Fn puffs_docc .
|
||||
.Fn puffs_dispatch_exec .
|
||||
.It Fn puffs_cc_schedule "pcc"
|
||||
Schedule a continuation.
|
||||
As opposed to
|
||||
@ -87,19 +83,6 @@ if this is the main thread.
|
||||
The argument
|
||||
.Ar pu
|
||||
will most likely disappear at some point.
|
||||
.It Fn puffs_docc "arg"
|
||||
Continues request suspended with
|
||||
.Fn puffs_cc_yield .
|
||||
If the request completes without yielding again, the result is put
|
||||
into the file server response queue.
|
||||
.Pp
|
||||
The argument must be of type
|
||||
.Vt "struct puffs_cc *" .
|
||||
The return value is ignored.
|
||||
The signature of this function is intended to match
|
||||
.Fn start_routine
|
||||
of
|
||||
.Fn pthread_create .
|
||||
.El
|
||||
.Pp
|
||||
Before calling
|
||||
@ -111,7 +94,9 @@ This cookie should be hooked to the
|
||||
so that the correct continuation can be continued when the event it
|
||||
was waiting for triggers. Alternatively, the
|
||||
.Xr puffs_framebuf 3
|
||||
framework can be used for handling this automatically.
|
||||
framework and
|
||||
.Fn puffs_mainloop
|
||||
can be used for handling this automatically.
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3 ,
|
||||
.Xr puffs_framebuf 3
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: puffs_priv.h,v 1.38 2008/01/16 21:30:00 pooka Exp $ */
|
||||
/* $NetBSD: puffs_priv.h,v 1.39 2008/01/28 18:35:50 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
|
||||
@ -91,10 +91,6 @@ struct puffs_fctrl_io {
|
||||
|| (fio->stat & FIO_ENABLE_W) == 0)) \
|
||||
&& (fio->wwait == 0)))
|
||||
|
||||
struct puffs_executor {
|
||||
struct puffs_framebuf *pex_pufbuf;
|
||||
TAILQ_ENTRY(puffs_executor) pex_entries;
|
||||
};
|
||||
|
||||
/*
|
||||
* usermount: describes one file system instance
|
||||
@ -108,6 +104,7 @@ struct puffs_usermount {
|
||||
uint32_t pu_flags;
|
||||
int pu_cc_stackshift;
|
||||
|
||||
struct puffs_cc *pu_cc_main;
|
||||
#define PUFFS_CCMAXSTORE 32
|
||||
int pu_cc_nstored;
|
||||
|
||||
@ -126,11 +123,9 @@ struct puffs_usermount {
|
||||
LIST_HEAD(, puffs_node) pu_pnodelst;
|
||||
|
||||
LIST_HEAD(, puffs_cc) pu_ccmagazin;
|
||||
LIST_HEAD(, puffs_cc) pu_ccnukelst;
|
||||
TAILQ_HEAD(, puffs_cc) pu_lazyctx;
|
||||
TAILQ_HEAD(, puffs_cc) pu_sched;
|
||||
|
||||
TAILQ_HEAD(, puffs_executor) pu_exq;
|
||||
|
||||
pu_cmap_fn pu_cmap;
|
||||
|
||||
pu_pathbuild_fn pu_pathbuild;
|
||||
@ -164,12 +159,24 @@ struct puffs_usermount {
|
||||
|
||||
/* call context */
|
||||
|
||||
struct puffs_cc;
|
||||
typedef void (*puffs_ccfunc)(struct puffs_cc *);
|
||||
|
||||
struct puffs_cc {
|
||||
struct puffs_usermount *pcc_pu;
|
||||
struct puffs_framebuf *pcc_pb;
|
||||
|
||||
ucontext_t pcc_uc; /* "continue" */
|
||||
ucontext_t pcc_uc_ret; /* "yield" */
|
||||
/* real cc */
|
||||
union {
|
||||
struct {
|
||||
ucontext_t uc; /* "continue" */
|
||||
ucontext_t uc_ret; /* "yield" */
|
||||
} real;
|
||||
struct {
|
||||
puffs_ccfunc func;
|
||||
void *farg;
|
||||
} fake;
|
||||
} pcc_u;
|
||||
|
||||
pid_t pcc_pid;
|
||||
lwpid_t pcc_lid;
|
||||
@ -179,21 +186,14 @@ struct puffs_cc {
|
||||
TAILQ_ENTRY(puffs_cc) pcc_schedent;
|
||||
LIST_ENTRY(puffs_cc) pcc_rope;
|
||||
};
|
||||
#define PCC_FAKECC 0x01
|
||||
#define PCC_REALCC 0x02
|
||||
#define PCC_DONE 0x04
|
||||
#define PCC_BORROWED 0x08
|
||||
#define PCC_HASCALLER 0x10
|
||||
#define PCC_THREADED 0x20
|
||||
|
||||
#define pcc_callstat(a) (a->pcc_flags & PCC_CALL_MASK)
|
||||
#define pcc_callset(a, b) (a->pcc_flags = (a->pcc_flags & ~PCC_CALL_MASK) | b)
|
||||
|
||||
#define pcc_init_unreal(ap, type) \
|
||||
do { \
|
||||
memset(ap, 0, sizeof(*ap)); \
|
||||
(ap)->pcc_flags = type; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#define pcc_uc pcc_u.real.uc
|
||||
#define pcc_uc_ret pcc_u.real.uc_ret
|
||||
#define pcc_func pcc_u.fake.func
|
||||
#define pcc_farg pcc_u.fake.farg
|
||||
#define PCC_DONE 0x01
|
||||
#define PCC_BORROWED 0x02
|
||||
#define PCC_HASCALLER 0x04
|
||||
#define PCC_MLCONT 0x08
|
||||
|
||||
struct puffs_newinfo {
|
||||
void **pni_cookie;
|
||||
@ -214,38 +214,40 @@ struct puffs_newinfo {
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void puffs_calldispatcher(struct puffs_cc *);
|
||||
|
||||
void puffs_framev_input(struct puffs_usermount *, struct puffs_framectrl *,
|
||||
void puffs__framev_input(struct puffs_usermount *, struct puffs_framectrl *,
|
||||
struct puffs_fctrl_io *);
|
||||
int puffs_framev_output(struct puffs_usermount *, struct puffs_framectrl*,
|
||||
int puffs__framev_output(struct puffs_usermount *, struct puffs_framectrl*,
|
||||
struct puffs_fctrl_io *);
|
||||
void puffs_framev_exit(struct puffs_usermount *);
|
||||
void puffs_framev_readclose(struct puffs_usermount *,
|
||||
void puffs__framev_exit(struct puffs_usermount *);
|
||||
void puffs__framev_readclose(struct puffs_usermount *,
|
||||
struct puffs_fctrl_io *, int);
|
||||
void puffs_framev_writeclose(struct puffs_usermount *,
|
||||
void puffs__framev_writeclose(struct puffs_usermount *,
|
||||
struct puffs_fctrl_io *, int);
|
||||
void puffs_framev_notify(struct puffs_fctrl_io *, int);
|
||||
void puffs__framev_notify(struct puffs_fctrl_io *, int);
|
||||
void *puffs__framebuf_getdataptr(struct puffs_framebuf *);
|
||||
int puffs__framev_addfd_ctrl(struct puffs_usermount *, int, int,
|
||||
struct puffs_framectrl *);
|
||||
void puffs__framebuf_moveinfo(struct puffs_framebuf *,
|
||||
struct puffs_framebuf *);
|
||||
|
||||
int puffs_cc_create(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, struct puffs_cc **);
|
||||
void puffs_cc_destroy(struct puffs_cc *);
|
||||
void puffs_cc_setcaller(struct puffs_cc *, pid_t, lwpid_t);
|
||||
void puffs_goto(struct puffs_cc *);
|
||||
void puffs__theloop(struct puffs_cc *);
|
||||
void puffs__ml_dispatch(struct puffs_usermount *, struct puffs_framebuf *);
|
||||
|
||||
int puffs_fsframe_read(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, int *);
|
||||
int puffs_fsframe_write(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, int *);
|
||||
int puffs_fsframe_cmp(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
struct puffs_framebuf *, int *);
|
||||
void puffs_fsframe_gotframe(struct puffs_usermount *,
|
||||
struct puffs_framebuf *);
|
||||
int puffs__cc_create(struct puffs_usermount *, puffs_ccfunc,
|
||||
struct puffs_cc **);
|
||||
void puffs__cc_cont(struct puffs_cc *);
|
||||
void puffs__cc_destroy(struct puffs_cc *, int);
|
||||
void puffs__cc_setcaller(struct puffs_cc *, pid_t, lwpid_t);
|
||||
void puffs__goto(struct puffs_cc *);
|
||||
|
||||
int puffs__fsframe_read(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, int *);
|
||||
int puffs__fsframe_write(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, int *);
|
||||
int puffs__fsframe_cmp(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
struct puffs_framebuf *, int *);
|
||||
void puffs__fsframe_gotframe(struct puffs_usermount *,
|
||||
struct puffs_framebuf *);
|
||||
|
||||
uint64_t puffs__nextreq(struct puffs_usermount *pu);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: requests.c,v 1.20 2007/12/05 11:06:05 pooka Exp $ */
|
||||
/* $NetBSD: requests.c,v 1.21 2008/01/28 18:35:51 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: requests.c,v 1.20 2007/12/05 11:06:05 pooka Exp $");
|
||||
__RCSID("$NetBSD: requests.c,v 1.21 2008/01/28 18:35:51 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -56,7 +56,7 @@ __RCSID("$NetBSD: requests.c,v 1.20 2007/12/05 11:06:05 pooka Exp $");
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
puffs__fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
int fd, int *done)
|
||||
{
|
||||
struct putter_hdr phdr;
|
||||
@ -117,7 +117,7 @@ puffs_fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
puffs__fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
int fd, int *done)
|
||||
{
|
||||
void *win;
|
||||
@ -200,7 +200,7 @@ puffs_fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fsframe_cmp(struct puffs_usermount *pu,
|
||||
puffs__fsframe_cmp(struct puffs_usermount *pu,
|
||||
struct puffs_framebuf *pb1, struct puffs_framebuf *pb2, int *notresp)
|
||||
{
|
||||
struct puffs_req *preq1, *preq2;
|
||||
@ -233,7 +233,7 @@ puffs_fsframe_cmp(struct puffs_usermount *pu,
|
||||
}
|
||||
|
||||
void
|
||||
puffs_fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
puffs__fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
{
|
||||
struct puffs_framebuf *newpb;
|
||||
|
||||
@ -245,5 +245,5 @@ puffs_fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
if (puffs_framebuf_reserve_space(newpb, PUFFS_MSG_MAXSIZE) == -1)
|
||||
abort();
|
||||
|
||||
puffs_dopufbuf(pu, newpb);
|
||||
puffs__ml_dispatch(pu, newpb);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user