[BACK]Return to perfuse.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libperfuse

Annotation of src/lib/libperfuse/perfuse.c, Revision 1.20

1.20    ! christos    1: /*  $NetBSD: perfuse.c,v 1.19 2011/09/09 15:35:22 manu Exp $ */
1.1       manu        2:
                      3: /*-
1.12      manu        4:  *  Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
1.1       manu        5:  *
                      6:  *  Redistribution and use in source and binary forms, with or without
                      7:  *  modification, are permitted provided that the following conditions
                      8:  *  are met:
                      9:  *  1. Redistributions of source code must retain the above copyright
                     10:  *     notice, this list of conditions and the following disclaimer.
                     11:  *  2. Redistributions in binary form must reproduce the above copyright
                     12:  *     notice, this list of conditions and the following disclaimer in the
                     13:  *     documentation and/or other materials provided with the distribution.
                     14:  *
                     15:  *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     16:  *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     17:  *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     18:  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     19:  *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     20:  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     21:  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     22:  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     23:  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     24:  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     25:  *  POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include <stdio.h>
                     29: #include <unistd.h>
                     30: #include <stdlib.h>
                     31: #include <fcntl.h>
                     32: #include <string.h>
                     33: #include <errno.h>
                     34: #include <puffs.h>
                     35: #include <sys/types.h>
1.19      manu       36: #include <sys/mman.h>
1.1       manu       37: #include <sys/socket.h>
1.16      manu       38: #include <sys/extattr.h>
1.1       manu       39: #include <sys/un.h>
1.6       manu       40: #include <machine/vmparam.h>
1.1       manu       41:
                     42: #define LIBPERFUSE
                     43: #include "perfuse.h"
                     44: #include "perfuse_if.h"
                     45: #include "perfuse_priv.h"
                     46:
                     47: int perfuse_diagflags = 0; /* global used only in DPRINTF/DERR/DWARN */
1.12      manu       48: extern char **environ;
1.1       manu       49:
                     50: static struct perfuse_state *init_state(void);
                     51: static int get_fd(const char *);
                     52:
