Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19650e85 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  NFS: Ensure we return the dirent->d_type when it is known
  NFS: Correct the array bound calculation in nfs_readdir_add_to_array
  NFS: Don't ignore errors from nfs_do_filldir()
  NFS: Fix the error handling in "uncached_readdir()"
  NFS: Fix a page leak in uncached_readdir()
  NFS: Fix a page leak in nfs_do_filldir()
  NFS: Assume eof if the server returns no readdir records
  NFS: Buffer overflow in ->decode_dirent() should not be fatal
  Pure nfs client performance using odirect.
  SUNRPC: Fix an infinite loop in call_refresh/call_refreshresult
parents 1eb4c636 0b26a0bf
Loading
Loading
Loading
Loading
+34 −28
Original line number Original line Diff line number Diff line
@@ -162,6 +162,7 @@ struct nfs_cache_array_entry {
	u64 cookie;
	u64 cookie;
	u64 ino;
	u64 ino;
	struct qstr string;
	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 __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
typedef struct {
typedef struct {
	struct file	*file;
	struct file	*file;
@@ -257,13 +256,17 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)


	if (IS_ERR(array))
	if (IS_ERR(array))
		return PTR_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->cookie = entry->prev_cookie;
	cache_entry->ino = entry->ino;
	cache_entry->ino = entry->ino;
	cache_entry->d_type = entry->d_type;
	ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
	ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
	if (ret)
	if (ret)
		goto out;
		goto out;
@@ -466,8 +469,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
	struct xdr_stream stream;
	struct xdr_stream stream;
	struct xdr_buf buf;
	struct xdr_buf buf;
	__be32 *ptr = xdr_page;
	__be32 *ptr = xdr_page;
	int status;
	struct nfs_cache_array *array;
	struct nfs_cache_array *array;
	unsigned int count = 0;
	int status;


	buf.head->iov_base = xdr_page;
	buf.head->iov_base = xdr_page;
	buf.head->iov_len = buflen;
	buf.head->iov_len = buflen;
@@ -488,6 +492,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
			break;
			break;
		}
		}


		count++;

		if (desc->plus == 1)
		if (desc->plus == 1)
			nfs_prime_dcache(desc->file->f_path.dentry, entry);
			nfs_prime_dcache(desc->file->f_path.dentry, entry);


@@ -496,13 +502,14 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
			break;
			break;
	} while (!entry->eof);
	} while (!entry->eof);


	if (status == -EBADCOOKIE && entry->eof) {
	if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) {
		array = nfs_readdir_get_array(page);
		array = nfs_readdir_get_array(page);
		if (!IS_ERR(array)) {
		if (!IS_ERR(array)) {
			array->eof_index = array->size;
			array->eof_index = array->size;
			status = 0;
			status = 0;
			nfs_readdir_release_array(page);
			nfs_readdir_release_array(page);
		}
		} else
			status = PTR_ERR(array);
	}
	}
	return status;
	return status;
}
}
@@ -696,21 +703,23 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
	int i = 0;
	int i = 0;
	int res = 0;
	int res = 0;
	struct nfs_cache_array *array = NULL;
	struct nfs_cache_array *array = NULL;
	unsigned int d_type = DT_UNKNOWN;
	struct dentry *dentry = NULL;


	array = nfs_readdir_get_array(desc->page);
	array = nfs_readdir_get_array(desc->page);
	if (IS_ERR(array))
	if (IS_ERR(array)) {
		return PTR_ERR(array);
		res = PTR_ERR(array);
		goto out;
	}


	for (i = desc->cache_entry_index; i < array->size; i++) {
	for (i = desc->cache_entry_index; i < array->size; i++) {
		d_type = DT_UNKNOWN;
		struct nfs_cache_array_entry *ent;


		res = filldir(dirent, array->array[i].string.name,
		ent = &array->array[i];
			array->array[i].string.len, file->f_pos,
		if (filldir(dirent, ent->string.name, ent->string.len,
			nfs_compat_user_ino64(array->array[i].ino), d_type);
		    file->f_pos, nfs_compat_user_ino64(ent->ino),
		if (res < 0)
		    ent->d_type) < 0) {
			desc->eof = 1;
			break;
			break;
		}
		file->f_pos++;
		file->f_pos++;
		desc->cache_entry_index = i;
		desc->cache_entry_index = i;
		if (i < (array->size-1))
		if (i < (array->size-1))
@@ -722,9 +731,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
		desc->eof = 1;
		desc->eof = 1;


	nfs_readdir_release_array(desc->page);
	nfs_readdir_release_array(desc->page);
out:
	cache_page_release(desc);
	cache_page_release(desc);
	if (dentry != NULL)
		dput(dentry);
	dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
	dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
			(unsigned long long)*desc->dir_cookie, res);
			(unsigned long long)*desc->dir_cookie, res);
	return res;
	return res;
