Commit f4921aff authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.linux-nfs.org/pub/linux/nfs-2.6

* git://git.linux-nfs.org/pub/linux/nfs-2.6: (131 commits)
  NFSv4: Fix a typo in nfs_inode_reclaim_delegation
  NFS: Add a boot parameter to disable 64 bit inode numbers
  NFS: nfs_refresh_inode should clear cache_validity flags on success
  NFS: Fix a connectathon regression in NFSv3 and NFSv4
  NFS: Use nfs_refresh_inode() in ops that aren't expected to change the inode
  SUNRPC: Don't call xprt_release in call refresh
  SUNRPC: Don't call xprt_release() if call_allocate fails
  SUNRPC: Fix buggy UDP transmission
  [23/37] Clean up duplicate includes in
  [2.6 patch] net/sunrpc/rpcb_clnt.c: make struct rpcb_program static
  SUNRPC: Use correct type in buffer length calculations
  SUNRPC: Fix default hostname created in rpc_create()
  nfs: add server port to rpc_pipe info file
  NFS: Get rid of some obsolete macros
  NFS: Simplify filehandle revalidation
  NFS: Ensure that nfs_link() returns a hashed dentry
  NFS: Be strict about dentry revalidation when doing exclusive create
  NFS: Don't zap the readdir caches upon error
  NFS: Remove the redundant nfs_reval_fsid()
  NFSv3: Always use directory post-op attributes in nfs3_proc_lookup
  ...

