Path: blob/main/sys/ofed/drivers/infiniband/ulp/sdp/sdp_zcopy.c
39566 views
/*-1* SPDX-License-Identifier: BSD-2-Clause OR GPL-2.02*3* Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved.4*5* This software is available to you under a choice of one of two6* licenses. You may choose to be licensed under the terms of the GNU7* General Public License (GPL) Version 2, available from the file8* COPYING in the main directory of this source tree, or the9* OpenIB.org BSD license below:10*11* Redistribution and use in source and binary forms, with or12* without modification, are permitted provided that the following13* conditions are met:14*15* - Redistributions of source code must retain the above16* copyright notice, this list of conditions and the following17* disclaimer.18*19* - Redistributions in binary form must reproduce the above20* copyright notice, this list of conditions and the following21* disclaimer in the documentation and/or other materials22* provided with the distribution.23*24* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31* SOFTWARE.32*/33#include <linux/tcp.h>34#include <asm/ioctls.h>35#include <linux/workqueue.h>36#include <linux/net.h>37#include <linux/socket.h>38#include <net/protocol.h>39#include <net/inet_common.h>40#include <rdma/rdma_cm.h>41#include <rdma/ib_verbs.h>42#include <rdma/ib_fmr_pool.h>43#include <rdma/ib_umem.h>44#include <net/tcp.h> /* for memcpy_toiovec */45#include <asm/io.h>46#include <asm/uaccess.h>47#include <linux/delay.h>48#include "sdp.h"4950static int sdp_post_srcavail(struct socket *sk, struct tx_srcavail_state *tx_sa)51{52struct sdp_sock *ssk = sdp_sk(sk);53struct mbuf *mb;54int payload_len;55struct page *payload_pg;56int off, len;57struct ib_umem_chunk *chunk;5859WARN_ON(ssk->tx_sa);6061BUG_ON(!tx_sa);62BUG_ON(!tx_sa->fmr || !tx_sa->fmr->fmr->lkey);63BUG_ON(!tx_sa->umem);64BUG_ON(!tx_sa->umem->chunk_list.next);6566chunk = list_entry(tx_sa->umem->chunk_list.next, struct ib_umem_chunk, list);67BUG_ON(!chunk->nmap);6869off = tx_sa->umem->offset;70len = tx_sa->umem->length;7172tx_sa->bytes_sent = tx_sa->bytes_acked = 0;7374mb = sdp_alloc_mb_srcavail(sk, len, tx_sa->fmr->fmr->lkey, off, 0);75if (!mb) {76return -ENOMEM;77}78sdp_dbg_data(sk, "sending SrcAvail\n");7980TX_SRCAVAIL_STATE(mb) = tx_sa; /* tx_sa is hanged on the mb81* but continue to live after mb is freed */82ssk->tx_sa = tx_sa;8384/* must have payload inlined in SrcAvail packet in combined mode */85payload_len = MIN(tx_sa->umem->page_size - off, len);86payload_len = MIN(payload_len, ssk->xmit_size_goal - sizeof(struct sdp_srcah));87payload_pg = sg_page(&chunk->page_list[0]);88get_page(payload_pg);8990sdp_dbg_data(sk, "payload: off: 0x%x, pg: %p, len: 0x%x\n",91off, payload_pg, payload_len);9293mb_fill_page_desc(mb, mb_shinfo(mb)->nr_frags,94payload_pg, off, payload_len);9596mb->len += payload_len;97mb->data_len = payload_len;98mb->truesize += payload_len;99// sk->sk_wmem_queued += payload_len;100// sk->sk_forward_alloc -= payload_len;101102mb_entail(sk, ssk, mb);103104ssk->write_seq += payload_len;105SDP_SKB_CB(mb)->end_seq += payload_len;106107tx_sa->bytes_sent = tx_sa->umem->length;108tx_sa->bytes_acked = payload_len;109110/* TODO: pushing the mb into the tx_queue should be enough */111112return 0;113}114115static int sdp_post_srcavail_cancel(struct socket *sk)116{117struct sdp_sock *ssk = sdp_sk(sk);118struct mbuf *mb;119120sdp_dbg_data(ssk->socket, "Posting srcavail cancel\n");121122mb = sdp_alloc_mb_srcavail_cancel(sk, 0);123mb_entail(sk, ssk, mb);124125sdp_post_sends(ssk, 0);126127schedule_delayed_work(&ssk->srcavail_cancel_work,128SDP_SRCAVAIL_CANCEL_TIMEOUT);129130return 0;131}132133void srcavail_cancel_timeout(struct work_struct *work)134{135struct sdp_sock *ssk =136container_of(work, struct sdp_sock, srcavail_cancel_work.work);137struct socket *sk = ssk->socket;138139lock_sock(sk);140141sdp_dbg_data(sk, "both SrcAvail and SrcAvailCancel timedout."142" closing connection\n");143sdp_set_error(sk, -ECONNRESET);144wake_up(&ssk->wq);145146release_sock(sk);147}148149static int sdp_wait_rdmardcompl(struct sdp_sock *ssk, long *timeo_p,150int ignore_signals)151{152struct socket *sk = ssk->socket;153int err = 0;154long vm_wait = 0;155long current_timeo = *timeo_p;156struct tx_srcavail_state *tx_sa = ssk->tx_sa;157DEFINE_WAIT(wait);158159sdp_dbg_data(sk, "sleep till RdmaRdCompl. timeo = %ld.\n", *timeo_p);160sdp_prf1(sk, NULL, "Going to sleep");161while (ssk->qp_active) {162prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);163164if (unlikely(!*timeo_p)) {165err = -ETIME;166tx_sa->abort_flags |= TX_SA_TIMEDOUT;167sdp_prf1(sk, NULL, "timeout");168SDPSTATS_COUNTER_INC(zcopy_tx_timeout);169break;170}171172else if (tx_sa->bytes_acked > tx_sa->bytes_sent) {173err = -EINVAL;174sdp_dbg_data(sk, "acked bytes > sent bytes\n");175tx_sa->abort_flags |= TX_SA_ERROR;176break;177}178179if (tx_sa->abort_flags & TX_SA_SENDSM) {180sdp_prf1(sk, NULL, "Aborting SrcAvail sending");181SDPSTATS_COUNTER_INC(zcopy_tx_aborted);182err = -EAGAIN;183break ;184}185186if (!ignore_signals) {187if (signal_pending(current)) {188err = -EINTR;189sdp_prf1(sk, NULL, "signalled");190tx_sa->abort_flags |= TX_SA_INTRRUPTED;191break;192}193194if (ssk->rx_sa && (tx_sa->bytes_acked < tx_sa->bytes_sent)) {195sdp_dbg_data(sk, "Crossing SrcAvail - aborting this\n");196tx_sa->abort_flags |= TX_SA_CROSS_SEND;197SDPSTATS_COUNTER_INC(zcopy_cross_send);198err = -ETIME;199break ;200}201}202203posts_handler_put(ssk);204205sk_wait_event(sk, ¤t_timeo,206tx_sa->abort_flags &&207ssk->rx_sa &&208(tx_sa->bytes_acked < tx_sa->bytes_sent) &&209vm_wait);210sdp_dbg_data(ssk->socket, "woke up sleepers\n");211212posts_handler_get(ssk);213214if (tx_sa->bytes_acked == tx_sa->bytes_sent)215break;216217if (vm_wait) {218vm_wait -= current_timeo;219current_timeo = *timeo_p;220if (current_timeo != MAX_SCHEDULE_TIMEOUT &&221(current_timeo -= vm_wait) < 0)222current_timeo = 0;223vm_wait = 0;224}225*timeo_p = current_timeo;226}227228finish_wait(sk->sk_sleep, &wait);229230sdp_dbg_data(sk, "Finished waiting - RdmaRdCompl: %d/%d bytes, flags: 0x%x\n",231tx_sa->bytes_acked, tx_sa->bytes_sent, tx_sa->abort_flags);232233if (!ssk->qp_active) {234sdp_dbg(sk, "QP destroyed while waiting\n");235return -EINVAL;236}237return err;238}239240static void sdp_wait_rdma_wr_finished(struct sdp_sock *ssk)241{242struct socket *sk = ssk->socket;243long timeo = HZ * 5; /* Timeout for RDMA read */244DEFINE_WAIT(wait);245246sdp_dbg_data(sk, "Sleep till RDMA wr finished.\n");247while (1) {248prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);249250if (!ssk->tx_ring.rdma_inflight->busy) {251sdp_dbg_data(sk, "got rdma cqe\n");252break;253}254255if (!ssk->qp_active) {256sdp_dbg_data(sk, "QP destroyed\n");257break;258}259260if (!timeo) {261sdp_warn(sk, "Panic: Timed out waiting for RDMA read\n");262WARN_ON(1);263break;264}265266posts_handler_put(ssk);267268sdp_prf1(sk, NULL, "Going to sleep");269sk_wait_event(sk, &timeo,270!ssk->tx_ring.rdma_inflight->busy);271sdp_prf1(sk, NULL, "Woke up");272sdp_dbg_data(ssk->socket, "woke up sleepers\n");273274posts_handler_get(ssk);275}276277finish_wait(sk->sk_sleep, &wait);278279sdp_dbg_data(sk, "Finished waiting\n");280}281282int sdp_post_rdma_rd_compl(struct sdp_sock *ssk,283struct rx_srcavail_state *rx_sa)284{285struct mbuf *mb;286int copied = rx_sa->used - rx_sa->reported;287288if (rx_sa->used <= rx_sa->reported)289return 0;290291mb = sdp_alloc_mb_rdmardcompl(ssk->socket, copied, 0);292293rx_sa->reported += copied;294295/* TODO: What if no tx_credits available? */296sdp_post_send(ssk, mb);297298return 0;299}300301int sdp_post_sendsm(struct socket *sk)302{303struct mbuf *mb = sdp_alloc_mb_sendsm(sk, 0);304305sdp_post_send(sdp_sk(sk), mb);306307return 0;308}309310static int sdp_update_iov_used(struct socket *sk, struct iovec *iov, int len)311{312sdp_dbg_data(sk, "updating consumed 0x%x bytes from iov\n", len);313while (len > 0) {314if (iov->iov_len) {315int copy = min_t(unsigned int, iov->iov_len, len);316len -= copy;317iov->iov_len -= copy;318iov->iov_base += copy;319}320iov++;321}322323return 0;324}325326static inline int sge_bytes(struct ib_sge *sge, int sge_cnt)327{328int bytes = 0;329330while (sge_cnt > 0) {331bytes += sge->length;332sge++;333sge_cnt--;334}335336return bytes;337}338void sdp_handle_sendsm(struct sdp_sock *ssk, u32 mseq_ack)339{340struct socket *sk = ssk->socket;341unsigned long flags;342343spin_lock_irqsave(&ssk->tx_sa_lock, flags);344345if (!ssk->tx_sa) {346sdp_prf1(sk, NULL, "SendSM for cancelled/finished SrcAvail");347goto out;348}349350if (ssk->tx_sa->mseq > mseq_ack) {351sdp_dbg_data(sk, "SendSM arrived for old SrcAvail. "352"SendSM mseq_ack: 0x%x, SrcAvail mseq: 0x%x\n",353mseq_ack, ssk->tx_sa->mseq);354goto out;355}356357sdp_dbg_data(sk, "Got SendSM - aborting SrcAvail\n");358359ssk->tx_sa->abort_flags |= TX_SA_SENDSM;360cancel_delayed_work(&ssk->srcavail_cancel_work);361362wake_up(sk->sk_sleep);363sdp_dbg_data(sk, "woke up sleepers\n");364365out:366spin_unlock_irqrestore(&ssk->tx_sa_lock, flags);367}368369void sdp_handle_rdma_read_compl(struct sdp_sock *ssk, u32 mseq_ack,370u32 bytes_completed)371{372struct socket *sk = ssk->socket;373unsigned long flags;374375sdp_prf1(sk, NULL, "RdmaRdCompl ssk=%p tx_sa=%p", ssk, ssk->tx_sa);376sdp_dbg_data(sk, "RdmaRdCompl ssk=%p tx_sa=%p\n", ssk, ssk->tx_sa);377378spin_lock_irqsave(&ssk->tx_sa_lock, flags);379380BUG_ON(!ssk);381382if (!ssk->tx_sa) {383sdp_dbg_data(sk, "Got RdmaRdCompl for aborted SrcAvail\n");384goto out;385}386387if (ssk->tx_sa->mseq > mseq_ack) {388sdp_dbg_data(sk, "RdmaRdCompl arrived for old SrcAvail. "389"SendSM mseq_ack: 0x%x, SrcAvail mseq: 0x%x\n",390mseq_ack, ssk->tx_sa->mseq);391goto out;392}393394ssk->tx_sa->bytes_acked += bytes_completed;395396wake_up(sk->sk_sleep);397sdp_dbg_data(sk, "woke up sleepers\n");398399out:400spin_unlock_irqrestore(&ssk->tx_sa_lock, flags);401return;402}403404static unsigned long sdp_get_max_memlockable_bytes(unsigned long offset)405{406unsigned long avail;407unsigned long lock_limit;408409if (capable(CAP_IPC_LOCK))410return ULONG_MAX;411412lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;413avail = lock_limit - (current->mm->locked_vm << PAGE_SHIFT);414415return avail - offset;416}417418static int sdp_alloc_fmr(struct socket *sk, void *uaddr, size_t len,419struct ib_pool_fmr **_fmr, struct ib_umem **_umem)420{421struct ib_pool_fmr *fmr;422struct ib_umem *umem;423struct ib_device *dev;424u64 *pages;425struct ib_umem_chunk *chunk;426int n, j, k;427int rc = 0;428unsigned long max_lockable_bytes;429430if (unlikely(len > SDP_MAX_RDMA_READ_LEN)) {431sdp_dbg_data(sk, "len:0x%lx > FMR_SIZE: 0x%lx\n",432len, SDP_MAX_RDMA_READ_LEN);433len = SDP_MAX_RDMA_READ_LEN;434}435436max_lockable_bytes = sdp_get_max_memlockable_bytes((unsigned long)uaddr & ~PAGE_MASK);437if (unlikely(len > max_lockable_bytes)) {438sdp_dbg_data(sk, "len:0x%lx > RLIMIT_MEMLOCK available: 0x%lx\n",439len, max_lockable_bytes);440len = max_lockable_bytes;441}442443sdp_dbg_data(sk, "user buf: %p, len:0x%lx max_lockable_bytes: 0x%lx\n",444uaddr, len, max_lockable_bytes);445446umem = ib_umem_get(&sdp_sk(sk)->context, (unsigned long)uaddr, len,447IB_ACCESS_REMOTE_WRITE, 0);448449if (IS_ERR(umem)) {450rc = PTR_ERR(umem);451sdp_warn(sk, "Error doing umem_get 0x%lx bytes: %d\n", len, rc);452sdp_warn(sk, "RLIMIT_MEMLOCK: 0x%lx[cur] 0x%lx[max] CAP_IPC_LOCK: %d\n",453current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur,454current->signal->rlim[RLIMIT_MEMLOCK].rlim_max,455capable(CAP_IPC_LOCK));456goto err_umem_get;457}458459sdp_dbg_data(sk, "umem->offset = 0x%x, length = 0x%lx\n",460umem->offset, umem->length);461462pages = (u64 *) __get_free_page(GFP_KERNEL);463if (!pages)464goto err_pages_alloc;465466n = 0;467468dev = sdp_sk(sk)->ib_device;469list_for_each_entry(chunk, &umem->chunk_list, list) {470for (j = 0; j < chunk->nmap; ++j) {471len = ib_sg_dma_len(dev,472&chunk->page_list[j]) >> PAGE_SHIFT;473474for (k = 0; k < len; ++k) {475pages[n++] = ib_sg_dma_address(dev,476&chunk->page_list[j]) +477umem->page_size * k;478479}480}481}482483fmr = ib_fmr_pool_map_phys(sdp_sk(sk)->sdp_dev->fmr_pool, pages, n, 0);484if (IS_ERR(fmr)) {485sdp_warn(sk, "Error allocating fmr: %ld\n", PTR_ERR(fmr));486goto err_fmr_alloc;487}488489free_page((unsigned long) pages);490491*_umem = umem;492*_fmr = fmr;493494return 0;495496err_fmr_alloc:497free_page((unsigned long) pages);498499err_pages_alloc:500ib_umem_release(umem);501502err_umem_get:503504return rc;505}506507void sdp_free_fmr(struct socket *sk, struct ib_pool_fmr **_fmr, struct ib_umem **_umem)508{509if (!sdp_sk(sk)->qp_active)510return;511512ib_fmr_pool_unmap(*_fmr);513*_fmr = NULL;514515ib_umem_release(*_umem);516*_umem = NULL;517}518519static int sdp_post_rdma_read(struct socket *sk, struct rx_srcavail_state *rx_sa)520{521struct sdp_sock *ssk = sdp_sk(sk);522struct ib_send_wr *bad_wr;523struct ib_send_wr wr = { NULL };524struct ib_sge sge;525526wr.opcode = IB_WR_RDMA_READ;527wr.next = NULL;528wr.wr_id = SDP_OP_RDMA;529wr.wr.rdma.rkey = rx_sa->rkey;530wr.send_flags = 0;531532ssk->tx_ring.rdma_inflight = rx_sa;533534sge.addr = rx_sa->umem->offset;535sge.length = rx_sa->umem->length;536sge.lkey = rx_sa->fmr->fmr->lkey;537538wr.wr.rdma.remote_addr = rx_sa->vaddr + rx_sa->used;539wr.num_sge = 1;540wr.sg_list = &sge;541rx_sa->busy++;542543wr.send_flags = IB_SEND_SIGNALED;544545return ib_post_send(ssk->qp, &wr, &bad_wr);546}547548int sdp_rdma_to_iovec(struct socket *sk, struct iovec *iov, struct mbuf *mb,549unsigned long *used)550{551struct sdp_sock *ssk = sdp_sk(sk);552struct rx_srcavail_state *rx_sa = RX_SRCAVAIL_STATE(mb);553int got_srcavail_cancel;554int rc = 0;555int len = *used;556int copied;557558sdp_dbg_data(ssk->socket, "preparing RDMA read."559" len: 0x%x. buffer len: 0x%lx\n", len, iov->iov_len);560561sock_hold(sk, SOCK_REF_RDMA_RD);562563if (len > rx_sa->len) {564sdp_warn(sk, "len:0x%x > rx_sa->len: 0x%x\n", len, rx_sa->len);565WARN_ON(1);566len = rx_sa->len;567}568569rc = sdp_alloc_fmr(sk, iov->iov_base, len, &rx_sa->fmr, &rx_sa->umem);570if (rc) {571sdp_warn(sk, "Error allocating fmr: %d\n", rc);572goto err_alloc_fmr;573}574575rc = sdp_post_rdma_read(sk, rx_sa);576if (unlikely(rc)) {577sdp_warn(sk, "ib_post_send failed with status %d.\n", rc);578sdp_set_error(ssk->socket, -ECONNRESET);579wake_up(&ssk->wq);580goto err_post_send;581}582583sdp_prf(sk, mb, "Finished posting(rc=%d), now to wait", rc);584585got_srcavail_cancel = ssk->srcavail_cancel_mseq > rx_sa->mseq;586587sdp_arm_tx_cq(sk);588589sdp_wait_rdma_wr_finished(ssk);590591sdp_prf(sk, mb, "Finished waiting(rc=%d)", rc);592if (!ssk->qp_active) {593sdp_dbg_data(sk, "QP destroyed during RDMA read\n");594rc = -EPIPE;595goto err_post_send;596}597598copied = rx_sa->umem->length;599600sdp_update_iov_used(sk, iov, copied);601rx_sa->used += copied;602atomic_add(copied, &ssk->rcv_nxt);603*used = copied;604605ssk->tx_ring.rdma_inflight = NULL;606607err_post_send:608sdp_free_fmr(sk, &rx_sa->fmr, &rx_sa->umem);609610err_alloc_fmr:611if (rc && ssk->qp_active) {612sdp_warn(sk, "Couldn't do RDMA - post sendsm\n");613rx_sa->flags |= RX_SA_ABORTED;614}615616sock_put(sk, SOCK_REF_RDMA_RD);617618return rc;619}620621static inline int wait_for_sndbuf(struct socket *sk, long *timeo_p)622{623struct sdp_sock *ssk = sdp_sk(sk);624int ret = 0;625int credits_needed = 1;626627sdp_dbg_data(sk, "Wait for mem\n");628629set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);630631SDPSTATS_COUNTER_INC(send_wait_for_mem);632633sdp_do_posts(ssk);634635sdp_xmit_poll(ssk, 1);636637ret = sdp_tx_wait_memory(ssk, timeo_p, &credits_needed);638639return ret;640}641642static int do_sdp_sendmsg_zcopy(struct socket *sk, struct tx_srcavail_state *tx_sa,643struct iovec *iov, long *timeo)644{645struct sdp_sock *ssk = sdp_sk(sk);646int rc = 0;647unsigned long lock_flags;648649rc = sdp_alloc_fmr(sk, iov->iov_base, iov->iov_len,650&tx_sa->fmr, &tx_sa->umem);651if (rc) {652sdp_warn(sk, "Error allocating fmr: %d\n", rc);653goto err_alloc_fmr;654}655656if (tx_slots_free(ssk) == 0) {657rc = wait_for_sndbuf(sk, timeo);658if (rc) {659sdp_warn(sk, "Couldn't get send buffer\n");660goto err_no_tx_slots;661}662}663664rc = sdp_post_srcavail(sk, tx_sa);665if (rc) {666sdp_dbg(sk, "Error posting SrcAvail\n");667goto err_abort_send;668}669670rc = sdp_wait_rdmardcompl(ssk, timeo, 0);671if (unlikely(rc)) {672enum tx_sa_flag f = tx_sa->abort_flags;673674if (f & TX_SA_SENDSM) {675sdp_dbg_data(sk, "Got SendSM. use SEND verb.\n");676} else if (f & TX_SA_ERROR) {677sdp_dbg_data(sk, "SrcAvail error completion\n");678sdp_reset(sk);679SDPSTATS_COUNTER_INC(zcopy_tx_error);680} else if (ssk->qp_active) {681sdp_post_srcavail_cancel(sk);682683/* Wait for RdmaRdCompl/SendSM to684* finish the transaction */685*timeo = 2 * HZ;686sdp_dbg_data(sk, "Waiting for SendSM\n");687sdp_wait_rdmardcompl(ssk, timeo, 1);688sdp_dbg_data(sk, "finished waiting\n");689690cancel_delayed_work(&ssk->srcavail_cancel_work);691} else {692sdp_dbg_data(sk, "QP was destroyed while waiting\n");693}694} else {695sdp_dbg_data(sk, "got RdmaRdCompl\n");696}697698spin_lock_irqsave(&ssk->tx_sa_lock, lock_flags);699ssk->tx_sa = NULL;700spin_unlock_irqrestore(&ssk->tx_sa_lock, lock_flags);701702err_abort_send:703sdp_update_iov_used(sk, iov, tx_sa->bytes_acked);704705err_no_tx_slots:706sdp_free_fmr(sk, &tx_sa->fmr, &tx_sa->umem);707708err_alloc_fmr:709return rc;710}711712int sdp_sendmsg_zcopy(struct kiocb *iocb, struct socket *sk, struct iovec *iov)713{714struct sdp_sock *ssk = sdp_sk(sk);715int rc = 0;716long timeo;717struct tx_srcavail_state *tx_sa;718int offset;719size_t bytes_to_copy = 0;720int copied = 0;721722sdp_dbg_data(sk, "Sending iov: %p, iov_len: 0x%lx\n",723iov->iov_base, iov->iov_len);724sdp_prf1(sk, NULL, "sdp_sendmsg_zcopy start");725if (ssk->rx_sa) {726sdp_dbg_data(sk, "Deadlock prevent: crossing SrcAvail\n");727return 0;728}729730sock_hold(ssk->socket, SOCK_REF_ZCOPY);731732SDPSTATS_COUNTER_INC(sendmsg_zcopy_segment);733734timeo = SDP_SRCAVAIL_ADV_TIMEOUT ;735736/* Ok commence sending. */737offset = (unsigned long)iov->iov_base & (PAGE_SIZE - 1);738739tx_sa = kmalloc(sizeof(struct tx_srcavail_state), GFP_KERNEL);740if (!tx_sa) {741sdp_warn(sk, "Error allocating zcopy context\n");742rc = -EAGAIN; /* Buffer too big - fallback to bcopy */743goto err_alloc_tx_sa;744}745746bytes_to_copy = iov->iov_len;747do {748tx_sa_reset(tx_sa);749750rc = do_sdp_sendmsg_zcopy(sk, tx_sa, iov, &timeo);751752if (iov->iov_len && iov->iov_len < sdp_zcopy_thresh) {753sdp_dbg_data(sk, "0x%lx bytes left, switching to bcopy\n",754iov->iov_len);755break;756}757} while (!rc && iov->iov_len > 0 && !tx_sa->abort_flags);758759kfree(tx_sa);760err_alloc_tx_sa:761copied = bytes_to_copy - iov->iov_len;762763sdp_prf1(sk, NULL, "sdp_sendmsg_zcopy end rc: %d copied: %d", rc, copied);764765sock_put(ssk->socket, SOCK_REF_ZCOPY);766767if (rc < 0 && rc != -EAGAIN && rc != -ETIME)768return rc;769770return copied;771}772773void sdp_abort_srcavail(struct socket *sk)774{775struct sdp_sock *ssk = sdp_sk(sk);776struct tx_srcavail_state *tx_sa = ssk->tx_sa;777unsigned long flags;778779if (!tx_sa)780return;781782cancel_delayed_work(&ssk->srcavail_cancel_work);783flush_scheduled_work();784785spin_lock_irqsave(&ssk->tx_sa_lock, flags);786787sdp_free_fmr(sk, &tx_sa->fmr, &tx_sa->umem);788789ssk->tx_sa = NULL;790791spin_unlock_irqrestore(&ssk->tx_sa_lock, flags);792}793794void sdp_abort_rdma_read(struct socket *sk)795{796struct sdp_sock *ssk = sdp_sk(sk);797struct rx_srcavail_state *rx_sa = ssk->rx_sa;798799if (!rx_sa)800return;801802sdp_free_fmr(sk, &rx_sa->fmr, &rx_sa->umem);803804ssk->rx_sa = NULL;805}806807808