]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/nfs/nfs3xdr.c
Merge branch 'next-s3c64xx-regs' of git://aeryn.fluff.org.uk/bjdooks/linux into devel
[linux-2.6-omap-h63xx.git] / fs / nfs / nfs3xdr.c
index 3917e2fa4e40f3e1a18c12bee149c576847d4b5f..6cdeacffde469143045588c6b20e6cff72cc586a 100644 (file)
 #define NFS3_commitres_sz      (1+NFS3_wcc_data_sz+2)
 
 #define ACL3_getaclargs_sz     (NFS3_fh_sz+1)
-#define ACL3_setaclargs_sz     (NFS3_fh_sz+1+2*(2+5*3))
-#define ACL3_getaclres_sz      (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
+#define ACL3_setaclargs_sz     (NFS3_fh_sz+1+ \
+                               XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
+#define ACL3_getaclres_sz      (1+NFS3_post_op_attr_sz+1+ \
+                               XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
 #define ACL3_setaclres_sz      (1+NFS3_post_op_attr_sz)
 
 /*
@@ -508,14 +510,14 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
        struct page **page;
        size_t hdrlen;
        u32 len, recvd, pglen;
-       int status, nr;
+       int status, nr = 0;
        __be32 *entry, *end, *kaddr;
 
        status = ntohl(*p++);
        /* Decode post_op_attrs */
        p = xdr_decode_post_op_attr(p, res->dir_attr);
        if (status)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
        /* Decode verifier cookie */
        if (res->verf) {
                res->verf[0] = *p++;
@@ -542,7 +544,12 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
        kaddr = p = kmap_atomic(*page, KM_USER0);
        end = (__be32 *)((char *)p + pglen);
        entry = p;
-       for (nr = 0; *p++; nr++) {
+
+       /* Make sure the packet actually has a value_follows and EOF entry */
+       if ((entry + 1) > end)
+               goto short_pkt;
+
+       for (; *p++; nr++) {
                if (p + 3 > end)
                        goto short_pkt;
                p += 2;                         /* inode # */
@@ -581,18 +588,32 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
                        goto short_pkt;
                entry = p;
        }
-       if (!nr && (entry[0] != 0 || entry[1] == 0))
-               goto short_pkt;
+
+       /*
+        * Apparently some server sends responses that are a valid size, but
+        * contain no entries, and have value_follows==0 and EOF==0. For
+        * those, just set the EOF marker.
+        */
+       if (!nr && entry[1] == 0) {
+               dprintk("NFS: readdir reply truncated!\n");
+               entry[1] = 1;
+       }
  out:
        kunmap_atomic(kaddr, KM_USER0);
        return nr;
  short_pkt:
+       /*
+        * When we get a short packet there are 2 possibilities. We can
+        * return an error, or fix up the response to look like a valid
+        * response and return what we have so far. If there are no
+        * entries and the packet was short, then return -EIO. If there
+        * are valid entries in the response, return them and pretend that
+        * the call was successful, but incomplete. The caller can retry the
+        * readdir starting at the last cookie.
+        */
        entry[0] = entry[1] = 0;
-       /* truncate listing ? */
-       if (!nr) {
-               dprintk("NFS: readdir reply truncated!\n");
-               entry[1] = 1;
-       }
+       if (!nr)
+               nr = -errno_NFSERR_IO;
        goto out;
 err_unmap:
        nr = -errno_NFSERR_IO;
@@ -684,28 +705,18 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
                    struct nfs3_setaclargs *args)
 {
        struct xdr_buf *buf = &req->rq_snd_buf;
-       unsigned int base, len_in_head, len = nfsacl_size(
-               (args->mask & NFS_ACL)   ? args->acl_access  : NULL,
-               (args->mask & NFS_DFACL) ? args->acl_default : NULL);
-       int count, err;
+       unsigned int base;
+       int err;
 
        p = xdr_encode_fhandle(p, NFS_FH(args->inode));
        *p++ = htonl(args->mask);
-       base = (char *)p - (char *)buf->head->iov_base;
-       /* put as much of the acls into head as possible. */
-       len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
-       len -= len_in_head;
-       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
-
-       for (count = 0; (count << PAGE_SHIFT) < len; count++) {
-               args->pages[count] = alloc_page(GFP_KERNEL);
-               if (!args->pages[count]) {
-                       while (count)
-                               __free_page(args->pages[--count]);
-                       return -ENOMEM;
-               }
-       }
-       xdr_encode_pages(buf, args->pages, 0, len);
+       req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+       base = req->rq_slen;
+
+       if (args->npages != 0)
+               xdr_encode_pages(buf, args->pages, 0, args->len);
+       else
+               req->rq_slen += args->len;
 
        err = nfsacl_encode(buf, base, args->inode,
                            (args->mask & NFS_ACL) ?
@@ -732,7 +743,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        int     status;
 
        if ((status = ntohl(*p++)))
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
        xdr_decode_fattr(p, fattr);
        return 0;
 }
@@ -747,7 +758,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        int     status;
 
        if ((status = ntohl(*p++)))
-               status = -nfs_stat_to_errno(status);
+               status = nfs_stat_to_errno(status);
        xdr_decode_wcc_data(p, fattr);
        return status;
 }
@@ -767,7 +778,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
        int     status;
 
        if ((status = ntohl(*p++))) {
-               status = -nfs_stat_to_errno(status);
+               status = nfs_stat_to_errno(status);
        } else {
                if (!(p = xdr_decode_fhandle(p, res->fh)))
                        return -errno_NFSERR_IO;
@@ -787,7 +798,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
 
        p = xdr_decode_post_op_attr(p, res->fattr);
        if (status)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
        res->access = ntohl(*p++);
        return 0;
 }
@@ -824,7 +835,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        p = xdr_decode_post_op_attr(p, fattr);
 
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
 
        /* Convert length of symlink */
        len = ntohl(*p++);
@@ -872,7 +883,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
        p = xdr_decode_post_op_attr(p, res->fattr);
 
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
 
        /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
         * in that it puts the count both in the res struct and in the
@@ -922,7 +933,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
        p = xdr_decode_wcc_data(p, res->fattr);
 
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
 
        res->count = ntohl(*p++);
        res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
@@ -953,7 +964,7 @@ nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
                        res->fattr->valid = 0;
                }
        } else {
-               status = -nfs_stat_to_errno(status);
+               status = nfs_stat_to_errno(status);
        }
        p = xdr_decode_wcc_data(p, res->dir_attr);
        return status;
