Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: nfs: Ignore kmemleak false positive in nfs_readdir_make_qstr SUNRPC: Simplify rpc_alloc_iostats by removing pointless local variable nfs: trivial: remove unused nfs_wait_event macro NFS: readdir shouldn't read beyond the reply returned by the server NFS: Fix a couple of regressions in readdir. Revert "NFSv4: Fall back to ordinary lookup if nfs4_atomic_open() returns EISDIR" Regression: fix mounting NFS when NFSv3 support is not compiled NLM: Fix a regression in lockd
This commit is contained in:
commit
1d6636502b
|
@ -124,7 +124,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
|||
continue;
|
||||
if (host->h_server != ni->server)
|
||||
continue;
|
||||
if (ni->server &&
|
||||
if (ni->server && ni->src_len != 0 &&
|
||||
!rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap))
|
||||
continue;
|
||||
|
||||
|
@ -167,6 +167,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
|||
host->h_addrlen = ni->salen;
|
||||
rpc_set_port(nlm_addr(host), 0);
|
||||
memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
|
||||
host->h_srcaddrlen = ni->src_len;
|
||||
host->h_version = ni->version;
|
||||
host->h_proto = ni->protocol;
|
||||
host->h_rpcclnt = NULL;
|
||||
|
@ -238,9 +239,6 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
|
|||
const char *hostname,
|
||||
int noresvport)
|
||||
{
|
||||
const struct sockaddr source = {
|
||||
.sa_family = AF_UNSPEC,
|
||||
};
|
||||
struct nlm_lookup_host_info ni = {
|
||||
.server = 0,
|
||||
.sap = sap,
|
||||
|
@ -249,8 +247,6 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
|
|||
.version = version,
|
||||
.hostname = hostname,
|
||||
.hostname_len = strlen(hostname),
|
||||
.src_sap = &source,
|
||||
.src_len = sizeof(source),
|
||||
.noresvport = noresvport,
|
||||
};
|
||||
|
||||
|
@ -357,7 +353,6 @@ nlm_bind_host(struct nlm_host *host)
|
|||
.protocol = host->h_proto,
|
||||
.address = nlm_addr(host),
|
||||
.addrsize = host->h_addrlen,
|
||||
.saddress = nlm_srcaddr(host),
|
||||
.timeout = &timeparms,
|
||||
.servername = host->h_name,
|
||||
.program = &nlm_program,
|
||||
|
@ -376,6 +371,8 @@ nlm_bind_host(struct nlm_host *host)
|
|||
args.flags |= RPC_CLNT_CREATE_HARDRTRY;
|
||||
if (host->h_noresvport)
|
||||
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
|
||||
if (host->h_srcaddrlen)
|
||||
args.saddress = nlm_srcaddr(host);
|
||||
|
||||
clnt = rpc_create(&args);
|
||||
if (!IS_ERR(clnt))
|
||||
|
|
100
fs/nfs/dir.c
100
fs/nfs/dir.c
|
@ -34,6 +34,7 @@
|
|||
#include <linux/mount.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/kmemleak.h>
|
||||
|
||||
#include "delegation.h"
|
||||
#include "iostat.h"
|
||||
|
@ -194,9 +195,13 @@ typedef struct {
|
|||
static
|
||||
struct nfs_cache_array *nfs_readdir_get_array(struct page *page)
|
||||
{
|
||||
void *ptr;
|
||||
if (page == NULL)
|
||||
return ERR_PTR(-EIO);
|
||||
return (struct nfs_cache_array *)kmap(page);
|
||||
ptr = kmap(page);
|
||||
if (ptr == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -213,6 +218,9 @@ int nfs_readdir_clear_array(struct page *page, gfp_t mask)
|
|||
{
|
||||
struct nfs_cache_array *array = nfs_readdir_get_array(page);
|
||||
int i;
|
||||
|
||||
if (IS_ERR(array))
|
||||
return PTR_ERR(array);
|
||||
for (i = 0; i < array->size; i++)
|
||||
kfree(array->array[i].string.name);
|
||||
nfs_readdir_release_array(page);
|
||||
|
@ -231,6 +239,11 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le
|
|||
string->name = kmemdup(name, len, GFP_KERNEL);
|
||||
if (string->name == NULL)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Avoid a kmemleak false positive. The pointer to the name is stored
|
||||
* in a page cache page which kmemleak does not scan.
|
||||
*/
|
||||
kmemleak_not_leak(string->name);
|
||||
string->hash = full_name_hash(name, len);
|
||||
return 0;
|
||||
}
|
||||
|
@ -244,7 +257,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
|
|||
|
||||
if (IS_ERR(array))
|
||||
return PTR_ERR(array);
|
||||
ret = -EIO;
|
||||
ret = -ENOSPC;
|
||||
if (array->size >= MAX_READDIR_ARRAY)
|
||||
goto out;
|
||||
|
||||
|
@ -255,9 +268,9 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
|
|||
if (ret)
|
||||
goto out;
|
||||
array->last_cookie = entry->cookie;
|
||||
array->size++;
|
||||
if (entry->eof == 1)
|
||||
array->eof_index = array->size;
|
||||
array->size++;
|
||||
out:
|
||||
nfs_readdir_release_array(page);
|
||||
return ret;
|
||||
|
@ -272,7 +285,7 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
|
|||
if (diff < 0)
|
||||
goto out_eof;
|
||||
if (diff >= array->size) {
|
||||
if (array->eof_index > 0)
|
||||
if (array->eof_index >= 0)
|
||||
goto out_eof;
|
||||
desc->current_index += array->size;
|
||||
return -EAGAIN;
|
||||
|
@ -281,8 +294,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
|
|||
index = (unsigned int)diff;
|
||||
*desc->dir_cookie = array->array[index].cookie;
|
||||
desc->cache_entry_index = index;
|
||||
if (index == array->eof_index)
|
||||
desc->eof = 1;
|
||||
return 0;
|
||||
out_eof:
|
||||
desc->eof = 1;
|
||||
|
@ -296,17 +307,17 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
|
|||
int status = -EAGAIN;
|
||||
|
||||
for (i = 0; i < array->size; i++) {
|
||||
if (i == array->eof_index) {
|
||||
desc->eof = 1;
|
||||
status = -EBADCOOKIE;
|
||||
}
|
||||
if (array->array[i].cookie == *desc->dir_cookie) {
|
||||
desc->cache_entry_index = i;
|
||||
status = 0;
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == array->eof_index) {
|
||||
desc->eof = 1;
|
||||
status = -EBADCOOKIE;
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -449,7 +460,7 @@ out:
|
|||
|
||||
/* Perform conversion from xdr to cache array */
|
||||
static
|
||||
void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
|
||||
int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
|
||||
void *xdr_page, struct page *page, unsigned int buflen)
|
||||
{
|
||||
struct xdr_stream stream;
|
||||
|
@ -471,21 +482,29 @@ void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *e
|
|||
|
||||
do {
|
||||
status = xdr_decode(desc, entry, &stream);
|
||||
if (status != 0)
|
||||
if (status != 0) {
|
||||
if (status == -EAGAIN)
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nfs_readdir_add_to_array(entry, page) == -1)
|
||||
break;
|
||||
if (desc->plus == 1)
|
||||
nfs_prime_dcache(desc->file->f_path.dentry, entry);
|
||||
|
||||
status = nfs_readdir_add_to_array(entry, page);
|
||||
if (status != 0)
|
||||
break;
|
||||
} while (!entry->eof);
|
||||
|
||||
if (status == -EBADCOOKIE && entry->eof) {
|
||||
array = nfs_readdir_get_array(page);
|
||||
array->eof_index = array->size - 1;
|
||||
status = 0;
|
||||
nfs_readdir_release_array(page);
|
||||
if (!IS_ERR(array)) {
|
||||
array->eof_index = array->size;
|
||||
status = 0;
|
||||
nfs_readdir_release_array(page);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -537,7 +556,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
|
|||
struct nfs_entry entry;
|
||||
struct file *file = desc->file;
|
||||
struct nfs_cache_array *array;
|
||||
int status = 0;
|
||||
int status = -ENOMEM;
|
||||
unsigned int array_size = ARRAY_SIZE(pages);
|
||||
|
||||
entry.prev_cookie = 0;
|
||||
|
@ -549,6 +568,10 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
|
|||
goto out;
|
||||
|
||||
array = nfs_readdir_get_array(page);
|
||||
if (IS_ERR(array)) {
|
||||
status = PTR_ERR(array);
|
||||
goto out;
|
||||
}
|
||||
memset(array, 0, sizeof(struct nfs_cache_array));
|
||||
array->eof_index = -1;
|
||||
|
||||
|
@ -556,12 +579,19 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
|
|||
if (!pages_ptr)
|
||||
goto out_release_array;
|
||||
do {
|
||||
unsigned int pglen;
|
||||
status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
|
||||
|
||||
if (status < 0)
|
||||
break;
|
||||
nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE);
|
||||
} while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY);
|
||||
pglen = status;
|
||||
status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
|
||||
if (status < 0) {
|
||||
if (status == -ENOSPC)
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
} while (array->eof_index < 0);
|
||||
|
||||
nfs_readdir_free_large_page(pages_ptr, pages, array_size);
|
||||
out_release_array:
|
||||
|
@ -582,8 +612,10 @@ static
|
|||
int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
|
||||
{
|
||||
struct inode *inode = desc->file->f_path.dentry->d_inode;
|
||||
int ret;
|
||||
|
||||
if (nfs_readdir_xdr_to_array(desc, page, inode) < 0)
|
||||
ret = nfs_readdir_xdr_to_array(desc, page, inode);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
SetPageUptodate(page);
|
||||
|
||||
|
@ -595,7 +627,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
|
|||
return 0;
|
||||
error:
|
||||
unlock_page(page);
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -608,12 +640,8 @@ void cache_page_release(nfs_readdir_descriptor_t *desc)
|
|||
static
|
||||
struct page *get_cache_page(nfs_readdir_descriptor_t *desc)
|
||||
{
|
||||
struct page *page;
|
||||
page = read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
|
||||
return read_cache_page(desc->file->f_path.dentry->d_inode->i_mapping,
|
||||
desc->page_index, (filler_t *)nfs_readdir_filler, desc);
|
||||
if (IS_ERR(page))
|
||||
desc->eof = 1;
|
||||
return page;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -639,8 +667,10 @@ int find_cache_page(nfs_readdir_descriptor_t *desc)
|
|||
static inline
|
||||
int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
|
||||
{
|
||||
int res = -EAGAIN;
|
||||
int res;
|
||||
|
||||
if (desc->page_index == 0)
|
||||
desc->current_index = 0;
|
||||
while (1) {
|
||||
res = find_cache_page(desc);
|
||||
if (res != -EAGAIN)
|
||||
|
@ -670,6 +700,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
|
|||
struct dentry *dentry = NULL;
|
||||
|
||||
array = nfs_readdir_get_array(desc->page);
|
||||
if (IS_ERR(array))
|
||||
return PTR_ERR(array);
|
||||
|
||||
for (i = desc->cache_entry_index; i < array->size; i++) {
|
||||
d_type = DT_UNKNOWN;
|
||||
|
@ -685,11 +717,9 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
|
|||
*desc->dir_cookie = array->array[i+1].cookie;
|
||||
else
|
||||
*desc->dir_cookie = array->last_cookie;
|
||||
if (i == array->eof_index) {
|
||||
desc->eof = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == array->eof_index)
|
||||
desc->eof = 1;
|
||||
|
||||
nfs_readdir_release_array(desc->page);
|
||||
cache_page_release(desc);
|
||||
|
@ -1345,12 +1375,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
|
|||
res = NULL;
|
||||
goto out;
|
||||
/* This turned out not to be a regular file */
|
||||
case -EISDIR:
|
||||
case -ENOTDIR:
|
||||
goto no_open;
|
||||
case -ELOOP:
|
||||
if (!(nd->intent.open.flags & O_NOFOLLOW))
|
||||
goto no_open;
|
||||
/* case -EISDIR: */
|
||||
/* case -EINVAL: */
|
||||
default:
|
||||
res = ERR_CAST(inode);
|
||||
|
|
|
@ -423,7 +423,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
|
|||
struct page **page;
|
||||
size_t hdrlen;
|
||||
unsigned int pglen, recvd;
|
||||
int status, nr = 0;
|
||||
int status;
|
||||
|
||||
if ((status = ntohl(*p++)))
|
||||
return nfs_stat_to_errno(status);
|
||||
|
@ -443,7 +443,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
|
|||
if (pglen > recvd)
|
||||
pglen = recvd;
|
||||
page = rcvbuf->pages;
|
||||
return nr;
|
||||
return pglen;
|
||||
}
|
||||
|
||||
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
|
||||
|
|
|
@ -555,7 +555,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
|
|||
struct page **page;
|
||||
size_t hdrlen;
|
||||
u32 recvd, pglen;
|
||||
int status, nr = 0;
|
||||
int status;
|
||||
|
||||
status = ntohl(*p++);
|
||||
/* Decode post_op_attrs */
|
||||
|
@ -586,7 +586,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
|
|||
pglen = recvd;
|
||||
page = rcvbuf->pages;
|
||||
|
||||
return nr;
|
||||
return pglen;
|
||||
}
|
||||
|
||||
__be32 *
|
||||
|
|
|
@ -2852,8 +2852,10 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
|
|||
nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
|
||||
res.pgbase = args.pgbase;
|
||||
status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0);
|
||||
if (status == 0)
|
||||
if (status >= 0) {
|
||||
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
|
||||
status += args.pgbase;
|
||||
}
|
||||
|
||||
nfs_invalidate_atime(dir);
|
||||
|
||||
|
|
|
@ -4518,7 +4518,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
|||
xdr_read_pages(xdr, pglen);
|
||||
|
||||
|
||||
return 0;
|
||||
return pglen;
|
||||
}
|
||||
|
||||
static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
|
||||
|
|
|
@ -67,6 +67,12 @@
|
|||
|
||||
#define NFSDBG_FACILITY NFSDBG_VFS
|
||||
|
||||
#ifdef CONFIG_NFS_V3
|
||||
#define NFS_DEFAULT_VERSION 3
|
||||
#else
|
||||
#define NFS_DEFAULT_VERSION 2
|
||||
#endif
|
||||
|
||||
enum {
|
||||
/* Mount options that take no arguments */
|
||||
Opt_soft, Opt_hard,
|
||||
|
@ -2277,7 +2283,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
|
|||
};
|
||||
int error = -ENOMEM;
|
||||
|
||||
data = nfs_alloc_parsed_mount_data(3);
|
||||
data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
|
||||
mntfh = nfs_alloc_fhandle();
|
||||
if (data == NULL || mntfh == NULL)
|
||||
goto out_free_fh;
|
||||
|
|
|
@ -43,6 +43,7 @@ struct nlm_host {
|
|||
struct sockaddr_storage h_addr; /* peer address */
|
||||
size_t h_addrlen;
|
||||
struct sockaddr_storage h_srcaddr; /* our address (optional) */
|
||||
size_t h_srcaddrlen;
|
||||
struct rpc_clnt *h_rpcclnt; /* RPC client to talk to peer */
|
||||
char *h_name; /* remote hostname */
|
||||
u32 h_version; /* interface version */
|
||||
|
|
|
@ -593,12 +593,6 @@ nfs_fileid_to_ino_t(u64 fileid)
|
|||
return ino;
|
||||
}
|
||||
|
||||
#define nfs_wait_event(clnt, wq, condition) \
|
||||
({ \
|
||||
int __retval = wait_event_killable(wq, condition); \
|
||||
__retval; \
|
||||
})
|
||||
|
||||
#define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
@ -115,9 +115,7 @@ EXPORT_SYMBOL_GPL(svc_seq_show);
|
|||
*/
|
||||
struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
|
||||
{
|
||||
struct rpc_iostats *new;
|
||||
new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
|
||||
return new;
|
||||
return kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
|
||||
|
||||
|
|
Loading…
Reference in a new issue