1.12      manu       53:
1.1       manu       54: static struct perfuse_state *
                     55: init_state(void)
                     56: {
                     57:        struct perfuse_state *ps;
1.12      manu       58:        char opts[1024];
1.1       manu       59:
                     60:        if ((ps = malloc(sizeof(*ps))) == NULL)
1.18      christos   61:                DERR(EX_OSERR, "%s: malloc failed", __func__);
1.1       manu       62:
                     63:        (void)memset(ps, 0, sizeof(*ps));
                     64:        ps->ps_max_write = UINT_MAX;
                     65:        ps->ps_max_readahead = UINT_MAX;
                     66:
1.12      manu       67:        /*
                     68:         * Most of the time, access() is broken because the filesystem
                     69:         * performs the check with root privileges. glusterfs will do that
                     70:         * if the Linux-specific setfsuid() is missing, for instance.
                     71:         */
                     72:        ps->ps_flags |= PS_NO_ACCESS;
                     73:
                     74:        /*
                     75:         * This is a temporary way to toggle access and creat usage.
                     76:         * It would be nice if that could be provided as mount options,
                     77:         * but that will not be obvious to do.
                     78:         */
                     79:        if (getenv_r("PERFUSE_OPTIONS", opts, sizeof(opts)) != -1) {
                     80:                char *optname;
                     81:                char *last;
                     82:
                     83:                 for ((optname = strtok_r(opts, ",", &last));
                     84:                      optname != NULL;
                     85:                      (optname = strtok_r(NULL, ",", &last))) {
                     86:                        if (strcmp(optname, "enable_access") == 0)
                     87:                                ps->ps_flags &= ~PS_NO_ACCESS;
                     88:
                     89:                        if (strcmp(optname, "disable_access") == 0)
                     90:                                ps->ps_flags |= PS_NO_ACCESS;
                     91:
                     92:                        if (strcmp(optname, "enable_creat") == 0)
                     93:                                ps->ps_flags &= ~PS_NO_CREAT;
                     94:
                     95:                        if (strcmp(optname, "disable_creat") == 0)
                     96:                                ps->ps_flags |= PS_NO_CREAT;
                     97:                }
                     98:        }
                     99:
                    100:
1.1       manu      101:        return ps;
                    102: }
                    103:
                    104:
                    105: static int
                    106: get_fd(data)
                    107:        const char *data;
                    108: {
                    109:        char *string;
                    110:        const char fdopt[] = "fd=";
                    111:        char *lastp;
                    112:        char *opt;
                    113:        int fd = -1;
                    114:
                    115:        if ((string = strdup(data)) == NULL)
                    116:                return -1;
                    117:
                    118:        for (opt = strtok_r(string, ",", &lastp);
                    119:             opt != NULL;
                    120:             opt = strtok_r(NULL, ",", &lastp)) {
                    121:                if (strncmp(opt, fdopt, strlen(fdopt)) == 0) {
                    122:                        fd =  atoi(opt + strlen(fdopt));
                    123:                        break;
                    124:                }
                    125:        }
                    126:
                    127:        /*
                    128:         * No file descriptor found
                    129:         */
                    130:        if (fd == -1)
                    131:                errno = EINVAL;
                    132:
                    133:        free(string);
                    134:        return fd;
                    135:
                    136: }
                    137:
                    138: int
                    139: perfuse_open(path, flags, mode)
                    140:        const char *path;
                    141:        int flags;
                    142:        mode_t mode;
                    143: {
1.2       manu      144:        int sv[2];
1.1       manu      145:        struct sockaddr_un sun;
                    146:        struct sockaddr *sa;
1.2       manu      147:        char progname[] = _PATH_PERFUSED;
                    148:        char minus_i[] = "-i";
                    149:        char fdstr[16];
                    150:        char *const argv[] = { progname, minus_i, fdstr, NULL};
1.6       manu      151:        uint32_t opt;
1.12      manu      152:        uint32_t optlen;
1.15      manu      153:        int sock_type = SOCK_SEQPACKET;
1.1       manu      154:
                    155:        if (strcmp(path, _PATH_FUSE) != 0)
                    156:                return open(path, flags, mode);
                    157:
1.15      manu      158:        /*
                    159:         * Try SOCK_SEQPACKET then SOCK_DGRAM if unavailable
                    160:         */
                    161:        if ((sv[0] = socket(PF_LOCAL, SOCK_SEQPACKET, 0)) == -1) {
                    162:                sock_type = SOCK_DGRAM;
                    163:                 DWARNX("SEQPACKET local sockets unavailable, using less "
                    164:                       "reliable DGRAM sockets. Expect file operation hangs.");
                    165:
                    166:                if ((sv[0] = socket(PF_LOCAL, SOCK_DGRAM, 0)) == -1) {
1.1       manu      167: #ifdef PERFUSE_DEBUG
1.18      christos  168:                        DWARN("%s: %d socket failed", __func__, __LINE__);
1.1       manu      169: #endif
1.15      manu      170:                        return -1;
                    171:                }
1.1       manu      172:        }
                    173:
1.6       manu      174:        /*
                    175:         * Set a buffer lentgh large enough so that any FUSE packet
                    176:         * will fit.
                    177:         */
1.20    ! christos  178:        opt = (uint32_t)FUSE_BUFSIZE;
1.12      manu      179:        optlen = sizeof(opt);
                    180:        if (setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &opt, optlen) != 0)
1.6       manu      181:                DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt);
                    182:
1.12      manu      183:        if (setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &opt, optlen) != 0)
1.6       manu      184:                DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt);
                    185:
1.1       manu      186:        sa = (struct sockaddr *)(void *)&sun;
                    187:        sun.sun_len = sizeof(sun);
                    188:        sun.sun_family = AF_LOCAL;
                    189:        (void)strcpy(sun.sun_path, path);
                    190:
1.15      manu      191:        if (connect(sv[0], sa, (socklen_t)sun.sun_len) == 0)
1.2       manu      192:                return sv[0];
                    193:
                    194:        /*
                    195:         * Attempt to run perfused on our own
                    196:         * if it does not run yet; In that case
                    197:         * we will talk using a socketpair
                    198:         * instead of /dev/fuse.
                    199:         */
