PageRenderTime 16ms CodeModel.GetById 14ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 0ms

/core/10.4/fusefs/fuse_internal.c

http://macfuse.googlecode.com/
C | 1525 lines | 1089 code | 299 blank | 137 comment | 208 complexity | b0aae47d34ad691836998bb76a57abe1 MD5 | raw file
   1/*
   2 * Copyright (C) 2006-2008 Google. All Rights Reserved.
   3 * Amit Singh <singh@>
   4 */
   5
   6#include <sys/param.h>
   7#include <kern/assert.h>
   8#include <libkern/libkern.h>
   9#include <libkern/OSMalloc.h>
  10#include <libkern/locks.h>
  11#include <mach/mach_types.h>
  12#include <sys/dirent.h>
  13#include <sys/disk.h>
  14#include <sys/errno.h>
  15#include <sys/fcntl.h>
  16#include <sys/kernel_types.h>
  17#include <sys/mount.h>
  18#include <sys/proc.h>
  19#include <sys/stat.h>
  20#include <sys/ubc.h>
  21#include <sys/unistd.h>
  22#include <sys/vnode.h>
  23#include <sys/vnode_if.h>
  24#include <sys/xattr.h>
  25#include <sys/buf.h>
  26#include <sys/namei.h>
  27#include <sys/mman.h>
  28
  29#include "fuse.h"
  30#include "fuse_file.h"
  31#include "fuse_internal.h"
  32#include "fuse_ipc.h"
  33#include "fuse_locking.h"
  34#include "fuse_node.h"
  35#include "fuse_file.h"
  36#include "fuse_nodehash.h"
  37#include "fuse_sysctl.h"
  38#include "fuse_kludges.h"
  39
  40/* access */
  41
  42__private_extern__
  43int
  44fuse_internal_access(vnode_t                   vp,
  45                     int                       action,
  46                     vfs_context_t             context,
  47                     struct fuse_access_param *facp)
  48{
  49    int err = 0;
  50    int default_error = 0;
  51    uint32_t mask = 0;
  52    int dataflags;
  53    mount_t mp;
  54    struct fuse_dispatcher fdi;
  55    struct fuse_access_in *fai;
  56    struct fuse_data      *data;
  57
  58    fuse_trace_printf_func();
  59
  60    mp = vnode_mount(vp);
  61
  62    data = fuse_get_mpdata(mp);
  63    dataflags = data->dataflags;
  64
  65    /* Allow for now; let checks be handled inline later. */
  66    if (fuse_isdeferpermissions_mp(mp)) {
  67        return 0;
  68    }
  69
  70    if (facp->facc_flags & FACCESS_FROM_VNOP) {
  71        default_error = ENOTSUP;
  72    }
  73
  74    /*
  75     * (action & KAUTH_VNODE_GENERIC_WRITE_BITS) on a read-only file system
  76     * would have been handled by higher layers.
  77     */
  78
  79    if (!fuse_implemented(data, FSESS_NOIMPLBIT(ACCESS))) {
  80        return default_error;
  81    }
  82
  83    /* Unless explicitly permitted, deny everyone except the fs owner. */
  84    if (!vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) {
  85        if (!(dataflags & FSESS_ALLOW_OTHER)) {
  86            int denied = fuse_match_cred(data->daemoncred,
  87                                         vfs_context_ucred(context));
  88            if (denied) {
  89                return EPERM;
  90            }
  91        }
  92        facp->facc_flags |= FACCESS_NOCHECKSPY;
  93    }
  94
  95    if (!(facp->facc_flags & FACCESS_DO_ACCESS)) {
  96        return default_error;
  97    }
  98
  99    if (vnode_isdir(vp)) {
 100        if (action & (KAUTH_VNODE_LIST_DIRECTORY   |
 101                      KAUTH_VNODE_READ_EXTATTRIBUTES)) {
 102            mask |= R_OK;
 103        }
 104        if (action & (KAUTH_VNODE_ADD_FILE         |
 105                      KAUTH_VNODE_ADD_SUBDIRECTORY |
 106                      KAUTH_VNODE_DELETE_CHILD)) {
 107            mask |= W_OK;
 108        }
 109        if (action & KAUTH_VNODE_SEARCH) {
 110            mask |= X_OK;
 111        }
 112    } else {
 113        if (action & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_EXTATTRIBUTES)) {
 114            mask |= R_OK;
 115        }
 116        if (action & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA)) {
 117            mask |= W_OK;
 118        }
 119        if (action & KAUTH_VNODE_EXECUTE) {
 120            mask |= X_OK;
 121        }
 122    }
 123
 124    if (action & (KAUTH_VNODE_WRITE_ATTRIBUTES    |
 125                  KAUTH_VNODE_WRITE_EXTATTRIBUTES |
 126                  KAUTH_VNODE_WRITE_SECURITY)) {
 127        mask |= W_OK;
 128    }
 129
 130    bzero(&fdi, sizeof(fdi));
 131
 132    fdisp_init(&fdi, sizeof(*fai));
 133    fdisp_make_vp(&fdi, FUSE_ACCESS, vp, context);
 134
 135    fai = fdi.indata;
 136    fai->mask = F_OK;
 137    fai->mask |= mask;
 138
 139    if (!(err = fdisp_wait_answ(&fdi))) {
 140        fuse_ticket_drop(fdi.tick);
 141    }
 142
 143    if (err == ENOSYS) {
 144        /*
 145         * Make sure we don't come in here again.
 146         */
 147        vfs_clearauthopaque(mp);
 148        fuse_clear_implemented(data, FSESS_NOIMPLBIT(ACCESS));
 149        err = default_error;
 150    }
 151
 152    if (err == ENOENT) {
 153
 154        const char *vname = NULL;
 155
 156#if M_MACFUSE_ENABLE_UNSUPPORTED
 157        vname = vnode_getname(vp);
 158#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
 159
 160        IOLog("MacFUSE: disappearing vnode %p (name=%s type=%d action=%x)\n",
 161              vp, (vname) ? vname : "?", vnode_vtype(vp), action);
 162
 163#if M_MACFUSE_ENABLE_UNSUPPORTED
 164        if (vname) {
 165            vnode_putname(vname);
 166        }
 167#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
 168
 169        /*
 170         * On 10.4, I think I can get Finder to lock because of /.Trashes/<uid>
 171         * unless I use REVOKE_NONE here.
 172         */
 173         
 174        fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT);
 175    }
 176
 177    return err;
 178}
 179
 180#if M_MACFUSE_ENABLE_EXCHANGE
 181
 182/* exchange */
 183
 184__private_extern__
 185int
 186fuse_internal_exchange(vnode_t       fvp,
 187                       const char   *fname,
 188                       size_t        flen,
 189                       vnode_t       tvp,
 190                       const char   *tname,
 191                       size_t        tlen,
 192                       int           options,
 193                       vfs_context_t context)
 194{
 195    struct fuse_dispatcher fdi;
 196    struct fuse_exchange_in *fei;
 197    struct fuse_vnode_data *ffud = VTOFUD(fvp);
 198    struct fuse_vnode_data *tfud = VTOFUD(tvp);
 199    vnode_t fdvp = ffud->parentvp;
 200    vnode_t tdvp = tfud->parentvp;
 201    int err = 0;
 202
 203    fdisp_init(&fdi, sizeof(*fei) + flen + tlen + 2);
 204    fdisp_make_vp(&fdi, FUSE_EXCHANGE, fvp, context);
 205
 206    fei = fdi.indata;
 207    fei->olddir = VTOI(fdvp);
 208    fei->newdir = VTOI(tdvp);
 209    fei->options = (uint64_t)options;
 210
 211    memcpy((char *)fdi.indata + sizeof(*fei), fname, flen);
 212    ((char *)fdi.indata)[sizeof(*fei) + flen] = '\0';
 213
 214    memcpy((char *)fdi.indata + sizeof(*fei) + flen + 1, tname, tlen);
 215    ((char *)fdi.indata)[sizeof(*fei) + flen + tlen + 1] = '\0';
 216
 217    ubc_sync_range(fvp, (off_t)0, (off_t)ffud->filesize,
 218                   UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC);
 219    ubc_sync_range(tvp, (off_t)0, (off_t)tfud->filesize,
 220                   UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC);
 221        
 222    if (!(err = fdisp_wait_answ(&fdi))) {
 223        fuse_ticket_drop(fdi.tick);
 224    }
 225
 226    if (err == 0) {
 227        if (fdvp) {
 228            fuse_invalidate_attr(fdvp);
 229        }
 230        if (tdvp != fdvp) {
 231            if (tdvp) {
 232                fuse_invalidate_attr(tdvp);
 233            }
 234        }
 235
 236        fuse_invalidate_attr(fvp);
 237        fuse_invalidate_attr(tvp);
 238
 239        cache_purge(fvp);
 240        cache_purge(tvp);
 241
 242        /* Swap sizes */
 243        off_t tmpfilesize = ffud->filesize;
 244        ffud->filesize = tfud->filesize;
 245        tfud->filesize = tmpfilesize;
 246        ubc_setsize(fvp, (off_t)ffud->filesize);
 247        ubc_setsize(tvp, (off_t)tfud->filesize);
 248
 249        fuse_kludge_exchange(fvp, tvp);
 250
 251        /*
 252         * Another approach (will need additional kernel support to work):
 253         *
 254        vnode_t tmpvp = ffud->vp;
 255        ffud->vp = tfud->vp;
 256        tfud->vp = tmpvp;
 257
 258        vnode_t tmpparentvp = ffud->parentvp;
 259        ffud->parentvp = tfud->parentvp;
 260        tfud->parentvp = tmpparentvp;
 261
 262        off_t tmpfilesize = ffud->filesize;
 263        ffud->filesize = tfud->filesize;
 264        tfud->filesize = tmpfilesize;
 265
 266        struct fuse_vnode_data tmpfud;
 267        memcpy(&tmpfud, ffud, sizeof(struct fuse_vnode_data));
 268        memcpy(ffud, tfud, sizeof(struct fuse_vnode_data));
 269        memcpy(tfud, &tmpfud, sizeof(struct fuse_vnode_data));
 270        
 271        HNodeExchangeFromFSNode(ffud, tfud);
 272        *
 273        */
 274    }
 275
 276    return err;
 277}
 278
 279#endif /* M_MACFUSE_ENABLE_EXCHANGE */
 280
 281/* fsync */
 282
 283__private_extern__
 284int
 285fuse_internal_fsync_callback(struct fuse_ticket *ftick, __unused uio_t uio)
 286{
 287    fuse_trace_printf_func();
 288
 289    if (ftick->tk_aw_ohead.error == ENOSYS) {
 290        if (fticket_opcode(ftick) == FUSE_FSYNC) {
 291            fuse_clear_implemented(ftick->tk_data, FSESS_NOIMPLBIT(FSYNC));
 292        } else if (fticket_opcode(ftick) == FUSE_FSYNCDIR) {
 293            fuse_clear_implemented(ftick->tk_data, FSESS_NOIMPLBIT(FSYNCDIR));
 294        } else {
 295            IOLog("MacFUSE: unexpected opcode in sync handling\n");
 296        }
 297    }
 298
 299    fuse_ticket_drop(ftick);
 300
 301    return 0;
 302}
 303
 304__private_extern__
 305int
 306fuse_internal_fsync(vnode_t                 vp,
 307                    vfs_context_t           context,
 308                    struct fuse_filehandle *fufh,
 309                    void                   *param,
 310                    fuse_op_waitfor_t       waitfor)
 311{
 312    int err = 0;
 313    int op = FUSE_FSYNC;
 314    struct fuse_fsync_in *ffsi;
 315    struct fuse_dispatcher *fdip = param;
 316
 317    fuse_trace_printf_func();
 318
 319    fdip->iosize = sizeof(*ffsi);
 320    fdip->tick = NULL;
 321    if (vnode_isdir(vp)) {
 322        op = FUSE_FSYNCDIR;
 323    }
 324    
 325    fdisp_make_vp(fdip, op, vp, context);
 326    ffsi = fdip->indata;
 327    ffsi->fh = fufh->fh_id;
 328
 329    ffsi->fsync_flags = 1; /* datasync */
 330
 331    if (waitfor == FUSE_OP_FOREGROUNDED) {
 332        if ((err = fdisp_wait_answ(fdip))) {
 333            if (err == ENOSYS) {
 334                if (op == FUSE_FSYNC) {
 335                    fuse_clear_implemented(fdip->tick->tk_data,
 336                                           FSESS_NOIMPLBIT(FSYNC));
 337                } else if (op == FUSE_FSYNCDIR) {
 338                    fuse_clear_implemented(fdip->tick->tk_data,
 339                                           FSESS_NOIMPLBIT(FSYNCDIR));
 340                }
 341            }
 342            goto out;
 343        } else {
 344            fuse_ticket_drop(fdip->tick);
 345        }
 346    } else {
 347        fuse_insert_callback(fdip->tick, fuse_internal_fsync_callback);
 348        fuse_insert_message(fdip->tick);
 349    }
 350
 351out:
 352    return err;
 353}
 354
 355/* getattr sidekicks */
 356__private_extern__
 357int
 358fuse_internal_loadxtimes(vnode_t vp, struct vnode_attr *out_vap,
 359                         vfs_context_t context)
 360{
 361    struct vnode_attr *in_vap = VTOVA(vp);
 362    struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
 363    struct fuse_dispatcher fdi;
 364    struct fuse_getxtimes_out *fgxo = NULL;
 365    int isvroot = vnode_isvroot(vp);
 366    struct timespec t = { 0, 0 };
 367    const struct timespec kZeroTime = { 0, 0 };
 368    int err = 0;
 369
 370    if (!(data->dataflags & FSESS_XTIMES)) {
 371        /* We don't return anything. */
 372        goto out;
 373    }
 374
 375    if (VTOFUD(vp)->c_flag & C_XTIMES_VALID) {
 376        VATTR_RETURN(out_vap, va_backup_time, in_vap->va_backup_time);
 377        VATTR_RETURN(out_vap, va_create_time, in_vap->va_create_time);
 378        goto out;
 379    }
 380
 381    if (!fuse_implemented(data, FSESS_NOIMPLBIT(GETXTIMES))) {
 382        goto fake;
 383    }
 384
 385    if (fuse_isdeadfs(vp) && isvroot) {
 386        goto fake;
 387    }
 388
 389    if (!(data->dataflags & FSESS_INITED) && isvroot) {
 390        goto fake;
 391    }
 392
 393    err = fdisp_simple_putget_vp(&fdi, FUSE_GETXTIMES, vp, context);
 394    if (err) {
 395        /* We don't ever treat this as a hard error. */
 396        err = 0;
 397        goto fake;
 398    }
 399
 400    fgxo = (struct fuse_getxtimes_out *)fdi.answ;
 401
 402    t.tv_sec = (time_t)fgxo->bkuptime; /* XXX: truncation */
 403    t.tv_nsec = fgxo->bkuptimensec;
 404    VATTR_RETURN(in_vap, va_backup_time, t);
 405    VATTR_RETURN(out_vap, va_backup_time, t);
 406
 407    t.tv_sec = (time_t)fgxo->crtime; /* XXX: truncation */
 408    t.tv_nsec = fgxo->crtimensec;
 409    VATTR_RETURN(in_vap, va_create_time, t);
 410    VATTR_RETURN(out_vap, va_create_time, t);
 411
 412    fuse_ticket_drop(fdi.tick);
 413
 414    VTOFUD(vp)->c_flag |= C_XTIMES_VALID;
 415
 416    goto out;
 417
 418fake:
 419    VATTR_RETURN(out_vap, va_backup_time, kZeroTime);
 420    VATTR_RETURN(out_vap, va_create_time, kZeroTime);
 421
 422out:
 423    return err;
 424}
 425
 426/* ioctl */
 427__private_extern__
 428int
 429fuse_internal_ioctl_avfi(vnode_t vp, __unused vfs_context_t context,
 430                         struct fuse_avfi_ioctl *avfi)
 431{
 432    int ret = 0;
 433    uint32_t hint = 0;
 434
 435    if (!avfi) {
 436        return EINVAL;
 437    }
 438
 439    if (avfi->cmd & FUSE_AVFI_MARKGONE) {
 440
 441        /*
 442         * TBD
 443         */
 444        return EINVAL;
 445    }
 446
 447    /* The result of this /does/ alter our return value. */
 448    if (avfi->cmd & FUSE_AVFI_UBC) {
 449        int ubc_flags = avfi->ubc_flags & (UBC_PUSHDIRTY  | UBC_PUSHALL |
 450                                           UBC_INVALIDATE | UBC_SYNC);
 451        if (ubc_sync_range(vp, (off_t)0, ubc_getsize(vp), ubc_flags) == 0) {
 452            /* failed */
 453            ret = EINVAL; /* don't really have a good error to return */
 454        }
 455    }
 456
 457    if (avfi->cmd & FUSE_AVFI_UBC_SETSIZE) {
 458        if (VTOFUD(vp)->filesize != avfi->size) {
 459            hint |= NOTE_WRITE;
 460            if (avfi->size > VTOFUD(vp)->filesize) {
 461                hint |= NOTE_EXTEND;
 462            }
 463            VTOFUD(vp)->filesize = avfi->size;
 464            ubc_setsize(vp, avfi->size);
 465        }
 466        (void)fuse_invalidate_attr(vp);
 467    }
 468
 469    /* The result of this doesn't alter our return value. */
 470    if (avfi->cmd & FUSE_AVFI_PURGEATTRCACHE) {
 471        hint |= NOTE_ATTRIB;
 472        (void)fuse_invalidate_attr(vp);
 473    }
 474
 475    /* The result of this doesn't alter our return value. */
 476    if (avfi->cmd & FUSE_AVFI_PURGEVNCACHE) {
 477        (void)fuse_vncache_purge(vp);
 478    }
 479
 480    if (avfi->cmd & FUSE_AVFI_KNOTE) {
 481        hint |= avfi->note;
 482    }
 483
 484    if (hint) {
 485        FUSE_KNOTE(vp, hint);
 486    }
 487
 488    return ret;
 489}
 490
 491/* readdir */
 492
 493__private_extern__
 494int
 495fuse_internal_readdir(vnode_t                 vp,
 496                      uio_t                   uio,
 497                      vfs_context_t           context,
 498                      struct fuse_filehandle *fufh,
 499                      struct fuse_iov        *cookediov,
 500                      int                    *numdirent)
 501{
 502    int err = 0;
 503    struct fuse_dispatcher fdi;
 504    struct fuse_read_in   *fri;
 505    struct fuse_data      *data;
 506
 507    if (uio_resid(uio) == 0) {
 508        return 0;
 509    }
 510
 511    fdisp_init(&fdi, 0);
 512
 513    /* Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p I/O). */
 514
 515    while (uio_resid(uio) > 0) {
 516
 517        fdi.iosize = sizeof(*fri);
 518        fdisp_make_vp(&fdi, FUSE_READDIR, vp, context);
 519
 520        fri = fdi.indata;
 521        fri->fh = fufh->fh_id;
 522        fri->offset = uio_offset(uio);
 523        data = fuse_get_mpdata(vnode_mount(vp));
 524        fri->size = (typeof(fri->size))min((size_t)uio_resid(uio), data->iosize);
 525
 526        if ((err = fdisp_wait_answ(&fdi))) {
 527            goto out;
 528        }
 529
 530        if ((err = fuse_internal_readdir_processdata(vp,
 531                                                     uio,
 532                                                     fri->size,
 533                                                     fdi.answ,
 534                                                     fdi.iosize,
 535                                                     cookediov,
 536                                                     numdirent))) {
 537            break;
 538        }
 539    }
 540
 541/* done: */
 542
 543    fuse_ticket_drop(fdi.tick);
 544
 545out:
 546    return ((err == -1) ? 0 : err);
 547}
 548
 549__private_extern__
 550int
 551fuse_internal_readdir_processdata(vnode_t          vp,
 552                                  uio_t            uio,
 553                         __unused size_t           reqsize,
 554                                  void            *buf,
 555                                  size_t           bufsize,
 556                                  struct fuse_iov *cookediov,
 557                                  int             *numdirent)
 558{
 559    int err = 0;
 560    int cou = 0;
 561    int n   = 0;
 562    size_t bytesavail;
 563    size_t freclen;
 564
 565    struct dirent      *de;
 566    struct fuse_dirent *fudge;
 567
 568    if (bufsize < FUSE_NAME_OFFSET) {
 569        return -1;
 570    }
 571
 572    for (;;) {
 573
 574        if (bufsize < FUSE_NAME_OFFSET) {
 575            err = -1;
 576            break;
 577        }
 578
 579        fudge = (struct fuse_dirent *)buf;
 580        freclen = FUSE_DIRENT_SIZE(fudge);
 581
 582        cou++;
 583
 584        if (bufsize < freclen) {
 585            err = ((cou == 1) ? -1 : 0);
 586            break;
 587        }
 588
 589        /*
 590         * if (isbzero(buf, FUSE_NAME_OFFSET)) {
 591         *     // zero-pad incomplete buffer
 592         *     ...
 593         *     err = -1;
 594         *     break;
 595         * }
 596         */
 597
 598        if (!fudge->namelen) { 
 599            err = EINVAL;
 600            break;
 601        }
 602
 603        if (fudge->namelen > MAXNAMLEN) {
 604            err = EIO;
 605            break;
 606        }
 607
 608#define GENERIC_DIRSIZ(dp) \
 609  ((sizeof(struct dirent) - (MAXNAMLEN + 1)) + (((dp)->d_namlen + 1 + 3) & ~3))
 610
 611        bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen); 
 612
 613        if (bytesavail > (size_t)uio_resid(uio)) {
 614            err = -1;
 615            break;
 616        }
 617
 618        fiov_refresh(cookediov);
 619        fiov_adjust(cookediov, bytesavail);
 620
 621        de = (struct dirent *)cookediov->base;
 622#if __DARWIN_64_BIT_INO_T
 623        de->d_fileno = fudge->ino;
 624#else
 625        de->d_fileno = (ino_t)fudge->ino; /* XXX: truncation */
 626#endif /* __DARWIN_64_BIT_INO_T */
 627        de->d_reclen = bytesavail;
 628        de->d_type   = fudge->type; 
 629        de->d_namlen = fudge->namelen;
 630
 631        /* Filter out any ._* files if the mount is configured as such. */
 632        if (fuse_skip_apple_double_mp(vnode_mount(vp),
 633                                      fudge->name, fudge->namelen)) {
 634            de->d_fileno = 0;
 635            de->d_type = DT_WHT;
 636        }
 637
 638        memcpy((char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1,
 639               (char *)buf + FUSE_NAME_OFFSET, fudge->namelen);
 640        ((char *)cookediov->base)[bytesavail] = '\0';
 641
 642        err = uiomove(cookediov->base, (int)cookediov->len, uio);
 643        if (err) {
 644            break;
 645        }
 646
 647        n++;
 648
 649        buf = (char *)buf + freclen;
 650        bufsize -= freclen;
 651        uio_setoffset(uio, fudge->off);
 652    }
 653
 654    if (!err && numdirent) {
 655        *numdirent = n;
 656    }
 657
 658    return err;
 659}
 660
 661/* remove */
 662
 663static int
 664fuse_internal_remove_callback(vnode_t vp, void *cargs)
 665{
 666    struct vnode_attr *vap;
 667    uint64_t target_nlink;
 668
 669    vap = VTOVA(vp);
 670
 671    target_nlink = *(uint64_t *)cargs;
 672
 673    /* somewhat lame "heuristics", but you got better ideas? */
 674    if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) {
 675        fuse_invalidate_attr(vp);
 676    }
 677
 678    return VNODE_RETURNED;
 679}
 680
 681__private_extern__
 682int
 683fuse_internal_remove(vnode_t               dvp,
 684                     vnode_t               vp,
 685                     struct componentname *cnp,
 686                     enum fuse_opcode      op,
 687                     vfs_context_t         context)
 688{
 689    struct fuse_dispatcher fdi;
 690
 691    struct vnode_attr *vap = VTOVA(vp);
 692    int need_invalidate = 0;
 693    uint64_t target_nlink = 0;
 694    mount_t mp = vnode_mount(vp);
 695
 696    int err = 0;
 697
 698    fdisp_init(&fdi, cnp->cn_namelen + 1);
 699    fdisp_make_vp(&fdi, op, dvp, context);
 700
 701    memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
 702    ((char *)fdi.indata)[cnp->cn_namelen] = '\0';
 703
 704    if ((vap->va_nlink > 1) && vnode_isreg(vp)) {
 705        need_invalidate = 1;
 706        target_nlink = vap->va_nlink;
 707    }
 708
 709    if (!(err = fdisp_wait_answ(&fdi))) {
 710        fuse_ticket_drop(fdi.tick);
 711    }
 712
 713    fuse_invalidate_attr(dvp);
 714    fuse_invalidate_attr(vp);
 715
 716    /*
 717     * XXX: M_MACFUSE_INVALIDATE_CACHED_VATTRS_UPON_UNLINK
 718     *
 719     * Consider the case where vap->va_nlink > 1 for the entity being
 720     * removed. In our world, other in-memory vnodes that share a link
 721     * count each with this one may not know right way that this one just
 722     * got deleted. We should let them know, say, through a vnode_iterate()
 723     * here and a callback that does fuse_invalidate_attr(vp) on each
 724     * relevant vnode.
 725     */
 726    if (need_invalidate && !err) {
 727        if (!vfs_busy(mp, LK_NOWAIT)) {
 728            vnode_iterate(mp, 0, fuse_internal_remove_callback,
 729                          (void *)&target_nlink);
 730            vfs_unbusy(mp);
 731        } else {
 732            IOLog("MacFUSE: skipping link count fixup upon remove\n");
 733        }
 734    }
 735
 736    return err;
 737}
 738
 739/* rename */
 740
 741__private_extern__
 742int
 743fuse_internal_rename(vnode_t               fdvp,
 744            __unused vnode_t               fvp,
 745                     struct componentname *fcnp,
 746                     vnode_t               tdvp,
 747            __unused vnode_t               tvp,
 748                     struct componentname *tcnp,
 749                     vfs_context_t         context)
 750{
 751    struct fuse_dispatcher fdi;
 752    struct fuse_rename_in *fri;
 753    int err = 0;
 754
 755    fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2);
 756    fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, context);
 757
 758    fri = fdi.indata;
 759    fri->newdir = VTOI(tdvp);
 760    memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr,
 761           fcnp->cn_namelen);
 762    ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0';
 763    memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1,
 764           tcnp->cn_nameptr, tcnp->cn_namelen);
 765    ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen +
 766                         tcnp->cn_namelen + 1] = '\0';
 767        
 768    if (!(err = fdisp_wait_answ(&fdi))) {
 769        fuse_ticket_drop(fdi.tick);
 770    }
 771
 772    if (err == 0) {
 773        fuse_invalidate_attr(fdvp);
 774        if (tdvp != fdvp) {
 775            fuse_invalidate_attr(tdvp);
 776        }
 777    }
 778
 779    return err;
 780}
 781
 782/* revoke */
 783
 784__private_extern__
 785int
 786fuse_internal_revoke(vnode_t vp, int flags, vfs_context_t context, int how)
 787{
 788    int ret = 0;
 789    struct fuse_vnode_data *fvdat = VTOFUD(vp);
 790
 791    fvdat->flag |= FN_REVOKED;
 792
 793    if (how == REVOKE_HARD) {
 794        ret = vn_revoke(vp, flags, context);
 795    }
 796
 797    return ret;
 798}
 799
 800/* strategy */
 801
 802__private_extern__
 803int
 804fuse_internal_strategy(vnode_t vp, buf_t bp)
 805{
 806    size_t biosize;
 807    size_t chunksize;
 808    size_t respsize;
 809
 810    int mapped = FALSE;
 811    int mode;
 812    int op;
 813    int vtype = vnode_vtype(vp);
 814
 815    int err = 0;
 816
 817    caddr_t bufdat;
 818    off_t   left;
 819    off_t   offset;
 820    int32_t bflags = buf_flags(bp);
 821
 822    fufh_type_t             fufh_type;
 823    struct fuse_dispatcher  fdi;
 824    struct fuse_data       *data;
 825    struct fuse_vnode_data *fvdat = VTOFUD(vp);
 826    struct fuse_filehandle *fufh = NULL;
 827    mount_t mp = vnode_mount(vp);
 828
 829    data = fuse_get_mpdata(mp);
 830
 831    biosize = data->blocksize;
 832
 833    if (!(vtype == VREG || vtype == VDIR)) {
 834        return ENOTSUP;
 835    }
 836 
 837    if (bflags & B_READ) {
 838        mode = FREAD;
 839        fufh_type = FUFH_RDONLY; /* FUFH_RDWR will also do */
 840    } else {
 841        mode = FWRITE;
 842        fufh_type = FUFH_WRONLY; /* FUFH_RDWR will also do */
 843    }
 844
 845    if (fvdat->flag & FN_CREATING) {
 846        fuse_lck_mtx_lock(fvdat->createlock);
 847        if (fvdat->flag & FN_CREATING) {
 848            (void)fuse_msleep(fvdat->creator, fvdat->createlock,
 849                              PDROP | PINOD | PCATCH, "fuse_internal_strategy",
 850                              NULL);
 851        } else {
 852            fuse_lck_mtx_unlock(fvdat->createlock);
 853        }
 854    }
 855
 856    fufh = &(fvdat->fufh[fufh_type]);
 857
 858    if (!FUFH_IS_VALID(fufh)) {
 859        fufh_type = FUFH_RDWR;
 860        fufh = &(fvdat->fufh[fufh_type]);
 861        if (!FUFH_IS_VALID(fufh)) {
 862            fufh = NULL;
 863        } else {
 864            /* We've successfully fallen back to FUFH_RDWR. */
 865        }
 866    }
 867
 868    if (!fufh) {
 869
 870        if (mode == FREAD) {
 871            fufh_type = FUFH_RDONLY;
 872        } else {
 873            fufh_type = FUFH_RDWR;
 874        }
 875
 876        /*
 877         * Lets NOT do the filehandle preflight check here.
 878         */
 879
 880        err = fuse_filehandle_get(vp, NULL, fufh_type, 0 /* mode */);
 881
 882        if (!err) {
 883            fufh = &(fvdat->fufh[fufh_type]);
 884            FUFH_AUX_INC(fufh);
 885            /* We've created a NEW fufh of type fufh_type. open_count is 1. */
 886        }
 887
 888    } else { /* good fufh */
 889
 890        FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count);
 891
 892        /* We're using an existing fufh of type fufh_type. */
 893    }
 894
 895    if (err) {
 896
 897         /* A more typical error case. */
 898         if ((err == ENOTCONN) || fuse_isdeadfs(vp)) {
 899             buf_seterror(bp, EIO);
 900             buf_biodone(bp);
 901             return EIO;
 902         }
 903
 904         IOLog("MacFUSE: strategy failed to get fh "
 905               "(vtype=%d, fufh_type=%d, err=%d)\n", vtype, fufh_type, err);
 906
 907         if (!vfs_issynchronous(mp)) {
 908             IOLog("MacFUSE: asynchronous write failed!\n");
 909         }
 910
 911         buf_seterror(bp, EIO);
 912         buf_biodone(bp);
 913         return EIO;
 914    }
 915
 916    if (!fufh) {
 917        panic("MacFUSE: tried everything but still no fufh");
 918        /* NOTREACHED */
 919    }
 920
 921#define B_INVAL 0x00040000 /* Does not contain valid info. */
 922#define B_ERROR 0x00080000 /* I/O error occurred. */
 923
 924    if (bflags & B_INVAL) {
 925        IOLog("MacFUSE: buffer does not contain valid information\n");
 926    } 
 927
 928    if (bflags & B_ERROR) {
 929        IOLog("MacFUSE: an I/O error has occured\n");
 930    }
 931
 932    if (buf_count(bp) == 0) {
 933        return 0;
 934    }
 935
 936    fdisp_init(&fdi, 0);
 937
 938    if (mode == FREAD) {
 939
 940        struct fuse_read_in *fri;
 941
 942        buf_setresid(bp, buf_count(bp));
 943        offset = (off_t)((off_t)buf_blkno(bp) * biosize);
 944
 945        if (offset >= fvdat->filesize) {
 946            /* Trying to read at/after EOF? */           
 947            if (offset != fvdat->filesize) {
 948                /* Trying to read after EOF? */
 949                buf_seterror(bp, EINVAL);
 950            }
 951            buf_biodone(bp);
 952            return 0;
 953        }
 954
 955        /* Note that we just made sure that offset < fvdat->filesize. */
 956        if ((offset + buf_count(bp)) > fvdat->filesize) {
 957            /* Trimming read */
 958            buf_setcount(bp, (uint32_t)(fvdat->filesize - offset));
 959        }
 960
 961        if (buf_map(bp, &bufdat)) {
 962            IOLog("MacFUSE: failed to map buffer in strategy\n");
 963            return EFAULT;
 964        } else {
 965            mapped = TRUE;
 966        }
 967
 968        while (buf_resid(bp) > 0) {
 969
 970            chunksize = min((size_t)buf_resid(bp), data->iosize);
 971
 972            fdi.iosize = sizeof(*fri);
 973
 974            op = FUSE_READ;
 975            if (vtype == VDIR) {
 976                op = FUSE_READDIR;
 977            }
 978            fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
 979        
 980            fri = fdi.indata;
 981            fri->fh = fufh->fh_id;
 982
 983            /*
 984             * Historical note:
 985             *
 986             * fri->offset = ((off_t)(buf_blkno(bp))) * biosize;
 987             *
 988             * This wasn't being incremented!?
 989             */
 990
 991            fri->offset = offset;
 992            fri->size = (typeof(fri->size))chunksize;
 993            fdi.tick->tk_aw_type = FT_A_BUF;
 994            fdi.tick->tk_aw_bufdata = bufdat;
 995        
 996            if ((err = fdisp_wait_answ(&fdi))) {
 997                /* There was a problem with reading. */
 998                goto out;
 999            }
1000
1001            respsize = fdi.tick->tk_aw_bufsize;
1002
1003            if (respsize < 0) { /* Cannot really happen... */
1004                err = EIO;
1005                goto out;
1006            }
1007
1008            buf_setresid(bp, (uint32_t)(buf_resid(bp) - respsize));
1009            bufdat += respsize;
1010            offset += respsize;
1011
1012            /* Did we hit EOF before being done? */
1013            if ((respsize == 0) && (buf_resid(bp) > 0)) {
1014                 /*
1015                  * Historical note:
1016                  * If we don't get enough data, just fill the rest with zeros.
1017                  * In NFS context, this would mean a hole in the file.
1018                  */
1019
1020                 /* Zero-pad the incomplete buffer. */
1021                 bzero(bufdat, buf_resid(bp));
1022                 buf_setresid(bp, 0);
1023                 break;
1024            }
1025        } /* while (buf_resid(bp) > 0) */
1026    } else {
1027        /* write */
1028        struct fuse_write_in  *fwi;
1029        struct fuse_write_out *fwo;
1030        int merr = 0;
1031        off_t diff;
1032
1033        if (buf_map(bp, &bufdat)) {
1034            IOLog("MacFUSE: failed to map buffer in strategy\n");
1035            return EFAULT;
1036        } else {
1037            mapped = TRUE;
1038        }
1039
1040        /* Write begin */
1041
1042        buf_setresid(bp, buf_count(bp));
1043        offset = (off_t)((off_t)buf_blkno(bp) * biosize);
1044
1045        /* XXX: TBD -- Check here for extension (writing past end) */
1046
1047        left = buf_count(bp);
1048
1049        while (left) {
1050
1051            fdi.iosize = sizeof(*fwi);
1052            op = FUSE_WRITE;
1053
1054            fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0);
1055            chunksize = min((size_t)left, data->iosize);
1056
1057            fwi = fdi.indata;
1058            fwi->fh = fufh->fh_id;
1059            fwi->offset = offset;
1060            fwi->size = (typeof(fwi->size))chunksize;
1061
1062            fdi.tick->tk_ms_type = FT_M_BUF;
1063            fdi.tick->tk_ms_bufdata = bufdat;
1064            fdi.tick->tk_ms_bufsize = chunksize;
1065
1066            /* About to write <chunksize> at <offset> */
1067
1068            if ((err = fdisp_wait_answ(&fdi))) {
1069                merr = 1;
1070                break;
1071            }
1072    
1073            fwo = fdi.answ;
1074            diff = chunksize - fwo->size;
1075            if (diff < 0) {
1076                err = EINVAL;
1077                break;
1078            }
1079    
1080            left -= fwo->size;
1081            bufdat += fwo->size;
1082            offset += fwo->size;
1083            buf_setresid(bp, buf_resid(bp) - fwo->size);
1084        }
1085
1086        if (merr) {
1087            goto out;
1088        }
1089    }
1090
1091    if (fdi.tick) {
1092        fuse_ticket_drop(fdi.tick);
1093    } else {
1094        /* No ticket upon leaving */
1095    }
1096
1097out:
1098
1099    if (err) {
1100        buf_seterror(bp, err);
1101    }
1102
1103    if (mapped == TRUE) {
1104        buf_unmap(bp);
1105    }
1106
1107    buf_biodone(bp);
1108
1109    return err;
1110}    
1111
1112__private_extern__
1113errno_t
1114fuse_internal_strategy_buf(struct vnop_strategy_args *ap)
1115{
1116    int32_t   bflags;
1117    upl_t     bupl;
1118    daddr64_t blkno, lblkno;
1119    int       bmap_flags;
1120    buf_t     bp    = ap->a_bp;
1121    vnode_t   vp    = buf_vnode(bp);
1122    int       vtype = vnode_vtype(vp);
1123
1124    struct fuse_data *data;
1125
1126    if (!vp || vtype == VCHR || vtype == VBLK) {
1127        panic("MacFUSE: buf_strategy: b_vp == NULL || vtype == VCHR | VBLK\n");
1128    }
1129
1130    bflags = buf_flags(bp);
1131
1132    if (bflags & B_READ) {
1133        bmap_flags = VNODE_READ;
1134    } else {
1135        bmap_flags = VNODE_WRITE;
1136    }
1137
1138    bupl = buf_upl(bp);
1139    blkno = buf_blkno(bp);
1140    lblkno = buf_lblkno(bp);
1141
1142    if (!(bflags & B_CLUSTER)) {
1143
1144        if (bupl) {
1145            return cluster_bp(bp);
1146        }
1147
1148        if (blkno == lblkno) {
1149            off_t  f_offset;
1150            size_t contig_bytes;
1151
1152            data = fuse_get_mpdata(vnode_mount(vp));
1153
1154            // Still think this is a kludge?
1155            f_offset = lblkno * data->blocksize;
1156            blkno = f_offset / data->blocksize;
1157
1158            buf_setblkno(bp, blkno);
1159
1160            contig_bytes = buf_count(bp);
1161
1162            if (blkno == -1) {
1163                buf_clear(bp);
1164            }
1165                        
1166            /*
1167             * Our "device" is always /all contiguous/. We don't wanna be
1168             * doing things like:
1169             *
1170             * ...
1171             *     else if ((long)contig_bytes < buf_count(bp)) {
1172             *         ret = buf_strategy_fragmented(devvp, bp, f_offset,
1173             *                                       contig_bytes));
1174             *         return ret;
1175             *      }
1176             */
1177        }
1178
1179        if (blkno == -1) {
1180            buf_biodone(bp);
1181            return 0;
1182        }
1183    }
1184
1185    // Issue the I/O
1186
1187    return fuse_internal_strategy(vp, bp);
1188}
1189
1190/* entity creation */
1191
1192__private_extern__
1193void
1194fuse_internal_newentry_makerequest(mount_t                 mp,
1195                                   uint64_t                dnid,
1196                                   struct componentname   *cnp,
1197                                   enum fuse_opcode        op,
1198                                   void                   *buf,
1199                                   size_t                  bufsize,
1200                                   struct fuse_dispatcher *fdip,
1201                                   vfs_context_t           context)
1202{
1203    fdisp_init(fdip, bufsize + cnp->cn_namelen + 1);
1204
1205    fdisp_make(fdip, op, mp, dnid, context);
1206    memcpy(fdip->indata, buf, bufsize);
1207    memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen);
1208    ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0';
1209}
1210
1211__private_extern__
1212int
1213fuse_internal_newentry_core(vnode_t                 dvp,
1214                            vnode_t                *vpp,
1215                            struct componentname   *cnp,
1216                            enum vtype              vtyp,
1217                            struct fuse_dispatcher *fdip,
1218                            vfs_context_t           context)
1219{
1220    int err = 0;
1221    struct fuse_entry_out *feo;
1222    mount_t mp = vnode_mount(dvp);
1223
1224    if ((err = fdisp_wait_answ(fdip))) {
1225        return err;
1226    }
1227        
1228    feo = fdip->answ;
1229
1230    if ((err = fuse_internal_checkentry(feo, vtyp))) {
1231        goto out;
1232    }
1233
1234    err = fuse_vget_i(vpp, 0 /* flags */, feo, cnp, dvp, mp, context);
1235    if (err) {
1236        fuse_internal_forget_send(mp, context, feo->nodeid, 1, fdip);
1237        return err;
1238    }
1239
1240    cache_attrs(*vpp, feo);
1241
1242out:
1243    fuse_ticket_drop(fdip->tick);
1244
1245    return err;
1246}
1247
1248__private_extern__
1249int
1250fuse_internal_newentry(vnode_t               dvp,
1251                       vnode_t              *vpp,
1252                       struct componentname *cnp,
1253                       enum fuse_opcode      op,
1254                       void                 *buf,
1255                       size_t                bufsize,
1256                       enum vtype            vtype,
1257                       vfs_context_t         context)
1258{   
1259    int err;
1260    struct fuse_dispatcher fdi;
1261    mount_t mp = vnode_mount(dvp);
1262    
1263    if (fuse_skip_apple_double_mp(mp, cnp->cn_nameptr, cnp->cn_namelen)) {
1264        return EACCES;
1265    }
1266    
1267    fdisp_init(&fdi, 0);
1268    fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf,
1269                                       bufsize, &fdi, context);
1270    err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi, context);
1271    fuse_invalidate_attr(dvp);            
1272                   
1273    return err;  
1274}         
1275
1276/* entity destruction */
1277
1278__private_extern__
1279int
1280fuse_internal_forget_callback(struct fuse_ticket *ftick, __unused uio_t uio)
1281{
1282    struct fuse_dispatcher fdi;
1283
1284    fdi.tick = ftick;
1285
1286    fuse_internal_forget_send(ftick->tk_data->mp, (vfs_context_t)0, 
1287        ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1, &fdi);
1288
1289    return 0;
1290}
1291
1292__private_extern__
1293void
1294fuse_internal_forget_send(mount_t                 mp,
1295                          vfs_context_t           context,
1296                          uint64_t                nodeid,
1297                          uint64_t                nlookup,
1298                          struct fuse_dispatcher *fdip)
1299{
1300    struct fuse_forget_in *ffi;
1301
1302    /*
1303     * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu",
1304     *         (long long unsigned) nodeid));
1305     */
1306
1307    fdisp_init(fdip, sizeof(*ffi));
1308    fdisp_make(fdip, FUSE_FORGET, mp, nodeid, context);
1309
1310    ffi = fdip->indata;
1311    ffi->nlookup = nlookup;
1312
1313    fticket_invalidate(fdip->tick);
1314    fuse_insert_message(fdip->tick);
1315}
1316
1317__private_extern__
1318void
1319fuse_internal_interrupt_send(struct fuse_ticket *ftick)
1320{
1321    struct fuse_dispatcher fdi;
1322    struct fuse_interrupt_in *fii;
1323
1324    fdi.tick = ftick;
1325    fdisp_init(&fdi, sizeof(*fii));
1326    fdisp_make(&fdi, FUSE_INTERRUPT, ftick->tk_data->mp, (uint64_t)0,
1327               (vfs_context_t)0);
1328    fii = fdi.indata;
1329    fii->unique = ftick->tk_unique;
1330    fticket_invalidate(fdi.tick);
1331    fuse_insert_message(fdi.tick);
1332}
1333
1334__private_extern__
1335void
1336fuse_internal_vnode_disappear(vnode_t vp, vfs_context_t context, int how)
1337{   
1338    int err = 0;
1339
1340    fuse_vncache_purge(vp);
1341
1342    if (how != REVOKE_NONE) {
1343        err = fuse_internal_revoke(vp, REVOKEALL, context, how);
1344        if (err) {
1345            IOLog("MacFUSE: disappearing act: revoke failed (%d)\n", err);
1346        }
1347
1348        err = vnode_recycle(vp);
1349        if (err) {
1350            IOLog("MacFUSE: disappearing act: recycle failed (%d)\n", err);
1351        }
1352    }
1353}
1354
1355/* fuse start/stop */
1356
1357__private_extern__
1358int
1359fuse_internal_init_synchronous(struct fuse_ticket *ftick)
1360{
1361    int err = 0;
1362    struct fuse_init_out *fiio;
1363    struct fuse_data *data = ftick->tk_data;
1364
1365    if ((err = ftick->tk_aw_ohead.error)) {
1366        goto out;
1367    }
1368
1369    fiio = fticket_resp(ftick)->base;
1370
1371    if ((fiio->major < MACFUSE_MIN_USER_VERSION_MAJOR) ||
1372        (fiio->minor < MACFUSE_MIN_USER_VERSION_MINOR)){
1373        IOLog("MacFUSE: user-space library has too low a version\n");
1374        err = EPROTONOSUPPORT;
1375        goto out;
1376    }
1377
1378    data->fuse_libabi_major = fiio->major;
1379    data->fuse_libabi_minor = fiio->minor;
1380
1381    if (fuse_libabi_geq(data, MACFUSE_MIN_USER_VERSION_MAJOR,
1382                              MACFUSE_MIN_USER_VERSION_MINOR)) {
1383        if (fticket_resp(ftick)->len == sizeof(struct fuse_init_out)) {
1384            data->max_write = fiio->max_write;
1385        } else {
1386            err = EINVAL;
1387        }
1388    } else {
1389        /* Old fix values */
1390        data->max_write = 4096;
1391    }
1392
1393    if (fiio->flags & FUSE_CASE_INSENSITIVE) {
1394        data->dataflags |= FSESS_CASE_INSENSITIVE;
1395    }
1396
1397    if (fiio->flags & FUSE_VOL_RENAME) {
1398        data->dataflags |= FSESS_VOL_RENAME;
1399    }
1400
1401    if (fiio->flags & FUSE_XTIMES) {
1402        data->dataflags |= FSESS_XTIMES;
1403    }
1404
1405out:
1406    fuse_ticket_drop(ftick);
1407
1408    if (err) {
1409        fdata_set_dead(data);
1410    }
1411
1412    fuse_lck_mtx_lock(data->ticket_mtx);
1413    data->dataflags |= FSESS_INITED;
1414    fuse_wakeup(&data->ticketer);
1415    fuse_lck_mtx_unlock(data->ticket_mtx);
1416
1417    return 0;
1418}
1419
1420__private_extern__
1421int
1422fuse_internal_send_init(struct fuse_data *data, vfs_context_t context)
1423{
1424    int err = 0;
1425    struct fuse_init_in   *fiii;
1426    struct fuse_dispatcher fdi;
1427
1428    fdisp_init(&fdi, sizeof(*fiii));
1429    fdisp_make(&fdi, FUSE_INIT, data->mp, 0, context);
1430    fiii = fdi.indata;
1431    fiii->major = FUSE_KERNEL_VERSION;
1432    fiii->minor = FUSE_KERNEL_MINOR_VERSION;
1433    fiii->max_readahead = data->iosize * 16;
1434    fiii->flags = 0;
1435
1436    /* blocking FUSE_INIT up to user space */
1437
1438    err = fdisp_wait_answ(&fdi);
1439    if (err) {
1440        IOLog("MacFUSE: user-space initialization failed (%d)\n", err);
1441        return err;
1442    }
1443
1444    err = fuse_internal_init_synchronous(fdi.tick);
1445    if (err) {
1446        IOLog("MacFUSE: in-kernel initialization failed (%d)\n", err);
1447        return err;
1448    }
1449
1450    return 0;
1451}
1452
1453/* other */
1454
1455static int
1456fuse_internal_print_vnodes_callback(vnode_t vp, __unused void *cargs)
1457{
1458    const char *vname = NULL;
1459    struct fuse_vnode_data *fvdat = VTOFUD(vp);
1460
1461#if M_MACFUSE_ENABLE_UNSUPPORTED
1462    vname = vnode_getname(vp);
1463#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
1464
1465    if (vname) {
1466        IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d %s\n",
1467              vp, fvdat->nodeid, fvdat->parent_nodeid,
1468              vnode_isinuse(vp, 0), vname);
1469    } else {
1470        if (fvdat->nodeid == FUSE_ROOT_ID) {
1471            IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d /\n",
1472                  vp, fvdat->nodeid, fvdat->parent_nodeid,
1473                  vnode_isinuse(vp, 0));
1474        } else {
1475            IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d\n",
1476                  vp, fvdat->nodeid, fvdat->parent_nodeid,
1477                  vnode_isinuse(vp, 0));
1478        }
1479    }
1480
1481#if M_MACFUSE_ENABLE_UNSUPPORTED
1482    if (vname) {
1483        vnode_putname(vname);
1484    }
1485#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
1486 
1487    return VNODE_RETURNED;
1488}
1489
1490__private_extern__
1491void
1492fuse_internal_print_vnodes(mount_t mp)
1493{
1494    vnode_iterate(mp, VNODE_ITERATE_ALL,
1495                  fuse_internal_print_vnodes_callback, NULL);
1496}
1497
1498__private_extern__
1499void
1500fuse_preflight_log(vnode_t vp, fufh_type_t fufh_type, int err, char *message)
1501{
1502    const char *vname = NULL;
1503
1504#if M_MACFUSE_ENABLE_UNSUPPORTED
1505    vname = vnode_getname(vp);
1506#else
1507    (void)vname;
1508    (void)vp;
1509#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
1510
1511    if (vname) {
1512        IOLog("MacFUSE: file handle preflight "
1513              "(caller=%s, type=%d, err=%d, name=%s)\n",
1514              message, fufh_type, err, vname);
1515    } else {
1516        IOLog("MacFUSE: file handle preflight "
1517              "(caller=%s, type=%d, err=%d)\n", message, fufh_type, err);
1518    }
1519
1520#if M_MACFUSE_ENABLE_UNSUPPORTED
1521    if (vname) {
1522        vnode_putname(vname);
1523    }
1524#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */
1525}