@@ -759,13 +767,13 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
		goto out;
		goto out;
	}
	}


	if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) {
		status = -EIO;
		goto out_release;
	}

	desc->page_index = 0;
	desc->page_index = 0;
	desc->page = page;
	desc->page = page;

	status = nfs_readdir_xdr_to_array(desc, page, inode);
	if (status < 0)
		goto out_release;

	status = nfs_do_filldir(desc, dirent, filldir);
	status = nfs_do_filldir(desc, dirent, filldir);


 out:
 out:
@@ -816,14 +824,14 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
		res = readdir_search_pagecache(desc);
		res = readdir_search_pagecache(desc);


		if (res == -EBADCOOKIE) {
		if (res == -EBADCOOKIE) {
			res = 0;
			/* This means either end of directory */
			/* This means either end of directory */
			if (*desc->dir_cookie && desc->eof == 0) {
			if (*desc->dir_cookie && desc->eof == 0) {
				/* Or that the server has 'lost' a cookie */
				/* Or that the server has 'lost' a cookie */
				res = uncached_readdir(desc, dirent, filldir);
				res = uncached_readdir(desc, dirent, filldir);
				if (res >= 0)
				if (res == 0)
					continue;
					continue;
			}
			}
			res = 0;
			break;
			break;
		}
		}
		if (res == -ETOOSMALL && desc->plus) {
		if (res == -ETOOSMALL && desc->plus) {
@@ -838,11 +846,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
			break;
			break;


		res = nfs_do_filldir(desc, dirent, filldir);
		res = nfs_do_filldir(desc, dirent, filldir);
		if (res < 0) {
		if (res < 0)
			res = 0;
			break;
			break;
	}
	}
	}
out:
out:
	nfs_unblock_sillyrename(dentry);
	nfs_unblock_sillyrename(dentry);
	if (res > 0)
	if (res > 0)
+1 −1
Original line number Original line Diff line number Diff line
@@ -867,7 +867,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
		goto out;
		goto out;
	nfs_alloc_commit_data(dreq);
	nfs_alloc_commit_data(dreq);


	if (dreq->commit_data == NULL || count < wsize)
	if (dreq->commit_data == NULL || count <= wsize)
		sync = NFS_FILE_SYNC;
		sync = NFS_FILE_SYNC;


	dreq->inode = inode;
	dreq->inode = inode;
+9 −0
Original line number Original line Diff line number Diff line
@@ -361,6 +361,15 @@ unsigned int nfs_page_length(struct page *page)
	return 0;
	return 0;
}
}


/*
 * Convert a umode to a dirent->d_type
 */
static inline
unsigned char nfs_umode_to_dtype(umode_t mode)
{
	return (mode >> 12) & 15;
}

/*
/*
 * Determine the number of pages in an array of length 'len' and
 * Determine the number of pages in an array of length 'len' and
 * with a base offset of 'base'
 * with a base offset of 'base'
+3 −1
Original line number Original line Diff line number Diff line
@@ -485,6 +485,8 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se
	entry->prev_cookie	  = entry->cookie;
	entry->prev_cookie	  = entry->cookie;
	entry->cookie	  = ntohl(*p++);
	entry->cookie	  = ntohl(*p++);


	entry->d_type = DT_UNKNOWN;

	p = xdr_inline_peek(xdr, 8);
	p = xdr_inline_peek(xdr, 8);
	if (p != NULL)
	if (p != NULL)
		entry->eof = !p[0] && p[1];
		entry->eof = !p[0] && p[1];
@@ -495,7 +497,7 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se


out_overflow:
out_overflow:
	print_overflow_msg(__func__, xdr);
	print_overflow_msg(__func__, xdr);
	return ERR_PTR(-EIO);
	return ERR_PTR(-EAGAIN);
}
}


/*
/*
+3 −1
Original line number Original line Diff line number Diff line
@@ -622,11 +622,13 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s
	entry->prev_cookie = entry->cookie;
	entry->prev_cookie = entry->cookie;
	p = xdr_decode_hyper(p, &entry->cookie);
	p = xdr_decode_hyper(p, &entry->cookie);


	entry->d_type = DT_UNKNOWN;
	if (plus) {
	if (plus) {
		entry->fattr->valid = 0;
		entry->fattr->valid = 0;
		p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
		p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
		if (IS_ERR(p))
		if (IS_ERR(p))
			goto out_overflow_exit;
			goto out_overflow_exit;
		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
		/* In fact, a post_op_fh3: */
		/* In fact, a post_op_fh3: */
		p = xdr_inline_decode(xdr, 4);
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
		if (unlikely(!p))
@@ -656,7 +658,7 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s
out_overflow:
out_overflow:
	print_overflow_msg(__func__, xdr);
	print_overflow_msg(__func__, xdr);
out_overflow_exit:
out_overflow_exit:
	return ERR_PTR(-EIO);
	return ERR_PTR(-EAGAIN);
}
}


/*
/*
Loading