2011-11-14 12:53:05 +01:00
|
|
|
/* $NetBSD: puffs.c,v 1.92.4.4 2009/10/27 20:37:38 bouyer Exp $ */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Development of this software was supported by the
|
|
|
|
* Google Summer of Code program and the Ulla Tuominen Foundation.
|
|
|
|
* The Google SoC project was mentored by Bill Studenmund.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* TODO: We don't support PUFFS_COMFD used in original puffs_mount,
|
|
|
|
* add it to the docs if any.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fs.h"
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
#if !defined(lint)
|
|
|
|
__RCSID("$NetBSD: puffs.c,v 1.92.4.4 2009/10/27 20:37:38 bouyer Exp $");
|
|
|
|
#endif /* !lint */
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
|
|
|
|
#include <minix/endpoint.h>
|
|
|
|
#include <minix/vfsif.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <err.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <paths.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "puffs.h"
|
|
|
|
#include "puffs_priv.h"
|
|
|
|
|
|
|
|
#ifdef PUFFS_WITH_THREADS
|
|
|
|
#include <pthread.h>
|
|
|
|
pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Declare some local functions. */
|
2012-03-25 20:25:53 +02:00
|
|
|
static void get_work(message *m_in);
|
|
|
|
static void reply(endpoint_t who, message *m_out);
|
2011-11-14 12:53:05 +01:00
|
|
|
|
|
|
|
/* SEF functions and variables. */
|
2012-03-25 20:25:53 +02:00
|
|
|
static void sef_local_startup(void);
|
|
|
|
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
|
|
|
static void sef_cb_signal_handler(int signo);
|
2011-11-14 12:53:05 +01:00
|
|
|
|
|
|
|
EXTERN int env_argc;
|
|
|
|
EXTERN char **env_argv;
|
|
|
|
|
|
|
|
|
|
|
|
#define PUFFS_MAX_ARGS 20
|
|
|
|
|
|
|
|
int __real_main(int argc, char* argv[]);
|
|
|
|
|
|
|
|
int __wrap_main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int new_argc = 0;
|
|
|
|
static char* new_argv[PUFFS_MAX_ARGS];
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
/* SEF local startup. */
|
|
|
|
env_setargs(argc, argv);
|
|
|
|
sef_local_startup();
|
|
|
|
|
|
|
|
global_kcred.pkcr_type = PUFFCRED_TYPE_INTERNAL;
|
|
|
|
|
|
|
|
if (argc < 3) {
|
|
|
|
panic("Unexpected arguments, use:\
|
|
|
|
mount -t fs /dev/ /dir [-o option1,option2]\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
name = argv[0] + strlen(argv[0]);
|
|
|
|
while (*name != '/' && name != argv[0])
|
|
|
|
name--;
|
|
|
|
if (name != argv[0])
|
|
|
|
name++;
|
|
|
|
strcpy(fs_name, name);
|
|
|
|
|
|
|
|
new_argv[new_argc] = argv[0];
|
|
|
|
new_argc++;
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
if (new_argc >= PUFFS_MAX_ARGS) {
|
|
|
|
panic("Too many arguments, change PUFFS_MAX_ARGS");
|
|
|
|
}
|
|
|
|
new_argv[new_argc] = argv[i];
|
|
|
|
new_argc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(new_argc > 0);
|
|
|
|
|
|
|
|
get_work(&fs_m_in);
|
|
|
|
|
|
|
|
return __real_main(new_argc, new_argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define FILLOP(lower, upper) \
|
|
|
|
do { \
|
|
|
|
if (pops->puffs_node_##lower) \
|
|
|
|
opmask[PUFFS_VN_##upper] = 1; \
|
|
|
|
} while (/*CONSTCOND*/0)
|
|
|
|
static void
|
|
|
|
fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
|
|
|
|
{
|
|
|
|
|
|
|
|
memset(opmask, 0, PUFFS_VN_MAX);
|
|
|
|
|
|
|
|
FILLOP(create, CREATE);
|
|
|
|
FILLOP(mknod, MKNOD);
|
|
|
|
FILLOP(open, OPEN);
|
|
|
|
FILLOP(close, CLOSE);
|
|
|
|
FILLOP(access, ACCESS);
|
|
|
|
FILLOP(getattr, GETATTR);
|
|
|
|
FILLOP(setattr, SETATTR);
|
|
|
|
FILLOP(poll, POLL); /* XXX: not ready in kernel */
|
|
|
|
FILLOP(mmap, MMAP);
|
|
|
|
FILLOP(fsync, FSYNC);
|
|
|
|
FILLOP(seek, SEEK);
|
|
|
|
FILLOP(remove, REMOVE);
|
|
|
|
FILLOP(link, LINK);
|
|
|
|
FILLOP(rename, RENAME);
|
|
|
|
FILLOP(mkdir, MKDIR);
|
|
|
|
FILLOP(rmdir, RMDIR);
|
|
|
|
FILLOP(symlink, SYMLINK);
|
|
|
|
FILLOP(readdir, READDIR);
|
|
|
|
FILLOP(readlink, READLINK);
|
|
|
|
FILLOP(reclaim, RECLAIM);
|
|
|
|
FILLOP(inactive, INACTIVE);
|
|
|
|
FILLOP(print, PRINT);
|
|
|
|
FILLOP(read, READ);
|
|
|
|
FILLOP(write, WRITE);
|
|
|
|
FILLOP(abortop, ABORTOP);
|
|
|
|
}
|
|
|
|
#undef FILLOP
|
|
|
|
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
static void
|
|
|
|
puffs_defaulterror(struct puffs_usermount *pu, uint8_t type,
|
|
|
|
int error, const char *str, puffs_cookie_t cookie)
|
|
|
|
{
|
|
|
|
|
|
|
|
lpuffs_debug("abort: type %d, error %d, cookie %p (%s)\n",
|
|
|
|
type, error, cookie, str);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
puffs_getstate(struct puffs_usermount *pu)
|
|
|
|
{
|
|
|
|
|
|
|
|
return pu->pu_state & PU_STATEMASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
|
|
|
|
{
|
|
|
|
long psize, minsize;
|
|
|
|
int stackshift;
|
|
|
|
int bonus;
|
|
|
|
|
|
|
|
assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT);
|
|
|
|
|
|
|
|
psize = sysconf(_SC_PAGESIZE);
|
|
|
|
minsize = 4*psize;
|
|
|
|
if (ss < minsize || ss == PUFFS_STACKSIZE_MIN) {
|
|
|
|
if (ss != PUFFS_STACKSIZE_MIN)
|
|
|
|
lpuffs_debug("puffs_setstacksize: adjusting "
|
|
|
|
"stacksize to minimum %ld\n", minsize);
|
|
|
|
ss = 4*psize;
|
|
|
|
}
|
|
|
|
|
|
|
|
stackshift = -1;
|
|
|
|
bonus = 0;
|
|
|
|
while (ss) {
|
|
|
|
if (ss & 0x1)
|
|
|
|
bonus++;
|
|
|
|
ss >>= 1;
|
|
|
|
stackshift++;
|
|
|
|
}
|
|
|
|
if (bonus > 1) {
|
|
|
|
stackshift++;
|
|
|
|
lpuffs_debug("puffs_setstacksize: using next power of two: "
|
|
|
|
"%d\n", 1<<stackshift);
|
|
|
|
}
|
|
|
|
|
|
|
|
pu->pu_cc_stackshift = stackshift;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct puffs_pathobj *
|
|
|
|
puffs_getrootpathobj(struct puffs_usermount *pu)
|
|
|
|
{
|
|
|
|
struct puffs_node *pnr;
|
|
|
|
|
|
|
|
pnr = pu->pu_pn_root;
|
|
|
|
if (pnr == NULL) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &pnr->pn_po;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_pn_root = pn;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct puffs_node *
|
|
|
|
puffs_getroot(struct puffs_usermount *pu)
|
|
|
|
{
|
|
|
|
|
|
|
|
return pu->pu_pn_root;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt,
|
|
|
|
vsize_t vsize, dev_t rdev)
|
|
|
|
{
|
|
|
|
struct puffs_kargs *pargs = pu->pu_kargp;
|
|
|
|
|
|
|
|
if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) {
|
|
|
|
warnx("puffs_setrootinfo: call has effect only "
|
|
|
|
"before mount\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pargs->pa_root_vtype = vt;
|
|
|
|
pargs->pa_root_vsize = vsize;
|
|
|
|
pargs->pa_root_rdev = rdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
puffs_getspecific(struct puffs_usermount *pu)
|
|
|
|
{
|
|
|
|
|
|
|
|
return pu->pu_privdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setspecific(struct puffs_usermount *pu, void *privdata)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_privdata = privdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setmntinfo(struct puffs_usermount *pu,
|
|
|
|
const char *mntfromname, const char *puffsname)
|
|
|
|
{
|
|
|
|
struct puffs_kargs *pargs = pu->pu_kargp;
|
|
|
|
|
|
|
|
(void)strlcpy(pargs->pa_mntfromname, mntfromname,
|
|
|
|
sizeof(pargs->pa_mntfromname));
|
|
|
|
(void)strlcpy(pargs->pa_typename, puffsname,
|
|
|
|
sizeof(pargs->pa_typename));
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
puffs_getmaxreqlen(struct puffs_usermount *pu)
|
|
|
|
{
|
|
|
|
|
|
|
|
return pu->pu_maxreqlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
|
|
|
|
warnx("puffs_setmaxreqlen: call has effect only "
|
|
|
|
"before mount\n");
|
|
|
|
|
|
|
|
pu->pu_kargp->pa_maxmsglen = reqlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
|
|
|
|
warnx("puffs_setfhsize: call has effect only before mount\n");
|
|
|
|
|
|
|
|
pu->pu_kargp->pa_fhsize = fhsize;
|
|
|
|
pu->pu_kargp->pa_fhflags = flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_setncookiehash(struct puffs_usermount *pu, int nhash)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT)
|
|
|
|
warnx("puffs_setfhsize: call has effect only before mount\n");
|
|
|
|
|
|
|
|
pu->pu_kargp->pa_nhashbuckets = nhash;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_pathbuild = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_pathtransform = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_pathcmp = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_pathfree = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_namemod = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_errnotify = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_cmap = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_ml_lfn = lfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (ts == NULL) {
|
|
|
|
pu->pu_ml_timep = NULL;
|
|
|
|
} else {
|
|
|
|
pu->pu_ml_timeout = *ts;
|
|
|
|
pu->pu_ml_timep = &pu->pu_ml_timeout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_set_prepost(struct puffs_usermount *pu,
|
|
|
|
pu_prepost_fn pre, pu_prepost_fn pst)
|
|
|
|
{
|
|
|
|
|
|
|
|
pu->pu_oppre = pre;
|
|
|
|
pu->pu_oppost = pst;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
|
|
|
|
puffs_cookie_t cookie)
|
|
|
|
{
|
|
|
|
endpoint_t src;
|
|
|
|
int error, ind;
|
|
|
|
|
|
|
|
pu->pu_kargp->pa_root_cookie = cookie;
|
|
|
|
|
|
|
|
src = fs_m_in.m_source;
|
|
|
|
error = OK;
|
|
|
|
caller_uid = INVAL_UID; /* To trap errors */
|
|
|
|
caller_gid = INVAL_GID;
|
|
|
|
req_nr = fs_m_in.m_type;
|
|
|
|
|
|
|
|
if (req_nr < VFS_BASE) {
|
|
|
|
fs_m_in.m_type += VFS_BASE;
|
|
|
|
req_nr = fs_m_in.m_type;
|
|
|
|
}
|
|
|
|
ind = req_nr - VFS_BASE;
|
|
|
|
|
|
|
|
assert(ind == REQ_READ_SUPER);
|
|
|
|
|
|
|
|
if (ind < 0 || ind >= NREQS) {
|
|
|
|
error = EINVAL;
|
|
|
|
} else {
|
|
|
|
error = (*fs_call_vec[ind])();
|
|
|
|
}
|
|
|
|
|
|
|
|
fs_m_out.m_type = error;
|
|
|
|
if (IS_VFS_FS_TRANSID(last_request_transid)) {
|
|
|
|
/* If a transaction ID was set, reset it */
|
|
|
|
fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type,
|
|
|
|
last_request_transid);
|
|
|
|
}
|
|
|
|
reply(src, &fs_m_out);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
free(pu->pu_kargp);
|
|
|
|
pu->pu_kargp = NULL;
|
|
|
|
errno = error;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
struct puffs_usermount *
|
|
|
|
_puffs_init(int dummy, struct puffs_ops *pops, const char *mntfromname,
|
|
|
|
const char *puffsname, void *priv, uint32_t pflags)
|
|
|
|
{
|
|
|
|
struct puffs_usermount *pu;
|
|
|
|
struct puffs_kargs *pargs;
|
|
|
|
int sverrno;
|
|
|
|
|
|
|
|
if (puffsname == PUFFS_DEFER)
|
|
|
|
puffsname = "n/a";
|
|
|
|
if (mntfromname == PUFFS_DEFER)
|
|
|
|
mntfromname = "n/a";
|
|
|
|
if (priv == PUFFS_DEFER)
|
|
|
|
priv = NULL;
|
|
|
|
|
|
|
|
pu = malloc(sizeof(struct puffs_usermount));
|
|
|
|
if (pu == NULL)
|
|
|
|
goto failfree;
|
|
|
|
memset(pu, 0, sizeof(struct puffs_usermount));
|
|
|
|
|
|
|
|
pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs));
|
|
|
|
if (pargs == NULL)
|
|
|
|
goto failfree;
|
|
|
|
memset(pargs, 0, sizeof(struct puffs_kargs));
|
|
|
|
|
|
|
|
pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
|
|
|
|
pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
|
|
|
|
fillvnopmask(pops, pargs->pa_vnopmask);
|
|
|
|
puffs_setmntinfo(pu, mntfromname, puffsname);
|
|
|
|
|
|
|
|
puffs_zerostatvfs(&pargs->pa_svfsb);
|
|
|
|
pargs->pa_root_cookie = NULL;
|
|
|
|
pargs->pa_root_vtype = VDIR;
|
|
|
|
pargs->pa_root_vsize = 0;
|
|
|
|
pargs->pa_root_rdev = 0;
|
|
|
|
pargs->pa_maxmsglen = 0;
|
|
|
|
|
|
|
|
pu->pu_flags = pflags;
|
|
|
|
buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; /* XXX */
|
|
|
|
pu->pu_ops = *pops;
|
|
|
|
free(pops); /* XXX */
|
|
|
|
|
|
|
|
pu->pu_privdata = priv;
|
|
|
|
pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT;
|
|
|
|
LIST_INIT(&pu->pu_pnodelst);
|
|
|
|
LIST_INIT(&pu->pu_pnode_removed_lst);
|
|
|
|
LIST_INIT(&pu->pu_ios);
|
|
|
|
LIST_INIT(&pu->pu_ios_rmlist);
|
|
|
|
LIST_INIT(&pu->pu_ccmagazin);
|
|
|
|
TAILQ_INIT(&pu->pu_sched);
|
|
|
|
|
|
|
|
/* defaults for some user-settable translation functions */
|
|
|
|
pu->pu_cmap = NULL; /* identity translation */
|
|
|
|
|
|
|
|
pu->pu_pathbuild = puffs_stdpath_buildpath;
|
|
|
|
pu->pu_pathfree = puffs_stdpath_freepath;
|
|
|
|
pu->pu_pathcmp = puffs_stdpath_cmppath;
|
|
|
|
pu->pu_pathtransform = NULL;
|
|
|
|
pu->pu_namemod = NULL;
|
|
|
|
|
|
|
|
pu->pu_errnotify = puffs_defaulterror;
|
|
|
|
|
|
|
|
PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT);
|
|
|
|
|
|
|
|
global_pu = pu;
|
|
|
|
|
|
|
|
return pu;
|
|
|
|
|
|
|
|
failfree:
|
|
|
|
/* can't unmount() from here for obvious reasons */
|
|
|
|
sverrno = errno;
|
|
|
|
free(pu);
|
|
|
|
errno = sverrno;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
puffs_cancel(struct puffs_usermount *pu, int error)
|
|
|
|
{
|
|
|
|
assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING);
|
|
|
|
free(pu);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*ARGSUSED1*/
|
|
|
|
int
|
|
|
|
puffs_exit(struct puffs_usermount *pu, int force)
|
|
|
|
{
|
|
|
|
struct puffs_node *pn;
|
|
|
|
|
|
|
|
lpuffs_debug("puffs_exit\n");
|
|
|
|
|
|
|
|
while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL)
|
|
|
|
puffs_pn_put(pn);
|
|
|
|
|
|
|
|
while ((pn = LIST_FIRST(&pu->pu_pnode_removed_lst)) != NULL)
|
|
|
|
puffs_pn_put(pn);
|
|
|
|
|
|
|
|
puffs__cc_exit(pu);
|
|
|
|
if (pu->pu_state & PU_HASKQ)
|
|
|
|
close(pu->pu_kq);
|
|
|
|
free(pu);
|
|
|
|
|
|
|
|
return 0; /* always succesful for now, WILL CHANGE */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
int error, ind;
|
|
|
|
|
|
|
|
while (!unmountdone || !exitsignaled) {
|
|
|
|
endpoint_t src;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Schedule existing requests.
|
|
|
|
*/
|
|
|
|
while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
|
|
|
|
lpuffs_debug("scheduling existing tasks\n");
|
|
|
|
TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
|
|
|
|
puffs__goto(pcc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pu->pu_ml_lfn) {
|
|
|
|
lpuffs_debug("Calling user mainloop handler\n");
|
|
|
|
pu->pu_ml_lfn(pu);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for request message. */
|
|
|
|
get_work(&fs_m_in);
|
|
|
|
|
|
|
|
src = fs_m_in.m_source;
|
|
|
|
error = OK;
|
|
|
|
caller_uid = INVAL_UID; /* To trap errors */
|
|
|
|
caller_gid = INVAL_GID;
|
|
|
|
req_nr = fs_m_in.m_type;
|
|
|
|
|
|
|
|
if (req_nr < VFS_BASE) {
|
|
|
|
fs_m_in.m_type += VFS_BASE;
|
|
|
|
req_nr = fs_m_in.m_type;
|
|
|
|
}
|
|
|
|
ind = req_nr - VFS_BASE;
|
|
|
|
|
|
|
|
if (ind < 0 || ind >= NREQS) {
|
|
|
|
error = EINVAL;
|
|
|
|
} else {
|
|
|
|
error = (*fs_call_vec[ind])();
|
|
|
|
}
|
|
|
|
|
|
|
|
fs_m_out.m_type = error;
|
|
|
|
if (IS_VFS_FS_TRANSID(last_request_transid)) {
|
|
|
|
/* If a transaction ID was set, reset it */
|
|
|
|
fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, last_request_transid);
|
|
|
|
}
|
|
|
|
reply(src, &fs_m_out);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (puffs__cc_restoremain(pu) == -1)
|
|
|
|
warn("cannot restore main context. impending doom");
|
|
|
|
|
|
|
|
/* May get here, if puffs_fakecc is set to 1. Currently librefuse sets it.
|
|
|
|
* Now we just return to the caller.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
puffs_mainloop(struct puffs_usermount *pu)
|
|
|
|
{
|
|
|
|
struct puffs_cc *pcc;
|
|
|
|
int sverrno;
|
|
|
|
|
|
|
|
assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
|
|
|
|
|
|
|
|
pu->pu_state |= PU_HASKQ | PU_INLOOP;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create alternate execution context and jump to it. Note
|
|
|
|
* that we come "out" of savemain twice. Where we come out
|
|
|
|
* of it depends on the architecture. If the return address is
|
|
|
|
* stored on the stack, we jump out from puffs_cc_continue(),
|
|
|
|
* for a register return address from puffs__cc_savemain().
|
|
|
|
* PU_MAINRESTORE makes sure we DTRT in both cases.
|
|
|
|
*/
|
|
|
|
if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (puffs__cc_savemain(pu) == -1) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if ((pu->pu_state & PU_MAINRESTORE) == 0)
|
|
|
|
puffs_cc_continue(pcc);
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
/* store the real error for a while */
|
|
|
|
sverrno = errno;
|
|
|
|
|
|
|
|
errno = sverrno;
|
|
|
|
if (errno)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* sef_local_startup *
|
|
|
|
*===========================================================================*/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void sef_local_startup()
|
2011-11-14 12:53:05 +01:00
|
|
|
{
|
|
|
|
/* Register init callbacks. */
|
|
|
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
|
|
|
sef_setcb_init_restart(sef_cb_init_fail);
|
|
|
|
|
|
|
|
/* No live update support for now. */
|
|
|
|
|
|
|
|
/* Register signal callbacks. */
|
|
|
|
sef_setcb_signal_handler(sef_cb_signal_handler);
|
|
|
|
|
|
|
|
/* Let SEF perform startup. */
|
|
|
|
sef_startup();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* sef_cb_init_fresh *
|
|
|
|
*===========================================================================*/
|
2012-03-25 20:25:53 +02:00
|
|
|
static int sef_cb_init_fresh(int type, sef_init_info_t *info)
|
2011-11-14 12:53:05 +01:00
|
|
|
{
|
|
|
|
/* Initialize the Minix file server. */
|
|
|
|
SELF_E = getprocnr();
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* sef_cb_signal_handler *
|
|
|
|
*===========================================================================*/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void sef_cb_signal_handler(int signo)
|
2011-11-14 12:53:05 +01:00
|
|
|
{
|
|
|
|
/* Only check for termination signal, ignore anything else. */
|
|
|
|
if (signo != SIGTERM) return;
|
|
|
|
|
|
|
|
exitsignaled = 1;
|
|
|
|
fs_sync();
|
|
|
|
|
|
|
|
/* If unmounting has already been performed, exit immediately.
|
|
|
|
* We might not get another message.
|
|
|
|
*/
|
|
|
|
if (unmountdone) {
|
|
|
|
if (puffs__cc_restoremain(global_pu) == -1)
|
|
|
|
warn("cannot restore main context. impending doom");
|
|
|
|
/* May happen if puffs_fakecc is set to 1. Currently librefuse sets it.
|
|
|
|
* There is a chance, that main loop hangs in receive() and we will
|
|
|
|
* never get any new message, so we have to exit() here.
|
|
|
|
*/
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* get_work *
|
|
|
|
*===========================================================================*/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void get_work(m_in)
|
2011-11-14 12:53:05 +01:00
|
|
|
message *m_in; /* pointer to message */
|
|
|
|
{
|
|
|
|
int r, srcok = 0;
|
|
|
|
endpoint_t src;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if ((r = sef_receive(ANY, m_in)) != OK) /* wait for message */
|
|
|
|
panic("sef_receive failed: %d", r);
|
|
|
|
src = m_in->m_source;
|
|
|
|
|
|
|
|
if(src == VFS_PROC_NR) {
|
|
|
|
if(unmountdone)
|
|
|
|
lpuffs_debug("libpuffs: unmounted: unexpected message from FS\n");
|
|
|
|
else
|
|
|
|
srcok = 1; /* Normal FS request. */
|
|
|
|
|
|
|
|
} else
|
|
|
|
lpuffs_debug("libpuffs: unexpected source %d\n", src);
|
|
|
|
} while(!srcok);
|
|
|
|
|
|
|
|
assert((src == VFS_PROC_NR && !unmountdone));
|
|
|
|
|
|
|
|
last_request_transid = TRNS_GET_ID(fs_m_in.m_type);
|
|
|
|
fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type);
|
|
|
|
if (fs_m_in.m_type == 0) {
|
|
|
|
assert(!IS_VFS_FS_TRANSID(last_request_transid));
|
|
|
|
fs_m_in.m_type = last_request_transid; /* Backwards compat. */
|
|
|
|
last_request_transid = 0;
|
|
|
|
} else
|
|
|
|
assert(IS_VFS_FS_TRANSID(last_request_transid));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* reply *
|
|
|
|
*===========================================================================*/
|
2012-03-25 20:25:53 +02:00
|
|
|
static void reply(
|
2011-11-14 12:53:05 +01:00
|
|
|
endpoint_t who,
|
|
|
|
message *m_out /* report result */
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (OK != send(who, m_out)) /* send the message */
|
|
|
|
lpuffs_debug("libpuffs(%d) was unable to send reply\n", SELF_E);
|
|
|
|
|
|
|
|
last_request_transid = 0;
|
|
|
|
}
|
|
|
|
|