linux-bk/fs/nfs/nfs2xdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfs/nfs2xdr.c
   3 *
   4 * XDR functions to encode/decode NFS RPC arguments and results.
   5 *
   6 * Copyright (C) 1992, 1993, 1994  Rick Sladkey
   7 * Copyright (C) 1996 Olaf Kirch
   8 * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
   9 *              FIFO's need special handling in NFSv2
  10 */
  11
  12#include <linux/param.h>
  13#include <linux/time.h>
  14#include <linux/mm.h>
  15#include <linux/slab.h>
  16#include <linux/utsname.h>
  17#include <linux/errno.h>
  18#include <linux/string.h>
  19#include <linux/in.h>
  20#include <linux/pagemap.h>
  21#include <linux/proc_fs.h>
  22#include <linux/sunrpc/clnt.h>
  23#include <linux/nfs.h>
  24#include <linux/nfs2.h>
  25#include <linux/nfs_fs.h>
  26
  27#define NFSDBG_FACILITY         NFSDBG_XDR
  28/* #define NFS_PARANOIA 1 */
  29
  30extern int                      nfs_stat_to_errno(int stat);
  31
  32/* Mapping from NFS error code to "errno" error code. */
  33#define errno_NFSERR_IO         EIO
  34
  35/*
  36 * Declare the space requirements for NFS arguments and replies as
  37 * number of 32bit-words
  38 */
  39#define NFS_fhandle_sz          (8)
  40#define NFS_sattr_sz            (8)
  41#define NFS_filename_sz         (1+(NFS2_MAXNAMLEN>>2))
  42#define NFS_path_sz             (1+(NFS2_MAXPATHLEN>>2))
  43#define NFS_fattr_sz            (17)
  44#define NFS_info_sz             (5)
  45#define NFS_entry_sz            (NFS_filename_sz+3)
  46
  47#define NFS_diropargs_sz        (NFS_fhandle_sz+NFS_filename_sz)
  48#define NFS_sattrargs_sz        (NFS_fhandle_sz+NFS_sattr_sz)
  49#define NFS_readlinkargs_sz     (NFS_fhandle_sz)
  50#define NFS_readargs_sz         (NFS_fhandle_sz+3)
  51#define NFS_writeargs_sz        (NFS_fhandle_sz+4)
  52#define NFS_createargs_sz       (NFS_diropargs_sz+NFS_sattr_sz)
  53#define NFS_renameargs_sz       (NFS_diropargs_sz+NFS_diropargs_sz)
  54#define NFS_linkargs_sz         (NFS_fhandle_sz+NFS_diropargs_sz)
  55#define NFS_symlinkargs_sz      (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
  56#define NFS_readdirargs_sz      (NFS_fhandle_sz+2)
  57
  58#define NFS_attrstat_sz         (1+NFS_fattr_sz)
  59#define NFS_diropres_sz         (1+NFS_fhandle_sz+NFS_fattr_sz)
  60#define NFS_readlinkres_sz      (2)
  61#define NFS_readres_sz          (1+NFS_fattr_sz+1)
  62#define NFS_writeres_sz         (NFS_attrstat_sz)
  63#define NFS_stat_sz             (1)
  64#define NFS_readdirres_sz       (1)
  65#define NFS_statfsres_sz        (1+NFS_info_sz)
  66
  67/*
  68 * Common NFS XDR functions as inlines
  69 */
  70static inline u32 *
  71xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
  72{
  73        memcpy(p, fhandle->data, NFS2_FHSIZE);
  74        return p + XDR_QUADLEN(NFS2_FHSIZE);
  75}
  76
  77static inline u32 *
  78xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
  79{
  80        /* NFSv2 handles have a fixed length */
  81        fhandle->size = NFS2_FHSIZE;
  82        memcpy(fhandle->data, p, NFS2_FHSIZE);
  83        return p + XDR_QUADLEN(NFS2_FHSIZE);
  84}
  85
  86static inline u32*
  87xdr_encode_time(u32 *p, struct timespec *timep)
  88{
  89        *p++ = htonl(timep->tv_sec);
  90        /* Convert nanoseconds into microseconds */
  91        *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
  92        return p;
  93}
  94
  95static inline u32*
  96xdr_encode_current_server_time(u32 *p, struct timespec *timep)
  97{
  98        /*
  99         * Passing the invalid value useconds=1000000 is a
 100         * Sun convention for "set to current server time".
 101         * It's needed to make permissions checks for the
 102         * "touch" program across v2 mounts to Solaris and
 103         * Irix boxes work correctly. See description of
 104         * sattr in section 6.1 of "NFS Illustrated" by
 105         * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
 106         */
 107        *p++ = htonl(timep->tv_sec);
 108        *p++ = htonl(1000000);
 109        return p;
 110}
 111
 112static inline u32*
 113xdr_decode_time(u32 *p, struct timespec *timep)
 114{
 115        timep->tv_sec = ntohl(*p++);
 116        /* Convert microseconds into nanoseconds */
 117        timep->tv_nsec = ntohl(*p++) * 1000;
 118        return p;
 119}
 120
 121static u32 *
 122xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 123{
 124        u32 rdev;
 125        fattr->type = (enum nfs_ftype) ntohl(*p++);
 126        fattr->mode = ntohl(*p++);
 127        fattr->nlink = ntohl(*p++);
 128        fattr->uid = ntohl(*p++);
 129        fattr->gid = ntohl(*p++);
 130        fattr->size = ntohl(*p++);
 131        fattr->du.nfs2.blocksize = ntohl(*p++);
 132        rdev = ntohl(*p++);
 133        fattr->du.nfs2.blocks = ntohl(*p++);
 134        fattr->fsid_u.nfs3 = ntohl(*p++);
 135        fattr->fileid = ntohl(*p++);
 136        p = xdr_decode_time(p, &fattr->atime);
 137        p = xdr_decode_time(p, &fattr->mtime);
 138        p = xdr_decode_time(p, &fattr->ctime);
 139        fattr->valid |= NFS_ATTR_FATTR;
 140        fattr->rdev = new_decode_dev(rdev);
 141        if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
 142                fattr->type = NFFIFO;
 143                fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
 144                fattr->rdev = 0;
 145        }
 146        fattr->timestamp = jiffies;
 147        return p;
 148}
 149
 150#define SATTR(p, attr, flag, field) \
 151        *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
 152static inline u32 *
 153xdr_encode_sattr(u32 *p, struct iattr *attr)
 154{
 155        SATTR(p, attr, ATTR_MODE, ia_mode);
 156        SATTR(p, attr, ATTR_UID, ia_uid);
 157        SATTR(p, attr, ATTR_GID, ia_gid);
 158        SATTR(p, attr, ATTR_SIZE, ia_size);
 159
 160        if (attr->ia_valid & ATTR_ATIME_SET) {
 161                p = xdr_encode_time(p, &attr->ia_atime);
 162        } else if (attr->ia_valid & ATTR_ATIME) {
 163                p = xdr_encode_current_server_time(p, &attr->ia_atime);
 164        } else {
 165                *p++ = ~(u32) 0;
 166                *p++ = ~(u32) 0;
 167        }
 168
 169        if (attr->ia_valid & ATTR_MTIME_SET) {
 170                p = xdr_encode_time(p, &attr->ia_mtime);
 171        } else if (attr->ia_valid & ATTR_MTIME) {
 172                p = xdr_encode_current_server_time(p, &attr->ia_mtime);
 173        } else {
 174                *p++ = ~(u32) 0;        
 175                *p++ = ~(u32) 0;
 176        }
 177        return p;
 178}
 179#undef SATTR
 180
 181/*
 182 * NFS encode functions
 183 */
 184/*
 185 * Encode file handle argument
 186 * GETATTR, READLINK, STATFS
 187 */
 188static int
 189nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
 190{
 191        p = xdr_encode_fhandle(p, fh);
 192        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 193        return 0;
 194}
 195
 196/*
 197 * Encode SETATTR arguments
 198 */
 199static int
 200nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
 201{
 202        p = xdr_encode_fhandle(p, args->fh);
 203        p = xdr_encode_sattr(p, args->sattr);
 204        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 205        return 0;
 206}
 207
 208/*
 209 * Encode directory ops argument
 210 * LOOKUP, REMOVE, RMDIR
 211 */
 212static int
 213nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
 214{
 215        p = xdr_encode_fhandle(p, args->fh);
 216        p = xdr_encode_array(p, args->name, args->len);
 217        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 218        return 0;
 219}
 220
 221/*
 222 * Arguments to a READ call. Since we read data directly into the page
 223 * cache, we also set up the reply iovec here so that iov[1] points
 224 * exactly to the page we want to fetch.
 225 */
 226static int
 227nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 228{
 229        struct rpc_auth *auth = req->rq_task->tk_auth;
 230        unsigned int replen;
 231        u32 offset = (u32)args->offset;
 232        u32 count = args->count;
 233
 234        p = xdr_encode_fhandle(p, args->fh);
 235        *p++ = htonl(offset);
 236        *p++ = htonl(count);
 237        *p++ = htonl(count);
 238        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 239
 240        /* Inline the page array */
 241        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
 242        xdr_inline_pages(&req->rq_rcv_buf, replen,
 243                         args->pages, args->pgbase, count);
 244        return 0;
 245}
 246
 247/*
 248 * Decode READ reply
 249 */
 250static int
 251nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 252{
 253        struct kvec *iov = req->rq_rcv_buf.head;
 254        int     status, count, recvd, hdrlen;
 255
 256        if ((status = ntohl(*p++)))
 257                return -nfs_stat_to_errno(status);
 258        p = xdr_decode_fattr(p, res->fattr);
 259
 260        count = ntohl(*p++);
 261        res->eof = 0;
 262        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 263        if (iov->iov_len < hdrlen) {
 264                printk(KERN_WARNING "NFS: READ reply header overflowed:"
 265                                "length %d > %Zu\n", hdrlen, iov->iov_len);
 266                return -errno_NFSERR_IO;
 267        } else if (iov->iov_len != hdrlen) {
 268                dprintk("NFS: READ header is short. iovec will be shifted.\n");
 269                xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 270        }
 271
 272        recvd = req->rq_rcv_buf.len - hdrlen;
 273        if (count > recvd) {
 274                printk(KERN_WARNING "NFS: server cheating in read reply: "
 275                        "count %d > recvd %d\n", count, recvd);
 276                count = recvd;
 277        }
 278
 279        dprintk("RPC:      readres OK count %d\n", count);
 280        if (count < res->count)
 281                res->count = count;
 282
 283        return count;
 284}
 285
 286
 287/*
 288 * Write arguments. Splice the buffer to be written into the iovec.
 289 */
 290static int
 291nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 292{
 293        struct xdr_buf *sndbuf = &req->rq_snd_buf;
 294        u32 offset = (u32)args->offset;
 295        u32 count = args->count;
 296
 297        p = xdr_encode_fhandle(p, args->fh);
 298        *p++ = htonl(offset);
 299        *p++ = htonl(offset);
 300        *p++ = htonl(count);
 301        *p++ = htonl(count);
 302        sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 303
 304        /* Copy the page array */
 305        xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 306        return 0;
 307}
 308
 309/*
 310 * Encode create arguments
 311 * CREATE, MKDIR
 312 */
 313static int
 314nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
 315{
 316        p = xdr_encode_fhandle(p, args->fh);
 317        p = xdr_encode_array(p, args->name, args->len);
 318        p = xdr_encode_sattr(p, args->sattr);
 319        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 320        return 0;
 321}
 322
 323/*
 324 * Encode RENAME arguments
 325 */
 326static int
 327nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
 328{
 329        p = xdr_encode_fhandle(p, args->fromfh);
 330        p = xdr_encode_array(p, args->fromname, args->fromlen);
 331        p = xdr_encode_fhandle(p, args->tofh);
 332        p = xdr_encode_array(p, args->toname, args->tolen);
 333        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 334        return 0;
 335}
 336
 337/*
 338 * Encode LINK arguments
 339 */
 340static int
 341nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
 342{
 343        p = xdr_encode_fhandle(p, args->fromfh);
 344        p = xdr_encode_fhandle(p, args->tofh);
 345        p = xdr_encode_array(p, args->toname, args->tolen);
 346        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 347        return 0;
 348}
 349
 350/*
 351 * Encode SYMLINK arguments
 352 */
 353static int
 354nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
 355{
 356        p = xdr_encode_fhandle(p, args->fromfh);
 357        p = xdr_encode_array(p, args->fromname, args->fromlen);
 358        p = xdr_encode_array(p, args->topath, args->tolen);
 359        p = xdr_encode_sattr(p, args->sattr);
 360        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 361        return 0;
 362}
 363
 364/*
 365 * Encode arguments to readdir call
 366 */
 367static int
 368nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
 369{
 370        struct rpc_task *task = req->rq_task;
 371        struct rpc_auth *auth = task->tk_auth;
 372        unsigned int replen;
 373        u32 count = args->count;
 374
 375        p = xdr_encode_fhandle(p, args->fh);
 376        *p++ = htonl(args->cookie);
 377        *p++ = htonl(count); /* see above */
 378        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 379
 380        /* Inline the page array */
 381        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
 382        xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 383        return 0;
 384}
 385
 386/*
 387 * Decode the result of a readdir call.
 388 * We're not really decoding anymore, we just leave the buffer untouched
 389 * and only check that it is syntactically correct.
 390 * The real decoding happens in nfs_decode_entry below, called directly
 391 * from nfs_readdir for each entry.
 392 */
 393static int
 394nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
 395{
 396        struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 397        struct kvec *iov = rcvbuf->head;
 398        struct page **page;
 399        int hdrlen, recvd;
 400        int status, nr;
 401        unsigned int len, pglen;
 402        u32 *end, *entry, *kaddr;
 403
 404        if ((status = ntohl(*p++)))
 405                return -nfs_stat_to_errno(status);
 406
 407        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 408        if (iov->iov_len < hdrlen) {
 409                printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
 410                                "length %d > %Zu\n", hdrlen, iov->iov_len);
 411                return -errno_NFSERR_IO;
 412        } else if (iov->iov_len != hdrlen) {
 413                dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
 414                xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 415        }
 416
 417        pglen = rcvbuf->page_len;
 418        recvd = rcvbuf->len - hdrlen;
 419        if (pglen > recvd)
 420                pglen = recvd;
 421        page = rcvbuf->pages;
 422        kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
 423        end = (u32 *)((char *)p + pglen);
 424        entry = p;
 425        for (nr = 0; *p++; nr++) {
 426                if (p + 2 > end)
 427                        goto short_pkt;
 428                p++; /* fileid */
 429                len = ntohl(*p++);
 430                p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
 431                if (len > NFS2_MAXNAMLEN) {
 432                        printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
 433                                                len);
 434                        goto err_unmap;
 435                }
 436                if (p + 2 > end)
 437                        goto short_pkt;
 438                entry = p;
 439        }
 440        if (!nr && (entry[0] != 0 || entry[1] == 0))
 441                goto short_pkt;
 442 out:
 443        kunmap_atomic(kaddr, KM_USER0);
 444        return nr;
 445 short_pkt:
 446        entry[0] = entry[1] = 0;
 447        /* truncate listing ? */
 448        if (!nr) {
 449                printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
 450                entry[1] = 1;
 451        }
 452        goto out;
 453err_unmap:
 454        nr = -errno_NFSERR_IO;
 455        goto out;
 456}
 457
 458u32 *
 459nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
 460{
 461        if (!*p++) {
 462                if (!*p)
 463                        return ERR_PTR(-EAGAIN);
 464                entry->eof = 1;
 465                return ERR_PTR(-EBADCOOKIE);
 466        }
 467
 468        entry->ino        = ntohl(*p++);
 469        entry->len        = ntohl(*p++);
 470        entry->name       = (const char *) p;
 471        p                += XDR_QUADLEN(entry->len);
 472        entry->prev_cookie        = entry->cookie;
 473        entry->cookie     = ntohl(*p++);
 474        entry->eof        = !p[0] && p[1];
 475
 476        return p;
 477}
 478
 479/*
 480 * NFS XDR decode functions
 481 */
 482/*
 483 * Decode simple status reply
 484 */
 485static int
 486nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
 487{
 488        int     status;
 489
 490        if ((status = ntohl(*p++)) != 0)
 491                status = -nfs_stat_to_errno(status);
 492        return status;
 493}
 494
 495/*
 496 * Decode attrstat reply
 497 * GETATTR, SETATTR, WRITE
 498 */
 499static int
 500nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 501{
 502        int     status;
 503
 504        if ((status = ntohl(*p++)))
 505                return -nfs_stat_to_errno(status);
 506        xdr_decode_fattr(p, fattr);
 507        return 0;
 508}
 509
 510/*
 511 * Decode diropres reply
 512 * LOOKUP, CREATE, MKDIR
 513 */
 514static int
 515nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
 516{
 517        int     status;
 518
 519        if ((status = ntohl(*p++)))
 520                return -nfs_stat_to_errno(status);
 521        p = xdr_decode_fhandle(p, res->fh);
 522        xdr_decode_fattr(p, res->fattr);
 523        return 0;
 524}
 525
 526/*
 527 * Encode READLINK args
 528 */
 529static int
 530nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
 531{
 532        struct rpc_auth *auth = req->rq_task->tk_auth;
 533        unsigned int replen;
 534
 535        p = xdr_encode_fhandle(p, args->fh);
 536        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 537
 538        /* Inline the page array */
 539        replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
 540        xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
 541        return 0;
 542}
 543
 544/*
 545 * Decode READLINK reply
 546 */
 547static int
 548nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
 549{
 550        struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 551        struct kvec *iov = rcvbuf->head;
 552        int hdrlen, len, recvd;
 553        char    *kaddr;
 554        int     status;
 555
 556        if ((status = ntohl(*p++)))
 557                return -nfs_stat_to_errno(status);
 558        /* Convert length of symlink */
 559        len = ntohl(*p++);
 560        if (len >= rcvbuf->page_len || len <= 0) {
 561                dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
 562                return -ENAMETOOLONG;
 563        }
 564        hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 565        if (iov->iov_len < hdrlen) {
 566                printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
 567                                "length %d > %Zu\n", hdrlen, iov->iov_len);
 568                return -errno_NFSERR_IO;
 569        } else if (iov->iov_len != hdrlen) {
 570                dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
 571                xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 572        }
 573        recvd = req->rq_rcv_buf.len - hdrlen;
 574        if (recvd < len) {
 575                printk(KERN_WARNING "NFS: server cheating in readlink reply: "
 576                                "count %u > recvd %u\n", len, recvd);
 577                return -EIO;
 578        }
 579
 580        /* NULL terminate the string we got */
 581        kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
 582        kaddr[len+rcvbuf->page_base] = '\0';
 583        kunmap_atomic(kaddr, KM_USER0);
 584        return 0;
 585}
 586
 587/*
 588 * Decode WRITE reply
 589 */
 590static int
 591nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
 592{
 593        res->verf->committed = NFS_FILE_SYNC;
 594        return nfs_xdr_attrstat(req, p, res->fattr);
 595}
 596
 597/*
 598 * Decode STATFS reply
 599 */
 600static int
 601nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
 602{
 603        int     status;
 604
 605        if ((status = ntohl(*p++)))
 606                return -nfs_stat_to_errno(status);
 607
 608        res->tsize  = ntohl(*p++);
 609        res->bsize  = ntohl(*p++);
 610        res->blocks = ntohl(*p++);
 611        res->bfree  = ntohl(*p++);
 612        res->bavail = ntohl(*p++);
 613        return 0;
 614}
 615
 616/*
 617 * We need to translate between nfs status return values and
 618 * the local errno values which may not be the same.
 619 */
 620static struct {
 621        int stat;
 622        int errno;
 623} nfs_errtbl[] = {
 624        { NFS_OK,               0               },
 625        { NFSERR_PERM,          EPERM           },
 626        { NFSERR_NOENT,         ENOENT          },
 627        { NFSERR_IO,            errno_NFSERR_IO },
 628        { NFSERR_NXIO,          ENXIO           },
 629/*      { NFSERR_EAGAIN,        EAGAIN          }, */
 630        { NFSERR_ACCES,         EACCES          },
 631        { NFSERR_EXIST,         EEXIST          },
 632        { NFSERR_XDEV,          EXDEV           },
 633        { NFSERR_NODEV,         ENODEV          },
 634        { NFSERR_NOTDIR,        ENOTDIR         },
 635        { NFSERR_ISDIR,         EISDIR          },
 636        { NFSERR_INVAL,         EINVAL          },
 637        { NFSERR_FBIG,          EFBIG           },
 638        { NFSERR_NOSPC,         ENOSPC          },
 639        { NFSERR_ROFS,          EROFS           },
 640        { NFSERR_MLINK,         EMLINK          },
 641        { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
 642        { NFSERR_NOTEMPTY,      ENOTEMPTY       },
 643        { NFSERR_DQUOT,         EDQUOT          },
 644        { NFSERR_STALE,         ESTALE          },
 645        { NFSERR_REMOTE,        EREMOTE         },
 646#ifdef EWFLUSH
 647        { NFSERR_WFLUSH,        EWFLUSH         },
 648#endif
 649        { NFSERR_BADHANDLE,     EBADHANDLE      },
 650        { NFSERR_NOT_SYNC,      ENOTSYNC        },
 651        { NFSERR_BAD_COOKIE,    EBADCOOKIE      },
 652        { NFSERR_NOTSUPP,       ENOTSUPP        },
 653        { NFSERR_TOOSMALL,      ETOOSMALL       },
 654        { NFSERR_SERVERFAULT,   ESERVERFAULT    },
 655        { NFSERR_BADTYPE,       EBADTYPE        },
 656        { NFSERR_JUKEBOX,       EJUKEBOX        },
 657        { -1,                   EIO             }
 658};
 659
 660/*
 661 * Convert an NFS error code to a local one.
 662 * This one is used jointly by NFSv2 and NFSv3.
 663 */
 664int
 665nfs_stat_to_errno(int stat)
 666{
 667        int i;
 668
 669        for (i = 0; nfs_errtbl[i].stat != -1; i++) {
 670                if (nfs_errtbl[i].stat == stat)
 671                        return nfs_errtbl[i].errno;
 672        }
 673        printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
 674        return nfs_errtbl[i].errno;
 675}
 676
 677#ifndef MAX
 678# define MAX(a, b)      (((a) > (b))? (a) : (b))
 679#endif
 680
 681#define PROC(proc, argtype, restype, timer)                             \
 682[NFSPROC_##proc] = {                                                    \
 683        .p_proc     =  NFSPROC_##proc,                                  \
 684        .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
 685        .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
 686        .p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
 687        .p_timer    =  timer                                            \
 688        }
 689struct rpc_procinfo     nfs_procedures[] = {
 690    PROC(GETATTR,       fhandle,        attrstat, 1),
 691    PROC(SETATTR,       sattrargs,      attrstat, 0),
 692    PROC(LOOKUP,        diropargs,      diropres, 2),
 693    PROC(READLINK,      readlinkargs,   readlinkres, 3),
 694    PROC(READ,          readargs,       readres, 3),
 695    PROC(WRITE,         writeargs,      writeres, 4),
 696    PROC(CREATE,        createargs,     diropres, 0),
 697    PROC(REMOVE,        diropargs,      stat, 0),
 698    PROC(RENAME,        renameargs,     stat, 0),
 699    PROC(LINK,          linkargs,       stat, 0),
 700    PROC(SYMLINK,       symlinkargs,    stat, 0),
 701    PROC(MKDIR,         createargs,     diropres, 0),
 702    PROC(RMDIR,         diropargs,      stat, 0),
 703    PROC(READDIR,       readdirargs,    readdirres, 3),
 704    PROC(STATFS,        fhandle,        statfsres, 0),
 705};
 706
 707struct rpc_version              nfs_version2 = {
 708        .number                 = 2,
 709        .nrprocs                = sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
 710        .procs                  = nfs_procedures
 711};
 712
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.