Fix up trivial conflict due to sock_owned_by_user() cleanup manually in
net/sunrpc/xprtsock.c
parents 419217cb 05c88bab
...@@ -1083,6 +1083,13 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -1083,6 +1083,13 @@ and is between 256 and 4096 characters. It is defined in the file
[NFS] set the maximum lifetime for idmapper cache [NFS] set the maximum lifetime for idmapper cache
entries. entries.
nfs.enable_ino64=
[NFS] enable 64-bit inode numbers.
If zero, the NFS client will fake up a 32-bit inode
number for the readdir() and stat() syscalls instead
of returning the full 64-bit number.
The default is to return 64-bit inode numbers.
nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels nmi_watchdog= [KNL,BUGS=X86-32] Debugging features for SMP kernels
no387 [BUGS=X86-32] Tells the kernel to use the 387 maths no387 [BUGS=X86-32] Tells the kernel to use the 387 maths
......
...@@ -1755,6 +1755,14 @@ config SUNRPC ...@@ -1755,6 +1755,14 @@ config SUNRPC
config SUNRPC_GSS config SUNRPC_GSS
tristate tristate
config SUNRPC_XPRT_RDMA
tristate "RDMA transport for sunrpc (EXPERIMENTAL)"
depends on SUNRPC && INFINIBAND && EXPERIMENTAL
default m
help
Adds a client RPC transport for supporting kernel NFS over RDMA
mounts, including Infiniband and iWARP. Experimental.
config SUNRPC_BIND34 config SUNRPC_BIND34
bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL depends on SUNRPC && EXPERIMENTAL
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/xprtsock.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h> #include <linux/lockd/sm_inter.h>
...@@ -132,7 +133,7 @@ nsm_create(void) ...@@ -132,7 +133,7 @@ nsm_create(void)
.sin_port = 0, .sin_port = 0,
}; };
struct rpc_create_args args = { struct rpc_create_args args = {
.protocol = IPPROTO_UDP, .protocol = XPRT_TRANSPORT_UDP,
.address = (struct sockaddr *)&sin, .address = (struct sockaddr *)&sin,
.addrsize = sizeof(sin), .addrsize = sizeof(sin),
.servername = "localhost", .servername = "localhost",
......
...@@ -62,8 +62,9 @@ static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) ...@@ -62,8 +62,9 @@ static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
} }
else else
{ {
printk(KERN_NOTICE dprintk("lockd: bad cookie size %d (only cookies under "
"lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); "%d bytes are supported.)\n",
len, NLM_MAXCOOKIELEN);
return NULL; return NULL;
} }
return p; return p;
...@@ -84,8 +85,7 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f) ...@@ -84,8 +85,7 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f)
unsigned int len; unsigned int len;
if ((len = ntohl(*p++)) != NFS2_FHSIZE) { if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
printk(KERN_NOTICE dprintk("lockd: bad fhandle size %d (should be %d)\n",
"lockd: bad fhandle size %d (should be %d)\n",
len, NFS2_FHSIZE); len, NFS2_FHSIZE);
return NULL; return NULL;
} }
......
...@@ -64,8 +64,9 @@ nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) ...@@ -64,8 +64,9 @@ nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
} }
else else
{ {
printk(KERN_NOTICE dprintk("lockd: bad cookie size %d (only cookies under "
"lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); "%d bytes are supported.)\n",
len, NLM_MAXCOOKIELEN);
return NULL; return NULL;
} }
return p; return p;
...@@ -86,8 +87,7 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f) ...@@ -86,8 +87,7 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
memset(f->data, 0, sizeof(f->data)); memset(f->data, 0, sizeof(f->data));
f->size = ntohl(*p++); f->size = ntohl(*p++);
if (f->size > NFS_MAXFHSIZE) { if (f->size > NFS_MAXFHSIZE) {
printk(KERN_NOTICE dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
"lockd: bad fhandle size %d (should be <=%d)\n",
f->size, NFS_MAXFHSIZE); f->size, NFS_MAXFHSIZE);
return NULL; return NULL;
} }
......
...@@ -16,4 +16,3 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ ...@@ -16,4 +16,3 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
nfs4namespace.o nfs4namespace.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-objs := $(nfs-y)
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h> #include <linux/sunrpc/stats.h>
#include <linux/sunrpc/metrics.h> #include <linux/sunrpc/metrics.h>
#include <linux/sunrpc/xprtsock.h>
#include <linux/sunrpc/xprtrdma.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_mount.h> #include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h> #include <linux/nfs4_mount.h>
...@@ -340,7 +342,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, ...@@ -340,7 +342,8 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_retries = 2; to->to_retries = 2;
switch (proto) { switch (proto) {
case IPPROTO_TCP: case XPRT_TRANSPORT_TCP:
case XPRT_TRANSPORT_RDMA:
if (!to->to_initval) if (!to->to_initval)
to->to_initval = 60 * HZ; to->to_initval = 60 * HZ;
if (to->to_initval > NFS_MAX_TCP_TIMEOUT) if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
...@@ -349,7 +352,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, ...@@ -349,7 +352,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
to->to_exponential = 0; to->to_exponential = 0;
break; break;
case IPPROTO_UDP: case XPRT_TRANSPORT_UDP:
default: default:
if (!to->to_initval) if (!to->to_initval)
to->to_initval = 11 * HZ / 10; to->to_initval = 11 * HZ / 10;
...@@ -501,9 +504,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t ...@@ -501,9 +504,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t
/* /*
* Initialise an NFS2 or NFS3 client * Initialise an NFS2 or NFS3 client
*/ */
static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data) static int nfs_init_client(struct nfs_client *clp,
const struct nfs_parsed_mount_data *data)
{ {
int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
int error; int error;
if (clp->cl_cons_state == NFS_CS_READY) { if (clp->cl_cons_state == NFS_CS_READY) {
...@@ -522,8 +525,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data * ...@@ -522,8 +525,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *
* Create a client RPC handle for doing FSSTAT with UNIX auth only * Create a client RPC handle for doing FSSTAT with UNIX auth only
* - RFC 2623, sec 2.3.2 * - RFC 2623, sec 2.3.2
*/ */
error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, error = nfs_create_rpc_client(clp, data->nfs_server.protocol,
RPC_AUTH_UNIX, 0); data->timeo, data->retrans, RPC_AUTH_UNIX, 0);
if (error < 0) if (error < 0)
goto error; goto error;
nfs_mark_client_ready(clp, NFS_CS_READY); nfs_mark_client_ready(clp, NFS_CS_READY);
...@@ -538,7 +541,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data * ...@@ -538,7 +541,8 @@ static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *
/* /*
* Create a version 2 or 3 client * Create a version 2 or 3 client
*/ */
static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data) static int nfs_init_server(struct nfs_server *server,
const struct nfs_parsed_mount_data *data)
{ {
struct nfs_client *clp; struct nfs_client *clp;
int error, nfsvers = 2; int error, nfsvers = 2;
...@@ -551,7 +555,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat ...@@ -551,7 +555,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
#endif #endif
/* Allocate or find a client reference we can use */ /* Allocate or find a client reference we can use */
clp = nfs_get_client(data->hostname, &data->addr, nfsvers); clp = nfs_get_client(data->nfs_server.hostname,
&data->nfs_server.address, nfsvers);
if (IS_ERR(clp)) { if (IS_ERR(clp)) {
dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
return PTR_ERR(clp); return PTR_ERR(clp);
...@@ -581,7 +586,7 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat ...@@ -581,7 +586,7 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
if (error < 0) if (error < 0)
goto error; goto error;
error = nfs_init_server_rpcclient(server, data->pseudoflavor); error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
if (error < 0) if (error < 0)
goto error; goto error;
...@@ -760,7 +765,7 @@ void nfs_free_server(struct nfs_server *server) ...@@ -760,7 +765,7 @@ void nfs_free_server(struct nfs_server *server)
* Create a version 2 or 3 volume record * Create a version 2 or 3 volume record
* - keyed on server and FSID * - keyed on server and FSID
*/ */
struct nfs_server *nfs_create_server(const struct nfs_mount_data *data, struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
struct nfs_fh *mntfh) struct nfs_fh *mntfh)
{ {
struct nfs_server *server; struct nfs_server *server;
...@@ -906,7 +911,7 @@ static int nfs4_set_client(struct nfs_server *server, ...@@ -906,7 +911,7 @@ static int nfs4_set_client(struct nfs_server *server,
* Create a version 4 volume record * Create a version 4 volume record
*/ */
static int nfs4_init_server(struct nfs_server *server, static int nfs4_init_server(struct nfs_server *server,
const struct nfs4_mount_data *data, rpc_authflavor_t authflavour) const struct nfs_parsed_mount_data *data)
{ {
int error; int error;
...@@ -926,7 +931,7 @@ static int nfs4_init_server(struct nfs_server *server, ...@@ -926,7 +931,7 @@ static int nfs4_init_server(struct nfs_server *server,
server->acdirmin = data->acdirmin * HZ; server->acdirmin = data->acdirmin * HZ;
server->acdirmax = data->acdirmax * HZ; server->acdirmax = data->acdirmax * HZ;
error = nfs_init_server_rpcclient(server, authflavour); error = nfs_init_server_rpcclient(server, data->auth_flavors[0]);
/* Done */ /* Done */
dprintk("<-- nfs4_init_server() = %d\n", error); dprintk("<-- nfs4_init_server() = %d\n", error);
...@@ -937,12 +942,7 @@ static int nfs4_init_server(struct nfs_server *server, ...@@ -937,12 +942,7 @@ static int nfs4_init_server(struct nfs_server *server,
* Create a version 4 volume record * Create a version 4 volume record
* - keyed on server and FSID * - keyed on server and FSID
*/ */
struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
const char *hostname,
const struct sockaddr_in *addr,
const char *mntpath,
const char *ip_addr,
rpc_authflavor_t authflavour,
struct nfs_fh *mntfh) struct nfs_fh *mntfh)
{ {
struct nfs_fattr fattr; struct nfs_fattr fattr;
...@@ -956,13 +956,18 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, ...@@ -956,13 +956,18 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* Get a client record */ /* Get a client record */
error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour, error = nfs4_set_client(server,
data->proto, data->timeo, data->retrans); data->nfs_server.hostname,
&data->nfs_server.address,
data->client_address,
data->auth_flavors[0],
data->nfs_server.protocol,
data->timeo, data->retrans);
if (error < 0) if (error < 0)
goto error; goto error;
/* set up the general RPC client */ /* set up the general RPC client */
error = nfs4_init_server(server, data, authflavour); error = nfs4_init_server(server, data);
if (error < 0) if (error < 0)
goto error; goto error;
...@@ -971,7 +976,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, ...@@ -971,7 +976,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
/* Probe the root fh to retrieve its FSID */ /* Probe the root fh to retrieve its FSID */
error = nfs4_path_walk(server, mntfh, mntpath); error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path);
if (error < 0) if (error < 0)
goto error; goto error;
......
...@@ -52,7 +52,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ ...@@ -52,7 +52,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) { for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue; continue;
if ((struct nfs_open_context *)fl->fl_file->private_data != ctx) if (nfs_file_open_context(fl->fl_file) != ctx)
continue; continue;
status = nfs4_lock_delegation_recall(state, fl); status = nfs4_lock_delegation_recall(state, fl);
if (status >= 0) if (status >= 0)
...@@ -109,6 +109,7 @@ static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid * ...@@ -109,6 +109,7 @@ static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{ {
struct nfs_delegation *delegation = NFS_I(inode)->delegation; struct nfs_delegation *delegation = NFS_I(inode)->delegation;
struct rpc_cred *oldcred;
if (delegation == NULL) if (delegation == NULL)
return; return;
...@@ -116,11 +117,12 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st ...@@ -116,11 +117,12 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
sizeof(delegation->stateid.data)); sizeof(delegation->stateid.data));
delegation->type = res->delegation_type; delegation->type = res->delegation_type;
delegation->maxsize = res->maxsize; delegation->maxsize = res->maxsize;
put_rpccred(cred); oldcred = delegation->cred;
delegation->cred = get_rpccred(cred); delegation->cred = get_rpccred(cred);
delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM; delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
NFS_I(inode)->delegation_state = delegation->type; NFS_I(inode)->delegation_state = delegation->type;
smp_wmb(); smp_wmb();
put_rpccred(oldcred);
} }
/* /*
......
This diff is collapsed.
...@@ -368,7 +368,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size ...@@ -368,7 +368,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
return -ENOMEM; return -ENOMEM;
dreq->inode = inode; dreq->inode = inode;
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
dreq->iocb = iocb; dreq->iocb = iocb;
...@@ -510,7 +510,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode ...@@ -510,7 +510,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
nfs_direct_write_reschedule(dreq); nfs_direct_write_reschedule(dreq);
break; break;
default: default:
nfs_end_data_update(inode);
if (dreq->commit_data != NULL) if (dreq->commit_data != NULL)
nfs_commit_free(dreq->commit_data); nfs_commit_free(dreq->commit_data);
nfs_direct_free_writedata(dreq); nfs_direct_free_writedata(dreq);
...@@ -533,7 +532,6 @@ static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq) ...@@ -533,7 +532,6 @@ static inline void nfs_alloc_commit_data(struct nfs_direct_req *dreq)
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode)
{ {
nfs_end_data_update(inode);
nfs_direct_free_writedata(dreq); nfs_direct_free_writedata(dreq);
nfs_zap_mapping(inode, inode->i_mapping); nfs_zap_mapping(inode, inode->i_mapping);
nfs_direct_complete(dreq); nfs_direct_complete(dreq);
...@@ -718,14 +716,12 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz ...@@ -718,14 +716,12 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
sync = FLUSH_STABLE; sync = FLUSH_STABLE;
dreq->inode = inode; dreq->inode = inode;
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data); dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
if (!is_sync_kiocb(iocb)) if (!is_sync_kiocb(iocb))
dreq->iocb = iocb; dreq->iocb = iocb;
nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count);
nfs_begin_data_update(inode);
rpc_clnt_sigmask(clnt, &oldset); rpc_clnt_sigmask(clnt, &oldset);
result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync); result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
if (!result) if (!result)
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/system.h> #include <asm/system.h>
#include "delegation.h" #include "delegation.h"
#include "internal.h"
#include "iostat.h" #include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_FILE #define NFSDBG_FACILITY NFSDBG_FILE
...@@ -55,6 +56,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); ...@@ -55,6 +56,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_setlease(struct file *file, long arg, struct file_lock **fl); static int nfs_setlease(struct file *file, long arg, struct file_lock **fl);
static struct vm_operations_struct nfs_file_vm_ops;
const struct file_operations nfs_file_operations = { const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek, .llseek = nfs_file_llseek,
.read = do_sync_read, .read = do_sync_read,
...@@ -173,6 +176,31 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) ...@@ -173,6 +176,31 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
return remote_llseek(filp, offset, origin); return remote_llseek(filp, offset, origin);
} }
/*
* Helper for nfs_file_flush() and nfs_fsync()
*
* Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
* disk, but it retrieves and clears ctx->error after synching, despite
* the two being set at the same time in nfs_context_set_write_error().
* This is because the former is used to notify the _next_ call to
* nfs_file_write() that a write error occured, and hence cause it to
* fall back to doing a synchronous write.
*/
static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
{
int have_error, status;
int ret = 0;
have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
status = nfs_wb_all(inode);
have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
if (have_error)
ret = xchg(&ctx->error, 0);
if (!ret)
ret = status;
return ret;
}
/* /*
* Flush all dirty pages, and check for write errors. * Flush all dirty pages, and check for write errors.
* *
...@@ -180,7 +208,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) ...@@ -180,7 +208,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
static int static int
nfs_file_flush(struct file *file, fl_owner_t id) nfs_file_flush(struct file *file, fl_owner_t id)
{ {
struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
int status; int status;
...@@ -189,16 +217,11 @@ nfs_file_flush(struct file *file, fl_owner_t id) ...@@ -189,16 +217,11 @@ nfs_file_flush(struct file *file, fl_owner_t id)
if ((file->f_mode & FMODE_WRITE) == 0) if ((file->f_mode & FMODE_WRITE) == 0)
return 0; return 0;
nfs_inc_stats(inode, NFSIOS_VFSFLUSH); nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
lock_kernel();
/* Ensure that data+attribute caches are up to date after close() */ /* Ensure that data+attribute caches are up to date after close() */
status = nfs_wb_all(inode); status = nfs_do_fsync(ctx, inode);
if (!status) {
status = ctx->error;
ctx->error = 0;
if (!status) if (!status)
nfs_revalidate_inode(NFS_SERVER(inode), inode); nfs_revalidate_inode(NFS_SERVER(inode), inode);
}
unlock_kernel();
return status; return status;
} }
...@@ -257,8 +280,11 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -257,8 +280,11 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
dentry->d_parent->d_name.name, dentry->d_name.name); dentry->d_parent->d_name.name, dentry->d_name.name);
status = nfs_revalidate_mapping(inode, file->f_mapping); status = nfs_revalidate_mapping(inode, file->f_mapping);
if (!status) if (!status) {
status = generic_file_mmap(file, vma); vma->vm_ops = &nfs_file_vm_ops;
vma->vm_flags |= VM_CAN_NONLINEAR;
file_accessed(file);
}
return status; return status;
} }
...@@ -270,21 +296,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -270,21 +296,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
static int static int
nfs_fsync(struct file *file, struct dentry *dentry, int datasync) nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{ {
struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int status;
dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC); nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
lock_kernel(); return nfs_do_fsync(ctx, inode);
status = nfs_wb_all(inode);
if (!status) {
status = ctx->error;
ctx->error = 0;
}
unlock_kernel();
return status;
} }
/* /*
...@@ -333,7 +351,7 @@ static int nfs_launder_page(struct page *page) ...@@ -333,7 +351,7 @@ static int nfs_launder_page(struct page *page)
const struct address_space_operations nfs_file_aops = { const struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage, .readpage = nfs_readpage,
.readpages = nfs_readpages, .readpages = nfs_readpages,
.set_page_dirty = nfs_set_page_dirty, .set_page_dirty = __set_page_dirty_nobuffers,
.writepage = nfs_writepage, .writepage = nfs_writepage,
.writepages = nfs_writepages, .writepages = nfs_writepages,
.prepare_write = nfs_prepare_write, .prepare_write = nfs_prepare_write,
...@@ -346,6 +364,43 @@ const struct address_space_operations nfs_file_aops = { ...@@ -346,6 +364,43 @@ const struct address_space_operations nfs_file_aops = {
.launder_page = nfs_launder_page, .launder_page = nfs_launder_page,
}; };
static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page)
{
struct file *filp = vma->vm_file;
unsigned pagelen;
int ret = -EINVAL;
lock_page(page);
if (page->mapping != vma->vm_file->f_path.dentry->d_inode->i_mapping)
goto out_unlock;
pagelen = nfs_page_length(page);
if (pagelen == 0)
goto out_unlock;
ret = nfs_prepare_write(filp, page, 0, pagelen);
if (!ret)
ret = nfs_commit_write(filp, page, 0, pagelen);
out_unlock:
unlock_page(page);
return ret;
}
static struct vm_operations_struct nfs_file_vm_ops = {
.fault = filemap_fault,
.page_mkwrite = nfs_vm_page_mkwrite,
};
static int nfs_need_sync_write(struct file *filp, struct inode *inode)
{
struct nfs_open_context *ctx;
if (IS_SYNC(inode) || (filp->f_flags & O_SYNC))
return 1;
ctx = nfs_file_open_context(filp);
if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags))
return 1;
return 0;
}
static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos) unsigned long nr_segs, loff_t pos)
{ {
...@@ -382,8 +437,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -382,8 +437,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
result = generic_file_aio_write(iocb, iov, nr_segs, pos); result = generic_file_aio_write(iocb, iov, nr_segs, pos);
/* Return error values for O_SYNC and IS_SYNC() */ /* Return error values for O_SYNC and IS_SYNC() */
if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) { if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
int err = nfs_fsync(iocb->ki_filp, dentry, 1); int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode);
if (err < 0) if (err < 0)
result = err; result = err;
} }
......
This diff is collapsed.
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#include <linux/mount.h> #include <linux/mount.h>
struct nfs_string; struct nfs_string;
struct nfs_mount_data;
struct nfs4_mount_data;
/* Maximum number of readahead requests /* Maximum number of readahead requests
* FIXME: this should really be a sysctl so that users may tune it to suit * FIXME: this should really be a sysctl so that users may tune it to suit
...@@ -27,19 +25,49 @@ struct nfs_clone_mount { ...@@ -27,19 +25,49 @@ struct nfs_clone_mount {
rpc_authflavor_t authflavor; rpc_authflavor_t authflavor;
}; };
/*
* In-kernel mount arguments
*/
struct nfs_parsed_mount_data {
int flags;
int rsize, wsize;
int timeo, retrans;
int acregmin, acregmax,
acdirmin, acdirmax;
int namlen;
unsigned int bsize;
unsigned int auth_flavor_len;
rpc_authflavor_t auth_flavors[1];
char *client_address;
struct {
struct sockaddr_in address;
char *hostname;
unsigned int program;
unsigned int version;
unsigned short port;
int protocol;
} mount_server;
struct {
struct sockaddr_in address;
char *hostname;
char *export_path;
unsigned int program;
int protocol;
} nfs_server;
};
/* client.c */ /* client.c */
extern struct rpc_program nfs_program; extern struct rpc_program nfs_program;
extern void nfs_put_client(struct nfs_client *); extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *, extern struct nfs_server *nfs_create_server(
const struct nfs_parsed_mount_data *,
struct nfs_fh *); struct nfs_fh *);
extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *, extern struct nfs_server *nfs4_create_server(
const char *, const struct nfs_parsed_mount_data *,
const struct sockaddr_in *,
const char *,
const char *,
rpc_authflavor_t,
struct nfs_fh *); struct nfs_fh *);
extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
struct nfs_fh *); struct nfs_fh *);
......
...@@ -251,6 +251,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) ...@@ -251,6 +251,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, count); args->pages, args->pgbase, count);
req->rq_rcv_buf.flags |= XDRBUF_READ;
return 0; return 0;
} }
...@@ -271,7 +272,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ...@@ -271,7 +272,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
res->eof = 0; res->eof = 0;
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READ reply header overflowed:" dprintk("NFS: READ reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
...@@ -281,7 +282,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ...@@ -281,7 +282,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) { if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: " dprintk("NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd); "count %d > recvd %d\n", count, recvd);
count = recvd; count = recvd;
} }
...@@ -313,6 +314,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) ...@@ -313,6 +314,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
/* Copy the page array */ /* Copy the page array */
xdr_encode_pages(sndbuf, args->pages, args->pgbase, count); xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
sndbuf->flags |= XDRBUF_WRITE;
return 0; return 0;
} }
...@@ -431,7 +433,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -431,7 +433,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READDIR reply header overflowed:" dprintk("NFS: READDIR reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
...@@ -454,7 +456,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -454,7 +456,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
len = ntohl(*p++); len = ntohl(*p++);
p += XDR_QUADLEN(len) + 1; /* name plus cookie */ p += XDR_QUADLEN(len) + 1; /* name plus cookie */
if (len > NFS2_MAXNAMLEN) { if (len > NFS2_MAXNAMLEN) {
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n", dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
len); len);
goto err_unmap; goto err_unmap;
} }
...@@ -471,7 +473,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -471,7 +473,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
entry[0] = entry[1] = 0; entry[0] = entry[1] = 0;
/* truncate listing ? */ /* truncate listing ? */
if (!nr) { if (!nr) {
printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1; entry[1] = 1;
} }
goto out; goto out;
...@@ -583,12 +585,12 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -583,12 +585,12 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*p++); len = ntohl(*p++);
if (len >= rcvbuf->page_len || len <= 0) { if (len >= rcvbuf->page_len || len <= 0) {
dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READLINK reply header overflowed:" dprintk("NFS: READLINK reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
...@@ -597,7 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -597,7 +599,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
} }
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) { if (recvd < len) {
printk(KERN_WARNING "NFS: server cheating in readlink reply: " dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd); "count %u > recvd %u\n", len, recvd);
return -EIO; return -EIO;
} }
...@@ -695,7 +697,7 @@ nfs_stat_to_errno(int stat) ...@@ -695,7 +697,7 @@ nfs_stat_to_errno(int stat)
if (nfs_errtbl[i].stat == stat) if (nfs_errtbl[i].stat == stat)
return nfs_errtbl[i].errno; return nfs_errtbl[i].errno;
} }
printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat); dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
return nfs_errtbl[i].errno; return nfs_errtbl[i].errno;
} }
......
...@@ -317,13 +317,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -317,13 +317,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
} }
dprintk("NFS call setacl\n"); dprintk("NFS call setacl\n");
nfs_begin_data_update(inode);
msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL];
status = rpc_call_sync(server->client_acl, &msg, 0); status = rpc_call_sync(server->client_acl, &msg, 0);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
nfs_end_data_update(inode);
dprintk("NFS reply setacl: %d\n", status); dprintk("NFS reply setacl: %d\n", status);
/* pages may have been allocated at the xdr layer. */ /* pages may have been allocated at the xdr layer. */
......
...@@ -166,6 +166,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, ...@@ -166,6 +166,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
nfs_fattr_init(&dir_attr); nfs_fattr_init(&dir_attr);
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_refresh_inode(dir, &dir_attr);
if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
msg.rpc_argp = fhandle; msg.rpc_argp = fhandle;
...@@ -173,8 +174,6 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, ...@@ -173,8 +174,6 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
} }
dprintk("NFS reply lookup: %d\n", status); dprintk("NFS reply lookup: %d\n", status);
if (status >= 0)
status = nfs_refresh_inode(dir, &dir_attr);
return status; return status;
} }
...@@ -607,6 +606,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -607,6 +606,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
nfs_fattr_init(&dir_attr); nfs_fattr_init(&dir_attr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_invalidate_atime(dir);
nfs_refresh_inode(dir, &dir_attr); nfs_refresh_inode(dir, &dir_attr);
dprintk("NFS reply readdir: %d\n", status); dprintk("NFS reply readdir: %d\n", status);
return status; return status;
...@@ -724,8 +726,8 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data) ...@@ -724,8 +726,8 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN; return -EAGAIN;
/* Call back common NFS readpage processing */
if (task->tk_status >= 0) nfs_invalidate_atime(data->inode);
nfs_refresh_inode(data->inode, &data->fattr); nfs_refresh_inode(data->inode, &data->fattr);
return 0; return 0;
} }
...@@ -747,7 +749,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -747,7 +749,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
if (nfs3_async_handle_jukebox(task, data->inode)) if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN; return -EAGAIN;
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
return 0; return 0;
} }
...@@ -775,8 +777,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -775,8 +777,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
{ {
if (nfs3_async_handle_jukebox(task, data->inode)) if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN; return -EAGAIN;
if (task->tk_status >= 0) nfs_refresh_inode(data->inode, data->res.fattr);
nfs_post_op_update_inode(data->inode, data->res.fattr);
return 0; return 0;
} }
......
...@@ -346,6 +346,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) ...@@ -346,6 +346,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, count); args->pages, args->pgbase, count);
req->rq_rcv_buf.flags |= XDRBUF_READ;
return 0; return 0;
} }
...@@ -367,6 +368,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args) ...@@ -367,6 +368,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
/* Copy the page array */ /* Copy the page array */
xdr_encode_pages(sndbuf, args->pages, args->pgbase, count); xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
sndbuf->flags |= XDRBUF_WRITE;
return 0; return 0;
} }
...@@ -524,7 +526,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res ...@@ -524,7 +526,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READDIR reply header overflowed:" dprintk("NFS: READDIR reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
...@@ -547,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res ...@@ -547,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
len = ntohl(*p++); /* string length */ len = ntohl(*p++); /* string length */
p += XDR_QUADLEN(len) + 2; /* name + cookie */ p += XDR_QUADLEN(len) + 2; /* name + cookie */
if (len > NFS3_MAXNAMLEN) { if (len > NFS3_MAXNAMLEN) {
printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n", dprintk("NFS: giant filename in readdir (len %x)!\n",
len); len);
goto err_unmap; goto err_unmap;
} }
...@@ -567,7 +569,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res ...@@ -567,7 +569,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
goto short_pkt; goto short_pkt;
len = ntohl(*p++); len = ntohl(*p++);
if (len > NFS3_FHSIZE) { if (len > NFS3_FHSIZE) {
printk(KERN_WARNING "NFS: giant filehandle in " dprintk("NFS: giant filehandle in "
"readdir (len %x)!\n", len); "readdir (len %x)!\n", len);
goto err_unmap; goto err_unmap;
} }
...@@ -588,7 +590,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res ...@@ -588,7 +590,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
entry[0] = entry[1] = 0; entry[0] = entry[1] = 0;
/* truncate listing ? */ /* truncate listing ? */
if (!nr) { if (!nr) {
printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1; entry[1] = 1;
} }
goto out; goto out;
...@@ -826,22 +828,23 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) ...@@ -826,22 +828,23 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*p++); len = ntohl(*p++);
if (len >= rcvbuf->page_len || len <= 0) { if (len >= rcvbuf->page_len || len <= 0) {
dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READLINK reply header overflowed:" dprintk("NFS: READLINK reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); dprintk("NFS: READLINK header is short. "
"iovec will be shifted.\n");
xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
} }
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) { if (recvd < len) {
printk(KERN_WARNING "NFS: server cheating in readlink reply: " dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd); "count %u > recvd %u\n", len, recvd);
return -EIO; return -EIO;
} }
...@@ -876,13 +879,13 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ...@@ -876,13 +879,13 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
ocount = ntohl(*p++); ocount = ntohl(*p++);
if (ocount != count) { if (ocount != count) {
printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n"); dprintk("NFS: READ count doesn't match RPC opaque count.\n");
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} }
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
printk(KERN_WARNING "NFS: READ reply header overflowed:" dprintk("NFS: READ reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %d > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
...@@ -892,7 +895,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ...@@ -892,7 +895,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) { if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: " dprintk("NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd); "count %d > recvd %d\n", count, recvd);
count = recvd; count = recvd;
res->eof = 0; res->eof = 0;
......
...@@ -62,10 +62,8 @@ struct nfs4_opendata; ...@@ -62,10 +62,8 @@ struct nfs4_opendata;
static int _nfs4_proc_open(struct nfs4_opendata *data); static int _nfs4_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags);
static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
...@@ -177,7 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent ...@@ -177,7 +175,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
*p++ = xdr_one; /* bitmap length */ *p++ = xdr_one; /* bitmap length */
*p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
*p++ = htonl(8); /* attribute buffer length */ *p++ = htonl(8); /* attribute buffer length */
p = xdr_encode_hyper(p, dentry->d_inode->i_ino); p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
} }
*p++ = xdr_one; /* next */ *p++ = xdr_one; /* next */
...@@ -189,7 +187,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent ...@@ -189,7 +187,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
*p++ = xdr_one; /* bitmap length */ *p++ = xdr_one; /* bitmap length */
*p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
*p++ = htonl(8); /* attribute buffer length */ *p++ = htonl(8); /* attribute buffer length */
p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino); p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
readdir->pgbase = (char *)p - (char *)start; readdir->pgbase = (char *)p - (char *)start;
readdir->count -= readdir->pgbase; readdir->count -= readdir->pgbase;
...@@ -211,7 +209,8 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) ...@@ -211,7 +209,8 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
spin_lock(&dir->i_lock); spin_lock(&dir->i_lock);
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA; nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
if (cinfo->before == nfsi->change_attr && cinfo->atomic) if (!cinfo->atomic || cinfo->before != nfsi->change_attr)
nfsi->cache_change_attribute = jiffies;
nfsi->change_attr = cinfo->after; nfsi->change_attr = cinfo->after;
spin_unlock(&dir->i_lock); spin_unlock(&dir->i_lock);
} }
...@@ -454,7 +453,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) ...@@ -454,7 +453,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
rcu_read_unlock(); rcu_read_unlock();
lock_kernel(); lock_kernel();
ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
unlock_kernel(); unlock_kernel();
if (ret != 0) if (ret != 0)
goto out; goto out;
...@@ -948,36 +947,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) ...@@ -948,36 +947,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
return 0; return 0;
} }
static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags)
{
struct nfs_access_entry cache;
int mask = 0;
int status;
if (openflags & FMODE_READ)
mask |= MAY_READ;
if (openflags & FMODE_WRITE)
mask |= MAY_WRITE;
if (openflags & FMODE_EXEC)
mask |= MAY_EXEC;
status = nfs_access_get_cached(inode, cred, &cache);
if (status == 0)
goto out;
/* Be clever: ask server to check for all possible rights */
cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
cache.cred = cred;
cache.jiffies = jiffies;
status = _nfs4_proc_access(inode, &cache);
if (status != 0)
return status;
nfs_access_add_cache(inode, &cache);
out:
if ((cache.mask & mask) == mask)
return 0;
return -EACCES;
}
static int nfs4_recover_expired_lease(struct nfs_server *server) static int nfs4_recover_expired_lease(struct nfs_server *server)
{ {
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
...@@ -1381,7 +1350,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct ...@@ -1381,7 +1350,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
/* If the open_intent is for execute, we have an extra check to make */ /* If the open_intent is for execute, we have an extra check to make */
if (nd->intent.open.flags & FMODE_EXEC) { if (nd->intent.open.flags & FMODE_EXEC) {
ret = _nfs4_do_access(state->inode, ret = nfs_may_open(state->inode,
state->owner->so_cred, state->owner->so_cred,
nd->intent.open.flags); nd->intent.open.flags);
if (ret < 0) if (ret < 0)
...@@ -1390,7 +1359,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct ...@@ -1390,7 +1359,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
filp = lookup_instantiate_filp(nd, path->dentry, NULL); filp = lookup_instantiate_filp(nd, path->dentry, NULL);
if (!IS_ERR(filp)) { if (!IS_ERR(filp)) {
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
ctx = (struct nfs_open_context *)filp->private_data; ctx = nfs_file_open_context(filp);
ctx->state = state; ctx->state = state;
return 0; return 0;
} }
...@@ -1428,13 +1397,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) ...@@ -1428,13 +1397,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
put_rpccred(cred); put_rpccred(cred);
if (IS_ERR(state)) { if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT) if (PTR_ERR(state) == -ENOENT) {
d_add(dentry, NULL); d_add(dentry, NULL);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
}
return (struct dentry *)state; return (struct dentry *)state;
} }
res = d_add_unique(dentry, igrab(state->inode)); res = d_add_unique(dentry, igrab(state->inode));
if (res != NULL) if (res != NULL)
path.dentry = res; path.dentry = res;
nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
nfs4_intent_set_file(nd, &path, state); nfs4_intent_set_file(nd, &path, state);
return res; return res;
} }
...@@ -1468,6 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st ...@@ -1468,6 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
} }
} }
if (state->inode == dentry->d_inode) { if (state->inode == dentry->d_inode) {
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
nfs4_intent_set_file(nd, &path, state); nfs4_intent_set_file(nd, &path, state);
return 1; return 1;
} }
...@@ -1757,10 +1730,16 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh ...@@ -1757,10 +1730,16 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{ {
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_fattr fattr;
struct nfs4_accessargs args = { struct nfs4_accessargs args = {
.fh = NFS_FH(inode), .fh = NFS_FH(inode),
.bitmask = server->attr_bitmask,
};
struct nfs4_accessres res = {
.server = server,
.fattr = &fattr,
}; };
struct nfs4_accessres res = { 0 };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
.rpc_argp = &args, .rpc_argp = &args,
...@@ -1786,6 +1765,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry ...@@ -1786,6 +1765,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
if (mode & MAY_EXEC) if (mode & MAY_EXEC)
args.access |= NFS4_ACCESS_EXECUTE; args.access |= NFS4_ACCESS_EXECUTE;
} }
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (!status) { if (!status) {
entry->mask = 0; entry->mask = 0;
...@@ -1795,6 +1775,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry ...@@ -1795,6 +1775,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
entry->mask |= MAY_WRITE; entry->mask |= MAY_WRITE;
if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
entry->mask |= MAY_EXEC; entry->mask |= MAY_EXEC;
nfs_refresh_inode(inode, &fattr);
} }
return status; return status;
} }
...@@ -1900,11 +1881,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -1900,11 +1881,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
} }
state = nfs4_do_open(dir, &path, flags, sattr, cred); state = nfs4_do_open(dir, &path, flags, sattr, cred);
put_rpccred(cred); put_rpccred(cred);
d_drop(dentry);
if (IS_ERR(state)) { if (IS_ERR(state)) {
status = PTR_ERR(state); status = PTR_ERR(state);
goto out; goto out;
} }
d_instantiate(dentry, igrab(state->inode)); d_add(dentry, igrab(state->inode));
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (flags & O_EXCL) { if (flags & O_EXCL) {
struct nfs_fattr fattr; struct nfs_fattr fattr;
status = nfs4_do_setattr(state->inode, &fattr, sattr, state); status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
...@@ -2218,6 +2201,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -2218,6 +2201,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (status == 0) if (status == 0)
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
nfs_invalidate_atime(dir);
dprintk("%s: returns %d\n", __FUNCTION__, status); dprintk("%s: returns %d\n", __FUNCTION__, status);
return status; return status;
} }
...@@ -2414,6 +2400,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) ...@@ -2414,6 +2400,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
rpc_restart_call(task); rpc_restart_call(task);
return -EAGAIN; return -EAGAIN;
} }
nfs_invalidate_atime(data->inode);
if (task->tk_status > 0) if (task->tk_status > 0)
renew_lease(server, data->timestamp); renew_lease(server, data->timestamp);
return 0; return 0;
...@@ -2443,7 +2431,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -2443,7 +2431,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
} }
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
renew_lease(NFS_SERVER(inode), data->timestamp); renew_lease(NFS_SERVER(inode), data->timestamp);
nfs_post_op_update_inode(inode, data->res.fattr); nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
} }
return 0; return 0;
} }
...@@ -2485,8 +2473,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) ...@@ -2485,8 +2473,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
rpc_restart_call(task); rpc_restart_call(task);
return -EAGAIN; return -EAGAIN;
} }
if (task->tk_status >= 0) nfs_refresh_inode(inode, data->res.fattr);
nfs_post_op_update_inode(inode, data->res.fattr);
return 0; return 0;
} }
...@@ -3056,7 +3043,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co ...@@ -3056,7 +3043,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
if (status == 0) { if (status == 0) {
status = data->rpc_status; status = data->rpc_status;
if (status == 0) if (status == 0)
nfs_post_op_update_inode(inode, &data->fattr); nfs_refresh_inode(inode, &data->fattr);
} }
rpc_put_task(task); rpc_put_task(task);
return status; return status;
...@@ -3303,7 +3290,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * ...@@ -3303,7 +3290,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
status = -ENOMEM; status = -ENOMEM;
if (seqid == NULL) if (seqid == NULL)
goto out; goto out;
task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
status = PTR_ERR(task); status = PTR_ERR(task);
if (IS_ERR(task)) if (IS_ERR(task))
goto out; goto out;
...@@ -3447,7 +3434,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f ...@@ -3447,7 +3434,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
int ret; int ret;
dprintk("%s: begin!\n", __FUNCTION__); dprintk("%s: begin!\n", __FUNCTION__);
data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data, data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
fl->fl_u.nfs4_fl.owner); fl->fl_u.nfs4_fl.owner);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -3573,7 +3560,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) ...@@ -3573,7 +3560,7 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
int status; int status;
/* verify open state */ /* verify open state */
ctx = (struct nfs_open_context *)filp->private_data; ctx = nfs_file_open_context(filp);
state = ctx->state; state = ctx->state;
if (request->fl_start < 0 || request->fl_end < 0) if (request->fl_start < 0 || request->fl_end < 0)
......
...@@ -774,7 +774,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s ...@@ -774,7 +774,7 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s
for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) { for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue; continue;
if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state) if (nfs_file_open_context(fl->fl_file)->state != state)
continue; continue;
status = ops->recover_lock(state, fl); status = ops->recover_lock(state, fl);
if (status >= 0) if (status >= 0)
......
...@@ -376,10 +376,12 @@ static int nfs4_stat_to_errno(int); ...@@ -376,10 +376,12 @@ static int nfs4_stat_to_errno(int);
decode_locku_maxsz) decode_locku_maxsz)
#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
encode_access_maxsz) encode_access_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \ decode_putfh_maxsz + \
decode_access_maxsz) decode_access_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
encode_getattr_maxsz) encode_getattr_maxsz)
...@@ -562,7 +564,6 @@ struct compound_hdr { ...@@ -562,7 +564,6 @@ struct compound_hdr {
#define RESERVE_SPACE(nbytes) do { \ #define RESERVE_SPACE(nbytes) do { \
p = xdr_reserve_space(xdr, nbytes); \ p = xdr_reserve_space(xdr, nbytes); \
if (!p) printk("RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
BUG_ON(!p); \ BUG_ON(!p); \
} while (0) } while (0)
...@@ -628,7 +629,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s ...@@ -628,7 +629,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
if (iap->ia_valid & ATTR_UID) { if (iap->ia_valid & ATTR_UID) {
owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name); owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
if (owner_namelen < 0) { if (owner_namelen < 0) {
printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", dprintk("nfs: couldn't resolve uid %d to string\n",
iap->ia_uid); iap->ia_uid);
/* XXX */ /* XXX */
strcpy(owner_name, "nobody"); strcpy(owner_name, "nobody");
...@@ -640,7 +641,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s ...@@ -640,7 +641,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
if (iap->ia_valid & ATTR_GID) { if (iap->ia_valid & ATTR_GID) {
owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group); owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
if (owner_grouplen < 0) { if (owner_grouplen < 0) {
printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", dprintk("nfs: couldn't resolve gid %d to string\n",
iap->ia_gid); iap->ia_gid);
strcpy(owner_group, "nobody"); strcpy(owner_group, "nobody");
owner_grouplen = sizeof("nobody") - 1; owner_grouplen = sizeof("nobody") - 1;
...@@ -711,7 +712,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s ...@@ -711,7 +712,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
* Now we backfill the bitmap and the attribute buffer length. * Now we backfill the bitmap and the attribute buffer length.
*/ */
if (len != ((char *)p - (char *)q) + 4) { if (len != ((char *)p - (char *)q) + 4) {
printk ("encode_attr: Attr length calculation error! %u != %Zu\n", printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
len, ((char *)p - (char *)q) + 4); len, ((char *)p - (char *)q) + 4);
BUG(); BUG();
} }
...@@ -1376,14 +1377,20 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs ...@@ -1376,14 +1377,20 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs
{ {
struct xdr_stream xdr; struct xdr_stream xdr;
struct compound_hdr hdr = { struct compound_hdr hdr = {
.nops = 2, .nops = 3,
}; };
int status; int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p); xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr); encode_compound_hdr(&xdr, &hdr);
if ((status = encode_putfh(&xdr, args->fh)) == 0) status = encode_putfh(&xdr, args->fh);
if (status != 0)
goto out;
status = encode_access(&xdr, args->access); status = encode_access(&xdr, args->access);
if (status != 0)
goto out;
status = encode_getfattr(&xdr, args->bitmask);
out:
return status; return status;
} }
...@@ -1857,6 +1864,7 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg ...@@ -1857,6 +1864,7 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, args->count); args->pages, args->pgbase, args->count);
req->rq_rcv_buf.flags |= XDRBUF_READ;
out: out:
return status; return status;
} }
...@@ -1933,6 +1941,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea ...@@ -1933,6 +1941,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea
status = encode_write(&xdr, args); status = encode_write(&xdr, args);
if (status) if (status)
goto out; goto out;
req->rq_snd_buf.flags |= XDRBUF_WRITE;
status = encode_getfattr(&xdr, args->bitmask); status = encode_getfattr(&xdr, args->bitmask);
out: out:
return status; return status;
...@@ -2180,9 +2189,9 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs ...@@ -2180,9 +2189,9 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
#define READ_BUF(nbytes) do { \ #define READ_BUF(nbytes) do { \
p = xdr_inline_decode(xdr, nbytes); \ p = xdr_inline_decode(xdr, nbytes); \
if (unlikely(!p)) { \ if (unlikely(!p)) { \
printk(KERN_INFO "%s: prematurely hit end of receive" \ dprintk("nfs: %s: prematurely hit end of receive" \
" buffer\n", __FUNCTION__); \ " buffer\n", __FUNCTION__); \
printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ dprintk("nfs: %s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
__FUNCTION__, xdr->p, nbytes, xdr->end); \ __FUNCTION__, xdr->p, nbytes, xdr->end); \
return -EIO; \ return -EIO; \
} \ } \
...@@ -2223,8 +2232,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) ...@@ -2223,8 +2232,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
READ_BUF(8); READ_BUF(8);
READ32(opnum); READ32(opnum);
if (opnum != expected) { if (opnum != expected) {
printk(KERN_NOTICE dprintk("nfs: Server returned operation"
"nfs4_decode_op_hdr: Server returned operation"
" %d but we issued a request for %d\n", " %d but we issued a request for %d\n",
opnum, expected); opnum, expected);
return -EIO; return -EIO;
...@@ -2758,7 +2766,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf ...@@ -2758,7 +2766,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
dprintk("%s: nfs_map_name_to_uid failed!\n", dprintk("%s: nfs_map_name_to_uid failed!\n",
__FUNCTION__); __FUNCTION__);
} else } else
printk(KERN_WARNING "%s: name too long (%u)!\n", dprintk("%s: name too long (%u)!\n",
__FUNCTION__, len); __FUNCTION__, len);
bitmap[1] &= ~FATTR4_WORD1_OWNER; bitmap[1] &= ~FATTR4_WORD1_OWNER;
} }
...@@ -2783,7 +2791,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf ...@@ -2783,7 +2791,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
dprintk("%s: nfs_map_group_to_gid failed!\n", dprintk("%s: nfs_map_group_to_gid failed!\n",
__FUNCTION__); __FUNCTION__);
} else } else
printk(KERN_WARNING "%s: name too long (%u)!\n", dprintk("%s: name too long (%u)!\n",
__FUNCTION__, len); __FUNCTION__, len);
bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP; bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
} }
...@@ -2950,7 +2958,8 @@ static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrl ...@@ -2950,7 +2958,8 @@ static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrl
unsigned int nwords = xdr->p - savep; unsigned int nwords = xdr->p - savep;
if (unlikely(attrwords != nwords)) { if (unlikely(attrwords != nwords)) {
printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n", dprintk("%s: server returned incorrect attribute length: "
"%u %c %u\n",
__FUNCTION__, __FUNCTION__,
attrwords << 2, attrwords << 2,
(attrwords < nwords) ? '<' : '>', (attrwords < nwords) ? '<' : '>',
...@@ -3451,7 +3460,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_ ...@@ -3451,7 +3460,7 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) { if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: " dprintk("NFS: server cheating in read reply: "
"count %u > recvd %u\n", count, recvd); "count %u > recvd %u\n", count, recvd);
count = recvd; count = recvd;
eof = 0; eof = 0;
...@@ -3500,7 +3509,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n ...@@ -3500,7 +3509,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
p += 2; /* cookie */ p += 2; /* cookie */
len = ntohl(*p++); /* filename length */ len = ntohl(*p++); /* filename length */
if (len > NFS4_MAXNAMLEN) { if (len > NFS4_MAXNAMLEN) {
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); dprintk("NFS: giant filename in readdir (len 0x%x)\n",
len);
goto err_unmap; goto err_unmap;
} }
xlen = XDR_QUADLEN(len); xlen = XDR_QUADLEN(len);
...@@ -3528,7 +3538,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n ...@@ -3528,7 +3538,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
entry[0] = entry[1] = 0; entry[0] = entry[1] = 0;
/* truncate listing ? */ /* truncate listing ? */
if (!nr) { if (!nr) {
printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1; entry[1] = 1;
} }
goto out; goto out;
...@@ -3554,13 +3564,13 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) ...@@ -3554,13 +3564,13 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
READ_BUF(4); READ_BUF(4);
READ32(len); READ32(len);
if (len >= rcvbuf->page_len || len <= 0) { if (len >= rcvbuf->page_len || len <= 0) {
dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
hdrlen = (char *) xdr->p - (char *) iov->iov_base; hdrlen = (char *) xdr->p - (char *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) { if (recvd < len) {
printk(KERN_WARNING "NFS: server cheating in readlink reply: " dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd); "count %u > recvd %u\n", len, recvd);
return -EIO; return -EIO;
} }
...@@ -3643,7 +3653,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, ...@@ -3643,7 +3653,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (attrlen > recvd) { if (attrlen > recvd) {
printk(KERN_WARNING "NFS: server cheating in getattr" dprintk("NFS: server cheating in getattr"
" acl reply: attrlen %u > recvd %u\n", " acl reply: attrlen %u > recvd %u\n",
attrlen, recvd); attrlen, recvd);
return -EINVAL; return -EINVAL;
...@@ -3688,8 +3698,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) ...@@ -3688,8 +3698,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
READ_BUF(8); READ_BUF(8);
READ32(opnum); READ32(opnum);
if (opnum != OP_SETCLIENTID) { if (opnum != OP_SETCLIENTID) {
printk(KERN_NOTICE dprintk("nfs: decode_setclientid: Server returned operation"
"nfs4_decode_setclientid: Server returned operation"
" %d\n", opnum); " %d\n", opnum);
return -EIO; return -EIO;
} }
...@@ -3783,8 +3792,13 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac ...@@ -3783,8 +3792,13 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out; goto out;
if ((status = decode_putfh(&xdr)) == 0) status = decode_putfh(&xdr);
if (status != 0)
goto out;
status = decode_access(&xdr, res); status = decode_access(&xdr, res);
if (status != 0)
goto out;
decode_getfattr(&xdr, res->fattr, res->server);
out: out:
return status; return status;
} }
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/xprtsock.h>
#include <linux/nfs.h> #include <linux/nfs.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_mount.h> #include <linux/nfs_mount.h>
...@@ -491,7 +492,7 @@ static int __init root_nfs_get_handle(void) ...@@ -491,7 +492,7 @@ static int __init root_nfs_get_handle(void)
struct sockaddr_in sin; struct sockaddr_in sin;
int status; int status;
int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
IPPROTO_TCP : IPPROTO_UDP; XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP;
int version = (nfs_data.flags & NFS_MOUNT_VER3) ? int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
NFS_MNT3_VERSION : NFS_MNT_VERSION; NFS_MNT3_VERSION : NFS_MNT_VERSION;
......
...@@ -476,6 +476,8 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -476,6 +476,8 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
dprintk("NFS call readdir %d\n", (unsigned int)cookie); dprintk("NFS call readdir %d\n", (unsigned int)cookie);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_invalidate_atime(dir);
dprintk("NFS reply readdir: %d\n", status); dprintk("NFS reply readdir: %d\n", status);
return status; return status;
} }
...@@ -550,6 +552,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -550,6 +552,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
{ {
nfs_invalidate_atime(data->inode);
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
nfs_refresh_inode(data->inode, data->res.fattr); nfs_refresh_inode(data->inode, data->res.fattr);
/* Emulate the eof flag, which isn't normally needed in NFSv2 /* Emulate the eof flag, which isn't normally needed in NFSv2
...@@ -576,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data) ...@@ -576,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data)
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
{ {
if (task->tk_status >= 0) if (task->tk_status >= 0)
nfs_post_op_update_inode(data->inode, data->res.fattr); nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
return 0; return 0;
} }
......
...@@ -341,9 +341,6 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) ...@@ -341,9 +341,6 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode));
nfs_mark_for_revalidate(data->inode); nfs_mark_for_revalidate(data->inode);
} }
spin_lock(&data->inode->i_lock);
NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME;
spin_unlock(&data->inode->i_lock);
return 0; return 0;
} }
...@@ -497,8 +494,7 @@ int nfs_readpage(struct file *file, struct page *page) ...@@ -497,8 +494,7 @@ int nfs_readpage(struct file *file, struct page *page)
if (ctx == NULL) if (ctx == NULL)
goto out_unlock; goto out_unlock;
} else } else
ctx = get_nfs_open_context((struct nfs_open_context *) ctx = get_nfs_open_context(nfs_file_open_context(file));
file->private_data);
error = nfs_readpage_async(ctx, inode, page); error = nfs_readpage_async(ctx, inode, page);
...@@ -576,8 +572,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, ...@@ -576,8 +572,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
if (desc.ctx == NULL) if (desc.ctx == NULL)
return -EBADF; return -EBADF;
} else } else
desc.ctx = get_nfs_open_context((struct nfs_open_context *) desc.ctx = get_nfs_open_context(nfs_file_open_context(filp));
filp->private_data);
if (rsize < PAGE_CACHE_SIZE) if (rsize < PAGE_CACHE_SIZE)
nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
else else
......
This diff is collapsed.
...@@ -66,7 +66,6 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata) ...@@ -66,7 +66,6 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
.rpc_cred = data->cred, .rpc_cred = data->cred,
}; };
nfs_begin_data_update(dir);
NFS_PROTO(dir)->unlink_setup(&msg, dir); NFS_PROTO(dir)->unlink_setup(&msg, dir);
rpc_call_setup(task, &msg, 0); rpc_call_setup(task, &msg, 0);
} }
...@@ -84,8 +83,6 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) ...@@ -84,8 +83,6 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
if (!NFS_PROTO(dir)->unlink_done(task, dir)) if (!NFS_PROTO(dir)->unlink_done(task, dir))
rpc_restart_call(task); rpc_restart_call(task);
else
nfs_end_data_update(dir);
} }
/** /**
......
This diff is collapsed.
...@@ -102,7 +102,8 @@ check_filename(char *str, int len, __be32 err) ...@@ -102,7 +102,8 @@ check_filename(char *str, int len, __be32 err)
out: \ out: \
return status; \ return status; \
xdr_error: \ xdr_error: \
printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ dprintk("NFSD: xdr error (%s:%d)\n", \
__FILE__, __LINE__); \
status = nfserr_bad_xdr; \ status = nfserr_bad_xdr; \
goto out goto out
...@@ -124,7 +125,8 @@ xdr_error: \ ...@@ -124,7 +125,8 @@ xdr_error: \
if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
savemem(argp, p, nbytes) : \ savemem(argp, p, nbytes) : \
(char *)p)) { \ (char *)p)) { \
printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ dprintk("NFSD: xdr error (%s:%d)\n", \
__FILE__, __LINE__); \
goto xdr_error; \ goto xdr_error; \
} \ } \
p += XDR_QUADLEN(nbytes); \ p += XDR_QUADLEN(nbytes); \
...@@ -140,7 +142,8 @@ xdr_error: \ ...@@ -140,7 +142,8 @@ xdr_error: \
p = argp->p; \ p = argp->p; \
argp->p += XDR_QUADLEN(nbytes); \ argp->p += XDR_QUADLEN(nbytes); \
} else if (!(p = read_buf(argp, nbytes))) { \ } else if (!(p = read_buf(argp, nbytes))) { \
printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \ dprintk("NFSD: xdr error (%s:%d)\n", \
__FILE__, __LINE__); \
goto xdr_error; \ goto xdr_error; \
} \ } \
} while (0) } while (0)
...@@ -948,7 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) ...@@ -948,7 +951,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
*/ */
avail = (char*)argp->end - (char*)argp->p; avail = (char*)argp->end - (char*)argp->p;
if (avail + argp->pagelen < write->wr_buflen) { if (avail + argp->pagelen < write->wr_buflen) {
printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); dprintk("NFSD: xdr error (%s:%d)\n",
__FILE__, __LINE__);
goto xdr_error; goto xdr_error;
} }
argp->rqstp->rq_vec[0].iov_base = p; argp->rqstp->rq_vec[0].iov_base = p;
...@@ -1019,7 +1023,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1019,7 +1023,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
if (!argp->ops) { if (!argp->ops) {
argp->ops = argp->iops; argp->ops = argp->iops;
printk(KERN_INFO "nfsd: couldn't allocate room for COMPOUND\n"); dprintk("nfsd: couldn't allocate room for COMPOUND\n");
goto xdr_error; goto xdr_error;
} }
} }
...@@ -1326,7 +1330,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * ...@@ -1326,7 +1330,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
path = exp->ex_path; path = exp->ex_path;
if (strncmp(path, rootpath, strlen(rootpath))) { if (strncmp(path, rootpath, strlen(rootpath))) {
printk("nfsd: fs_locations failed;" dprintk("nfsd: fs_locations failed;"
"%s is not contained in %s\n", path, rootpath); "%s is not contained in %s\n", path, rootpath);
*stat = nfserr_notsupp; *stat = nfserr_notsupp;
return NULL; return NULL;
......
...@@ -109,6 +109,10 @@ static inline u64 get_jiffies_64(void) ...@@ -109,6 +109,10 @@ static inline u64 get_jiffies_64(void)
((long)(a) - (long)(b) >= 0)) ((long)(a) - (long)(b) >= 0))
#define time_before_eq(a,b) time_after_eq(b,a) #define time_before_eq(a,b) time_after_eq(b,a)
#define time_in_range(a,b,c) \
(time_after_eq(a,b) && \
time_before_eq(a,c))
/* Same as above, but does so with platform independent 64bit types. /* Same as above, but does so with platform independent 64bit types.
* These must be used when utilizing jiffies_64 (i.e. return value of * These must be used when utilizing jiffies_64 (i.e. return value of
* get_jiffies_64() */ * get_jiffies_64() */
......
...@@ -47,10 +47,8 @@ ...@@ -47,10 +47,8 @@
#include <linux/nfs3.h> #include <linux/nfs3.h>
#include <linux/nfs4.h> #include <linux/nfs4.h>
#include <linux/nfs_xdr.h> #include <linux/nfs_xdr.h>
#include <linux/nfs_fs_sb.h> #include <linux/nfs_fs_sb.h>
#include <linux/rwsem.h>
#include <linux/mempool.h> #include <linux/mempool.h>
/* /*
...@@ -77,6 +75,9 @@ struct nfs_open_context { ...@@ -77,6 +75,9 @@ struct nfs_open_context {
struct nfs4_state *state; struct nfs4_state *state;
fl_owner_t lockowner; fl_owner_t lockowner;
int mode; int mode;
unsigned long flags;
#define NFS_CONTEXT_ERROR_WRITE (0)
int error; int error;
struct list_head list; struct list_head list;
...@@ -133,11 +134,6 @@ struct nfs_inode { ...@@ -133,11 +134,6 @@ struct nfs_inode {
* server. * server.
*/ */
unsigned long cache_change_attribute; unsigned long cache_change_attribute;
/*
* Counter indicating the number of outstanding requests that
* will cause a file data update.
*/
atomic_t data_updates;
struct rb_root access_cache; struct rb_root access_cache;
struct list_head access_cache_entry_lru; struct list_head access_cache_entry_lru;
...@@ -205,27 +201,18 @@ static inline struct nfs_inode *NFS_I(struct inode *inode) ...@@ -205,27 +201,18 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
#define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
#define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops) #define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops)
#define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf) #define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf)
#define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies)
#define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr)
#define NFS_ATTRTIMEO(inode) (NFS_I(inode)->attrtimeo)
#define NFS_MINATTRTIMEO(inode) \ #define NFS_MINATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \ (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
: NFS_SERVER(inode)->acregmin) : NFS_SERVER(inode)->acregmin)
#define NFS_MAXATTRTIMEO(inode) \ #define NFS_MAXATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \ (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
: NFS_SERVER(inode)->acregmax) : NFS_SERVER(inode)->acregmax)
#define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp)
#define NFS_FLAGS(inode) (NFS_I(inode)->flags) #define NFS_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode))) #define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode)))
#define NFS_FILEID(inode) (NFS_I(inode)->fileid) #define NFS_FILEID(inode) (NFS_I(inode)->fileid)
static inline int nfs_caches_unstable(struct inode *inode)
{
return atomic_read(&NFS_I(inode)->data_updates) != 0;
}
static inline void nfs_mark_for_revalidate(struct inode *inode) static inline void nfs_mark_for_revalidate(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
...@@ -237,12 +224,6 @@ static inline void nfs_mark_for_revalidate(struct inode *inode) ...@@ -237,12 +224,6 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
static inline void NFS_CACHEINV(struct inode *inode)
{
if (!nfs_caches_unstable(inode))
nfs_mark_for_revalidate(inode);
}
static inline int nfs_server_capable(struct inode *inode, int cap) static inline int nfs_server_capable(struct inode *inode, int cap)
{ {
return NFS_SERVER(inode)->caps & cap; return NFS_SERVER(inode)->caps & cap;
...@@ -253,28 +234,33 @@ static inline int NFS_USE_READDIRPLUS(struct inode *inode) ...@@ -253,28 +234,33 @@ static inline int NFS_USE_READDIRPLUS(struct inode *inode)
return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
} }
static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
{
dentry->d_time = verf;
}
/** /**
* nfs_save_change_attribute - Returns the inode attribute change cookie * nfs_save_change_attribute - Returns the inode attribute change cookie
* @inode - pointer to inode * @dir - pointer to parent directory inode
* The "change attribute" is updated every time we finish an operation * The "change attribute" is updated every time we finish an operation
* that will result in a metadata change on the server. * that will result in a metadata change on the server.
*/ */
static inline long nfs_save_change_attribute(struct inode *inode) static inline unsigned long nfs_save_change_attribute(struct inode *dir)
{ {
return NFS_I(inode)->cache_change_attribute; return NFS_I(dir)->cache_change_attribute;
} }
/** /**
* nfs_verify_change_attribute - Detects NFS inode cache updates * nfs_verify_change_attribute - Detects NFS remote directory changes
* @inode - pointer to inode * @dir - pointer to parent directory inode
* @chattr - previously saved change attribute * @chattr - previously saved change attribute
* Return "false" if metadata has been updated (or is in the process of * Return "false" if the verifiers doesn't match the change attribute.
* being updated) since the change attribute was saved. * This would usually indicate that the directory contents have changed on
* the server, and that any dentries need revalidating.
*/ */
static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr) static inline int nfs_verify_change_attribute(struct inode *dir, unsigned long chattr)
{ {
return !nfs_caches_unstable(inode) return chattr == NFS_I(dir)->cache_change_attribute;
&& time_after_eq(chattr, NFS_I(inode)->cache_change_attribute);
} }
/* /*
...@@ -283,15 +269,14 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long ...@@ -283,15 +269,14 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long
extern int nfs_sync_mapping(struct address_space *mapping); extern int nfs_sync_mapping(struct address_space *mapping);
extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping); extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
extern void nfs_zap_caches(struct inode *); extern void nfs_zap_caches(struct inode *);
extern void nfs_invalidate_atime(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *); struct nfs_fattr *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *); extern int nfs_permission(struct inode *, int, struct nameidata *);
extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
extern void nfs_access_zap_cache(struct inode *inode);
extern int nfs_open(struct inode *, struct file *); extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *);
extern int nfs_attribute_timeout(struct inode *inode); extern int nfs_attribute_timeout(struct inode *inode);
...@@ -301,13 +286,10 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map ...@@ -301,13 +286,10 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
extern int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping); extern int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *); extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
extern void nfs_begin_attr_update(struct inode *);
extern void nfs_end_attr_update(struct inode *);
extern void nfs_begin_data_update(struct inode *);
extern void nfs_end_data_update(struct inode *);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
extern u64 nfs_compat_user_ino64(u64 fileid);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern __be32 root_nfs_parse_addr(char *name); /*__init*/ extern __be32 root_nfs_parse_addr(char *name); /*__init*/
...@@ -328,14 +310,15 @@ extern const struct inode_operations nfs3_file_inode_operations; ...@@ -328,14 +310,15 @@ extern const struct inode_operations nfs3_file_inode_operations;
extern const struct file_operations nfs_file_operations; extern const struct file_operations nfs_file_operations;
extern const struct address_space_operations nfs_file_aops; extern const struct address_space_operations nfs_file_aops;
static inline struct rpc_cred *nfs_file_cred(struct file *file) static inline struct nfs_open_context *nfs_file_open_context(struct file *filp)
{ {
if (file != NULL) { return filp->private_data;
struct nfs_open_context *ctx; }
ctx = (struct nfs_open_context*)file->private_data; static inline struct rpc_cred *nfs_file_cred(struct file *file)
return ctx->cred; {
} if (file != NULL)
return nfs_file_open_context(file)->cred;
return NULL; return NULL;
} }
...@@ -378,6 +361,8 @@ extern const struct file_operations nfs_dir_operations; ...@@ -378,6 +361,8 @@ extern const struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations; extern struct dentry_operations nfs_dentry_operations;
extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
extern void nfs_access_zap_cache(struct inode *inode);
/* /*
* linux/fs/nfs/symlink.c * linux/fs/nfs/symlink.c
...@@ -420,15 +405,14 @@ extern int nfs_flush_incompatible(struct file *file, struct page *page); ...@@ -420,15 +405,14 @@ extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
extern void nfs_writedata_release(void *); extern void nfs_writedata_release(void *);
extern int nfs_set_page_dirty(struct page *);
/* /*
* Try to write back everything synchronously (but check the * Try to write back everything synchronously (but check the
* return value!) * return value!)
*/ */
extern long nfs_sync_mapping_wait(struct address_space *, struct writeback_control *, int); extern long nfs_sync_mapping_wait(struct address_space *, struct writeback_control *, int);
extern int nfs_sync_mapping_range(struct address_space *, loff_t, loff_t, int);
extern int nfs_wb_all(struct inode *inode); extern int nfs_wb_all(struct inode *inode);
extern int nfs_wb_nocommit(struct inode *inode);
extern int nfs_wb_page(struct inode *inode, struct page* page); extern int nfs_wb_page(struct inode *inode, struct page* page);
extern int nfs_wb_page_priority(struct inode *inode, struct page* page, int how); extern int nfs_wb_page_priority(struct inode *inode, struct page* page, int how);
extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#define PG_BUSY 0 #define PG_BUSY 0
#define PG_NEED_COMMIT 1 #define PG_NEED_COMMIT 1
#define PG_NEED_RESCHED 2 #define PG_NEED_RESCHED 2
#define PG_NEED_FLUSH 3
struct nfs_inode; struct nfs_inode;
struct nfs_page { struct nfs_page {
......
...@@ -62,7 +62,8 @@ struct nfs_fattr { ...@@ -62,7 +62,8 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */ #define NFS_ATTR_FATTR 0x0002 /* post-op attributes */
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */ #define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */
#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */ #define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */
#define NFS_ATTR_FATTR_V4_REFERRAL 0x0010 /* NFSv4 referral */ #define NFS_ATTR_WCC_V4 0x0010 /* pre-op change attribute */
#define NFS_ATTR_FATTR_V4_REFERRAL 0x0020 /* NFSv4 referral */
/* /*
* Info on the file system * Info on the file system
...@@ -538,10 +539,13 @@ typedef u64 clientid4; ...@@ -538,10 +539,13 @@ typedef u64 clientid4;
struct nfs4_accessargs { struct nfs4_accessargs {
const struct nfs_fh * fh; const struct nfs_fh * fh;
const u32 * bitmask;
u32 access; u32 access;
}; };
struct nfs4_accessres { struct nfs4_accessres {
const struct nfs_server * server;
struct nfs_fattr * fattr;
u32 supported; u32 supported;
u32 access; u32 access;
}; };
......
...@@ -117,7 +117,7 @@ struct rpc_create_args { ...@@ -117,7 +117,7 @@ struct rpc_create_args {
struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
struct rpc_program *, int); struct rpc_program *, u32);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
void rpc_shutdown_client(struct rpc_clnt *); void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *); void rpc_release_client(struct rpc_clnt *);
......
...@@ -88,6 +88,11 @@ enum { ...@@ -88,6 +88,11 @@ enum {
CTL_SLOTTABLE_TCP, CTL_SLOTTABLE_TCP,
CTL_MIN_RESVPORT, CTL_MIN_RESVPORT,
CTL_MAX_RESVPORT, CTL_MAX_RESVPORT,
CTL_SLOTTABLE_RDMA,
CTL_RDMA_MAXINLINEREAD,
CTL_RDMA_MAXINLINEWRITE,
CTL_RDMA_WRITEPADDING,
CTL_RDMA_MEMREG,
}; };
#endif /* _LINUX_SUNRPC_DEBUG_H_ */ #endif /* _LINUX_SUNRPC_DEBUG_H_ */
...@@ -138,6 +138,19 @@ typedef __be32 rpc_fraghdr; ...@@ -138,6 +138,19 @@ typedef __be32 rpc_fraghdr;
#define RPC_MAX_HEADER_WITH_AUTH \ #define RPC_MAX_HEADER_WITH_AUTH \
(RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4)) (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
/*
* RFC1833/RFC3530 rpcbind (v3+) well-known netid's.
*/
#define RPCBIND_NETID_UDP "udp"
#define RPCBIND_NETID_TCP "tcp"
#define RPCBIND_NETID_UDP6 "udp6"
#define RPCBIND_NETID_TCP6 "tcp6"
/*
* Note that RFC 1833 does not put any size restrictions on the
* netid string, but all currently defined netid's fit in 4 bytes.
*/
#define RPCBIND_MAXNETIDLEN (4u)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */ #endif /* _LINUX_SUNRPC_MSGPROT_H_ */
/*
* Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the BSD-type
* license below:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* Neither the name of the Network Appliance, Inc. nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LINUX_SUNRPC_RPC_RDMA_H
#define _LINUX_SUNRPC_RPC_RDMA_H
struct rpcrdma_segment {
uint32_t rs_handle; /* Registered memory handle */
uint32_t rs_length; /* Length of the chunk in bytes */
uint64_t rs_offset; /* Chunk virtual address or offset */
};
/*
* read chunk(s), encoded as a linked list.
*/
struct rpcrdma_read_chunk {
uint32_t rc_discrim; /* 1 indicates presence */
uint32_t rc_position; /* Position in XDR stream */
struct rpcrdma_segment rc_target;
};
/*
* write chunk, and reply chunk.
*/
struct rpcrdma_write_chunk {
struct rpcrdma_segment wc_target;
};
/*
* write chunk(s), encoded as a counted array.
*/
struct rpcrdma_write_array {
uint32_t wc_discrim; /* 1 indicates presence */
uint32_t wc_nchunks; /* Array count */
struct rpcrdma_write_chunk wc_array[0];
};
struct rpcrdma_msg {
uint32_t rm_xid; /* Mirrors the RPC header xid */
uint32_t rm_vers; /* Version of this protocol */
uint32_t rm_credit; /* Buffers requested/granted */
uint32_t rm_type; /* Type of message (enum rpcrdma_proc) */
union {
struct { /* no chunks */
uint32_t rm_empty[3]; /* 3 empty chunk lists */
} rm_nochunks;
struct { /* no chunks and padded */
uint32_t rm_align; /* Padding alignment */
uint32_t rm_thresh; /* Padding threshold */
uint32_t rm_pempty[3]; /* 3 empty chunk lists */
} rm_padded;
uint32_t rm_chunks[0]; /* read, write and reply chunks */
} rm_body;
};
#define RPCRDMA_HDRLEN_MIN 28
enum rpcrdma_errcode {
ERR_VERS = 1,
ERR_CHUNK = 2
};
struct rpcrdma_err_vers {
uint32_t rdma_vers_low; /* Version range supported by peer */
uint32_t rdma_vers_high;
};
enum rpcrdma_proc {
RDMA_MSG = 0, /* An RPC call or reply msg */
RDMA_NOMSG = 1, /* An RPC call or reply msg - separate body */
RDMA_MSGP = 2, /* An RPC call or reply msg with padding */
RDMA_DONE = 3, /* Client signals reply completion */
RDMA_ERROR = 4 /* An RPC RDMA encoding error */
};
#endif /* _LINUX_SUNRPC_RPC_RDMA_H */
...@@ -70,7 +70,10 @@ struct xdr_buf { ...@@ -70,7 +70,10 @@ struct xdr_buf {
struct page ** pages; /* Array of contiguous pages */ struct page ** pages; /* Array of contiguous pages */
unsigned int page_base, /* Start of page data */ unsigned int page_base, /* Start of page data */
page_len; /* Length of page data */ page_len, /* Length of page data */
flags; /* Flags for data disposition */
#define XDRBUF_READ 0x01 /* target of file read */
#define XDRBUF_WRITE 0x02 /* source of file write */
unsigned int buflen, /* Total length of storage buffer */ unsigned int buflen, /* Total length of storage buffer */
len; /* Length of XDR encoded message */ len; /* Length of XDR encoded message */
......
...@@ -19,24 +19,10 @@ ...@@ -19,24 +19,10 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
extern unsigned int xprt_udp_slot_table_entries;
extern unsigned int xprt_tcp_slot_table_entries;
#define RPC_MIN_SLOT_TABLE (2U) #define RPC_MIN_SLOT_TABLE (2U)
#define RPC_DEF_SLOT_TABLE (16U) #define RPC_DEF_SLOT_TABLE (16U)
#define RPC_MAX_SLOT_TABLE (128U) #define RPC_MAX_SLOT_TABLE (128U)
/*
* Parameters for choosing a free port
*/
extern unsigned int xprt_min_resvport;
extern unsigned int xprt_max_resvport;
#define RPC_MIN_RESVPORT (1U)
#define RPC_MAX_RESVPORT (65535U)
#define RPC_DEF_MIN_RESVPORT (665U)
#define RPC_DEF_MAX_RESVPORT (1023U)
/* /*
* This describes a timeout strategy * This describes a timeout strategy
*/ */
...@@ -53,6 +39,10 @@ enum rpc_display_format_t { ...@@ -53,6 +39,10 @@ enum rpc_display_format_t {
RPC_DISPLAY_PORT, RPC_DISPLAY_PORT,
RPC_DISPLAY_PROTO, RPC_DISPLAY_PROTO,
RPC_DISPLAY_ALL, RPC_DISPLAY_ALL,
RPC_DISPLAY_HEX_ADDR,
RPC_DISPLAY_HEX_PORT,
RPC_DISPLAY_UNIVERSAL_ADDR,
RPC_DISPLAY_NETID,
RPC_DISPLAY_MAX, RPC_DISPLAY_MAX,
}; };
...@@ -196,14 +186,22 @@ struct rpc_xprt { ...@@ -196,14 +186,22 @@ struct rpc_xprt {
char * address_strings[RPC_DISPLAY_MAX]; char * address_strings[RPC_DISPLAY_MAX];
}; };
struct rpc_xprtsock_create { struct xprt_create {
int proto; /* IPPROTO_UDP or IPPROTO_TCP */ int ident; /* XPRT_TRANSPORT identifier */
struct sockaddr * srcaddr; /* optional local address */ struct sockaddr * srcaddr; /* optional local address */
struct sockaddr * dstaddr; /* remote peer address */ struct sockaddr * dstaddr; /* remote peer address */
size_t addrlen; size_t addrlen;
struct rpc_timeout * timeout; /* optional timeout parameters */ struct rpc_timeout * timeout; /* optional timeout parameters */
}; };
struct xprt_class {
struct list_head list;
int ident; /* XPRT_TRANSPORT identifier */
struct rpc_xprt * (*setup)(struct xprt_create *);
struct module *owner;
char name[32];
};
/* /*
* Transport operations used by ULPs * Transport operations used by ULPs
*/ */
...@@ -212,7 +210,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long ...@@ -212,7 +210,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long
/* /*
* Generic internal transport functions * Generic internal transport functions
*/ */
struct rpc_xprt * xprt_create_transport(struct rpc_xprtsock_create *args); struct rpc_xprt *xprt_create_transport(struct xprt_create *args);
void xprt_connect(struct rpc_task *task); void xprt_connect(struct rpc_task *task);
void xprt_reserve(struct rpc_task *task); void xprt_reserve(struct rpc_task *task);
int xprt_reserve_xprt(struct rpc_task *task); int xprt_reserve_xprt(struct rpc_task *task);
...@@ -235,6 +233,8 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 * ...@@ -235,6 +233,8 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *
/* /*
* Transport switch helper functions * Transport switch helper functions
*/ */
int xprt_register_transport(struct xprt_class *type);
int xprt_unregister_transport(struct xprt_class *type);
void xprt_set_retrans_timeout_def(struct rpc_task *task); void xprt_set_retrans_timeout_def(struct rpc_task *task);
void xprt_set_retrans_timeout_rtt(struct rpc_task *task); void xprt_set_retrans_timeout_rtt(struct rpc_task *task);
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
...@@ -247,14 +247,6 @@ void xprt_complete_rqst(struct rpc_task *task, int copied); ...@@ -247,14 +247,6 @@ void xprt_complete_rqst(struct rpc_task *task, int copied);
void xprt_release_rqst_cong(struct rpc_task *task); void xprt_release_rqst_cong(struct rpc_task *task);
void xprt_disconnect(struct rpc_xprt *xprt); void xprt_disconnect(struct rpc_xprt *xprt);
/*
* Socket transport setup operations
*/
struct rpc_xprt * xs_setup_udp(struct rpc_xprtsock_create *args);
struct rpc_xprt * xs_setup_tcp(struct rpc_xprtsock_create *args);
int init_socket_xprt(void);
void cleanup_socket_xprt(void);
/* /*
* Reserved bit positions in xprt->state * Reserved bit positions in xprt->state
*/ */
......
/*
* Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the BSD-type
* license below:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* Neither the name of the Network Appliance, Inc. nor the names of
* its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LINUX_SUNRPC_XPRTRDMA_H
#define _LINUX_SUNRPC_XPRTRDMA_H
/*
* RPC transport identifier for RDMA
*/
#define XPRT_TRANSPORT_RDMA 256
/*
* rpcbind (v3+) RDMA netid.
*/
#define RPCBIND_NETID_RDMA "rdma"
/*
* Constants. Max RPC/NFS header is big enough to account for
* additional marshaling buffers passed down by Linux client.
*
* RDMA header is currently fixed max size, and is big enough for a
* fully-chunked NFS message (read chunks are the largest). Note only
* a single chunk type per message is supported currently.
*/
#define RPCRDMA_MIN_SLOT_TABLE (2U)
#define RPCRDMA_DEF_SLOT_TABLE (32U)
#define RPCRDMA_MAX_SLOT_TABLE (256U)
#define RPCRDMA_DEF_INLINE (1024) /* default inline max */
#define RPCRDMA_INLINE_PAD_THRESH (512)/* payload threshold to pad (bytes) */
#define RDMA_RESOLVE_TIMEOUT (5*HZ) /* TBD 5 seconds */
#define RDMA_CONNECT_RETRY_MAX (2) /* retries if no listener backlog */
/* memory registration strategies */
#define RPCRDMA_PERSISTENT_REGISTRATION (1)
enum rpcrdma_memreg {
RPCRDMA_BOUNCEBUFFERS = 0,
RPCRDMA_REGISTER,
RPCRDMA_MEMWINDOWS,
RPCRDMA_MEMWINDOWS_ASYNC,
RPCRDMA_MTHCAFMR,
RPCRDMA_ALLPHYSICAL,
RPCRDMA_LAST
};
#endif /* _LINUX_SUNRPC_XPRTRDMA_H */
/*
* linux/include/linux/sunrpc/xprtsock.h
*
* Declarations for the RPC transport socket provider.
*/
#ifndef _LINUX_SUNRPC_XPRTSOCK_H
#define _LINUX_SUNRPC_XPRTSOCK_H
#ifdef __KERNEL__
/*
* Socket transport setup operations
*/
struct rpc_xprt *xs_setup_udp(struct xprt_create *args);
struct rpc_xprt *xs_setup_tcp(struct xprt_create *args);
int init_socket_xprt(void);
void cleanup_socket_xprt(void);
/*
* RPC transport identifiers for UDP, TCP
*
* To preserve compatibility with the historical use of raw IP protocol
* id's for transport selection, these are specified with the previous
* values. No such restriction exists for new transports, except that
* they may not collide with these values (17 and 6, respectively).
*/
#define XPRT_TRANSPORT_UDP IPPROTO_UDP
#define XPRT_TRANSPORT_TCP IPPROTO_TCP
/*
* RPC slot table sizes for UDP, TCP transports
*/
extern unsigned int xprt_udp_slot_table_entries;
extern unsigned int xprt_tcp_slot_table_entries;
/*
* Parameters for choosing a free port
*/
extern unsigned int xprt_min_resvport;
extern unsigned int xprt_max_resvport;
#define RPC_MIN_RESVPORT (1U)
#define RPC_MAX_RESVPORT (65535U)
#define RPC_DEF_MIN_RESVPORT (665U)
#define RPC_DEF_MAX_RESVPORT (1023U)
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_XPRTSOCK_H */
...@@ -62,8 +62,6 @@ struct writeback_control { ...@@ -62,8 +62,6 @@ struct writeback_control {
unsigned for_reclaim:1; /* Invoked from the page allocator */ unsigned for_reclaim:1; /* Invoked from the page allocator */
unsigned for_writepages:1; /* This is a writepages() call */ unsigned for_writepages:1; /* This is a writepages() call */
unsigned range_cyclic:1; /* range_start is cyclic */ unsigned range_cyclic:1; /* range_start is cyclic */
void *fs_private; /* For use by ->writepages() */
}; };
/* /*
......
...@@ -1525,6 +1525,7 @@ void __audit_inode_child(const char *dname, const struct inode *inode, ...@@ -1525,6 +1525,7 @@ void __audit_inode_child(const char *dname, const struct inode *inode,
context->names[idx].ino = (unsigned long)-1; context->names[idx].ino = (unsigned long)-1;
} }
} }
EXPORT_SYMBOL_GPL(__audit_inode_child);
/** /**
* auditsc_get_stamp - get local copies of audit_context values * auditsc_get_stamp - get local copies of audit_context values
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
obj-$(CONFIG_SUNRPC) += sunrpc.o obj-$(CONFIG_SUNRPC) += sunrpc.o
obj-$(CONFIG_SUNRPC_GSS) += auth_gss/ obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
auth.o auth_null.o auth_unix.o \ auth.o auth_null.o auth_unix.o \
......
...@@ -42,7 +42,7 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize) ...@@ -42,7 +42,7 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
{ {
u8 *ptr; u8 *ptr;
u8 pad; u8 pad;
int len = buf->len; size_t len = buf->len;
if (len <= buf->head[0].iov_len) { if (len <= buf->head[0].iov_len) {
pad = *(u8 *)(buf->head[0].iov_base + len - 1); pad = *(u8 *)(buf->head[0].iov_base + len - 1);
...@@ -53,9 +53,9 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize) ...@@ -53,9 +53,9 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
} else } else
len -= buf->head[0].iov_len; len -= buf->head[0].iov_len;
if (len <= buf->page_len) { if (len <= buf->page_len) {
int last = (buf->page_base + len - 1) unsigned int last = (buf->page_base + len - 1)
>>PAGE_CACHE_SHIFT; >>PAGE_CACHE_SHIFT;
int offset = (buf->page_base + len - 1) unsigned int offset = (buf->page_base + len - 1)
& (PAGE_CACHE_SIZE - 1); & (PAGE_CACHE_SIZE - 1);
ptr = kmap_atomic(buf->pages[last], KM_USER0); ptr = kmap_atomic(buf->pages[last], KM_USER0);
pad = *(ptr + offset); pad = *(ptr + offset);
......
...@@ -127,7 +127,14 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s ...@@ -127,7 +127,14 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
struct rpc_clnt *clnt = NULL; struct rpc_clnt *clnt = NULL;
struct rpc_auth *auth; struct rpc_auth *auth;
int err; int err;
int len; size_t len;
/* sanity check the name before trying to print it */
err = -EINVAL;
len = strlen(servname);
if (len > RPC_MAXNETNAMELEN)
goto out_no_rpciod;
len++;
dprintk("RPC: creating %s client for %s (xprt %p)\n", dprintk("RPC: creating %s client for %s (xprt %p)\n",
program->name, servname, xprt); program->name, servname, xprt);
...@@ -148,7 +155,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s ...@@ -148,7 +155,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
clnt->cl_parent = clnt; clnt->cl_parent = clnt;
clnt->cl_server = clnt->cl_inline_name; clnt->cl_server = clnt->cl_inline_name;
len = strlen(servname) + 1;
if (len > sizeof(clnt->cl_inline_name)) { if (len > sizeof(clnt->cl_inline_name)) {
char *buf = kmalloc(len, GFP_KERNEL); char *buf = kmalloc(len, GFP_KERNEL);
if (buf != 0) if (buf != 0)
...@@ -234,8 +240,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) ...@@ -234,8 +240,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
{ {
struct rpc_xprt *xprt; struct rpc_xprt *xprt;
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct rpc_xprtsock_create xprtargs = { struct xprt_create xprtargs = {
.proto = args->protocol, .ident = args->protocol,
.srcaddr = args->saddress, .srcaddr = args->saddress,
.dstaddr = args->address, .dstaddr = args->address,
.addrlen = args->addrsize, .addrlen = args->addrsize,
...@@ -253,7 +259,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) ...@@ -253,7 +259,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
*/ */
if (args->servername == NULL) { if (args->servername == NULL) {
struct sockaddr_in *addr = struct sockaddr_in *addr =
(struct sockaddr_in *) &args->address; (struct sockaddr_in *) args->address;
snprintf(servername, sizeof(servername), NIPQUAD_FMT, snprintf(servername, sizeof(servername), NIPQUAD_FMT,
NIPQUAD(addr->sin_addr.s_addr)); NIPQUAD(addr->sin_addr.s_addr));
args->servername = servername; args->servername = servername;
...@@ -269,9 +275,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) ...@@ -269,9 +275,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
xprt->resvport = 0; xprt->resvport = 0;
dprintk("RPC: creating %s client for %s (xprt %p)\n",
args->program->name, args->servername, xprt);
clnt = rpc_new_client(xprt, args->servername, args->program, clnt = rpc_new_client(xprt, args->servername, args->program,
args->version, args->authflavor); args->version, args->authflavor);
if (IS_ERR(clnt)) if (IS_ERR(clnt))
...@@ -439,7 +442,7 @@ rpc_release_client(struct rpc_clnt *clnt) ...@@ -439,7 +442,7 @@ rpc_release_client(struct rpc_clnt *clnt)
*/ */
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
struct rpc_program *program, struct rpc_program *program,
int vers) u32 vers)
{ {
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct rpc_version *version; struct rpc_version *version;
...@@ -843,8 +846,7 @@ call_allocate(struct rpc_task *task) ...@@ -843,8 +846,7 @@ call_allocate(struct rpc_task *task)
dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid); dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
if (RPC_IS_ASYNC(task) || !signalled()) { if (RPC_IS_ASYNC(task) || !signalled()) {
xprt_release(task); task->tk_action = call_allocate;
task->tk_action = call_reserve;
rpc_delay(task, HZ>>4); rpc_delay(task, HZ>>4);
return; return;
} }
...@@ -871,6 +873,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) ...@@ -871,6 +873,7 @@ rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
buf->head[0].iov_len = len; buf->head[0].iov_len = len;
buf->tail[0].iov_len = 0; buf->tail[0].iov_len = 0;
buf->page_len = 0; buf->page_len = 0;
buf->flags = 0;
buf->len = 0; buf->len = 0;
buf->buflen = len; buf->buflen = len;
} }
...@@ -937,7 +940,7 @@ call_bind(struct rpc_task *task) ...@@ -937,7 +940,7 @@ call_bind(struct rpc_task *task)
static void static void
call_bind_status(struct rpc_task *task) call_bind_status(struct rpc_task *task)
{ {
int status = -EACCES; int status = -EIO;
if (task->tk_status >= 0) { if (task->tk_status >= 0) {
dprint_status(task); dprint_status(task);
...@@ -947,9 +950,20 @@ call_bind_status(struct rpc_task *task) ...@@ -947,9 +950,20 @@ call_bind_status(struct rpc_task *task)
} }
switch (task->tk_status) { switch (task->tk_status) {
case -EAGAIN:
dprintk("RPC: %5u rpcbind waiting for another request "
"to finish\n", task->tk_pid);
/* avoid busy-waiting here -- could be a network outage. */
rpc_delay(task, 5*HZ);
goto retry_timeout;
case -EACCES: case -EACCES:
dprintk("RPC: %5u remote rpcbind: RPC program/version " dprintk("RPC: %5u remote rpcbind: RPC program/version "
"unavailable\n", task->tk_pid); "unavailable\n", task->tk_pid);
/* fail immediately if this is an RPC ping */
if (task->tk_msg.rpc_proc->p_proc == 0) {
status = -EOPNOTSUPP;
break;
}
rpc_delay(task, 3*HZ); rpc_delay(task, 3*HZ);
goto retry_timeout; goto retry_timeout;
case -ETIMEDOUT: case -ETIMEDOUT:
...@@ -957,6 +971,7 @@ call_bind_status(struct rpc_task *task) ...@@ -957,6 +971,7 @@ call_bind_status(struct rpc_task *task)
task->tk_pid); task->tk_pid);
goto retry_timeout; goto retry_timeout;
case -EPFNOSUPPORT: case -EPFNOSUPPORT:
/* server doesn't support any rpcbind version we know of */
dprintk("RPC: %5u remote rpcbind service unavailable\n", dprintk("RPC: %5u remote rpcbind service unavailable\n",
task->tk_pid); task->tk_pid);
break; break;
...@@ -969,7 +984,6 @@ call_bind_status(struct rpc_task *task) ...@@ -969,7 +984,6 @@ call_bind_status(struct rpc_task *task)
default: default:
dprintk("RPC: %5u unrecognized rpcbind error (%d)\n", dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
task->tk_pid, -task->tk_status); task->tk_pid, -task->tk_status);
status = -EIO;
} }
rpc_exit(task, status); rpc_exit(task, status);
...@@ -1257,7 +1271,6 @@ call_refresh(struct rpc_task *task) ...@@ -1257,7 +1271,6 @@ call_refresh(struct rpc_task *task)
{ {
dprint_status(task); dprint_status(task);
xprt_release(task); /* Must do to obtain new XID */
task->tk_action = call_refreshresult; task->tk_action = call_refreshresult;
task->tk_status = 0; task->tk_status = 0;
task->tk_client->cl_stats->rpcauthrefresh++; task->tk_client->cl_stats->rpcauthrefresh++;
...@@ -1375,6 +1388,8 @@ call_verify(struct rpc_task *task) ...@@ -1375,6 +1388,8 @@ call_verify(struct rpc_task *task)
dprintk("RPC: %5u %s: retry stale creds\n", dprintk("RPC: %5u %s: retry stale creds\n",
task->tk_pid, __FUNCTION__); task->tk_pid, __FUNCTION__);
rpcauth_invalcred(task); rpcauth_invalcred(task);
/* Ensure we obtain a new XID! */
xprt_release(task);
task->tk_action = call_refresh; task->tk_action = call_refresh;
goto out_retry; goto out_retry;
case RPC_AUTH_BADCRED: case RPC_AUTH_BADCRED:
...@@ -1523,13 +1538,18 @@ void rpc_show_tasks(void) ...@@ -1523,13 +1538,18 @@ void rpc_show_tasks(void)
spin_lock(&clnt->cl_lock); spin_lock(&clnt->cl_lock);
list_for_each_entry(t, &clnt->cl_tasks, tk_task) { list_for_each_entry(t, &clnt->cl_tasks, tk_task) {
const char *rpc_waitq = "none"; const char *rpc_waitq = "none";
int proc;
if (t->tk_msg.rpc_proc)
proc = t->tk_msg.rpc_proc->p_proc;
else
proc = -1;
if (RPC_IS_QUEUED(t)) if (RPC_IS_QUEUED(t))
rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
t->tk_pid, t->tk_pid, proc,
(t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
t->tk_flags, t->tk_status, t->tk_flags, t->tk_status,
t->tk_client, t->tk_client,
(t->tk_client ? t->tk_client->cl_prog : 0), (t->tk_client ? t->tk_client->cl_prog : 0),
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/dnotify.h> #include <linux/fsnotify.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
...@@ -329,6 +329,7 @@ rpc_show_info(struct seq_file *m, void *v) ...@@ -329,6 +329,7 @@ rpc_show_info(struct seq_file *m, void *v)
clnt->cl_prog, clnt->cl_vers); clnt->cl_prog, clnt->cl_vers);
seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
return 0; return 0;
} }
...@@ -585,6 +586,7 @@ rpc_populate(struct dentry *parent, ...@@ -585,6 +586,7 @@ rpc_populate(struct dentry *parent,
if (S_ISDIR(mode)) if (S_ISDIR(mode))
inc_nlink(dir); inc_nlink(dir);
d_add(dentry, inode); d_add(dentry, inode);
fsnotify_create(dir, dentry);
} }
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
return 0; return 0;
...@@ -606,7 +608,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) ...@@ -606,7 +608,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
inode->i_ino = iunique(dir->i_sb, 100); inode->i_ino = iunique(dir->i_sb, 100);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
inc_nlink(dir); inc_nlink(dir);
inode_dir_notify(dir, DN_CREATE); fsnotify_mkdir(dir, dentry);
return 0; return 0;
out_err: out_err:
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
...@@ -748,7 +750,7 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi ...@@ -748,7 +750,7 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi
rpci->flags = flags; rpci->flags = flags;
rpci->ops = ops; rpci->ops = ops;
rpci->nkern_readwriters = 1; rpci->nkern_readwriters = 1;
inode_dir_notify(dir, DN_CREATE); fsnotify_create(dir, dentry);
dget(dentry); dget(dentry);
out: out:
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
......
...@@ -16,11 +16,14 @@ ...@@ -16,11 +16,14 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h> #include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xprtsock.h>
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_BIND # define RPCDBG_FACILITY RPCDBG_BIND
...@@ -90,26 +93,6 @@ enum { ...@@ -90,26 +93,6 @@ enum {
*/ */
#define RPCB_MAXADDRLEN (128u) #define RPCB_MAXADDRLEN (128u)
/*
* r_netid
*
* Quoting RFC 3530, section 2.2:
*
* For TCP over IPv4 the value of r_netid is the string "tcp". For UDP
* over IPv4 the value of r_netid is the string "udp".
*
* ...
*
* For TCP over IPv6 the value of r_netid is the string "tcp6". For UDP
* over IPv6 the value of r_netid is the string "udp6".
*/
#define RPCB_NETID_UDP "\165\144\160" /* "udp" */
#define RPCB_NETID_TCP "\164\143\160" /* "tcp" */
#define RPCB_NETID_UDP6 "\165\144\160\066" /* "udp6" */
#define RPCB_NETID_TCP6 "\164\143\160\066" /* "tcp6" */
#define RPCB_MAXNETIDLEN (4u)
/* /*
* r_owner * r_owner
* *
...@@ -120,7 +103,7 @@ enum { ...@@ -120,7 +103,7 @@ enum {
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
static void rpcb_getport_done(struct rpc_task *, void *); static void rpcb_getport_done(struct rpc_task *, void *);
extern struct rpc_program rpcb_program; static struct rpc_program rpcb_program;
struct rpcbind_args { struct rpcbind_args {
struct rpc_xprt * r_xprt; struct rpc_xprt * r_xprt;
...@@ -137,10 +120,13 @@ struct rpcbind_args { ...@@ -137,10 +120,13 @@ struct rpcbind_args {
static struct rpc_procinfo rpcb_procedures2[]; static struct rpc_procinfo rpcb_procedures2[];
static struct rpc_procinfo rpcb_procedures3[]; static struct rpc_procinfo rpcb_procedures3[];
static struct rpcb_info { struct rpcb_info {
int rpc_vers; int rpc_vers;
struct rpc_procinfo * rpc_proc; struct rpc_procinfo * rpc_proc;
} rpcb_next_version[]; };
static struct rpcb_info rpcb_next_version[];
static struct rpcb_info rpcb_next_version6[];
static void rpcb_getport_prepare(struct rpc_task *task, void *calldata) static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
{ {
...@@ -190,7 +176,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, ...@@ -190,7 +176,17 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
RPC_CLNT_CREATE_INTR), RPC_CLNT_CREATE_INTR),
}; };
switch (srvaddr->sa_family) {
case AF_INET:
((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
break;
case AF_INET6:
((struct sockaddr_in6 *)srvaddr)->sin6_port = htons(RPCBIND_PORT);
break;
default:
return NULL;
}
if (!privileged) if (!privileged)
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
return rpc_create(&args); return rpc_create(&args);
...@@ -234,7 +230,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) ...@@ -234,7 +230,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
prog, vers, prot, port); prog, vers, prot, port);
rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
IPPROTO_UDP, 2, 1); XPRT_TRANSPORT_UDP, 2, 1);
if (IS_ERR(rpcb_clnt)) if (IS_ERR(rpcb_clnt))
return PTR_ERR(rpcb_clnt); return PTR_ERR(rpcb_clnt);
...@@ -316,6 +312,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -316,6 +312,7 @@ void rpcb_getport_async(struct rpc_task *task)
struct rpc_task *child; struct rpc_task *child;
struct sockaddr addr; struct sockaddr addr;
int status; int status;
struct rpcb_info *info;
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
task->tk_pid, __FUNCTION__, task->tk_pid, __FUNCTION__,
...@@ -325,7 +322,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -325,7 +322,7 @@ void rpcb_getport_async(struct rpc_task *task)
BUG_ON(clnt->cl_parent != clnt); BUG_ON(clnt->cl_parent != clnt);
if (xprt_test_and_set_binding(xprt)) { if (xprt_test_and_set_binding(xprt)) {
status = -EACCES; /* tell caller to check again */ status = -EAGAIN; /* tell caller to check again */
dprintk("RPC: %5u %s: waiting for another binder\n", dprintk("RPC: %5u %s: waiting for another binder\n",
task->tk_pid, __FUNCTION__); task->tk_pid, __FUNCTION__);
goto bailout_nowake; goto bailout_nowake;
...@@ -343,18 +340,43 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -343,18 +340,43 @@ void rpcb_getport_async(struct rpc_task *task)
goto bailout_nofree; goto bailout_nofree;
} }
if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) { rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
/* Don't ever use rpcbind v2 for AF_INET6 requests */
switch (addr.sa_family) {
case AF_INET:
info = rpcb_next_version;
break;
case AF_INET6:
info = rpcb_next_version6;
break;
default:
status = -EAFNOSUPPORT;
dprintk("RPC: %5u %s: bad address family\n",
task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
if (info[xprt->bind_index].rpc_proc == NULL) {
xprt->bind_index = 0; xprt->bind_index = 0;
status = -EACCES; /* tell caller to try again later */ status = -EPFNOSUPPORT;
dprintk("RPC: %5u %s: no more getport versions available\n", dprintk("RPC: %5u %s: no more getport versions available\n",
task->tk_pid, __FUNCTION__); task->tk_pid, __FUNCTION__);
goto bailout_nofree; goto bailout_nofree;
} }
bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; bind_version = info[xprt->bind_index].rpc_vers;
dprintk("RPC: %5u %s: trying rpcbind version %u\n", dprintk("RPC: %5u %s: trying rpcbind version %u\n",
task->tk_pid, __FUNCTION__, bind_version); task->tk_pid, __FUNCTION__, bind_version);
rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
bind_version, 0);
if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt);
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
goto bailout_nofree;
}
map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC); map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
if (!map) { if (!map) {
status = -ENOMEM; status = -ENOMEM;
...@@ -367,28 +389,19 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -367,28 +389,19 @@ void rpcb_getport_async(struct rpc_task *task)
map->r_prot = xprt->prot; map->r_prot = xprt->prot;
map->r_port = 0; map->r_port = 0;
map->r_xprt = xprt_get(xprt); map->r_xprt = xprt_get(xprt);
map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP : map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
RPCB_NETID_UDP; memcpy(map->r_addr,
memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR), rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
sizeof(map->r_addr)); sizeof(map->r_addr));
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt);
dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
goto bailout;
}
child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
rpc_release_client(rpcb_clnt); rpc_release_client(rpcb_clnt);
if (IS_ERR(child)) { if (IS_ERR(child)) {
status = -EIO; status = -EIO;
dprintk("RPC: %5u %s: rpc_run_task failed\n", dprintk("RPC: %5u %s: rpc_run_task failed\n",
task->tk_pid, __FUNCTION__); task->tk_pid, __FUNCTION__);
goto bailout_nofree; goto bailout;
} }
rpc_put_task(child); rpc_put_task(child);
...@@ -403,6 +416,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -403,6 +416,7 @@ void rpcb_getport_async(struct rpc_task *task)
bailout_nowake: bailout_nowake:
task->tk_status = status; task->tk_status = status;
} }
EXPORT_SYMBOL_GPL(rpcb_getport_async);
/* /*
* Rpcbind child task calls this callback via tk_exit. * Rpcbind child task calls this callback via tk_exit.
...@@ -413,6 +427,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) ...@@ -413,6 +427,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
struct rpc_xprt *xprt = map->r_xprt; struct rpc_xprt *xprt = map->r_xprt;
int status = child->tk_status; int status = child->tk_status;
/* Garbage reply: retry with a lesser rpcbind version */
if (status == -EIO)
status = -EPROTONOSUPPORT;
/* rpcbind server doesn't support this rpcbind protocol version */ /* rpcbind server doesn't support this rpcbind protocol version */
if (status == -EPROTONOSUPPORT) if (status == -EPROTONOSUPPORT)
xprt->bind_index++; xprt->bind_index++;
...@@ -490,16 +508,24 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, ...@@ -490,16 +508,24 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
unsigned short *portp) unsigned short *portp)
{ {
char *addr; char *addr;
int addr_len, c, i, f, first, val; u32 addr_len;
int c, i, f, first, val;
*portp = 0; *portp = 0;
addr_len = (unsigned int) ntohl(*p++); addr_len = ntohl(*p++);
if (addr_len > RPCB_MAXADDRLEN) /* sanity */
return -EINVAL;
dprintk("RPC: rpcb_decode_getaddr returned string: '%s'\n", /*
(char *) p); * Simple sanity check. The smallest possible universal
* address is an IPv4 address string containing 11 bytes.
*/
if (addr_len < 11 || addr_len > RPCB_MAXADDRLEN)
goto out_err;
/*
* Start at the end and walk backwards until the first dot
* is encountered. When the second dot is found, we have
* both parts of the port number.
*/
addr = (char *)p; addr = (char *)p;
val = 0; val = 0;
first = 1; first = 1;
...@@ -521,8 +547,19 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, ...@@ -521,8 +547,19 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
} }
} }
/*
* Simple sanity check. If we never saw a dot in the reply,
* then this was probably just garbage.
*/
if (first)
goto out_err;
dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp); dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp);
return 0; return 0;
out_err:
dprintk("RPC: rpcbind server returned malformed reply\n");
return -EIO;
} }
#define RPCB_program_sz (1u) #define RPCB_program_sz (1u)
...@@ -531,7 +568,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, ...@@ -531,7 +568,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
#define RPCB_port_sz (1u) #define RPCB_port_sz (1u)
#define RPCB_boolean_sz (1u) #define RPCB_boolean_sz (1u)
#define RPCB_netid_sz (1+XDR_QUADLEN(RPCB_MAXNETIDLEN)) #define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
#define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN)) #define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN))
#define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN)) #define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
...@@ -593,6 +630,14 @@ static struct rpcb_info rpcb_next_version[] = { ...@@ -593,6 +630,14 @@ static struct rpcb_info rpcb_next_version[] = {
{ 0, NULL }, { 0, NULL },
}; };
static struct rpcb_info rpcb_next_version6[] = {
#ifdef CONFIG_SUNRPC_BIND34
{ 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
{ 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
#endif
{ 0, NULL },
};
static struct rpc_version rpcb_version2 = { static struct rpc_version rpcb_version2 = {
.number = 2, .number = 2,
.nrprocs = RPCB_HIGHPROC_2, .nrprocs = RPCB_HIGHPROC_2,
...@@ -621,7 +666,7 @@ static struct rpc_version *rpcb_version[] = { ...@@ -621,7 +666,7 @@ static struct rpc_version *rpcb_version[] = {
static struct rpc_stat rpcb_stats; static struct rpc_stat rpcb_stats;
struct rpc_program rpcb_program = { static struct rpc_program rpcb_program = {
.name = "rpcbind", .name = "rpcbind",
.number = RPCBIND_PROGRAM, .number = RPCBIND_PROGRAM,
.nrvers = ARRAY_SIZE(rpcb_version), .nrvers = ARRAY_SIZE(rpcb_version),
......
...@@ -777,6 +777,7 @@ void *rpc_malloc(struct rpc_task *task, size_t size) ...@@ -777,6 +777,7 @@ void *rpc_malloc(struct rpc_task *task, size_t size)
task->tk_pid, size, buf); task->tk_pid, size, buf);
return &buf->data; return &buf->data;
} }
EXPORT_SYMBOL_GPL(rpc_malloc);
/** /**
* rpc_free - free buffer allocated via rpc_malloc * rpc_free - free buffer allocated via rpc_malloc
...@@ -802,6 +803,7 @@ void rpc_free(void *buffer) ...@@ -802,6 +803,7 @@ void rpc_free(void *buffer)
else else
kfree(buf); kfree(buf);
} }
EXPORT_SYMBOL_GPL(rpc_free);
/* /*
* Creation and deletion of RPC task structures * Creation and deletion of RPC task structures
......
...@@ -34,6 +34,7 @@ size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len) ...@@ -34,6 +34,7 @@ size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len)
desc->offset += len; desc->offset += len;
return len; return len;
} }
EXPORT_SYMBOL_GPL(xdr_skb_read_bits);
/** /**
* xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer * xdr_skb_read_and_csum_bits - copy and checksum from skb to buffer
...@@ -137,6 +138,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct ...@@ -137,6 +138,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct
out: out:
return copied; return copied;
} }
EXPORT_SYMBOL_GPL(xdr_partial_copy_from_skb);
/** /**
* csum_partial_copy_to_xdr - checksum and copy data * csum_partial_copy_to_xdr - checksum and copy data
...@@ -179,3 +181,4 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) ...@@ -179,3 +181,4 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
return -1; return -1;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(csum_partial_copy_to_xdr);
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/sunrpc/auth.h> #include <linux/sunrpc/auth.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h> #include <linux/sunrpc/rpc_pipe_fs.h>
#include <linux/sunrpc/xprtsock.h>
/* RPC scheduler */ /* RPC scheduler */
EXPORT_SYMBOL(rpc_execute); EXPORT_SYMBOL(rpc_execute);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/module.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
...@@ -40,6 +41,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) ...@@ -40,6 +41,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
rt->ntimeouts[i] = 0; rt->ntimeouts[i] = 0;
} }
} }
EXPORT_SYMBOL_GPL(rpc_init_rtt);
/* /*
* NB: When computing the smoothed RTT and standard deviation, * NB: When computing the smoothed RTT and standard deviation,
...@@ -75,6 +77,7 @@ rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m) ...@@ -75,6 +77,7 @@ rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
if (*sdrtt < RPC_RTO_MIN) if (*sdrtt < RPC_RTO_MIN)
*sdrtt = RPC_RTO_MIN; *sdrtt = RPC_RTO_MIN;
} }
EXPORT_SYMBOL_GPL(rpc_update_rtt);
/* /*
* Estimate rto for an nfs rpc sent via. an unreliable datagram. * Estimate rto for an nfs rpc sent via. an unreliable datagram.
...@@ -103,3 +106,4 @@ rpc_calc_rto(struct rpc_rtt *rt, unsigned timer) ...@@ -103,3 +106,4 @@ rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
return res; return res;
} }
EXPORT_SYMBOL_GPL(rpc_calc_rto);
...@@ -62,6 +62,9 @@ static inline void do_xprt_reserve(struct rpc_task *); ...@@ -62,6 +62,9 @@ static inline void do_xprt_reserve(struct rpc_task *);
static void xprt_connect_status(struct rpc_task *task); static void xprt_connect_status(struct rpc_task *task);
static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
static spinlock_t xprt_list_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(xprt_list);
/* /*
* The transport code maintains an estimate on the maximum number of out- * The transport code maintains an estimate on the maximum number of out-
* standing RPC requests, using a smoothed version of the congestion * standing RPC requests, using a smoothed version of the congestion
...@@ -80,6 +83,78 @@ static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); ...@@ -80,6 +83,78 @@ static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) #define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
/**
* xprt_register_transport - register a transport implementation
* @transport: transport to register
*
* If a transport implementation is loaded as a kernel module, it can
* call this interface to make itself known to the RPC client.
*
* Returns:
* 0: transport successfully registered
* -EEXIST: transport already registered
* -EINVAL: transport module being unloaded
*/
int xprt_register_transport(struct xprt_class *transport)
{
struct xprt_class *t;
int result;
result = -EEXIST;
spin_lock(&xprt_list_lock);
list_for_each_entry(t, &xprt_list, list) {
/* don't register the same transport class twice */
if (t->ident == transport->ident)
goto out;
}
result = -EINVAL;
if (try_module_get(THIS_MODULE)) {
list_add_tail(&transport->list, &xprt_list);
printk(KERN_INFO "RPC: Registered %s transport module.\n",
transport->name);
result = 0;
}
out:
spin_unlock(&xprt_list_lock);
return result;
}
EXPORT_SYMBOL_GPL(xprt_register_transport);
/**
* xprt_unregister_transport - unregister a transport implementation
* transport: transport to unregister
*
* Returns:
* 0: transport successfully unregistered
* -ENOENT: transport never registered
*/
int xprt_unregister_transport(struct xprt_class *transport)
{
struct xprt_class *t;
int result;
result = 0;
spin_lock(&xprt_list_lock);
list_for_each_entry(t, &xprt_list, list) {
if (t == transport) {
printk(KERN_INFO
"RPC: Unregistered %s transport module.\n",
transport->name);
list_del_init(&transport->list);
module_put(THIS_MODULE);
goto out;
}
}
result = -ENOENT;
out:
spin_unlock(&xprt_list_lock);
return result;
}
EXPORT_SYMBOL_GPL(xprt_unregister_transport);
/** /**
* xprt_reserve_xprt - serialize write access to transports * xprt_reserve_xprt - serialize write access to transports
* @task: task that is requesting access to the transport * @task: task that is requesting access to the transport
...@@ -118,6 +193,7 @@ int xprt_reserve_xprt(struct rpc_task *task) ...@@ -118,6 +193,7 @@ int xprt_reserve_xprt(struct rpc_task *task)
rpc_sleep_on(&xprt->sending, task, NULL, NULL); rpc_sleep_on(&xprt->sending, task, NULL, NULL);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
static void xprt_clear_locked(struct rpc_xprt *xprt) static void xprt_clear_locked(struct rpc_xprt *xprt)
{ {
...@@ -167,6 +243,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task) ...@@ -167,6 +243,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task)
rpc_sleep_on(&xprt->sending, task, NULL, NULL); rpc_sleep_on(&xprt->sending, task, NULL, NULL);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
{ {
...@@ -246,6 +323,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -246,6 +323,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
__xprt_lock_write_next(xprt); __xprt_lock_write_next(xprt);
} }
} }
EXPORT_SYMBOL_GPL(xprt_release_xprt);
/** /**
* xprt_release_xprt_cong - allow other requests to use a transport * xprt_release_xprt_cong - allow other requests to use a transport
...@@ -262,6 +340,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -262,6 +340,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
__xprt_lock_write_next_cong(xprt); __xprt_lock_write_next_cong(xprt);
} }
} }
EXPORT_SYMBOL_GPL(xprt_release_xprt_cong);
static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task) static inline void xprt_release_write(struct rpc_xprt *xprt, struct rpc_task *task)
{ {
...@@ -314,6 +393,7 @@ void xprt_release_rqst_cong(struct rpc_task *task) ...@@ -314,6 +393,7 @@ void xprt_release_rqst_cong(struct rpc_task *task)
{ {
__xprt_put_cong(task->tk_xprt, task->tk_rqstp); __xprt_put_cong(task->tk_xprt, task->tk_rqstp);
} }
EXPORT_SYMBOL_GPL(xprt_release_rqst_cong);
/** /**
* xprt_adjust_cwnd - adjust transport congestion window * xprt_adjust_cwnd - adjust transport congestion window
...@@ -345,6 +425,7 @@ void xprt_adjust_cwnd(struct rpc_task *task, int result) ...@@ -345,6 +425,7 @@ void xprt_adjust_cwnd(struct rpc_task *task, int result)
xprt->cwnd = cwnd; xprt->cwnd = cwnd;
__xprt_put_cong(xprt, req); __xprt_put_cong(xprt, req);
} }
EXPORT_SYMBOL_GPL(xprt_adjust_cwnd);
/** /**
* xprt_wake_pending_tasks - wake all tasks on a transport's pending queue * xprt_wake_pending_tasks - wake all tasks on a transport's pending queue
...@@ -359,6 +440,7 @@ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status) ...@@ -359,6 +440,7 @@ void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status)
else else
rpc_wake_up(&xprt->pending); rpc_wake_up(&xprt->pending);
} }
EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks);
/** /**
* xprt_wait_for_buffer_space - wait for transport output buffer to clear * xprt_wait_for_buffer_space - wait for transport output buffer to clear
...@@ -373,6 +455,7 @@ void xprt_wait_for_buffer_space(struct rpc_task *task) ...@@ -373,6 +455,7 @@ void xprt_wait_for_buffer_space(struct rpc_task *task)
task->tk_timeout = req->rq_timeout; task->tk_timeout = req->rq_timeout;
rpc_sleep_on(&xprt->pending, task, NULL, NULL); rpc_sleep_on(&xprt->pending, task, NULL, NULL);
} }
EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
/** /**
* xprt_write_space - wake the task waiting for transport output buffer space * xprt_write_space - wake the task waiting for transport output buffer space
...@@ -393,6 +476,7 @@ void xprt_write_space(struct rpc_xprt *xprt) ...@@ -393,6 +476,7 @@ void xprt_write_space(struct rpc_xprt *xprt)
} }
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
} }
EXPORT_SYMBOL_GPL(xprt_write_space);
/** /**
* xprt_set_retrans_timeout_def - set a request's retransmit timeout * xprt_set_retrans_timeout_def - set a request's retransmit timeout
...@@ -406,6 +490,7 @@ void xprt_set_retrans_timeout_def(struct rpc_task *task) ...@@ -406,6 +490,7 @@ void xprt_set_retrans_timeout_def(struct rpc_task *task)
{ {
task->tk_timeout = task->tk_rqstp->rq_timeout; task->tk_timeout = task->tk_rqstp->rq_timeout;
} }
EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_def);
/* /*
* xprt_set_retrans_timeout_rtt - set a request's retransmit timeout * xprt_set_retrans_timeout_rtt - set a request's retransmit timeout
...@@ -425,6 +510,7 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task) ...@@ -425,6 +510,7 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task)
if (task->tk_timeout > max_timeout || task->tk_timeout == 0) if (task->tk_timeout > max_timeout || task->tk_timeout == 0)
task->tk_timeout = max_timeout; task->tk_timeout = max_timeout;
} }
EXPORT_SYMBOL_GPL(xprt_set_retrans_timeout_rtt);
static void xprt_reset_majortimeo(struct rpc_rqst *req) static void xprt_reset_majortimeo(struct rpc_rqst *req)
{ {
...@@ -500,6 +586,7 @@ void xprt_disconnect(struct rpc_xprt *xprt) ...@@ -500,6 +586,7 @@ void xprt_disconnect(struct rpc_xprt *xprt)
xprt_wake_pending_tasks(xprt, -ENOTCONN); xprt_wake_pending_tasks(xprt, -ENOTCONN);
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
} }
EXPORT_SYMBOL_GPL(xprt_disconnect);
static void static void
xprt_init_autodisconnect(unsigned long data) xprt_init_autodisconnect(unsigned long data)
...@@ -610,6 +697,7 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) ...@@ -610,6 +697,7 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
xprt->stat.bad_xids++; xprt->stat.bad_xids++;
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(xprt_lookup_rqst);
/** /**
* xprt_update_rtt - update an RPC client's RTT state after receiving a reply * xprt_update_rtt - update an RPC client's RTT state after receiving a reply
...@@ -629,6 +717,7 @@ void xprt_update_rtt(struct rpc_task *task) ...@@ -629,6 +717,7 @@ void xprt_update_rtt(struct rpc_task *task)
rpc_set_timeo(rtt, timer, req->rq_ntrans - 1); rpc_set_timeo(rtt, timer, req->rq_ntrans - 1);
} }
} }
EXPORT_SYMBOL_GPL(xprt_update_rtt);
/** /**
* xprt_complete_rqst - called when reply processing is complete * xprt_complete_rqst - called when reply processing is complete
...@@ -653,6 +742,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) ...@@ -653,6 +742,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
req->rq_received = req->rq_private_buf.len = copied; req->rq_received = req->rq_private_buf.len = copied;
rpc_wake_up_task(task); rpc_wake_up_task(task);
} }
EXPORT_SYMBOL_GPL(xprt_complete_rqst);
static void xprt_timer(struct rpc_task *task) static void xprt_timer(struct rpc_task *task)
{ {
...@@ -889,23 +979,25 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i ...@@ -889,23 +979,25 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
* @args: rpc transport creation arguments * @args: rpc transport creation arguments
* *
*/ */
struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args) struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
{ {
struct rpc_xprt *xprt; struct rpc_xprt *xprt;
struct rpc_rqst *req; struct rpc_rqst *req;
struct xprt_class *t;
switch (args->proto) { spin_lock(&xprt_list_lock);
case IPPROTO_UDP: list_for_each_entry(t, &xprt_list, list) {
xprt = xs_setup_udp(args); if (t->ident == args->ident) {
break; spin_unlock(&xprt_list_lock);
case IPPROTO_TCP: goto found;
xprt = xs_setup_tcp(args);
break;
default:
printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
args->proto);
return ERR_PTR(-EIO);
} }
}
spin_unlock(&xprt_list_lock);
printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident);
return ERR_PTR(-EIO);
found:
xprt = t->setup(args);
if (IS_ERR(xprt)) { if (IS_ERR(xprt)) {
dprintk("RPC: xprt_create_transport: failed, %ld\n", dprintk("RPC: xprt_create_transport: failed, %ld\n",
-PTR_ERR(xprt)); -PTR_ERR(xprt));
......
obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
xprtrdma-y := transport.o rpc_rdma.o verbs.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment