LCOV - code coverage report
Current view: top level - net/sunrpc - xdr.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 721 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 55 0.0 %
Branches: 0 406 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * linux/net/sunrpc/xdr.c
       4                 :            :  *
       5                 :            :  * Generic XDR support.
       6                 :            :  *
       7                 :            :  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/module.h>
      11                 :            : #include <linux/slab.h>
      12                 :            : #include <linux/types.h>
      13                 :            : #include <linux/string.h>
      14                 :            : #include <linux/kernel.h>
      15                 :            : #include <linux/pagemap.h>
      16                 :            : #include <linux/errno.h>
      17                 :            : #include <linux/sunrpc/xdr.h>
      18                 :            : #include <linux/sunrpc/msg_prot.h>
      19                 :            : #include <linux/bvec.h>
      20                 :            : #include <trace/events/sunrpc.h>
      21                 :            : 
      22                 :            : /*
      23                 :            :  * XDR functions for basic NFS types
      24                 :            :  */
      25                 :            : __be32 *
      26                 :          0 : xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
      27                 :            : {
      28                 :          0 :         unsigned int    quadlen = XDR_QUADLEN(obj->len);
      29                 :            : 
      30                 :          0 :         p[quadlen] = 0;         /* zero trailing bytes */
      31                 :          0 :         *p++ = cpu_to_be32(obj->len);
      32                 :          0 :         memcpy(p, obj->data, obj->len);
      33                 :          0 :         return p + XDR_QUADLEN(obj->len);
      34                 :            : }
      35                 :            : EXPORT_SYMBOL_GPL(xdr_encode_netobj);
      36                 :            : 
      37                 :            : __be32 *
      38                 :          0 : xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
      39                 :            : {
      40                 :            :         unsigned int    len;
      41                 :            : 
      42         [ #  # ]:          0 :         if ((len = be32_to_cpu(*p++)) > XDR_MAX_NETOBJ)
      43                 :            :                 return NULL;
      44                 :          0 :         obj->len  = len;
      45                 :          0 :         obj->data = (u8 *) p;
      46                 :          0 :         return p + XDR_QUADLEN(len);
      47                 :            : }
      48                 :            : EXPORT_SYMBOL_GPL(xdr_decode_netobj);
      49                 :            : 
      50                 :            : /**
      51                 :            :  * xdr_encode_opaque_fixed - Encode fixed length opaque data
      52                 :            :  * @p: pointer to current position in XDR buffer.
      53                 :            :  * @ptr: pointer to data to encode (or NULL)
      54                 :            :  * @nbytes: size of data.
      55                 :            :  *
      56                 :            :  * Copy the array of data of length nbytes at ptr to the XDR buffer
      57                 :            :  * at position p, then align to the next 32-bit boundary by padding
      58                 :            :  * with zero bytes (see RFC1832).
      59                 :            :  * Note: if ptr is NULL, only the padding is performed.
      60                 :            :  *
      61                 :            :  * Returns the updated current XDR buffer position
      62                 :            :  *
      63                 :            :  */
      64                 :          0 : __be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes)
      65                 :            : {
      66         [ #  # ]:          0 :         if (likely(nbytes != 0)) {
      67                 :          0 :                 unsigned int quadlen = XDR_QUADLEN(nbytes);
      68                 :          0 :                 unsigned int padding = (quadlen << 2) - nbytes;
      69                 :            : 
      70         [ #  # ]:          0 :                 if (ptr != NULL)
      71                 :          0 :                         memcpy(p, ptr, nbytes);
      72         [ #  # ]:          0 :                 if (padding != 0)
      73                 :          0 :                         memset((char *)p + nbytes, 0, padding);
      74                 :          0 :                 p += quadlen;
      75                 :            :         }
      76                 :          0 :         return p;
      77                 :            : }
      78                 :            : EXPORT_SYMBOL_GPL(xdr_encode_opaque_fixed);
      79                 :            : 
      80                 :            : /**
      81                 :            :  * xdr_encode_opaque - Encode variable length opaque data
      82                 :            :  * @p: pointer to current position in XDR buffer.
      83                 :            :  * @ptr: pointer to data to encode (or NULL)
      84                 :            :  * @nbytes: size of data.
      85                 :            :  *
      86                 :            :  * Returns the updated current XDR buffer position
      87                 :            :  */
      88                 :          0 : __be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes)
      89                 :            : {
      90                 :          0 :         *p++ = cpu_to_be32(nbytes);
      91                 :          0 :         return xdr_encode_opaque_fixed(p, ptr, nbytes);
      92                 :            : }
      93                 :            : EXPORT_SYMBOL_GPL(xdr_encode_opaque);
      94                 :            : 
      95                 :            : __be32 *
      96                 :          0 : xdr_encode_string(__be32 *p, const char *string)
      97                 :            : {
      98                 :          0 :         return xdr_encode_array(p, string, strlen(string));
      99                 :            : }
     100                 :            : EXPORT_SYMBOL_GPL(xdr_encode_string);
     101                 :            : 
     102                 :            : __be32 *
     103                 :          0 : xdr_decode_string_inplace(__be32 *p, char **sp,
     104                 :            :                           unsigned int *lenp, unsigned int maxlen)
     105                 :            : {
     106                 :            :         u32 len;
     107                 :            : 
     108                 :          0 :         len = be32_to_cpu(*p++);
     109         [ #  # ]:          0 :         if (len > maxlen)
     110                 :            :                 return NULL;
     111                 :          0 :         *lenp = len;
     112                 :          0 :         *sp = (char *) p;
     113                 :          0 :         return p + XDR_QUADLEN(len);
     114                 :            : }
     115                 :            : EXPORT_SYMBOL_GPL(xdr_decode_string_inplace);
     116                 :            : 
     117                 :            : /**
     118                 :            :  * xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf
     119                 :            :  * @buf: XDR buffer where string resides
     120                 :            :  * @len: length of string, in bytes
     121                 :            :  *
     122                 :            :  */
     123                 :            : void
     124                 :          0 : xdr_terminate_string(struct xdr_buf *buf, const u32 len)
     125                 :            : {
     126                 :            :         char *kaddr;
     127                 :            : 
     128                 :          0 :         kaddr = kmap_atomic(buf->pages[0]);
     129                 :          0 :         kaddr[buf->page_base + len] = '\0';
     130                 :            :         kunmap_atomic(kaddr);
     131                 :          0 : }
     132                 :            : EXPORT_SYMBOL_GPL(xdr_terminate_string);
     133                 :            : 
     134                 :            : size_t
     135                 :          0 : xdr_buf_pagecount(struct xdr_buf *buf)
     136                 :            : {
     137   [ #  #  #  # ]:          0 :         if (!buf->page_len)
     138                 :            :                 return 0;
     139                 :          0 :         return (buf->page_base + buf->page_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
     140                 :            : }
     141                 :            : 
     142                 :            : int
     143                 :          0 : xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp)
     144                 :            : {
     145                 :            :         size_t i, n = xdr_buf_pagecount(buf);
     146                 :            : 
     147   [ #  #  #  # ]:          0 :         if (n != 0 && buf->bvec == NULL) {
     148                 :          0 :                 buf->bvec = kmalloc_array(n, sizeof(buf->bvec[0]), gfp);
     149         [ #  # ]:          0 :                 if (!buf->bvec)
     150                 :            :                         return -ENOMEM;
     151         [ #  # ]:          0 :                 for (i = 0; i < n; i++) {
     152                 :          0 :                         buf->bvec[i].bv_page = buf->pages[i];
     153                 :          0 :                         buf->bvec[i].bv_len = PAGE_SIZE;
     154                 :          0 :                         buf->bvec[i].bv_offset = 0;
     155                 :            :                 }
     156                 :            :         }
     157                 :            :         return 0;
     158                 :            : }
     159                 :            : 
     160                 :            : void
     161                 :          0 : xdr_free_bvec(struct xdr_buf *buf)
     162                 :            : {
     163                 :          0 :         kfree(buf->bvec);
     164                 :          0 :         buf->bvec = NULL;
     165                 :          0 : }
     166                 :            : 
     167                 :            : /**
     168                 :            :  * xdr_inline_pages - Prepare receive buffer for a large reply
     169                 :            :  * @xdr: xdr_buf into which reply will be placed
     170                 :            :  * @offset: expected offset where data payload will start, in bytes
     171                 :            :  * @pages: vector of struct page pointers
     172                 :            :  * @base: offset in first page where receive should start, in bytes
     173                 :            :  * @len: expected size of the upper layer data payload, in bytes
     174                 :            :  *
     175                 :            :  */
     176                 :            : void
     177                 :          0 : xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
     178                 :            :                  struct page **pages, unsigned int base, unsigned int len)
     179                 :            : {
     180                 :            :         struct kvec *head = xdr->head;
     181                 :            :         struct kvec *tail = xdr->tail;
     182                 :          0 :         char *buf = (char *)head->iov_base;
     183                 :          0 :         unsigned int buflen = head->iov_len;
     184                 :            : 
     185                 :          0 :         head->iov_len  = offset;
     186                 :            : 
     187                 :          0 :         xdr->pages = pages;
     188                 :          0 :         xdr->page_base = base;
     189                 :          0 :         xdr->page_len = len;
     190                 :            : 
     191                 :          0 :         tail->iov_base = buf + offset;
     192                 :          0 :         tail->iov_len = buflen - offset;
     193         [ #  # ]:          0 :         if ((xdr->page_len & 3) == 0)
     194                 :          0 :                 tail->iov_len -= sizeof(__be32);
     195                 :            : 
     196                 :          0 :         xdr->buflen += len;
     197                 :          0 : }
     198                 :            : EXPORT_SYMBOL_GPL(xdr_inline_pages);
     199                 :            : 
     200                 :            : /*
     201                 :            :  * Helper routines for doing 'memmove' like operations on a struct xdr_buf
     202                 :            :  */
     203                 :            : 
     204                 :            : /**
     205                 :            :  * _shift_data_right_pages
     206                 :            :  * @pages: vector of pages containing both the source and dest memory area.
     207                 :            :  * @pgto_base: page vector address of destination
     208                 :            :  * @pgfrom_base: page vector address of source
     209                 :            :  * @len: number of bytes to copy
     210                 :            :  *
     211                 :            :  * Note: the addresses pgto_base and pgfrom_base are both calculated in
     212                 :            :  *       the same way:
     213                 :            :  *            if a memory area starts at byte 'base' in page 'pages[i]',
     214                 :            :  *            then its address is given as (i << PAGE_SHIFT) + base
     215                 :            :  * Also note: pgfrom_base must be < pgto_base, but the memory areas
     216                 :            :  *      they point to may overlap.
     217                 :            :  */
     218                 :            : static void
     219                 :          0 : _shift_data_right_pages(struct page **pages, size_t pgto_base,
     220                 :            :                 size_t pgfrom_base, size_t len)
     221                 :            : {
     222                 :            :         struct page **pgfrom, **pgto;
     223                 :            :         char *vfrom, *vto;
     224                 :            :         size_t copy;
     225                 :            : 
     226         [ #  # ]:          0 :         BUG_ON(pgto_base <= pgfrom_base);
     227                 :            : 
     228                 :          0 :         pgto_base += len;
     229                 :          0 :         pgfrom_base += len;
     230                 :            : 
     231                 :          0 :         pgto = pages + (pgto_base >> PAGE_SHIFT);
     232                 :          0 :         pgfrom = pages + (pgfrom_base >> PAGE_SHIFT);
     233                 :            : 
     234                 :          0 :         pgto_base &= ~PAGE_MASK;
     235                 :          0 :         pgfrom_base &= ~PAGE_MASK;
     236                 :            : 
     237                 :            :         do {
     238                 :            :                 /* Are any pointers crossing a page boundary? */
     239         [ #  # ]:          0 :                 if (pgto_base == 0) {
     240                 :            :                         pgto_base = PAGE_SIZE;
     241                 :          0 :                         pgto--;
     242                 :            :                 }
     243         [ #  # ]:          0 :                 if (pgfrom_base == 0) {
     244                 :            :                         pgfrom_base = PAGE_SIZE;
     245                 :          0 :                         pgfrom--;
     246                 :            :                 }
     247                 :            : 
     248                 :            :                 copy = len;
     249         [ #  # ]:          0 :                 if (copy > pgto_base)
     250                 :            :                         copy = pgto_base;
     251         [ #  # ]:          0 :                 if (copy > pgfrom_base)
     252                 :            :                         copy = pgfrom_base;
     253                 :          0 :                 pgto_base -= copy;
     254                 :          0 :                 pgfrom_base -= copy;
     255                 :            : 
     256                 :          0 :                 vto = kmap_atomic(*pgto);
     257         [ #  # ]:          0 :                 if (*pgto != *pgfrom) {
     258                 :          0 :                         vfrom = kmap_atomic(*pgfrom);
     259                 :          0 :                         memcpy(vto + pgto_base, vfrom + pgfrom_base, copy);
     260                 :            :                         kunmap_atomic(vfrom);
     261                 :            :                 } else
     262                 :          0 :                         memmove(vto + pgto_base, vto + pgfrom_base, copy);
     263                 :          0 :                 flush_dcache_page(*pgto);
     264                 :            :                 kunmap_atomic(vto);
     265                 :            : 
     266         [ #  # ]:          0 :         } while ((len -= copy) != 0);
     267                 :          0 : }
     268                 :            : 
     269                 :            : /**
     270                 :            :  * _copy_to_pages
     271                 :            :  * @pages: array of pages
     272                 :            :  * @pgbase: page vector address of destination
     273                 :            :  * @p: pointer to source data
     274                 :            :  * @len: length
     275                 :            :  *
     276                 :            :  * Copies data from an arbitrary memory location into an array of pages
     277                 :            :  * The copy is assumed to be non-overlapping.
     278                 :            :  */
     279                 :            : static void
     280                 :          0 : _copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len)
     281                 :            : {
     282                 :            :         struct page **pgto;
     283                 :            :         char *vto;
     284                 :            :         size_t copy;
     285                 :            : 
     286                 :          0 :         pgto = pages + (pgbase >> PAGE_SHIFT);
     287                 :          0 :         pgbase &= ~PAGE_MASK;
     288                 :            : 
     289                 :            :         for (;;) {
     290                 :          0 :                 copy = PAGE_SIZE - pgbase;
     291         [ #  # ]:          0 :                 if (copy > len)
     292                 :            :                         copy = len;
     293                 :            : 
     294                 :          0 :                 vto = kmap_atomic(*pgto);
     295                 :          0 :                 memcpy(vto + pgbase, p, copy);
     296                 :            :                 kunmap_atomic(vto);
     297                 :            : 
     298                 :          0 :                 len -= copy;
     299         [ #  # ]:          0 :                 if (len == 0)
     300                 :            :                         break;
     301                 :            : 
     302                 :          0 :                 pgbase += copy;
     303         [ #  # ]:          0 :                 if (pgbase == PAGE_SIZE) {
     304                 :          0 :                         flush_dcache_page(*pgto);
     305                 :            :                         pgbase = 0;
     306                 :          0 :                         pgto++;
     307                 :            :                 }
     308                 :          0 :                 p += copy;
     309                 :          0 :         }
     310                 :          0 :         flush_dcache_page(*pgto);
     311                 :          0 : }
     312                 :            : 
     313                 :            : /**
     314                 :            :  * _copy_from_pages
     315                 :            :  * @p: pointer to destination
     316                 :            :  * @pages: array of pages
     317                 :            :  * @pgbase: offset of source data
     318                 :            :  * @len: length
     319                 :            :  *
     320                 :            :  * Copies data into an arbitrary memory location from an array of pages
     321                 :            :  * The copy is assumed to be non-overlapping.
     322                 :            :  */
     323                 :            : void
     324                 :          0 : _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
     325                 :            : {
     326                 :            :         struct page **pgfrom;
     327                 :            :         char *vfrom;
     328                 :            :         size_t copy;
     329                 :            : 
     330                 :          0 :         pgfrom = pages + (pgbase >> PAGE_SHIFT);
     331                 :          0 :         pgbase &= ~PAGE_MASK;
     332                 :            : 
     333                 :            :         do {
     334                 :          0 :                 copy = PAGE_SIZE - pgbase;
     335         [ #  # ]:          0 :                 if (copy > len)
     336                 :            :                         copy = len;
     337                 :            : 
     338                 :          0 :                 vfrom = kmap_atomic(*pgfrom);
     339                 :          0 :                 memcpy(p, vfrom + pgbase, copy);
     340                 :            :                 kunmap_atomic(vfrom);
     341                 :            : 
     342                 :          0 :                 pgbase += copy;
     343         [ #  # ]:          0 :                 if (pgbase == PAGE_SIZE) {
     344                 :            :                         pgbase = 0;
     345                 :          0 :                         pgfrom++;
     346                 :            :                 }
     347                 :          0 :                 p += copy;
     348                 :            : 
     349         [ #  # ]:          0 :         } while ((len -= copy) != 0);
     350                 :          0 : }
     351                 :            : EXPORT_SYMBOL_GPL(_copy_from_pages);
     352                 :            : 
     353                 :            : /**
     354                 :            :  * xdr_shrink_bufhead
     355                 :            :  * @buf: xdr_buf
     356                 :            :  * @len: bytes to remove from buf->head[0]
     357                 :            :  *
     358                 :            :  * Shrinks XDR buffer's header kvec buf->head[0] by
     359                 :            :  * 'len' bytes. The extra data is not lost, but is instead
     360                 :            :  * moved into the inlined pages and/or the tail.
     361                 :            :  */
     362                 :            : static unsigned int
     363                 :          0 : xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
     364                 :            : {
     365                 :            :         struct kvec *head, *tail;
     366                 :            :         size_t copy, offs;
     367                 :          0 :         unsigned int pglen = buf->page_len;
     368                 :            :         unsigned int result;
     369                 :            : 
     370                 :            :         result = 0;
     371                 :            :         tail = buf->tail;
     372                 :            :         head = buf->head;
     373                 :            : 
     374   [ #  #  #  # ]:          0 :         WARN_ON_ONCE(len > head->iov_len);
     375         [ #  # ]:          0 :         if (len > head->iov_len)
     376                 :            :                 len = head->iov_len;
     377                 :            : 
     378                 :            :         /* Shift the tail first */
     379         [ #  # ]:          0 :         if (tail->iov_len != 0) {
     380         [ #  # ]:          0 :                 if (tail->iov_len > len) {
     381                 :          0 :                         copy = tail->iov_len - len;
     382                 :          0 :                         memmove((char *)tail->iov_base + len,
     383                 :            :                                         tail->iov_base, copy);
     384                 :            :                         result += copy;
     385                 :            :                 }
     386                 :            :                 /* Copy from the inlined pages into the tail */
     387                 :            :                 copy = len;
     388         [ #  # ]:          0 :                 if (copy > pglen)
     389                 :            :                         copy = pglen;
     390                 :          0 :                 offs = len - copy;
     391         [ #  # ]:          0 :                 if (offs >= tail->iov_len)
     392                 :            :                         copy = 0;
     393         [ #  # ]:          0 :                 else if (copy > tail->iov_len - offs)
     394                 :            :                         copy = tail->iov_len - offs;
     395         [ #  # ]:          0 :                 if (copy != 0) {
     396                 :          0 :                         _copy_from_pages((char *)tail->iov_base + offs,
     397                 :            :                                         buf->pages,
     398                 :          0 :                                         buf->page_base + pglen + offs - len,
     399                 :            :                                         copy);
     400                 :          0 :                         result += copy;
     401                 :            :                 }
     402                 :            :                 /* Do we also need to copy data from the head into the tail ? */
     403         [ #  # ]:          0 :                 if (len > pglen) {
     404                 :          0 :                         offs = copy = len - pglen;
     405         [ #  # ]:          0 :                         if (copy > tail->iov_len)
     406                 :            :                                 copy = tail->iov_len;
     407                 :          0 :                         memcpy(tail->iov_base,
     408                 :          0 :                                         (char *)head->iov_base +
     409                 :          0 :                                         head->iov_len - offs,
     410                 :            :                                         copy);
     411                 :          0 :                         result += copy;
     412                 :            :                 }
     413                 :            :         }
     414                 :            :         /* Now handle pages */
     415         [ #  # ]:          0 :         if (pglen != 0) {
     416         [ #  # ]:          0 :                 if (pglen > len)
     417                 :          0 :                         _shift_data_right_pages(buf->pages,
     418                 :          0 :                                         buf->page_base + len,
     419                 :            :                                         buf->page_base,
     420                 :            :                                         pglen - len);
     421                 :            :                 copy = len;
     422         [ #  # ]:          0 :                 if (len > pglen)
     423                 :            :                         copy = pglen;
     424                 :          0 :                 _copy_to_pages(buf->pages, buf->page_base,
     425                 :          0 :                                 (char *)head->iov_base + head->iov_len - len,
     426                 :            :                                 copy);
     427                 :          0 :                 result += copy;
     428                 :            :         }
     429                 :          0 :         head->iov_len -= len;
     430                 :          0 :         buf->buflen -= len;
     431                 :            :         /* Have we truncated the message? */
     432         [ #  # ]:          0 :         if (buf->len > buf->buflen)
     433                 :          0 :                 buf->len = buf->buflen;
     434                 :            : 
     435                 :          0 :         return result;
     436                 :            : }
     437                 :            : 
     438                 :            : /**
     439                 :            :  * xdr_shrink_pagelen - shrinks buf->pages by up to @len bytes
     440                 :            :  * @buf: xdr_buf
     441                 :            :  * @len: bytes to remove from buf->pages
     442                 :            :  *
     443                 :            :  * The extra data is not lost, but is instead moved into buf->tail.
     444                 :            :  * Returns the actual number of bytes moved.
     445                 :            :  */
     446                 :            : static unsigned int
     447                 :          0 : xdr_shrink_pagelen(struct xdr_buf *buf, size_t len)
     448                 :            : {
     449                 :            :         struct kvec *tail;
     450                 :            :         size_t copy;
     451                 :          0 :         unsigned int pglen = buf->page_len;
     452                 :            :         unsigned int tailbuf_len;
     453                 :            :         unsigned int result;
     454                 :            : 
     455                 :            :         result = 0;
     456                 :            :         tail = buf->tail;
     457         [ #  # ]:          0 :         if (len > buf->page_len)
     458                 :            :                 len = buf-> page_len;
     459                 :          0 :         tailbuf_len = buf->buflen - buf->head->iov_len - buf->page_len;
     460                 :            : 
     461                 :            :         /* Shift the tail first */
     462         [ #  # ]:          0 :         if (tailbuf_len != 0) {
     463                 :          0 :                 unsigned int free_space = tailbuf_len - tail->iov_len;
     464                 :            : 
     465         [ #  # ]:          0 :                 if (len < free_space)
     466                 :            :                         free_space = len;
     467                 :          0 :                 tail->iov_len += free_space;
     468                 :            : 
     469                 :            :                 copy = len;
     470         [ #  # ]:          0 :                 if (tail->iov_len > len) {
     471                 :          0 :                         char *p = (char *)tail->iov_base + len;
     472                 :          0 :                         memmove(p, tail->iov_base, tail->iov_len - len);
     473                 :          0 :                         result += tail->iov_len - len;
     474                 :            :                 } else
     475                 :            :                         copy = tail->iov_len;
     476                 :            :                 /* Copy from the inlined pages into the tail */
     477                 :          0 :                 _copy_from_pages((char *)tail->iov_base,
     478                 :          0 :                                 buf->pages, buf->page_base + pglen - len,
     479                 :            :                                 copy);
     480                 :          0 :                 result += copy;
     481                 :            :         }
     482                 :          0 :         buf->page_len -= len;
     483                 :          0 :         buf->buflen -= len;
     484                 :            :         /* Have we truncated the message? */
     485         [ #  # ]:          0 :         if (buf->len > buf->buflen)
     486                 :          0 :                 buf->len = buf->buflen;
     487                 :            : 
     488                 :          0 :         return result;
     489                 :            : }
     490                 :            : 
     491                 :            : void
     492                 :          0 : xdr_shift_buf(struct xdr_buf *buf, size_t len)
     493                 :            : {
     494                 :          0 :         xdr_shrink_bufhead(buf, len);
     495                 :          0 : }
     496                 :            : EXPORT_SYMBOL_GPL(xdr_shift_buf);
     497                 :            : 
     498                 :            : /**
     499                 :            :  * xdr_stream_pos - Return the current offset from the start of the xdr_stream
     500                 :            :  * @xdr: pointer to struct xdr_stream
     501                 :            :  */
     502                 :          0 : unsigned int xdr_stream_pos(const struct xdr_stream *xdr)
     503                 :            : {
     504                 :          0 :         return (unsigned int)(XDR_QUADLEN(xdr->buf->len) - xdr->nwords) << 2;
     505                 :            : }
     506                 :            : EXPORT_SYMBOL_GPL(xdr_stream_pos);
     507                 :            : 
     508                 :            : /**
     509                 :            :  * xdr_init_encode - Initialize a struct xdr_stream for sending data.
     510                 :            :  * @xdr: pointer to xdr_stream struct
     511                 :            :  * @buf: pointer to XDR buffer in which to encode data
     512                 :            :  * @p: current pointer inside XDR buffer
     513                 :            :  * @rqst: pointer to controlling rpc_rqst, for debugging
     514                 :            :  *
     515                 :            :  * Note: at the moment the RPC client only passes the length of our
     516                 :            :  *       scratch buffer in the xdr_buf's header kvec. Previously this
     517                 :            :  *       meant we needed to call xdr_adjust_iovec() after encoding the
     518                 :            :  *       data. With the new scheme, the xdr_stream manages the details
     519                 :            :  *       of the buffer length, and takes care of adjusting the kvec
     520                 :            :  *       length for us.
     521                 :            :  */
     522                 :          0 : void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
     523                 :            :                      struct rpc_rqst *rqst)
     524                 :            : {
     525                 :          0 :         struct kvec *iov = buf->head;
     526                 :          0 :         int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
     527                 :            : 
     528                 :            :         xdr_set_scratch_buffer(xdr, NULL, 0);
     529         [ #  # ]:          0 :         BUG_ON(scratch_len < 0);
     530                 :          0 :         xdr->buf = buf;
     531                 :          0 :         xdr->iov = iov;
     532                 :          0 :         xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);
     533                 :          0 :         xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);
     534         [ #  # ]:          0 :         BUG_ON(iov->iov_len > scratch_len);
     535                 :            : 
     536   [ #  #  #  # ]:          0 :         if (p != xdr->p && p != NULL) {
     537                 :            :                 size_t len;
     538                 :            : 
     539   [ #  #  #  # ]:          0 :                 BUG_ON(p < xdr->p || p > xdr->end);
     540                 :          0 :                 len = (char *)p - (char *)xdr->p;
     541                 :          0 :                 xdr->p = p;
     542                 :          0 :                 buf->len += len;
     543                 :          0 :                 iov->iov_len += len;
     544                 :            :         }
     545                 :          0 :         xdr->rqst = rqst;
     546                 :          0 : }
     547                 :            : EXPORT_SYMBOL_GPL(xdr_init_encode);
     548                 :            : 
     549                 :            : /**
     550                 :            :  * xdr_commit_encode - Ensure all data is written to buffer
     551                 :            :  * @xdr: pointer to xdr_stream
     552                 :            :  *
     553                 :            :  * We handle encoding across page boundaries by giving the caller a
     554                 :            :  * temporary location to write to, then later copying the data into
     555                 :            :  * place; xdr_commit_encode does that copying.
     556                 :            :  *
     557                 :            :  * Normally the caller doesn't need to call this directly, as the
     558                 :            :  * following xdr_reserve_space will do it.  But an explicit call may be
     559                 :            :  * required at the end of encoding, or any other time when the xdr_buf
     560                 :            :  * data might be read.
     561                 :            :  */
     562                 :          0 : inline void xdr_commit_encode(struct xdr_stream *xdr)
     563                 :            : {
     564                 :          0 :         int shift = xdr->scratch.iov_len;
     565                 :            :         void *page;
     566                 :            : 
     567         [ #  # ]:          0 :         if (shift == 0)
     568                 :          0 :                 return;
     569                 :          0 :         page = page_address(*xdr->page_ptr);
     570                 :          0 :         memcpy(xdr->scratch.iov_base, page, shift);
     571                 :          0 :         memmove(page, page + shift, (void *)xdr->p - page);
     572                 :          0 :         xdr->scratch.iov_len = 0;
     573                 :            : }
     574                 :            : EXPORT_SYMBOL_GPL(xdr_commit_encode);
     575                 :            : 
     576                 :          0 : static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
     577                 :            :                 size_t nbytes)
     578                 :            : {
     579                 :            :         __be32 *p;
     580                 :            :         int space_left;
     581                 :            :         int frag1bytes, frag2bytes;
     582                 :            : 
     583         [ #  # ]:          0 :         if (nbytes > PAGE_SIZE)
     584                 :            :                 goto out_overflow; /* Bigger buffers require special handling */
     585         [ #  # ]:          0 :         if (xdr->buf->len + nbytes > xdr->buf->buflen)
     586                 :            :                 goto out_overflow; /* Sorry, we're totally out of space */
     587                 :          0 :         frag1bytes = (xdr->end - xdr->p) << 2;
     588                 :          0 :         frag2bytes = nbytes - frag1bytes;
     589         [ #  # ]:          0 :         if (xdr->iov)
     590                 :          0 :                 xdr->iov->iov_len += frag1bytes;
     591                 :            :         else
     592                 :          0 :                 xdr->buf->page_len += frag1bytes;
     593                 :          0 :         xdr->page_ptr++;
     594                 :          0 :         xdr->iov = NULL;
     595                 :            :         /*
     596                 :            :          * If the last encode didn't end exactly on a page boundary, the
     597                 :            :          * next one will straddle boundaries.  Encode into the next
     598                 :            :          * page, then copy it back later in xdr_commit_encode.  We use
     599                 :            :          * the "scratch" iov to track any temporarily unused fragment of
     600                 :            :          * space at the end of the previous buffer:
     601                 :            :          */
     602                 :          0 :         xdr->scratch.iov_base = xdr->p;
     603                 :          0 :         xdr->scratch.iov_len = frag1bytes;
     604                 :          0 :         p = page_address(*xdr->page_ptr);
     605                 :            :         /*
     606                 :            :          * Note this is where the next encode will start after we've
     607                 :            :          * shifted this one back:
     608                 :            :          */
     609                 :          0 :         xdr->p = (void *)p + frag2bytes;
     610                 :          0 :         space_left = xdr->buf->buflen - xdr->buf->len;
     611                 :          0 :         xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
     612                 :          0 :         xdr->buf->page_len += frag2bytes;
     613                 :          0 :         xdr->buf->len += nbytes;
     614                 :          0 :         return p;
     615                 :            : out_overflow:
     616                 :          0 :         trace_rpc_xdr_overflow(xdr, nbytes);
     617                 :          0 :         return NULL;
     618                 :            : }
     619                 :            : 
     620                 :            : /**
     621                 :            :  * xdr_reserve_space - Reserve buffer space for sending
     622                 :            :  * @xdr: pointer to xdr_stream
     623                 :            :  * @nbytes: number of bytes to reserve
     624                 :            :  *
     625                 :            :  * Checks that we have enough buffer space to encode 'nbytes' more
     626                 :            :  * bytes of data. If so, update the total xdr_buf length, and
     627                 :            :  * adjust the length of the current kvec.
     628                 :            :  */
     629                 :          0 : __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
     630                 :            : {
     631                 :          0 :         __be32 *p = xdr->p;
     632                 :            :         __be32 *q;
     633                 :            : 
     634                 :          0 :         xdr_commit_encode(xdr);
     635                 :            :         /* align nbytes on the next 32-bit boundary */
     636                 :          0 :         nbytes += 3;
     637                 :          0 :         nbytes &= ~3;
     638                 :          0 :         q = p + (nbytes >> 2);
     639   [ #  #  #  # ]:          0 :         if (unlikely(q > xdr->end || q < p))
     640                 :          0 :                 return xdr_get_next_encode_buffer(xdr, nbytes);
     641                 :          0 :         xdr->p = q;
     642         [ #  # ]:          0 :         if (xdr->iov)
     643                 :          0 :                 xdr->iov->iov_len += nbytes;
     644                 :            :         else
     645                 :          0 :                 xdr->buf->page_len += nbytes;
     646                 :          0 :         xdr->buf->len += nbytes;
     647                 :          0 :         return p;
     648                 :            : }
     649                 :            : EXPORT_SYMBOL_GPL(xdr_reserve_space);
     650                 :            : 
     651                 :            : /**
     652                 :            :  * xdr_truncate_encode - truncate an encode buffer
     653                 :            :  * @xdr: pointer to xdr_stream
     654                 :            :  * @len: new length of buffer
     655                 :            :  *
     656                 :            :  * Truncates the xdr stream, so that xdr->buf->len == len,
     657                 :            :  * and xdr->p points at offset len from the start of the buffer, and
     658                 :            :  * head, tail, and page lengths are adjusted to correspond.
     659                 :            :  *
     660                 :            :  * If this means moving xdr->p to a different buffer, we assume that
     661                 :            :  * that the end pointer should be set to the end of the current page,
     662                 :            :  * except in the case of the head buffer when we assume the head
     663                 :            :  * buffer's current length represents the end of the available buffer.
     664                 :            :  *
     665                 :            :  * This is *not* safe to use on a buffer that already has inlined page
     666                 :            :  * cache pages (as in a zero-copy server read reply), except for the
     667                 :            :  * simple case of truncating from one position in the tail to another.
     668                 :            :  *
     669                 :            :  */
     670                 :          0 : void xdr_truncate_encode(struct xdr_stream *xdr, size_t len)
     671                 :            : {
     672                 :          0 :         struct xdr_buf *buf = xdr->buf;
     673                 :            :         struct kvec *head = buf->head;
     674                 :            :         struct kvec *tail = buf->tail;
     675                 :            :         int fraglen;
     676                 :            :         int new;
     677                 :            : 
     678         [ #  # ]:          0 :         if (len > buf->len) {
     679         [ #  # ]:          0 :                 WARN_ON_ONCE(1);
     680                 :            :                 return;
     681                 :            :         }
     682                 :          0 :         xdr_commit_encode(xdr);
     683                 :            : 
     684                 :          0 :         fraglen = min_t(int, buf->len - len, tail->iov_len);
     685                 :          0 :         tail->iov_len -= fraglen;
     686                 :          0 :         buf->len -= fraglen;
     687         [ #  # ]:          0 :         if (tail->iov_len) {
     688                 :          0 :                 xdr->p = tail->iov_base + tail->iov_len;
     689   [ #  #  #  # ]:          0 :                 WARN_ON_ONCE(!xdr->end);
     690   [ #  #  #  # ]:          0 :                 WARN_ON_ONCE(!xdr->iov);
     691                 :            :                 return;
     692                 :            :         }
     693   [ #  #  #  # ]:          0 :         WARN_ON_ONCE(fraglen);
     694                 :          0 :         fraglen = min_t(int, buf->len - len, buf->page_len);
     695                 :          0 :         buf->page_len -= fraglen;
     696                 :          0 :         buf->len -= fraglen;
     697                 :            : 
     698                 :          0 :         new = buf->page_base + buf->page_len;
     699                 :            : 
     700                 :          0 :         xdr->page_ptr = buf->pages + (new >> PAGE_SHIFT);
     701                 :            : 
     702         [ #  # ]:          0 :         if (buf->page_len) {
     703                 :          0 :                 xdr->p = page_address(*xdr->page_ptr);
     704                 :          0 :                 xdr->end = (void *)xdr->p + PAGE_SIZE;
     705                 :          0 :                 xdr->p = (void *)xdr->p + (new % PAGE_SIZE);
     706   [ #  #  #  # ]:          0 :                 WARN_ON_ONCE(xdr->iov);
     707                 :            :                 return;
     708                 :            :         }
     709         [ #  # ]:          0 :         if (fraglen)
     710                 :          0 :                 xdr->end = head->iov_base + head->iov_len;
     711                 :            :         /* (otherwise assume xdr->end is already set) */
     712                 :          0 :         xdr->page_ptr--;
     713                 :          0 :         head->iov_len = len;
     714                 :          0 :         buf->len = len;
     715                 :          0 :         xdr->p = head->iov_base + head->iov_len;
     716                 :          0 :         xdr->iov = buf->head;
     717                 :            : }
     718                 :            : EXPORT_SYMBOL(xdr_truncate_encode);
     719                 :            : 
     720                 :            : /**
     721                 :            :  * xdr_restrict_buflen - decrease available buffer space
     722                 :            :  * @xdr: pointer to xdr_stream
     723                 :            :  * @newbuflen: new maximum number of bytes available
     724                 :            :  *
     725                 :            :  * Adjust our idea of how much space is available in the buffer.
     726                 :            :  * If we've already used too much space in the buffer, returns -1.
     727                 :            :  * If the available space is already smaller than newbuflen, returns 0
     728                 :            :  * and does nothing.  Otherwise, adjusts xdr->buf->buflen to newbuflen
     729                 :            :  * and ensures xdr->end is set at most offset newbuflen from the start
     730                 :            :  * of the buffer.
     731                 :            :  */
     732                 :          0 : int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen)
     733                 :            : {
     734                 :          0 :         struct xdr_buf *buf = xdr->buf;
     735                 :          0 :         int left_in_this_buf = (void *)xdr->end - (void *)xdr->p;
     736                 :          0 :         int end_offset = buf->len + left_in_this_buf;
     737                 :            : 
     738   [ #  #  #  # ]:          0 :         if (newbuflen < 0 || newbuflen < buf->len)
     739                 :            :                 return -1;
     740         [ #  # ]:          0 :         if (newbuflen > buf->buflen)
     741                 :            :                 return 0;
     742         [ #  # ]:          0 :         if (newbuflen < end_offset)
     743                 :          0 :                 xdr->end = (void *)xdr->end + newbuflen - end_offset;
     744                 :          0 :         buf->buflen = newbuflen;
     745                 :          0 :         return 0;
     746                 :            : }
     747                 :            : EXPORT_SYMBOL(xdr_restrict_buflen);
     748                 :            : 
     749                 :            : /**
     750                 :            :  * xdr_write_pages - Insert a list of pages into an XDR buffer for sending
     751                 :            :  * @xdr: pointer to xdr_stream
     752                 :            :  * @pages: list of pages
     753                 :            :  * @base: offset of first byte
     754                 :            :  * @len: length of data in bytes
     755                 :            :  *
     756                 :            :  */
     757                 :          0 : void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
     758                 :            :                  unsigned int len)
     759                 :            : {
     760                 :          0 :         struct xdr_buf *buf = xdr->buf;
     761                 :          0 :         struct kvec *iov = buf->tail;
     762                 :          0 :         buf->pages = pages;
     763                 :          0 :         buf->page_base = base;
     764                 :          0 :         buf->page_len = len;
     765                 :            : 
     766                 :          0 :         iov->iov_base = (char *)xdr->p;
     767                 :          0 :         iov->iov_len  = 0;
     768                 :          0 :         xdr->iov = iov;
     769                 :            : 
     770         [ #  # ]:          0 :         if (len & 3) {
     771                 :          0 :                 unsigned int pad = 4 - (len & 3);
     772                 :            : 
     773         [ #  # ]:          0 :                 BUG_ON(xdr->p >= xdr->end);
     774                 :          0 :                 iov->iov_base = (char *)xdr->p + (len & 3);
     775                 :          0 :                 iov->iov_len  += pad;
     776                 :          0 :                 len += pad;
     777                 :          0 :                 *xdr->p++ = 0;
     778                 :            :         }
     779                 :          0 :         buf->buflen += len;
     780                 :          0 :         buf->len += len;
     781                 :          0 : }
     782                 :            : EXPORT_SYMBOL_GPL(xdr_write_pages);
     783                 :            : 
     784                 :            : static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
     785                 :            :                 unsigned int len)
     786                 :            : {
     787   [ #  #  #  #  :          0 :         if (len > iov->iov_len)
             #  #  #  # ]
     788                 :            :                 len = iov->iov_len;
     789                 :          0 :         xdr->p = (__be32*)iov->iov_base;
     790                 :          0 :         xdr->end = (__be32*)(iov->iov_base + len);
     791                 :          0 :         xdr->iov = iov;
     792                 :          0 :         xdr->page_ptr = NULL;
     793                 :            : }
     794                 :            : 
     795                 :          0 : static int xdr_set_page_base(struct xdr_stream *xdr,
     796                 :            :                 unsigned int base, unsigned int len)
     797                 :            : {
     798                 :            :         unsigned int pgnr;
     799                 :            :         unsigned int maxlen;
     800                 :            :         unsigned int pgoff;
     801                 :            :         unsigned int pgend;
     802                 :            :         void *kaddr;
     803                 :            : 
     804                 :          0 :         maxlen = xdr->buf->page_len;
     805         [ #  # ]:          0 :         if (base >= maxlen)
     806                 :            :                 return -EINVAL;
     807                 :          0 :         maxlen -= base;
     808         [ #  # ]:          0 :         if (len > maxlen)
     809                 :            :                 len = maxlen;
     810                 :            : 
     811                 :          0 :         base += xdr->buf->page_base;
     812                 :            : 
     813                 :          0 :         pgnr = base >> PAGE_SHIFT;
     814                 :          0 :         xdr->page_ptr = &xdr->buf->pages[pgnr];
     815                 :          0 :         kaddr = page_address(*xdr->page_ptr);
     816                 :            : 
     817                 :          0 :         pgoff = base & ~PAGE_MASK;
     818                 :          0 :         xdr->p = (__be32*)(kaddr + pgoff);
     819                 :            : 
     820                 :          0 :         pgend = pgoff + len;
     821         [ #  # ]:          0 :         if (pgend > PAGE_SIZE)
     822                 :            :                 pgend = PAGE_SIZE;
     823                 :          0 :         xdr->end = (__be32*)(kaddr + pgend);
     824                 :          0 :         xdr->iov = NULL;
     825                 :          0 :         return 0;
     826                 :            : }
     827                 :            : 
     828                 :          0 : static void xdr_set_next_page(struct xdr_stream *xdr)
     829                 :            : {
     830                 :            :         unsigned int newbase;
     831                 :            : 
     832                 :          0 :         newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
     833                 :          0 :         newbase -= xdr->buf->page_base;
     834                 :            : 
     835         [ #  # ]:          0 :         if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
     836                 :          0 :                 xdr_set_iov(xdr, xdr->buf->tail, xdr->nwords << 2);
     837                 :          0 : }
     838                 :            : 
     839                 :          0 : static bool xdr_set_next_buffer(struct xdr_stream *xdr)
     840                 :            : {
     841         [ #  # ]:          0 :         if (xdr->page_ptr != NULL)
     842                 :          0 :                 xdr_set_next_page(xdr);
     843         [ #  # ]:          0 :         else if (xdr->iov == xdr->buf->head) {
     844         [ #  # ]:          0 :                 if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
     845                 :          0 :                         xdr_set_iov(xdr, xdr->buf->tail, xdr->nwords << 2);
     846                 :            :         }
     847                 :          0 :         return xdr->p != xdr->end;
     848                 :            : }
     849                 :            : 
     850                 :            : /**
     851                 :            :  * xdr_init_decode - Initialize an xdr_stream for decoding data.
     852                 :            :  * @xdr: pointer to xdr_stream struct
     853                 :            :  * @buf: pointer to XDR buffer from which to decode data
     854                 :            :  * @p: current pointer inside XDR buffer
     855                 :            :  * @rqst: pointer to controlling rpc_rqst, for debugging
     856                 :            :  */
     857                 :          0 : void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
     858                 :            :                      struct rpc_rqst *rqst)
     859                 :            : {
     860                 :          0 :         xdr->buf = buf;
     861                 :          0 :         xdr->scratch.iov_base = NULL;
     862                 :          0 :         xdr->scratch.iov_len = 0;
     863                 :          0 :         xdr->nwords = XDR_QUADLEN(buf->len);
     864         [ #  # ]:          0 :         if (buf->head[0].iov_len != 0)
     865                 :          0 :                 xdr_set_iov(xdr, buf->head, buf->len);
     866         [ #  # ]:          0 :         else if (buf->page_len != 0)
     867                 :          0 :                 xdr_set_page_base(xdr, 0, buf->len);
     868                 :            :         else
     869                 :          0 :                 xdr_set_iov(xdr, buf->head, buf->len);
     870   [ #  #  #  #  :          0 :         if (p != NULL && p > xdr->p && xdr->end >= p) {
                   #  # ]
     871                 :          0 :                 xdr->nwords -= p - xdr->p;
     872                 :          0 :                 xdr->p = p;
     873                 :            :         }
     874                 :          0 :         xdr->rqst = rqst;
     875                 :          0 : }
     876                 :            : EXPORT_SYMBOL_GPL(xdr_init_decode);
     877                 :            : 
     878                 :            : /**
     879                 :            :  * xdr_init_decode_pages - Initialize an xdr_stream for decoding into pages
     880                 :            :  * @xdr: pointer to xdr_stream struct
     881                 :            :  * @buf: pointer to XDR buffer from which to decode data
     882                 :            :  * @pages: list of pages to decode into
     883                 :            :  * @len: length in bytes of buffer in pages
     884                 :            :  */
     885                 :          0 : void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
     886                 :            :                            struct page **pages, unsigned int len)
     887                 :            : {
     888                 :          0 :         memset(buf, 0, sizeof(*buf));
     889                 :          0 :         buf->pages =  pages;
     890                 :          0 :         buf->page_len =  len;
     891                 :          0 :         buf->buflen =  len;
     892                 :          0 :         buf->len = len;
     893                 :          0 :         xdr_init_decode(xdr, buf, NULL, NULL);
     894                 :          0 : }
     895                 :            : EXPORT_SYMBOL_GPL(xdr_init_decode_pages);
     896                 :            : 
     897                 :          0 : static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
     898                 :            : {
     899                 :          0 :         unsigned int nwords = XDR_QUADLEN(nbytes);
     900                 :          0 :         __be32 *p = xdr->p;
     901                 :          0 :         __be32 *q = p + nwords;
     902                 :            : 
     903   [ #  #  #  #  :          0 :         if (unlikely(nwords > xdr->nwords || q > xdr->end || q < p))
             #  #  #  # ]
     904                 :            :                 return NULL;
     905                 :          0 :         xdr->p = q;
     906                 :          0 :         xdr->nwords -= nwords;
     907                 :          0 :         return p;
     908                 :            : }
     909                 :            : 
     910                 :            : /**
     911                 :            :  * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
     912                 :            :  * @xdr: pointer to xdr_stream struct
     913                 :            :  * @buf: pointer to an empty buffer
     914                 :            :  * @buflen: size of 'buf'
     915                 :            :  *
     916                 :            :  * The scratch buffer is used when decoding from an array of pages.
     917                 :            :  * If an xdr_inline_decode() call spans across page boundaries, then
     918                 :            :  * we copy the data into the scratch buffer in order to allow linear
     919                 :            :  * access.
     920                 :            :  */
     921                 :          0 : void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
     922                 :            : {
     923                 :          0 :         xdr->scratch.iov_base = buf;
     924                 :          0 :         xdr->scratch.iov_len = buflen;
     925                 :          0 : }
     926                 :            : EXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
     927                 :            : 
     928                 :          0 : static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
     929                 :            : {
     930                 :            :         __be32 *p;
     931                 :          0 :         char *cpdest = xdr->scratch.iov_base;
     932                 :          0 :         size_t cplen = (char *)xdr->end - (char *)xdr->p;
     933                 :            : 
     934         [ #  # ]:          0 :         if (nbytes > xdr->scratch.iov_len)
     935                 :            :                 goto out_overflow;
     936                 :          0 :         p = __xdr_inline_decode(xdr, cplen);
     937         [ #  # ]:          0 :         if (p == NULL)
     938                 :            :                 return NULL;
     939                 :          0 :         memcpy(cpdest, p, cplen);
     940         [ #  # ]:          0 :         if (!xdr_set_next_buffer(xdr))
     941                 :            :                 goto out_overflow;
     942                 :          0 :         cpdest += cplen;
     943                 :          0 :         nbytes -= cplen;
     944                 :          0 :         p = __xdr_inline_decode(xdr, nbytes);
     945         [ #  # ]:          0 :         if (p == NULL)
     946                 :            :                 return NULL;
     947                 :          0 :         memcpy(cpdest, p, nbytes);
     948                 :          0 :         return xdr->scratch.iov_base;
     949                 :            : out_overflow:
     950                 :          0 :         trace_rpc_xdr_overflow(xdr, nbytes);
     951                 :          0 :         return NULL;
     952                 :            : }
     953                 :            : 
     954                 :            : /**
     955                 :            :  * xdr_inline_decode - Retrieve XDR data to decode
     956                 :            :  * @xdr: pointer to xdr_stream struct
     957                 :            :  * @nbytes: number of bytes of data to decode
     958                 :            :  *
     959                 :            :  * Check if the input buffer is long enough to enable us to decode
     960                 :            :  * 'nbytes' more bytes of data starting at the current position.
     961                 :            :  * If so return the current pointer, then update the current
     962                 :            :  * pointer position.
     963                 :            :  */
     964                 :          0 : __be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
     965                 :            : {
     966                 :            :         __be32 *p;
     967                 :            : 
     968         [ #  # ]:          0 :         if (unlikely(nbytes == 0))
     969                 :          0 :                 return xdr->p;
     970   [ #  #  #  # ]:          0 :         if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
     971                 :            :                 goto out_overflow;
     972                 :          0 :         p = __xdr_inline_decode(xdr, nbytes);
     973         [ #  # ]:          0 :         if (p != NULL)
     974                 :            :                 return p;
     975                 :          0 :         return xdr_copy_to_scratch(xdr, nbytes);
     976                 :            : out_overflow:
     977                 :          0 :         trace_rpc_xdr_overflow(xdr, nbytes);
     978                 :          0 :         return NULL;
     979                 :            : }
     980                 :            : EXPORT_SYMBOL_GPL(xdr_inline_decode);
     981                 :            : 
     982                 :          0 : static unsigned int xdr_align_pages(struct xdr_stream *xdr, unsigned int len)
     983                 :            : {
     984                 :          0 :         struct xdr_buf *buf = xdr->buf;
     985                 :            :         struct kvec *iov;
     986                 :          0 :         unsigned int nwords = XDR_QUADLEN(len);
     987                 :            :         unsigned int cur = xdr_stream_pos(xdr);
     988                 :            :         unsigned int copied, offset;
     989                 :            : 
     990         [ #  # ]:          0 :         if (xdr->nwords == 0)
     991                 :            :                 return 0;
     992                 :            : 
     993                 :            :         /* Realign pages to current pointer position */
     994                 :            :         iov = buf->head;
     995         [ #  # ]:          0 :         if (iov->iov_len > cur) {
     996                 :          0 :                 offset = iov->iov_len - cur;
     997                 :          0 :                 copied = xdr_shrink_bufhead(buf, offset);
     998                 :          0 :                 trace_rpc_xdr_alignment(xdr, offset, copied);
     999                 :          0 :                 xdr->nwords = XDR_QUADLEN(buf->len - cur);
    1000                 :            :         }
    1001                 :            : 
    1002         [ #  # ]:          0 :         if (nwords > xdr->nwords) {
    1003                 :            :                 nwords = xdr->nwords;
    1004                 :          0 :                 len = nwords << 2;
    1005                 :            :         }
    1006         [ #  # ]:          0 :         if (buf->page_len <= len)
    1007                 :            :                 len = buf->page_len;
    1008         [ #  # ]:          0 :         else if (nwords < xdr->nwords) {
    1009                 :            :                 /* Truncate page data and move it into the tail */
    1010                 :          0 :                 offset = buf->page_len - len;
    1011                 :          0 :                 copied = xdr_shrink_pagelen(buf, offset);
    1012                 :          0 :                 trace_rpc_xdr_alignment(xdr, offset, copied);
    1013                 :          0 :                 xdr->nwords = XDR_QUADLEN(buf->len - cur);
    1014                 :            :         }
    1015                 :          0 :         return len;
    1016                 :            : }
    1017                 :            : 
    1018                 :            : /**
    1019                 :            :  * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
    1020                 :            :  * @xdr: pointer to xdr_stream struct
    1021                 :            :  * @len: number of bytes of page data
    1022                 :            :  *
    1023                 :            :  * Moves data beyond the current pointer position from the XDR head[] buffer
    1024                 :            :  * into the page list. Any data that lies beyond current position + "len"
    1025                 :            :  * bytes is moved into the XDR tail[].
    1026                 :            :  *
    1027                 :            :  * Returns the number of XDR encoded bytes now contained in the pages
    1028                 :            :  */
    1029                 :          0 : unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
    1030                 :            : {
    1031                 :          0 :         struct xdr_buf *buf = xdr->buf;
    1032                 :            :         struct kvec *iov;
    1033                 :            :         unsigned int nwords;
    1034                 :            :         unsigned int end;
    1035                 :            :         unsigned int padding;
    1036                 :            : 
    1037                 :          0 :         len = xdr_align_pages(xdr, len);
    1038         [ #  # ]:          0 :         if (len == 0)
    1039                 :            :                 return 0;
    1040                 :          0 :         nwords = XDR_QUADLEN(len);
    1041                 :          0 :         padding = (nwords << 2) - len;
    1042                 :          0 :         xdr->iov = iov = buf->tail;
    1043                 :            :         /* Compute remaining message length.  */
    1044                 :          0 :         end = ((xdr->nwords - nwords) << 2) + padding;
    1045         [ #  # ]:          0 :         if (end > iov->iov_len)
    1046                 :            :                 end = iov->iov_len;
    1047                 :            : 
    1048                 :            :         /*
    1049                 :            :          * Position current pointer at beginning of tail, and
    1050                 :            :          * set remaining message length.
    1051                 :            :          */
    1052                 :          0 :         xdr->p = (__be32 *)((char *)iov->iov_base + padding);
    1053                 :          0 :         xdr->end = (__be32 *)((char *)iov->iov_base + end);
    1054                 :          0 :         xdr->page_ptr = NULL;
    1055                 :          0 :         xdr->nwords = XDR_QUADLEN(end - padding);
    1056                 :          0 :         return len;
    1057                 :            : }
    1058                 :            : EXPORT_SYMBOL_GPL(xdr_read_pages);
    1059                 :            : 
    1060                 :            : /**
    1061                 :            :  * xdr_enter_page - decode data from the XDR page
    1062                 :            :  * @xdr: pointer to xdr_stream struct
    1063                 :            :  * @len: number of bytes of page data
    1064                 :            :  *
    1065                 :            :  * Moves data beyond the current pointer position from the XDR head[] buffer
    1066                 :            :  * into the page list. Any data that lies beyond current position + "len"
    1067                 :            :  * bytes is moved into the XDR tail[]. The current pointer is then
    1068                 :            :  * repositioned at the beginning of the first XDR page.
    1069                 :            :  */
    1070                 :          0 : void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
    1071                 :            : {
    1072                 :          0 :         len = xdr_align_pages(xdr, len);
    1073                 :            :         /*
    1074                 :            :          * Position current pointer at beginning of tail, and
    1075                 :            :          * set remaining message length.
    1076                 :            :          */
    1077         [ #  # ]:          0 :         if (len != 0)
    1078                 :          0 :                 xdr_set_page_base(xdr, 0, len);
    1079                 :          0 : }
    1080                 :            : EXPORT_SYMBOL_GPL(xdr_enter_page);
    1081                 :            : 
    1082                 :            : static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};
    1083                 :            : 
    1084                 :            : void
    1085                 :          0 : xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
    1086                 :            : {
    1087                 :          0 :         buf->head[0] = *iov;
    1088                 :          0 :         buf->tail[0] = empty_iov;
    1089                 :          0 :         buf->page_len = 0;
    1090                 :          0 :         buf->buflen = buf->len = iov->iov_len;
    1091                 :          0 : }
    1092                 :            : EXPORT_SYMBOL_GPL(xdr_buf_from_iov);
    1093                 :            : 
    1094                 :            : /**
    1095                 :            :  * xdr_buf_subsegment - set subbuf to a portion of buf
    1096                 :            :  * @buf: an xdr buffer
    1097                 :            :  * @subbuf: the result buffer
    1098                 :            :  * @base: beginning of range in bytes
    1099                 :            :  * @len: length of range in bytes
    1100                 :            :  *
    1101                 :            :  * sets @subbuf to an xdr buffer representing the portion of @buf of
    1102                 :            :  * length @len starting at offset @base.
    1103                 :            :  *
    1104                 :            :  * @buf and @subbuf may be pointers to the same struct xdr_buf.
    1105                 :            :  *
    1106                 :            :  * Returns -1 if base of length are out of bounds.
    1107                 :            :  */
    1108                 :            : int
    1109                 :          0 : xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
    1110                 :            :                         unsigned int base, unsigned int len)
    1111                 :            : {
    1112                 :          0 :         subbuf->buflen = subbuf->len = len;
    1113         [ #  # ]:          0 :         if (base < buf->head[0].iov_len) {
    1114                 :          0 :                 subbuf->head[0].iov_base = buf->head[0].iov_base + base;
    1115                 :          0 :                 subbuf->head[0].iov_len = min_t(unsigned int, len,
    1116                 :            :                                                 buf->head[0].iov_len - base);
    1117                 :          0 :                 len -= subbuf->head[0].iov_len;
    1118                 :            :                 base = 0;
    1119                 :            :         } else {
    1120                 :          0 :                 base -= buf->head[0].iov_len;
    1121                 :          0 :                 subbuf->head[0].iov_base = buf->head[0].iov_base;
    1122                 :          0 :                 subbuf->head[0].iov_len = 0;
    1123                 :            :         }
    1124                 :            : 
    1125         [ #  # ]:          0 :         if (base < buf->page_len) {
    1126                 :          0 :                 subbuf->page_len = min(buf->page_len - base, len);
    1127                 :          0 :                 base += buf->page_base;
    1128                 :          0 :                 subbuf->page_base = base & ~PAGE_MASK;
    1129                 :          0 :                 subbuf->pages = &buf->pages[base >> PAGE_SHIFT];
    1130                 :          0 :                 len -= subbuf->page_len;
    1131                 :            :                 base = 0;
    1132                 :            :         } else {
    1133                 :          0 :                 base -= buf->page_len;
    1134                 :          0 :                 subbuf->pages = buf->pages;
    1135                 :          0 :                 subbuf->page_base = 0;
    1136                 :          0 :                 subbuf->page_len = 0;
    1137                 :            :         }
    1138                 :            : 
    1139         [ #  # ]:          0 :         if (base < buf->tail[0].iov_len) {
    1140                 :          0 :                 subbuf->tail[0].iov_base = buf->tail[0].iov_base + base;
    1141                 :          0 :                 subbuf->tail[0].iov_len = min_t(unsigned int, len,
    1142                 :            :                                                 buf->tail[0].iov_len - base);
    1143                 :          0 :                 len -= subbuf->tail[0].iov_len;
    1144                 :            :                 base = 0;
    1145                 :            :         } else {
    1146                 :          0 :                 base -= buf->tail[0].iov_len;
    1147                 :          0 :                 subbuf->tail[0].iov_base = buf->tail[0].iov_base;
    1148                 :          0 :                 subbuf->tail[0].iov_len = 0;
    1149                 :            :         }
    1150                 :            : 
    1151         [ #  # ]:          0 :         if (base || len)
    1152                 :            :                 return -1;
    1153                 :          0 :         return 0;
    1154                 :            : }
    1155                 :            : EXPORT_SYMBOL_GPL(xdr_buf_subsegment);
    1156                 :            : 
    1157                 :            : /**
    1158                 :            :  * xdr_buf_trim - lop at most "len" bytes off the end of "buf"
    1159                 :            :  * @buf: buf to be trimmed
    1160                 :            :  * @len: number of bytes to reduce "buf" by
    1161                 :            :  *
    1162                 :            :  * Trim an xdr_buf by the given number of bytes by fixing up the lengths. Note
    1163                 :            :  * that it's possible that we'll trim less than that amount if the xdr_buf is
    1164                 :            :  * too small, or if (for instance) it's all in the head and the parser has
    1165                 :            :  * already read too far into it.
    1166                 :            :  */
    1167                 :          0 : void xdr_buf_trim(struct xdr_buf *buf, unsigned int len)
    1168                 :            : {
    1169                 :            :         size_t cur;
    1170                 :            :         unsigned int trim = len;
    1171                 :            : 
    1172         [ #  # ]:          0 :         if (buf->tail[0].iov_len) {
    1173                 :          0 :                 cur = min_t(size_t, buf->tail[0].iov_len, trim);
    1174                 :          0 :                 buf->tail[0].iov_len -= cur;
    1175                 :          0 :                 trim -= cur;
    1176         [ #  # ]:          0 :                 if (!trim)
    1177                 :            :                         goto fix_len;
    1178                 :            :         }
    1179                 :            : 
    1180         [ #  # ]:          0 :         if (buf->page_len) {
    1181                 :          0 :                 cur = min_t(unsigned int, buf->page_len, trim);
    1182                 :          0 :                 buf->page_len -= cur;
    1183                 :          0 :                 trim -= cur;
    1184         [ #  # ]:          0 :                 if (!trim)
    1185                 :            :                         goto fix_len;
    1186                 :            :         }
    1187                 :            : 
    1188         [ #  # ]:          0 :         if (buf->head[0].iov_len) {
    1189                 :          0 :                 cur = min_t(size_t, buf->head[0].iov_len, trim);
    1190                 :          0 :                 buf->head[0].iov_len -= cur;
    1191                 :          0 :                 trim -= cur;
    1192                 :            :         }
    1193                 :            : fix_len:
    1194                 :          0 :         buf->len -= (len - trim);
    1195                 :          0 : }
    1196                 :            : EXPORT_SYMBOL_GPL(xdr_buf_trim);
    1197                 :            : 
    1198                 :          0 : static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
    1199                 :            : {
    1200                 :            :         unsigned int this_len;
    1201                 :            : 
    1202                 :          0 :         this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);
    1203                 :          0 :         memcpy(obj, subbuf->head[0].iov_base, this_len);
    1204                 :          0 :         len -= this_len;
    1205                 :          0 :         obj += this_len;
    1206                 :          0 :         this_len = min_t(unsigned int, len, subbuf->page_len);
    1207         [ #  # ]:          0 :         if (this_len)
    1208                 :          0 :                 _copy_from_pages(obj, subbuf->pages, subbuf->page_base, this_len);
    1209                 :          0 :         len -= this_len;
    1210                 :          0 :         obj += this_len;
    1211                 :          0 :         this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);
    1212                 :          0 :         memcpy(obj, subbuf->tail[0].iov_base, this_len);
    1213                 :          0 : }
    1214                 :            : 
    1215                 :            : /* obj is assumed to point to allocated memory of size at least len: */
    1216                 :          0 : int read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len)
    1217                 :            : {
    1218                 :            :         struct xdr_buf subbuf;
    1219                 :            :         int status;
    1220                 :            : 
    1221                 :          0 :         status = xdr_buf_subsegment(buf, &subbuf, base, len);
    1222         [ #  # ]:          0 :         if (status != 0)
    1223                 :            :                 return status;
    1224                 :          0 :         __read_bytes_from_xdr_buf(&subbuf, obj, len);
    1225                 :          0 :         return 0;
    1226                 :            : }
    1227                 :            : EXPORT_SYMBOL_GPL(read_bytes_from_xdr_buf);
    1228                 :            : 
    1229                 :          0 : static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len)
    1230                 :            : {
    1231                 :            :         unsigned int this_len;
    1232                 :            : 
    1233                 :          0 :         this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);
    1234                 :          0 :         memcpy(subbuf->head[0].iov_base, obj, this_len);
    1235                 :          0 :         len -= this_len;
    1236                 :          0 :         obj += this_len;
    1237                 :          0 :         this_len = min_t(unsigned int, len, subbuf->page_len);
    1238         [ #  # ]:          0 :         if (this_len)
    1239                 :          0 :                 _copy_to_pages(subbuf->pages, subbuf->page_base, obj, this_len);
    1240                 :          0 :         len -= this_len;
    1241                 :          0 :         obj += this_len;
    1242                 :          0 :         this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);
    1243                 :          0 :         memcpy(subbuf->tail[0].iov_base, obj, this_len);
    1244                 :          0 : }
    1245                 :            : 
    1246                 :            : /* obj is assumed to point to allocated memory of size at least len: */
    1247                 :          0 : int write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len)
    1248                 :            : {
    1249                 :            :         struct xdr_buf subbuf;
    1250                 :            :         int status;
    1251                 :            : 
    1252                 :          0 :         status = xdr_buf_subsegment(buf, &subbuf, base, len);
    1253         [ #  # ]:          0 :         if (status != 0)
    1254                 :            :                 return status;
    1255                 :          0 :         __write_bytes_to_xdr_buf(&subbuf, obj, len);
    1256                 :          0 :         return 0;
    1257                 :            : }
    1258                 :            : EXPORT_SYMBOL_GPL(write_bytes_to_xdr_buf);
    1259                 :            : 
    1260                 :            : int
    1261                 :          0 : xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj)
    1262                 :            : {
    1263                 :            :         __be32  raw;
    1264                 :            :         int     status;
    1265                 :            : 
    1266                 :          0 :         status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
    1267         [ #  # ]:          0 :         if (status)
    1268                 :            :                 return status;
    1269                 :          0 :         *obj = be32_to_cpu(raw);
    1270                 :          0 :         return 0;
    1271                 :            : }
    1272                 :            : EXPORT_SYMBOL_GPL(xdr_decode_word);
    1273                 :            : 
    1274                 :            : int
    1275                 :          0 : xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
    1276                 :            : {
    1277                 :          0 :         __be32  raw = cpu_to_be32(obj);
    1278                 :            : 
    1279                 :          0 :         return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
    1280                 :            : }
    1281                 :            : EXPORT_SYMBOL_GPL(xdr_encode_word);
    1282                 :            : 
    1283                 :            : /**
    1284                 :            :  * xdr_buf_read_mic() - obtain the address of the GSS mic from xdr buf
    1285                 :            :  * @buf: pointer to buffer containing a mic
    1286                 :            :  * @mic: on success, returns the address of the mic
    1287                 :            :  * @offset: the offset in buf where mic may be found
    1288                 :            :  *
    1289                 :            :  * This function may modify the xdr buf if the mic is found to be straddling
    1290                 :            :  * a boundary between head, pages, and tail.  On success the mic can be read
    1291                 :            :  * from the address returned.  There is no need to free the mic.
    1292                 :            :  *
    1293                 :            :  * Return: Success returns 0, otherwise an integer error.
    1294                 :            :  */
    1295                 :          0 : int xdr_buf_read_mic(struct xdr_buf *buf, struct xdr_netobj *mic, unsigned int offset)
    1296                 :            : {
    1297                 :            :         struct xdr_buf subbuf;
    1298                 :            :         unsigned int boundary;
    1299                 :            : 
    1300         [ #  # ]:          0 :         if (xdr_decode_word(buf, offset, &mic->len))
    1301                 :            :                 return -EFAULT;
    1302                 :          0 :         offset += 4;
    1303                 :            : 
    1304                 :            :         /* Is the mic partially in the head? */
    1305                 :          0 :         boundary = buf->head[0].iov_len;
    1306   [ #  #  #  # ]:          0 :         if (offset < boundary && (offset + mic->len) > boundary)
    1307                 :          0 :                 xdr_shift_buf(buf, boundary - offset);
    1308                 :            : 
    1309                 :            :         /* Is the mic partially in the pages? */
    1310                 :          0 :         boundary += buf->page_len;
    1311   [ #  #  #  # ]:          0 :         if (offset < boundary && (offset + mic->len) > boundary)
    1312                 :          0 :                 xdr_shrink_pagelen(buf, boundary - offset);
    1313                 :            : 
    1314         [ #  # ]:          0 :         if (xdr_buf_subsegment(buf, &subbuf, offset, mic->len))
    1315                 :            :                 return -EFAULT;
    1316                 :            : 
    1317                 :            :         /* Is the mic contained entirely in the head? */
    1318                 :          0 :         mic->data = subbuf.head[0].iov_base;
    1319         [ #  # ]:          0 :         if (subbuf.head[0].iov_len == mic->len)
    1320                 :            :                 return 0;
    1321                 :            :         /* ..or is the mic contained entirely in the tail? */
    1322                 :          0 :         mic->data = subbuf.tail[0].iov_base;
    1323         [ #  # ]:          0 :         if (subbuf.tail[0].iov_len == mic->len)
    1324                 :            :                 return 0;
    1325                 :            : 
    1326                 :            :         /* Find a contiguous area in @buf to hold all of @mic */
    1327         [ #  # ]:          0 :         if (mic->len > buf->buflen - buf->len)
    1328                 :            :                 return -ENOMEM;
    1329         [ #  # ]:          0 :         if (buf->tail[0].iov_len != 0)
    1330                 :          0 :                 mic->data = buf->tail[0].iov_base + buf->tail[0].iov_len;
    1331                 :            :         else
    1332                 :          0 :                 mic->data = buf->head[0].iov_base + buf->head[0].iov_len;
    1333                 :          0 :         __read_bytes_from_xdr_buf(&subbuf, mic->data, mic->len);
    1334                 :          0 :         return 0;
    1335                 :            : }
    1336                 :            : EXPORT_SYMBOL_GPL(xdr_buf_read_mic);
    1337                 :            : 
    1338                 :            : /* Returns 0 on success, or else a negative error code. */
    1339                 :            : static int
    1340                 :          0 : xdr_xcode_array2(struct xdr_buf *buf, unsigned int base,
    1341                 :            :                  struct xdr_array2_desc *desc, int encode)
    1342                 :            : {
    1343                 :            :         char *elem = NULL, *c;
    1344                 :            :         unsigned int copied = 0, todo, avail_here;
    1345                 :            :         struct page **ppages = NULL;
    1346                 :            :         int err;
    1347                 :            : 
    1348         [ #  # ]:          0 :         if (encode) {
    1349         [ #  # ]:          0 :                 if (xdr_encode_word(buf, base, desc->array_len) != 0)
    1350                 :            :                         return -EINVAL;
    1351                 :            :         } else {
    1352   [ #  #  #  # ]:          0 :                 if (xdr_decode_word(buf, base, &desc->array_len) != 0 ||
    1353         [ #  # ]:          0 :                     desc->array_len > desc->array_maxlen ||
    1354                 :          0 :                     (unsigned long) base + 4 + desc->array_len *
    1355                 :          0 :                                     desc->elem_size > buf->len)
    1356                 :            :                         return -EINVAL;
    1357                 :            :         }
    1358                 :          0 :         base += 4;
    1359                 :            : 
    1360         [ #  # ]:          0 :         if (!desc->xcode)
    1361                 :            :                 return 0;
    1362                 :            : 
    1363                 :          0 :         todo = desc->array_len * desc->elem_size;
    1364                 :            : 
    1365                 :            :         /* process head */
    1366   [ #  #  #  # ]:          0 :         if (todo && base < buf->head->iov_len) {
    1367                 :          0 :                 c = buf->head->iov_base + base;
    1368                 :          0 :                 avail_here = min_t(unsigned int, todo,
    1369                 :            :                                    buf->head->iov_len - base);
    1370                 :          0 :                 todo -= avail_here;
    1371                 :            : 
    1372         [ #  # ]:          0 :                 while (avail_here >= desc->elem_size) {
    1373                 :          0 :                         err = desc->xcode(desc, c);
    1374         [ #  # ]:          0 :                         if (err)
    1375                 :            :                                 goto out;
    1376                 :          0 :                         c += desc->elem_size;
    1377                 :          0 :                         avail_here -= desc->elem_size;
    1378                 :            :                 }
    1379         [ #  # ]:          0 :                 if (avail_here) {
    1380                 :            :                         if (!elem) {
    1381                 :          0 :                                 elem = kmalloc(desc->elem_size, GFP_KERNEL);
    1382                 :            :                                 err = -ENOMEM;
    1383         [ #  # ]:          0 :                                 if (!elem)
    1384                 :            :                                         goto out;
    1385                 :            :                         }
    1386         [ #  # ]:          0 :                         if (encode) {
    1387                 :          0 :                                 err = desc->xcode(desc, elem);
    1388         [ #  # ]:          0 :                                 if (err)
    1389                 :            :                                         goto out;
    1390                 :          0 :                                 memcpy(c, elem, avail_here);
    1391                 :            :                         } else
    1392                 :          0 :                                 memcpy(elem, c, avail_here);
    1393                 :          0 :                         copied = avail_here;
    1394                 :            :                 }
    1395                 :          0 :                 base = buf->head->iov_len;  /* align to start of pages */
    1396                 :            :         }
    1397                 :            : 
    1398                 :            :         /* process pages array */
    1399                 :          0 :         base -= buf->head->iov_len;
    1400   [ #  #  #  # ]:          0 :         if (todo && base < buf->page_len) {
    1401                 :            :                 unsigned int avail_page;
    1402                 :            : 
    1403                 :          0 :                 avail_here = min(todo, buf->page_len - base);
    1404                 :          0 :                 todo -= avail_here;
    1405                 :            : 
    1406                 :          0 :                 base += buf->page_base;
    1407                 :          0 :                 ppages = buf->pages + (base >> PAGE_SHIFT);
    1408                 :          0 :                 base &= ~PAGE_MASK;
    1409                 :          0 :                 avail_page = min_t(unsigned int, PAGE_SIZE - base,
    1410                 :            :                                         avail_here);
    1411                 :          0 :                 c = kmap(*ppages) + base;
    1412                 :            : 
    1413         [ #  # ]:          0 :                 while (avail_here) {
    1414                 :          0 :                         avail_here -= avail_page;
    1415   [ #  #  #  # ]:          0 :                         if (copied || avail_page < desc->elem_size) {
    1416                 :          0 :                                 unsigned int l = min(avail_page,
    1417                 :            :                                         desc->elem_size - copied);
    1418         [ #  # ]:          0 :                                 if (!elem) {
    1419                 :            :                                         elem = kmalloc(desc->elem_size,
    1420                 :            :                                                        GFP_KERNEL);
    1421                 :            :                                         err = -ENOMEM;
    1422         [ #  # ]:          0 :                                         if (!elem)
    1423                 :            :                                                 goto out;
    1424                 :            :                                 }
    1425         [ #  # ]:          0 :                                 if (encode) {
    1426         [ #  # ]:          0 :                                         if (!copied) {
    1427                 :          0 :                                                 err = desc->xcode(desc, elem);
    1428         [ #  # ]:          0 :                                                 if (err)
    1429                 :            :                                                         goto out;
    1430                 :            :                                         }
    1431                 :          0 :                                         memcpy(c, elem + copied, l);
    1432                 :          0 :                                         copied += l;
    1433         [ #  # ]:          0 :                                         if (copied == desc->elem_size)
    1434                 :            :                                                 copied = 0;
    1435                 :            :                                 } else {
    1436                 :          0 :                                         memcpy(elem + copied, c, l);
    1437                 :          0 :                                         copied += l;
    1438         [ #  # ]:          0 :                                         if (copied == desc->elem_size) {
    1439                 :          0 :                                                 err = desc->xcode(desc, elem);
    1440         [ #  # ]:          0 :                                                 if (err)
    1441                 :            :                                                         goto out;
    1442                 :            :                                                 copied = 0;
    1443                 :            :                                         }
    1444                 :            :                                 }
    1445                 :          0 :                                 avail_page -= l;
    1446                 :          0 :                                 c += l;
    1447                 :            :                         }
    1448         [ #  # ]:          0 :                         while (avail_page >= desc->elem_size) {
    1449                 :          0 :                                 err = desc->xcode(desc, c);
    1450         [ #  # ]:          0 :                                 if (err)
    1451                 :            :                                         goto out;
    1452                 :          0 :                                 c += desc->elem_size;
    1453                 :          0 :                                 avail_page -= desc->elem_size;
    1454                 :            :                         }
    1455         [ #  # ]:          0 :                         if (avail_page) {
    1456                 :          0 :                                 unsigned int l = min(avail_page,
    1457                 :            :                                             desc->elem_size - copied);
    1458         [ #  # ]:          0 :                                 if (!elem) {
    1459                 :          0 :                                         elem = kmalloc(desc->elem_size,
    1460                 :            :                                                        GFP_KERNEL);
    1461                 :            :                                         err = -ENOMEM;
    1462         [ #  # ]:          0 :                                         if (!elem)
    1463                 :            :                                                 goto out;
    1464                 :            :                                 }
    1465         [ #  # ]:          0 :                                 if (encode) {
    1466         [ #  # ]:          0 :                                         if (!copied) {
    1467                 :          0 :                                                 err = desc->xcode(desc, elem);
    1468         [ #  # ]:          0 :                                                 if (err)
    1469                 :            :                                                         goto out;
    1470                 :            :                                         }
    1471                 :          0 :                                         memcpy(c, elem + copied, l);
    1472                 :          0 :                                         copied += l;
    1473         [ #  # ]:          0 :                                         if (copied == desc->elem_size)
    1474                 :            :                                                 copied = 0;
    1475                 :            :                                 } else {
    1476                 :          0 :                                         memcpy(elem + copied, c, l);
    1477                 :          0 :                                         copied += l;
    1478         [ #  # ]:          0 :                                         if (copied == desc->elem_size) {
    1479                 :          0 :                                                 err = desc->xcode(desc, elem);
    1480         [ #  # ]:          0 :                                                 if (err)
    1481                 :            :                                                         goto out;
    1482                 :            :                                                 copied = 0;
    1483                 :            :                                         }
    1484                 :            :                                 }
    1485                 :            :                         }
    1486         [ #  # ]:          0 :                         if (avail_here) {
    1487                 :            :                                 kunmap(*ppages);
    1488                 :          0 :                                 ppages++;
    1489                 :          0 :                                 c = kmap(*ppages);
    1490                 :            :                         }
    1491                 :            : 
    1492                 :          0 :                         avail_page = min(avail_here,
    1493                 :            :                                  (unsigned int) PAGE_SIZE);
    1494                 :            :                 }
    1495                 :          0 :                 base = buf->page_len;  /* align to start of tail */
    1496                 :            :         }
    1497                 :            : 
    1498                 :            :         /* process tail */
    1499                 :          0 :         base -= buf->page_len;
    1500         [ #  # ]:          0 :         if (todo) {
    1501                 :          0 :                 c = buf->tail->iov_base + base;
    1502         [ #  # ]:          0 :                 if (copied) {
    1503                 :          0 :                         unsigned int l = desc->elem_size - copied;
    1504                 :            : 
    1505         [ #  # ]:          0 :                         if (encode)
    1506                 :          0 :                                 memcpy(c, elem + copied, l);
    1507                 :            :                         else {
    1508                 :          0 :                                 memcpy(elem + copied, c, l);
    1509                 :          0 :                                 err = desc->xcode(desc, elem);
    1510         [ #  # ]:          0 :                                 if (err)
    1511                 :            :                                         goto out;
    1512                 :            :                         }
    1513                 :          0 :                         todo -= l;
    1514                 :          0 :                         c += l;
    1515                 :            :                 }
    1516         [ #  # ]:          0 :                 while (todo) {
    1517                 :          0 :                         err = desc->xcode(desc, c);
    1518         [ #  # ]:          0 :                         if (err)
    1519                 :            :                                 goto out;
    1520                 :          0 :                         c += desc->elem_size;
    1521                 :          0 :                         todo -= desc->elem_size;
    1522                 :            :                 }
    1523                 :            :         }
    1524                 :            :         err = 0;
    1525                 :            : 
    1526                 :            : out:
    1527                 :          0 :         kfree(elem);
    1528                 :            :         if (ppages)
    1529                 :            :                 kunmap(*ppages);
    1530                 :          0 :         return err;
    1531                 :            : }
    1532                 :            : 
    1533                 :            : int
    1534                 :          0 : xdr_decode_array2(struct xdr_buf *buf, unsigned int base,
    1535                 :            :                   struct xdr_array2_desc *desc)
    1536                 :            : {
    1537         [ #  # ]:          0 :         if (base >= buf->len)
    1538                 :            :                 return -EINVAL;
    1539                 :            : 
    1540                 :          0 :         return xdr_xcode_array2(buf, base, desc, 0);
    1541                 :            : }
    1542                 :            : EXPORT_SYMBOL_GPL(xdr_decode_array2);
    1543                 :            : 
    1544                 :            : int
    1545                 :          0 : xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
    1546                 :            :                   struct xdr_array2_desc *desc)
    1547                 :            : {
    1548         [ #  # ]:          0 :         if ((unsigned long) base + 4 + desc->array_len * desc->elem_size >
    1549                 :          0 :             buf->head->iov_len + buf->page_len + buf->tail->iov_len)
    1550                 :            :                 return -EINVAL;
    1551                 :            : 
    1552                 :          0 :         return xdr_xcode_array2(buf, base, desc, 1);
    1553                 :            : }
    1554                 :            : EXPORT_SYMBOL_GPL(xdr_encode_array2);
    1555                 :            : 
    1556                 :            : int
    1557                 :          0 : xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len,
    1558                 :            :                 int (*actor)(struct scatterlist *, void *), void *data)
    1559                 :            : {
    1560                 :            :         int i, ret = 0;
    1561                 :            :         unsigned int page_len, thislen, page_offset;
    1562                 :            :         struct scatterlist      sg[1];
    1563                 :            : 
    1564                 :          0 :         sg_init_table(sg, 1);
    1565                 :            : 
    1566         [ #  # ]:          0 :         if (offset >= buf->head[0].iov_len) {
    1567                 :          0 :                 offset -= buf->head[0].iov_len;
    1568                 :            :         } else {
    1569                 :          0 :                 thislen = buf->head[0].iov_len - offset;
    1570         [ #  # ]:          0 :                 if (thislen > len)
    1571                 :            :                         thislen = len;
    1572                 :          0 :                 sg_set_buf(sg, buf->head[0].iov_base + offset, thislen);
    1573                 :          0 :                 ret = actor(sg, data);
    1574         [ #  # ]:          0 :                 if (ret)
    1575                 :            :                         goto out;
    1576                 :            :                 offset = 0;
    1577                 :          0 :                 len -= thislen;
    1578                 :            :         }
    1579         [ #  # ]:          0 :         if (len == 0)
    1580                 :            :                 goto out;
    1581                 :            : 
    1582         [ #  # ]:          0 :         if (offset >= buf->page_len) {
    1583                 :          0 :                 offset -= buf->page_len;
    1584                 :            :         } else {
    1585                 :          0 :                 page_len = buf->page_len - offset;
    1586         [ #  # ]:          0 :                 if (page_len > len)
    1587                 :            :                         page_len = len;
    1588                 :          0 :                 len -= page_len;
    1589                 :          0 :                 page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
    1590                 :          0 :                 i = (offset + buf->page_base) >> PAGE_SHIFT;
    1591                 :          0 :                 thislen = PAGE_SIZE - page_offset;
    1592                 :            :                 do {
    1593         [ #  # ]:          0 :                         if (thislen > page_len)
    1594                 :            :                                 thislen = page_len;
    1595                 :          0 :                         sg_set_page(sg, buf->pages[i], thislen, page_offset);
    1596                 :          0 :                         ret = actor(sg, data);
    1597         [ #  # ]:          0 :                         if (ret)
    1598                 :            :                                 goto out;
    1599                 :          0 :                         page_len -= thislen;
    1600                 :          0 :                         i++;
    1601                 :            :                         page_offset = 0;
    1602                 :            :                         thislen = PAGE_SIZE;
    1603         [ #  # ]:          0 :                 } while (page_len != 0);
    1604                 :            :                 offset = 0;
    1605                 :            :         }
    1606         [ #  # ]:          0 :         if (len == 0)
    1607                 :            :                 goto out;
    1608         [ #  # ]:          0 :         if (offset < buf->tail[0].iov_len) {
    1609                 :          0 :                 thislen = buf->tail[0].iov_len - offset;
    1610         [ #  # ]:          0 :                 if (thislen > len)
    1611                 :            :                         thislen = len;
    1612                 :          0 :                 sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen);
    1613                 :          0 :                 ret = actor(sg, data);
    1614                 :          0 :                 len -= thislen;
    1615                 :            :         }
    1616         [ #  # ]:          0 :         if (len != 0)
    1617                 :            :                 ret = -EINVAL;
    1618                 :            : out:
    1619                 :          0 :         return ret;
    1620                 :            : }
    1621                 :            : EXPORT_SYMBOL_GPL(xdr_process_buf);
    1622                 :            : 
    1623                 :            : /**
    1624                 :            :  * xdr_stream_decode_opaque - Decode variable length opaque
    1625                 :            :  * @xdr: pointer to xdr_stream
    1626                 :            :  * @ptr: location to store opaque data
    1627                 :            :  * @size: size of storage buffer @ptr
    1628                 :            :  *
    1629                 :            :  * Return values:
    1630                 :            :  *   On success, returns size of object stored in *@ptr
    1631                 :            :  *   %-EBADMSG on XDR buffer overflow
    1632                 :            :  *   %-EMSGSIZE on overflow of storage buffer @ptr
    1633                 :            :  */
    1634                 :          0 : ssize_t xdr_stream_decode_opaque(struct xdr_stream *xdr, void *ptr, size_t size)
    1635                 :            : {
    1636                 :            :         ssize_t ret;
    1637                 :            :         void *p;
    1638                 :            : 
    1639                 :          0 :         ret = xdr_stream_decode_opaque_inline(xdr, &p, size);
    1640         [ #  # ]:          0 :         if (ret <= 0)
    1641                 :            :                 return ret;
    1642                 :          0 :         memcpy(ptr, p, ret);
    1643                 :          0 :         return ret;
    1644                 :            : }
    1645                 :            : EXPORT_SYMBOL_GPL(xdr_stream_decode_opaque);
    1646                 :            : 
    1647                 :            : /**
    1648                 :            :  * xdr_stream_decode_opaque_dup - Decode and duplicate variable length opaque
    1649                 :            :  * @xdr: pointer to xdr_stream
    1650                 :            :  * @ptr: location to store pointer to opaque data
    1651                 :            :  * @maxlen: maximum acceptable object size
    1652                 :            :  * @gfp_flags: GFP mask to use
    1653                 :            :  *
    1654                 :            :  * Return values:
    1655                 :            :  *   On success, returns size of object stored in *@ptr
    1656                 :            :  *   %-EBADMSG on XDR buffer overflow
    1657                 :            :  *   %-EMSGSIZE if the size of the object would exceed @maxlen
    1658                 :            :  *   %-ENOMEM on memory allocation failure
    1659                 :            :  */
    1660                 :          0 : ssize_t xdr_stream_decode_opaque_dup(struct xdr_stream *xdr, void **ptr,
    1661                 :            :                 size_t maxlen, gfp_t gfp_flags)
    1662                 :            : {
    1663                 :            :         ssize_t ret;
    1664                 :            :         void *p;
    1665                 :            : 
    1666                 :          0 :         ret = xdr_stream_decode_opaque_inline(xdr, &p, maxlen);
    1667         [ #  # ]:          0 :         if (ret > 0) {
    1668                 :          0 :                 *ptr = kmemdup(p, ret, gfp_flags);
    1669         [ #  # ]:          0 :                 if (*ptr != NULL)
    1670                 :            :                         return ret;
    1671                 :            :                 ret = -ENOMEM;
    1672                 :            :         }
    1673                 :          0 :         *ptr = NULL;
    1674                 :          0 :         return ret;
    1675                 :            : }
    1676                 :            : EXPORT_SYMBOL_GPL(xdr_stream_decode_opaque_dup);
    1677                 :            : 
    1678                 :            : /**
    1679                 :            :  * xdr_stream_decode_string - Decode variable length string
    1680                 :            :  * @xdr: pointer to xdr_stream
    1681                 :            :  * @str: location to store string
    1682                 :            :  * @size: size of storage buffer @str
    1683                 :            :  *
    1684                 :            :  * Return values:
    1685                 :            :  *   On success, returns length of NUL-terminated string stored in *@str
    1686                 :            :  *   %-EBADMSG on XDR buffer overflow
    1687                 :            :  *   %-EMSGSIZE on overflow of storage buffer @str
    1688                 :            :  */
    1689                 :          0 : ssize_t xdr_stream_decode_string(struct xdr_stream *xdr, char *str, size_t size)
    1690                 :            : {
    1691                 :            :         ssize_t ret;
    1692                 :            :         void *p;
    1693                 :            : 
    1694                 :          0 :         ret = xdr_stream_decode_opaque_inline(xdr, &p, size);
    1695         [ #  # ]:          0 :         if (ret > 0) {
    1696                 :          0 :                 memcpy(str, p, ret);
    1697                 :          0 :                 str[ret] = '\0';
    1698                 :          0 :                 return strlen(str);
    1699                 :            :         }
    1700                 :          0 :         *str = '\0';
    1701                 :          0 :         return ret;
    1702                 :            : }
    1703                 :            : EXPORT_SYMBOL_GPL(xdr_stream_decode_string);
    1704                 :            : 
    1705                 :            : /**
    1706                 :            :  * xdr_stream_decode_string_dup - Decode and duplicate variable length string
    1707                 :            :  * @xdr: pointer to xdr_stream
    1708                 :            :  * @str: location to store pointer to string
    1709                 :            :  * @maxlen: maximum acceptable string length
    1710                 :            :  * @gfp_flags: GFP mask to use
    1711                 :            :  *
    1712                 :            :  * Return values:
    1713                 :            :  *   On success, returns length of NUL-terminated string stored in *@ptr
    1714                 :            :  *   %-EBADMSG on XDR buffer overflow
    1715                 :            :  *   %-EMSGSIZE if the size of the string would exceed @maxlen
    1716                 :            :  *   %-ENOMEM on memory allocation failure
    1717                 :            :  */
    1718                 :          0 : ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str,
    1719                 :            :                 size_t maxlen, gfp_t gfp_flags)
    1720                 :            : {
    1721                 :            :         void *p;
    1722                 :            :         ssize_t ret;
    1723                 :            : 
    1724                 :          0 :         ret = xdr_stream_decode_opaque_inline(xdr, &p, maxlen);
    1725         [ #  # ]:          0 :         if (ret > 0) {
    1726                 :          0 :                 char *s = kmalloc(ret + 1, gfp_flags);
    1727         [ #  # ]:          0 :                 if (s != NULL) {
    1728                 :          0 :                         memcpy(s, p, ret);
    1729                 :          0 :                         s[ret] = '\0';
    1730                 :          0 :                         *str = s;
    1731                 :          0 :                         return strlen(s);
    1732                 :            :                 }
    1733                 :            :                 ret = -ENOMEM;
    1734                 :            :         }
    1735                 :          0 :         *str = NULL;
    1736                 :          0 :         return ret;
    1737                 :            : }
    1738                 :            : EXPORT_SYMBOL_GPL(xdr_stream_decode_string_dup);

Generated by: LCOV version 1.14