Commit 4fe70410 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'for-linus' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (58 commits)
  SUNRPC: Ensure IPV6_V6ONLY is set on the socket before binding to a port
  NSM: Fix unaligned accesses in nsm_init_private()
  NFS: Simplify logic to compare socket addresses in client.c
  NFS: Start PF_INET6 callback listener only if IPv6 support is available
  lockd: Start PF_INET6 listener only if IPv6 support is available
  SUNRPC: Remove CONFIG_SUNRPC_REGISTER_V4
  SUNRPC: rpcb_register() should handle errors silently
  SUNRPC: Simplify kernel RPC service registration
  SUNRPC: Simplify svc_unregister()
  SUNRPC: Allow callers to pass rpcb_v4_register a NULL address
  SUNRPC: rpcbind actually interprets r_owner string
  SUNRPC: Clean up address type casts in rpcb_v4_register()
  SUNRPC: Don't return EPROTONOSUPPORT in svc_register()'s helpers
  SUNRPC: Use IPv4 loopback for registering AF_INET6 kernel RPC services
  SUNRPC: Set IPV6ONLY flag on PF_INET6 RPC listener sockets
  NFS: Revert creation of IPv6 listeners for lockd and NFSv4 callbacks
  SUNRPC: Remove @family argument from svc_create() and svc_create_pooled()
  SUNRPC: Change svc_create_xprt() to take a @family argument
  SUNRPC: svc_setup_socket() gets protocol family from socket
  SUNRPC: Pass a family argument to svc_register()
  ...
