static int oo_splice_read_cb(void* context, struct iovec* iov, int iov_num, int flags) { struct oo_splice_read_context* ctx = context; int rc; citp_exit_lib_if(ctx->lib_context, TRUE); rc = writev(ctx->alien_fd, iov, iov_num); citp_enter_lib(ctx->lib_context); return rc; }
int onload_recvmsg_kernel(int fd, struct msghdr *msg, int flags) { int rc; citp_lib_context_t lib_context; citp_fdinfo* fdi; Log_CALL(ci_log("%s(%d, %p, %x)", __FUNCTION__, fd, msg, flags)); if( (fdi = citp_fdtable_lookup_fast(&lib_context, fd)) ) { rc = citp_fdinfo_get_ops(fdi)->recvmsg_kernel(fdi, msg, flags); citp_fdinfo_release_ref_fast(fdi); citp_exit_lib(&lib_context, rc >= 0); } else { citp_exit_lib_if(&lib_context, TRUE); rc = -ESOCKTNOSUPPORT; } Log_CALL_RESULT(rc); return rc; }
int onload_zc_recv(int fd, struct onload_zc_recv_args* args) { int rc; citp_lib_context_t lib_context; citp_fdinfo* fdi; Log_CALL(ci_log("%s(%d, %p(flags=%x))", __FUNCTION__, fd, args, args->flags)); if( (fdi = citp_fdtable_lookup_fast(&lib_context, fd)) ) { rc = citp_fdinfo_get_ops(fdi)->zc_recv(fdi, args); citp_fdinfo_release_ref_fast(fdi); citp_exit_lib(&lib_context, rc >= 0); } else { citp_exit_lib_if(&lib_context, TRUE); rc = -ESOCKTNOSUPPORT; } Log_CALL_RESULT(rc); return rc; }
int onload_set_recv_filter(int fd, onload_zc_recv_filter_callback filter, void* cb_arg, int flags) { int rc; citp_lib_context_t lib_context; citp_fdinfo* fdi; Log_CALL(ci_log("%s(%d, %p, %p, %x)", __FUNCTION__, fd, filter, cb_arg, flags)); if( (fdi = citp_fdtable_lookup_fast(&lib_context, fd)) ) { rc = citp_fdinfo_get_ops(fdi)->zc_recv_filter(fdi, filter, cb_arg, flags); citp_fdinfo_release_ref_fast(fdi); citp_exit_lib(&lib_context, rc >= 0); } else { citp_exit_lib_if(&lib_context, TRUE); rc = -ESOCKTNOSUPPORT; } Log_CALL_RESULT(rc); return rc; }
int citp_pipe_splice_write(citp_fdinfo* fdi, int alien_fd, loff_t* alien_off, size_t olen, int flags, citp_lib_context_t* lib_context) { citp_pipe_fdi* epi = fdi_to_pipe_fdi(fdi); int len_in_bufs = OO_PIPE_SIZE_TO_BUFS(olen); struct iovec iov_on_stack[CITP_PIPE_SPLICE_WRITE_STACK_IOV_LEN]; struct iovec* iov = iov_on_stack; int want_buf_count; int rc; int bytes_to_read; int len = olen; int no_more = 1; /* for now we only run single loop */ int written_total = 0; int non_block = (flags & SPLICE_F_NONBLOCK) || (epi->pipe->aflags & (CI_PFD_AFLAG_NONBLOCK << CI_PFD_AFLAG_WRITER_SHIFT)); if( fdi_is_reader(fdi) ) { errno = EINVAL; return -1; } if( alien_off ) { /* TODO support this */ errno = ENOTSUP; return -1; } do { int count; int iov_num; int bytes_to_write; struct ci_pipe_pkt_list pkts = {}; struct ci_pipe_pkt_list pkts2; want_buf_count = len_in_bufs; /* We might need to wait for buffers here on the first iteration */ rc = ci_pipe_zc_alloc_buffers(epi->ni, epi->pipe, want_buf_count, MSG_NOSIGNAL | (non_block || written_total ? MSG_DONTWAIT : 0), &pkts); if( rc < 0 && written_total ) { /* whatever the error we need to report already written_bytes */ rc = written_total; break; } else if( rc < 0 ) break; else if( pkts.count == 0 && non_block ) { errno = EAGAIN; rc = -1; break; } else ci_assert_gt(pkts.count, 0); count = pkts.count; if( count > CITP_PIPE_SPLICE_WRITE_STACK_IOV_LEN ) { void* niov = realloc(iov == iov_on_stack ? NULL : iov, sizeof(*iov) * len_in_bufs); if( niov == NULL ) /* we can still move quite a few pkts */ count = CITP_PIPE_SPLICE_WRITE_STACK_IOV_LEN; else niov = iov; } ci_assert_ge(count, 1); iov_num = count; pkts2 = pkts; bytes_to_read = ci_pipe_list_to_iovec(epi->ni, epi->pipe, iov, &iov_num, &pkts2, len); citp_exit_lib_if(lib_context, TRUE); /* Note: the following call might be non-blocking as well as blocking */ rc = readv(alien_fd, iov, count); citp_reenter_lib(lib_context); if( rc > 0 ) { bytes_to_write = rc; written_total += bytes_to_write; len -= bytes_to_write; no_more |= bytes_to_write < bytes_to_read; } else { bytes_to_write = 0; no_more = 1; } { /* pipe zc_write will write non_empty buffers and release the empty * ones */ int rc2 = ci_pipe_zc_write(epi->ni, epi->pipe, &pkts, bytes_to_write, CI_PIPE_ZC_WRITE_FLAG_FORCE | MSG_DONTWAIT | MSG_NOSIGNAL); (void) rc2; ci_assert_equal(rc2, bytes_to_write); } /* for now we will not be doing second iteration, to allow for that * we'd need to have guarantee that read will not block * e.g. insight into type of fd and a nonblokcing operation * (to name a valid case: socket, recvmsg) */ } while( ! no_more ); if( iov != iov_on_stack ) free(iov); if( rc > 0 ) return written_total; if( rc < 0 && errno == EPIPE && ! (flags & MSG_NOSIGNAL) ) { ci_sys_ioctl(ci_netif_get_driver_handle(epi->ni), OO_IOC_KILL_SELF_SIGPIPE, NULL); } return rc; }