Merge branch 'bugfixes' into nfs-for-2.6.38
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 10 Jan 2011 19:48:02 +0000 (14:48 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 10 Jan 2011 19:48:02 +0000 (14:48 -0500)
Conflicts:
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c

1  2 
fs/nfs/dir.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c
include/linux/sunrpc/xdr.h

diff --cc fs/nfs/dir.c
@@@ -33,9 -33,7 +33,8 @@@
  #include <linux/namei.h>
  #include <linux/mount.h>
  #include <linux/sched.h>
- #include <linux/vmalloc.h>
  #include <linux/kmemleak.h>
 +#include <linux/xattr.h>
  
  #include "delegation.h"
  #include "iostat.h"
@@@ -943,12 -487,7 +943,7 @@@ int nfs2_decode_dirent(struct xdr_strea
  
        entry->d_type = DT_UNKNOWN;
  
-       /* Peek at the next entry to see if we're at EOD */
-       p = xdr_inline_peek(xdr, 4 + 4);
-       entry->eof = 0;
-       if (p != NULL)
-               entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
 -      return p;
 +      return 0;
  
  out_overflow:
        print_overflow_msg(__func__, xdr);
@@@ -1771,238 -1048,23 +1771,233 @@@ out_default
  }
  
  /*
 - * Decode PATHCONF reply
 + * 3.3.12  REMOVE3res
 + *
 + *    struct REMOVE3resok {
 + *            wcc_data    dir_wcc;
 + *    };
 + *
 + *    struct REMOVE3resfail {
 + *            wcc_data    dir_wcc;
 + *    };
 + *
 + *    union REMOVE3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            REMOVE3resok   resok;
 + *    default:
 + *            REMOVE3resfail resfail;
 + *    };
   */
 -static int
 -nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
 +static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_removeres *result)
  {
 -      int             status;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      status = ntohl(*p++);
 +/*
 + * 3.3.14  RENAME3res
 + *
 + *    struct RENAME3resok {
 + *            wcc_data        fromdir_wcc;
 + *            wcc_data        todir_wcc;
 + *    };
 + *
 + *    struct RENAME3resfail {
 + *            wcc_data        fromdir_wcc;
 + *            wcc_data        todir_wcc;
 + *    };
 + *
 + *    union RENAME3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            RENAME3resok   resok;
 + *    default:
 + *            RENAME3resfail resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_renameres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->old_fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->new_fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 -      res->max_link = ntohl(*p++);
 -      res->max_namelen = ntohl(*p++);
 +/*
 + * 3.3.15  LINK3res
 + *
 + *    struct LINK3resok {
 + *            post_op_attr    file_attributes;
 + *            wcc_data        linkdir_wcc;
 + *    };
 + *
 + *    struct LINK3resfail {
 + *            post_op_attr    file_attributes;
 + *            wcc_data        linkdir_wcc;
 + *    };
 + *
 + *    union LINK3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            LINK3resok      resok;
 + *    default:
 + *            LINK3resfail    resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs3_linkres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
 +
 +/**
 + * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
 + *                    the local page cache
 + * @xdr: XDR stream where entry resides
 + * @entry: buffer to fill in with entry data
 + * @plus: boolean indicating whether this should be a readdirplus entry
 + *
 + * Returns zero if successful, otherwise a negative errno value is
 + * returned.
 + *
 + * This function is not invoked during READDIR reply decoding, but
 + * rather whenever an application invokes the getdents(2) system call
 + * on a directory already in our cache.
 + *
 + * 3.3.16  entry3
 + *
 + *    struct entry3 {
 + *            fileid3         fileid;
 + *            filename3       name;
 + *            cookie3         cookie;
 + *            fhandle3        filehandle;
 + *            post_op_attr3   attributes;
 + *            entry3          *nextentry;
 + *    };
 + *
 + * 3.3.17  entryplus3
 + *    struct entryplus3 {
 + *            fileid3         fileid;
 + *            filename3       name;
 + *            cookie3         cookie;
 + *            post_op_attr    name_attributes;
 + *            post_op_fh3     name_handle;
 + *            entryplus3      *nextentry;
 + *    };
 + */
 +int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 +                     int plus)
 +{
 +      struct nfs_entry old = *entry;
 +      __be32 *p;
 +      int error;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      if (*p == xdr_zero) {
 +              p = xdr_inline_decode(xdr, 4);
 +              if (unlikely(p == NULL))
 +                      goto out_overflow;
 +              if (*p == xdr_zero)
 +                      return -EAGAIN;
 +              entry->eof = 1;
 +              return -EBADCOOKIE;
 +      }
 +
 +      error = decode_fileid3(xdr, &entry->ino);
 +      if (unlikely(error))
 +              return error;
 +
 +      error = decode_inline_filename3(xdr, &entry->name, &entry->len);
 +      if (unlikely(error))
 +              return error;
 +
 +      entry->prev_cookie = entry->cookie;
 +      error = decode_cookie3(xdr, &entry->cookie);
 +      if (unlikely(error))
 +              return error;
 +
 +      entry->d_type = DT_UNKNOWN;
 +
 +      if (plus) {
 +              entry->fattr->valid = 0;
 +              error = decode_post_op_attr(xdr, entry->fattr);
 +              if (unlikely(error))
 +                      return error;
 +              if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
 +                      entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 +
 +              /* In fact, a post_op_fh3: */
 +              p = xdr_inline_decode(xdr, 4);
 +              if (unlikely(p == NULL))
 +                      goto out_overflow;
 +              if (*p != xdr_zero) {
 +                      error = decode_nfs_fh3(xdr, entry->fh);
 +                      if (unlikely(error)) {
 +                              if (error == -E2BIG)
 +                                      goto out_truncated;
 +                              return error;
 +                      }
 +              } else
 +                      zero_nfs_fh3(entry->fh);
 +      }
  
-       /* Peek at the next entry to see if we're at EOD */
-       p = xdr_inline_peek(xdr, 4 + 4);
-       entry->eof = 0;
-       if (p != NULL)
-               entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
 -      /* ignore remaining fields */
        return 0;
 +
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EAGAIN;
 +out_truncated:
 +      dprintk("NFS: directory entry contains invalid file handle\n");
 +      *entry = old;
 +      return -EAGAIN;
  }
  
  /*
@@@ -6135,13 -6215,7 +6135,7 @@@ int nfs4_decode_dirent(struct xdr_strea
        if (verify_attr_len(xdr, p, len) < 0)
                goto out_overflow;
  
-       p = xdr_inline_peek(xdr, 8);
-       if (p != NULL)
-               entry->eof = !p[0] && p[1];
-       else
-               entry->eof = 0;
 -      return p;
 +      return 0;
  
  out_overflow:
        print_overflow_msg(__func__, xdr);
@@@ -201,14 -201,10 +201,16 @@@ struct xdr_stream 
  
        __be32 *end;            /* end of available buffer space */
        struct kvec *iov;       /* pointer to the current kvec */
+       struct kvec scratch;    /* Scratch buffer */
+       struct page **page_ptr; /* pointer to the current page */
  };
  
 +/*
 + * These are the xdr_stream style generic XDR encode and decode functions.
 + */
 +typedef void  (*kxdreproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
 +typedef int   (*kxdrdproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
 +
  extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
  extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
  extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,