linux/fs/nfs/nfs3xdr.c
<<
>>
Prefs
   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/time.h>
  11#include <linux/mm.h>
  12#include <linux/slab.h>
  13#include <linux/errno.h>
  14#include <linux/string.h>
  15#include <linux/in.h>
  16#include <linux/pagemap.h>
  17#include <linux/proc_fs.h>
  18#include <linux/kdev_t.h>
  19#include <linux/sunrpc/clnt.h>
  20#include <linux/nfs.h>
  21#include <linux/nfs3.h>
  22#include <linux/nfs_fs.h>
  23#include <linux/nfsacl.h>
  24#include "internal.h"
  25
  26#define NFSDBG_FACILITY         NFSDBG_XDR
  27
  28/* Mapping from NFS error code to "errno" error code. */
  29#define errno_NFSERR_IO         EIO
  30
  31/*
  32 * Declare the space requirements for NFS arguments and replies as
  33 * number of 32bit-words
  34 */
  35#define NFS3_fhandle_sz         (1+16)
  36#define NFS3_fh_sz              (NFS3_fhandle_sz)       /* shorthand */
  37#define NFS3_sattr_sz           (15)
  38#define NFS3_filename_sz        (1+(NFS3_MAXNAMLEN>>2))
  39#define NFS3_path_sz            (1+(NFS3_MAXPATHLEN>>2))
  40#define NFS3_fattr_sz           (21)
  41#define NFS3_wcc_attr_sz                (6)
  42#define NFS3_pre_op_attr_sz     (1+NFS3_wcc_attr_sz)
  43#define NFS3_post_op_attr_sz    (1+NFS3_fattr_sz)
  44#define NFS3_wcc_data_sz                (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
  45#define NFS3_fsstat_sz          
  46#define NFS3_fsinfo_sz          
  47#define NFS3_pathconf_sz                
  48#define NFS3_entry_sz           (NFS3_filename_sz+3)
  49
  50#define NFS3_sattrargs_sz       (NFS3_fh_sz+NFS3_sattr_sz+3)
  51#define NFS3_diropargs_sz       (NFS3_fh_sz+NFS3_filename_sz)
  52#define NFS3_removeargs_sz      (NFS3_fh_sz+NFS3_filename_sz)
  53#define NFS3_accessargs_sz      (NFS3_fh_sz+1)
  54#define NFS3_readlinkargs_sz    (NFS3_fh_sz)
  55#define NFS3_readargs_sz        (NFS3_fh_sz+3)
  56#define NFS3_writeargs_sz       (NFS3_fh_sz+5)
  57#define NFS3_createargs_sz      (NFS3_diropargs_sz+NFS3_sattr_sz)
  58#define NFS3_mkdirargs_sz       (NFS3_diropargs_sz+NFS3_sattr_sz)
  59#define NFS3_symlinkargs_sz     (NFS3_diropargs_sz+1+NFS3_sattr_sz)
  60#define NFS3_mknodargs_sz       (NFS3_diropargs_sz+2+NFS3_sattr_sz)
  61#define NFS3_renameargs_sz      (NFS3_diropargs_sz+NFS3_diropargs_sz)
  62#define NFS3_linkargs_sz                (NFS3_fh_sz+NFS3_diropargs_sz)
  63#define NFS3_readdirargs_sz     (NFS3_fh_sz+2)
  64#define NFS3_commitargs_sz      (NFS3_fh_sz+3)
  65
  66#define NFS3_attrstat_sz        (1+NFS3_fattr_sz)
  67#define NFS3_wccstat_sz         (1+NFS3_wcc_data_sz)
  68#define NFS3_removeres_sz       (NFS3_wccstat_sz)
  69#define NFS3_lookupres_sz       (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
  70#define NFS3_accessres_sz       (1+NFS3_post_op_attr_sz+1)
  71#define NFS3_readlinkres_sz     (1+NFS3_post_op_attr_sz+1)
  72#define NFS3_readres_sz         (1+NFS3_post_op_attr_sz+3)
  73#define NFS3_writeres_sz        (1+NFS3_wcc_data_sz+4)
  74#define NFS3_createres_sz       (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
  75#define NFS3_renameres_sz       (1+(2 * NFS3_wcc_data_sz))
  76#define NFS3_linkres_sz         (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
  77#define NFS3_readdirres_sz      (1+NFS3_post_op_attr_sz+2)
  78#define NFS3_fsstatres_sz       (1+NFS3_post_op_attr_sz+13)
  79#define NFS3_fsinfores_sz       (1+NFS3_post_op_attr_sz+12)
  80#define NFS3_pathconfres_sz     (1+NFS3_post_op_attr_sz+6)
  81#define NFS3_commitres_sz       (1+NFS3_wcc_data_sz+2)
  82
  83#define ACL3_getaclargs_sz      (NFS3_fh_sz+1)
  84#define ACL3_setaclargs_sz      (NFS3_fh_sz+1+ \
  85                                XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
  86#define ACL3_getaclres_sz       (1+NFS3_post_op_attr_sz+1+ \
  87                                XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
  88#define ACL3_setaclres_sz       (1+NFS3_post_op_attr_sz)
  89
  90/*
  91 * Map file type to S_IFMT bits
  92 */
  93static const umode_t nfs_type2fmt[] = {
  94        [NF3BAD] = 0,
  95        [NF3REG] = S_IFREG,
  96        [NF3DIR] = S_IFDIR,
  97        [NF3BLK] = S_IFBLK,
  98        [NF3CHR] = S_IFCHR,
  99        [NF3LNK] = S_IFLNK,
 100        [NF3SOCK] = S_IFSOCK,
 101        [NF3FIFO] = S_IFIFO,
 102};
 103
 104/*
 105 * Common NFS XDR functions as inlines
 106 */
 107static inline __be32 *
 108xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
 109{
 110        return xdr_encode_array(p, fh->data, fh->size);
 111}
 112
 113static inline __be32 *
 114xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
 115{
 116        if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
 117                memcpy(fh->data, p, fh->size);
 118                return p + XDR_QUADLEN(fh->size);
 119        }
 120        return NULL;
 121}
 122
 123/*
 124 * Encode/decode time.
 125 */
 126static inline __be32 *
 127xdr_encode_time3(__be32 *p, struct timespec *timep)
 128{
 129        *p++ = htonl(timep->tv_sec);
 130        *p++ = htonl(timep->tv_nsec);
 131        return p;
 132}
 133
 134static inline __be32 *
 135xdr_decode_time3(__be32 *p, struct timespec *timep)
 136{
 137        timep->tv_sec = ntohl(*p++);
 138        timep->tv_nsec = ntohl(*p++);
 139        return p;
 140}
 141
 142static __be32 *
 143xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 144{
 145        unsigned int    type, major, minor;
 146        umode_t         fmode;
 147
 148        type = ntohl(*p++);
 149        if (type > NF3FIFO)
 150                type = NF3NON;
 151        fmode = nfs_type2fmt[type];
 152        fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
 153        fattr->nlink = ntohl(*p++);
 154        fattr->uid = ntohl(*p++);
 155        fattr->gid = ntohl(*p++);
 156        p = xdr_decode_hyper(p, &fattr->size);
 157        p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
 158
 159        /* Turn remote device info into Linux-specific dev_t */
 160        major = ntohl(*p++);
 161        minor = ntohl(*p++);
 162        fattr->rdev = MKDEV(major, minor);
 163        if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
 164                fattr->rdev = 0;
 165
 166        p = xdr_decode_hyper(p, &fattr->fsid.major);
 167        fattr->fsid.minor = 0;
 168        p = xdr_decode_hyper(p, &fattr->fileid);
 169        p = xdr_decode_time3(p, &fattr->atime);
 170        p = xdr_decode_time3(p, &fattr->mtime);
 171        p = xdr_decode_time3(p, &fattr->ctime);
 172
 173        /* Update the mode bits */
 174        fattr->valid |= NFS_ATTR_FATTR_V3;
 175        return p;
 176}
 177
 178static inline __be32 *
 179xdr_encode_sattr(__be32 *p, struct iattr *attr)
 180{
 181        if (attr->ia_valid & ATTR_MODE) {
 182                *p++ = xdr_one;
 183                *p++ = htonl(attr->ia_mode & S_IALLUGO);
 184        } else {
 185                *p++ = xdr_zero;
 186        }
 187        if (attr->ia_valid & ATTR_UID) {
 188                *p++ = xdr_one;
 189                *p++ = htonl(attr->ia_uid);
 190        } else {
 191                *p++ = xdr_zero;
 192        }
 193        if (attr->ia_valid & ATTR_GID) {
 194                *p++ = xdr_one;
 195                *p++ = htonl(attr->ia_gid);
 196        } else {
 197                *p++ = xdr_zero;
 198        }
 199        if (attr->ia_valid & ATTR_SIZE) {
 200                *p++ = xdr_one;
 201                p = xdr_encode_hyper(p, (__u64) attr->ia_size);
 202        } else {
 203                *p++ = xdr_zero;
 204        }
 205        if (attr->ia_valid & ATTR_ATIME_SET) {
 206                *p++ = xdr_two;
 207                p = xdr_encode_time3(p, &attr->ia_atime);
 208        } else if (attr->ia_valid & ATTR_ATIME) {
 209                *p++ = xdr_one;
 210        } else {
 211                *p++ = xdr_zero;
 212        }
 213        if (attr->ia_valid & ATTR_MTIME_SET) {
 214                *p++ = xdr_two;
 215                p = xdr_encode_time3(p, &attr->ia_mtime);
 216        } else if (attr->ia_valid & ATTR_MTIME) {
 217                *p++ = xdr_one;
 218        } else {
 219                *p++ = xdr_zero;
 220        }
 221        return p;
 222}
 223
 224static inline __be32 *
 225xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
 226{
 227        p = xdr_decode_hyper(p, &fattr->pre_size);
 228        p = xdr_decode_time3(p, &fattr->pre_mtime);
 229        p = xdr_decode_time3(p, &fattr->pre_ctime);
 230        fattr->valid |= NFS_ATTR_FATTR_PRESIZE
 231                | NFS_ATTR_FATTR_PREMTIME
 232                | NFS_ATTR_FATTR_PRECTIME;
 233        return p;
 234}
 235
 236static inline __be32 *
 237xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
 238{
 239        if (*p++)
 240                p = xdr_decode_fattr(p, fattr);
 241        return p;
 242}
 243
 244static inline __be32 *
 245xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
 246{
 247        if (*p++)
 248                return xdr_decode_wcc_attr(p, fattr);
 249        return p;
 250}
 251
 252
 253static inline __be32 *
 254xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
 255{
 256        p = xdr_decode_pre_op_attr(p, fattr);
 257        return xdr_decode_post_op_attr(p, fattr);
 258}
 259
 260/*
 261 * NFS encode functions
 262 */
 263
 264/*
 265 * Encode file handle argument
 266 */
 267static int
 268nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
 269{
 270        p = xdr_encode_fhandle(p, fh);
 271        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 272        return 0;
 273}
 274
 275/*
 276 * Encode SETATTR arguments
 277 */
 278static int
 279nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
 280{
 281        p = xdr_encode_fhandle(p, args->fh);
 282        p = xdr_encode_sattr(p, args->sattr);
 283        *p++ = htonl(args->guard);
 284        if (args->guard)
 285                p = xdr_encode_time3(p, &args->guardtime);
 286        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 287        return 0;
 288}
 289
 290/*
 291 * Encode directory ops argument
 292 */
 293static int
 294nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
 295{
 296        p = xdr_encode_fhandle(p, args->fh);
 297        p = xdr_encode_array(p, args->name, args->len);
 298        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 299        return 0;
 300}
 301
 302/*
 303 * Encode REMOVE argument
 304 */
 305static int
 306nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
 307{
 308        p = xdr_encode_fhandle(p, args->fh);
 309        p = xdr_encode_array(p, args->name.name, args->name.len);
 310        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 311        return 0;
 312}
 313
 314/*
 315 * Encode access() argument
 316 */
 317static int
 318nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
 319{
 320        p = xdr_encode_fhandle(p, args->fh);
 321        *p++ = htonl(args->access);
 322        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 323        return 0;
 324}
 325
 326/*
 327 * Arguments to a READ call. Since we read data directly into the page
 328 * cache, we also set up the reply iovec here so that iov[1] points
 329 * exactly to the page we want to fetch.
 330 */
 331static int
 332nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 333{
 334        struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
 335        unsigned int replen;
 336        u32 count = args->count;
 337
 338        p = xdr_encode_fhandle(p, args->fh);
 339        p = xdr_encode_hyper(p, args->offset);
 340        *p++ = htonl(count);
 341        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 342
 343        /* Inline the page array */
 344        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
 345        xdr_inline_pages(&req->rq_rcv_buf, replen,
 346                         args->pages, args->pgbase, count);
 347        req->rq_rcv_buf.flags |= XDRBUF_READ;
 348        return 0;
 349}
 350
 351/*
 352 * Write arguments. Splice the buffer to be written into the iovec.
 353 */
 354static int
 355nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 356{
 357        struct xdr_buf *sndbuf = &req->rq_snd_buf;
 358        u32 count = args->count;
 359
 360        p = xdr_encode_fhandle(p, args->fh);
 361        p = xdr_encode_hyper(p, args->offset);
 362        *p++ = htonl(count);
 363        *p++ = htonl(args->stable);
 364        *p++ = htonl(count);
 365        sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 366
 367        /* Copy the page array */
 368        xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 369        sndbuf->flags |= XDRBUF_WRITE;
 370        return 0;
 371}
 372
 373/*
 374 * Encode CREATE arguments
 375 */
 376static int
 377nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
 378{
 379        p = xdr_encode_fhandle(p, args->fh);
 380        p = xdr_encode_array(p, args->name, args->len);
 381
 382        *p++ = htonl(args->createmode);
 383        if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
 384                *p++ = args->verifier[0];
 385                *p++ = args->verifier[1];
 386        } else
 387                p = xdr_encode_sattr(p, args->sattr);
 388
 389        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 390        return 0;
 391}
 392
 393/*
 394 * Encode MKDIR arguments
 395 */
 396static int
 397nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
 398{
 399        p = xdr_encode_fhandle(p, args->fh);
 400        p = xdr_encode_array(p, args->name, args->len);
 401        p = xdr_encode_sattr(p, args->sattr);
 402        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 403        return 0;
 404}
 405
 406/*
 407 * Encode SYMLINK arguments
 408 */
 409static int
 410nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
 411{
 412        p = xdr_encode_fhandle(p, args->fromfh);
 413        p = xdr_encode_array(p, args->fromname, args->fromlen);
 414        p = xdr_encode_sattr(p, args->sattr);
 415        *p++ = htonl(args->pathlen);
 416        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 417
 418        /* Copy the page */
 419        xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
 420        return 0;
 421}
 422
 423/*
 424 * Encode MKNOD arguments
 425 */
 426static int
 427nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
 428{
 429        p = xdr_encode_fhandle(p, args->fh);
 430        p = xdr_encode_array(p, args->name, args->len);
 431        *p++ = htonl(args->type);
 432        p = xdr_encode_sattr(p, args->sattr);
 433        if (args->type == NF3CHR || args->type == NF3BLK) {
 434                *p++ = htonl(MAJOR(args->rdev));
 435                *p++ = htonl(MINOR(args->rdev));
 436        }
 437
 438        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 439        return 0;
 440}
 441
 442/*
 443 * Encode RENAME arguments
 444 */
 445static int
 446nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
 447{
 448        p = xdr_encode_fhandle(p, args->fromfh);
 449        p = xdr_encode_array(p, args->fromname, args->fromlen);
 450        p = xdr_encode_fhandle(p, args->tofh);
 451        p = xdr_encode_array(p, args->toname, args->tolen);
 452        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 453        return 0;
 454}
 455
 456/*
 457 * Encode LINK arguments
 458 */
 459static int
 460nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
 461{
 462        p = xdr_encode_fhandle(p, args->fromfh);
 463        p = xdr_encode_fhandle(p, args->tofh);
 464        p = xdr_encode_array(p, args->toname, args->tolen);
 465        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 466        return 0;
 467}
 468
 469/*
 470 * Encode arguments to readdir call
 471 */
 472static int
 473nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
 474{
 475        struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
 476        unsigned int replen;
 477        u32 count = args->count;
 478
 479        p = xdr_encode_fhandle(p, args->fh);
 480        p = xdr_encode_hyper(p, args->cookie);
 481        *p++ = args->verf[0];
 482        *p++ = args->verf[1];
 483        if (args->plus) {
 484                /* readdirplus: need dircount + buffer size.
 485                 * We just make sure we make dircount big enough */
 486                *p++ = htonl(count >> 3);
 487        }
 488        *p++ = htonl(count);
 489        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 490
 491        /* Inline the page array */
 492        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
 493        xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 494        return 0;
 495}
 496
 497/*
 498 * Decode the result of a readdir call.
 499 * We just check for syntactical correctness.
 500 */
 501static int
 502nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
 503{
 504        struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 505        struct kvec *iov = rcvbuf->head;
 506        struct page **page;
 507        size_t hdrlen;
 508        u32 len, recvd, pglen;
 509        int status, nr = 0;
 510        __be32 *entry, *end, *kaddr;
 511
 512        status = ntohl(*p++);
 513        /* Decode post_op_attrs */
 514        p = xdr_decode_post_op_attr(p, res->dir_attr);
 515        if (status)
 516                return nfs_stat_to_errno(status);
 517        /* Decode verifier cookie */
 518        if (res->verf) {
 519                res->verf[0] = *p++;
 520                res->verf[1] = *p++;
 521        } else {
 522                p += 2;
 523        }
 524
 525        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 526        if (iov->iov_len < hdrlen) {
 527                dprintk("NFS: READDIR reply header overflowed:"
 528                                "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 529                return -errno_NFSERR_IO;
 530        } else if (iov->iov_len != hdrlen) {
 531                dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
 532                xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 533        }
 534
 535        pglen = rcvbuf->page_len;
 536        recvd = rcvbuf->len - hdrlen;
 537        if (pglen > recvd)
 538                pglen = recvd;
 539        page = rcvbuf->pages;
 540        kaddr = p = kmap_atomic(*page, KM_USER0);
 541        end = (__be32 *)((char *)p + pglen);
 542        entry = p;
 543
 544        /* Make sure the packet actually has a value_follows and EOF entry */
 545        if ((entry + 1) > end)
 546                goto short_pkt;
 547
 548        for (; *p++; nr++) {
 549                if (p + 3 > end)
 550                        goto short_pkt;
 551                p += 2;                         /* inode # */
 552                len = ntohl(*p++);              /* string length */
 553                p += XDR_QUADLEN(len) + 2;      /* name + cookie */
 554                if (len > NFS3_MAXNAMLEN) {
 555                        dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
 556                                                len);
 557                        goto err_unmap;
 558                }
 559
 560                if (res->plus) {
 561                        /* post_op_attr */
 562                        if (p + 2 > end)
 563                                goto short_pkt;
 564                        if (*p++) {
 565                                p += 21;
 566                                if (p + 1 > end)
 567                                        goto short_pkt;
 568                        }
 569                        /* post_op_fh3 */
 570                        if (*p++) {
 571                                if (p + 1 > end)
 572                                        goto short_pkt;
 573                                len = ntohl(*p++);
 574                                if (len > NFS3_FHSIZE) {
 575                                        dprintk("NFS: giant filehandle in "
 576                                                "readdir (len 0x%x)!\n", len);
 577                                        goto err_unmap;
 578                                }
 579                                p += XDR_QUADLEN(len);
 580                        }
 581                }
 582
 583                if (p + 2 > end)
 584                        goto short_pkt;
 585                entry = p;
 586        }
 587
 588        /*
 589         * Apparently some server sends responses that are a valid size, but
 590         * contain no entries, and have value_follows==0 and EOF==0. For
 591         * those, just set the EOF marker.
 592         */
 593        if (!nr && entry[1] == 0) {
 594                dprintk("NFS: readdir reply truncated!\n");
 595                entry[1] = 1;
 596        }
 597 out:
 598        kunmap_atomic(kaddr, KM_USER0);
 599        return nr;
 600 short_pkt:
 601        /*
 602         * When we get a short packet there are 2 possibilities. We can
 603         * return an error, or fix up the response to look like a valid
 604         * response and return what we have so far. If there are no
 605         * entries and the packet was short, then return -EIO. If there
 606         * are valid entries in the response, return them and pretend that
 607         * the call was successful, but incomplete. The caller can retry the
 608         * readdir starting at the last cookie.
 609         */
 610        entry[0] = entry[1] = 0;
 611        if (!nr)
 612                nr = -errno_NFSERR_IO;
 613        goto out;
 614err_unmap:
 615        nr = -errno_NFSERR_IO;
 616        goto out;
 617}
 618
 619__be32 *
 620nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
 621{
 622        struct nfs_entry old = *entry;
 623
 624        if (!*p++) {
 625                if (!*p)
 626                        return ERR_PTR(-EAGAIN);
 627                entry->eof = 1;
 628                return ERR_PTR(-EBADCOOKIE);
 629        }
 630
 631        p = xdr_decode_hyper(p, &entry->ino);
 632        entry->len  = ntohl(*p++);
 633        entry->name = (const char *) p;
 634        p += XDR_QUADLEN(entry->len);
 635        entry->prev_cookie = entry->cookie;
 636        p = xdr_decode_hyper(p, &entry->cookie);
 637
 638        if (plus) {
 639                entry->fattr->valid = 0;
 640                p = xdr_decode_post_op_attr(p, entry->fattr);
 641                /* In fact, a post_op_fh3: */
 642                if (*p++) {
 643                        p = xdr_decode_fhandle(p, entry->fh);
 644                        /* Ugh -- server reply was truncated */
 645                        if (p == NULL) {
 646                                dprintk("NFS: FH truncated\n");
 647                                *entry = old;
 648                                return ERR_PTR(-EAGAIN);
 649                        }
 650                } else
 651                        memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
 652        }
 653
 654        entry->eof = !p[0] && p[1];
 655        return p;
 656}
 657
 658/*
 659 * Encode COMMIT arguments
 660 */
 661static int
 662nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 663{
 664        p = xdr_encode_fhandle(p, args->fh);
 665        p = xdr_encode_hyper(p, args->offset);
 666        *p++ = htonl(args->count);
 667        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 668        return 0;
 669}
 670
 671#ifdef CONFIG_NFS_V3_ACL
 672/*
 673 * Encode GETACL arguments
 674 */
 675static int
 676nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
 677                    struct nfs3_getaclargs *args)
 678{
 679        struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
 680        unsigned int replen;
 681
 682        p = xdr_encode_fhandle(p, args->fh);
 683        *p++ = htonl(args->mask);
 684        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 685
 686        if (args->mask & (NFS_ACL | NFS_DFACL)) {
 687                /* Inline the page array */
 688                replen = (RPC_REPHDRSIZE + auth->au_rslack +
 689                          ACL3_getaclres_sz) << 2;
 690                xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
 691                                 NFSACL_MAXPAGES << PAGE_SHIFT);
 692        }
 693        return 0;
 694}
 695
 696/*
 697 * Encode SETACL arguments
 698 */
 699static int
 700nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
 701                   struct nfs3_setaclargs *args)
 702{
 703        struct xdr_buf *buf = &req->rq_snd_buf;
 704        unsigned int base;
 705        int err;
 706
 707        p = xdr_encode_fhandle(p, NFS_FH(args->inode));
 708        *p++ = htonl(args->mask);
 709        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 710        base = req->rq_slen;
 711
 712        if (args->npages != 0)
 713                xdr_encode_pages(buf, args->pages, 0, args->len);
 714        else
 715                req->rq_slen = xdr_adjust_iovec(req->rq_svec,
 716                                p + XDR_QUADLEN(args->len));
 717
 718        err = nfsacl_encode(buf, base, args->inode,
 719                            (args->mask & NFS_ACL) ?
 720                            args->acl_access : NULL, 1, 0);
 721        if (err > 0)
 722                err = nfsacl_encode(buf, base + err, args->inode,
 723                                    (args->mask & NFS_DFACL) ?
 724                                    args->acl_default : NULL, 1,
 725                                    NFS_ACL_DEFAULT);
 726        return (err > 0) ? 0 : err;
 727}
 728#endif  /* CONFIG_NFS_V3_ACL */
 729
 730/*
 731 * NFS XDR decode functions
 732 */
 733
 734/*
 735 * Decode attrstat reply.
 736 */
 737static int
 738nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 739{
 740        int     status;
 741
 742        if ((status = ntohl(*p++)))
 743                return nfs_stat_to_errno(status);
 744        xdr_decode_fattr(p, fattr);
 745        return 0;
 746}
 747
 748/*
 749 * Decode status+wcc_data reply
 750 * SATTR, REMOVE, RMDIR
 751 */
 752static int
 753nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 754{
 755        int     status;
 756
 757        if ((status = ntohl(*p++)))
 758                status = nfs_stat_to_errno(status);
 759        xdr_decode_wcc_data(p, fattr);
 760        return status;
 761}
 762
 763static int
 764nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
 765{
 766        return nfs3_xdr_wccstat(req, p, &res->dir_attr);
 767}
 768
 769/*
 770 * Decode LOOKUP reply
 771 */
 772static int
 773nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
 774{
 775        int     status;
 776
 777        if ((status = ntohl(*p++))) {
 778                status = nfs_stat_to_errno(status);
 779        } else {
 780                if (!(p = xdr_decode_fhandle(p, res->fh)))
 781                        return -errno_NFSERR_IO;
 782                p = xdr_decode_post_op_attr(p, res->fattr);
 783        }
 784        xdr_decode_post_op_attr(p, res->dir_attr);
 785        return status;
 786}
 787
 788/*
 789 * Decode ACCESS reply
 790 */
 791static int
 792nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
 793{
 794        int     status = ntohl(*p++);
 795
 796        p = xdr_decode_post_op_attr(p, res->fattr);
 797        if (status)
 798                return nfs_stat_to_errno(status);
 799        res->access = ntohl(*p++);
 800        return 0;
 801}
 802
 803static int
 804nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
 805{
 806        struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
 807        unsigned int replen;
 808
 809        p = xdr_encode_fhandle(p, args->fh);
 810        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 811
 812        /* Inline the page array */
 813        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
 814        xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
 815        return 0;
 816}
 817
 818/*
 819 * Decode READLINK reply
 820 */
 821static int
 822nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 823{
 824        struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 825        struct kvec *iov = rcvbuf->head;
 826        size_t hdrlen;
 827        u32 len, recvd;
 828        char    *kaddr;
 829        int     status;
 830
 831        status = ntohl(*p++);
 832        p = xdr_decode_post_op_attr(p, fattr);
 833
 834        if (status != 0)
 835                return nfs_stat_to_errno(status);
 836
 837        /* Convert length of symlink */
 838        len = ntohl(*p++);
 839        if (len >= rcvbuf->page_len) {
 840                dprintk("nfs: server returned giant symlink!\n");
 841                return -ENAMETOOLONG;
 842        }
 843
 844        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 845        if (iov->iov_len < hdrlen) {
 846                dprintk("NFS: READLINK reply header overflowed:"
 847                                "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 848                return -errno_NFSERR_IO;
 849        } else if (iov->iov_len != hdrlen) {
 850                dprintk("NFS: READLINK header is short. "
 851                        "iovec will be shifted.\n");
 852                xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 853        }
 854        recvd = req->rq_rcv_buf.len - hdrlen;
 855        if (recvd < len) {
 856                dprintk("NFS: server cheating in readlink reply: "
 857                                "count %u > recvd %u\n", len, recvd);
 858                return -EIO;
 859        }
 860
 861        /* NULL terminate the string we got */
 862        kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
 863        kaddr[len+rcvbuf->page_base] = '\0';
 864        kunmap_atomic(kaddr, KM_USER0);
 865        return 0;
 866}
 867
 868/*
 869 * Decode READ reply
 870 */
 871static int
 872nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 873{
 874        struct kvec *iov = req->rq_rcv_buf.head;
 875        size_t hdrlen;
 876        u32 count, ocount, recvd;
 877        int status;
 878
 879        status = ntohl(*p++);
 880        p = xdr_decode_post_op_attr(p, res->fattr);
 881
 882        if (status != 0)
 883                return nfs_stat_to_errno(status);
 884
 885        /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
 886         * in that it puts the count both in the res struct and in the
 887         * opaque data count. */
 888        count    = ntohl(*p++);
 889        res->eof = ntohl(*p++);
 890        ocount   = ntohl(*p++);
 891
 892        if (ocount != count) {
 893                dprintk("NFS: READ count doesn't match RPC opaque count.\n");
 894                return -errno_NFSERR_IO;
 895        }
 896
 897        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 898        if (iov->iov_len < hdrlen) {
 899                dprintk("NFS: READ reply header overflowed:"
 900                                "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 901                return -errno_NFSERR_IO;
 902        } else if (iov->iov_len != hdrlen) {
 903                dprintk("NFS: READ header is short. iovec will be shifted.\n");
 904                xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 905        }
 906
 907        recvd = req->rq_rcv_buf.len - hdrlen;
 908        if (count > recvd) {
 909                dprintk("NFS: server cheating in read reply: "
 910                        "count %u > recvd %u\n", count, recvd);
 911                count = recvd;
 912                res->eof = 0;
 913        }
 914
 915        if (count < res->count)
 916                res->count = count;
 917
 918        return count;
 919}
 920
 921/*
 922 * Decode WRITE response
 923 */
 924static int
 925nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 926{
 927        int     status;
 928
 929        status = ntohl(*p++);
 930        p = xdr_decode_wcc_data(p, res->fattr);
 931
 932        if (status != 0)
 933                return nfs_stat_to_errno(status);
 934
 935        res->count = ntohl(*p++);
 936        res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
 937        res->verf->verifier[0] = *p++;
 938        res->verf->verifier[1] = *p++;
 939
 940        return res->count;
 941}
 942
 943/*
 944 * Decode a CREATE response
 945 */
 946static int
 947nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
 948{
 949        int     status;
 950
 951        status = ntohl(*p++);
 952        if (status == 0) {
 953                if (*p++) {
 954                        if (!(p = xdr_decode_fhandle(p, res->fh)))
 955                                return -errno_NFSERR_IO;
 956                        p = xdr_decode_post_op_attr(p, res->fattr);
 957                } else {
 958                        memset(res->fh, 0, sizeof(*res->fh));
 959                        /* Do decode post_op_attr but set it to NULL */
 960                        p = xdr_decode_post_op_attr(p, res->fattr);
 961                        res->fattr->valid = 0;
 962                }
 963        } else {
 964                status = nfs_stat_to_errno(status);
 965        }
 966        p = xdr_decode_wcc_data(p, res->dir_attr);
 967        return status;
 968}
 969
 970/*
 971 * Decode RENAME reply
 972 */
 973static int
 974nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
 975{
 976        int     status;
 977
 978        if ((status = ntohl(*p++)) != 0)
 979                status = nfs_stat_to_errno(status);
 980        p = xdr_decode_wcc_data(p, res->fromattr);
 981        p = xdr_decode_wcc_data(p, res->toattr);
 982        return status;
 983}
 984
 985/*
 986 * Decode LINK reply
 987 */
 988static int
 989nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
 990{
 991        int     status;
 992
 993        if ((status = ntohl(*p++)) != 0)
 994                status = nfs_stat_to_errno(status);
 995        p = xdr_decode_post_op_attr(p, res->fattr);
 996        p = xdr_decode_wcc_data(p, res->dir_attr);
 997        return status;
 998}
 999
1000/*
1001 * Decode FSSTAT reply
1002 */
1003static int
1004nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1005{
1006        int             status;
1007
1008        status = ntohl(*p++);
1009
1010        p = xdr_decode_post_op_attr(p, res->fattr);
1011        if (status != 0)
1012                return nfs_stat_to_errno(status);
1013
1014        p = xdr_decode_hyper(p, &res->tbytes);
1015        p = xdr_decode_hyper(p, &res->fbytes);
1016        p = xdr_decode_hyper(p, &res->abytes);
1017        p = xdr_decode_hyper(p, &res->tfiles);
1018        p = xdr_decode_hyper(p, &res->ffiles);
1019        p = xdr_decode_hyper(p, &res->afiles);
1020
1021        /* ignore invarsec */
1022        return 0;
1023}
1024
1025/*
1026 * Decode FSINFO reply
1027 */
1028static int
1029nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1030{
1031        int             status;
1032
1033        status = ntohl(*p++);
1034
1035        p = xdr_decode_post_op_attr(p, res->fattr);
1036        if (status != 0)
1037                return nfs_stat_to_errno(status);
1038
1039        res->rtmax  = ntohl(*p++);
1040        res->rtpref = ntohl(*p++);
1041        res->rtmult = ntohl(*p++);
1042        res->wtmax  = ntohl(*p++);
1043        res->wtpref = ntohl(*p++);
1044        res->wtmult = ntohl(*p++);
1045        res->dtpref = ntohl(*p++);
1046        p = xdr_decode_hyper(p, &res->maxfilesize);
1047
1048        /* ignore time_delta and properties */
1049        res->lease_time = 0;
1050        return 0;
1051}
1052
1053/*
1054 * Decode PATHCONF reply
1055 */
1056static int
1057nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1058{
1059        int             status;
1060
1061        status = ntohl(*p++);
1062
1063        p = xdr_decode_post_op_attr(p, res->fattr);
1064        if (status != 0)
1065                return nfs_stat_to_errno(status);
1066        res->max_link = ntohl(*p++);
1067        res->max_namelen = ntohl(*p++);
1068
1069        /* ignore remaining fields */
1070        return 0;
1071}
1072
1073/*
1074 * Decode COMMIT reply
1075 */
1076static int
1077nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1078{
1079        int             status;
1080
1081        status = ntohl(*p++);
1082        p = xdr_decode_wcc_data(p, res->fattr);
1083        if (status != 0)
1084                return nfs_stat_to_errno(status);
1085
1086        res->verf->verifier[0] = *p++;
1087        res->verf->verifier[1] = *p++;
1088        return 0;
1089}
1090
1091#ifdef CONFIG_NFS_V3_ACL
1092/*
1093 * Decode GETACL reply
1094 */
1095static int
1096nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1097                   struct nfs3_getaclres *res)
1098{
1099        struct xdr_buf *buf = &req->rq_rcv_buf;
1100        int status = ntohl(*p++);
1101        struct posix_acl **acl;
1102        unsigned int *aclcnt;
1103        int err, base;
1104
1105        if (status != 0)
1106                return nfs_stat_to_errno(status);
1107        p = xdr_decode_post_op_attr(p, res->fattr);
1108        res->mask = ntohl(*p++);
1109        if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1110                return -EINVAL;
1111        base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1112
1113        acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1114        aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1115        err = nfsacl_decode(buf, base, aclcnt, acl);
1116
1117        acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1118        aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1119        if (err > 0)
1120                err = nfsacl_decode(buf, base + err, aclcnt, acl);
1121        return (err > 0) ? 0 : err;
1122}
1123
1124/*
1125 * Decode setacl reply.
1126 */
1127static int
1128nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1129{
1130        int status = ntohl(*p++);
1131
1132        if (status)
1133                return nfs_stat_to_errno(status);
1134        xdr_decode_post_op_attr(p, fattr);
1135        return 0;
1136}
1137#endif  /* CONFIG_NFS_V3_ACL */
1138
1139#define PROC(proc, argtype, restype, timer)                             \
1140[NFS3PROC_##proc] = {                                                   \
1141        .p_proc      = NFS3PROC_##proc,                                 \
1142        .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,                 \
1143        .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,                 \
1144        .p_arglen    = NFS3_##argtype##_sz,                             \
1145        .p_replen    = NFS3_##restype##_sz,                             \
1146        .p_timer     = timer,                                           \
1147        .p_statidx   = NFS3PROC_##proc,                                 \
1148        .p_name      = #proc,                                           \
1149        }
1150
1151struct rpc_procinfo     nfs3_procedures[] = {
1152  PROC(GETATTR,         fhandle,        attrstat, 1),
1153  PROC(SETATTR,         sattrargs,      wccstat, 0),
1154  PROC(LOOKUP,          diropargs,      lookupres, 2),
1155  PROC(ACCESS,          accessargs,     accessres, 1),
1156  PROC(READLINK,        readlinkargs,   readlinkres, 3),
1157  PROC(READ,            readargs,       readres, 3),
1158  PROC(WRITE,           writeargs,      writeres, 4),
1159  PROC(CREATE,          createargs,     createres, 0),
1160  PROC(MKDIR,           mkdirargs,      createres, 0),
1161  PROC(SYMLINK,         symlinkargs,    createres, 0),
1162  PROC(MKNOD,           mknodargs,      createres, 0),
1163  PROC(REMOVE,          removeargs,     removeres, 0),
1164  PROC(RMDIR,           diropargs,      wccstat, 0),
1165  PROC(RENAME,          renameargs,     renameres, 0),
1166  PROC(LINK,            linkargs,       linkres, 0),
1167  PROC(READDIR,         readdirargs,    readdirres, 3),
1168  PROC(READDIRPLUS,     readdirargs,    readdirres, 3),
1169  PROC(FSSTAT,          fhandle,        fsstatres, 0),
1170  PROC(FSINFO,          fhandle,        fsinfores, 0),
1171  PROC(PATHCONF,        fhandle,        pathconfres, 0),
1172  PROC(COMMIT,          commitargs,     commitres, 5),
1173};
1174
1175struct rpc_version              nfs_version3 = {
1176        .number                 = 3,
1177        .nrprocs                = ARRAY_SIZE(nfs3_procedures),
1178        .procs                  = nfs3_procedures
1179};
1180
1181#ifdef CONFIG_NFS_V3_ACL
1182static struct rpc_procinfo      nfs3_acl_procedures[] = {
1183        [ACLPROC3_GETACL] = {
1184                .p_proc = ACLPROC3_GETACL,
1185                .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1186                .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1187                .p_arglen = ACL3_getaclargs_sz,
1188                .p_replen = ACL3_getaclres_sz,
1189                .p_timer = 1,
1190                .p_name = "GETACL",
1191        },
1192        [ACLPROC3_SETACL] = {
1193                .p_proc = ACLPROC3_SETACL,
1194                .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1195                .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1196                .p_arglen = ACL3_setaclargs_sz,
1197                .p_replen = ACL3_setaclres_sz,
1198                .p_timer = 0,
1199                .p_name = "SETACL",
1200        },
1201};
1202
1203struct rpc_version              nfsacl_version3 = {
1204        .number                 = 3,
1205        .nrprocs                = sizeof(nfs3_acl_procedures)/
1206                                  sizeof(nfs3_acl_procedures[0]),
1207        .procs                  = nfs3_acl_procedures,
1208};
1209#endif  /* CONFIG_NFS_V3_ACL */
1210