The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfs/nfs3xdr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/fs/nfs/nfs3xdr.c
    3  *
    4  * XDR functions to encode/decode NFSv3 RPC arguments and results.
    5  *
    6  * Copyright (C) 1996, 1997 Olaf Kirch
    7  */
    8 
    9 #include <linux/param.h>
   10 #include <linux/sched.h>
   11 #include <linux/mm.h>
   12 #include <linux/slab.h>
   13 #include <linux/utsname.h>
   14 #include <linux/errno.h>
   15 #include <linux/string.h>
   16 #include <linux/in.h>
   17 #include <linux/pagemap.h>
   18 #include <linux/proc_fs.h>
   19 #include <linux/kdev_t.h>
   20 #include <linux/sunrpc/clnt.h>
   21 #include <linux/nfs.h>
   22 #include <linux/nfs3.h>
   23 #include <linux/nfs_fs.h>
   24 
   25 #define NFSDBG_FACILITY         NFSDBG_XDR
   26 
   27 /* Mapping from NFS error code to "errno" error code. */
   28 #define errno_NFSERR_IO         EIO
   29 
   30 extern int                      nfs_stat_to_errno(int);
   31 
   32 /*
   33  * Declare the space requirements for NFS arguments and replies as
   34  * number of 32bit-words
   35  */
   36 #define NFS3_fhandle_sz         1+16
   37 #define NFS3_fh_sz              NFS3_fhandle_sz /* shorthand */
   38 #define NFS3_sattr_sz           15
   39 #define NFS3_filename_sz        1+(NFS3_MAXNAMLEN>>2)
   40 #define NFS3_path_sz            1+(NFS3_MAXPATHLEN>>2)
   41 #define NFS3_fattr_sz           21
   42 #define NFS3_wcc_attr_sz                6
   43 #define NFS3_pre_op_attr_sz     1+NFS3_wcc_attr_sz
   44 #define NFS3_post_op_attr_sz    1+NFS3_fattr_sz
   45 #define NFS3_wcc_data_sz                NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
   46 #define NFS3_fsstat_sz          
   47 #define NFS3_fsinfo_sz          
   48 #define NFS3_pathconf_sz                
   49 #define NFS3_entry_sz           NFS3_filename_sz+3
   50 
   51 #define NFS3_enc_void_sz        0
   52 #define NFS3_sattrargs_sz       NFS3_fh_sz+NFS3_sattr_sz+3
   53 #define NFS3_diropargs_sz       NFS3_fh_sz+NFS3_filename_sz
   54 #define NFS3_accessargs_sz      NFS3_fh_sz+1
   55 #define NFS3_readlinkargs_sz    NFS3_fh_sz
   56 #define NFS3_readargs_sz        NFS3_fh_sz+3
   57 #define NFS3_writeargs_sz       NFS3_fh_sz+5
   58 #define NFS3_createargs_sz      NFS3_diropargs_sz+NFS3_sattr_sz
   59 #define NFS3_mkdirargs_sz       NFS3_diropargs_sz+NFS3_sattr_sz
   60 #define NFS3_symlinkargs_sz     NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
   61 #define NFS3_mknodargs_sz       NFS3_diropargs_sz+2+NFS3_sattr_sz
   62 #define NFS3_renameargs_sz      NFS3_diropargs_sz+NFS3_diropargs_sz
   63 #define NFS3_linkargs_sz                NFS3_fh_sz+NFS3_diropargs_sz
   64 #define NFS3_readdirargs_sz     NFS3_fh_sz+2
   65 #define NFS3_commitargs_sz      NFS3_fh_sz+3
   66 
   67 #define NFS3_dec_void_sz        0
   68 #define NFS3_attrstat_sz        1+NFS3_fattr_sz
   69 #define NFS3_wccstat_sz         1+NFS3_wcc_data_sz
   70 #define NFS3_lookupres_sz       1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
   71 #define NFS3_accessres_sz       1+NFS3_post_op_attr_sz+1
   72 #define NFS3_readlinkres_sz     1+NFS3_post_op_attr_sz
   73 #define NFS3_readres_sz         1+NFS3_post_op_attr_sz+3
   74 #define NFS3_writeres_sz        1+NFS3_wcc_data_sz+4
   75 #define NFS3_createres_sz       1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
   76 #define NFS3_renameres_sz       1+(2 * NFS3_wcc_data_sz)
   77 #define NFS3_linkres_sz         1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
   78 #define NFS3_readdirres_sz      1+NFS3_post_op_attr_sz+2
   79 #define NFS3_fsstatres_sz       1+NFS3_post_op_attr_sz+13
   80 #define NFS3_fsinfores_sz       1+NFS3_post_op_attr_sz+12
   81 #define NFS3_pathconfres_sz     1+NFS3_post_op_attr_sz+6
   82 #define NFS3_commitres_sz       1+NFS3_wcc_data_sz+2
   83 
   84 /*
   85  * Map file type to S_IFMT bits
   86  */
   87 static struct {
   88         unsigned int    mode;
   89         unsigned int    nfs2type;
   90 } nfs_type2fmt[] = {
   91       { 0,              NFNON   },
   92       { S_IFREG,        NFREG   },
   93       { S_IFDIR,        NFDIR   },
   94       { S_IFBLK,        NFBLK   },
   95       { S_IFCHR,        NFCHR   },
   96       { S_IFLNK,        NFLNK   },
   97       { S_IFSOCK,       NFSOCK  },
   98       { S_IFIFO,        NFFIFO  },
   99       { 0,              NFBAD   }
  100 };
  101 
  102 /*
  103  * Common NFS XDR functions as inlines
  104  */
  105 static inline u32 *
  106 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
  107 {
  108         *p++ = htonl(fh->size);
  109         memcpy(p, fh->data, fh->size);
  110         return p + XDR_QUADLEN(fh->size);
  111 }
  112 
  113 static inline u32 *
  114 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
  115 {
  116         /*
  117          * Zero all nonused bytes
  118          */
  119         memset((u8 *)fh, 0, sizeof(*fh));
  120         if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
  121                 memcpy(fh->data, p, fh->size);
  122                 return p + XDR_QUADLEN(fh->size);
  123         }
  124         return NULL;
  125 }
  126 
  127 /*
  128  * Encode/decode time.
  129  * Since the VFS doesn't care for fractional times, we ignore the
  130  * nanosecond field.
  131  */
  132 static inline u32 *
  133 xdr_encode_time(u32 *p, time_t time)
  134 {
  135         *p++ = htonl(time);
  136         *p++ = 0;
  137         return p;
  138 }
  139 
  140 static inline u32 *
  141 xdr_decode_time3(u32 *p, u64 *timep)
  142 {
  143         u64 tmp = (u64)ntohl(*p++) << 32;
  144         *timep = tmp + (u64)ntohl(*p++);
  145         return p;
  146 }
  147 
  148 static inline u32 *
  149 xdr_encode_time3(u32 *p, u64 time)
  150 {
  151         *p++ = htonl(time >> 32);
  152         *p++ = htonl(time & 0xFFFFFFFF);
  153         return p;
  154 }
  155 
  156 static u32 *
  157 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
  158 {
  159         unsigned int    type;
  160         int             fmode;
  161 
  162         type = ntohl(*p++);
  163         if (type >= NF3BAD)
  164                 type = NF3BAD;
  165         fmode = nfs_type2fmt[type].mode;
  166         fattr->type = nfs_type2fmt[type].nfs2type;
  167         fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
  168         fattr->nlink = ntohl(*p++);
  169         fattr->uid = ntohl(*p++);
  170         fattr->gid = ntohl(*p++);
  171         p = xdr_decode_hyper(p, &fattr->size);
  172         p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
  173         /* Turn remote device info into Linux-specific dev_t */
  174         fattr->rdev = ntohl(*p++) << MINORBITS;
  175         fattr->rdev |= ntohl(*p++) & MINORMASK;
  176         p = xdr_decode_hyper(p, &fattr->fsid);
  177         p = xdr_decode_hyper(p, &fattr->fileid);
  178         p = xdr_decode_time3(p, &fattr->atime);
  179         p = xdr_decode_time3(p, &fattr->mtime);
  180         p = xdr_decode_time3(p, &fattr->ctime);
  181 
  182         /* Update the mode bits */
  183         fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
  184         return p;
  185 }
  186 
  187 static inline u32 *
  188 xdr_encode_sattr(u32 *p, struct iattr *attr)
  189 {
  190         if (attr->ia_valid & ATTR_MODE) {
  191                 *p++ = xdr_one;
  192                 *p++ = htonl(attr->ia_mode);
  193         } else {
  194                 *p++ = xdr_zero;
  195         }
  196         if (attr->ia_valid & ATTR_UID) {
  197                 *p++ = xdr_one;
  198                 *p++ = htonl(attr->ia_uid);
  199         } else {
  200                 *p++ = xdr_zero;
  201         }
  202         if (attr->ia_valid & ATTR_GID) {
  203                 *p++ = xdr_one;
  204                 *p++ = htonl(attr->ia_gid);
  205         } else {
  206                 *p++ = xdr_zero;
  207         }
  208         if (attr->ia_valid & ATTR_SIZE) {
  209                 *p++ = xdr_one;
  210                 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
  211         } else {
  212                 *p++ = xdr_zero;
  213         }
  214         if (attr->ia_valid & ATTR_ATIME_SET) {
  215                 *p++ = xdr_two;
  216                 p = xdr_encode_time(p, attr->ia_atime);
  217         } else if (attr->ia_valid & ATTR_ATIME) {
  218                 *p++ = xdr_one;
  219         } else {
  220                 *p++ = xdr_zero;
  221         }
  222         if (attr->ia_valid & ATTR_MTIME_SET) {
  223                 *p++ = xdr_two;
  224                 p = xdr_encode_time(p, attr->ia_mtime);
  225         } else if (attr->ia_valid & ATTR_MTIME) {
  226                 *p++ = xdr_one;
  227         } else {
  228                 *p++ = xdr_zero;
  229         }
  230         return p;
  231 }
  232 
  233 static inline u32 *
  234 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
  235 {
  236         p = xdr_decode_hyper(p, &fattr->pre_size);
  237         p = xdr_decode_time3(p, &fattr->pre_mtime);
  238         p = xdr_decode_time3(p, &fattr->pre_ctime);
  239         fattr->valid |= NFS_ATTR_WCC;
  240         return p;
  241 }
  242 
  243 static inline u32 *
  244 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
  245 {
  246         if (*p++)
  247                 p = xdr_decode_fattr(p, fattr);
  248         return p;
  249 }
  250 
  251 static inline u32 *
  252 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
  253 {
  254         if (*p++)
  255                 return xdr_decode_wcc_attr(p, fattr);
  256         return p;
  257 }
  258 
  259 
  260 static inline u32 *
  261 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
  262 {
  263         p = xdr_decode_pre_op_attr(p, fattr);
  264         return xdr_decode_post_op_attr(p, fattr);
  265 }
  266 
  267 /*
  268  * NFS encode functions
  269  */
  270 /*
  271  * Encode void argument
  272  */
  273 static int
  274 nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
  275 {
  276         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  277         return 0;
  278 }
  279 
  280 /*
  281  * Encode file handle argument
  282  */
  283 static int
  284 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
  285 {
  286         p = xdr_encode_fhandle(p, fh);
  287         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  288         return 0;
  289 }
  290 
  291 /*
  292  * Encode SETATTR arguments
  293  */
  294 static int
  295 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
  296 {
  297         p = xdr_encode_fhandle(p, args->fh);
  298         p = xdr_encode_sattr(p, args->sattr);
  299         *p++ = htonl(args->guard);
  300         if (args->guard)
  301                 p = xdr_encode_time3(p, args->guardtime);
  302         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  303         return 0;
  304 }
  305 
  306 /*
  307  * Encode directory ops argument
  308  */
  309 static int
  310 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
  311 {
  312         p = xdr_encode_fhandle(p, args->fh);
  313         p = xdr_encode_array(p, args->name, args->len);
  314         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  315         return 0;
  316 }
  317 
  318 /*
  319  * Encode access() argument
  320  */
  321 static int
  322 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
  323 {
  324         p = xdr_encode_fhandle(p, args->fh);
  325         *p++ = htonl(args->access);
  326         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  327         return 0;
  328 }
  329 
  330 /*
  331  * Arguments to a READ call. Since we read data directly into the page
  332  * cache, we also set up the reply iovec here so that iov[1] points
  333  * exactly to the page we want to fetch.
  334  */
  335 static int
  336 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
  337 {
  338         struct rpc_auth *auth = req->rq_task->tk_auth;
  339         unsigned int replen;
  340         u32 count = args->count;
  341 
  342         p = xdr_encode_fhandle(p, args->fh);
  343         p = xdr_encode_hyper(p, args->offset);
  344         *p++ = htonl(count);
  345         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  346 
  347         /* Inline the page array */
  348         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
  349         xdr_inline_pages(&req->rq_rcv_buf, replen,
  350                          args->pages, args->pgbase, count);
  351         return 0;
  352 }
  353 
  354 /*
  355  * Write arguments. Splice the buffer to be written into the iovec.
  356  */
  357 static int
  358 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
  359 {
  360         struct xdr_buf *sndbuf = &req->rq_snd_buf;
  361         u32 count = args->count;
  362 
  363         p = xdr_encode_fhandle(p, args->fh);
  364         p = xdr_encode_hyper(p, args->offset);
  365         *p++ = htonl(count);
  366         *p++ = htonl(args->stable);
  367         *p++ = htonl(count);
  368         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
  369 
  370         /* Copy the page array */
  371         xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
  372         return 0;
  373 }
  374 
  375 /*
  376  * Encode CREATE arguments
  377  */
  378 static int
  379 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
  380 {
  381         p = xdr_encode_fhandle(p, args->fh);
  382         p = xdr_encode_array(p, args->name, args->len);
  383 
  384         *p++ = htonl(args->createmode);
  385         if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
  386                 *p++ = args->verifier[0];
  387                 *p++ = args->verifier[1];
  388         } else
  389                 p = xdr_encode_sattr(p, args->sattr);
  390 
  391         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  392         return 0;
  393 }
  394 
  395 /*
  396  * Encode MKDIR arguments
  397  */
  398 static int
  399 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
  400 {
  401         p = xdr_encode_fhandle(p, args->fh);
  402         p = xdr_encode_array(p, args->name, args->len);
  403         p = xdr_encode_sattr(p, args->sattr);
  404         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  405         return 0;
  406 }
  407 
  408 /*
  409  * Encode SYMLINK arguments
  410  */
  411 static int
  412 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
  413 {
  414         p = xdr_encode_fhandle(p, args->fromfh);
  415         p = xdr_encode_array(p, args->fromname, args->fromlen);
  416         p = xdr_encode_sattr(p, args->sattr);
  417         p = xdr_encode_array(p, args->topath, args->tolen);
  418         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  419         return 0;
  420 }
  421 
  422 /*
  423  * Encode MKNOD arguments
  424  */
  425 static int
  426 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
  427 {
  428         p = xdr_encode_fhandle(p, args->fh);
  429         p = xdr_encode_array(p, args->name, args->len);
  430         *p++ = htonl(args->type);
  431         p = xdr_encode_sattr(p, args->sattr);
  432         if (args->type == NF3CHR || args->type == NF3BLK) {
  433                 *p++ = htonl(args->rdev >> MINORBITS);
  434                 *p++ = htonl(args->rdev & MINORMASK);
  435         }
  436 
  437         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  438         return 0;
  439 }
  440 
  441 /*
  442  * Encode RENAME arguments
  443  */
  444 static int
  445 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
  446 {
  447         p = xdr_encode_fhandle(p, args->fromfh);
  448         p = xdr_encode_array(p, args->fromname, args->fromlen);
  449         p = xdr_encode_fhandle(p, args->tofh);
  450         p = xdr_encode_array(p, args->toname, args->tolen);
  451         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  452         return 0;
  453 }
  454 
  455 /*
  456  * Encode LINK arguments
  457  */
  458 static int
  459 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
  460 {
  461         p = xdr_encode_fhandle(p, args->fromfh);
  462         p = xdr_encode_fhandle(p, args->tofh);
  463         p = xdr_encode_array(p, args->toname, args->tolen);
  464         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  465         return 0;
  466 }
  467 
  468 /*
  469  * Encode arguments to readdir call
  470  */
  471 static int
  472 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
  473 {
  474         struct rpc_auth *auth = req->rq_task->tk_auth;
  475         unsigned int replen;
  476         u32 count = args->count;
  477 
  478         p = xdr_encode_fhandle(p, args->fh);
  479         p = xdr_encode_hyper(p, args->cookie);
  480         *p++ = args->verf[0];
  481         *p++ = args->verf[1];
  482         if (args->plus) {
  483                 /* readdirplus: need dircount + buffer size.
  484                  * We just make sure we make dircount big enough */
  485                 *p++ = htonl(count >> 3);
  486         }
  487         *p++ = htonl(count);
  488         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  489 
  490         /* Inline the page array */
  491         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
  492         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
  493         return 0;
  494 }
  495 
  496 /*
  497  * Decode the result of a readdir call.
  498  * We just check for syntactical correctness.
  499  */
  500 static int
  501 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
  502 {
  503         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
  504         struct iovec *iov = rcvbuf->head;
  505         struct page **page;
  506         int hdrlen, recvd;
  507         int status, nr;
  508         unsigned int len, pglen;
  509         u32 *entry, *end;
  510 
  511         status = ntohl(*p++);
  512         /* Decode post_op_attrs */
  513         p = xdr_decode_post_op_attr(p, res->dir_attr);
  514         if (status)
  515                 return -nfs_stat_to_errno(status);
  516         /* Decode verifier cookie */
  517         if (res->verf) {
  518                 res->verf[0] = *p++;
  519                 res->verf[1] = *p++;
  520         } else {
  521                 p += 2;
  522         }
  523 
  524         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  525         if (iov->iov_len < hdrlen) {
  526                 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
  527                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
  528                 return -errno_NFSERR_IO;
  529         } else if (iov->iov_len != hdrlen) {
  530                 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
  531                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
  532         }
  533 
  534         pglen = rcvbuf->page_len;
  535         recvd = req->rq_received - hdrlen;
  536         if (pglen > recvd)
  537                 pglen = recvd;
  538         page = rcvbuf->pages;
  539         p = kmap(*page);
  540         end = (u32 *)((char *)p + pglen);
  541         entry = p;
  542         for (nr = 0; *p++; nr++) {
  543                 if (p + 3 > end)
  544                         goto short_pkt;
  545                 p += 2;                         /* inode # */
  546                 len = ntohl(*p++);              /* string length */
  547                 p += XDR_QUADLEN(len) + 2;      /* name + cookie */
  548                 if (len > NFS3_MAXNAMLEN) {
  549                         printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
  550                                                 len);
  551                         goto err_unmap;
  552                 }
  553 
  554                 if (res->plus) {
  555                         /* post_op_attr */
  556                         if (p > end)
  557                                 goto short_pkt;
  558                         if (*p++) {
  559                                 p += 21;
  560                                 if (p > end)
  561                                         goto short_pkt;
  562                         }
  563                         /* post_op_fh3 */
  564                         if (*p++) {
  565                                 if (p > end)
  566                                         goto short_pkt;
  567                                 len = ntohl(*p++);
  568                                 if (len > NFS3_FHSIZE) {
  569                                         printk(KERN_WARNING "NFS: giant filehandle in "
  570                                                 "readdir (len %x)!\n", len);
  571                                         goto err_unmap;
  572                                 }
  573                                 p += XDR_QUADLEN(len);
  574                         }
  575                 }
  576 
  577                 if (p + 2 > end)
  578                         goto short_pkt;
  579                 entry = p;
  580         }
  581         if (!nr && (entry[0] != 0 || entry[1] == 0))
  582                 goto short_pkt;
  583  out:
  584         kunmap(*page);
  585         return nr;
  586  short_pkt:
  587         entry[0] = entry[1] = 0;
  588         /* truncate listing ? */
  589         if (!nr) {
  590                 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
  591                 entry[1] = 1;
  592         }
  593         goto out;
  594 err_unmap:
  595         kunmap(*page);
  596         return -errno_NFSERR_IO;
  597 }
  598 
  599 u32 *
  600 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
  601 {
  602         struct nfs_entry old = *entry;
  603 
  604         if (!*p++) {
  605                 if (!*p)
  606                         return ERR_PTR(-EAGAIN);
  607                 entry->eof = 1;
  608                 return ERR_PTR(-EBADCOOKIE);
  609         }
  610 
  611         p = xdr_decode_hyper(p, &entry->ino);
  612         entry->len  = ntohl(*p++);
  613         entry->name = (const char *) p;
  614         p += XDR_QUADLEN(entry->len);
  615         entry->prev_cookie = entry->cookie;
  616         p = xdr_decode_hyper(p, &entry->cookie);
  617 
  618         if (plus) {
  619                 p = xdr_decode_post_op_attr(p, &entry->fattr);
  620                 /* In fact, a post_op_fh3: */
  621                 if (*p++) {
  622                         p = xdr_decode_fhandle(p, &entry->fh);
  623                         /* Ugh -- server reply was truncated */
  624                         if (p == NULL) {
  625                                 dprintk("NFS: FH truncated\n");
  626                                 *entry = old;
  627                                 return ERR_PTR(-EAGAIN);
  628                         }
  629                 } else {
  630                         /* If we don't get a file handle, the attrs
  631                          * aren't worth a lot. */
  632                         entry->fattr.valid = 0;
  633                 }
  634         }
  635 
  636         entry->eof = !p[0] && p[1];
  637         return p;
  638 }
  639 
  640 /*
  641  * Encode COMMIT arguments
  642  */
  643 static int
  644 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
  645 {
  646         p = xdr_encode_fhandle(p, args->fh);
  647         p = xdr_encode_hyper(p, args->offset);
  648         *p++ = htonl(args->count);
  649         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  650         return 0;
  651 }
  652 
  653 /*
  654  * NFS XDR decode functions
  655  */
  656 /*
  657  * Decode void reply
  658  */
  659 static int
  660 nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
  661 {
  662         return 0;
  663 }
  664 
  665 /*
  666  * Decode attrstat reply.
  667  */
  668 static int
  669 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  670 {
  671         int     status;
  672 
  673         if ((status = ntohl(*p++)))
  674                 return -nfs_stat_to_errno(status);
  675         xdr_decode_fattr(p, fattr);
  676         return 0;
  677 }
  678 
  679 /*
  680  * Decode status+wcc_data reply
  681  * SATTR, REMOVE, RMDIR
  682  */
  683 static int
  684 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  685 {
  686         int     status;
  687 
  688         if ((status = ntohl(*p++)))
  689                 status = -nfs_stat_to_errno(status);
  690         xdr_decode_wcc_data(p, fattr);
  691         return status;
  692 }
  693 
  694 /*
  695  * Decode LOOKUP reply
  696  */
  697 static int
  698 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
  699 {
  700         int     status;
  701 
  702         if ((status = ntohl(*p++))) {
  703                 status = -nfs_stat_to_errno(status);
  704         } else {
  705                 if (!(p = xdr_decode_fhandle(p, res->fh)))
  706                         return -errno_NFSERR_IO;
  707                 p = xdr_decode_post_op_attr(p, res->fattr);
  708         }
  709         xdr_decode_post_op_attr(p, res->dir_attr);
  710         return status;
  711 }
  712 
  713 /*
  714  * Decode ACCESS reply
  715  */
  716 static int
  717 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
  718 {
  719         int     status = ntohl(*p++);
  720 
  721         p = xdr_decode_post_op_attr(p, res->fattr);
  722         if (status)
  723                 return -nfs_stat_to_errno(status);
  724         res->access = ntohl(*p++);
  725         return 0;
  726 }
  727 
  728 static int
  729 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
  730 {
  731         struct rpc_auth *auth = req->rq_task->tk_auth;
  732         unsigned int replen;
  733         u32 count = args->count - 4;
  734 
  735         p = xdr_encode_fhandle(p, args->fh);
  736         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  737 
  738         /* Inline the page array */
  739         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
  740         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
  741         return 0;
  742 }
  743 
  744 /*
  745  * Decode READLINK reply
  746  */
  747 static int
  748 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  749 {
  750         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
  751         struct iovec *iov = rcvbuf->head;
  752         unsigned int hdrlen;
  753         u32     *strlen, len;
  754         char    *string;
  755         int     status;
  756 
  757         status = ntohl(*p++);
  758         p = xdr_decode_post_op_attr(p, fattr);
  759 
  760         if (status != 0)
  761                 return -nfs_stat_to_errno(status);
  762 
  763         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  764         if (iov->iov_len > hdrlen) {
  765                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
  766                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
  767         }
  768 
  769         strlen = (u32*)kmap(rcvbuf->pages[0]);
  770         /* Convert length of symlink */
  771         len = ntohl(*strlen);
  772         if (len > rcvbuf->page_len)
  773                 len = rcvbuf->page_len;
  774         *strlen = len;
  775         /* NULL terminate the string we got */
  776         string = (char *)(strlen + 1);
  777         string[len] = 0;
  778         kunmap(rcvbuf->pages[0]);
  779         return 0;
  780 }
  781 
  782 /*
  783  * Decode READ reply
  784  */
  785 static int
  786 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
  787 {
  788         struct iovec *iov = req->rq_rvec;
  789         int     status, count, ocount, recvd, hdrlen;
  790 
  791         status = ntohl(*p++);
  792         p = xdr_decode_post_op_attr(p, res->fattr);
  793 
  794         if (status != 0)
  795                 return -nfs_stat_to_errno(status);
  796 
  797         /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
  798          * in that it puts the count both in the res struct and in the
  799          * opaque data count. */
  800         count    = ntohl(*p++);
  801         res->eof = ntohl(*p++);
  802         ocount   = ntohl(*p++);
  803 
  804         if (ocount != count) {
  805                 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
  806                 return -errno_NFSERR_IO;
  807         }
  808 
  809         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  810         if (iov->iov_len < hdrlen) {
  811                 printk(KERN_WARNING "NFS: READ reply header overflowed:"
  812                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
  813                 return -errno_NFSERR_IO;
  814         } else if (iov->iov_len != hdrlen) {
  815                 dprintk("NFS: READ header is short. iovec will be shifted.\n");
  816                 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
  817         }
  818 
  819         recvd = req->rq_received - hdrlen;
  820         if (count > recvd) {
  821                 printk(KERN_WARNING "NFS: server cheating in read reply: "
  822                         "count %d > recvd %d\n", count, recvd);
  823                 count = recvd;
  824                 res->eof = 0;
  825         }
  826 
  827         if (count < res->count)
  828                 res->count = count;
  829 
  830         return count;
  831 }
  832 
  833 /*
  834  * Decode WRITE response
  835  */
  836 static int
  837 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
  838 {
  839         int     status;
  840 
  841         status = ntohl(*p++);
  842         p = xdr_decode_wcc_data(p, res->fattr);
  843 
  844         if (status != 0)
  845                 return -nfs_stat_to_errno(status);
  846 
  847         res->count = ntohl(*p++);
  848         res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
  849         res->verf->verifier[0] = *p++;
  850         res->verf->verifier[1] = *p++;
  851 
  852         return res->count;
  853 }
  854 
  855 /*
  856  * Decode a CREATE response
  857  */
  858 static int
  859 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
  860 {
  861         int     status;
  862 
  863         status = ntohl(*p++);
  864         if (status == 0) {
  865                 if (*p++) {
  866                         if (!(p = xdr_decode_fhandle(p, res->fh)))
  867                                 return -errno_NFSERR_IO;
  868                         p = xdr_decode_post_op_attr(p, res->fattr);
  869                 } else {
  870                         memset(res->fh, 0, sizeof(*res->fh));
  871                         /* Do decode post_op_attr but set it to NULL */
  872                         p = xdr_decode_post_op_attr(p, res->fattr);
  873                         res->fattr->valid = 0;
  874                 }
  875         } else {
  876                 status = -nfs_stat_to_errno(status);
  877         }
  878         p = xdr_decode_wcc_data(p, res->dir_attr);
  879         return status;
  880 }
  881 
  882 /*
  883  * Decode RENAME reply
  884  */
  885 static int
  886 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
  887 {
  888         int     status;
  889 
  890         if ((status = ntohl(*p++)) != 0)
  891                 status = -nfs_stat_to_errno(status);
  892         p = xdr_decode_wcc_data(p, res->fromattr);
  893         p = xdr_decode_wcc_data(p, res->toattr);
  894         return status;
  895 }
  896 
  897 /*
  898  * Decode LINK reply
  899  */
  900 static int
  901 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
  902 {
  903         int     status;
  904 
  905         if ((status = ntohl(*p++)) != 0)
  906                 status = -nfs_stat_to_errno(status);
  907         p = xdr_decode_post_op_attr(p, res->fattr);
  908         p = xdr_decode_wcc_data(p, res->dir_attr);
  909         return status;
  910 }
  911 
  912 /*
  913  * Decode FSSTAT reply
  914  */
  915 static int
  916 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  917 {
  918         struct nfs_fattr dummy;
  919         int             status;
  920 
  921         status = ntohl(*p++);
  922 
  923         p = xdr_decode_post_op_attr(p, &dummy);
  924         if (status != 0)
  925                 return -nfs_stat_to_errno(status);
  926 
  927         p = xdr_decode_hyper(p, &res->tbytes);
  928         p = xdr_decode_hyper(p, &res->fbytes);
  929         p = xdr_decode_hyper(p, &res->abytes);
  930         p = xdr_decode_hyper(p, &res->tfiles);
  931         p = xdr_decode_hyper(p, &res->ffiles);
  932         p = xdr_decode_hyper(p, &res->afiles);
  933 
  934         /* ignore invarsec */
  935         return 0;
  936 }
  937 
  938 /*
  939  * Decode FSINFO reply
  940  */
  941 static int
  942 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  943 {
  944         struct nfs_fattr dummy;
  945         int             status;
  946 
  947         status = ntohl(*p++);
  948 
  949         p = xdr_decode_post_op_attr(p, &dummy);
  950         if (status != 0)
  951                 return -nfs_stat_to_errno(status);
  952 
  953         res->rtmax  = ntohl(*p++);
  954         res->rtpref = ntohl(*p++);
  955         res->rtmult = ntohl(*p++);
  956         res->wtmax  = ntohl(*p++);
  957         res->wtpref = ntohl(*p++);
  958         res->wtmult = ntohl(*p++);
  959         res->dtpref = ntohl(*p++);
  960         p = xdr_decode_hyper(p, &res->maxfilesize);
  961 
  962         /* ignore time_delta and properties */
  963         return 0;
  964 }
  965 
  966 /*
  967  * Decode PATHCONF reply
  968  */
  969 static int
  970 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  971 {
  972         struct nfs_fattr dummy;
  973         int             status;
  974 
  975         status = ntohl(*p++);
  976 
  977         p = xdr_decode_post_op_attr(p, &dummy);
  978         if (status != 0)
  979                 return -nfs_stat_to_errno(status);
  980         res->linkmax = ntohl(*p++);
  981         res->namelen = ntohl(*p++);
  982 
  983         /* ignore remaining fields */
  984         return 0;
  985 }
  986 
  987 /*
  988  * Decode COMMIT reply
  989  */
  990 static int
  991 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
  992 {
  993         int             status;
  994 
  995         status = ntohl(*p++);
  996         p = xdr_decode_wcc_data(p, res->fattr);
  997         if (status != 0)
  998                 return -nfs_stat_to_errno(status);
  999 
 1000         res->verf->verifier[0] = *p++;
 1001         res->verf->verifier[1] = *p++;
 1002         return 0;
 1003 }
 1004 
 1005 #ifndef MAX
 1006 # define MAX(a, b)      (((a) > (b))? (a) : (b))
 1007 #endif
 1008 
 1009 #define PROC(proc, argtype, restype, timer)                             \
 1010     { .p_procname  = "nfs3_" #proc,                                     \
 1011       .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,                   \
 1012       .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,                   \
 1013       .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
 1014       .p_timer     = timer                                              \
 1015     }
 1016 
 1017 static struct rpc_procinfo      nfs3_procedures[22] = {
 1018   PROC(null,            enc_void,       dec_void, 0),
 1019   PROC(getattr,         fhandle,        attrstat, 1),
 1020   PROC(setattr,         sattrargs,      wccstat, 0),
 1021   PROC(lookup,          diropargs,      lookupres, 2),
 1022   PROC(access,          accessargs,     accessres, 1),
 1023   PROC(readlink,        readlinkargs,   readlinkres, 3),
 1024   PROC(read,            readargs,       readres, 3),
 1025   PROC(write,           writeargs,      writeres, 4),
 1026   PROC(create,          createargs,     createres, 0),
 1027   PROC(mkdir,           mkdirargs,      createres, 0),
 1028   PROC(symlink,         symlinkargs,    createres, 0),
 1029   PROC(mknod,           mknodargs,      createres, 0),
 1030   PROC(remove,          diropargs,      wccstat, 0),
 1031   PROC(rmdir,           diropargs,      wccstat, 0),
 1032   PROC(rename,          renameargs,     renameres, 0),
 1033   PROC(link,            linkargs,       linkres, 0),
 1034   PROC(readdir,         readdirargs,    readdirres, 3),
 1035   PROC(readdirplus,     readdirargs,    readdirres, 3),
 1036   PROC(fsstat,          fhandle,        fsstatres, 0),
 1037   PROC(fsinfo,          fhandle,        fsinfores, 0),
 1038   PROC(pathconf,        fhandle,        pathconfres, 0),
 1039   PROC(commit,          commitargs,     commitres, 5),
 1040 };
 1041 
 1042 struct rpc_version              nfs_version3 = {
 1043         3,
 1044         sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
 1045         nfs3_procedures
 1046 };
 1047 

Cache object: c2d9d4c5e9d8d19c99e529a66bc92744


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.