NFSv4: in readdir, use MOUNTED_ON_FILEID, rather than true fileid Some servers return an error if the READDIR call attempts to read the fileid of a mountpoint. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 1 + fs/nfs/nfs4xdr.c | 24 +++++++++++++++++------- include/linux/nfs_xdr.h | 1 + 3 files changed, 19 insertions(+), 7 deletions(-) Index: linux-2.6.11/fs/nfs/nfs4xdr.c =================================================================== --- linux-2.6.11.orig/fs/nfs/nfs4xdr.c +++ linux-2.6.11/fs/nfs/nfs4xdr.c @@ -1010,8 +1010,13 @@ static int encode_readdir(struct xdr_str WRITE32(readdir->count >> 1); /* We're not doing readdirplus */ WRITE32(readdir->count); WRITE32(2); - WRITE32(FATTR4_WORD0_FILEID); - WRITE32(0); + if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) { + WRITE32(0); + WRITE32(FATTR4_WORD1_MOUNTED_ON_FILEID); + } else { + WRITE32(FATTR4_WORD0_FILEID); + WRITE32(0); + } /* set up reply kvec * toplevel_status + taglen + rescount + OP_PUTFH + status @@ -3857,7 +3862,7 @@ static int nfs4_xdr_dec_delegreturn(stru uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus) { - uint32_t bitmap[1] = {0}; + uint32_t bitmap[2] = {0}; uint32_t len; if (!*p++) { @@ -3881,13 +3886,18 @@ uint32_t *nfs4_decode_dirent(uint32_t *p entry->ino = 1; len = ntohl(*p++); /* bitmap length */ - if (len > 0) { - bitmap[0] = ntohl(*p); - p += len; + if (len-- > 0) { + bitmap[0] = ntohl(*p++); + if (len-- > 0) { + bitmap[1] = ntohl(*p++); + p += len; + } } len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ if (len > 0) { - if (bitmap[0] == FATTR4_WORD0_FILEID) + if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) + xdr_decode_hyper(p, &entry->ino); + else if (bitmap[0] == FATTR4_WORD0_FILEID) xdr_decode_hyper(p, &entry->ino); p += len; } Index: linux-2.6.11/fs/nfs/nfs4proc.c =================================================================== --- linux-2.6.11.orig/fs/nfs/nfs4proc.c +++ linux-2.6.11/fs/nfs/nfs4proc.c @@ -1720,6 +1720,7 @@ static int _nfs4_proc_readdir(struct den .pages = &page, .pgbase = 0, .count = count, + .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, }; struct nfs4_readdir_res res; struct rpc_message msg = { Index: linux-2.6.11/include/linux/nfs_xdr.h =================================================================== --- linux-2.6.11.orig/include/linux/nfs_xdr.h +++ linux-2.6.11/include/linux/nfs_xdr.h @@ -563,6 +563,7 @@ struct nfs4_readdir_arg { u32 count; struct page ** pages; /* zero-copy data */ unsigned int pgbase; /* zero-copy data */ + const u32 * bitmask; }; struct nfs4_readdir_res {