1.15      manu      200:        if (socketpair(PF_LOCAL, sock_type, 0, sv) != 0) {
1.5       manu      201:                DWARN("%s:%d: socketpair failed", __func__, __LINE__);
1.1       manu      202:                return -1;
                    203:        }
                    204:
1.6       manu      205:        /*
                    206:         * Set a buffer lentgh large enough so that any FUSE packet
                    207:         * will fit.
                    208:         */
1.20    ! christos  209:        opt = (uint32_t)(4 * FUSE_BUFSIZE);
1.12      manu      210:        optlen = sizeof(opt);
                    211:        if (setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &opt, optlen) != 0)
1.6       manu      212:                DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt);
                    213:
1.12      manu      214:        if (setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &opt, optlen) != 0)
1.6       manu      215:                DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt);
                    216:
1.12      manu      217:        if (setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &opt, optlen) != 0)
1.6       manu      218:                DWARN("%s: setsockopt SO_SNDBUF to %d failed", __func__, opt);
                    219:
1.12      manu      220:        if (setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &opt, optlen) != 0)
1.6       manu      221:                DWARN("%s: setsockopt SO_RCVBUF to %d failed", __func__, opt);
                    222:
                    223:        /*
                    224:         * Request peer credentials. This musr be done before first
                    225:         * frame is sent.
                    226:         */
                    227:        opt = 1;
1.12      manu      228:        optlen = sizeof(opt);
                    229:        if (setsockopt(sv[1], 0, LOCAL_CREDS, &opt, optlen) != 0)
1.6       manu      230:                DWARN("%s: setsockopt LOCAL_CREDS failed", __func__);
                    231:
1.2       manu      232:        (void)sprintf(fdstr, "%d", sv[1]);
                    233:
                    234:        switch(fork()) {
                    235:        case -1:
                    236: #ifdef PERFUSE_DEBUG
1.5       manu      237:                DWARN("%s:%d: fork failed", __func__, __LINE__);
1.2       manu      238: #endif
                    239:                return -1;
                    240:                /* NOTREACHED */
                    241:                break;
                    242:        case 0:
1.12      manu      243:                (void)execve(argv[0], argv, environ);
1.2       manu      244: #ifdef PERFUSE_DEBUG
1.5       manu      245:                DWARN("%s:%d: execve failed", __func__, __LINE__);
1.2       manu      246: #endif
                    247:                return -1;
                    248:                /* NOTREACHED */
                    249:                break;
                    250:        default:
                    251:                break;
                    252:        }
                    253:
                    254:        return sv[0];
1.1       manu      255: }
                    256:
                    257: int
                    258: perfuse_mount(source, target, filesystemtype, mountflags, data)
                    259:        const char *source;
                    260:        const char *target;
                    261:        const char *filesystemtype;
                    262:        long mountflags;
                    263:        const void *data;
                    264: {
                    265:        int s;
                    266:        size_t len;
1.6       manu      267:        struct perfuse_mount_out *pmo;
                    268:        struct sockaddr_storage ss;
1.7       manu      269:        struct sockaddr_un *sun;
1.6       manu      270:        struct sockaddr *sa;
                    271:        socklen_t sa_len;
                    272:        size_t sock_len;
                    273:        char *frame;
                    274:        char *cp;
1.1       manu      275:
                    276: #ifdef PERFUSE_DEBUG
1.5       manu      277:        if (perfuse_diagflags & PDF_MISC)
                    278:                DPRINTF("%s(\"%s\", \"%s\", \"%s\", 0x%lx, \"%s\")\n",
                    279:                        __func__, source, target, filesystemtype,
                    280:                        mountflags, (const char *)data);
1.1       manu      281: #endif
                    282:
                    283:        if ((s = get_fd(data)) == -1)
                    284:                return -1;
                    285:
1.6       manu      286:        /*
                    287:         * If we are connected to /dev/fuse, we need a second
                    288:         * socket to get replies from perfused.
                    289:         * XXX This socket is not removed at exit time yet
                    290:         */
                    291:        sock_len = 0;
                    292:        sa = (struct sockaddr *)(void *)&ss;
1.7       manu      293:        sun = (struct sockaddr_un *)(void *)&ss;
1.6       manu      294:        sa_len = sizeof(ss);
                    295:        if ((getpeername(s, sa, &sa_len) == 0) &&
                    296:            (sa->sa_family = AF_LOCAL) &&
1.7       manu      297:            (strcmp(sun->sun_path, _PATH_FUSE) == 0)) {
1.6       manu      298:
1.7       manu      299:                sun->sun_len = sizeof(*sun);
                    300:                sun->sun_family = AF_LOCAL;
                    301:                (void)sprintf(sun->sun_path, "%s/%s-%d",
1.6       manu      302:                              _PATH_TMP, getprogname(), getpid());
                    303:
1.7       manu      304:                if (bind(s, sa, (socklen_t)sa->sa_len) != 0)
1.6       manu      305:                        DERR(EX_OSERR, "%s:%d bind to \"%s\" failed",
1.7       manu      306:                             __func__, __LINE__, sun->sun_path);
1.6       manu      307:
1.7       manu      308:                sock_len = strlen(sun->sun_path) + 1;
1.6       manu      309:        }
                    310:
                    311:        len = sizeof(*pmo);
                    312:        len += source ? (uint32_t)strlen(source) + 1 : 0;
                    313:        len += target ? (uint32_t)strlen(target) + 1 : 0;
                    314:        len += filesystemtype ? (uint32_t)strlen(filesystemtype) + 1 : 0;
                    315:        len += data ? (uint32_t)strlen(data) + 1 : 0;
                    316:        len += sock_len;
                    317:
                    318:        if ((frame = malloc(len)) == NULL) {
1.1       manu      319: #ifdef PERFUSE_DEBUG
1.5       manu      320:                if (perfuse_diagflags & PDF_MISC)
1.6       manu      321:                        DWARN("%s:%d malloc failed", __func__, __LINE__);
1.1       manu      322: #endif
                    323:                return -1;
                    324:        }
1.6       manu      325:
                    326:        pmo = (struct perfuse_mount_out *)(void *)frame;
1.12      manu      327:        pmo->pmo_len = (uint32_t)len;
1.6       manu      328:        pmo->pmo_error = 0;
                    329:        pmo->pmo_unique = (uint64_t)-1;
                    330:        (void)strcpy(pmo->pmo_magic, PERFUSE_MOUNT_MAGIC);
                    331:
                    332:        pmo->pmo_source_len = source ? (uint32_t)strlen(source) + 1 : 0;
                    333:        pmo->pmo_target_len = target ? (uint32_t)strlen(target) + 1: 0;
                    334:        pmo->pmo_filesystemtype_len =
                    335:            filesystemtype ? (uint32_t)strlen(filesystemtype) + 1 : 0;
                    336:        pmo->pmo_mountflags = (uint32_t)mountflags;
                    337:        pmo->pmo_data_len = data ? (uint32_t)strlen(data) + 1 : 0;
1.12      manu      338:        pmo->pmo_sock_len = (uint32_t)sock_len;
1.1       manu      339:
1.6       manu      340:        cp = (char *)(void *)(pmo + 1);
                    341:
1.1       manu      342:        if (source) {
1.6       manu      343:                (void)strcpy(cp, source);
                    344:                cp += pmo->pmo_source_len;
1.1       manu      345:        }
                    346:
                    347:        if (target) {
1.6       manu      348:                (void)strcpy(cp, target);
                    349:                cp += pmo->pmo_target_len;
1.1       manu      350:        }
1.6       manu      351:
1.1       manu      352:        if (filesystemtype) {
1.6       manu      353:                (void)strcpy(cp, filesystemtype);
                    354:                cp += pmo->pmo_filesystemtype_len;
1.1       manu      355:        }
                    356:
                    357:        if (data) {
1.6       manu      358:                (void)strcpy(cp, data);
                    359:                cp += pmo->pmo_data_len;
                    360:        }
                    361:
                    362:        if (sock_len != 0) {
1.7       manu      363:                (void)strcpy(cp, sun->sun_path);
1.6       manu      364:                cp += pmo->pmo_sock_len;
                    365:        }
                    366:
1.12      manu      367:        if (send(s, frame, len, MSG_NOSIGNAL) != (ssize_t)len) {
1.1       manu      368: #ifdef PERFUSE_DEBUG
1.6       manu      369:                DWARN("%s:%d sendto failed", __func__, __LINE__);
1.1       manu      370: #endif
1.6       manu      371:                return -1;
1.1       manu      372:        }
                    373:
                    374:        return 0;
                    375: }
                    376:
                    377:
                    378: uint64_t
                    379: perfuse_next_unique(pu)
                    380:        struct puffs_usermount *pu;
                    381: {
                    382:        struct perfuse_state *ps;
                    383:
                    384:        ps = puffs_getspecific(pu);
                    385:
                    386:        return ps->ps_unique++;
                    387: }
                    388:
                    389: struct puffs_usermount *
                    390: perfuse_init(pc, pmi)
                    391:        struct perfuse_callbacks *pc;
                    392:        struct perfuse_mount_info *pmi;
                    393: {
                    394:        struct perfuse_state *ps;
                    395:        struct puffs_usermount *pu;
                    396:        struct puffs_ops *pops;
1.13      manu      397:        const char *source = _PATH_PUFFS;
                    398:        char *fstype;
1.1       manu      399:        unsigned int puffs_flags;
                    400:        struct puffs_node *pn_root;
                    401:        struct puffs_pathobj *po_root;
                    402:
1.19      manu      403:        /*
                    404:         * perfused needs to remain in memory. If it gets
                    405:         * swapped out, the kernel will deadlock when trying
                    406:         * to free memory backed by the PUFFS filesystem
                    407:         */
                    408:        mlockall(MCL_CURRENT|MCL_FUTURE);
                    409:
1.1       manu      410:        ps = init_state();
1.2       manu      411:        ps->ps_owner_uid = pmi->pmi_uid;
1.1       manu      412:
1.13      manu      413:        if (pmi->pmi_source) {
                    414:                if ((ps->ps_source = strdup(pmi->pmi_source)) == NULL)
1.18      christos  415:                        DERR(EX_OSERR, "%s: strdup failed", __func__);
1.13      manu      416:
                    417:                source = ps->ps_source;
                    418:        }
                    419:
                    420:        if (pmi->pmi_filesystemtype) {
                    421:                size_t len;
                    422:
1.1       manu      423:                ps->ps_filesystemtype = strdup(pmi->pmi_filesystemtype);
1.13      manu      424:                if (ps->ps_filesystemtype == NULL)
1.18      christos  425:                        DERR(EX_OSERR, "%s: strdup failed", __func__);
1.13      manu      426:
                    427:                len = sizeof("perfuse|") + strlen(ps->ps_filesystemtype) + 1;
                    428:                if ((fstype = malloc(len)) == NULL)
1.18      christos  429:                        DERR(EX_OSERR, "%s: malloc failed", __func__);
1.13      manu      430:
                    431:                (void)sprintf(fstype, "perfuse|%s", ps->ps_filesystemtype);
                    432:        } else {
                    433:                if ((fstype = strdup("perfuse")) == NULL)
1.18      christos  434:                        DERR(EX_OSERR, "%s: strdup failed", __func__);
1.13      manu      435:        }
                    436:
                    437:        if ((ps->ps_target = strdup(pmi->pmi_target)) == NULL)
1.18      christos  438:                DERR(EX_OSERR, "%s: strdup failed", __func__);
1.13      manu      439:
1.1       manu      440:        ps->ps_mountflags = pmi->pmi_mountflags;
                    441:
                    442:        /*
                    443:         * Some options are forbidden for non root users
                    444:         */
1.2       manu      445:        if (ps->ps_owner_uid != 0)
1.1       manu      446:            ps->ps_mountflags |= MNT_NOSUID|MNT_NODEV;
                    447:
                    448:        PUFFSOP_INIT(pops);
                    449:        PUFFSOP_SET(pops, perfuse, fs, unmount);
                    450:        PUFFSOP_SET(pops, perfuse, fs, statvfs);
                    451:        PUFFSOP_SET(pops, perfuse, fs, sync);
                    452:        PUFFSOP_SET(pops, perfuse, node, lookup);
                    453:        PUFFSOP_SET(pops, perfuse, node, create);
                    454:        PUFFSOP_SET(pops, perfuse, node, mknod);
                    455:        PUFFSOP_SET(pops, perfuse, node, open);
                    456:        PUFFSOP_SET(pops, perfuse, node, close);
                    457:        PUFFSOP_SET(pops, perfuse, node, access);
                    458:        PUFFSOP_SET(pops, perfuse, node, getattr);
                    459:        PUFFSOP_SET(pops, perfuse, node, setattr);
                    460:        PUFFSOP_SET(pops, perfuse, node, poll);
                    461: #if 0
                    462:        PUFFSOP_SET(pops, perfuse, node, mmap);
                    463: #endif
                    464:        PUFFSOP_SET(pops, perfuse, node, fsync);
                    465:        PUFFSOP_SET(pops, perfuse, node, seek);
                    466:        PUFFSOP_SET(pops, perfuse, node, remove);
                    467:        PUFFSOP_SET(pops, perfuse, node, link);
                    468:        PUFFSOP_SET(pops, perfuse, node, rename);
                    469:        PUFFSOP_SET(pops, perfuse, node, mkdir);
                    470:        PUFFSOP_SET(pops, perfuse, node, rmdir);
                    471:        PUFFSOP_SET(pops, perfuse, node, symlink);
                    472:        PUFFSOP_SET(pops, perfuse, node, readdir);
                    473:        PUFFSOP_SET(pops, perfuse, node, readlink);
                    474:        PUFFSOP_SET(pops, perfuse, node, reclaim);
                    475:        PUFFSOP_SET(pops, perfuse, node, inactive);
                    476:        PUFFSOP_SET(pops, perfuse, node, print);
                    477:        PUFFSOP_SET(pops, perfuse, node, advlock);
                    478:        PUFFSOP_SET(pops, perfuse, node, read);
                    479:        PUFFSOP_SET(pops, perfuse, node, write);
1.16      manu      480: #ifdef PUFFS_EXTNAMELEN
                    481:        PUFFSOP_SET(pops, perfuse, node, getextattr);
                    482:        PUFFSOP_SET(pops, perfuse, node, setextattr);
                    483:        PUFFSOP_SET(pops, perfuse, node, listextattr);
                    484:        PUFFSOP_SET(pops, perfuse, node, deleteextattr);
                    485: #endif /* PUFFS_EXTNAMELEN */
1.1       manu      486:
1.17      manu      487:        /*
                    488:         * We used to have PUFFS_KFLAG_WTCACHE here, which uses the
                    489:         * page cache (highly desirable to get mmap(2)), but still sends
                    490:         * all writes to the filesystem. In fact it does not send the
                    491:         * data written, but the pages that contain it.
                    492:         *
                    493:         * There is a nasty bug hidden somewhere, possibly in libpuffs'
                    494:         * VOP_FSYNC, which sends an asynchronous PUFFS_SETATTR that
                    495:         * update file size. When writes are in progress, it will cause
                    496:         * the file to be truncated and we get a zero-filled chunk at the
                    497:         * beginning of a page. Removing PUFFS_KFLAG_WTCACHE fixes that
                    498:         * problem.
                    499:         *
                    500:         * The other consequences are that changes will not be propagated
                    501:         * immediatly to the filesystem, and we get a huge performance gain
                    502:         * because much less requests are sent. A test case for the above
                    503:         * mentioned bug got its execution time slashed by factor 50.
                    504:         */
                    505:        puffs_flags = 0;
1.9       manu      506:
1.1       manu      507:        if (perfuse_diagflags & PDF_PUFFS)
                    508:                puffs_flags |= PUFFS_FLAG_OPDUMP;
                    509:
1.13      manu      510:        if ((pu = puffs_init(pops, source, fstype, ps, puffs_flags)) == NULL)
1.18      christos  511:                DERR(EX_OSERR, "%s: puffs_init failed", __func__);
1.1       manu      512:
                    513:        ps->ps_pu = pu;
                    514:
                    515:        /*
                    516:         * Setup filesystem root
                    517:         */
1.10      manu      518:        pn_root = perfuse_new_pn(pu, "", NULL);
1.1       manu      519:        PERFUSE_NODE_DATA(pn_root)->pnd_ino = FUSE_ROOT_ID;
1.3       manu      520:        PERFUSE_NODE_DATA(pn_root)->pnd_parent = pn_root;
1.1       manu      521:        puffs_setroot(pu, pn_root);
                    522:        ps->ps_fsid = pn_root->pn_va.va_fsid;
                    523:
                    524:        po_root = puffs_getrootpathobj(pu);
                    525:        if ((po_root->po_path = strdup("/")) == NULL)
                    526:                DERRX(EX_OSERR, "perfuse_mount_start() failed");
                    527:
                    528:        po_root->po_len = 1;
                    529:        puffs_path_buildhash(pu, po_root);
                    530:
                    531:        puffs_vattr_null(&pn_root->pn_va);
                    532:        pn_root->pn_va.va_type = VDIR;
                    533:        pn_root->pn_va.va_mode = 0755;
                    534:
                    535:        ps->ps_root = pn_root;
                    536:
                    537:        /*
                    538:         *  Callbacks
                    539:         */
                    540:        ps->ps_new_msg = pc->pc_new_msg;
                    541:        ps->ps_xchg_msg = pc->pc_xchg_msg;
                    542:        ps->ps_destroy_msg = pc->pc_destroy_msg;
                    543:        ps->ps_get_inhdr = pc->pc_get_inhdr;
                    544:        ps->ps_get_inpayload = pc->pc_get_inpayload;
                    545:        ps->ps_get_outhdr = pc->pc_get_outhdr;
                    546:        ps->ps_get_outpayload = pc->pc_get_outpayload;
1.15      manu      547:        ps->ps_umount = pc->pc_umount;
1.1       manu      548:
                    549:        return pu;
                    550: }
                    551:
                    552: void
                    553: perfuse_setspecific(pu, priv)
                    554:        struct puffs_usermount *pu;
                    555:        void *priv;
                    556: {
                    557:        struct perfuse_state *ps;
                    558:
                    559:        ps = puffs_getspecific(pu);
                    560:        ps->ps_private = priv;
                    561:
                    562:        return;
                    563: }
                    564:
                    565: void *
                    566: perfuse_getspecific(pu)
                    567:        struct puffs_usermount *pu;
                    568: {
                    569:        struct perfuse_state *ps;
                    570:
                    571:        ps = puffs_getspecific(pu);
                    572:
                    573:        return ps->ps_private;
                    574: }
                    575:
                    576: int
                    577: perfuse_inloop(pu)
                    578:        struct puffs_usermount *pu;
                    579: {
                    580:        struct perfuse_state *ps;
                    581:
                    582:        ps = puffs_getspecific(pu);
                    583:
                    584:        return ps->ps_flags & PS_INLOOP;
                    585: }
                    586:
                    587: int
                    588: perfuse_mainloop(pu)
                    589:        struct puffs_usermount *pu;
                    590: {
                    591:        struct perfuse_state *ps;
                    592:
                    593:        ps = puffs_getspecific(pu);
                    594:
                    595:        ps->ps_flags |= PS_INLOOP;
1.15      manu      596:        if (puffs_mainloop(ps->ps_pu) != 0) {
1.18      christos  597:                DERR(EX_OSERR, "%s: failed", __func__);
1.15      manu      598:                return -1;
                    599:        }
1.1       manu      600:
1.15      manu      601:        /*
                    602:         * Normal exit after unmount
                    603:         */
                    604:        return 0;
1.1       manu      605: }
                    606:
                    607: /* ARGSUSED0 */
                    608: uint64_t
                    609: perfuse_get_ino(pu, opc)
                    610:        struct puffs_usermount *pu;
                    611:        puffs_cookie_t opc;
                    612: {
                    613:        return PERFUSE_NODE_DATA(opc)->pnd_ino;
                    614: }
1.2       manu      615:
                    616: int
                    617: perfuse_unmount(pu)
                    618:        struct puffs_usermount *pu;
                    619: {
                    620:        struct perfuse_state *ps;
                    621:
                    622:        ps = puffs_getspecific(pu);
                    623:
                    624:        return unmount(ps->ps_target, MNT_FORCE);
                    625: }

CVSweb <webmaster@jp.NetBSD.org>