NFS: Readdir plus in v4
[linux-2.6-block.git] / fs / nfs / nfs4xdr.c
index b7eff205d3d813c5b02c303f1a29d5e5ca0f7634..ccfb1c92b2624e53016f5486e637efc9ff7b4e67 100644 (file)
@@ -1385,12 +1385,20 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-       uint32_t attrs[2] = {
-               FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
-               FATTR4_WORD1_MOUNTED_ON_FILEID,
-       };
+       uint32_t attrs[2] = {0, 0};
        __be32 *p;
 
+       if (readdir->plus) {
+               attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
+                       FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE;
+               attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
+                       FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
+                       FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
+                       FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+       }
+       attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID;
+       attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
+
        p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
        *p++ = cpu_to_be32(OP_READDIR);
        p = xdr_encode_hyper(p, readdir->cookie);
@@ -1398,11 +1406,15 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
        *p++ = cpu_to_be32(readdir->count >> 1);  /* We're not doing readdirplus */
        *p++ = cpu_to_be32(readdir->count);
        *p++ = cpu_to_be32(2);
-       /* Switch to mounted_on_fileid if the server supports it */
-       if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
-               attrs[0] &= ~FATTR4_WORD0_FILEID;
-       else
-               attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+
+       if (!readdir->plus) {
+               /* Switch to mounted_on_fileid if the server supports it */
+               if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
+                       attrs[0] &= ~FATTR4_WORD0_FILEID;
+               else
+                       attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+       }
+
        *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
        *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
        hdr->nops++;
@@ -5768,7 +5780,8 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
 }
 #endif /* CONFIG_NFS_V4_1 */
 
-__be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, int plus)
+__be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
+                          struct nfs_server *server, int plus)
 {
        uint32_t bitmap[2] = {0};
        uint32_t len;
@@ -5824,24 +5837,10 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, int
                goto out_overflow;
        len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */
        if (len > 0) {
-               if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
-                       bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
-                       /* Ignore the return value of rdattr_error for now */
-                       p = xdr_inline_decode(xdr, 4);
-                       if (unlikely(!p))
-                               goto out_overflow;
-               }
-               if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) {
-                       p = xdr_inline_decode(xdr, 8);
-                       if (unlikely(!p))
-                               goto out_overflow;
-                       xdr_decode_hyper(p, &entry->ino);
-               } else if (bitmap[0] == FATTR4_WORD0_FILEID) {
-                       p = xdr_inline_decode(xdr, 8);
-                       if (unlikely(!p))
-                               goto out_overflow;
-                       xdr_decode_hyper(p, &entry->ino);
-               }
+               if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, server, 1) < 0)
+                       goto out_overflow;
+               if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
+                       entry->ino = entry->fattr->fileid;
        }
 
        p = xdr_inline_peek(xdr, 8);