PageRenderTime 77ms CodeModel.GetById 14ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 1ms

/core/10.5/fusefs/fuse_device.c

http://macfuse.googlecode.com/
C | 836 lines | 601 code | 186 blank | 49 comment | 100 complexity | d912749367c1306738898a2b7e5a5d3c MD5 | raw file
  1/*
  2 * Copyright (C) 2006-2008 Google. All Rights Reserved.
  3 * Amit Singh <singh@>
  4 */
  5
  6#include "fuse.h"
  7#include "fuse_device.h"
  8#include "fuse_ipc.h"
  9#include "fuse_internal.h"
 10#include "fuse_kludges.h"
 11#include "fuse_locking.h"
 12#include "fuse_nodehash.h"
 13#include "fuse_sysctl.h"
 14
 15#include <fuse_ioctl.h>
 16#include <libkern/libkern.h>
 17
 18#define FUSE_DEVICE_GLOBAL_LOCK()   fuse_lck_mtx_lock(fuse_device_mutex)
 19#define FUSE_DEVICE_GLOBAL_UNLOCK() fuse_lck_mtx_unlock(fuse_device_mutex)
 20#define FUSE_DEVICE_LOCAL_LOCK(d)   fuse_lck_mtx_lock((d)->mtx)
 21#define FUSE_DEVICE_LOCAL_UNLOCK(d) fuse_lck_mtx_unlock((d)->mtx)
 22
 23#define TAILQ_FOREACH_SAFE(var, head, field, tvar)           \
 24        for ((var) = TAILQ_FIRST((head));                    \
 25            (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
 26            (var) = (tvar))
 27
 28static int    fuse_cdev_major          = -1;
 29static UInt32 fuse_interface_available = FALSE;
 30
 31struct fuse_device {
 32    lck_mtx_t        *mtx;
 33    int               usecount;
 34    pid_t             pid;
 35    uint32_t          random;
 36    dev_t             dev;
 37    void             *cdev;
 38    struct fuse_data *data;
 39};
 40
 41static struct fuse_device fuse_device_table[MACFUSE_NDEVICES];
 42
 43#define FUSE_DEVICE_FROM_UNIT_FAST(u) (fuse_device_t)&(fuse_device_table[(u)])
 44
 45/* Interface for VFS */
 46
 47/* Doesn't need lock. */
 48fuse_device_t
 49fuse_device_get(dev_t dev)
 50{
 51    int unit = minor(dev);
 52
 53    if ((unit < 0) || (unit >= MACFUSE_NDEVICES)) {
 54        return (fuse_device_t)0;
 55    }
 56
 57    return FUSE_DEVICE_FROM_UNIT_FAST(unit);
 58}
 59
 60__inline__
 61void
 62fuse_device_lock(fuse_device_t fdev)
 63{
 64    FUSE_DEVICE_LOCAL_LOCK(fdev);
 65}
 66
 67__inline__
 68void
 69fuse_device_unlock(fuse_device_t fdev)
 70{
 71    FUSE_DEVICE_LOCAL_UNLOCK(fdev);
 72}
 73
 74/* Must be called under lock. */
 75__inline__
 76struct fuse_data *
 77fuse_device_get_mpdata(fuse_device_t fdev)
 78{
 79    return fdev->data;
 80}
 81
 82/* Must be called under lock. */
 83__inline__
 84uint32_t
 85fuse_device_get_random(fuse_device_t fdev)
 86{
 87    return fdev->random;
 88}
 89
 90/* Must be called under lock. */
 91__inline__
 92void
 93fuse_device_close_final(fuse_device_t fdev)
 94{
 95    if (fdev) {
 96        fdata_destroy(fdev->data);
 97        fdev->data   = NULL;
 98        fdev->pid    = -1;
 99        fdev->random = 0;
100    }
101}
102
103/* /dev/fuseN implementation */
104
105d_open_t   fuse_device_open;
106d_close_t  fuse_device_close;
107d_read_t   fuse_device_read;
108d_write_t  fuse_device_write;
109d_ioctl_t  fuse_device_ioctl;
110
111#if M_MACFUSE_ENABLE_DSELECT
112
113d_select_t fuse_device_select;
114
115#else
116#define fuse_device_select (d_select_t*)enodev
117#endif /* M_MACFUSE_ENABLE_DSELECT */
118
119static struct cdevsw fuse_device_cdevsw = {
120    /* open     */ fuse_device_open,
121    /* close    */ fuse_device_close,
122    /* read     */ fuse_device_read,
123    /* write    */ fuse_device_write,
124    /* ioctl    */ fuse_device_ioctl,
125    /* stop     */ (d_stop_t *)enodev,
126    /* reset    */ (d_reset_t *)enodev,
127    /* ttys     */ 0,
128    /* select   */ fuse_device_select,
129    /* mmap     */ (d_mmap_t *)enodev,
130    /* strategy */ (d_strategy_t *)enodev_strat,
131#ifdef d_getc_t
132    /* getc     */ (d_getc_t *)enodev,
133#else
134    /* reserved */ (void *)enodev,
135#endif
136#ifdef d_putc_t
137    /* putc     */ (d_putc_t *)enodev,
138#else
139    /* reserved */ (void *)enodev,
140#endif
141    /* flags    */ D_TTY,
142};
143
144int
145fuse_device_open(dev_t dev, __unused int flags, __unused int devtype,
146                 struct proc *p)
147{
148    int unit;
149    struct fuse_device *fdev;
150    struct fuse_data   *fdata;
151
152    fuse_trace_printf_func();
153
154    if (fuse_interface_available == FALSE) {
155        return ENOENT;
156    }
157
158    unit = minor(dev);
159    if ((unit >= MACFUSE_NDEVICES) || (unit < 0)) {
160        FUSE_DEVICE_GLOBAL_UNLOCK();
161        return ENOENT;
162    }
163
164    fdev = FUSE_DEVICE_FROM_UNIT_FAST(unit);
165    if (!fdev) {
166        FUSE_DEVICE_GLOBAL_UNLOCK();
167        IOLog("MacFUSE: device found with no softc\n");
168        return ENXIO;
169    }
170
171    FUSE_DEVICE_GLOBAL_LOCK();
172
173    if (fdev->usecount != 0) {
174        FUSE_DEVICE_GLOBAL_UNLOCK();
175        return EBUSY;
176    }
177
178    fdev->usecount++;
179
180    FUSE_DEVICE_LOCAL_LOCK(fdev);
181
182    FUSE_DEVICE_GLOBAL_UNLOCK();
183
184    /* Could block. */
185    fdata = fdata_alloc(p);
186
187    if (fdev->data) {
188        /*
189         * This slot isn't currently open by a user daemon. However, it was
190         * used earlier for a mount that's still lingering, even though the
191         * user daemon is dead.
192         */
193
194        FUSE_DEVICE_GLOBAL_LOCK();
195
196        fdev->usecount--;
197
198        FUSE_DEVICE_LOCAL_UNLOCK(fdev);
199
200        FUSE_DEVICE_GLOBAL_UNLOCK();
201
202        fdata_destroy(fdata);
203
204        return EBUSY;
205    } else {
206        fdata->dataflags |= FSESS_OPENED;
207        fdata->fdev  = fdev;
208        fdev->data   = fdata;
209        fdev->pid    = proc_pid(p);
210        fdev->random = random();
211    }       
212
213    FUSE_DEVICE_LOCAL_UNLOCK(fdev);
214
215    return KERN_SUCCESS;
216}
217
218int
219fuse_device_close(dev_t dev, __unused int flags, __unused int devtype,
220                  __unused struct proc *p)
221{
222    int unit;
223    struct fuse_device *fdev;
224    struct fuse_data   *data;
225
226    fuse_trace_printf_func();
227
228    unit = minor(dev);
229    if (unit >= MACFUSE_NDEVICES) {
230        return ENOENT;
231    }
232
233    fdev = FUSE_DEVICE_FROM_UNIT_FAST(unit);
234    if (!fdev) {
235        return ENXIO;
236    }
237
238    data = fdev->data;
239    if (!data) {
240        panic("MacFUSE: no device private data in device_close");
241    }
242
243    fdata_set_dead(data);
244
245    FUSE_DEVICE_LOCAL_LOCK(fdev);
246
247    data->dataflags &= ~FSESS_OPENED;
248
249    fuse_lck_mtx_lock(data->aw_mtx);
250
251#if M_MACFUSE_ENABLE_DSELECT
252    selwakeup((struct selinfo*)&data->d_rsel);
253#endif /* M_MACFUSE_ENABLE_DSELECT */
254
255    if (data->mount_state == FM_MOUNTED) {
256
257        /* Uh-oh, the device is closing but we're still mounted. */
258
259        struct fuse_ticket *ftick;
260
261        while ((ftick = fuse_aw_pop(data))) {
262            fuse_lck_mtx_lock(ftick->tk_aw_mtx);
263            fticket_set_answered(ftick);
264            ftick->tk_aw_errno = ENOTCONN;
265            fuse_wakeup(ftick);
266            fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
267        }
268
269        fuse_lck_mtx_unlock(data->aw_mtx);
270
271        /* Left mpdata for unmount to destroy. */
272
273    } else {
274
275        /* We're not mounted. Can destroy mpdata. */
276
277        fdev->data   = NULL;
278        fdev->pid    = -1;
279        fdev->random = 0;
280        fdata_destroy(data);
281    }
282
283    FUSE_DEVICE_LOCAL_UNLOCK(fdev);
284
285    FUSE_DEVICE_GLOBAL_LOCK();
286
287    /*
288     * Even if usecount goes 0 here, at open time, we check if fdev->data
289     * is non-NULL (that is, a lingering mount). If so, we return EBUSY.
290     * We could make the usecount depend on both device-use and mount-state,
291     * but I think this is truer to reality, if a bit more complex to maintain.
292     */
293    fdev->usecount--;
294
295    FUSE_DEVICE_GLOBAL_UNLOCK();
296
297    return KERN_SUCCESS;
298}
299
300int
301fuse_device_read(dev_t dev, uio_t uio, int ioflag)
302{
303    int i, err = 0;
304    size_t buflen[3];
305    void *buf[] = { NULL, NULL, NULL };
306
307    struct fuse_device *fdev;
308    struct fuse_data   *data;
309    struct fuse_ticket *ftick;
310
311    fuse_trace_printf_func();
312
313    fdev = FUSE_DEVICE_FROM_UNIT_FAST(minor(dev));
314    if (!fdev) {
315        return ENXIO;
316    }
317
318    data = fdev->data;
319
320    fuse_lck_mtx_lock(data->ms_mtx);
321
322    /* The read loop (outgoing messages to the user daemon). */
323
324again:
325    if (fdata_dead_get(data)) {
326        fuse_lck_mtx_unlock(data->ms_mtx);
327        return ENODEV;
328    }
329
330    if (!(ftick = fuse_ms_pop(data))) {
331        if (ioflag & FNONBLOCK) {
332            fuse_lck_mtx_unlock(data->ms_mtx);
333            return EAGAIN;
334        }
335        err = fuse_msleep(data, data->ms_mtx, PCATCH, "fu_msg", NULL);
336        if (err != 0) {
337            fuse_lck_mtx_unlock(data->ms_mtx);
338            return (fdata_dead_get(data) ? ENODEV : err);
339        }
340        ftick = fuse_ms_pop(data);
341    }
342
343    if (!ftick) {
344        goto again;
345    }
346
347    fuse_lck_mtx_unlock(data->ms_mtx);
348
349    if (fdata_dead_get(data)) {
350         if (ftick) {
351             fuse_ticket_drop_invalid(ftick);
352         }
353         return ENODEV;
354    }
355
356    switch (ftick->tk_ms_type) {
357
358    case FT_M_FIOV:
359        buf[0]    = ftick->tk_ms_fiov.base;
360        buflen[0] = ftick->tk_ms_fiov.len;
361        break;
362
363    case FT_M_BUF:
364        buf[0]    = ftick->tk_ms_fiov.base;
365        buflen[0] = ftick->tk_ms_fiov.len;
366        buf[1]    = ftick->tk_ms_bufdata;
367        buflen[1] = ftick->tk_ms_bufsize;
368        break;
369
370    default:
371        panic("MacFUSE: unknown message type for ticket %p", ftick);
372    }
373
374    for (i = 0; buf[i]; i++) {
375        if (uio_resid(uio) < (user_ssize_t)buflen[i]) {
376            data->dataflags |= FSESS_DEAD;
377            err = ENODEV;
378            break;
379        }
380
381        err = uiomove(buf[i], (int)buflen[i], uio);
382
383        if (err) {
384            break;
385        }
386    }
387
388    /*
389     * XXX: Stop gap! I really need to finish interruption plumbing.
390     */
391    if (fticket_answered(ftick)) {
392        err = EINTR;
393    }
394
395    /*
396     * The FORGET message is an example of a ticket that has explicitly
397     * been invalidated by the sender. The sender is not expecting or wanting
398     * a reply, so he sets the FT_INVALID bit in the ticket.
399     */
400   
401    fuse_ticket_drop_invalid(ftick);
402
403    return err;
404}
405
406int
407fuse_device_write(dev_t dev, uio_t uio, __unused int ioflag)
408{
409    int err = 0, found = 0;
410
411    struct fuse_device    *fdev;
412    struct fuse_data      *data;
413    struct fuse_ticket    *ftick;
414    struct fuse_ticket    *x_ftick;
415    struct fuse_out_header ohead;
416
417    fuse_trace_printf_func();
418
419    fdev = FUSE_DEVICE_FROM_UNIT_FAST(minor(dev));
420    if (!fdev) {
421        return ENXIO;
422    }
423
424    if (uio_resid(uio) < (user_ssize_t)sizeof(struct fuse_out_header)) {
425        return EINVAL;
426    }
427
428    if ((err = uiomove((caddr_t)&ohead, (int)sizeof(struct fuse_out_header),
429                       uio))
430        != 0) {
431        return err;
432    }
433
434    /* begin audit */
435
436    if (uio_resid(uio) + sizeof(struct fuse_out_header) != ohead.len) {
437        IOLog("MacFUSE: message body size does not match that in the header\n");
438        return EINVAL; 
439    }   
440
441    if (uio_resid(uio) && ohead.error) {
442        IOLog("MacFUSE: non-zero error for a message with a body\n");
443        return EINVAL;
444    }
445
446    ohead.error = -(ohead.error);
447
448    /* end audit */
449
450    data = fdev->data;
451
452    fuse_lck_mtx_lock(data->aw_mtx);
453
454    TAILQ_FOREACH_SAFE(ftick, &data->aw_head, tk_aw_link, x_ftick) {
455        if (ftick->tk_unique == ohead.unique) {
456            found = 1;
457            fuse_aw_remove(ftick);
458            break;
459        }
460    }
461
462    fuse_lck_mtx_unlock(data->aw_mtx);
463
464    if (found) {
465        if (ftick->tk_aw_handler) {
466            memcpy(&ftick->tk_aw_ohead, &ohead, sizeof(ohead));
467            err = ftick->tk_aw_handler(ftick, uio);
468        } else {
469            fuse_ticket_drop(ftick);
470            return err;
471        }
472    } else {
473        /* ticket has no response handler */
474    }
475
476    return err;
477}
478
479int
480fuse_devices_start(void)
481{
482    int i = 0;
483
484    fuse_trace_printf_func();
485
486    bzero((void *)fuse_device_table, sizeof(fuse_device_table));
487
488    if ((fuse_cdev_major = cdevsw_add(-1, &fuse_device_cdevsw)) == -1) {
489        goto error;
490    }
491
492    for (i = 0; i < MACFUSE_NDEVICES; i++) {
493
494        dev_t dev = makedev(fuse_cdev_major, i);
495        fuse_device_table[i].cdev = devfs_make_node(
496                                        dev,
497                                        DEVFS_CHAR,
498                                        UID_ROOT,
499                                        GID_OPERATOR,
500                                        0666,
501                                        MACFUSE_DEVICE_BASENAME "%d",
502                                        i);
503        if (fuse_device_table[i].cdev == NULL) {
504            goto error;
505        }
506
507        fuse_device_table[i].data     = NULL;
508        fuse_device_table[i].dev      = dev;
509        fuse_device_table[i].pid      = -1;
510        fuse_device_table[i].random   = 0;
511        fuse_device_table[i].usecount = 0;
512        fuse_device_table[i].mtx      = lck_mtx_alloc_init(fuse_lock_group,
513                                                           fuse_lock_attr);
514    }
515
516    fuse_interface_available = TRUE;
517
518    return KERN_SUCCESS;
519
520error:
521    for (--i; i >= 0; i--) {
522        devfs_remove(fuse_device_table[i].cdev);
523        fuse_device_table[i].cdev = NULL;
524        fuse_device_table[i].dev  = 0;
525        lck_mtx_free(fuse_device_table[i].mtx, fuse_lock_group);
526    }
527
528    (void)cdevsw_remove(fuse_cdev_major, &fuse_device_cdevsw);
529    fuse_cdev_major = -1;
530
531    return KERN_FAILURE;
532}
533
534int
535fuse_devices_stop(void)
536{
537    int i, ret;
538
539    fuse_trace_printf_func();
540
541    fuse_interface_available = FALSE;
542
543    FUSE_DEVICE_GLOBAL_LOCK();
544
545    if (fuse_cdev_major == -1) {
546        FUSE_DEVICE_GLOBAL_UNLOCK();
547        return KERN_SUCCESS;
548    }
549
550    for (i = 0; i < MACFUSE_NDEVICES; i++) {
551
552        char p_comm[MAXCOMLEN + 1] = { '?', '\0' };
553
554        if (fuse_device_table[i].usecount != 0) {
555            fuse_interface_available = TRUE;
556            FUSE_DEVICE_GLOBAL_UNLOCK();
557            proc_name(fuse_device_table[i].pid, p_comm, MAXCOMLEN + 1);
558            IOLog("MacFUSE: /dev/fuse%d is still active (pid=%d %s)\n",
559                  i, fuse_device_table[i].pid, p_comm);
560            return KERN_FAILURE;
561        }
562
563        if (fuse_device_table[i].data != NULL) {
564            fuse_interface_available = TRUE;
565            FUSE_DEVICE_GLOBAL_UNLOCK();
566            proc_name(fuse_device_table[i].pid, p_comm, MAXCOMLEN + 1);
567            /* The pid can't possibly be active here. */
568            IOLog("MacFUSE: /dev/fuse%d has a lingering mount (pid=%d, %s)\n",
569                  i, fuse_device_table[i].pid, p_comm);
570            return KERN_FAILURE;
571        }
572    }
573
574    /* No device is in use. */
575
576    for (i = 0; i < MACFUSE_NDEVICES; i++) {
577        devfs_remove(fuse_device_table[i].cdev);
578        lck_mtx_free(fuse_device_table[i].mtx, fuse_lock_group);
579        fuse_device_table[i].cdev   = NULL;
580        fuse_device_table[i].dev    = 0;
581        fuse_device_table[i].pid    = -1;
582        fuse_device_table[i].random = 0;
583        fuse_device_table[i].mtx    = NULL;
584    }
585
586    ret = cdevsw_remove(fuse_cdev_major, &fuse_device_cdevsw);
587    if (ret != fuse_cdev_major) {
588        IOLog("MacFUSE: fuse_cdev_major != return from cdevsw_remove()\n");
589    }
590
591    fuse_cdev_major = -1;
592
593    FUSE_DEVICE_GLOBAL_UNLOCK();
594
595    return KERN_SUCCESS;
596}
597
598/* Control/Debug Utilities */
599
600int
601fuse_device_ioctl(dev_t dev, u_long cmd, caddr_t udata,
602                  __unused int flags, __unused proc_t proc)
603{
604    int ret = EINVAL;
605    struct fuse_device *fdev;
606    struct fuse_data   *data;
607
608    fuse_trace_printf_func();
609
610    fdev = FUSE_DEVICE_FROM_UNIT_FAST(minor(dev));
611    if (!fdev) {
612        return ENXIO;
613    }
614
615    FUSE_DEVICE_LOCAL_LOCK(fdev);
616
617    data = fdev->data;
618    if (!data) {
619        FUSE_DEVICE_LOCAL_UNLOCK(fdev);
620        return ENXIO;
621    }
622
623    switch (cmd) {
624    case FUSEDEVIOCSETIMPLEMENTEDBITS:
625        ret = fuse_set_implemented_custom(data, *(uint64_t *)udata);
626        break;
627
628    case FUSEDEVIOCGETHANDSHAKECOMPLETE:
629        if (data->mount_state == FM_NOTMOUNTED) {
630            ret = ENXIO;
631        } else {
632            *(u_int32_t *)udata = (data->dataflags & FSESS_INITED);
633            ret = 0;
634        }
635        break;
636
637    case FUSEDEVIOCSETDAEMONDEAD:
638        fdata_set_dead(data);
639        fuse_lck_mtx_lock(data->timeout_mtx);
640        data->timeout_status = FUSE_DAEMON_TIMEOUT_DEAD;
641        fuse_lck_mtx_unlock(data->timeout_mtx);
642        ret = 0;
643        break;
644
645    case FUSEDEVIOCGETRANDOM:
646        *(u_int32_t *)udata = fdev->random;
647        ret = 0;
648        break;
649
650    /*
651     * The 'AVFI' (alter-vnode-for-inode) ioctls all require an inode number
652     * as an argument. In the user-space library, you can get the inode number
653     * from a path by using fuse_lookup_inode_by_path_np() [lib/fuse.c].
654     *
655     * To see an example of using this, see the implementation of 
656     * fuse_purge_path_np() in lib/fuse_darwin.c.
657     */
658    case FUSEDEVIOCALTERVNODEFORINODE:
659        {
660            HNodeRef hn;
661            vnode_t  vn;
662            fuse_device_t dummy_device = data->fdev;
663
664            struct fuse_avfi_ioctl *avfi = (struct fuse_avfi_ioctl *)udata;
665
666            ret = (int)HNodeLookupRealQuickIfExists(dummy_device,
667                                                    (ino_t)avfi->inode,
668                                                    0, /* fork index */
669                                                    &hn,
670                                                    &vn);
671            if (ret) {
672                break;
673            }
674
675            assert(vn != NULL);
676
677            ret = fuse_internal_ioctl_avfi(vn, (vfs_context_t)0, avfi);
678
679            if (vn) {
680                vnode_put(vn);
681            }
682        }
683        break;
684
685    default:
686        break;
687        
688    }
689
690    FUSE_DEVICE_LOCAL_UNLOCK(fdev);
691
692    return ret;
693}
694
695#if M_MACFUSE_ENABLE_DSELECT
696
697int
698fuse_device_select(dev_t dev, int events, void *wql, struct proc *p)
699{
700    int unit, revents = 0;
701    struct fuse_device *fdev;
702    struct fuse_data  *data;
703
704    fuse_trace_printf_func();
705
706    unit = minor(dev);
707    if (unit >= MACFUSE_NDEVICES) {
708        return ENOENT;
709    }
710
711    fdev = FUSE_DEVICE_FROM_UNIT_FAST(unit);
712    if (!fdev) {
713        return ENXIO;
714    }
715
716    data = fdev->data;
717    if (!data) {
718        panic("MacFUSE: no device private data in device_select");
719    }
720
721    if (events & (POLLIN | POLLRDNORM)) {
722        fuse_lck_mtx_lock(data->ms_mtx);
723        if (fdata_dead_get(data) || STAILQ_FIRST(&data->ms_head)) {
724            revents |= (events & (POLLIN | POLLRDNORM));
725        } else {
726            selrecord((proc_t)p, (struct selinfo*)&data->d_rsel, wql);
727        }
728        fuse_lck_mtx_unlock(data->ms_mtx);
729    }
730
731    if (events & (POLLOUT | POLLWRNORM)) {
732        revents |= (events & (POLLOUT | POLLWRNORM));
733    }
734
735    return revents;
736}
737
738#endif /* M_MACFUSE_ENABLE_DSELECT */
739
740int
741fuse_device_kill(int unit, struct proc *p)
742{
743    int error = ENOENT;
744    struct fuse_device *fdev;
745
746    if ((unit < 0) || (unit >= MACFUSE_NDEVICES)) {
747        return EINVAL;
748    }
749
750    fdev = FUSE_DEVICE_FROM_UNIT_FAST(unit);
751    if (!fdev) {
752        return ENOENT;
753    }
754
755    FUSE_DEVICE_LOCAL_LOCK(fdev);
756
757    if (fdev->data) {
758        error = EPERM;
759        if (p) {
760            kauth_cred_t request_cred = kauth_cred_proc_ref(p);
761            if ((kauth_cred_getuid(request_cred) == 0) ||
762                (fuse_match_cred(fdev->data->daemoncred, request_cred) == 0)) {
763
764                /* The following can block. */
765                fdata_set_dead(fdev->data);
766
767                error = 0;
768
769                fuse_lck_mtx_lock(fdev->data->aw_mtx);
770                {
771                    struct fuse_ticket *ftick;
772                    while ((ftick = fuse_aw_pop(fdev->data))) {
773                        fuse_lck_mtx_lock(ftick->tk_aw_mtx);
774                        fticket_set_answered(ftick);
775                        ftick->tk_aw_errno = ENOTCONN;
776                        fuse_wakeup(ftick);
777                        fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
778                    }
779                }
780                fuse_lck_mtx_unlock(fdev->data->aw_mtx);
781            }
782            kauth_cred_unref(&request_cred);
783        }
784    }
785
786    FUSE_DEVICE_LOCAL_UNLOCK(fdev);
787
788    return error;
789}
790
791int
792fuse_device_print_vnodes(int unit_flags, struct proc *p)
793{
794    int error = ENOENT;
795    struct fuse_device *fdev;
796
797    int unit = unit_flags;
798
799    if ((unit < 0) || (unit >= MACFUSE_NDEVICES)) {
800        return EINVAL;
801    }
802
803    fdev = FUSE_DEVICE_FROM_UNIT_FAST(unit);
804    if (!fdev) {
805        return ENOENT;
806    }
807
808    FUSE_DEVICE_LOCAL_LOCK(fdev);
809
810    if (fdev->data) {
811
812        mount_t mp = fdev->data->mp;
813
814        if (vfs_busy(mp, LK_NOWAIT)) {
815            FUSE_DEVICE_LOCAL_UNLOCK(fdev);
816            return EBUSY;
817        }
818        
819        error = EPERM;
820        if (p) {
821            kauth_cred_t request_cred = kauth_cred_proc_ref(p);
822            if ((kauth_cred_getuid(request_cred) == 0) ||
823                (fuse_match_cred(fdev->data->daemoncred, request_cred) == 0)) {
824                fuse_internal_print_vnodes(fdev->data->mp);
825                error = 0;
826            }
827            kauth_cred_unref(&request_cred);
828        }
829
830        vfs_unbusy(mp);
831    }
832
833    FUSE_DEVICE_LOCAL_UNLOCK(fdev);
834
835    return error;
836}