/core/10.4/fusefs/fuse_ipc.c

http://macfuse.googlecode.com/ · C · 1102 lines · 850 code · 225 blank · 27 comment · 116 complexity · 27c1ba812fde08f4f2ad194aafffebbb MD5 · raw file

  1. /*
  2. * Copyright (C) 2006-2008 Google. All Rights Reserved.
  3. * Amit Singh <singh@>
  4. */
  5. #include <sys/types.h>
  6. #include <sys/malloc.h>
  7. #include "fuse.h"
  8. #include "fuse_internal.h"
  9. #include "fuse_ipc.h"
  10. #include "fuse_locking.h"
  11. #include "fuse_node.h"
  12. #include "fuse_sysctl.h"
  13. static struct fuse_ticket *fticket_alloc(struct fuse_data *data);
  14. static void fticket_refresh(struct fuse_ticket *ftick);
  15. static void fticket_destroy(struct fuse_ticket *ftick);
  16. static int fticket_wait_answer(struct fuse_ticket *ftick);
  17. static __inline__ int fticket_aw_pull_uio(struct fuse_ticket *ftick,
  18. uio_t uio);
  19. static __inline__ void fuse_push_freeticks(struct fuse_ticket *ftick);
  20. static __inline__ struct fuse_ticket *
  21. fuse_pop_freeticks(struct fuse_data *data);
  22. static __inline__ void fuse_push_allticks(struct fuse_ticket *ftick);
  23. static __inline__ void fuse_remove_allticks(struct fuse_ticket *ftick);
  24. static struct fuse_ticket *fuse_pop_allticks(struct fuse_data *data);
  25. static int fuse_body_audit(struct fuse_ticket *ftick, size_t blen);
  26. static __inline__ void fuse_setup_ihead(struct fuse_in_header *ihead,
  27. struct fuse_ticket *ftick,
  28. uint64_t nid,
  29. enum fuse_opcode op,
  30. size_t blen,
  31. vfs_context_t context);
  32. static fuse_handler_t fuse_standard_handler;
  33. void
  34. fiov_init(struct fuse_iov *fiov, size_t size)
  35. {
  36. size_t msize = FU_AT_LEAST(size);
  37. fiov->len = 0;
  38. fiov->base = FUSE_OSMalloc(msize, fuse_malloc_tag);
  39. if (!fiov->base) {
  40. panic("MacFUSE: OSMalloc failed in fiov_init");
  41. }
  42. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_iov_current);
  43. bzero(fiov->base, msize);
  44. fiov->allocated_size = msize;
  45. fiov->credit = fuse_iov_credit;
  46. }
  47. void
  48. fiov_teardown(struct fuse_iov *fiov)
  49. {
  50. FUSE_OSFree(fiov->base, fiov->allocated_size, fuse_malloc_tag);
  51. fiov->allocated_size = 0;
  52. FUSE_OSAddAtomic(-1, (SInt32 *)&fuse_iov_current);
  53. }
  54. void
  55. fiov_adjust(struct fuse_iov *fiov, size_t size)
  56. {
  57. if (fiov->allocated_size < size ||
  58. (fuse_iov_permanent_bufsize >= 0 &&
  59. fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
  60. --fiov->credit < 0)) {
  61. fiov->base = FUSE_OSRealloc_nocopy(fiov->base, fiov->allocated_size,
  62. FU_AT_LEAST(size));
  63. if (!fiov->base) {
  64. panic("MacFUSE: realloc failed");
  65. }
  66. fiov->allocated_size = FU_AT_LEAST(size);
  67. fiov->credit = fuse_iov_credit;
  68. }
  69. fiov->len = size;
  70. }
  71. int
  72. fiov_adjust_canfail(struct fuse_iov *fiov, size_t size)
  73. {
  74. if (fiov->allocated_size < size ||
  75. (fuse_iov_permanent_bufsize >= 0 &&
  76. fiov->allocated_size - size > fuse_iov_permanent_bufsize &&
  77. --fiov->credit < 0)) {
  78. void *tmpbase = NULL;
  79. tmpbase = FUSE_OSRealloc_nocopy_canfail(fiov->base,
  80. fiov->allocated_size,
  81. FU_AT_LEAST(size));
  82. if (!tmpbase) {
  83. return ENOMEM;
  84. }
  85. fiov->base = tmpbase;
  86. fiov->allocated_size = FU_AT_LEAST(size);
  87. fiov->credit = fuse_iov_credit;
  88. }
  89. fiov->len = size;
  90. return 0;
  91. }
  92. void
  93. fiov_refresh(struct fuse_iov *fiov)
  94. {
  95. bzero(fiov->base, fiov->len);
  96. fiov_adjust(fiov, 0);
  97. }
  98. static struct fuse_ticket *
  99. fticket_alloc(struct fuse_data *data)
  100. {
  101. struct fuse_ticket *ftick;
  102. ftick = (struct fuse_ticket *)FUSE_OSMalloc(sizeof(struct fuse_ticket),
  103. fuse_malloc_tag);
  104. if (!ftick) {
  105. panic("MacFUSE: OSMalloc failed in fticket_alloc");
  106. }
  107. FUSE_OSAddAtomic(1, (SInt32 *)&fuse_tickets_current);
  108. bzero(ftick, sizeof(struct fuse_ticket));
  109. ftick->tk_unique = data->ticketer++;
  110. ftick->tk_data = data;
  111. fiov_init(&ftick->tk_ms_fiov, sizeof(struct fuse_in_header));
  112. ftick->tk_ms_type = FT_M_FIOV;
  113. ftick->tk_aw_mtx = lck_mtx_alloc_init(fuse_lock_group, fuse_lock_attr);
  114. fiov_init(&ftick->tk_aw_fiov, 0);
  115. ftick->tk_aw_type = FT_A_FIOV;
  116. return ftick;
  117. }
  118. static __inline__
  119. void
  120. fticket_refresh(struct fuse_ticket *ftick)
  121. {
  122. fiov_refresh(&ftick->tk_ms_fiov);
  123. ftick->tk_ms_bufdata = NULL;
  124. ftick->tk_ms_bufsize = 0;
  125. ftick->tk_ms_type = FT_M_FIOV;
  126. bzero(&ftick->tk_aw_ohead, sizeof(struct fuse_out_header));
  127. fiov_refresh(&ftick->tk_aw_fiov);
  128. ftick->tk_aw_errno = 0;
  129. ftick->tk_aw_bufdata = NULL;
  130. ftick->tk_aw_bufsize = 0;
  131. ftick->tk_aw_type = FT_A_FIOV;
  132. ftick->tk_flag = 0;
  133. ftick->tk_age++;
  134. }
  135. static void
  136. fticket_destroy(struct fuse_ticket *ftick)
  137. {
  138. fiov_teardown(&ftick->tk_ms_fiov);
  139. lck_mtx_free(ftick->tk_aw_mtx, fuse_lock_group);
  140. ftick->tk_aw_mtx = NULL;
  141. fiov_teardown(&ftick->tk_aw_fiov);
  142. FUSE_OSFree(ftick, sizeof(struct fuse_ticket), fuse_malloc_tag);
  143. FUSE_OSAddAtomic(-1, (SInt32 *)&fuse_tickets_current);
  144. }
  145. static int
  146. fticket_wait_answer(struct fuse_ticket *ftick)
  147. {
  148. int err = 0;
  149. struct fuse_data *data;
  150. fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  151. if (fticket_answered(ftick)) {
  152. goto out;
  153. }
  154. data = ftick->tk_data;
  155. if (fdata_dead_get(data)) {
  156. err = ENOTCONN;
  157. fticket_set_answered(ftick);
  158. goto out;
  159. }
  160. again:
  161. err = fuse_msleep(ftick, ftick->tk_aw_mtx, PCATCH, "fu_ans",
  162. data->daemon_timeout_p);
  163. if (err == EAGAIN) { /* same as EWOULDBLOCK */
  164. kern_return_t kr;
  165. unsigned int rf;
  166. fuse_lck_mtx_lock(data->timeout_mtx);
  167. if (data->dataflags & FSESS_NO_ALERTS) {
  168. data->timeout_status = FUSE_DAEMON_TIMEOUT_DEAD;
  169. fuse_lck_mtx_unlock(data->timeout_mtx);
  170. goto alreadydead;
  171. }
  172. switch (data->timeout_status) {
  173. case FUSE_DAEMON_TIMEOUT_NONE:
  174. data->timeout_status = FUSE_DAEMON_TIMEOUT_PROCESSING;
  175. fuse_lck_mtx_unlock(data->timeout_mtx);
  176. break;
  177. case FUSE_DAEMON_TIMEOUT_PROCESSING:
  178. fuse_lck_mtx_unlock(data->timeout_mtx);
  179. goto again;
  180. break; /* NOTREACHED */
  181. case FUSE_DAEMON_TIMEOUT_DEAD:
  182. fuse_lck_mtx_unlock(data->timeout_mtx);
  183. goto alreadydead;
  184. break; /* NOTREACHED */
  185. default:
  186. IOLog("MacFUSE: invalid timeout status (%d)\n",
  187. data->timeout_status);
  188. fuse_lck_mtx_unlock(data->timeout_mtx);
  189. goto again;
  190. break; /* NOTREACHED */
  191. }
  192. /*
  193. * We will "hang" while this is showing.
  194. */
  195. #if M_MACFUSE_ENABLE_KUNC
  196. kr = KUNCUserNotificationDisplayAlert(
  197. FUSE_DAEMON_TIMEOUT_ALERT_TIMEOUT, // timeout
  198. 0, // flags (stop alert)
  199. NULL, // iconPath
  200. NULL, // soundPath
  201. NULL, // localizationPath
  202. data->volname, // alertHeader
  203. FUSE_DAEMON_TIMEOUT_ALERT_MESSAGE,
  204. FUSE_DAEMON_TIMEOUT_DEFAULT_BUTTON_TITLE,
  205. FUSE_DAEMON_TIMEOUT_ALTERNATE_BUTTON_TITLE,
  206. FUSE_DAEMON_TIMEOUT_OTHER_BUTTON_TITLE,
  207. &rf);
  208. #else
  209. kr = KERN_FAILURE;
  210. #endif
  211. if (kr != KERN_SUCCESS) {
  212. /* force ejection if we couldn't show the dialog */
  213. IOLog("MacFUSE: force ejecting (no response from user space %d)\n",
  214. kr);
  215. rf = kKUNCOtherResponse;
  216. }
  217. fuse_lck_mtx_lock(data->timeout_mtx);
  218. switch (rf) {
  219. case kKUNCOtherResponse: /* Force Eject */
  220. data->timeout_status = FUSE_DAEMON_TIMEOUT_DEAD;
  221. fuse_lck_mtx_unlock(data->timeout_mtx);
  222. break;
  223. case kKUNCDefaultResponse: /* Keep Trying */
  224. case kKUNCAlternateResponse: /* Don't Warn Again */
  225. case kKUNCCancelResponse: /* No Selection */
  226. data->timeout_status = FUSE_DAEMON_TIMEOUT_NONE;
  227. if (rf == kKUNCAlternateResponse) {
  228. data->daemon_timeout_p = (struct timespec *)0;
  229. }
  230. fuse_lck_mtx_unlock(data->timeout_mtx);
  231. goto again;
  232. break; /* NOTREACHED */
  233. default:
  234. IOLog("MacFUSE: unknown response from alert panel (kr=%d, rf=%d)\n",
  235. kr, rf);
  236. data->timeout_status = FUSE_DAEMON_TIMEOUT_DEAD;
  237. fuse_lck_mtx_unlock(data->timeout_mtx);
  238. break;
  239. }
  240. alreadydead:
  241. if (!fdata_dead_get(data)) {
  242. fdata_set_dead(data);
  243. }
  244. err = ENOTCONN;
  245. fticket_set_answered(ftick);
  246. goto out;
  247. }
  248. #if M_MACFUSE_ENABLE_INTERRUPT
  249. else if (err == -1) {
  250. /*
  251. * XXX: Stop gap! I really need to finish interruption plumbing.
  252. */
  253. fuse_internal_interrupt_send(ftick);
  254. }
  255. #endif
  256. out:
  257. fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  258. if (!(err || fticket_answered(ftick))) {
  259. IOLog("MacFUSE: requester was woken up but still no answer");
  260. err = ENXIO;
  261. }
  262. return err;
  263. }
  264. static __inline__
  265. int
  266. fticket_aw_pull_uio(struct fuse_ticket *ftick, uio_t uio)
  267. {
  268. int err = 0;
  269. size_t len = (size_t)uio_resid(uio);
  270. if (len) {
  271. switch (ftick->tk_aw_type) {
  272. case FT_A_FIOV:
  273. err = fiov_adjust_canfail(fticket_resp(ftick), len);
  274. if (err) {
  275. fticket_set_killl(ftick);
  276. IOLog("MacFUSE: failed to pull uio (error=%d)\n", err);
  277. break;
  278. }
  279. err = uiomove(fticket_resp(ftick)->base, (int)len, uio);
  280. if (err) {
  281. IOLog("MacFUSE: FT_A_FIOV error is %d (%p, %ld, %p)\n",
  282. err, fticket_resp(ftick)->base, len, uio);
  283. }
  284. break;
  285. case FT_A_BUF:
  286. ftick->tk_aw_bufsize = len;
  287. err = uiomove(ftick->tk_aw_bufdata, (int)len, uio);
  288. if (err) {
  289. IOLog("MacFUSE: FT_A_BUF error is %d (%p, %ld, %p)\n",
  290. err, ftick->tk_aw_bufdata, len, uio);
  291. }
  292. break;
  293. default:
  294. panic("MacFUSE: unknown answer type for ticket %p", ftick);
  295. }
  296. }
  297. return err;
  298. }
  299. int
  300. fticket_pull(struct fuse_ticket *ftick, uio_t uio)
  301. {
  302. int err = 0;
  303. if (ftick->tk_aw_ohead.error) {
  304. return 0;
  305. }
  306. err = fuse_body_audit(ftick, (size_t)uio_resid(uio));
  307. if (!err) {
  308. err = fticket_aw_pull_uio(ftick, uio);
  309. }
  310. return err;
  311. }
  312. struct fuse_data *
  313. fdata_alloc(struct proc *p)
  314. {
  315. struct fuse_data *data;
  316. data = (struct fuse_data *)FUSE_OSMalloc(sizeof(struct fuse_data),
  317. fuse_malloc_tag);
  318. if (!data) {
  319. panic("MacFUSE: OSMalloc failed in fdata_alloc");
  320. }
  321. bzero(data, sizeof(struct fuse_data));
  322. data->mp = NULL;
  323. data->rootvp = NULLVP;
  324. data->mount_state = FM_NOTMOUNTED;
  325. data->daemoncred = proc_ucred(p);
  326. data->daemonpid = proc_pid(p);
  327. data->dataflags = 0;
  328. data->mountaltflags = 0ULL;
  329. data->noimplflags = 0ULL;
  330. data->rwlock = lck_rw_alloc_init(fuse_lock_group, fuse_lock_attr);
  331. data->ms_mtx = lck_mtx_alloc_init(fuse_lock_group, fuse_lock_attr);
  332. data->aw_mtx = lck_mtx_alloc_init(fuse_lock_group, fuse_lock_attr);
  333. data->ticket_mtx = lck_mtx_alloc_init(fuse_lock_group, fuse_lock_attr);
  334. STAILQ_INIT(&data->ms_head);
  335. TAILQ_INIT(&data->aw_head);
  336. STAILQ_INIT(&data->freetickets_head);
  337. TAILQ_INIT(&data->alltickets_head);
  338. data->freeticket_counter = 0;
  339. data->deadticket_counter = 0;
  340. data->ticketer = 0;
  341. kauth_cred_ref(data->daemoncred);
  342. #if M_MACFUSE_EXCPLICIT_RENAME_LOCK
  343. data->rename_lock = lck_rw_alloc_init(fuse_lock_group, fuse_lock_attr);
  344. #endif
  345. data->timeout_status = FUSE_DAEMON_TIMEOUT_NONE;
  346. data->timeout_mtx = lck_mtx_alloc_init(fuse_lock_group, fuse_lock_attr);
  347. return data;
  348. }
  349. void
  350. fdata_destroy(struct fuse_data *data)
  351. {
  352. struct fuse_ticket *ftick;
  353. lck_mtx_free(data->ms_mtx, fuse_lock_group);
  354. data->ms_mtx = NULL;
  355. lck_mtx_free(data->aw_mtx, fuse_lock_group);
  356. data->aw_mtx = NULL;
  357. lck_mtx_free(data->ticket_mtx, fuse_lock_group);
  358. data->ticket_mtx = NULL;
  359. #if M_MACFUSE_EXPLICIT_RENAME_LOCK
  360. lck_rw_free(data->rename_lock, fuse_lock_group);
  361. data->rename_lock = NULL;
  362. #endif
  363. data->timeout_status = FUSE_DAEMON_TIMEOUT_NONE;
  364. lck_mtx_free(data->timeout_mtx, fuse_lock_group);
  365. while ((ftick = fuse_pop_allticks(data))) {
  366. fticket_destroy(ftick);
  367. }
  368. /* XXX: deprecated; should use kauth_cred_unref() */
  369. kauth_cred_rele(data->daemoncred);
  370. lck_rw_free(data->rwlock, fuse_lock_group);
  371. FUSE_OSFree(data, sizeof(struct fuse_data), fuse_malloc_tag);
  372. }
  373. int
  374. fdata_dead_get(struct fuse_data *data)
  375. {
  376. return (data->dataflags & FSESS_DEAD);
  377. }
  378. void
  379. fdata_set_dead(struct fuse_data *data)
  380. {
  381. fuse_lck_mtx_lock(data->ms_mtx);
  382. if (fdata_dead_get(data)) {
  383. fuse_lck_mtx_unlock(data->ms_mtx);
  384. return;
  385. }
  386. data->dataflags |= FSESS_DEAD;
  387. fuse_wakeup_one((caddr_t)data);
  388. #if M_MACFUSE_ENABLE_DSELECT
  389. selwakeup((struct selinfo*)&data->d_rsel);
  390. #endif /* M_MACFUSE_ENABLE_DSELECT */
  391. fuse_lck_mtx_unlock(data->ms_mtx);
  392. fuse_lck_mtx_lock(data->ticket_mtx);
  393. fuse_wakeup(&data->ticketer);
  394. fuse_lck_mtx_unlock(data->ticket_mtx);
  395. vfs_event_signal(&vfs_statfs(data->mp)->f_fsid, VQ_DEAD, 0);
  396. }
  397. static __inline__
  398. void
  399. fuse_push_freeticks(struct fuse_ticket *ftick)
  400. {
  401. STAILQ_INSERT_TAIL(&ftick->tk_data->freetickets_head, ftick,
  402. tk_freetickets_link);
  403. ftick->tk_data->freeticket_counter++;
  404. }
  405. static __inline__
  406. struct fuse_ticket *
  407. fuse_pop_freeticks(struct fuse_data *data)
  408. {
  409. struct fuse_ticket *ftick;
  410. if ((ftick = STAILQ_FIRST(&data->freetickets_head))) {
  411. STAILQ_REMOVE_HEAD(&data->freetickets_head, tk_freetickets_link);
  412. data->freeticket_counter--;
  413. }
  414. if (STAILQ_EMPTY(&data->freetickets_head) &&
  415. (data->freeticket_counter != 0)) {
  416. panic("MacFUSE: ticket count mismatch!");
  417. }
  418. return ftick;
  419. }
  420. static __inline__
  421. void
  422. fuse_push_allticks(struct fuse_ticket *ftick)
  423. {
  424. TAILQ_INSERT_TAIL(&ftick->tk_data->alltickets_head, ftick,
  425. tk_alltickets_link);
  426. }
  427. static __inline__
  428. void
  429. fuse_remove_allticks(struct fuse_ticket *ftick)
  430. {
  431. ftick->tk_data->deadticket_counter++;
  432. TAILQ_REMOVE(&ftick->tk_data->alltickets_head, ftick, tk_alltickets_link);
  433. }
  434. static struct fuse_ticket *
  435. fuse_pop_allticks(struct fuse_data *data)
  436. {
  437. struct fuse_ticket *ftick;
  438. if ((ftick = TAILQ_FIRST(&data->alltickets_head))) {
  439. fuse_remove_allticks(ftick);
  440. }
  441. return ftick;
  442. }
  443. struct fuse_ticket *
  444. fuse_ticket_fetch(struct fuse_data *data)
  445. {
  446. int err = 0;
  447. struct fuse_ticket *ftick;
  448. fuse_lck_mtx_lock(data->ticket_mtx);
  449. if (data->freeticket_counter == 0) {
  450. fuse_lck_mtx_unlock(data->ticket_mtx);
  451. ftick = fticket_alloc(data);
  452. if (!ftick) {
  453. panic("MacFUSE: ticket allocation failed");
  454. }
  455. fuse_lck_mtx_lock(data->ticket_mtx);
  456. fuse_push_allticks(ftick);
  457. } else {
  458. /* locked here */
  459. ftick = fuse_pop_freeticks(data);
  460. if (!ftick) {
  461. panic("MacFUSE: no free ticket despite the counter's value");
  462. }
  463. }
  464. if (!(data->dataflags & FSESS_INITED) && data->ticketer > 1) {
  465. err = fuse_msleep(&data->ticketer, data->ticket_mtx, PCATCH | PDROP,
  466. "fu_ini", 0);
  467. } else {
  468. if ((fuse_max_tickets != 0) &&
  469. ((data->ticketer - data->deadticket_counter) > fuse_max_tickets)) {
  470. err = 1;
  471. }
  472. fuse_lck_mtx_unlock(data->ticket_mtx);
  473. }
  474. if (err) {
  475. fdata_set_dead(data);
  476. }
  477. return ftick;
  478. }
  479. void
  480. fuse_ticket_drop(struct fuse_ticket *ftick)
  481. {
  482. int die = 0;
  483. fuse_lck_mtx_lock(ftick->tk_data->ticket_mtx);
  484. if ((fuse_max_freetickets >= 0 &&
  485. fuse_max_freetickets <= ftick->tk_data->freeticket_counter) ||
  486. (ftick->tk_flag & FT_KILLL)) {
  487. die = 1;
  488. } else {
  489. fuse_lck_mtx_unlock(ftick->tk_data->ticket_mtx);
  490. fticket_refresh(ftick);
  491. fuse_lck_mtx_lock(ftick->tk_data->ticket_mtx);
  492. }
  493. /* locked here */
  494. if (die) {
  495. fuse_remove_allticks(ftick);
  496. fuse_lck_mtx_unlock(ftick->tk_data->ticket_mtx);
  497. fticket_destroy(ftick);
  498. } else {
  499. fuse_push_freeticks(ftick);
  500. fuse_lck_mtx_unlock(ftick->tk_data->ticket_mtx);
  501. }
  502. }
  503. void
  504. fuse_ticket_kill(struct fuse_ticket *ftick)
  505. {
  506. fuse_lck_mtx_lock(ftick->tk_data->ticket_mtx);
  507. fuse_remove_allticks(ftick);
  508. fuse_lck_mtx_unlock(ftick->tk_data->ticket_mtx);
  509. fticket_destroy(ftick);
  510. }
  511. void
  512. fuse_ticket_drop_invalid(struct fuse_ticket *ftick)
  513. {
  514. if (ftick->tk_flag & FT_INVAL) {
  515. fuse_ticket_drop(ftick);
  516. }
  517. }
  518. void
  519. fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler)
  520. {
  521. if (fdata_dead_get(ftick->tk_data)) {
  522. return;
  523. }
  524. ftick->tk_aw_handler = handler;
  525. fuse_lck_mtx_lock(ftick->tk_data->aw_mtx);
  526. fuse_aw_push(ftick);
  527. fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx);
  528. }
  529. void
  530. fuse_insert_message(struct fuse_ticket *ftick)
  531. {
  532. if (ftick->tk_flag & FT_DIRTY) {
  533. panic("MacFUSE: ticket reused without being refreshed");
  534. }
  535. ftick->tk_flag |= FT_DIRTY;
  536. if (fdata_dead_get(ftick->tk_data)) {
  537. return;
  538. }
  539. fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
  540. fuse_ms_push(ftick);
  541. fuse_wakeup_one((caddr_t)ftick->tk_data);
  542. #if M_MACFUSE_ENABLE_DSELECT
  543. selwakeup((struct selinfo*)&ftick->tk_data->d_rsel);
  544. #endif /* M_MACFUSE_ENABLE_DSELECT */
  545. fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
  546. }
  547. void
  548. fuse_insert_message_head(struct fuse_ticket *ftick)
  549. {
  550. if (ftick->tk_flag & FT_DIRTY) {
  551. panic("MacFUSE: ticket reused without being refreshed");
  552. }
  553. ftick->tk_flag |= FT_DIRTY;
  554. if (fdata_dead_get(ftick->tk_data)) {
  555. return;
  556. }
  557. fuse_lck_mtx_lock(ftick->tk_data->ms_mtx);
  558. fuse_ms_push_head(ftick);
  559. fuse_wakeup_one((caddr_t)ftick->tk_data);
  560. #if M_MACFUSE_ENABLE_DSELECT
  561. selwakeup((struct selinfo*)&ftick->tk_data->d_rsel);
  562. #endif /* M_MACFUSE_ENABLE_DSELECT */
  563. fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx);
  564. }
  565. static int
  566. fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
  567. {
  568. int err = 0;
  569. enum fuse_opcode opcode;
  570. if (fdata_dead_get(ftick->tk_data)) {
  571. return ENOTCONN;
  572. }
  573. opcode = fticket_opcode(ftick);
  574. switch (opcode) {
  575. case FUSE_LOOKUP:
  576. err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  577. break;
  578. case FUSE_FORGET:
  579. panic("MacFUSE: a handler has been intalled for FUSE_FORGET");
  580. break;
  581. case FUSE_GETATTR:
  582. err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
  583. break;
  584. case FUSE_SETATTR:
  585. err = (blen == sizeof(struct fuse_attr_out)) ? 0 : EINVAL;
  586. break;
  587. case FUSE_GETXTIMES:
  588. err = (blen == sizeof(struct fuse_getxtimes_out)) ? 0 : EINVAL;
  589. break;
  590. case FUSE_READLINK:
  591. err = (PAGE_SIZE >= blen) ? 0 : EINVAL;
  592. break;
  593. case FUSE_SYMLINK:
  594. err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  595. break;
  596. case FUSE_MKNOD:
  597. err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  598. break;
  599. case FUSE_MKDIR:
  600. err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  601. break;
  602. case FUSE_UNLINK:
  603. err = (blen == 0) ? 0 : EINVAL;
  604. break;
  605. case FUSE_RMDIR:
  606. err = (blen == 0) ? 0 : EINVAL;
  607. break;
  608. case FUSE_RENAME:
  609. err = (blen == 0) ? 0 : EINVAL;
  610. break;
  611. case FUSE_LINK:
  612. err = (blen == sizeof(struct fuse_entry_out)) ? 0 : EINVAL;
  613. break;
  614. case FUSE_OPEN:
  615. err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  616. break;
  617. case FUSE_READ:
  618. err = (((struct fuse_read_in *)(
  619. (char *)ftick->tk_ms_fiov.base +
  620. sizeof(struct fuse_in_header)
  621. ))->size >= blen) ? 0 : EINVAL;
  622. break;
  623. case FUSE_WRITE:
  624. err = (blen == sizeof(struct fuse_write_out)) ? 0 : EINVAL;
  625. break;
  626. case FUSE_STATFS:
  627. if (fuse_libabi_geq(ftick->tk_data, 7, 4)) {
  628. err = (blen == sizeof(struct fuse_statfs_out)) ? 0 : EINVAL;
  629. } else {
  630. err = (blen == FUSE_COMPAT_STATFS_SIZE) ? 0 : EINVAL;
  631. }
  632. break;
  633. case FUSE_RELEASE:
  634. err = (blen == 0) ? 0 : EINVAL;
  635. break;
  636. case FUSE_FSYNC:
  637. err = (blen == 0) ? 0 : EINVAL;
  638. break;
  639. case FUSE_SETXATTR:
  640. /* TBD */
  641. break;
  642. case FUSE_GETXATTR:
  643. /* TBD */
  644. break;
  645. case FUSE_LISTXATTR:
  646. /* TBD */
  647. break;
  648. case FUSE_REMOVEXATTR:
  649. /* TBD */
  650. break;
  651. case FUSE_FLUSH:
  652. err = (blen == 0) ? 0 : EINVAL;
  653. break;
  654. case FUSE_INIT:
  655. if (blen == sizeof(struct fuse_init_out) || blen == 8) {
  656. err = 0;
  657. } else {
  658. err = EINVAL;
  659. }
  660. break;
  661. case FUSE_OPENDIR:
  662. err = (blen == sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  663. break;
  664. case FUSE_READDIR:
  665. err = (((struct fuse_read_in *)(
  666. (char *)ftick->tk_ms_fiov.base +
  667. sizeof(struct fuse_in_header)
  668. ))->size >= blen) ? 0 : EINVAL;
  669. break;
  670. case FUSE_RELEASEDIR:
  671. err = (blen == 0) ? 0 : EINVAL;
  672. break;
  673. case FUSE_FSYNCDIR:
  674. err = (blen == 0) ? 0 : EINVAL;
  675. break;
  676. case FUSE_GETLK:
  677. panic("MacFUSE: no response body format check for FUSE_GETLK");
  678. break;
  679. case FUSE_SETLK:
  680. panic("MacFUSE: no response body format check for FUSE_SETLK");
  681. break;
  682. case FUSE_SETLKW:
  683. panic("MacFUSE: no response body format check for FUSE_SETLKW");
  684. break;
  685. case FUSE_ACCESS:
  686. err = (blen == 0) ? 0 : EINVAL;
  687. break;
  688. case FUSE_CREATE:
  689. err = (blen == sizeof(struct fuse_entry_out) +
  690. sizeof(struct fuse_open_out)) ? 0 : EINVAL;
  691. break;
  692. case FUSE_INTERRUPT:
  693. /* TBD */
  694. break;
  695. case FUSE_BMAP:
  696. /* TBD */
  697. break;
  698. case FUSE_DESTROY:
  699. err = (blen == 0) ? 0 : EINVAL;
  700. break;
  701. case FUSE_EXCHANGE:
  702. err = (blen == 0) ? 0 : EINVAL;
  703. break;
  704. case FUSE_SETVOLNAME:
  705. err = (blen == 0) ? 0 : EINVAL;
  706. break;
  707. default:
  708. IOLog("MacFUSE: opcodes out of sync (%d)\n", opcode);
  709. panic("MacFUSE: opcodes out of sync (%d)", opcode);
  710. }
  711. return err;
  712. }
  713. static void
  714. fuse_setup_ihead(struct fuse_in_header *ihead,
  715. struct fuse_ticket *ftick,
  716. uint64_t nid,
  717. enum fuse_opcode op,
  718. size_t blen,
  719. vfs_context_t context)
  720. {
  721. ihead->len = (uint32_t)(sizeof(*ihead) + blen);
  722. ihead->unique = ftick->tk_unique;
  723. ihead->nodeid = nid;
  724. ihead->opcode = op;
  725. if (context) {
  726. ihead->pid = vfs_context_pid(context);
  727. ihead->uid = vfs_context_ucred(context)->cr_uid;
  728. ihead->gid = vfs_context_ucred(context)->cr_gid;
  729. } else {
  730. /* XXX: could use more thought */
  731. ihead->pid = proc_pid((proc_t)current_proc());
  732. ihead->uid = kauth_cred_getuid(kauth_cred_get());
  733. ihead->gid = kauth_cred_getgid(kauth_cred_get());
  734. }
  735. }
  736. static int
  737. fuse_standard_handler(struct fuse_ticket *ftick, uio_t uio)
  738. {
  739. int err = 0;
  740. int dropflag = 0;
  741. err = fticket_pull(ftick, uio);
  742. fuse_lck_mtx_lock(ftick->tk_aw_mtx);
  743. if (fticket_answered(ftick)) {
  744. dropflag = 1;
  745. } else {
  746. fticket_set_answered(ftick);
  747. ftick->tk_aw_errno = err;
  748. fuse_wakeup(ftick);
  749. }
  750. fuse_lck_mtx_unlock(ftick->tk_aw_mtx);
  751. if (dropflag) {
  752. fuse_ticket_drop(ftick);
  753. }
  754. return err;
  755. }
  756. void
  757. fdisp_make(struct fuse_dispatcher *fdip,
  758. enum fuse_opcode op,
  759. mount_t mp,
  760. uint64_t nid,
  761. vfs_context_t context)
  762. {
  763. struct fuse_data *data = fuse_get_mpdata(mp);
  764. if (fdip->tick) {
  765. fticket_refresh(fdip->tick);
  766. } else {
  767. fdip->tick = fuse_ticket_fetch(data);
  768. }
  769. if (fdip->tick == 0) {
  770. panic("MacFUSE: fuse_ticket_fetch() failed");
  771. }
  772. FUSE_DIMALLOC(&fdip->tick->tk_ms_fiov, fdip->finh,
  773. fdip->indata, fdip->iosize);
  774. fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, context);
  775. }
  776. int
  777. fdisp_make_canfail(struct fuse_dispatcher *fdip,
  778. enum fuse_opcode op,
  779. mount_t mp,
  780. uint64_t nid,
  781. vfs_context_t context)
  782. {
  783. int failed = 0;
  784. struct fuse_iov *fiov = NULL;
  785. struct fuse_data *data = fuse_get_mpdata(mp);
  786. if (fdip->tick) {
  787. fticket_refresh(fdip->tick);
  788. } else {
  789. fdip->tick = fuse_ticket_fetch(data);
  790. }
  791. if (fdip->tick == 0) {
  792. panic("MacFUSE: fuse_ticket_fetch() failed");
  793. }
  794. fiov = &fdip->tick->tk_ms_fiov;
  795. failed = fiov_adjust_canfail(fiov,
  796. sizeof(struct fuse_in_header) + fdip->iosize);
  797. if (failed) {
  798. fuse_ticket_kill(fdip->tick);
  799. return failed;
  800. }
  801. fdip->finh = fiov->base;
  802. fdip->indata = (char *)(fiov->base) + sizeof(struct fuse_in_header);
  803. fuse_setup_ihead(fdip->finh, fdip->tick, nid, op, fdip->iosize, context);
  804. return 0;
  805. }
  806. void
  807. fdisp_make_vp(struct fuse_dispatcher *fdip,
  808. enum fuse_opcode op,
  809. vnode_t vp,
  810. vfs_context_t context)
  811. {
  812. return fdisp_make(fdip, op, vnode_mount(vp), VTOI(vp), context);
  813. }
  814. int
  815. fdisp_make_vp_canfail(struct fuse_dispatcher *fdip,
  816. enum fuse_opcode op,
  817. vnode_t vp,
  818. vfs_context_t context)
  819. {
  820. return fdisp_make_canfail(fdip, op, vnode_mount(vp), VTOI(vp), context);
  821. }
  822. int
  823. fdisp_wait_answ(struct fuse_dispatcher *fdip)
  824. {
  825. int err = 0;
  826. fdip->answ_stat = 0;
  827. fuse_insert_callback(fdip->tick, fuse_standard_handler);
  828. fuse_insert_message(fdip->tick);
  829. if ((err = fticket_wait_answer(fdip->tick))) { /* interrupted */
  830. #ifndef DONT_TRY_HARD_PREVENT_IO_IN_VAIN
  831. struct fuse_ticket *ftick;
  832. unsigned age;
  833. #endif
  834. fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx);
  835. if (fticket_answered(fdip->tick)) {
  836. /* IPC: already answered */
  837. fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  838. goto out;
  839. } else {
  840. /* IPC: explicitly setting to answered */
  841. age = fdip->tick->tk_age;
  842. fticket_set_answered(fdip->tick);
  843. fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx);
  844. #ifndef DONT_TRY_HARD_PREVENT_IO_IN_VAIN
  845. fuse_lck_mtx_lock(fdip->tick->tk_data->aw_mtx);
  846. TAILQ_FOREACH(ftick, &fdip->tick->tk_data->aw_head, tk_aw_link) {
  847. if (ftick == fdip->tick) {
  848. if (fdip->tick->tk_age == age) {
  849. /* Succeeded preventing I/O in vain */
  850. fdip->tick->tk_aw_handler = NULL;
  851. }
  852. break;
  853. }
  854. }
  855. fuse_lck_mtx_unlock(fdip->tick->tk_data->aw_mtx);
  856. #endif
  857. return err;
  858. }
  859. }
  860. /* IPC was NOT interrupt */
  861. if (fdip->tick->tk_aw_errno) {
  862. /* Explicitly EIO-ing */
  863. err = EIO;
  864. goto out;
  865. }
  866. if ((err = fdip->tick->tk_aw_ohead.error)) {
  867. /* Explicitly setting status */
  868. fdip->answ_stat = err;
  869. goto out;
  870. }
  871. fdip->answ = fticket_resp(fdip->tick)->base;
  872. fdip->iosize = fticket_resp(fdip->tick)->len;
  873. return 0;
  874. out:
  875. fuse_ticket_drop(fdip->tick);
  876. return err;
  877. }