@@ -968,7 +979,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
        int     status;
 
        if ((status = ntohl(*p++)) != 0)
-               status = -nfs_stat_to_errno(status);
+               status = nfs_stat_to_errno(status);
        p = xdr_decode_wcc_data(p, res->fromattr);
        p = xdr_decode_wcc_data(p, res->toattr);
        return status;
@@ -983,7 +994,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
        int     status;
 
        if ((status = ntohl(*p++)) != 0)
-               status = -nfs_stat_to_errno(status);
+               status = nfs_stat_to_errno(status);
        p = xdr_decode_post_op_attr(p, res->fattr);
        p = xdr_decode_wcc_data(p, res->dir_attr);
        return status;
@@ -1001,7 +1012,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
 
        p = xdr_decode_post_op_attr(p, res->fattr);
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
 
        p = xdr_decode_hyper(p, &res->tbytes);
        p = xdr_decode_hyper(p, &res->fbytes);
@@ -1026,7 +1037,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
 
        p = xdr_decode_post_op_attr(p, res->fattr);
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
 
        res->rtmax  = ntohl(*p++);
        res->rtpref = ntohl(*p++);
@@ -1054,7 +1065,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
 
        p = xdr_decode_post_op_attr(p, res->fattr);
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
        res->max_link = ntohl(*p++);
        res->max_namelen = ntohl(*p++);
 
@@ -1073,7 +1084,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
        status = ntohl(*p++);
        p = xdr_decode_wcc_data(p, res->fattr);
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
 
        res->verf->verifier[0] = *p++;
        res->verf->verifier[1] = *p++;
@@ -1095,7 +1106,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
        int err, base;
 
        if (status != 0)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
        p = xdr_decode_post_op_attr(p, res->fattr);
        res->mask = ntohl(*p++);
        if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
@@ -1122,7 +1133,7 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
        int status = ntohl(*p++);
 
        if (status)
-               return -nfs_stat_to_errno(status);
+               return nfs_stat_to_errno(status);
        xdr_decode_post_op_attr(p, fattr);
        return 0;
 }