parents 395d7341 cc859061
...@@ -139,55 +139,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) ...@@ -139,55 +139,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
return 0; return 0;
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap,
struct in6_addr *addr_mapped)
{
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
switch (sap->sa_family) {
case AF_INET6:
return &((const struct sockaddr_in6 *)sap)->sin6_addr;
case AF_INET:
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped);
return addr_mapped;
}
return NULL;
}
/*
* If lockd is using a PF_INET6 listener, all incoming requests appear
* to come from AF_INET6 remotes. The address of AF_INET remotes are
* mapped to AF_INET6 automatically by the network layer. In case the
* user passed an AF_INET server address at mount time, ensure both
* addresses are AF_INET6 before comparing them.
*/
static int nlmclnt_cmp_addr(const struct nlm_host *host,
const struct sockaddr *sap)
{
const struct in6_addr *addr1;
const struct in6_addr *addr2;
struct in6_addr addr1_mapped;
struct in6_addr addr2_mapped;
addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped);
if (likely(addr1 != NULL)) {
addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped);
if (likely(addr2 != NULL))
return ipv6_addr_equal(addr1, addr2);
}
return 0;
}
#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static int nlmclnt_cmp_addr(const struct nlm_host *host,
const struct sockaddr *sap)
{
return nlm_cmp_addr(nlm_addr(host), sap);
}
#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
/* /*
* The server lockd has called us back to tell us the lock was granted * The server lockd has called us back to tell us the lock was granted
*/ */
...@@ -215,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) ...@@ -215,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
*/ */
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
continue; continue;
if (!nlmclnt_cmp_addr(block->b_host, addr)) if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
continue; continue;
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue; continue;
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <asm/unaligned.h>
#define NLMDBG_FACILITY NLMDBG_MONITOR #define NLMDBG_FACILITY NLMDBG_MONITOR
#define NSM_PROGRAM 100024 #define NSM_PROGRAM 100024
#define NSM_VERSION 1 #define NSM_VERSION 1
...@@ -274,10 +276,12 @@ static void nsm_init_private(struct nsm_handle *nsm) ...@@ -274,10 +276,12 @@ static void nsm_init_private(struct nsm_handle *nsm)
{ {
u64 *p = (u64 *)&nsm->sm_priv.data; u64 *p = (u64 *)&nsm->sm_priv.data;
struct timespec ts; struct timespec ts;
s64 ns;
ktime_get_ts(&ts); ktime_get_ts(&ts);
*p++ = timespec_to_ns(&ts); ns = timespec_to_ns(&ts);
*p = (unsigned long)nsm; put_unaligned(ns, p);
put_unaligned((unsigned long)nsm, p + 1);
} }
static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
......
...@@ -52,17 +52,6 @@ static struct task_struct *nlmsvc_task; ...@@ -52,17 +52,6 @@ static struct task_struct *nlmsvc_task;
static struct svc_rqst *nlmsvc_rqst; static struct svc_rqst *nlmsvc_rqst;
unsigned long nlmsvc_timeout; unsigned long nlmsvc_timeout;
/*
* If the kernel has IPv6 support available, always listen for
* both AF_INET and AF_INET6 requests.
*/
#if (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) && \
defined(CONFIG_SUNRPC_REGISTER_V4)
static const sa_family_t nlmsvc_family = AF_INET6;
#else /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
static const sa_family_t nlmsvc_family = AF_INET;
#endif /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
/* /*
* These can be set at insmod time (useful for NFS as root filesystem), * These can be set at insmod time (useful for NFS as root filesystem),
* and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
...@@ -204,19 +193,30 @@ lockd(void *vrqstp) ...@@ -204,19 +193,30 @@ lockd(void *vrqstp)
return 0; return 0;
} }
static int create_lockd_listener(struct svc_serv *serv, char *name, static int create_lockd_listener(struct svc_serv *serv, const char *name,
unsigned short port) const int family, const unsigned short port)
{ {
struct svc_xprt *xprt; struct svc_xprt *xprt;
xprt = svc_find_xprt(serv, name, 0, 0); xprt = svc_find_xprt(serv, name, family, 0);
if (xprt == NULL) if (xprt == NULL)
return svc_create_xprt(serv, name, port, SVC_SOCK_DEFAULTS); return svc_create_xprt(serv, name, family, port,
SVC_SOCK_DEFAULTS);
svc_xprt_put(xprt); svc_xprt_put(xprt);
return 0; return 0;
} }
static int create_lockd_family(struct svc_serv *serv, const int family)
{
int err;
err = create_lockd_listener(serv, "udp", family, nlm_udpport);
if (err < 0)
return err;
return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
}
/* /*
* Ensure there are active UDP and TCP listeners for lockd. * Ensure there are active UDP and TCP listeners for lockd.
* *
...@@ -232,13 +232,15 @@ static int make_socks(struct svc_serv *serv) ...@@ -232,13 +232,15 @@ static int make_socks(struct svc_serv *serv)
static int warned; static int warned;
int err; int err;
err = create_lockd_listener(serv, "udp", nlm_udpport); err = create_lockd_family(serv, PF_INET);
if (err < 0) if (err < 0)
goto out_err; goto out_err;
err = create_lockd_listener(serv, "tcp", nlm_tcpport); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
if (err < 0) err = create_lockd_family(serv, PF_INET6);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_err; goto out_err;
#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
warned = 0; warned = 0;
return 0; return 0;
...@@ -274,7 +276,7 @@ int lockd_up(void) ...@@ -274,7 +276,7 @@ int lockd_up(void)
"lockd_up: no pid, %d users??\n", nlmsvc_users); "lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM; error = -ENOMEM;
serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, nlmsvc_family, NULL); serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
if (!serv) { if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n"); printk(KERN_WARNING "lockd_up: create service failed\n");
goto out; goto out;
......
...@@ -38,19 +38,10 @@ static struct svc_program nfs4_callback_program; ...@@ -38,19 +38,10 @@ static struct svc_program nfs4_callback_program;
unsigned int nfs_callback_set_tcpport; unsigned int nfs_callback_set_tcpport;
unsigned short nfs_callback_tcpport; unsigned short nfs_callback_tcpport;
unsigned short nfs_callback_tcpport6;
static const int nfs_set_port_min = 0; static const int nfs_set_port_min = 0;
static const int nfs_set_port_max = 65535; static const int nfs_set_port_max = 65535;
/*
* If the kernel has IPv6 support available, always listen for
* both AF_INET and AF_INET6 requests.
*/
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const sa_family_t nfs_callback_family = AF_INET6;
#else
static const sa_family_t nfs_callback_family = AF_INET;
#endif
static int param_set_port(const char *val, struct kernel_param *kp) static int param_set_port(const char *val, struct kernel_param *kp)
{ {
char *endp; char *endp;
...@@ -116,19 +107,29 @@ int nfs_callback_up(void) ...@@ -116,19 +107,29 @@ int nfs_callback_up(void)
mutex_lock(&nfs_callback_mutex); mutex_lock(&nfs_callback_mutex);
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
goto out; goto out;
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
nfs_callback_family, NULL);
ret = -ENOMEM; ret = -ENOMEM;
if (!serv) if (!serv)
goto out_err; goto out_err;
ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport, ret = svc_create_xprt(serv, "tcp", PF_INET,
SVC_SOCK_ANONYMOUS); nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
if (ret <= 0) if (ret <= 0)
goto out_err; goto out_err;
nfs_callback_tcpport = ret; nfs_callback_tcpport = ret;
dprintk("NFS: Callback listener port = %u (af %u)\n", dprintk("NFS: Callback listener port = %u (af %u)\n",
nfs_callback_tcpport, nfs_callback_family); nfs_callback_tcpport, PF_INET);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
ret = svc_create_xprt(serv, "tcp", PF_INET6,
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
if (ret > 0) {
nfs_callback_tcpport6 = ret;
dprintk("NFS: Callback listener port = %u (af %u)\n",
nfs_callback_tcpport6, PF_INET6);
} else if (ret != -EAFNOSUPPORT)
goto out_err;
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
if (IS_ERR(nfs_callback_info.rqst)) { if (IS_ERR(nfs_callback_info.rqst)) {
......
...@@ -72,5 +72,6 @@ extern void nfs_callback_down(void); ...@@ -72,5 +72,6 @@ extern void nfs_callback_down(void);
extern unsigned int nfs_callback_set_tcpport; extern unsigned int nfs_callback_set_tcpport;
extern unsigned short nfs_callback_tcpport; extern unsigned short nfs_callback_tcpport;
extern unsigned short nfs_callback_tcpport6;
#endif /* __LINUX_FS_NFS_CALLBACK_H */ #endif /* __LINUX_FS_NFS_CALLBACK_H */
...@@ -224,38 +224,6 @@ void nfs_put_client(struct nfs_client *clp) ...@@ -224,38 +224,6 @@ void nfs_put_client(struct nfs_client *clp)
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
{
switch (sa->sa_family) {
default:
return NULL;
case AF_INET6:
return &((const struct sockaddr_in6 *)sa)->sin6_addr;
break;
case AF_INET:
ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr,
addr_mapped);
return addr_mapped;
}
}
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
const struct in6_addr *addr1;
const struct in6_addr *addr2;
struct in6_addr addr1_mapped;
struct in6_addr addr2_mapped;
addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped);
if (likely(addr1 != NULL)) {
addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped);
if (likely(addr2 != NULL))
return ipv6_addr_equal(addr1, addr2);
}
return 0;
}
/* /*
* Test if two ip6 socket addresses refer to the same socket by * Test if two ip6 socket addresses refer to the same socket by
* comparing relevant fields. The padding bytes specifically, are not * comparing relevant fields. The padding bytes specifically, are not
...@@ -267,38 +235,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, ...@@ -267,38 +235,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
* *
* The caller should ensure both socket addresses are AF_INET6. * The caller should ensure both socket addresses are AF_INET6.
*/ */
static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
const struct sockaddr *sa2) const struct sockaddr *sa2)
{ {
const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1; const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2; const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
if (!ipv6_addr_equal(&saddr1->sin6_addr, if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
&saddr1->sin6_addr)) sin1->sin6_scope_id != sin2->sin6_scope_id)
return 0; return 0;
if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
saddr1->sin6_scope_id != saddr2->sin6_scope_id)
return 0;
return saddr1->sin6_port == saddr2->sin6_port;
}
#else
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
const struct sockaddr_in *sa2)
{
return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
}
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr);
const struct sockaddr *sa2)
{
if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
return 0;
return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
(const struct sockaddr_in *)sa2);
} }
#else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
const struct sockaddr * sa2) const struct sockaddr *sa2)
{ {
return 0; return 0;
} }
...@@ -311,20 +262,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, ...@@ -311,20 +262,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
* *
* The caller should ensure both socket addresses are AF_INET. * The caller should ensure both socket addresses are AF_INET.
*/ */
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
}
static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
return nfs_sockaddr_match_ipaddr6(sa1, sa2) &&
(sin1->sin6_port == sin2->sin6_port);
}
static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
const struct sockaddr *sa2) const struct sockaddr *sa2)
{ {
const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1; const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2; const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr) return nfs_sockaddr_match_ipaddr4(sa1, sa2) &&
(sin1->sin_port == sin2->sin_port);
}
/*
* Test if two socket addresses represent the same actual socket,
* by comparing (only) relevant fields, excluding the port number.
*/
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
if (sa1->sa_family != sa2->sa_family)
return 0; return 0;
return saddr1->sin_port == saddr2->sin_port;
switch (sa1->sa_family) {
case AF_INET:
return nfs_sockaddr_match_ipaddr4(sa1, sa2);
case AF_INET6:
return nfs_sockaddr_match_ipaddr6(sa1, sa2);
}
return 0;
} }
/* /*
* Test if two socket addresses represent the same actual socket, * Test if two socket addresses represent the same actual socket,
* by comparing (only) relevant fields. * by comparing (only) relevant fields, including the port number.
*/ */
static int nfs_sockaddr_cmp(const struct sockaddr *sa1, static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
const struct sockaddr *sa2) const struct sockaddr *sa2)
......
...@@ -1624,8 +1624,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1624,8 +1624,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} else if (atomic_read(&new_dentry->d_count) > 1) } else if (atomic_read(&new_dentry->d_count) > 1)
/* dentry still busy? */ /* dentry still busy? */
goto out; goto out;
} else }
nfs_drop_nlink(new_inode);
go_ahead: go_ahead:
/* /*
...@@ -1638,10 +1637,8 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1638,10 +1637,8 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
nfs_inode_return_delegation(old_inode); nfs_inode_return_delegation(old_inode);
if (new_inode != NULL) { if (new_inode != NULL)
nfs_inode_return_delegation(new_inode); nfs_inode_return_delegation(new_inode);
d_delete(new_dentry);
}
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
new_dir, &new_dentry->d_name); new_dir, &new_dentry->d_name);
...@@ -1650,6 +1647,8 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1650,6 +1647,8 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (rehash) if (rehash)
d_rehash(rehash); d_rehash(rehash);
if (!error) { if (!error) {
if (new_inode != NULL)
nfs_drop_nlink(new_inode);
d_move(old_dentry, new_dentry); d_move(old_dentry, new_dentry);
nfs_set_verifier(new_dentry, nfs_set_verifier(new_dentry,
nfs_save_change_attribute(new_dir)); nfs_save_change_attribute(new_dir));
......
...@@ -64,11 +64,7 @@ const struct file_operations nfs_file_operations = { ...@@ -64,11 +64,7 @@ const struct file_operations nfs_file_operations = {
.write = do_sync_write, .write = do_sync_write,
.aio_read = nfs_file_read, .aio_read = nfs_file_read,
.aio_write = nfs_file_write, .aio_write = nfs_file_write,
#ifdef CONFIG_MMU
.mmap = nfs_file_mmap, .mmap = nfs_file_mmap,
#else
.mmap = generic_file_mmap,
#endif
.open = nfs_file_open, .open = nfs_file_open,
.flush = nfs_file_flush, .flush = nfs_file_flush,
.release = nfs_file_release, .release = nfs_file_release,
...@@ -141,9 +137,6 @@ nfs_file_release(struct inode *inode, struct file *filp) ...@@ -141,9 +137,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
dentry->d_parent->d_name.name, dentry->d_parent->d_name.name,
dentry->d_name.name); dentry->d_name.name);
/* Ensure that dirty pages are flushed out with the right creds */
if (filp->f_mode & FMODE_WRITE)
nfs_wb_all(dentry->d_inode);
nfs_inc_stats(inode, NFSIOS_VFSRELEASE); nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
return nfs_release(inode, filp); return nfs_release(inode, filp);
} }
...@@ -235,7 +228,6 @@ nfs_file_flush(struct file *file, fl_owner_t id) ...@@ -235,7 +228,6 @@ nfs_file_flush(struct file *file, fl_owner_t id)
struct nfs_open_context *ctx = nfs_file_open_context(file); struct nfs_open_context *ctx = nfs_file_open_context(file);
struct dentry *dentry = file->f_path.dentry; struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int status;
dprintk("NFS: flush(%s/%s)\n", dprintk("NFS: flush(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_parent->d_name.name,
...@@ -245,11 +237,8 @@ nfs_file_flush(struct file *file, fl_owner_t id) ...@@ -245,11 +237,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
return 0; return 0;
nfs_inc_stats(inode, NFSIOS_VFSFLUSH); nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
/* Ensure that data+attribute caches are up to date after close() */ /* Flush writes to the server and return any errors */
status = nfs_do_fsync(ctx, inode); return nfs_do_fsync(ctx, inode);
if (!status)
nfs_revalidate_inode(NFS_SERVER(inode), inode);
return status;
} }
static ssize_t static ssize_t
...@@ -304,11 +293,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -304,11 +293,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
dprintk("NFS: mmap(%s/%s)\n", dprintk("NFS: mmap(%s/%s)\n",
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); /* Note: generic_file_mmap() returns ENOSYS on nommu systems
* so we call that before revalidating the mapping
*/
status = generic_file_mmap(file, vma);
if (!status) { if (!status) {
vma->vm_ops = &nfs_file_vm_ops; vma->vm_ops = &nfs_file_vm_ops;
vma->vm_flags |= VM_CAN_NONLINEAR; status = nfs_revalidate_mapping(inode, file->f_mapping);
file_accessed(file);
} }
return status; return status;
} }
...@@ -354,6 +345,15 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, ...@@ -354,6 +345,15 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
file->f_path.dentry->d_name.name, file->f_path.dentry->d_name.name,
mapping->host->i_ino, len, (long long) pos); mapping->host->i_ino, len, (long long) pos);
/*
* Prevent starvation issues if someone is doing a consistency
* sync-to-disk
*/
ret = wait_on_bit(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
nfs_wait_bit_killable, TASK_KILLABLE);
if (ret)
return ret;
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
......
...@@ -156,7 +156,7 @@ int nfs4_path_walk(struct nfs_server *server, ...@@ -156,7 +156,7 @@ int nfs4_path_walk(struct nfs_server *server,
return ret; return ret;
} }
if (fattr.type != NFDIR) { if (!S_ISDIR(fattr.mode)) {
printk(KERN_ERR "nfs4_get_root:" printk(KERN_ERR "nfs4_get_root:"
" getroot encountered non-directory\n"); " getroot encountered non-directory\n");
return -ENOTDIR; return -ENOTDIR;
...@@ -213,7 +213,7 @@ int nfs4_path_walk(struct nfs_server *server, ...@@ -213,7 +213,7 @@ int nfs4_path_walk(struct nfs_server *server,
return ret; return ret;
} }
if (fattr.type != NFDIR) { if (!S_ISDIR(fattr.mode)) {
printk(KERN_ERR "nfs4_get_root:" printk(KERN_ERR "nfs4_get_root:"
" lookupfh encountered non-directory\n"); " lookupfh encountered non-directory\n");
return -ENOTDIR; return -ENOTDIR;
......
This diff is collapsed.
...@@ -152,6 +152,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); ...@@ -152,6 +152,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[]; extern struct rpc_procinfo nfs4_procedures[];
#endif #endif
/* proc.c */
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
/* dir.c */ /* dir.c */
extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
...@@ -165,6 +168,7 @@ extern void nfs_clear_inode(struct inode *); ...@@ -165,6 +168,7 @@ extern void nfs_clear_inode(struct inode *);
extern void nfs4_clear_inode(struct inode *); extern void nfs4_clear_inode(struct inode *);
#endif #endif
void nfs_zap_acl_cache(struct inode *inode); void nfs_zap_acl_cache(struct inode *inode);
extern int nfs_wait_bit_killable(void *word);
/* super.c */ /* super.c */
void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *); void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
......
...@@ -120,8 +120,8 @@ xdr_decode_time(__be32 *p, struct timespec *timep) ...@@ -120,8 +120,8 @@ xdr_decode_time(__be32 *p, struct timespec *timep)
static __be32 * static __be32 *
xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
{ {
u32 rdev; u32 rdev, type;
fattr->type = (enum nfs_ftype) ntohl(*p++); type = ntohl(*p++);
fattr->mode = ntohl(*p++); fattr->mode = ntohl(*p++);
fattr->nlink = ntohl(*p++); fattr->nlink = ntohl(*p++);
fattr->uid = ntohl(*p++); fattr->uid = ntohl(*p++);
...@@ -136,10 +136,9 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) ...@@ -136,10 +136,9 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
p = xdr_decode_time(p, &fattr->atime); p = xdr_decode_time(p, &fattr->atime);
p = xdr_decode_time(p, &fattr->mtime); p = xdr_decode_time(p, &fattr->mtime);
p = xdr_decode_time(p, &fattr->ctime); p = xdr_decode_time(p, &fattr->ctime);
fattr->valid |= NFS_ATTR_FATTR; fattr->valid |= NFS_ATTR_FATTR_V2;
fattr->rdev = new_decode_dev(rdev); fattr->rdev = new_decode_dev(rdev);
if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) { if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
fattr->type = NFFIFO;
fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
fattr->rdev = 0; fattr->rdev = 0;
} }
......
...@@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.commit_done = nfs3_commit_done, .commit_done = nfs3_commit_done,
.lock = nfs3_proc_lock, .lock = nfs3_proc_lock,
.clear_acl_cache = nfs3_forget_cached_acls, .clear_acl_cache = nfs3_forget_cached_acls,
.close_context = nfs_close_context,
}; };
...@@ -91,19 +91,15 @@ ...@@ -91,19 +91,15 @@
/* /*
* Map file type to S_IFMT bits * Map file type to S_IFMT bits
*/ */
static struct { static const umode_t nfs_type2fmt[] = {
unsigned int mode; [NF3BAD] = 0,
unsigned int nfs2type; [NF3REG] = S_IFREG,
} nfs_type2fmt[] = { [NF3DIR] = S_IFDIR,
{ 0, NFNON }, [NF3BLK] = S_IFBLK,
{ S_IFREG, NFREG }, [NF3CHR] = S_IFCHR,
{ S_IFDIR, NFDIR }, [NF3LNK] = S_IFLNK,
{ S_IFBLK, NFBLK }, [NF3SOCK] = S_IFSOCK,
{ S_IFCHR, NFCHR }, [NF3FIFO] = S_IFIFO,
{ S_IFLNK, NFLNK },
{ S_IFSOCK, NFSOCK },
{ S_IFIFO, NFFIFO },
{ 0, NFBAD }
}; };
/* /*
...@@ -148,13 +144,12 @@ static __be32 * ...@@ -148,13 +144,12 @@ static __be32 *
xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
{ {
unsigned int type, major, minor; unsigned int type, major, minor;
int fmode; umode_t fmode;
type = ntohl(*p++); type = ntohl(*p++);
if (type >= NF3BAD) if (type > NF3FIFO)
type = NF3BAD; type = NF3NON;
fmode = nfs_type2fmt[type].mode; fmode = nfs_type2fmt[type];
fattr->type = nfs_type2fmt[type].nfs2type;
fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode; fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
fattr->nlink = ntohl(*p++); fattr->nlink = ntohl(*p++);
fattr->uid = ntohl(*p++); fattr->uid = ntohl(*p++);
...@@ -177,7 +172,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr) ...@@ -177,7 +172,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
p = xdr_decode_time3(p, &fattr->ctime); p = xdr_decode_time3(p, &fattr->ctime);
/* Update the mode bits */ /* Update the mode bits */
fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3); fattr->valid |= NFS_ATTR_FATTR_V3;
return p; return p;
} }
...@@ -233,7 +228,9 @@ xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr) ...@@ -233,7 +228,9 @@ xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
p = xdr_decode_hyper(p, &fattr->pre_size); p = xdr_decode_hyper(p, &fattr->pre_size);
p = xdr_decode_time3(p, &fattr->pre_mtime); p = xdr_decode_time3(p, &fattr->pre_mtime);
p = xdr_decode_time3(p, &fattr->pre_ctime); p = xdr_decode_time3(p, &fattr->pre_ctime);
fattr->valid |= NFS_ATTR_WCC; fattr->valid |= NFS_ATTR_FATTR_PRESIZE
| NFS_ATTR_FATTR_PREMTIME
| NFS_ATTR_FATTR_PRECTIME;
return p; return p;
} }
......
...@@ -193,14 +193,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent ...@@ -193,14 +193,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
kunmap_atomic(start, KM_USER0); kunmap_atomic(start, KM_USER0);
} }
static int nfs4_wait_bit_killable(void *word)
{
if (fatal_signal_pending(current))
return -ERESTARTSYS;
schedule();
return 0;
}
static int nfs4_wait_clnt_recover(struct nfs_client *clp) static int nfs4_wait_clnt_recover(struct nfs_client *clp)
{ {
int res; int res;
...@@ -208,7 +200,7 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp) ...@@ -208,7 +200,7 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp)
might_sleep(); might_sleep();
res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING, res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
nfs4_wait_bit_killable, TASK_KILLABLE); nfs_wait_bit_killable, TASK_KILLABLE);
return res; return res;
} }
...@@ -1439,7 +1431,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) ...@@ -1439,7 +1431,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
if (calldata->arg.seqid == NULL) if (calldata->arg.seqid == NULL)
goto out_free_calldata; goto out_free_calldata;
calldata->arg.fmode = 0; calldata->arg.fmode = 0;
calldata->arg.bitmask = server->attr_bitmask; calldata->arg.bitmask = server->cache_consistency_bitmask;
calldata->res.fattr = &calldata->fattr; calldata->res.fattr = &calldata->fattr;
calldata->res.seqid = calldata->arg.seqid; calldata->res.seqid = calldata->arg.seqid;
calldata->res.server = server; calldata->res.server = server;
...@@ -1580,6 +1572,15 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st ...@@ -1580,6 +1572,15 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
return 0; return 0;
} }
void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
{
if (ctx->state == NULL)
return;
if (is_sync)
nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
else
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
}
static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{ {
...@@ -1600,6 +1601,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f ...@@ -1600,6 +1601,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
server->caps |= NFS_CAP_HARDLINKS; server->caps |= NFS_CAP_HARDLINKS;
if (res.has_symlinks != 0) if (res.has_symlinks != 0)
server->caps |= NFS_CAP_SYMLINKS; server->caps |= NFS_CAP_SYMLINKS;
memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
server->acl_bitmask = res.acl_bitmask; server->acl_bitmask = res.acl_bitmask;
} }
return status; return status;
...@@ -2079,7 +2083,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) ...@@ -2079,7 +2083,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
struct nfs_removeargs *args = msg->rpc_argp; struct nfs_removeargs *args = msg->rpc_argp;
struct nfs_removeres *res = msg->rpc_resp; struct nfs_removeres *res = msg->rpc_resp;
args->bitmask = server->attr_bitmask; args->bitmask = server->cache_consistency_bitmask;
res->server = server; res->server = server;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
} }
...@@ -2323,7 +2327,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -2323,7 +2327,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
.pages = &page, .pages = &page,
.pgbase = 0, .pgbase = 0,
.count = count, .count = count,
.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, .bitmask = NFS_SERVER(dentry->d_inode)->cache_consistency_bitmask,
}; };
struct nfs4_readdir_res res; struct nfs4_readdir_res res;
struct rpc_message msg = { struct rpc_message msg = {
...@@ -2552,7 +2556,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag ...@@ -2552,7 +2556,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
{ {
struct nfs_server *server = NFS_SERVER(data->inode); struct nfs_server *server = NFS_SERVER(data->inode);
data->args.bitmask = server->attr_bitmask; data->args.bitmask = server->cache_consistency_bitmask;
data->res.server = server; data->res.server = server;
data->timestamp = jiffies; data->timestamp = jiffies;
...@@ -2575,7 +2579,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa ...@@ -2575,7 +2579,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
{ {
struct nfs_server *server = NFS_SERVER(data->inode); struct nfs_server *server = NFS_SERVER(data->inode);
data->args.bitmask = server->attr_bitmask; data->args.bitmask = server->cache_consistency_bitmask;
data->res.server = server; data->res.server = server;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
} }
...@@ -3678,6 +3682,19 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) ...@@ -3678,6 +3682,19 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
return len; return len;
} }
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
{
if (!((fattr->valid & NFS_ATTR_FATTR_FILEID) &&
(fattr->valid & NFS_ATTR_FATTR_FSID) &&
(fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
return;
fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
NFS_ATTR_FATTR_NLINK;
fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
fattr->nlink = 2;
}
int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page) struct nfs4_fs_locations *fs_locations, struct page *page)
{ {
...@@ -3704,6 +3721,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, ...@@ -3704,6 +3721,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
fs_locations->server = server; fs_locations->server = server;
fs_locations->nlocations = 0; fs_locations->nlocations = 0;
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, 0);
nfs_fixup_referral_attributes(&fs_locations->fattr);
dprintk("%s: returned status = %d\n", __func__, status); dprintk("%s: returned status = %d\n", __func__, status);
return status; return status;
} }
...@@ -3767,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { ...@@ -3767,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.commit_done = nfs4_commit_done, .commit_done = nfs4_commit_done,
.lock = nfs4_proc_lock, .lock = nfs4_proc_lock,
.clear_acl_cache = nfs4_zap_acl_attr, .clear_acl_cache = nfs4_zap_acl_attr,
.close_context = nfs4_close_context,
}; };
/* /*
......
...@@ -62,8 +62,14 @@ static LIST_HEAD(nfs4_clientid_list); ...@@ -62,8 +62,14 @@ static LIST_HEAD(nfs4_clientid_list);
static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
{ {
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, unsigned short port;
nfs_callback_tcpport, cred); int status;
port = nfs_callback_tcpport;
if (clp->cl_addr.ss_family == AF_INET6)
port = nfs_callback_tcpport6;
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred);
if (status == 0) if (status == 0)
status = nfs4_proc_setclientid_confirm(clp, cred); status = nfs4_proc_setclientid_confirm(clp, cred);
if (status == 0) if (status == 0)
......
This diff is collapsed.
...@@ -176,17 +176,6 @@ void nfs_release_request(struct nfs_page *req) ...@@ -176,17 +176,6 @@ void nfs_release_request(struct nfs_page *req)
kref_put(&req->wb_kref, nfs_free_request); kref_put(&req->wb_kref, nfs_free_request);
} }
static int nfs_wait_bit_killable(void *word)
{
int ret = 0;
if (fatal_signal_pending(current))
ret = -ERESTARTSYS;
else
schedule();
return ret;
}
/** /**
* nfs_wait_on_request - Wait for a request to complete. * nfs_wait_on_request - Wait for a request to complete.
* @req: request to wait upon. * @req: request to wait upon.
......
...@@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.commit_setup = nfs_proc_commit_setup, .commit_setup = nfs_proc_commit_setup,
.lock = nfs_proc_lock, .lock = nfs_proc_lock,
.lock_check_bounds = nfs_lock_check_bounds, .lock_check_bounds = nfs_lock_check_bounds,
.close_context = nfs_close_context,
}; };
...@@ -1018,6 +1018,7 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1018,6 +1018,7 @@ static int nfs_parse_mount_options(char *raw,
case Opt_rdma: case Opt_rdma:
mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */ mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(p);
break; break;
case Opt_acl: case Opt_acl:
mnt->flags &= ~NFS_MOUNT_NOACL; mnt->flags &= ~NFS_MOUNT_NOACL;
...@@ -1205,12 +1206,14 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1205,12 +1206,14 @@ static int nfs_parse_mount_options(char *raw,
/* vector side protocols to TCP */ /* vector side protocols to TCP */
mnt->flags |= NFS_MOUNT_TCP; mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(string);
break; break;
default: default:
errors++; errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"transport protocol\n"); "transport protocol\n");
} }
kfree(string);
break; break;
case Opt_mountproto: case Opt_mountproto:
string = match_strdup(args); string = match_strdup(args);
...@@ -1218,7 +1221,6 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1218,7 +1221,6 @@ static int nfs_parse_mount_options(char *raw,
goto out_nomem; goto out_nomem;
token = match_token(string, token = match_token(string,
nfs_xprt_protocol_tokens, args); nfs_xprt_protocol_tokens, args);
kfree(string);
switch (token) { switch (token) {
case Opt_xprt_udp: case Opt_xprt_udp:
......
...@@ -313,19 +313,34 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control * ...@@ -313,19 +313,34 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
unsigned long *bitlock = &NFS_I(inode)->flags;
struct nfs_pageio_descriptor pgio; struct nfs_pageio_descriptor pgio;
int err; int err;
/* Stop dirtying of new pages while we sync */
err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING,
nfs_wait_bit_killable, TASK_KILLABLE);
if (err)
goto out_err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
nfs_pageio_complete(&pgio); nfs_pageio_complete(&pgio);
clear_bit_unlock(NFS_INO_FLUSHING, bitlock);
smp_mb__after_clear_bit();
wake_up_bit(bitlock, NFS_INO_FLUSHING);
if (err < 0) if (err < 0)
return err; goto out_err;
if (pgio.pg_error < 0) err = pgio.pg_error;
return pgio.pg_error; if (err < 0)
goto out_err;
return 0; return 0;
out_err:
return err;
} }
/* /*
...@@ -404,7 +419,6 @@ nfs_mark_request_commit(struct nfs_page *req) ...@@ -404,7 +419,6 @@ nfs_mark_request_commit(struct nfs_page *req)
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfsi->ncommit++;
set_bit(PG_CLEAN, &(req)->wb_flags); set_bit(PG_CLEAN, &(req)->wb_flags);
radix_tree_tag_set(&nfsi->nfs_page_tree, radix_tree_tag_set(&nfsi->nfs_page_tree,
req->wb_index, req->wb_index,
...@@ -524,6 +538,12 @@ static void nfs_cancel_commit_list(struct list_head *head) ...@@ -524,6 +538,12 @@ static void nfs_cancel_commit_list(struct list_head *head)
} }
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
static int
nfs_need_commit(struct nfs_inode *nfsi)
{
return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
}
/* /*
* nfs_scan_commit - Scan an inode for commit requests * nfs_scan_commit - Scan an inode for commit requests
* @inode: NFS inode to scan * @inode: NFS inode to scan
...@@ -538,16 +558,18 @@ static int ...@@ -538,16 +558,18 @@ static int
nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
int res = 0;
if (nfsi->ncommit != 0) { if (!nfs_need_commit(nfsi))
res = nfs_scan_list(nfsi, dst, idx_start, npages, return 0;
NFS_PAGE_TAG_COMMIT);
nfsi->ncommit -= res; return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
}
return res;
} }
#else #else
static inline int nfs_need_commit(struct nfs_inode *nfsi)
{
return 0;
}
static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
{ {
return 0; return 0;
...@@ -820,7 +842,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, ...@@ -820,7 +842,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
data->args.stable = NFS_UNSTABLE; data->args.stable = NFS_UNSTABLE;
if (how & FLUSH_STABLE) { if (how & FLUSH_STABLE) {
data->args.stable = NFS_DATA_SYNC; data->args.stable = NFS_DATA_SYNC;
if (!NFS_I(inode)->ncommit) if (!nfs_need_commit(NFS_I(inode)))
data->args.stable = NFS_FILE_SYNC; data->args.stable = NFS_FILE_SYNC;
} }
...@@ -1425,18 +1447,13 @@ static int nfs_write_mapping(struct address_space *mapping, int how) ...@@ -1425,18 +1447,13 @@ static int nfs_write_mapping(struct address_space *mapping, int how)
{ {
struct writeback_control wbc = { struct writeback_control wbc = {
.bdi = mapping->backing_dev_info, .bdi = mapping->backing_dev_info,
.sync_mode = WB_SYNC_NONE, .sync_mode = WB_SYNC_ALL,
.nr_to_write = LONG_MAX, .nr_to_write = LONG_MAX,
.range_start = 0, .range_start = 0,
.range_end = LLONG_MAX, .range_end = LLONG_MAX,
.for_writepages = 1, .for_writepages = 1,
}; };
int ret;
ret = __nfs_write_mapping(mapping, &wbc, how);
if (ret < 0)
return ret;
wbc.sync_mode = WB_SYNC_ALL;
return __nfs_write_mapping(mapping, &wbc, how); return __nfs_write_mapping(mapping, &wbc, how);
} }
......
...@@ -938,10 +938,12 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) ...@@ -938,10 +938,12 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
char transport[16]; char transport[16];
int port; int port;
if (sscanf(buf, "%15s %4d", transport, &port) == 2) { if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
if (port < 1 || port > 65535)
return -EINVAL;
err = nfsd_create_serv(); err = nfsd_create_serv();
if (!err) { if (!err) {
err = svc_create_xprt(nfsd_serv, err = svc_create_xprt(nfsd_serv,
transport, port, transport, PF_INET, port,
SVC_SOCK_ANONYMOUS); SVC_SOCK_ANONYMOUS);
if (err == -ENOENT) if (err == -ENOENT)
/* Give a reasonable perror msg for /* Give a reasonable perror msg for
...@@ -960,7 +962,7 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) ...@@ -960,7 +962,7 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
char transport[16]; char transport[16];
int port; int port;
if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
if (port == 0) if (port < 1 || port > 65535)
return -EINVAL; return -EINVAL;
if (nfsd_serv) { if (nfsd_serv) {
xprt = svc_find_xprt(nfsd_serv, transport, xprt = svc_find_xprt(nfsd_serv, transport,
......
...@@ -229,7 +229,6 @@ int nfsd_create_serv(void) ...@@ -229,7 +229,6 @@ int nfsd_create_serv(void)
atomic_set(&nfsd_busy, 0); atomic_set(&nfsd_busy, 0);
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
AF_INET,
nfsd_last_thread, nfsd, THIS_MODULE); nfsd_last_thread, nfsd, THIS_MODULE);
if (nfsd_serv == NULL) if (nfsd_serv == NULL)
err = -ENOMEM; err = -ENOMEM;
...@@ -244,7 +243,7 @@ static int nfsd_init_socks(int port) ...@@ -244,7 +243,7 @@ static int nfsd_init_socks(int port)
if (!list_empty(&nfsd_serv->sv_permsocks)) if (!list_empty(&nfsd_serv->sv_permsocks))
return 0; return 0;
error = svc_create_xprt(nfsd_serv, "udp", port, error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port,
SVC_SOCK_DEFAULTS); SVC_SOCK_DEFAULTS);
if (error < 0) if (error < 0)
return error; return error;
...@@ -253,7 +252,7 @@ static int nfsd_init_socks(int port) ...@@ -253,7 +252,7 @@ static int nfsd_init_socks(int port)
if (error < 0) if (error < 0)
return error; return error;
error = svc_create_xprt(nfsd_serv, "tcp", port, error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port,
SVC_SOCK_DEFAULTS); SVC_SOCK_DEFAULTS);
if (error < 0) if (error < 0)
return error; return error;
......
...@@ -166,8 +166,7 @@ struct nfs_inode { ...@@ -166,8 +166,7 @@ struct nfs_inode {
*/ */
struct radix_tree_root nfs_page_tree; struct radix_tree_root nfs_page_tree;
unsigned long ncommit, unsigned long npages;
npages;
/* Open contexts for shared mmap writes */ /* Open contexts for shared mmap writes */
struct list_head open_files; struct list_head open_files;
...@@ -207,6 +206,7 @@ struct nfs_inode { ...@@ -207,6 +206,7 @@ struct nfs_inode {
#define NFS_INO_STALE (1) /* possible stale inode */ #define NFS_INO_STALE (1) /* possible stale inode */
#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */ #define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
static inline struct nfs_inode *NFS_I(const struct inode *inode) static inline struct nfs_inode *NFS_I(const struct inode *inode)
{ {
......
...@@ -106,6 +106,11 @@ struct nfs_server { ...@@ -106,6 +106,11 @@ struct nfs_server {
u32 attr_bitmask[2];/* V4 bitmask representing the set u32 attr_bitmask[2];/* V4 bitmask representing the set
of attributes supported on this of attributes supported on this
filesystem */ filesystem */
u32 cache_consistency_bitmask[2];
/* V4 bitmask representing the subset
of change attribute, size, ctime
and mtime attributes supported by
the server */
u32 acl_bitmask; /* V4 bitmask representing the ACEs u32 acl_bitmask; /* V4 bitmask representing the ACEs
that are supported on this that are supported on this
filesystem */ filesystem */
......
...@@ -27,12 +27,8 @@ static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid ...@@ -27,12 +27,8 @@ static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid
} }
struct nfs_fattr { struct nfs_fattr {
unsigned short valid; /* which fields are valid */ unsigned int valid; /* which fields are valid */
__u64 pre_size; /* pre_op_attr.size */ umode_t mode;
struct timespec pre_mtime; /* pre_op_attr.mtime */
struct timespec pre_ctime; /* pre_op_attr.ctime */
enum nfs_ftype type; /* always use NFSv2 types */
__u32 mode;
__u32 nlink; __u32 nlink;
__u32 uid; __u32 uid;
__u32 gid; __u32 gid;
...@@ -52,19 +48,55 @@ struct nfs_fattr { ...@@ -52,19 +48,55 @@ struct nfs_fattr {
struct timespec atime; struct timespec atime;
struct timespec mtime; struct timespec mtime;
struct timespec ctime; struct timespec ctime;
__u32 bitmap[2]; /* NFSv4 returned attribute bitmap */
__u64 change_attr; /* NFSv4 change attribute */ __u64 change_attr; /* NFSv4 change attribute */
__u64 pre_change_attr;/* pre-op NFSv4 change attribute */ __u64 pre_change_attr;/* pre-op NFSv4 change attribute */
__u64 pre_size; /* pre_op_attr.size */
struct timespec pre_mtime; /* pre_op_attr.mtime */
struct timespec pre_ctime; /* pre_op_attr.ctime */
unsigned long time_start; unsigned long time_start;
unsigned long gencount; unsigned long gencount;
}; };
#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */ #define NFS_ATTR_FATTR_TYPE (1U << 0)
#define NFS_ATTR_FATTR 0x0002 /* post-op attributes */ #define NFS_ATTR_FATTR_MODE (1U << 1)
#define NFS_ATTR_FATTR_V3 0x0004 /* NFSv3 attributes */ #define NFS_ATTR_FATTR_NLINK (1U << 2)
#define NFS_ATTR_FATTR_V4 0x0008 /* NFSv4 change attribute */ #define NFS_ATTR_FATTR_OWNER (1U << 3)
#define NFS_ATTR_WCC_V4 0x0010 /* pre-op change attribute */ #define NFS_ATTR_FATTR_GROUP (1U << 4)
#define NFS_ATTR_FATTR_V4_REFERRAL 0x0020 /* NFSv4 referral */ #define NFS_ATTR_FATTR_RDEV (1U << 5)
#define NFS_ATTR_FATTR_SIZE (1U << 6)
#define NFS_ATTR_FATTR_PRESIZE (1U << 7)
#define NFS_ATTR_FATTR_BLOCKS_USED (1U << 8)
#define NFS_ATTR_FATTR_SPACE_USED (1U << 9)
#define NFS_ATTR_FATTR_FSID (1U << 10)
#define NFS_ATTR_FATTR_FILEID (1U << 11)
#define NFS_ATTR_FATTR_ATIME (1U << 12)
#define NFS_ATTR_FATTR_MTIME (1U << 13)
#define NFS_ATTR_FATTR_CTIME (1U << 14)
#define NFS_ATTR_FATTR_PREMTIME (1U << 15)
#define NFS_ATTR_FATTR_PRECTIME (1U << 16)
#define NFS_ATTR_FATTR_CHANGE (1U << 17)
#define NFS_ATTR_FATTR_PRECHANGE (1U << 18)
#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
| NFS_ATTR_FATTR_MODE \
| NFS_ATTR_FATTR_NLINK \
| NFS_ATTR_FATTR_OWNER \
| NFS_ATTR_FATTR_GROUP \
| NFS_ATTR_FATTR_RDEV \
| NFS_ATTR_FATTR_SIZE \
| NFS_ATTR_FATTR_FSID \
| NFS_ATTR_FATTR_FILEID \
| NFS_ATTR_FATTR_ATIME \
| NFS_ATTR_FATTR_MTIME \
| NFS_ATTR_FATTR_CTIME)
#define NFS_ATTR_FATTR_V2 (NFS_ATTR_FATTR \
| NFS_ATTR_FATTR_BLOCKS_USED)
#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
| NFS_ATTR_FATTR_SPACE_USED)
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
| NFS_ATTR_FATTR_SPACE_USED \
| NFS_ATTR_FATTR_CHANGE)
/* /*
* Info on the file system * Info on the file system
...@@ -836,6 +868,7 @@ struct nfs_rpc_ops { ...@@ -836,6 +868,7 @@ struct nfs_rpc_ops {
int (*lock)(struct file *, int, struct file_lock *); int (*lock)(struct file *, int, struct file_lock *);
int (*lock_check_bounds)(const struct file_lock *); int (*lock_check_bounds)(const struct file_lock *);
void (*clear_acl_cache)(struct inode *); void (*clear_acl_cache)(struct inode *);
void (*close_context)(struct nfs_open_context *ctx, int);
}; };
/* /*
......
...@@ -69,7 +69,6 @@ struct svc_serv { ...@@ -69,7 +69,6 @@ struct svc_serv {
struct list_head sv_tempsocks; /* all temporary sockets */ struct list_head sv_tempsocks; /* all temporary sockets */
int sv_tmpcnt; /* count of temporary sockets */ int sv_tmpcnt; /* count of temporary sockets */
struct timer_list sv_temptimer; /* timer for aging temporary sockets */ struct timer_list sv_temptimer; /* timer for aging temporary sockets */
sa_family_t sv_family; /* listener's address family */
char * sv_name; /* service name */ char * sv_name; /* service name */
...@@ -385,19 +384,19 @@ struct svc_procedure { ...@@ -385,19 +384,19 @@ struct svc_procedure {
/* /*
* Function prototypes. * Function prototypes.
*/ */
struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t, struct svc_serv *svc_create(struct svc_program *, unsigned int,
void (*shutdown)(struct svc_serv *)); void (*shutdown)(struct svc_serv *));
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
struct svc_pool *pool); struct svc_pool *pool);
void svc_exit_thread(struct svc_rqst *); void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
sa_family_t, void (*shutdown)(struct svc_serv *), void (*shutdown)(struct svc_serv *),
svc_thread_fn, struct module *); svc_thread_fn, struct module *);
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
void svc_destroy(struct svc_serv *); void svc_destroy(struct svc_serv *);
int svc_process(struct svc_rqst *); int svc_process(struct svc_rqst *);
int svc_register(const struct svc_serv *, const unsigned short, int svc_register(const struct svc_serv *, const int,
const unsigned short); const unsigned short, const unsigned short);
void svc_wake_up(struct svc_serv *); void svc_wake_up(struct svc_serv *);
void svc_reserve(struct svc_rqst *rqstp, int space); void svc_reserve(struct svc_rqst *rqstp, int space);
......
...@@ -71,7 +71,8 @@ int svc_reg_xprt_class(struct svc_xprt_class *); ...@@ -71,7 +71,8 @@ int svc_reg_xprt_class(struct svc_xprt_class *);
void svc_unreg_xprt_class(struct svc_xprt_class *); void svc_unreg_xprt_class(struct svc_xprt_class *);
void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *, void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
struct svc_serv *); struct svc_serv *);
int svc_create_xprt(struct svc_serv *, char *, unsigned short, int); int svc_create_xprt(struct svc_serv *, const char *, const int,
const unsigned short, int);
void svc_xprt_enqueue(struct svc_xprt *xprt); void svc_xprt_enqueue(struct svc_xprt *xprt);
void svc_xprt_received(struct svc_xprt *); void svc_xprt_received(struct svc_xprt *);
void svc_xprt_put(struct svc_xprt *xprt); void svc_xprt_put(struct svc_xprt *xprt);
...@@ -80,7 +81,8 @@ void svc_close_xprt(struct svc_xprt *xprt); ...@@ -80,7 +81,8 @@ void svc_close_xprt(struct svc_xprt *xprt);
void svc_delete_xprt(struct svc_xprt *xprt); void svc_delete_xprt(struct svc_xprt *xprt);
int svc_port_is_privileged(struct sockaddr *sin); int svc_port_is_privileged(struct sockaddr *sin);
int svc_print_xprts(char *buf, int maxlen); int svc_print_xprts(char *buf, int maxlen);
struct svc_xprt *svc_find_xprt(struct svc_serv *, char *, int, int); struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
const sa_family_t af, const unsigned short port);
int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen); int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
static inline void svc_xprt_get(struct svc_xprt *xprt) static inline void svc_xprt_get(struct svc_xprt *xprt)
...@@ -88,29 +90,32 @@ static inline void svc_xprt_get(struct svc_xprt *xprt) ...@@ -88,29 +90,32 @@ static inline void svc_xprt_get(struct svc_xprt *xprt)
kref_get(&xprt->xpt_ref); kref_get(&xprt->xpt_ref);
} }
static inline void svc_xprt_set_local(struct svc_xprt *xprt, static inline void svc_xprt_set_local(struct svc_xprt *xprt,
struct sockaddr *sa, int salen) const struct sockaddr *sa,
const size_t salen)
{ {
memcpy(&xprt->xpt_local, sa, salen); memcpy(&xprt->xpt_local, sa, salen);
xprt->xpt_locallen = salen; xprt->xpt_locallen = salen;
} }
static inline void svc_xprt_set_remote(struct svc_xprt *xprt, static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
struct sockaddr *sa, int salen) const struct sockaddr *sa,
const size_t salen)
{ {
memcpy(&xprt->xpt_remote, sa, salen); memcpy(&xprt->xpt_remote, sa, salen);
xprt->xpt_remotelen = salen; xprt->xpt_remotelen = salen;
} }
static inline unsigned short svc_addr_port(struct sockaddr *sa) static inline unsigned short svc_addr_port(const struct sockaddr *sa)
{ {
unsigned short ret = 0; const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
switch (sa->sa_family) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
ret = ntohs(((struct sockaddr_in *)sa)->sin_port); return ntohs(sin->sin_port);
break;
case AF_INET6: case AF_INET6:
ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); return ntohs(sin6->sin6_port);
break;
} }
return ret;
return 0;
} }
static inline size_t svc_addr_len(struct sockaddr *sa) static inline size_t svc_addr_len(struct sockaddr *sa)
...@@ -124,36 +129,39 @@ static inline size_t svc_addr_len(struct sockaddr *sa) ...@@ -124,36 +129,39 @@ static inline size_t svc_addr_len(struct sockaddr *sa)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
} }
static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt) static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt)
{ {
return svc_addr_port((struct sockaddr *)&xprt->xpt_local); return svc_addr_port((const struct sockaddr *)&xprt->xpt_local);
} }
static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt) static inline unsigned short svc_xprt_remote_port(const struct svc_xprt *xprt)
{ {
return svc_addr_port((struct sockaddr *)&xprt->xpt_remote); return svc_addr_port((const struct sockaddr *)&xprt->xpt_remote);
} }
static inline char *__svc_print_addr(struct sockaddr *addr, static inline char *__svc_print_addr(const struct sockaddr *addr,
char *buf, size_t len) char *buf, const size_t len)
{ {
const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
switch (addr->sa_family) { switch (addr->sa_family) {
case AF_INET: case AF_INET:
snprintf(buf, len, "%pI4, port=%u", snprintf(buf, len, "%pI4, port=%u", &sin->sin_addr,
&((struct sockaddr_in *)addr)->sin_addr, ntohs(sin->sin_port));
ntohs(((struct sockaddr_in *) addr)->sin_port));
break; break;
case AF_INET6: case AF_INET6:
snprintf(buf, len, "%pI6, port=%u", snprintf(buf, len, "%pI6, port=%u",
&((struct sockaddr_in6 *)addr)->sin6_addr, &sin6->sin6_addr,
ntohs(((struct sockaddr_in6 *) addr)->sin6_port)); ntohs(sin6->sin6_port));
break; break;
default: default:
snprintf(buf, len, "unknown address type: %d", addr->sa_family); snprintf(buf, len, "unknown address type: %d", addr->sa_family);
break; break;
} }
return buf; return buf;
} }
#endif /* SUNRPC_SVC_XPRT_H */ #endif /* SUNRPC_SVC_XPRT_H */
...@@ -235,6 +235,7 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 * ...@@ -235,6 +235,7 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *
*/ */
int xprt_register_transport(struct xprt_class *type); int xprt_register_transport(struct xprt_class *type);
int xprt_unregister_transport(struct xprt_class *type); int xprt_unregister_transport(struct xprt_class *type);
int xprt_load_transport(const char *);
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);
...@@ -259,6 +260,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); ...@@ -259,6 +260,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
#define XPRT_BOUND (4) #define XPRT_BOUND (4)
#define XPRT_BINDING (5) #define XPRT_BINDING (5)
#define XPRT_CLOSING (6) #define XPRT_CLOSING (6)
#define XPRT_CONNECTION_ABORT (7)
static inline void xprt_set_connected(struct rpc_xprt *xprt) static inline void xprt_set_connected(struct rpc_xprt *xprt)
{ {
......
...@@ -17,28 +17,6 @@ config SUNRPC_XPRT_RDMA ...@@ -17,28 +17,6 @@ config SUNRPC_XPRT_RDMA
If unsure, say N. If unsure, say N.
config SUNRPC_REGISTER_V4
bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
default n
help
Sun added support for registering RPC services at an IPv6
address by creating two new versions of the rpcbind protocol
(RFC 1833).
This option enables support in the kernel RPC server for
registering kernel RPC services via version 4 of the rpcbind
protocol. If you enable this option, you must run a portmapper
daemon that supports rpcbind protocol version 4.
Serving NFS over IPv6 from knfsd (the kernel's NFS server)
requires that you enable this option and use a portmapper that
supports rpcbind version 4.
If unsure, say N to get traditional behavior (register kernel
RPC services using only rpcbind version 2). Distributions
using the legacy Linux portmapper daemon must say N here.
config RPCSEC_GSS_KRB5 config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL depends on SUNRPC && EXPERIMENTAL
......
...@@ -1032,27 +1032,20 @@ call_connect_status(struct rpc_task *task) ...@@ -1032,27 +1032,20 @@ call_connect_status(struct rpc_task *task)
dprint_status(task); dprint_status(task);
task->tk_status = 0; task->tk_status = 0;
if (status >= 0) { if (status >= 0 || status == -EAGAIN) {
clnt->cl_stats->netreconn++; clnt->cl_stats->netreconn++;
task->tk_action = call_transmit; task->tk_action = call_transmit;
return; return;
} }
/* Something failed: remote service port may have changed */
rpc_force_rebind(clnt);
switch (status) { switch (status) {
case -ENOTCONN:
case -EAGAIN:
task->tk_action = call_bind;
if (!RPC_IS_SOFT(task))
return;
/* if soft mounted, test if we've timed out */ /* if soft mounted, test if we've timed out */
case -ETIMEDOUT: case -ETIMEDOUT:
task->tk_action = call_timeout; task->tk_action = call_timeout;
return; break;
default:
rpc_exit(task, -EIO);
} }
rpc_exit(task, -EIO);
} }
/* /*
...@@ -1105,14 +1098,26 @@ static void ...@@ -1105,14 +1098,26 @@ static void
call_transmit_status(struct rpc_task *task) call_transmit_status(struct rpc_task *task)
{ {
task->tk_action = call_status; task->tk_action = call_status;
/* switch (task->tk_status) {
* Special case: if we've been waiting on the socket's write_space() case -EAGAIN:
* callback, then don't call xprt_end_transmit(). break;
*/ default:
if (task->tk_status == -EAGAIN) xprt_end_transmit(task);
return; /*
xprt_end_transmit(task); * Special cases: if we've been waiting on the
rpc_task_force_reencode(task); * socket's write_space() callback, or if the
* socket just returned a connection error,
* then hold onto the transport lock.
*/
case -ECONNREFUSED:
case -ECONNRESET:
case -ENOTCONN:
case -EHOSTDOWN:
case -EHOSTUNREACH:
case -ENETUNREACH:
case -EPIPE:
rpc_task_force_reencode(task);
}
} }
/* /*
...@@ -1152,9 +1157,12 @@ call_status(struct rpc_task *task) ...@@ -1152,9 +1157,12 @@ call_status(struct rpc_task *task)
xprt_conditional_disconnect(task->tk_xprt, xprt_conditional_disconnect(task->tk_xprt,
req->rq_connect_cookie); req->rq_connect_cookie);
break; break;
case -ECONNRESET:
case -ECONNREFUSED: case -ECONNREFUSED:
case -ENOTCONN:
rpc_force_rebind(clnt); rpc_force_rebind(clnt);
rpc_delay(task, 3*HZ);
case -EPIPE:
case -ENOTCONN:
task->tk_action = call_bind; task->tk_action = call_bind;
break; break;
case -EAGAIN: case -EAGAIN:
......
...@@ -63,9 +63,16 @@ enum { ...@@ -63,9 +63,16 @@ enum {
* r_owner * r_owner
* *
* The "owner" is allowed to unset a service in the rpcbind database. * The "owner" is allowed to unset a service in the rpcbind database.
* We always use the following (arbitrary) fixed string. *
* For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a
* UID which it maps to a local user name via a password lookup.
* In all other cases it is ignored.
*
* For SET/UNSET requests, user space provides a value, even for
* network requests, and GETADDR uses an empty string. We follow
* those precedents here.
*/ */
#define RPCB_OWNER_STRING "rpcb" #define RPCB_OWNER_STRING "0"
#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 *);
...@@ -124,12 +131,6 @@ static const struct sockaddr_in rpcb_inaddr_loopback = { ...@@ -124,12 +131,6 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
.sin_port = htons(RPCBIND_PORT), .sin_port = htons(RPCBIND_PORT),
}; };
static const struct sockaddr_in6 rpcb_in6addr_loopback = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
.sin6_port = htons(RPCBIND_PORT),
};
static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr, static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
size_t addrlen, u32 version) size_t addrlen, u32 version)
{ {
...@@ -176,9 +177,10 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, ...@@ -176,9 +177,10 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
return rpc_create(&args); return rpc_create(&args);
} }
static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, static int rpcb_register_call(const u32 version, struct rpc_message *msg)
u32 version, struct rpc_message *msg)
{ {
struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback;
size_t addrlen = sizeof(rpcb_inaddr_loopback);
struct rpc_clnt *rpcb_clnt; struct rpc_clnt *rpcb_clnt;
int result, error = 0; int result, error = 0;
...@@ -192,7 +194,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, ...@@ -192,7 +194,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
error = PTR_ERR(rpcb_clnt); error = PTR_ERR(rpcb_clnt);
if (error < 0) { if (error < 0) {
printk(KERN_WARNING "RPC: failed to contact local rpcbind " dprintk("RPC: failed to contact local rpcbind "
"server (errno %d).\n", -error); "server (errno %d).\n", -error);
return error; return error;
} }
...@@ -254,25 +256,23 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) ...@@ -254,25 +256,23 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
if (port) if (port)
msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, return rpcb_register_call(RPCBVERS_2, &msg);
sizeof(rpcb_inaddr_loopback),
RPCBVERS_2, &msg);
} }
/* /*
* Fill in AF_INET family-specific arguments to register * Fill in AF_INET family-specific arguments to register
*/ */
static int rpcb_register_netid4(struct sockaddr_in *address_to_register, static int rpcb_register_inet4(const struct sockaddr *sap,
struct rpc_message *msg) struct rpc_message *msg)
{ {
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
struct rpcbind_args *map = msg->rpc_argp; struct rpcbind_args *map = msg->rpc_argp;
unsigned short port = ntohs(address_to_register->sin_port); unsigned short port = ntohs(sin->sin_port);
char buf[32]; char buf[32];
/* Construct AF_INET universal address */ /* Construct AF_INET universal address */
snprintf(buf, sizeof(buf), "%pI4.%u.%u", snprintf(buf, sizeof(buf), "%pI4.%u.%u",
&address_to_register->sin_addr.s_addr, &sin->sin_addr.s_addr, port >> 8, port & 0xff);
port >> 8, port & 0xff);
map->r_addr = buf; map->r_addr = buf;
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
...@@ -284,29 +284,27 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register, ...@@ -284,29 +284,27 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
if (port) if (port)
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, return rpcb_register_call(RPCBVERS_4, msg);
sizeof(rpcb_inaddr_loopback),
RPCBVERS_4, msg);
} }
/* /*
* Fill in AF_INET6 family-specific arguments to register * Fill in AF_INET6 family-specific arguments to register
*/ */
static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, static int rpcb_register_inet6(const struct sockaddr *sap,
struct rpc_message *msg) struct rpc_message *msg)
{ {
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
struct rpcbind_args *map = msg->rpc_argp; struct rpcbind_args *map = msg->rpc_argp;
unsigned short port = ntohs(address_to_register->sin6_port); unsigned short port = ntohs(sin6->sin6_port);
char buf[64]; char buf[64];
/* Construct AF_INET6 universal address */ /* Construct AF_INET6 universal address */
if (ipv6_addr_any(&address_to_register->sin6_addr)) if (ipv6_addr_any(&sin6->sin6_addr))
snprintf(buf, sizeof(buf), "::.%u.%u", snprintf(buf, sizeof(buf), "::.%u.%u",
port >> 8, port & 0xff); port >> 8, port & 0xff);
else else
snprintf(buf, sizeof(buf), "%pI6.%u.%u", snprintf(buf, sizeof(buf), "%pI6.%u.%u",
&address_to_register->sin6_addr, &sin6->sin6_addr, port >> 8, port & 0xff);
port >> 8, port & 0xff);
map->r_addr = buf; map->r_addr = buf;
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
...@@ -318,9 +316,21 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, ...@@ -318,9 +316,21 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
if (port) if (port)
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback, return rpcb_register_call(RPCBVERS_4, msg);
sizeof(rpcb_in6addr_loopback), }
RPCBVERS_4, msg);
static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
{
struct rpcbind_args *map = msg->rpc_argp;
dprintk("RPC: unregistering [%u, %u, '%s'] with "
"local rpcbind\n",
map->r_prog, map->r_vers, map->r_netid);
map->r_addr = "";
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
return rpcb_register_call(RPCBVERS_4, msg);
} }
/** /**
...@@ -340,10 +350,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, ...@@ -340,10 +350,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* invoke this function once for each [program, version, address, * invoke this function once for each [program, version, address,
* netid] tuple they wish to advertise. * netid] tuple they wish to advertise.
* *
* Callers may also unregister RPC services that are no longer * Callers may also unregister RPC services that are registered at a
* available by setting the port number in the passed-in address * specific address by setting the port number in @address to zero.
* to zero. Callers pass a netid of "" to unregister all * They may unregister all registered protocol families at once for
* transport netids associated with [program, version, address]. * a service by passing a NULL @address argument. If @netid is ""
* then all netids for [program, version, address] are unregistered.
* *
* This function uses rpcbind protocol version 4 to contact the * This function uses rpcbind protocol version 4 to contact the
* local rpcbind daemon. The local rpcbind daemon must support * local rpcbind daemon. The local rpcbind daemon must support
...@@ -378,13 +389,14 @@ int rpcb_v4_register(const u32 program, const u32 version, ...@@ -378,13 +389,14 @@ int rpcb_v4_register(const u32 program, const u32 version,
.rpc_argp = &map, .rpc_argp = &map,
}; };
if (address == NULL)
return rpcb_unregister_all_protofamilies(&msg);
switch (address->sa_family) { switch (address->sa_family) {
case AF_INET: case AF_INET:
return rpcb_register_netid4((struct sockaddr_in *)address, return rpcb_register_inet4(address, &msg);
&msg);
case AF_INET6: case AF_INET6:
return rpcb_register_netid6((struct sockaddr_in6 *)address, return rpcb_register_inet6(address, &msg);
&msg);
} }
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
...@@ -579,7 +591,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -579,7 +591,7 @@ void rpcb_getport_async(struct rpc_task *task)
map->r_xprt = xprt_get(xprt); map->r_xprt = xprt_get(xprt);
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ map->r_owner = "";
map->r_status = -EIO; map->r_status = -EIO;
child = rpcb_call_async(rpcb_clnt, map, proc); child = rpcb_call_async(rpcb_clnt, map, proc);
...@@ -703,11 +715,16 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, ...@@ -703,11 +715,16 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
*portp = 0; *portp = 0;
addr_len = ntohl(*p++); addr_len = ntohl(*p++);
if (addr_len == 0) {
dprintk("RPC: rpcb_decode_getaddr: "
"service is not registered\n");
return 0;
}
/* /*
* Simple sanity check. The smallest possible universal * Simple sanity check.
* address is an IPv4 address string containing 11 bytes.
*/ */
if (addr_len < 11 || addr_len > RPCBIND_MAXUADDRLEN) if (addr_len > RPCBIND_MAXUADDRLEN)
goto out_err; goto out_err;
/* /*
......
...@@ -359,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu) ...@@ -359,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
*/ */
static struct svc_serv * static struct svc_serv *
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools, __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
sa_family_t family, void (*shutdown)(struct svc_serv *serv)) void (*shutdown)(struct svc_serv *serv))
{ {
struct svc_serv *serv; struct svc_serv *serv;
unsigned int vers; unsigned int vers;
...@@ -368,7 +368,6 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, ...@@ -368,7 +368,6 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL; return NULL;
serv->sv_family = family;
serv->sv_name = prog->pg_name; serv->sv_name = prog->pg_name;
serv->sv_program = prog; serv->sv_program = prog;
serv->sv_nrthreads = 1; serv->sv_nrthreads = 1;
...@@ -427,21 +426,21 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, ...@@ -427,21 +426,21 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
struct svc_serv * struct svc_serv *
svc_create(struct svc_program *prog, unsigned int bufsize, svc_create(struct svc_program *prog, unsigned int bufsize,
sa_family_t family, void (*shutdown)(struct svc_serv *serv)) void (*shutdown)(struct svc_serv *serv))
{ {
return __svc_create(prog, bufsize, /*npools*/1, family, shutdown); return __svc_create(prog, bufsize, /*npools*/1, shutdown);
} }
EXPORT_SYMBOL_GPL(svc_create); EXPORT_SYMBOL_GPL(svc_create);
struct svc_serv * struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize, svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
sa_family_t family, void (*shutdown)(struct svc_serv *serv), void (*shutdown)(struct svc_serv *serv),
svc_thread_fn func, struct module *mod) svc_thread_fn func, struct module *mod)
{ {
struct svc_serv *serv; struct svc_serv *serv;
unsigned int npools = svc_pool_map_get(); unsigned int npools = svc_pool_map_get();
serv = __svc_create(prog, bufsize, npools, family, shutdown); serv = __svc_create(prog, bufsize, npools, shutdown);
if (serv != NULL) { if (serv != NULL) {
serv->sv_function = func; serv->sv_function = func;
...@@ -719,8 +718,6 @@ svc_exit_thread(struct svc_rqst *rqstp) ...@@ -719,8 +718,6 @@ svc_exit_thread(struct svc_rqst *rqstp)
} }
EXPORT_SYMBOL_GPL(svc_exit_thread); EXPORT_SYMBOL_GPL(svc_exit_thread);
#ifdef CONFIG_SUNRPC_REGISTER_V4
/* /*
* Register an "inet" protocol family netid with the local * Register an "inet" protocol family netid with the local
* rpcbind daemon via an rpcbind v4 SET request. * rpcbind daemon via an rpcbind v4 SET request.
...@@ -735,12 +732,13 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, ...@@ -735,12 +732,13 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
const unsigned short protocol, const unsigned short protocol,
const unsigned short port) const unsigned short port)
{ {
struct sockaddr_in sin = { const struct sockaddr_in sin = {
.sin_family = AF_INET, .sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY), .sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(port), .sin_port = htons(port),
}; };
char *netid; const char *netid;
int error;
switch (protocol) { switch (protocol) {
case IPPROTO_UDP: case IPPROTO_UDP:
...@@ -750,13 +748,23 @@ static int __svc_rpcb_register4(const u32 program, const u32 version, ...@@ -750,13 +748,23 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
netid = RPCBIND_NETID_TCP; netid = RPCBIND_NETID_TCP;
break; break;
default: default:
return -EPROTONOSUPPORT; return -ENOPROTOOPT;
} }
return rpcb_v4_register(program, version, error = rpcb_v4_register(program, version,
(struct sockaddr *)&sin, netid); (const struct sockaddr *)&sin, netid);
/*
* User space didn't support rpcbind v4, so retry this
* registration request with the legacy rpcbind v2 protocol.
*/
if (error == -EPROTONOSUPPORT)
error = rpcb_register(program, version, protocol, port);
return error;
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/* /*
* Register an "inet6" protocol family netid with the local * Register an "inet6" protocol family netid with the local
* rpcbind daemon via an rpcbind v4 SET request. * rpcbind daemon via an rpcbind v4 SET request.
...@@ -771,12 +779,13 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, ...@@ -771,12 +779,13 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
const unsigned short protocol, const unsigned short protocol,
const unsigned short port) const unsigned short port)
{ {
struct sockaddr_in6 sin6 = { const struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6, .sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT, .sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = htons(port), .sin6_port = htons(port),
}; };
char *netid; const char *netid;
int error;
switch (protocol) { switch (protocol) {
case IPPROTO_UDP: case IPPROTO_UDP:
...@@ -786,12 +795,22 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, ...@@ -786,12 +795,22 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
netid = RPCBIND_NETID_TCP6; netid = RPCBIND_NETID_TCP6;
break; break;
default: default:
return -EPROTONOSUPPORT; return -ENOPROTOOPT;
} }
return rpcb_v4_register(program, version, error = rpcb_v4_register(program, version,
(struct sockaddr *)&sin6, netid); (const struct sockaddr *)&sin6, netid);
/*
* User space didn't support rpcbind version 4, so we won't
* use a PF_INET6 listener.
*/
if (error == -EPROTONOSUPPORT)
error = -EAFNOSUPPORT;
return error;
} }
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
/* /*
* Register a kernel RPC service via rpcbind version 4. * Register a kernel RPC service via rpcbind version 4.
...@@ -799,69 +818,43 @@ static int __svc_rpcb_register6(const u32 program, const u32 version, ...@@ -799,69 +818,43 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
* Returns zero on success; a negative errno value is returned * Returns zero on success; a negative errno value is returned
* if any error occurs. * if any error occurs.
*/ */
static int __svc_register(const u32 program, const u32 version, static int __svc_register(const char *progname,
const sa_family_t family, const u32 program, const u32 version,
const int family,
const unsigned short protocol, const unsigned short protocol,
const unsigned short port) const unsigned short port)
{ {
int error; int error = -EAFNOSUPPORT;
switch (family) { switch (family) {
case AF_INET: case PF_INET:
return __svc_rpcb_register4(program, version, error = __svc_rpcb_register4(program, version,
protocol, port); protocol, port);
case AF_INET6: break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case PF_INET6:
error = __svc_rpcb_register6(program, version, error = __svc_rpcb_register6(program, version,
protocol, port); protocol, port);
if (error < 0) #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
return error;
/*
* Work around bug in some versions of Linux rpcbind
* which don't allow registration of both inet and
* inet6 netids.
*
* Error return ignored for now.
*/
__svc_rpcb_register4(program, version,
protocol, port);
return 0;
} }
return -EAFNOSUPPORT; if (error < 0)
} printk(KERN_WARNING "svc: failed to register %sv%u RPC "
"service (errno %d).\n", progname, version, -error);
#else /* CONFIG_SUNRPC_REGISTER_V4 */ return error;
/*
* Register a kernel RPC service via rpcbind version 2.
*
* Returns zero on success; a negative errno value is returned
* if any error occurs.
*/
static int __svc_register(const u32 program, const u32 version,
sa_family_t family,
const unsigned short protocol,
const unsigned short port)
{
if (family != AF_INET)
return -EAFNOSUPPORT;
return rpcb_register(program, version, protocol, port);
} }
#endif /* CONFIG_SUNRPC_REGISTER_V4 */
/** /**
* svc_register - register an RPC service with the local portmapper * svc_register - register an RPC service with the local portmapper
* @serv: svc_serv struct for the service to register * @serv: svc_serv struct for the service to register
* @family: protocol family of service's listener socket
* @proto: transport protocol number to advertise * @proto: transport protocol number to advertise
* @port: port to advertise * @port: port to advertise
* *
* Service is registered for any address in serv's address family * Service is registered for any address in the passed-in protocol family
*/ */
int svc_register(const struct svc_serv *serv, const unsigned short proto, int svc_register(const struct svc_serv *serv, const int family,
const unsigned short port) const unsigned short proto, const unsigned short port)
{ {
struct svc_program *progp; struct svc_program *progp;
unsigned int i; unsigned int i;
...@@ -879,15 +872,15 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto, ...@@ -879,15 +872,15 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto,
i, i,
proto == IPPROTO_UDP? "udp" : "tcp", proto == IPPROTO_UDP? "udp" : "tcp",
port, port,
serv->sv_family, family,
progp->pg_vers[i]->vs_hidden? progp->pg_vers[i]->vs_hidden?
" (but not telling portmap)" : ""); " (but not telling portmap)" : "");
if (progp->pg_vers[i]->vs_hidden) if (progp->pg_vers[i]->vs_hidden)
continue; continue;
error = __svc_register(progp->pg_prog, i, error = __svc_register(progp->pg_name, progp->pg_prog,
serv->sv_family, proto, port); i, family, proto, port);
if (error < 0) if (error < 0)
break; break;
} }
...@@ -896,38 +889,31 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto, ...@@ -896,38 +889,31 @@ int svc_register(const struct svc_serv *serv, const unsigned short proto,
return error; return error;
} }
#ifdef CONFIG_SUNRPC_REGISTER_V4 /*
* If user space is running rpcbind, it should take the v4 UNSET
* and clear everything for this [program, version]. If user space
* is running portmap, it will reject the v4 UNSET, but won't have
* any "inet6" entries anyway. So a PMAP_UNSET should be sufficient
* in this case to clear all existing entries for [program, version].
*/
static void __svc_unregister(const u32 program, const u32 version, static void __svc_unregister(const u32 program, const u32 version,
const char *progname) const char *progname)
{ {
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = 0,
};
int error; int error;
error = rpcb_v4_register(program, version, error = rpcb_v4_register(program, version, NULL, "");
(struct sockaddr *)&sin6, "");
dprintk("svc: %s(%sv%u), error %d\n",
__func__, progname, version, error);
}
#else /* CONFIG_SUNRPC_REGISTER_V4 */
static void __svc_unregister(const u32 program, const u32 version, /*
const char *progname) * User space didn't support rpcbind v4, so retry this
{ * request with the legacy rpcbind v2 protocol.
int error; */
if (error == -EPROTONOSUPPORT)
error = rpcb_register(program, version, 0, 0);
error = rpcb_register(program, version, 0, 0);
dprintk("svc: %s(%sv%u), error %d\n", dprintk("svc: %s(%sv%u), error %d\n",
__func__, progname, version, error); __func__, progname, version, error);
} }
#endif /* CONFIG_SUNRPC_REGISTER_V4 */
/* /*
* All netids, bind addresses and ports registered for [program, version] * All netids, bind addresses and ports registered for [program, version]
* are removed from the local rpcbind database (if the service is not * are removed from the local rpcbind database (if the service is not
......
...@@ -161,7 +161,9 @@ EXPORT_SYMBOL_GPL(svc_xprt_init); ...@@ -161,7 +161,9 @@ EXPORT_SYMBOL_GPL(svc_xprt_init);
static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
struct svc_serv *serv, struct svc_serv *serv,
unsigned short port, int flags) const int family,
const unsigned short port,
int flags)
{ {
struct sockaddr_in sin = { struct sockaddr_in sin = {
.sin_family = AF_INET, .sin_family = AF_INET,
...@@ -176,12 +178,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, ...@@ -176,12 +178,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
struct sockaddr *sap; struct sockaddr *sap;
size_t len; size_t len;
switch (serv->sv_family) { switch (family) {
case AF_INET: case PF_INET:
sap = (struct sockaddr *)&sin; sap = (struct sockaddr *)&sin;
len = sizeof(sin); len = sizeof(sin);
break; break;
case AF_INET6: case PF_INET6:
sap = (struct sockaddr *)&sin6; sap = (struct sockaddr *)&sin6;
len = sizeof(sin6); len = sizeof(sin6);
break; break;
...@@ -192,7 +194,8 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, ...@@ -192,7 +194,8 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
return xcl->xcl_ops->xpo_create(serv, sap, len, flags); return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
} }
int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port, int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
const int family, const unsigned short port,
int flags) int flags)
{ {
struct svc_xprt_class *xcl; struct svc_xprt_class *xcl;
...@@ -209,7 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port, ...@@ -209,7 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
goto err; goto err;
spin_unlock(&svc_xprt_class_lock); spin_unlock(&svc_xprt_class_lock);
newxprt = __svc_xpo_create(xcl, serv, port, flags); newxprt = __svc_xpo_create(xcl, serv, family, port, flags);
if (IS_ERR(newxprt)) { if (IS_ERR(newxprt)) {
module_put(xcl->xcl_owner); module_put(xcl->xcl_owner);
return PTR_ERR(newxprt); return PTR_ERR(newxprt);
...@@ -1033,7 +1036,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) ...@@ -1033,7 +1036,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
return dr; return dr;
} }
/* /**
* svc_find_xprt - find an RPC transport instance
* @serv: pointer to svc_serv to search
* @xcl_name: C string containing transport's class name
* @af: Address family of transport's local address
* @port: transport's IP port number
*
* Return the transport instance pointer for the endpoint accepting * Return the transport instance pointer for the endpoint accepting
* connections/peer traffic from the specified transport class, * connections/peer traffic from the specified transport class,
* address family and port. * address family and port.
...@@ -1042,14 +1051,14 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) ...@@ -1042,14 +1051,14 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
* wild-card, and will result in matching the first transport in the * wild-card, and will result in matching the first transport in the
* service's list that has a matching class name. * service's list that has a matching class name.
*/ */
struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name, struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
int af, int port) const sa_family_t af, const unsigned short port)
{ {
struct svc_xprt *xprt; struct svc_xprt *xprt;
struct svc_xprt *found = NULL; struct svc_xprt *found = NULL;
/* Sanity check the args */ /* Sanity check the args */
if (!serv || !xcl_name) if (serv == NULL || xcl_name == NULL)
return found; return found;
spin_lock_bh(&serv->sv_lock); spin_lock_bh(&serv->sv_lock);
...@@ -1058,7 +1067,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name, ...@@ -1058,7 +1067,7 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
continue; continue;
if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family) if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
continue; continue;
if (port && port != svc_xprt_local_port(xprt)) if (port != 0 && port != svc_xprt_local_port(xprt))
continue; continue;
found = xprt; found = xprt;
svc_xprt_get(xprt); svc_xprt_get(xprt);
......
...@@ -1110,7 +1110,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, ...@@ -1110,7 +1110,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
struct svc_sock *svsk; struct svc_sock *svsk;
struct sock *inet; struct sock *inet;
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS); int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
int val;
dprintk("svc: svc_setup_socket %p\n", sock); dprintk("svc: svc_setup_socket %p\n", sock);
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) { if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
...@@ -1122,7 +1121,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, ...@@ -1122,7 +1121,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
/* Register socket with portmapper */ /* Register socket with portmapper */
if (*errp >= 0 && pmap_register) if (*errp >= 0 && pmap_register)
*errp = svc_register(serv, inet->sk_protocol, *errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
ntohs(inet_sk(inet)->sport)); ntohs(inet_sk(inet)->sport));
if (*errp < 0) { if (*errp < 0) {
...@@ -1143,18 +1142,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, ...@@ -1143,18 +1142,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
else else
svc_tcp_init(svsk, serv); svc_tcp_init(svsk, serv);
/*
* We start one listener per sv_serv. We want AF_INET
* requests to be automatically shunted to our AF_INET6
* listener using a mapped IPv4 address. Make sure
* no-one starts an equivalent IPv4 listener, which
* would steal our incoming connections.
*/
val = 0;
if (serv->sv_family == AF_INET6)
kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
(char *)&val, sizeof(val));
dprintk("svc: svc_setup_socket created %p (inet %p)\n", dprintk("svc: svc_setup_socket created %p (inet %p)\n",
svsk, svsk->sk_sk); svsk, svsk->sk_sk);
...@@ -1222,6 +1209,8 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv, ...@@ -1222,6 +1209,8 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
struct sockaddr_storage addr; struct sockaddr_storage addr;
struct sockaddr *newsin = (struct sockaddr *)&addr; struct sockaddr *newsin = (struct sockaddr *)&addr;
int newlen; int newlen;
int family;
int val;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
dprintk("svc: svc_create_socket(%s, %d, %s)\n", dprintk("svc: svc_create_socket(%s, %d, %s)\n",
...@@ -1233,14 +1222,35 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv, ...@@ -1233,14 +1222,35 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
"sockets supported\n"); "sockets supported\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
switch (sin->sa_family) {
case AF_INET6:
family = PF_INET6;
break;
case AF_INET:
family = PF_INET;
break;
default:
return ERR_PTR(-EINVAL);
}
error = sock_create_kern(sin->sa_family, type, protocol, &sock); error = sock_create_kern(family, type, protocol, &sock);
if (error < 0) if (error < 0)
return ERR_PTR(error); return ERR_PTR(error);
svc_reclassify_socket(sock); svc_reclassify_socket(sock);
/*
* If this is an PF_INET6 listener, we want to avoid
* getting requests from IPv4 remotes. Those should
* be shunted to a PF_INET listener via rpcbind.
*/
val = 1;
if (family == PF_INET6)
kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
(char *)&val, sizeof(val));
if (type == SOCK_STREAM) if (type == SOCK_STREAM)
sock->sk->sk_reuse = 1; /* allow address reuse */ sock->sk->sk_reuse = 1; /* allow address reuse */
error = kernel_bind(sock, sin, len); error = kernel_bind(sock, sin, len);
......
...@@ -151,6 +151,37 @@ int xprt_unregister_transport(struct xprt_class *transport) ...@@ -151,6 +151,37 @@ int xprt_unregister_transport(struct xprt_class *transport)
} }
EXPORT_SYMBOL_GPL(xprt_unregister_transport); EXPORT_SYMBOL_GPL(xprt_unregister_transport);
/**
* xprt_load_transport - load a transport implementation
* @transport_name: transport to load
*
* Returns:
* 0: transport successfully loaded
* -ENOENT: transport module not available
*/
int xprt_load_transport(const char *transport_name)
{
struct xprt_class *t;
char module_name[sizeof t->name + 5];
int result;
result = 0;
spin_lock(&xprt_list_lock);
list_for_each_entry(t, &xprt_list, list) {
if (strcmp(t->name, transport_name) == 0) {
spin_unlock(&xprt_list_lock);
goto out;
}
}
spin_unlock(&xprt_list_lock);
strcpy(module_name, "xprt");
strncat(module_name, transport_name, sizeof t->name);
result = request_module(module_name);
out:
return result;
}
EXPORT_SYMBOL_GPL(xprt_load_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
...@@ -580,7 +611,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt) ...@@ -580,7 +611,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt)
dprintk("RPC: disconnected transport %p\n", xprt); dprintk("RPC: disconnected transport %p\n", xprt);
spin_lock_bh(&xprt->transport_lock); spin_lock_bh(&xprt->transport_lock);
xprt_clear_connected(xprt); xprt_clear_connected(xprt);
xprt_wake_pending_tasks(xprt, -ENOTCONN); xprt_wake_pending_tasks(xprt, -EAGAIN);
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
} }
EXPORT_SYMBOL_GPL(xprt_disconnect_done); EXPORT_SYMBOL_GPL(xprt_disconnect_done);
...@@ -598,7 +629,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) ...@@ -598,7 +629,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
/* Try to schedule an autoclose RPC call */ /* Try to schedule an autoclose RPC call */
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
queue_work(rpciod_workqueue, &xprt->task_cleanup); queue_work(rpciod_workqueue, &xprt->task_cleanup);
xprt_wake_pending_tasks(xprt, -ENOTCONN); xprt_wake_pending_tasks(xprt, -EAGAIN);
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
} }
...@@ -625,7 +656,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie) ...@@ -625,7 +656,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie)
/* Try to schedule an autoclose RPC call */ /* Try to schedule an autoclose RPC call */
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
queue_work(rpciod_workqueue, &xprt->task_cleanup); queue_work(rpciod_workqueue, &xprt->task_cleanup);
xprt_wake_pending_tasks(xprt, -ENOTCONN); xprt_wake_pending_tasks(xprt, -EAGAIN);
out: out:
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
} }
...@@ -695,9 +726,8 @@ static void xprt_connect_status(struct rpc_task *task) ...@@ -695,9 +726,8 @@ static void xprt_connect_status(struct rpc_task *task)
} }
switch (task->tk_status) { switch (task->tk_status) {
case -ENOTCONN: case -EAGAIN:
dprintk("RPC: %5u xprt_connect_status: connection broken\n", dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
task->tk_pid);
break; break;
case -ETIMEDOUT: case -ETIMEDOUT:
dprintk("RPC: %5u xprt_connect_status: connect attempt timed " dprintk("RPC: %5u xprt_connect_status: connect attempt timed "
...@@ -818,15 +848,8 @@ int xprt_prepare_transmit(struct rpc_task *task) ...@@ -818,15 +848,8 @@ int xprt_prepare_transmit(struct rpc_task *task)
err = req->rq_received; err = req->rq_received;
goto out_unlock; goto out_unlock;
} }
if (!xprt->ops->reserve_xprt(task)) { if (!xprt->ops->reserve_xprt(task))
err = -EAGAIN; err = -EAGAIN;
goto out_unlock;
}
if (!xprt_connected(xprt)) {
err = -ENOTCONN;
goto out_unlock;
}
out_unlock: out_unlock:
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
return err; return err;
...@@ -870,32 +893,26 @@ void xprt_transmit(struct rpc_task *task) ...@@ -870,32 +893,26 @@ void xprt_transmit(struct rpc_task *task)
req->rq_connect_cookie = xprt->connect_cookie; req->rq_connect_cookie = xprt->connect_cookie;
req->rq_xtime = jiffies; req->rq_xtime = jiffies;
status = xprt->ops->send_request(task); status = xprt->ops->send_request(task);
if (status == 0) { if (status != 0) {
dprintk("RPC: %5u xmit complete\n", task->tk_pid); task->tk_status = status;
spin_lock_bh(&xprt->transport_lock); return;
}
xprt->ops->set_retrans_timeout(task); dprintk("RPC: %5u xmit complete\n", task->tk_pid);
spin_lock_bh(&xprt->transport_lock);
xprt->stat.sends++; xprt->ops->set_retrans_timeout(task);
xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
xprt->stat.bklog_u += xprt->backlog.qlen;
/* Don't race with disconnect */ xprt->stat.sends++;
if (!xprt_connected(xprt)) xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
task->tk_status = -ENOTCONN; xprt->stat.bklog_u += xprt->backlog.qlen;
else if (!req->rq_received)
rpc_sleep_on(&xprt->pending, task, xprt_timer);
spin_unlock_bh(&xprt->transport_lock);
return;
}
/* Note: at this point, task->tk_sleeping has not yet been set, /* Don't race with disconnect */
* hence there is no danger of the waking up task being put on if (!xprt_connected(xprt))
* schedq, and being picked up by a parallel run of rpciod(). task->tk_status = -ENOTCONN;
*/ else if (!req->rq_received)
task->tk_status = status; rpc_sleep_on(&xprt->pending, task, xprt_timer);
if (status == -ECONNREFUSED) spin_unlock_bh(&xprt->transport_lock);
rpc_sleep_on(&xprt->sending, task, NULL);
} }
static inline void do_xprt_reserve(struct rpc_task *task) static inline void do_xprt_reserve(struct rpc_task *task)
......
...@@ -310,6 +310,19 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) ...@@ -310,6 +310,19 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
__func__, pad, destp, rqst->rq_slen, curlen); __func__, pad, destp, rqst->rq_slen, curlen);
copy_len = rqst->rq_snd_buf.page_len; copy_len = rqst->rq_snd_buf.page_len;
if (rqst->rq_snd_buf.tail[0].iov_len) {
curlen = rqst->rq_snd_buf.tail[0].iov_len;
if (destp + copy_len != rqst->rq_snd_buf.tail[0].iov_base) {
memmove(destp + copy_len,
rqst->rq_snd_buf.tail[0].iov_base, curlen);
r_xprt->rx_stats.pullup_copy_count += curlen;
}
dprintk("RPC: %s: tail destp 0x%p len %d\n",
__func__, destp + copy_len, curlen);
rqst->rq_svec[0].iov_len += curlen;
}
r_xprt->rx_stats.pullup_copy_count += copy_len; r_xprt->rx_stats.pullup_copy_count += copy_len;
npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT; npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
for (i = 0; copy_len && i < npages; i++) { for (i = 0; copy_len && i < npages; i++) {
...@@ -332,17 +345,6 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) ...@@ -332,17 +345,6 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
destp += curlen; destp += curlen;
copy_len -= curlen; copy_len -= curlen;
} }
if (rqst->rq_snd_buf.tail[0].iov_len) {
curlen = rqst->rq_snd_buf.tail[0].iov_len;
if (destp != rqst->rq_snd_buf.tail[0].iov_base) {
memcpy(destp,
rqst->rq_snd_buf.tail[0].iov_base, curlen);
r_xprt->rx_stats.pullup_copy_count += curlen;
}
dprintk("RPC: %s: tail destp 0x%p len %d curlen %d\n",
__func__, destp, copy_len, curlen);
rqst->rq_svec[0].iov_len += curlen;
}
/* header now contains entire send message */ /* header now contains entire send message */
return pad; return pad;
} }
...@@ -656,7 +658,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) ...@@ -656,7 +658,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
if (curlen > rqst->rq_rcv_buf.tail[0].iov_len) if (curlen > rqst->rq_rcv_buf.tail[0].iov_len)
curlen = rqst->rq_rcv_buf.tail[0].iov_len; curlen = rqst->rq_rcv_buf.tail[0].iov_len;
if (rqst->rq_rcv_buf.tail[0].iov_base != srcp) if (rqst->rq_rcv_buf.tail[0].iov_base != srcp)
memcpy(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen); memmove(rqst->rq_rcv_buf.tail[0].iov_base, srcp, curlen);
dprintk("RPC: %s: tail srcp 0x%p len %d curlen %d\n", dprintk("RPC: %s: tail srcp 0x%p len %d curlen %d\n",
__func__, srcp, copy_len, curlen); __func__, srcp, copy_len, curlen);
rqst->rq_rcv_buf.tail[0].iov_len = curlen; rqst->rq_rcv_buf.tail[0].iov_len = curlen;
......
...@@ -191,7 +191,6 @@ static int map_xdr(struct svcxprt_rdma *xprt, ...@@ -191,7 +191,6 @@ static int map_xdr(struct svcxprt_rdma *xprt,
struct xdr_buf *xdr, struct xdr_buf *xdr,
struct svc_rdma_req_map *vec) struct svc_rdma_req_map *vec)
{ {
int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
int sge_no; int sge_no;
u32 sge_bytes; u32 sge_bytes;
u32 page_bytes; u32 page_bytes;
...@@ -235,7 +234,11 @@ static int map_xdr(struct svcxprt_rdma *xprt, ...@@ -235,7 +234,11 @@ static int map_xdr(struct svcxprt_rdma *xprt,
sge_no++; sge_no++;
} }
BUG_ON(sge_no > sge_max); dprintk("svcrdma: map_xdr: sge_no %d page_no %d "
"page_base %u page_len %u head_len %zu tail_len %zu\n",
sge_no, page_no, xdr->page_base, xdr->page_len,
xdr->head[0].iov_len, xdr->tail[0].iov_len);
vec->count = sge_no; vec->count = sge_no;
return 0; return 0;
} }
...@@ -579,7 +582,6 @@ static int send_reply(struct svcxprt_rdma *rdma, ...@@ -579,7 +582,6 @@ static int send_reply(struct svcxprt_rdma *rdma,
ctxt->sge[page_no+1].length = 0; ctxt->sge[page_no+1].length = 0;
} }
BUG_ON(sge_no > rdma->sc_max_sge); BUG_ON(sge_no > rdma->sc_max_sge);
BUG_ON(sge_no > ctxt->count);
memset(&send_wr, 0, sizeof send_wr); memset(&send_wr, 0, sizeof send_wr);
ctxt->wr_op = IB_WR_SEND; ctxt->wr_op = IB_WR_SEND;
send_wr.wr_id = (unsigned long)ctxt; send_wr.wr_id = (unsigned long)ctxt;
......
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