linux-bk/fs/nfsd/nfs3xdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfsd/nfs3xdr.c
   3 *
   4 * XDR support for nfsd/protocol version 3.
   5 *
   6 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/time.h>
  11#include <linux/nfs3.h>
  12#include <linux/list.h>
  13#include <linux/spinlock.h>
  14#include <linux/dcache.h>
  15#include <linux/namei.h>
  16
  17#include <linux/sunrpc/xdr.h>
  18#include <linux/sunrpc/svc.h>
  19#include <linux/nfsd/nfsd.h>
  20#include <linux/nfsd/xdr3.h>
  21
  22#define NFSDDBG_FACILITY                NFSDDBG_XDR
  23
  24#ifdef NFSD_OPTIMIZE_SPACE
  25# define inline
  26#endif
  27
  28
  29/*
  30 * Mapping of S_IF* types to NFS file types
  31 */
  32static u32      nfs3_ftypes[] = {
  33        NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
  34        NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
  35        NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
  36        NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
  37};
  38
  39/*
  40 * XDR functions for basic NFS types
  41 */
  42static inline u32 *
  43encode_time3(u32 *p, time_t secs)
  44{
  45        *p++ = htonl((u32) secs); *p++ = 0;
  46        return p;
  47}
  48
  49static inline u32 *
  50decode_time3(u32 *p, time_t *secp)
  51{
  52        *secp = ntohl(*p++);
  53        return p + 1;
  54}
  55
  56static inline u32 *
  57decode_fh(u32 *p, struct svc_fh *fhp)
  58{
  59        int size;
  60        fh_init(fhp, NFS3_FHSIZE);
  61        size = ntohl(*p++);
  62        if (size > NFS3_FHSIZE)
  63                return NULL;
  64
  65        memcpy(&fhp->fh_handle.fh_base, p, size);
  66        fhp->fh_handle.fh_size = size;
  67        return p + XDR_QUADLEN(size);
  68}
  69
  70static inline u32 *
  71encode_fh(u32 *p, struct svc_fh *fhp)
  72{
  73        int size = fhp->fh_handle.fh_size;
  74        *p++ = htonl(size);
  75        if (size) p[XDR_QUADLEN(size)-1]=0;
  76        memcpy(p, &fhp->fh_handle.fh_base, size);
  77        return p + XDR_QUADLEN(size);
  78}
  79
  80/*
  81 * Decode a file name and make sure that the path contains
  82 * no slashes or null bytes.
  83 */
  84static inline u32 *
  85decode_filename(u32 *p, char **namp, int *lenp)
  86{
  87        char            *name;
  88        int             i;
  89
  90        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
  91                for (i = 0, name = *namp; i < *lenp; i++, name++) {
  92                        if (*name == '\0' || *name == '/')
  93                                return NULL;
  94                }
  95        }
  96
  97        return p;
  98}
  99
 100static inline u32 *
 101decode_pathname(u32 *p, char **namp, int *lenp)
 102{
 103        char            *name;
 104        int             i;
 105
 106        if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
 107                for (i = 0, name = *namp; i < *lenp; i++, name++) {
 108                        if (*name == '\0')
 109                                return NULL;
 110                }
 111        }
 112
 113        return p;
 114}
 115
 116static inline u32 *
 117decode_sattr3(u32 *p, struct iattr *iap)
 118{
 119        u32     tmp;
 120
 121        iap->ia_valid = 0;
 122
 123        if (*p++) {
 124                iap->ia_valid |= ATTR_MODE;
 125                iap->ia_mode = ntohl(*p++);
 126        }
 127        if (*p++) {
 128                iap->ia_valid |= ATTR_UID;
 129                iap->ia_uid = ntohl(*p++);
 130        }
 131        if (*p++) {
 132                iap->ia_valid |= ATTR_GID;
 133                iap->ia_gid = ntohl(*p++);
 134        }
 135        if (*p++) {
 136                u64     newsize;
 137
 138                iap->ia_valid |= ATTR_SIZE;
 139                p = xdr_decode_hyper(p, &newsize);
 140                if (newsize <= NFS_OFFSET_MAX)
 141                        iap->ia_size = newsize;
 142                else
 143                        iap->ia_size = NFS_OFFSET_MAX;
 144        }
 145        if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
 146                iap->ia_valid |= ATTR_ATIME;
 147        } else if (tmp == 2) {          /* set to client time */
 148                iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
 149                iap->ia_atime = ntohl(*p++), p++;
 150        }
 151        if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
 152                iap->ia_valid |= ATTR_MTIME;
 153        } else if (tmp == 2) {          /* set to client time */
 154                iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 155                iap->ia_mtime = ntohl(*p++), p++;
 156        }
 157        return p;
 158}
 159
 160static inline u32 *
 161encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 162{
 163        struct vfsmount *mnt = fhp->fh_export->ex_mnt;
 164        struct dentry   *dentry = fhp->fh_dentry;
 165        struct kstat stat;
 166
 167        vfs_getattr(mnt, dentry, &stat);
 168
 169        *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
 170        *p++ = htonl((u32) stat.mode);
 171        *p++ = htonl((u32) stat.nlink);
 172        *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
 173        *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
 174        if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
 175                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 176        } else {
 177                p = xdr_encode_hyper(p, (u64) stat.size);
 178        }
 179        p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9);
 180        *p++ = htonl((u32) MAJOR(stat.rdev));
 181        *p++ = htonl((u32) MINOR(stat.rdev));
 182        if (rqstp->rq_reffh->fh_version == 1
 183            && rqstp->rq_reffh->fh_fsid_type == 1
 184            && (fhp->fh_export->ex_flags & NFSEXP_FSID))
 185                p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
 186        else
 187                p = xdr_encode_hyper(p, (u64) stat.dev);
 188        p = xdr_encode_hyper(p, (u64) stat.ino);
 189        p = encode_time3(p, stat.atime);
 190        p = encode_time3(p, lease_get_mtime(dentry->d_inode));
 191        p = encode_time3(p, stat.ctime);
 192
 193        return p;
 194}
 195
 196static inline u32 *
 197encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 198{
 199        struct inode    *inode = fhp->fh_dentry->d_inode;
 200
 201        /* Attributes to follow */
 202        *p++ = xdr_one;
 203
 204        *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
 205        *p++ = htonl((u32) fhp->fh_post_mode);
 206        *p++ = htonl((u32) fhp->fh_post_nlink);
 207        *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
 208        *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
 209        if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
 210                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 211        } else {
 212                p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
 213        }
 214        p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
 215        *p++ = htonl((u32) major(fhp->fh_post_rdev));
 216        *p++ = htonl((u32) minor(fhp->fh_post_rdev));
 217        if (rqstp->rq_reffh->fh_version == 1
 218            && rqstp->rq_reffh->fh_fsid_type == 1
 219            && (fhp->fh_export->ex_flags & NFSEXP_FSID))
 220                p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
 221        else
 222                p = xdr_encode_hyper(p, (u64) inode->i_dev);
 223        p = xdr_encode_hyper(p, (u64) inode->i_ino);
 224        p = encode_time3(p, fhp->fh_post_atime);
 225        p = encode_time3(p, fhp->fh_post_mtime);
 226        p = encode_time3(p, fhp->fh_post_ctime);
 227
 228        return p;
 229}
 230
 231/*
 232 * Encode post-operation attributes.
 233 * The inode may be NULL if the call failed because of a stale file
 234 * handle. In this case, no attributes are returned.
 235 */
 236static u32 *
 237encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 238{
 239        struct dentry *dentry = fhp->fh_dentry;
 240        if (dentry && dentry->d_inode != NULL) {
 241                *p++ = xdr_one;         /* attributes follow */
 242                return encode_fattr3(rqstp, p, fhp);
 243        }
 244        *p++ = xdr_zero;
 245        return p;
 246}
 247
 248/*
 249 * Enocde weak cache consistency data
 250 */
 251static u32 *
 252encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 253{
 254        struct dentry   *dentry = fhp->fh_dentry;
 255
 256        if (dentry && dentry->d_inode && fhp->fh_post_saved) {
 257                if (fhp->fh_pre_saved) {
 258                        *p++ = xdr_one;
 259                        p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
 260                        p = encode_time3(p, fhp->fh_pre_mtime);
 261                        p = encode_time3(p, fhp->fh_pre_ctime);
 262                } else {
 263                        *p++ = xdr_zero;
 264                }
 265                return encode_saved_post_attr(rqstp, p, fhp);
 266        }
 267        /* no pre- or post-attrs */
 268        *p++ = xdr_zero;
 269        return encode_post_op_attr(rqstp, p, fhp);
 270}
 271
 272/*
 273 * Check buffer bounds after decoding arguments
 274 */
 275static inline int
 276xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
 277{
 278        struct svc_buf  *buf = &rqstp->rq_argbuf;
 279
 280        return p - buf->base <= buf->buflen;
 281}
 282
 283static inline int
 284xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
 285{
 286        struct svc_buf  *buf = &rqstp->rq_resbuf;
 287
 288        buf->len = p - buf->base;
 289        dprintk("nfsd: ressize_check p %p base %p len %d\n",
 290                        p, buf->base, buf->buflen);
 291        return (buf->len <= buf->buflen);
 292}
 293
 294/*
 295 * XDR decode functions
 296 */
 297int
 298nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 299{
 300        if (!(p = decode_fh(p, fhp)))
 301                return 0;
 302        return xdr_argsize_check(rqstp, p);
 303}
 304
 305int
 306nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
 307                                        struct nfsd3_sattrargs *args)
 308{
 309        if (!(p = decode_fh(p, &args->fh))
 310         || !(p = decode_sattr3(p, &args->attrs)))
 311                return 0;
 312
 313        if ((args->check_guard = ntohl(*p++)) != 0)
 314                p = decode_time3(p, &args->guardtime);
 315
 316        return xdr_argsize_check(rqstp, p);
 317}
 318
 319int
 320nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
 321                                        struct nfsd3_diropargs *args)
 322{
 323        if (!(p = decode_fh(p, &args->fh))
 324         || !(p = decode_filename(p, &args->name, &args->len)))
 325                return 0;
 326
 327        return xdr_argsize_check(rqstp, p);
 328}
 329
 330int
 331nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
 332                                        struct nfsd3_accessargs *args)
 333{
 334        if (!(p = decode_fh(p, &args->fh)))
 335                return 0;
 336        args->access = ntohl(*p++);
 337
 338        return xdr_argsize_check(rqstp, p);
 339}
 340
 341int
 342nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
 343                                        struct nfsd3_readargs *args)
 344{
 345        if (!(p = decode_fh(p, &args->fh))
 346         || !(p = xdr_decode_hyper(p, &args->offset)))
 347                return 0;
 348
 349        args->count = ntohl(*p++);
 350        return xdr_argsize_check(rqstp, p);
 351}
 352
 353int
 354nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
 355                                        struct nfsd3_writeargs *args)
 356{
 357        if (!(p = decode_fh(p, &args->fh))
 358         || !(p = xdr_decode_hyper(p, &args->offset)))
 359                return 0;
 360
 361        args->count = ntohl(*p++);
 362        args->stable = ntohl(*p++);
 363        args->len = ntohl(*p++);
 364        args->data = (char *) p;
 365        p += XDR_QUADLEN(args->len);
 366
 367        return xdr_argsize_check(rqstp, p);
 368}
 369
 370int
 371nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
 372                                        struct nfsd3_createargs *args)
 373{
 374        if (!(p = decode_fh(p, &args->fh))
 375         || !(p = decode_filename(p, &args->name, &args->len)))
 376                return 0;
 377
 378        switch (args->createmode = ntohl(*p++)) {
 379        case NFS3_CREATE_UNCHECKED:
 380        case NFS3_CREATE_GUARDED:
 381                if (!(p = decode_sattr3(p, &args->attrs)))
 382                        return 0;
 383                break;
 384        case NFS3_CREATE_EXCLUSIVE:
 385                args->verf = p;
 386                p += 2;
 387                break;
 388        default:
 389                return 0;
 390        }
 391
 392        return xdr_argsize_check(rqstp, p);
 393}
 394int
 395nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
 396                                        struct nfsd3_createargs *args)
 397{
 398        if (!(p = decode_fh(p, &args->fh))
 399         || !(p = decode_filename(p, &args->name, &args->len))
 400         || !(p = decode_sattr3(p, &args->attrs)))
 401                return 0;
 402
 403        return xdr_argsize_check(rqstp, p);
 404}
 405
 406int
 407nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
 408                                        struct nfsd3_symlinkargs *args)
 409{
 410        if (!(p = decode_fh(p, &args->ffh))
 411         || !(p = decode_filename(p, &args->fname, &args->flen))
 412         || !(p = decode_sattr3(p, &args->attrs))
 413         || !(p = decode_pathname(p, &args->tname, &args->tlen)))
 414                return 0;
 415
 416        return xdr_argsize_check(rqstp, p);
 417}
 418
 419int
 420nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
 421                                        struct nfsd3_mknodargs *args)
 422{
 423        if (!(p = decode_fh(p, &args->fh))
 424         || !(p = decode_filename(p, &args->name, &args->len)))
 425                return 0;
 426
 427        args->ftype = ntohl(*p++);
 428
 429        if (args->ftype == NF3BLK  || args->ftype == NF3CHR
 430         || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
 431                if (!(p = decode_sattr3(p, &args->attrs)))
 432                        return 0;
 433        }
 434
 435        if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
 436                args->major = ntohl(*p++);
 437                args->minor = ntohl(*p++);
 438        }
 439
 440        return xdr_argsize_check(rqstp, p);
 441}
 442
 443int
 444nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
 445                                        struct nfsd3_renameargs *args)
 446{
 447        if (!(p = decode_fh(p, &args->ffh))
 448         || !(p = decode_filename(p, &args->fname, &args->flen))
 449         || !(p = decode_fh(p, &args->tfh))
 450         || !(p = decode_filename(p, &args->tname, &args->tlen)))
 451                return 0;
 452
 453        return xdr_argsize_check(rqstp, p);
 454}
 455
 456int
 457nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
 458                                        struct nfsd3_linkargs *args)
 459{
 460        if (!(p = decode_fh(p, &args->ffh))
 461         || !(p = decode_fh(p, &args->tfh))
 462         || !(p = decode_filename(p, &args->tname, &args->tlen)))
 463                return 0;
 464
 465        return xdr_argsize_check(rqstp, p);
 466}
 467
 468int
 469nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
 470                                        struct nfsd3_readdirargs *args)
 471{
 472        if (!(p = decode_fh(p, &args->fh)))
 473                return 0;
 474        p = xdr_decode_hyper(p, &args->cookie);
 475        args->verf   = p; p += 2;
 476        args->dircount = ~0;
 477        args->count  = ntohl(*p++);
 478
 479        return xdr_argsize_check(rqstp, p);
 480}
 481
 482int
 483nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
 484                                        struct nfsd3_readdirargs *args)
 485{
 486        if (!(p = decode_fh(p, &args->fh)))
 487                return 0;
 488        p = xdr_decode_hyper(p, &args->cookie);
 489        args->verf     = p; p += 2;
 490        args->dircount = ntohl(*p++);
 491        args->count    = ntohl(*p++);
 492
 493        return xdr_argsize_check(rqstp, p);
 494}
 495
 496int
 497nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
 498                                        struct nfsd3_commitargs *args)
 499{
 500        if (!(p = decode_fh(p, &args->fh)))
 501                return 0;
 502        p = xdr_decode_hyper(p, &args->offset);
 503        args->count = ntohl(*p++);
 504
 505        return xdr_argsize_check(rqstp, p);
 506}
 507
 508/*
 509 * XDR encode functions
 510 */
 511/*
 512 * There must be an encoding function for void results so svc_process
 513 * will work properly.
 514 */
 515int
 516nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
 517{
 518        return xdr_ressize_check(rqstp, p);
 519}
 520
 521/* GETATTR */
 522int
 523nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
 524                                        struct nfsd3_attrstat *resp)
 525{
 526        if (resp->status == 0)
 527                p = encode_fattr3(rqstp, p, &resp->fh);
 528        return xdr_ressize_check(rqstp, p);
 529}
 530
 531/* SETATTR, REMOVE, RMDIR */
 532int
 533nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
 534                                        struct nfsd3_attrstat *resp)
 535{
 536        p = encode_wcc_data(rqstp, p, &resp->fh);
 537        return xdr_ressize_check(rqstp, p);
 538}
 539
 540/* LOOKUP */
 541int
 542nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
 543                                        struct nfsd3_diropres *resp)
 544{
 545        if (resp->status == 0) {
 546                p = encode_fh(p, &resp->fh);
 547                p = encode_post_op_attr(rqstp, p, &resp->fh);
 548        }
 549        p = encode_post_op_attr(rqstp, p, &resp->dirfh);
 550        return xdr_ressize_check(rqstp, p);
 551}
 552
 553/* ACCESS */
 554int
 555nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
 556                                        struct nfsd3_accessres *resp)
 557{
 558        p = encode_post_op_attr(rqstp, p, &resp->fh);
 559        if (resp->status == 0)
 560                *p++ = htonl(resp->access);
 561        return xdr_ressize_check(rqstp, p);
 562}
 563
 564/* READLINK */
 565int
 566nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
 567                                        struct nfsd3_readlinkres *resp)
 568{
 569        p = encode_post_op_attr(rqstp, p, &resp->fh);
 570        if (resp->status == 0) {
 571                *p++ = htonl(resp->len);
 572                p += XDR_QUADLEN(resp->len);
 573        }
 574        return xdr_ressize_check(rqstp, p);
 575}
 576
 577/* READ */
 578int
 579nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 580                                        struct nfsd3_readres *resp)
 581{
 582        p = encode_post_op_attr(rqstp, p, &resp->fh);
 583        if (resp->status == 0) {
 584                *p++ = htonl(resp->count);
 585                *p++ = htonl(resp->eof);
 586                *p++ = htonl(resp->count);      /* xdr opaque count */
 587                p += XDR_QUADLEN(resp->count);
 588        }
 589        return xdr_ressize_check(rqstp, p);
 590}
 591
 592/* WRITE */
 593int
 594nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
 595                                        struct nfsd3_writeres *resp)
 596{
 597        p = encode_wcc_data(rqstp, p, &resp->fh);
 598        if (resp->status == 0) {
 599                *p++ = htonl(resp->count);
 600                *p++ = htonl(resp->committed);
 601                *p++ = htonl(nfssvc_boot.tv_sec);
 602                *p++ = htonl(nfssvc_boot.tv_usec);
 603        }
 604        return xdr_ressize_check(rqstp, p);
 605}
 606
 607/* CREATE, MKDIR, SYMLINK, MKNOD */
 608int
 609nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
 610                                        struct nfsd3_diropres *resp)
 611{
 612        if (resp->status == 0) {
 613                *p++ = xdr_one;
 614                p = encode_fh(p, &resp->fh);
 615                p = encode_post_op_attr(rqstp, p, &resp->fh);
 616        }
 617        p = encode_wcc_data(rqstp, p, &resp->dirfh);
 618        return xdr_ressize_check(rqstp, p);
 619}
 620
 621/* RENAME */
 622int
 623nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
 624                                        struct nfsd3_renameres *resp)
 625{
 626        p = encode_wcc_data(rqstp, p, &resp->ffh);
 627        p = encode_wcc_data(rqstp, p, &resp->tfh);
 628        return xdr_ressize_check(rqstp, p);
 629}
 630
 631/* LINK */
 632int
 633nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
 634                                        struct nfsd3_linkres *resp)
 635{
 636        p = encode_post_op_attr(rqstp, p, &resp->fh);
 637        p = encode_wcc_data(rqstp, p, &resp->tfh);
 638        return xdr_ressize_check(rqstp, p);
 639}
 640
 641/* READDIR */
 642int
 643nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
 644                                        struct nfsd3_readdirres *resp)
 645{
 646        p = encode_post_op_attr(rqstp, p, &resp->fh);
 647        if (resp->status == 0) {
 648                /* stupid readdir cookie */
 649                memcpy(p, resp->verf, 8); p += 2;
 650                p += XDR_QUADLEN(resp->count);
 651        }
 652
 653        return xdr_ressize_check(rqstp, p);
 654}
 655
 656/*
 657 * Encode a directory entry. This one works for both normal readdir
 658 * and readdirplus.
 659 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
 660 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
 661 * 
 662 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
 663 * file handle.
 664 */
 665
 666#define NFS3_ENTRY_BAGGAGE      (2 + 1 + 2 + 1)
 667#define NFS3_ENTRYPLUS_BAGGAGE  (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
 668static int
 669encode_entry(struct readdir_cd *cd, const char *name,
 670             int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
 671{
 672        u32             *p = cd->buffer;
 673        int             buflen, slen, elen;
 674
 675        if (cd->offset)
 676                xdr_encode_hyper(cd->offset, (u64) offset);
 677
 678        /* nfsd_readdir calls us with name == 0 when it wants us to
 679         * set the last offset entry. */
 680        if (name == 0)
 681                return 0;
 682
 683        /*
 684        dprintk("encode_entry(%.*s @%ld%s)\n",
 685                namlen, name, (long) offset, plus? " plus" : "");
 686         */
 687
 688        /* truncate filename if too long */
 689        if (namlen > NFS3_MAXNAMLEN)
 690                namlen = NFS3_MAXNAMLEN;
 691
 692        slen = XDR_QUADLEN(namlen);
 693        elen = slen + NFS3_ENTRY_BAGGAGE
 694                + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
 695        if ((buflen = cd->buflen - elen) < 0) {
 696                cd->eob = 1;
 697                return -EINVAL;
 698        }
 699        *p++ = xdr_one;                          /* mark entry present */
 700        p    = xdr_encode_hyper(p, ino);         /* file id */
 701        p    = xdr_encode_array(p, name, namlen);/* name length & name */
 702
 703        cd->offset = p;                 /* remember pointer */
 704        p = xdr_encode_hyper(p, NFS_OFFSET_MAX);        /* offset of next entry */
 705
 706        /* throw in readdirplus baggage */
 707        if (plus) {
 708                struct svc_fh   fh;
 709                struct svc_export       *exp;
 710                struct dentry           *dparent, *dchild;
 711
 712                dparent = cd->dirfh->fh_dentry;
 713                exp  = cd->dirfh->fh_export;
 714
 715                fh_init(&fh, NFS3_FHSIZE);
 716                if (isdotent(name, namlen)) {
 717                        if (namlen == 2) {
 718                                read_lock(&dparent_lock);
 719                                dchild = dget(dparent->d_parent);
 720                                read_unlock(&dparent_lock);
 721                        } else
 722                                dchild = dget(dparent);
 723                } else
 724                        dchild = lookup_one_len(name, dparent,namlen);
 725                if (IS_ERR(dchild))
 726                        goto noexec;
 727                if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
 728                        goto noexec;
 729                p = encode_post_op_attr(cd->rqstp, p, &fh);
 730                *p++ = xdr_one; /* yes, a file handle follows */
 731                p = encode_fh(p, &fh);
 732                fh_put(&fh);
 733        }
 734
 735out:
 736        cd->buflen = buflen;
 737        cd->buffer = p;
 738        return 0;
 739
 740noexec:
 741        *p++ = 0;
 742        *p++ = 0;
 743        goto out;
 744}
 745
 746int
 747nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
 748                     int namlen, loff_t offset, ino_t ino, unsigned int d_type)
 749{
 750        return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
 751}
 752
 753int
 754nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
 755                          int namlen, loff_t offset, ino_t ino, unsigned int d_type)
 756{
 757        return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
 758}
 759
 760/* FSSTAT */
 761int
 762nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
 763                                        struct nfsd3_fsstatres *resp)
 764{
 765        struct statfs   *s = &resp->stats;
 766        u64             bs = s->f_bsize;
 767
 768        *p++ = xdr_zero;        /* no post_op_attr */
 769
 770        if (resp->status == 0) {
 771                p = xdr_encode_hyper(p, bs * s->f_blocks);      /* total bytes */
 772                p = xdr_encode_hyper(p, bs * s->f_bfree);       /* free bytes */
 773                p = xdr_encode_hyper(p, bs * s->f_bavail);      /* user available bytes */
 774                p = xdr_encode_hyper(p, s->f_files);    /* total inodes */
 775                p = xdr_encode_hyper(p, s->f_ffree);    /* free inodes */
 776                p = xdr_encode_hyper(p, s->f_ffree);    /* user available inodes */
 777                *p++ = htonl(resp->invarsec);   /* mean unchanged time */
 778        }
 779        return xdr_ressize_check(rqstp, p);
 780}
 781
 782/* FSINFO */
 783int
 784nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
 785                                        struct nfsd3_fsinfores *resp)
 786{
 787        *p++ = xdr_zero;        /* no post_op_attr */
 788
 789        if (resp->status == 0) {
 790                *p++ = htonl(resp->f_rtmax);
 791                *p++ = htonl(resp->f_rtpref);
 792                *p++ = htonl(resp->f_rtmult);
 793                *p++ = htonl(resp->f_wtmax);
 794                *p++ = htonl(resp->f_wtpref);
 795                *p++ = htonl(resp->f_wtmult);
 796                *p++ = htonl(resp->f_dtpref);
 797                p = xdr_encode_hyper(p, resp->f_maxfilesize);
 798                *p++ = xdr_one;
 799                *p++ = xdr_zero;
 800                *p++ = htonl(resp->f_properties);
 801        }
 802
 803        return xdr_ressize_check(rqstp, p);
 804}
 805
 806/* PATHCONF */
 807int
 808nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
 809                                        struct nfsd3_pathconfres *resp)
 810{
 811        *p++ = xdr_zero;        /* no post_op_attr */
 812
 813        if (resp->status == 0) {
 814                *p++ = htonl(resp->p_link_max);
 815                *p++ = htonl(resp->p_name_max);
 816                *p++ = htonl(resp->p_no_trunc);
 817                *p++ = htonl(resp->p_chown_restricted);
 818                *p++ = htonl(resp->p_case_insensitive);
 819                *p++ = htonl(resp->p_case_preserving);
 820        }
 821
 822        return xdr_ressize_check(rqstp, p);
 823}
 824
 825/* COMMIT */
 826int
 827nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
 828                                        struct nfsd3_commitres *resp)
 829{
 830        p = encode_wcc_data(rqstp, p, &resp->fh);
 831        /* Write verifier */
 832        if (resp->status == 0) {
 833                *p++ = htonl(nfssvc_boot.tv_sec);
 834                *p++ = htonl(nfssvc_boot.tv_usec);
 835        }
 836        return xdr_ressize_check(rqstp, p);
 837}
 838
 839/*
 840 * XDR release functions
 841 */
 842int
 843nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
 844                                        struct nfsd3_attrstat *resp)
 845{
 846        fh_put(&resp->fh);
 847        return 1;
 848}
 849
 850int
 851nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
 852                                        struct nfsd3_fhandle_pair *resp)
 853{
 854        fh_put(&resp->fh1);
 855        fh_put(&resp->fh2);
 856        return 1;
 857}
 858
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.