LCOV - code coverage report
Current view: top level - net/sunrpc - socklib.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 91 0.0 %
Date: 2022-04-01 14:35:51 Functions: 0 4 0.0 %
Branches: 0 58 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * linux/net/sunrpc/socklib.c
       4                 :            :  *
       5                 :            :  * Common socket helper routines for RPC client and server
       6                 :            :  *
       7                 :            :  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/compiler.h>
      11                 :            : #include <linux/netdevice.h>
      12                 :            : #include <linux/gfp.h>
      13                 :            : #include <linux/skbuff.h>
      14                 :            : #include <linux/types.h>
      15                 :            : #include <linux/pagemap.h>
      16                 :            : #include <linux/udp.h>
      17                 :            : #include <linux/sunrpc/xdr.h>
      18                 :            : #include <linux/export.h>
      19                 :            : 
      20                 :            : 
      21                 :            : /**
      22                 :            :  * xdr_skb_read_bits - copy some data bits from skb to internal buffer
      23                 :            :  * @desc: sk_buff copy helper
      24                 :            :  * @to: copy destination
      25                 :            :  * @len: number of bytes to copy
      26                 :            :  *
      27                 :            :  * Possibly called several times to iterate over an sk_buff and copy
      28                 :            :  * data out of it.
      29                 :            :  */
      30                 :            : static size_t
      31                 :          0 : xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)
      32                 :            : {
      33                 :          0 :         if (len > desc->count)
      34                 :            :                 len = desc->count;
      35         [ #  # ]:          0 :         if (unlikely(skb_copy_bits(desc->skb, desc->offset, to, len)))
      36                 :            :                 return 0;
      37                 :          0 :         desc->count -= len;
      38                 :          0 :         desc->offset += len;
      39                 :          0 :         return len;
      40                 :            : }
      41                 :            : 
      42                 :            : /**
      43                 :            :  * xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer
      44                 :            :  * @desc: sk_buff copy helper
      45                 :            :  * @to: copy destination
      46                 :            :  * @len: number of bytes to copy
      47                 :            :  *
      48                 :            :  * Same as skb_read_bits, but calculate a checksum at the same time.
      49                 :            :  */
      50                 :          0 : static size_t xdr_skb_read_and_csum_bits(struct xdr_skb_reader *desc, void *to, size_t len)
      51                 :            : {
      52                 :          0 :         unsigned int pos;
      53                 :          0 :         __wsum csum2;
      54                 :            : 
      55                 :          0 :         if (len > desc->count)
      56                 :            :                 len = desc->count;
      57                 :          0 :         pos = desc->offset;
      58                 :          0 :         csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0);
      59         [ #  # ]:          0 :         desc->csum = csum_block_add(desc->csum, csum2, pos);
      60                 :          0 :         desc->count -= len;
      61                 :          0 :         desc->offset += len;
      62                 :          0 :         return len;
      63                 :            : }
      64                 :            : 
      65                 :            : /**
      66                 :            :  * xdr_partial_copy_from_skb - copy data out of an skb
      67                 :            :  * @xdr: target XDR buffer
      68                 :            :  * @base: starting offset
      69                 :            :  * @desc: sk_buff copy helper
      70                 :            :  * @copy_actor: virtual method for copying data
      71                 :            :  *
      72                 :            :  */
      73                 :            : static ssize_t
      74                 :          0 : xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct xdr_skb_reader *desc, xdr_skb_read_actor copy_actor)
      75                 :            : {
      76                 :          0 :         struct page     **ppage = xdr->pages;
      77                 :          0 :         unsigned int    len, pglen = xdr->page_len;
      78                 :          0 :         ssize_t         copied = 0;
      79                 :          0 :         size_t          ret;
      80                 :            : 
      81                 :          0 :         len = xdr->head[0].iov_len;
      82         [ #  # ]:          0 :         if (base < len) {
      83                 :          0 :                 len -= base;
      84                 :          0 :                 ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
      85                 :          0 :                 copied += ret;
      86   [ #  #  #  # ]:          0 :                 if (ret != len || !desc->count)
      87                 :          0 :                         goto out;
      88                 :            :                 base = 0;
      89                 :            :         } else
      90                 :          0 :                 base -= len;
      91                 :            : 
      92         [ #  # ]:          0 :         if (unlikely(pglen == 0))
      93                 :          0 :                 goto copy_tail;
      94         [ #  # ]:          0 :         if (unlikely(base >= pglen)) {
      95                 :          0 :                 base -= pglen;
      96                 :          0 :                 goto copy_tail;
      97                 :            :         }
      98   [ #  #  #  # ]:          0 :         if (base || xdr->page_base) {
      99                 :          0 :                 pglen -= base;
     100                 :          0 :                 base += xdr->page_base;
     101                 :          0 :                 ppage += base >> PAGE_SHIFT;
     102                 :          0 :                 base &= ~PAGE_MASK;
     103                 :            :         }
     104                 :          0 :         do {
     105                 :          0 :                 char *kaddr;
     106                 :            : 
     107                 :            :                 /* ACL likes to be lazy in allocating pages - ACLs
     108                 :            :                  * are small by default but can get huge. */
     109   [ #  #  #  # ]:          0 :                 if ((xdr->flags & XDRBUF_SPARSE_PAGES) && *ppage == NULL) {
     110                 :          0 :                         *ppage = alloc_page(GFP_NOWAIT | __GFP_NOWARN);
     111         [ #  # ]:          0 :                         if (unlikely(*ppage == NULL)) {
     112         [ #  # ]:          0 :                                 if (copied == 0)
     113                 :          0 :                                         copied = -ENOMEM;
     114                 :          0 :                                 goto out;
     115                 :            :                         }
     116                 :            :                 }
     117                 :            : 
     118                 :          0 :                 len = PAGE_SIZE;
     119                 :          0 :                 kaddr = kmap_atomic(*ppage);
     120         [ #  # ]:          0 :                 if (base) {
     121                 :          0 :                         len -= base;
     122                 :          0 :                         if (pglen < len)
     123                 :            :                                 len = pglen;
     124                 :          0 :                         ret = copy_actor(desc, kaddr + base, len);
     125                 :          0 :                         base = 0;
     126                 :            :                 } else {
     127         [ #  # ]:          0 :                         if (pglen < len)
     128                 :          0 :                                 len = pglen;
     129                 :          0 :                         ret = copy_actor(desc, kaddr, len);
     130                 :            :                 }
     131                 :          0 :                 flush_dcache_page(*ppage);
     132                 :          0 :                 kunmap_atomic(kaddr);
     133                 :          0 :                 copied += ret;
     134   [ #  #  #  # ]:          0 :                 if (ret != len || !desc->count)
     135                 :          0 :                         goto out;
     136                 :          0 :                 ppage++;
     137         [ #  # ]:          0 :         } while ((pglen -= len) != 0);
     138                 :          0 : copy_tail:
     139                 :          0 :         len = xdr->tail[0].iov_len;
     140         [ #  # ]:          0 :         if (base < len)
     141                 :          0 :                 copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base);
     142                 :          0 : out:
     143                 :          0 :         return copied;
     144                 :            : }
     145                 :            : 
     146                 :            : /**
     147                 :            :  * csum_partial_copy_to_xdr - checksum and copy data
     148                 :            :  * @xdr: target XDR buffer
     149                 :            :  * @skb: source skb
     150                 :            :  *
     151                 :            :  * We have set things up such that we perform the checksum of the UDP
     152                 :            :  * packet in parallel with the copies into the RPC client iovec.  -DaveM
     153                 :            :  */
     154                 :          0 : int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
     155                 :            : {
     156                 :          0 :         struct xdr_skb_reader   desc;
     157                 :            : 
     158                 :          0 :         desc.skb = skb;
     159                 :          0 :         desc.offset = 0;
     160                 :          0 :         desc.count = skb->len - desc.offset;
     161                 :            : 
     162         [ #  # ]:          0 :         if (skb_csum_unnecessary(skb))
     163                 :          0 :                 goto no_checksum;
     164                 :            : 
     165                 :          0 :         desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
     166         [ #  # ]:          0 :         if (xdr_partial_copy_from_skb(xdr, 0, &desc, xdr_skb_read_and_csum_bits) < 0)
     167                 :            :                 return -1;
     168         [ #  # ]:          0 :         if (desc.offset != skb->len) {
     169                 :          0 :                 __wsum csum2;
     170                 :          0 :                 csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
     171         [ #  # ]:          0 :                 desc.csum = csum_block_add(desc.csum, csum2, desc.offset);
     172                 :            :         }
     173         [ #  # ]:          0 :         if (desc.count)
     174                 :            :                 return -1;
     175         [ #  # ]:          0 :         if (csum_fold(desc.csum))
     176                 :            :                 return -1;
     177         [ #  # ]:          0 :         if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
     178         [ #  # ]:          0 :             !skb->csum_complete_sw)
     179                 :          0 :                 netdev_rx_csum_fault(skb->dev, skb);
     180                 :            :         return 0;
     181                 :            : no_checksum:
     182         [ #  # ]:          0 :         if (xdr_partial_copy_from_skb(xdr, 0, &desc, xdr_skb_read_bits) < 0)
     183                 :            :                 return -1;
     184         [ #  # ]:          0 :         if (desc.count)
     185                 :          0 :                 return -1;
     186                 :            :         return 0;
     187                 :            : }
     188                 :            : EXPORT_SYMBOL_GPL(csum_partial_copy_to_xdr);

Generated by: LCOV version 1.14