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