NFS: Fix a readdirplus bug
[pandora-kernel.git] / fs / nfs / dir.c
index ddc2e43..f0a384e 100644 (file)
@@ -162,6 +162,7 @@ struct nfs_cache_array_entry {
        u64 cookie;
        u64 ino;
        struct qstr string;
        u64 cookie;
        u64 ino;
        struct qstr string;
+       unsigned char d_type;
 };
 
 struct nfs_cache_array {
 };
 
 struct nfs_cache_array {
@@ -171,8 +172,6 @@ struct nfs_cache_array {
        struct nfs_cache_array_entry array[0];
 };
 
        struct nfs_cache_array_entry array[0];
 };
 
-#define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry))
-
 typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 typedef struct {
        struct file     *file;
 typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 typedef struct {
        struct file     *file;
@@ -257,13 +256,17 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
 
        if (IS_ERR(array))
                return PTR_ERR(array);
 
        if (IS_ERR(array))
                return PTR_ERR(array);
+
+       cache_entry = &array->array[array->size];
+
+       /* Check that this entry lies within the page bounds */
        ret = -ENOSPC;
        ret = -ENOSPC;
-       if (array->size >= MAX_READDIR_ARRAY)
+       if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE)
                goto out;
 
                goto out;
 
-       cache_entry = &array->array[array->size];
        cache_entry->cookie = entry->prev_cookie;
        cache_entry->ino = entry->ino;
        cache_entry->cookie = entry->prev_cookie;
        cache_entry->ino = entry->ino;
+       cache_entry->d_type = entry->d_type;
        ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
        if (ret)
                goto out;
        ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
        if (ret)
                goto out;
@@ -392,13 +395,9 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct x
 static
 int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
 {
 static
 int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
 {
-       struct nfs_inode *node;
        if (dentry->d_inode == NULL)
                goto different;
        if (dentry->d_inode == NULL)
                goto different;
-       node = NFS_I(dentry->d_inode);
-       if (node->fh.size != entry->fh->size)
-               goto different;
-       if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0)
+       if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
                goto different;
        return 1;
 different:
                goto different;
        return 1;
 different:
@@ -700,7 +699,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
        int i = 0;
        int res = 0;
        struct nfs_cache_array *array = NULL;
        int i = 0;
        int res = 0;
        struct nfs_cache_array *array = NULL;
-       unsigned int d_type = DT_UNKNOWN;
 
        array = nfs_readdir_get_array(desc->page);
        if (IS_ERR(array)) {
 
        array = nfs_readdir_get_array(desc->page);
        if (IS_ERR(array)) {
@@ -710,11 +708,11 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
 
        for (i = desc->cache_entry_index; i < array->size; i++) {
                struct nfs_cache_array_entry *ent;
 
        for (i = desc->cache_entry_index; i < array->size; i++) {
                struct nfs_cache_array_entry *ent;
-               d_type = DT_UNKNOWN;
 
                ent = &array->array[i];
                if (filldir(dirent, ent->string.name, ent->string.len,
 
                ent = &array->array[i];
                if (filldir(dirent, ent->string.name, ent->string.len,
-                   file->f_pos, nfs_compat_user_ino64(ent->ino), d_type) < 0) {
+                   file->f_pos, nfs_compat_user_ino64(ent->ino),
+                   ent->d_type) < 0) {
                        desc->eof = 1;
                        break;
                }
                        desc->eof = 1;
                        break;
                }