You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

423 lines
7.7 KiB

5 years ago
5 years ago
5 years ago
  1. #define _GNU_SOURCE
  2. #include "fuse_chan.h"
  3. #include "fuse_lowlevel.h"
  4. #include "fuse_kernel.h"
  5. #include "sys.h"
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <sys/ioctl.h>
  13. #include <unistd.h>
  14. static const char DEV_FUSE[] = "/dev/fuse";
  15. static
  16. void*
  17. aligned_mem(const uint64_t size_)
  18. {
  19. int rv;
  20. void *mem;
  21. int pagesize;
  22. pagesize = sys_get_pagesize();
  23. rv = posix_memalign(&mem,pagesize,size_);
  24. if(rv == 0)
  25. return mem;
  26. errno = rv;
  27. return NULL;
  28. }
  29. static
  30. int
  31. clone_devfuse_fd(const int devfuse_fd_)
  32. {
  33. #ifdef FUSE_DEV_IOC_CLONE
  34. int rv;
  35. int clone_fd;
  36. clone_fd = open(DEV_FUSE,O_RDWR|O_CLOEXEC);
  37. if(clone_fd == -1)
  38. return devfuse_fd_;
  39. rv = ioctl(clone_fd,FUSE_DEV_IOC_CLONE,&devfuse_fd_);
  40. if(rv == -1)
  41. {
  42. perror("fuse: failed to clone /dev/fuse");
  43. close(clone_fd);
  44. return devfuse_fd_;
  45. }
  46. return clone_fd;
  47. #else
  48. return devfuse_fd_;
  49. #endif
  50. }
  51. int
  52. fuse_msg_bufsize(void)
  53. {
  54. int bufsize;
  55. bufsize = ((FUSE_MSG_MAX_PAGES + 1) * sys_get_pagesize());
  56. return bufsize;
  57. }
  58. fuse_chan_t*
  59. fuse_chan_new(int32_t devfuse_fd_,
  60. uint32_t flags_)
  61. {
  62. int rv;
  63. int bufsize;
  64. fuse_chan_t *ch;
  65. ch = (fuse_chan_t*)calloc(1,sizeof(fuse_chan_t));
  66. if(ch == NULL)
  67. {
  68. fprintf(stderr, "fuse: failed to allocate channel memory\n");
  69. return NULL;
  70. }
  71. bufsize = fuse_msg_bufsize();
  72. ch->fd = clone_devfuse_fd(devfuse_fd_);
  73. ch->buf = aligned_mem(bufsize);
  74. ch->bufsize = bufsize;
  75. ch->flags = flags_;
  76. if(flags_ & (FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE))
  77. {
  78. rv = sys_alloc_pipe(ch->splice_pipe,bufsize);
  79. if(rv == -1)
  80. ch->flags &= ~(FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE);
  81. }
  82. return ch;
  83. }
  84. static
  85. int64_t
  86. fuse_chan_recv_splice(fuse_chan_t *ch_,
  87. char *buf_,
  88. uint64_t size_)
  89. {
  90. int64_t rv;
  91. struct iovec iov;
  92. restart_splice:
  93. rv = splice(ch_->fd,NULL,ch_->splice_pipe[1],NULL,size_,SPLICE_F_MOVE);
  94. switch((rv == -1) ? errno : 0)
  95. {
  96. case 0:
  97. break;
  98. case ENOENT:
  99. case EINTR:
  100. case EAGAIN:
  101. goto restart_splice;
  102. case ENODEV:
  103. return 0;
  104. default:
  105. return -errno;
  106. }
  107. iov.iov_base = buf_;
  108. iov.iov_len = rv;
  109. restart_vmsplice:
  110. rv = vmsplice(ch_->splice_pipe[0],&iov,1,SPLICE_F_MOVE);
  111. switch((rv == -1) ? errno : 0)
  112. {
  113. case 0:
  114. break;
  115. case ENOENT:
  116. case EINTR:
  117. case EAGAIN:
  118. goto restart_vmsplice;
  119. case ENODEV:
  120. return 0;
  121. default:
  122. return -errno;
  123. }
  124. return rv;
  125. }
  126. static
  127. int
  128. fuse_chan_recv_read(fuse_chan_t *ch_,
  129. char *buf_,
  130. uint64_t size_)
  131. {
  132. int64_t rv;
  133. restart:
  134. rv = read(ch_->fd,buf_,size_);
  135. switch((rv == -1) ? errno : 0)
  136. {
  137. case 0:
  138. break;
  139. case ENOENT:
  140. case EINTR:
  141. case EAGAIN:
  142. goto restart;
  143. case ENODEV:
  144. return 0;
  145. default:
  146. return -errno;
  147. }
  148. if(rv < sizeof(struct fuse_in_header))
  149. {
  150. fprintf(stderr, "fuse: short read on fuse device\n");
  151. return -EIO;
  152. }
  153. return rv;
  154. }
  155. int64_t
  156. fuse_chan_recv(fuse_chan_t *ch_,
  157. char *buf_,
  158. size_t size_)
  159. {
  160. if(ch_->flags & FUSE_CHAN_SPLICE_READ)
  161. return fuse_chan_recv_splice(ch_,buf_,size_);
  162. return fuse_chan_recv_read(ch_,buf_,size_);
  163. }
  164. static
  165. int64_t
  166. fuse_chan_send_write(fuse_chan_t *ch_,
  167. const struct iovec iov_[],
  168. size_t count_)
  169. {
  170. int64_t rv;
  171. if(iov_ == NULL)
  172. return 0;
  173. rv = writev(ch_->fd,iov_,count_);
  174. if(rv == -1)
  175. return -errno;
  176. return rv;
  177. }
  178. static
  179. int64_t
  180. fuse_chan_send_splice(fuse_chan_t *ch_,
  181. const struct iovec iov_[],
  182. size_t count_)
  183. {
  184. int64_t rv;
  185. rv = vmsplice(ch_->splice_pipe[1],iov_,count_,SPLICE_F_MOVE);
  186. if(rv == -1)
  187. return -errno;
  188. rv = splice(ch_->splice_pipe[0],NULL,ch_->fd,NULL,rv,SPLICE_F_MOVE);
  189. return rv;
  190. }
  191. int64_t
  192. fuse_chan_send(fuse_chan_t *ch,
  193. const struct iovec iov[],
  194. size_t count)
  195. {
  196. if(ch->flags & FUSE_CHAN_SPLICE_WRITE)
  197. return fuse_chan_send_splice(ch,iov,count);
  198. return fuse_chan_send_write(ch,iov,count);
  199. }
  200. static
  201. int
  202. retryable_error(const int errno_)
  203. {
  204. switch(errno_)
  205. {
  206. case EINTR:
  207. case EAGAIN:
  208. return 1;
  209. default:
  210. return 0;
  211. }
  212. }
  213. static
  214. int
  215. retry_error(const int rv_,
  216. const int errno_)
  217. {
  218. if(rv_ == -1)
  219. return retryable_error(errno_);
  220. return 0;
  221. }
  222. static
  223. int64_t
  224. writen(const int fd_,
  225. void *buf_,
  226. const uint64_t count_)
  227. {
  228. char *buf;
  229. uint64_t n_left;
  230. int64_t n_written;
  231. buf = buf_;
  232. n_left = count_;
  233. do
  234. {
  235. n_written = write(fd_,buf,n_left);
  236. if(retry_error(n_written,errno))
  237. continue;
  238. if(n_written == -1)
  239. return -1;
  240. n_left -= n_written;
  241. buf += n_written;
  242. }
  243. while(n_left > 0);
  244. return count_;
  245. }
  246. static
  247. int64_t
  248. readn(const int fd_,
  249. char *buf_,
  250. const uint64_t count_)
  251. {
  252. uint64_t n_left;
  253. int64_t n_read;
  254. n_left = count_;
  255. do
  256. {
  257. n_read = read(fd_,buf_,n_left);
  258. if(n_read == 0)
  259. return 0;
  260. if(retry_error(n_read,errno))
  261. continue;
  262. if(n_read == -1)
  263. return -1;
  264. n_left -= n_read;
  265. }
  266. while(n_left > 0);
  267. return count_;
  268. }
  269. static
  270. int64_t
  271. splicen_seek(const int fd_in_,
  272. const loff_t off_in_,
  273. const int fd_out_,
  274. const uint64_t len_)
  275. {
  276. uint64_t n_left;
  277. int64_t n_written;
  278. loff_t off_in;
  279. n_left = len_;
  280. off_in = off_in_;
  281. do
  282. {
  283. n_written = splice(fd_in_,&off_in,fd_out_,NULL,n_left,SPLICE_F_MOVE);
  284. if(retry_error(n_written,errno))
  285. continue;
  286. if(n_written == -1)
  287. return -1;
  288. n_left -= n_written;
  289. off_in += n_written;
  290. }
  291. while(n_left > 0);
  292. return len_;
  293. }
  294. static
  295. int64_t
  296. splicen_noseek(const int fd_in_,
  297. const int fd_out_,
  298. const uint64_t len_)
  299. {
  300. uint64_t n_left;
  301. int64_t n_written;
  302. n_left = len_;
  303. do
  304. {
  305. n_written = splice(fd_in_,NULL,fd_out_,NULL,n_left,SPLICE_F_MOVE);
  306. if(retry_error(n_written,errno))
  307. continue;
  308. if(n_written == -1)
  309. return -1;
  310. n_left -= n_written;
  311. }
  312. while(n_left > 0);
  313. return len_;
  314. }
  315. int64_t
  316. fuse_chan_send_data_splice(fuse_chan_t *ch_,
  317. struct fuse_out_header *hdr_,
  318. const int data_fd_,
  319. const loff_t data_off_,
  320. const int data_len_)
  321. {
  322. int64_t rv;
  323. rv = writen(ch_->splice_pipe[1],hdr_,sizeof(struct fuse_out_header));
  324. if(rv == -1)
  325. return -1;
  326. rv = splicen_seek(data_fd_,data_off_,ch_->splice_pipe[1],data_len_);
  327. if(rv == -1)
  328. return -1;
  329. rv = splicen_noseek(ch_->splice_pipe[0],ch_->fd,(sizeof(struct fuse_out_header)+data_len_));
  330. return rv;
  331. }
  332. int64_t
  333. fuse_chan_send_data(fuse_chan_t *ch_,
  334. struct fuse_out_header *hdr_,
  335. const int data_fd_,
  336. const int data_len_)
  337. {
  338. int64_t rv;
  339. memcpy(ch_->buf,hdr_,sizeof(struct fuse_out_header));
  340. rv = readn(data_fd_,
  341. &ch_->buf[sizeof(struct fuse_out_header)],
  342. data_len_);
  343. if(rv == -1)
  344. return -1;
  345. rv = write(ch_->fd,ch_->buf,(sizeof(struct fuse_out_header) + data_len_));
  346. return rv;
  347. }
  348. void
  349. fuse_chan_destroy(fuse_chan_t *ch)
  350. {
  351. close(ch->fd);
  352. if(ch->flags & (FUSE_CHAN_SPLICE_READ|FUSE_CHAN_SPLICE_WRITE))
  353. {
  354. close(ch->splice_pipe[0]);
  355. close(ch->splice_pipe[1]);
  356. }
  357. free(ch->buf);
  358. free(ch);
  359. }