- res = fuse_buf_copy(&pipe_buf, buf,
- FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
- if (res< 0) {
- if (res == -EAGAIN || res == -EINVAL) {
- /*
- * Should only get EAGAIN on kernels with
- * broken SPLICE_F_NONBLOCK support (<=
- * 2.6.35) where this error or a short read is
- * returned even if the pipe itself is not
- * full
- *
- * EINVAL might mean that splice can't handle
- * this combination of input and output.
- */
- if (res == -EAGAIN)
- se->broken_splice_nonblock = 1;
-
- pthread_setspecific(se->pipe_key, NULL);
- fuse_ll_pipe_free(llp);
- goto fallback;
- }
- res = -res;
- goto clear_pipe;
- }
-
- if (res != 0&& res< len) {
- struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
- void *mbuf;
- size_t now_len = res;
- /*
- * For regular files a short count is either
- * 1) due to EOF, or
- * 2) because of broken SPLICE_F_NONBLOCK (see above)
- *
- * For other inputs it's possible that we overflowed
- * the pipe because of small buffer fragments.
- */
-
- res = posix_memalign(&mbuf, pagesize, len);
- if (res != 0)
- goto clear_pipe;
-
- mem_buf.buf[0].mem = mbuf;
- mem_buf.off = now_len;
- res = fuse_buf_copy(&mem_buf, buf, 0);
- if (res> 0) {
- char *tmpbuf;
- size_t extra_len = res;
- /*
- * Trickiest case: got more data. Need to get
- * back the data from the pipe and then fall
- * back to regular write.
- */
- tmpbuf = malloc(headerlen);
- if (tmpbuf == NULL) {
- free(mbuf);
- res = ENOMEM;
- goto clear_pipe;
- }
- res = read_back(llp->pipe[0], tmpbuf, headerlen);
- free(tmpbuf);
- if (res != 0) {
- free(mbuf);
- goto clear_pipe;
- }
- res = read_back(llp->pipe[0], mbuf, now_len);
- if (res != 0) {
- free(mbuf);
- goto clear_pipe;
- }
- len = now_len + extra_len;
- iov[iov_count].iov_base = mbuf;
- iov[iov_count].iov_len = len;
- iov_count++;
- res = fuse_send_msg(se, ch, iov, iov_count);
- free(mbuf);
- return res;
- }
- free(mbuf);
- res = now_len;
- }
- len = res;
- out->len = headerlen + len;
-
- if (se->debug) {
- fuse_log(FUSE_LOG_DEBUG,
- " unique: %llu, success, outsize: %i (splice)\n",
- (unsigned long long) out->unique, out->len);
- }
-
- splice_flags = 0;
- if ((flags& FUSE_BUF_SPLICE_MOVE)&&
- (se->conn.want& FUSE_CAP_SPLICE_MOVE))
- splice_flags |= SPLICE_F_MOVE;
-
- res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd,
- NULL, out->len, splice_flags);