Commit 713404d6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-2.6.29' of git://linux-nfs.org/~bfields/linux

* 'for-2.6.29' of git://linux-nfs.org/~bfields/linux: (67 commits)
  nfsd: get rid of NFSD_VERSION
  nfsd: last_byte_offset
  nfsd: delete wrong file comment from nfsd/nfs4xdr.c
  nfsd: git rid of nfs4_cb_null_ops declaration
  nfsd: dprint each op status in nfsd4_proc_compound
  nfsd: add etoosmall to nfserrno
  NFSD: FIDs need to take precedence over UUIDs
  SUNRPC: The sunrpc server code should not be used by out-of-tree modules
  svc: Clean up deferred requests on transport destruction
  nfsd: fix double-locks of directory mutex
  svc: Move kfree of deferral record to common code
  CRED: Fix NFSD regression
  NLM: Clean up flow of control in make_socks() function
  NLM: Refactor make_socks() function
  nfsd: Ensure nfsv4 calls the underlying filesystem on LOCKT
  SUNRPC: Ensure the server closes sockets in a timely fashion
  NFSD: Add documenting comments for nfsctl interface
  NFSD: Replace open-coded integer with macro
  NFSD: Fix a handful of coding style issues in write_filehandle()
  NFSD: clean up failover sysctl function naming
  ...
parents d599edca db43910c
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
#define NLMCLNT_GRACE_WAIT (5*HZ) #define NLMCLNT_GRACE_WAIT (5*HZ)
...@@ -518,11 +517,9 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -518,11 +517,9 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
unsigned char fl_type; unsigned char fl_type;
int status = -ENOLCK; int status = -ENOLCK;
if (nsm_monitor(host) < 0) { if (nsm_monitor(host) < 0)
printk(KERN_NOTICE "lockd: failed to monitor %s\n",
host->h_name);
goto out; goto out;
}
fl->fl_flags |= FL_ACCESS; fl->fl_flags |= FL_ACCESS;
status = do_vfs_lock(fl); status = do_vfs_lock(fl);
fl->fl_flags = fl_flags; fl->fl_flags = fl_flags;
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <net/ipv6.h> #include <net/ipv6.h>
...@@ -32,11 +31,6 @@ static int nrhosts; ...@@ -32,11 +31,6 @@ static int nrhosts;
static DEFINE_MUTEX(nlm_host_mutex); static DEFINE_MUTEX(nlm_host_mutex);
static void nlm_gc_hosts(void); static void nlm_gc_hosts(void);
static struct nsm_handle *nsm_find(const struct sockaddr *sap,
const size_t salen,
const char *hostname,
const size_t hostname_len,
const int create);
struct nlm_lookup_host_info { struct nlm_lookup_host_info {
const int server; /* search for server|client */ const int server; /* search for server|client */
...@@ -105,32 +99,6 @@ static void nlm_clear_port(struct sockaddr *sap) ...@@ -105,32 +99,6 @@ static void nlm_clear_port(struct sockaddr *sap)
} }
} }
static void nlm_display_address(const struct sockaddr *sap,
char *buf, const size_t len)
{
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
switch (sap->sa_family) {
case AF_UNSPEC:
snprintf(buf, len, "unspecified");
break;
case AF_INET:
snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
break;
case AF_INET6:
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
snprintf(buf, len, "%pI4",
&sin6->sin6_addr.s6_addr32[3]);
else
snprintf(buf, len, "%pI6", &sin6->sin6_addr);
break;
default:
snprintf(buf, len, "unsupported address family");
break;
}
}
/* /*
* Common host lookup routine for server & client * Common host lookup routine for server & client
*/ */
...@@ -190,8 +158,8 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) ...@@ -190,8 +158,8 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
atomic_inc(&nsm->sm_count); atomic_inc(&nsm->sm_count);
else { else {
host = NULL; host = NULL;
nsm = nsm_find(ni->sap, ni->salen, nsm = nsm_get_handle(ni->sap, ni->salen,
ni->hostname, ni->hostname_len, 1); ni->hostname, ni->hostname_len);
if (!nsm) { if (!nsm) {
dprintk("lockd: nlm_lookup_host failed; " dprintk("lockd: nlm_lookup_host failed; "
"no nsm handle\n"); "no nsm handle\n");
...@@ -206,6 +174,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) ...@@ -206,6 +174,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
goto out; goto out;
} }
host->h_name = nsm->sm_name; host->h_name = nsm->sm_name;
host->h_addrbuf = nsm->sm_addrbuf;
memcpy(nlm_addr(host), ni->sap, ni->salen); memcpy(nlm_addr(host), ni->sap, ni->salen);
host->h_addrlen = ni->salen; host->h_addrlen = ni->salen;
nlm_clear_port(nlm_addr(host)); nlm_clear_port(nlm_addr(host));
...@@ -232,11 +201,6 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) ...@@ -232,11 +201,6 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
nrhosts++; nrhosts++;
nlm_display_address((struct sockaddr *)&host->h_addr,
host->h_addrbuf, sizeof(host->h_addrbuf));
nlm_display_address((struct sockaddr *)&host->h_srcaddr,
host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
dprintk("lockd: nlm_lookup_host created host %s\n", dprintk("lockd: nlm_lookup_host created host %s\n",
host->h_name); host->h_name);
...@@ -256,10 +220,8 @@ nlm_destroy_host(struct nlm_host *host) ...@@ -256,10 +220,8 @@ nlm_destroy_host(struct nlm_host *host)
BUG_ON(!list_empty(&host->h_lockowners)); BUG_ON(!list_empty(&host->h_lockowners));
BUG_ON(atomic_read(&host->h_count)); BUG_ON(atomic_read(&host->h_count));
/*
* Release NSM handle and unmonitor host.
*/
nsm_unmonitor(host); nsm_unmonitor(host);
nsm_release(host->h_nsmhandle);
clnt = host->h_rpcclnt; clnt = host->h_rpcclnt;
if (clnt != NULL) if (clnt != NULL)
...@@ -378,8 +340,8 @@ nlm_bind_host(struct nlm_host *host) ...@@ -378,8 +340,8 @@ nlm_bind_host(struct nlm_host *host)
{ {
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n", dprintk("lockd: nlm_bind_host %s (%s)\n",
host->h_name, host->h_addrbuf, host->h_srcaddrbuf); host->h_name, host->h_addrbuf);
/* Lock host handle */ /* Lock host handle */
mutex_lock(&host->h_mutex); mutex_lock(&host->h_mutex);
...@@ -481,35 +443,23 @@ void nlm_release_host(struct nlm_host *host) ...@@ -481,35 +443,23 @@ void nlm_release_host(struct nlm_host *host)
} }
} }
/* /**
* We were notified that the host indicated by address &sin * nlm_host_rebooted - Release all resources held by rebooted host
* has rebooted. * @info: pointer to decoded results of NLM_SM_NOTIFY call
* Release all resources held by that peer. *
* We were notified that the specified host has rebooted. Release
* all resources held by that peer.
*/ */
void nlm_host_rebooted(const struct sockaddr_in *sin, void nlm_host_rebooted(const struct nlm_reboot *info)
const char *hostname,
unsigned int hostname_len,
u32 new_state)
{ {
struct hlist_head *chain; struct hlist_head *chain;
struct hlist_node *pos; struct hlist_node *pos;
struct nsm_handle *nsm; struct nsm_handle *nsm;
struct nlm_host *host; struct nlm_host *host;
nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin), nsm = nsm_reboot_lookup(info);
hostname, hostname_len, 0); if (unlikely(nsm == NULL))
if (nsm == NULL) {
dprintk("lockd: never saw rebooted peer '%.*s' before\n",
hostname_len, hostname);
return; return;
}
dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
hostname_len, hostname, nsm->sm_addrbuf);
/* When reclaiming locks on this peer, make sure that
* we set up a new notification */
nsm->sm_monitored = 0;
/* Mark all hosts tied to this NSM state as having rebooted. /* Mark all hosts tied to this NSM state as having rebooted.
* We run the loop repeatedly, because we drop the host table * We run the loop repeatedly, because we drop the host table
...@@ -520,8 +470,8 @@ again: mutex_lock(&nlm_host_mutex); ...@@ -520,8 +470,8 @@ again: mutex_lock(&nlm_host_mutex);
for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
hlist_for_each_entry(host, pos, chain, h_hash) { hlist_for_each_entry(host, pos, chain, h_hash) {
if (host->h_nsmhandle == nsm if (host->h_nsmhandle == nsm
&& host->h_nsmstate != new_state) { && host->h_nsmstate != info->state) {
host->h_nsmstate = new_state; host->h_nsmstate = info->state;
host->h_state++; host->h_state++;
nlm_get_host(host); nlm_get_host(host);
...@@ -629,89 +579,3 @@ nlm_gc_hosts(void) ...@@ -629,89 +579,3 @@ nlm_gc_hosts(void)
next_gc = jiffies + NLM_HOST_COLLECT; next_gc = jiffies + NLM_HOST_COLLECT;
} }
/*
* Manage NSM handles
*/
static LIST_HEAD(nsm_handles);
static DEFINE_SPINLOCK(nsm_lock);
static struct nsm_handle *nsm_find(const struct sockaddr *sap,
const size_t salen,
const char *hostname,
const size_t hostname_len,
const int create)
{
struct nsm_handle *nsm = NULL;
struct nsm_handle *pos;
if (!sap)
return NULL;
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
if (printk_ratelimit()) {
printk(KERN_WARNING "Invalid hostname \"%.*s\" "
"in NFS lock request\n",
(int)hostname_len, hostname);
}
return NULL;
}
retry:
spin_lock(&nsm_lock);
list_for_each_entry(pos, &nsm_handles, sm_link) {
if (hostname && nsm_use_hostnames) {
if (strlen(pos->sm_name) != hostname_len
|| memcmp(pos->sm_name, hostname, hostname_len))
continue;
} else if (!nlm_cmp_addr(nsm_addr(pos), sap))
continue;
atomic_inc(&pos->sm_count);
kfree(nsm);
nsm = pos;
goto found;
}
if (nsm) {
list_add(&nsm->sm_link, &nsm_handles);
goto found;
}
spin_unlock(&nsm_lock);
if (!create)
return NULL;
nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
if (nsm == NULL)
return NULL;
memcpy(nsm_addr(nsm), sap, salen);
nsm->sm_addrlen = salen;
nsm->sm_name = (char *) (nsm + 1);
memcpy(nsm->sm_name, hostname, hostname_len);
nsm->sm_name[hostname_len] = '\0';
nlm_display_address((struct sockaddr *)&nsm->sm_addr,
nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
atomic_set(&nsm->sm_count, 1);
goto retry;
found:
spin_unlock(&nsm_lock);
return nsm;
}
/*
* Release an NSM handle
*/
void
nsm_release(struct nsm_handle *nsm)
{
if (!nsm)
return;
if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
list_del(&nsm->sm_link);
spin_unlock(&nsm_lock);
kfree(nsm);
}
}
This diff is collapsed.
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/svcsock.h>
#include <net/ip.h> #include <net/ip.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
#include <linux/nfs.h> #include <linux/nfs.h>
#define NLMDBG_FACILITY NLMDBG_SVC #define NLMDBG_FACILITY NLMDBG_SVC
...@@ -53,6 +52,17 @@ static struct task_struct *nlmsvc_task; ...@@ -53,6 +52,17 @@ 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
...@@ -60,7 +70,9 @@ unsigned long nlmsvc_timeout; ...@@ -60,7 +70,9 @@ unsigned long nlmsvc_timeout;
static unsigned long nlm_grace_period; static unsigned long nlm_grace_period;
static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
static int nlm_udpport, nlm_tcpport; static int nlm_udpport, nlm_tcpport;
int nsm_use_hostnames = 0;
/* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
static unsigned int nlm_max_connections = 1024;
/* /*
* Constants needed for the sysctl interface. * Constants needed for the sysctl interface.
...@@ -143,6 +155,9 @@ lockd(void *vrqstp) ...@@ -143,6 +155,9 @@ lockd(void *vrqstp)
long timeout = MAX_SCHEDULE_TIMEOUT; long timeout = MAX_SCHEDULE_TIMEOUT;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
/* update sv_maxconn if it has changed */
rqstp->rq_server->sv_maxconn = nlm_max_connections;
if (signalled()) { if (signalled()) {
flush_signals(current); flush_signals(current);
if (nlmsvc_ops) { if (nlmsvc_ops) {
...@@ -189,6 +204,19 @@ lockd(void *vrqstp) ...@@ -189,6 +204,19 @@ lockd(void *vrqstp)
return 0; return 0;
} }
static int create_lockd_listener(struct svc_serv *serv, char *name,
unsigned short port)
{
struct svc_xprt *xprt;
xprt = svc_find_xprt(serv, name, 0, 0);
if (xprt == NULL)
return svc_create_xprt(serv, name, port, SVC_SOCK_DEFAULTS);
svc_xprt_put(xprt);
return 0;
}
/* /*
* Ensure there are active UDP and TCP listeners for lockd. * Ensure there are active UDP and TCP listeners for lockd.
* *
...@@ -202,29 +230,23 @@ lockd(void *vrqstp) ...@@ -202,29 +230,23 @@ lockd(void *vrqstp)
static int make_socks(struct svc_serv *serv) static int make_socks(struct svc_serv *serv)
{ {
static int warned; static int warned;
struct svc_xprt *xprt; int err;
int err = 0;
xprt = svc_find_xprt(serv, "udp", 0, 0); err = create_lockd_listener(serv, "udp", nlm_udpport);
if (!xprt) if (err < 0)
err = svc_create_xprt(serv, "udp", nlm_udpport, goto out_err;
SVC_SOCK_DEFAULTS);
else err = create_lockd_listener(serv, "tcp", nlm_tcpport);
svc_xprt_put(xprt); if (err < 0)
if (err >= 0) { goto out_err;
xprt = svc_find_xprt(serv, "tcp", 0, 0);
if (!xprt) warned = 0;
err = svc_create_xprt(serv, "tcp", nlm_tcpport, return 0;
SVC_SOCK_DEFAULTS);
else out_err:
svc_xprt_put(xprt); if (warned++ == 0)
}
if (err >= 0) {
warned = 0;
err = 0;
} else if (warned++ == 0)
printk(KERN_WARNING printk(KERN_WARNING
"lockd_up: makesock failed, error=%d\n", err); "lockd_up: makesock failed, error=%d\n", err);
return err; return err;
} }
...@@ -252,7 +274,7 @@ int lockd_up(void) ...@@ -252,7 +274,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, AF_INET, NULL); serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, nlmsvc_family, 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;
...@@ -276,6 +298,7 @@ int lockd_up(void) ...@@ -276,6 +298,7 @@ int lockd_up(void)
} }
svc_sock_update_bufs(serv); svc_sock_update_bufs(serv);
serv->sv_maxconn = nlm_max_connections;
nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
if (IS_ERR(nlmsvc_task)) { if (IS_ERR(nlmsvc_task)) {
...@@ -485,6 +508,7 @@ module_param_call(nlm_udpport, param_set_port, param_get_int, ...@@ -485,6 +508,7 @@ module_param_call(nlm_udpport, param_set_port, param_get_int,
module_param_call(nlm_tcpport, param_set_port, param_get_int, module_param_call(nlm_tcpport, param_set_port, param_get_int,
&nlm_tcpport, 0644); &nlm_tcpport, 0644);
module_param(nsm_use_hostnames, bool, 0644); module_param(nsm_use_hostnames, bool, 0644);
module_param(nlm_max_connections, uint, 0644);
/* /*
* Initialising and terminating the module. * Initialising and terminating the module.
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
#include <linux/nfsd/nfsd.h> #include <linux/nfsd/nfsd.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/share.h> #include <linux/lockd/share.h>
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
...@@ -419,8 +417,6 @@ static __be32 ...@@ -419,8 +417,6 @@ static __be32
nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
void *resp) void *resp)
{ {
struct sockaddr_in saddr;
dprintk("lockd: SM_NOTIFY called\n"); dprintk("lockd: SM_NOTIFY called\n");
if (!nlm_privileged_requester(rqstp)) { if (!nlm_privileged_requester(rqstp)) {
...@@ -430,14 +426,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, ...@@ -430,14 +426,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
return rpc_system_err; return rpc_system_err;
} }
/* Obtain the host pointer for this NFS server and try to nlm_host_rebooted(argp);
* reclaim all locks we hold on this server.
*/
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = argp->addr;
nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
return rpc_success; return rpc_success;
} }
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
#include <linux/nfsd/nfsd.h> #include <linux/nfsd/nfsd.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/share.h> #include <linux/lockd/share.h>
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
...@@ -451,8 +449,6 @@ static __be32 ...@@ -451,8 +449,6 @@ static __be32
nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
void *resp) void *resp)
{ {
struct sockaddr_in saddr;
dprintk("lockd: SM_NOTIFY called\n"); dprintk("lockd: SM_NOTIFY called\n");
if (!nlm_privileged_requester(rqstp)) { if (!nlm_privileged_requester(rqstp)) {
...@@ -462,14 +458,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, ...@@ -462,14 +458,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
return rpc_system_err; return rpc_system_err;
} }
/* Obtain the host pointer for this NFS server and try to nlm_host_rebooted(argp);
* reclaim all locks we hold on this server.
*/
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = argp->addr;
nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
return rpc_success; return rpc_success;
} }
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/nfsd/export.h> #include <linux/nfsd/export.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/share.h> #include <linux/lockd/share.h>
#include <linux/lockd/sm_inter.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/sunrpc/stats.h> #include <linux/sunrpc/stats.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_XDR #define NLMDBG_FACILITY NLMDBG_XDR
...@@ -349,8 +348,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) ...@@ -349,8 +348,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
return 0; return 0;
argp->state = ntohl(*p++); argp->state = ntohl(*p++);
/* Preserve the address in network byte order */ memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
argp->addr = *p++; p += XDR_QUADLEN(SM_PRIV_SIZE);
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/sunrpc/stats.h> #include <linux/sunrpc/stats.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_XDR #define NLMDBG_FACILITY NLMDBG_XDR
...@@ -356,8 +355,8 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp ...@@ -356,8 +355,8 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
return 0; return 0;
argp->state = ntohl(*p++); argp->state = ntohl(*p++);
/* Preserve the address in network byte order */ memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
argp->addr = *p++; p += XDR_QUADLEN(SM_PRIV_SIZE);
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
......
...@@ -76,10 +76,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) ...@@ -76,10 +76,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
ret = set_groups(new, gi); ret = set_groups(new, gi);
put_group_info(gi); put_group_info(gi);
if (!ret) if (ret < 0)
goto error; goto error;
if (new->uid) if (new->fsuid)
new->cap_effective = cap_drop_nfsd_set(new->cap_effective); new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
else else
new->cap_effective = cap_raise_nfsd_set(new->cap_effective, new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
......
...@@ -53,9 +53,6 @@ ...@@ -53,9 +53,6 @@
#define NFSPROC4_CB_NULL 0 #define NFSPROC4_CB_NULL 0
#define NFSPROC4_CB_COMPOUND 1 #define NFSPROC4_CB_COMPOUND 1
/* declarations */
static const struct rpc_call_ops nfs4_cb_null_ops;
/* Index of predefined Linux callback client operations */ /* Index of predefined Linux callback client operations */
enum { enum {
......
...@@ -946,6 +946,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -946,6 +946,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
nfsd4_encode_operation(resp, op); nfsd4_encode_operation(resp, op);
status = op->status; status = op->status;
} }
dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
args->ops, args->opcnt, resp->opcnt, op->opnum,
be32_to_cpu(status));
if (cstate->replay_owner) { if (cstate->replay_owner) {
nfs4_put_stateowner(cstate->replay_owner); nfs4_put_stateowner(cstate->replay_owner);
cstate->replay_owner = NULL; cstate->replay_owner = NULL;
......
...@@ -116,9 +116,9 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) ...@@ -116,9 +116,9 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
md5_to_hex(dname, cksum.data); md5_to_hex(dname, cksum.data);
kfree(cksum.data);
status = nfs_ok; status = nfs_ok;
out: out:
kfree(cksum.data);
crypto_free_hash(desc.tfm); crypto_free_hash(desc.tfm);
out_no_tfm: out_no_tfm:
return status; return status;
......
...@@ -2416,6 +2416,26 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2416,6 +2416,26 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) #define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS)
#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) #define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1)
static inline u64
end_offset(u64 start, u64 len)
{
u64 end;
end = start + len;
return end >= start ? end: NFS4_MAX_UINT64;
}
/* last octet in a range */
static inline u64
last_byte_offset(u64 start, u64 len)
{
u64 end;
BUG_ON(!len);
end = start + len;
return end > start ? end - 1: NFS4_MAX_UINT64;
}
#define lockownerid_hashval(id) \ #define lockownerid_hashval(id) \
((id) & LOCK_HASH_MASK) ((id) & LOCK_HASH_MASK)
...@@ -2435,13 +2455,13 @@ static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; ...@@ -2435,13 +2455,13 @@ static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
static struct nfs4_stateid * static struct nfs4_stateid *
find_stateid(stateid_t *stid, int flags) find_stateid(stateid_t *stid, int flags)
{ {
struct nfs4_stateid *local = NULL; struct nfs4_stateid *local;
u32 st_id = stid->si_stateownerid; u32 st_id = stid->si_stateownerid;
u32 f_id = stid->si_fileid; u32 f_id = stid->si_fileid;
unsigned int hashval; unsigned int hashval;
dprintk("NFSD: find_stateid flags 0x%x\n",flags); dprintk("NFSD: find_stateid flags 0x%x\n",flags);
if ((flags & LOCK_STATE) || (flags & RD_STATE) || (flags & WR_STATE)) { if (flags & (LOCK_STATE | RD_STATE | WR_STATE)) {
hashval = stateid_hashval(st_id, f_id); hashval = stateid_hashval(st_id, f_id);
list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
if ((local->st_stateid.si_stateownerid == st_id) && if ((local->st_stateid.si_stateownerid == st_id) &&
...@@ -2449,7 +2469,8 @@ find_stateid(stateid_t *stid, int flags) ...@@ -2449,7 +2469,8 @@ find_stateid(stateid_t *stid, int flags)
return local; return local;
} }
} }
if ((flags & OPEN_STATE) || (flags & RD_STATE) || (flags & WR_STATE)) {
if (flags & (OPEN_STATE | RD_STATE | WR_STATE)) {
hashval = stateid_hashval(st_id, f_id); hashval = stateid_hashval(st_id, f_id);
list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
if ((local->st_stateid.si_stateownerid == st_id) && if ((local->st_stateid.si_stateownerid == st_id) &&
...@@ -2518,8 +2539,8 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) ...@@ -2518,8 +2539,8 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
deny->ld_clientid.cl_id = 0; deny->ld_clientid.cl_id = 0;
} }
deny->ld_start = fl->fl_start; deny->ld_start = fl->fl_start;
deny->ld_length = ~(u64)0; deny->ld_length = NFS4_MAX_UINT64;
if (fl->fl_end != ~(u64)0) if (fl->fl_end != NFS4_MAX_UINT64)
deny->ld_length = fl->fl_end - fl->fl_start + 1; deny->ld_length = fl->fl_end - fl->fl_start + 1;
deny->ld_type = NFS4_READ_LT; deny->ld_type = NFS4_READ_LT;
if (fl->fl_type != F_RDLCK) if (fl->fl_type != F_RDLCK)
...@@ -2616,7 +2637,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc ...@@ -2616,7 +2637,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
static int static int
check_lock_length(u64 offset, u64 length) check_lock_length(u64 offset, u64 length)
{ {
return ((length == 0) || ((length != ~(u64)0) && return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
LOFF_OVERFLOW(offset, length))); LOFF_OVERFLOW(offset, length)));
} }
...@@ -2736,11 +2757,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2736,11 +2757,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
file_lock.fl_lmops = &nfsd_posix_mng_ops; file_lock.fl_lmops = &nfsd_posix_mng_ops;
file_lock.fl_start = lock->lk_offset; file_lock.fl_start = lock->lk_offset;
if ((lock->lk_length == ~(u64)0) || file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
LOFF_OVERFLOW(lock->lk_offset, lock->lk_length))
file_lock.fl_end = ~(u64)0;
else
file_lock.fl_end = lock->lk_offset + lock->lk_length - 1;
nfs4_transform_lock_offset(&file_lock); nfs4_transform_lock_offset(&file_lock);
/* /*
...@@ -2780,6 +2797,25 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2780,6 +2797,25 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return status; return status;
} }
/*
* The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
* so we do a temporary open here just to get an open file to pass to
* vfs_test_lock. (Arguably perhaps test_lock should be done with an
* inode operation.)
*/
static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
{
struct file *file;
int err;
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
if (err)
return err;
err = vfs_test_lock(file, lock);
nfsd_close(file);
return err;
}
/* /*
* LOCKT operation * LOCKT operation
*/ */
...@@ -2788,7 +2824,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2788,7 +2824,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_lockt *lockt) struct nfsd4_lockt *lockt)
{ {
struct inode *inode; struct inode *inode;
struct file file;
struct file_lock file_lock; struct file_lock file_lock;
int error; int error;
__be32 status; __be32 status;
...@@ -2839,23 +2874,12 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2839,23 +2874,12 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
file_lock.fl_lmops = &nfsd_posix_mng_ops; file_lock.fl_lmops = &nfsd_posix_mng_ops;
file_lock.fl_start = lockt->lt_offset; file_lock.fl_start = lockt->lt_offset;
if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length)) file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
file_lock.fl_end = ~(u64)0;
else
file_lock.fl_end = lockt->lt_offset + lockt->lt_length - 1;
nfs4_transform_lock_offset(&file_lock); nfs4_transform_lock_offset(&file_lock);
/* vfs_test_lock uses the struct file _only_ to resolve the inode.
* since LOCKT doesn't require an OPEN, and therefore a struct
* file may not exist, pass vfs_test_lock a struct file with
* only the dentry:inode set.
*/
memset(&file, 0, sizeof (struct file));
file.f_path.dentry = cstate->current_fh.fh_dentry;
status = nfs_ok; status = nfs_ok;
error = vfs_test_lock(&file, &file_lock); error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
if (error) { if (error) {
status = nfserrno(error); status = nfserrno(error);
goto out; goto out;
...@@ -2906,10 +2930,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2906,10 +2930,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
file_lock.fl_lmops = &nfsd_posix_mng_ops; file_lock.fl_lmops = &nfsd_posix_mng_ops;
file_lock.fl_start = locku->lu_offset; file_lock.fl_start = locku->lu_offset;
if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length)) file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
file_lock.fl_end = ~(u64)0;
else
file_lock.fl_end = locku->lu_offset + locku->lu_length - 1;
nfs4_transform_lock_offset(&file_lock); nfs4_transform_lock_offset(&file_lock);
/* /*
......
/* /*
* fs/nfs/nfs4xdr.c
*
* Server-side XDR for NFSv4 * Server-side XDR for NFSv4
* *
* Copyright (c) 2002 The Regents of the University of Michigan. * Copyright (c) 2002 The Regents of the University of Michigan.
......
This diff is collapsed.
...@@ -258,14 +258,32 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) ...@@ -258,14 +258,32 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
return error; return error;
} }
/* /**
* Perform sanity checks on the dentry in a client's file handle. * fh_verify - filehandle lookup and access checking
* @rqstp: pointer to current rpc request
* @fhp: filehandle to be verified
* @type: expected type of object pointed to by filehandle
* @access: type of access needed to object
*
* Look up a dentry from the on-the-wire filehandle, check the client's
* access to the export, and set the current task's credentials.
*
* Regardless of success or failure of fh_verify(), fh_put() should be
* called on @fhp when the caller is finished with the filehandle.
* *
* Note that the file handle dentry may need to be freed even after * fh_verify() may be called multiple times on a given filehandle, for
* an error return. * example, when processing an NFSv4 compound. The first call will look
* up a dentry using the on-the-wire filehandle. Subsequent calls will
* skip the lookup and just perform the other checks and possibly change
* the current task's credentials.
* *
* This is only called at the start of an nfsproc call, so fhp points to * @type specifies the type of object expected using one of the S_IF*
* a svc_fh which is all 0 except for the over-the-wire file handle. * constants defined in include/linux/stat.h. The caller may use zero
* to indicate that it doesn't care, or a negative integer to indicate
* that it expects something not of the given type.
*
* @access is formed from the NFSD_MAY_* constants defined in
* include/linux/nfsd/nfsd.h.
*/ */
__be32 __be32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
...@@ -466,6 +484,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -466,6 +484,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
goto retry; goto retry;
break; break;
} }
} else if (exp->ex_flags & NFSEXP_FSID) {
fsid_type = FSID_NUM;
} else if (exp->ex_uuid) { } else if (exp->ex_uuid) {
if (fhp->fh_maxsize >= 64) { if (fhp->fh_maxsize >= 64) {
if (root_export) if (root_export)
...@@ -478,9 +498,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, ...@@ -478,9 +498,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
else else
fsid_type = FSID_UUID4_INUM; fsid_type = FSID_UUID4_INUM;
} }
} else if (exp->ex_flags & NFSEXP_FSID) } else if (!old_valid_dev(ex_dev))
fsid_type = FSID_NUM;
else if (!old_valid_dev(ex_dev))
/* for newer device numbers, we must use a newer fsid format */ /* for newer device numbers, we must use a newer fsid format */
fsid_type = FSID_ENCODE_DEV; fsid_type = FSID_ENCODE_DEV;
else else
......
...@@ -622,6 +622,7 @@ nfserrno (int errno) ...@@ -622,6 +622,7 @@ nfserrno (int errno)
{ nfserr_badname, -ESRCH }, { nfserr_badname, -ESRCH },
{ nfserr_io, -ETXTBSY }, { nfserr_io, -ETXTBSY },
{ nfserr_notsupp, -EOPNOTSUPP }, { nfserr_notsupp, -EOPNOTSUPP },
{ nfserr_toosmall, -ETOOSMALL },
}; };
int i; int i;
......
...@@ -744,16 +744,44 @@ nfsd_close(struct file *filp) ...@@ -744,16 +744,44 @@ nfsd_close(struct file *filp)
fput(filp); fput(filp);
} }
/*
* Sync a file
* As this calls fsync (not fdatasync) there is no need for a write_inode
* after it.
*/
static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
const struct file_operations *fop)
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
int err;
err = filemap_fdatawrite(inode->i_mapping);
if (err == 0 && fop && (fsync = fop->fsync))
err = fsync(filp, dp, 0);
if (err == 0)
err = filemap_fdatawait(inode->i_mapping);
return err;
}
static int static int
nfsd_sync(struct file *filp) nfsd_sync(struct file *filp)
{ {
return vfs_fsync(filp, filp->f_path.dentry, 0); int err;
struct inode *inode = filp->f_path.dentry->d_inode;
dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
mutex_lock(&inode->i_mutex);
err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
mutex_unlock(&inode->i_mutex);
return err;
} }
int int
nfsd_sync_dir(struct dentry *dentry) nfsd_sync_dir(struct dentry *dp)
{ {
return vfs_fsync(NULL, dentry, 0); return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
} }
/* /*
......
...@@ -43,8 +43,8 @@ struct nlm_host { ...@@ -43,8 +43,8 @@ struct nlm_host {
struct sockaddr_storage h_addr; /* peer address */ struct sockaddr_storage h_addr; /* peer address */
size_t h_addrlen; size_t h_addrlen;
struct sockaddr_storage h_srcaddr; /* our address (optional) */ struct sockaddr_storage h_srcaddr; /* our address (optional) */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ struct rpc_clnt *h_rpcclnt; /* RPC client to talk to peer */
char * h_name; /* remote hostname */ char *h_name; /* remote hostname */
u32 h_version; /* interface version */ u32 h_version; /* interface version */
unsigned short h_proto; /* transport proto */ unsigned short h_proto; /* transport proto */
unsigned short h_reclaiming : 1, unsigned short h_reclaiming : 1,
...@@ -64,21 +64,29 @@ struct nlm_host { ...@@ -64,21 +64,29 @@ struct nlm_host {
spinlock_t h_lock; spinlock_t h_lock;
struct list_head h_granted; /* Locks in GRANTED state */ struct list_head h_granted; /* Locks in GRANTED state */
struct list_head h_reclaim; /* Locks in RECLAIM state */ struct list_head h_reclaim; /* Locks in RECLAIM state */
struct nsm_handle * h_nsmhandle; /* NSM status handle */ struct nsm_handle *h_nsmhandle; /* NSM status handle */
char *h_addrbuf; /* address eyecatcher */
char h_addrbuf[48], /* address eyecatchers */
h_srcaddrbuf[48];
}; };
/*
* The largest string sm_addrbuf should hold is a full-size IPv6 address
* (no "::" anywhere) with a scope ID. The buffer size is computed to
* hold eight groups of colon-separated four-hex-digit numbers, a
* percent sign, a scope id (at most 32 bits, in decimal), and NUL.
*/
#define NSM_ADDRBUF ((8 * 4 + 7) + (1 + 10) + 1)
struct nsm_handle { struct nsm_handle {
struct list_head sm_link; struct list_head sm_link;
atomic_t sm_count; atomic_t sm_count;
char * sm_name; char *sm_mon_name;
char *sm_name;
struct sockaddr_storage sm_addr; struct sockaddr_storage sm_addr;
size_t sm_addrlen; size_t sm_addrlen;
unsigned int sm_monitored : 1, unsigned int sm_monitored : 1,
sm_sticky : 1; /* don't unmonitor */ sm_sticky : 1; /* don't unmonitor */
char sm_addrbuf[48]; /* address eyecatcher */ struct nsm_private sm_priv;
char sm_addrbuf[NSM_ADDRBUF];
}; };
/* /*
...@@ -104,16 +112,6 @@ static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host) ...@@ -104,16 +112,6 @@ static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
return (struct sockaddr *)&host->h_srcaddr; return (struct sockaddr *)&host->h_srcaddr;
} }
static inline struct sockaddr_in *nsm_addr_in(const struct nsm_handle *handle)
{
return (struct sockaddr_in *)&handle->sm_addr;
}
static inline struct sockaddr *nsm_addr(const struct nsm_handle *handle)
{
return (struct sockaddr *)&handle->sm_addr;
}
/* /*
* Map an fl_owner_t into a unique 32-bit "pid" * Map an fl_owner_t into a unique 32-bit "pid"
*/ */
...@@ -197,6 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[]; ...@@ -197,6 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[];
extern int nlmsvc_grace_period; extern int nlmsvc_grace_period;
extern unsigned long nlmsvc_timeout; extern unsigned long nlmsvc_timeout;
extern int nsm_use_hostnames; extern int nsm_use_hostnames;
extern int nsm_local_state;
/* /*
* Lockd client functions * Lockd client functions
...@@ -231,10 +230,20 @@ void nlm_rebind_host(struct nlm_host *); ...@@ -231,10 +230,20 @@ void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_release_host(struct nlm_host *); void nlm_release_host(struct nlm_host *);
void nlm_shutdown_hosts(void); void nlm_shutdown_hosts(void);
extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, void nlm_host_rebooted(const struct nlm_reboot *);
unsigned int, u32);
void nsm_release(struct nsm_handle *);
/*
* Host monitoring
*/
int nsm_monitor(const struct nlm_host *host);
void nsm_unmonitor(const struct nlm_host *host);
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
const size_t salen,
const char *hostname,
const size_t hostname_len);
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info);
void nsm_release(struct nsm_handle *nsm);
/* /*
* This is used in garbage collection and resource reclaim * This is used in garbage collection and resource reclaim
...@@ -282,16 +291,25 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) ...@@ -282,16 +291,25 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
static inline int __nlm_privileged_request4(const struct sockaddr *sap) static inline int __nlm_privileged_request4(const struct sockaddr *sap)
{ {
const struct sockaddr_in *sin = (struct sockaddr_in *)sap; const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
(ntohs(sin->sin_port) < 1024); if (ntohs(sin->sin_port) > 1023)
return 0;
return ipv4_is_loopback(sin->sin_addr.s_addr);
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static inline int __nlm_privileged_request6(const struct sockaddr *sap) static inline int __nlm_privileged_request6(const struct sockaddr *sap)
{ {
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) &&
(ntohs(sin6->sin6_port) < 1024); if (ntohs(sin6->sin6_port) > 1023)
return 0;
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED)
return ipv4_is_loopback(sin6->sin6_addr.s6_addr32[3]);
return ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK;
} }
#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
static inline int __nlm_privileged_request6(const struct sockaddr *sap) static inline int __nlm_privileged_request6(const struct sockaddr *sap)
......
/*
* linux/include/linux/lockd/sm_inter.h
*
* Declarations for the kernel statd client.
*
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
#ifndef LINUX_LOCKD_SM_INTER_H
#define LINUX_LOCKD_SM_INTER_H
#define SM_PROGRAM 100024
#define SM_VERSION 1
#define SM_STAT 1
#define SM_MON 2
#define SM_UNMON 3
#define SM_UNMON_ALL 4
#define SM_SIMU_CRASH 5
#define SM_NOTIFY 6
#define SM_MAXSTRLEN 1024
#define SM_PRIV_SIZE 16
/*
* Arguments for all calls to statd
*/
struct nsm_args {
__be32 addr; /* remote address */
u32 prog; /* RPC callback info */
u32 vers;
u32 proc;
char * mon_name;
};
/*
* Result returned by statd
*/
struct nsm_res {
u32 status;
u32 state;
};
int nsm_monitor(struct nlm_host *);
int nsm_unmonitor(struct nlm_host *);
extern int nsm_local_state;
#endif /* LINUX_LOCKD_SM_INTER_H */
...@@ -13,6 +13,13 @@ ...@@ -13,6 +13,13 @@
#include <linux/nfs.h> #include <linux/nfs.h>
#include <linux/sunrpc/xdr.h> #include <linux/sunrpc/xdr.h>
#define SM_MAXSTRLEN 1024
#define SM_PRIV_SIZE 16
struct nsm_private {
unsigned char data[SM_PRIV_SIZE];
};
struct svc_rqst; struct svc_rqst;
#define NLM_MAXCOOKIELEN 32 #define NLM_MAXCOOKIELEN 32
...@@ -77,10 +84,10 @@ struct nlm_res { ...@@ -77,10 +84,10 @@ struct nlm_res {
* statd callback when client has rebooted * statd callback when client has rebooted
*/ */
struct nlm_reboot { struct nlm_reboot {
char * mon; char *mon;
unsigned int len; unsigned int len;
u32 state; u32 state;
__be32 addr; struct nsm_private priv;
}; };
/* /*
......
...@@ -88,6 +88,8 @@ ...@@ -88,6 +88,8 @@
#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0 #define NFS4_ACE_GENERIC_EXECUTE 0x001200A0
#define NFS4_ACE_MASK_ALL 0x001F01FF #define NFS4_ACE_MASK_ALL 0x001F01FF
#define NFS4_MAX_UINT64 (~(u64)0)
enum nfs4_acl_whotype { enum nfs4_acl_whotype {
NFS4_ACL_WHO_NAMED = 0, NFS4_ACL_WHO_NAMED = 0,
NFS4_ACL_WHO_OWNER, NFS4_ACL_WHO_OWNER,
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
/* /*
* nfsd version * nfsd version
*/ */
#define NFSD_VERSION "0.5"
#define NFSD_SUPPORTED_MINOR_VERSION 0 #define NFSD_SUPPORTED_MINOR_VERSION 0
/* /*
......
...@@ -68,6 +68,10 @@ struct nfs_fhbase_old { ...@@ -68,6 +68,10 @@ struct nfs_fhbase_old {
* 1 - 4 byte user specified identifier * 1 - 4 byte user specified identifier
* 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
* 3 - 4 byte device id, encoded for user-space, 4 byte inode number * 3 - 4 byte device id, encoded for user-space, 4 byte inode number
* 4 - 4 byte inode number and 4 byte uuid
* 5 - 8 byte uuid
* 6 - 16 byte uuid
* 7 - 8 byte inode number and 16 byte uuid
* *
* The fileid_type identified how the file within the filesystem is encoded. * The fileid_type identified how the file within the filesystem is encoded.
* This is (will be) passed to, and set by, the underlying filesystem if it supports * This is (will be) passed to, and set by, the underlying filesystem if it supports
......
...@@ -58,10 +58,13 @@ struct svc_serv { ...@@ -58,10 +58,13 @@ struct svc_serv {
struct svc_stat * sv_stats; /* RPC statistics */ struct svc_stat * sv_stats; /* RPC statistics */
spinlock_t sv_lock; spinlock_t sv_lock;
unsigned int sv_nrthreads; /* # of server threads */ unsigned int sv_nrthreads; /* # of server threads */
unsigned int sv_maxconn; /* max connections allowed or
* '0' causing max to be based
* on number of threads. */
unsigned int sv_max_payload; /* datagram payload size */ unsigned int sv_max_payload; /* datagram payload size */
unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */ unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
unsigned int sv_xdrsize; /* XDR buffer size */ unsigned int sv_xdrsize; /* XDR buffer size */
struct list_head sv_permsocks; /* all permanent sockets */ struct list_head sv_permsocks; /* all permanent sockets */
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 */
......
...@@ -98,7 +98,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, ...@@ -98,7 +98,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
return new; return new;
} }
EXPORT_SYMBOL(sunrpc_cache_lookup); EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
static void queue_loose(struct cache_detail *detail, struct cache_head *ch); static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
...@@ -173,7 +173,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, ...@@ -173,7 +173,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
cache_put(old, detail); cache_put(old, detail);
return tmp; return tmp;
} }
EXPORT_SYMBOL(sunrpc_cache_update); EXPORT_SYMBOL_GPL(sunrpc_cache_update);
static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
/* /*
...@@ -245,7 +245,7 @@ int cache_check(struct cache_detail *detail, ...@@ -245,7 +245,7 @@ int cache_check(struct cache_detail *detail,
cache_put(h, detail); cache_put(h, detail);
return rv; return rv;
} }
EXPORT_SYMBOL(cache_check); EXPORT_SYMBOL_GPL(cache_check);
/* /*
* caches need to be periodically cleaned. * caches need to be periodically cleaned.
...@@ -373,7 +373,7 @@ int cache_register(struct cache_detail *cd) ...@@ -373,7 +373,7 @@ int cache_register(struct cache_detail *cd)
schedule_delayed_work(&cache_cleaner, 0); schedule_delayed_work(&cache_cleaner, 0);
return 0; return 0;
} }
EXPORT_SYMBOL(cache_register); EXPORT_SYMBOL_GPL(cache_register);
void cache_unregister(struct cache_detail *cd) void cache_unregister(struct cache_detail *cd)
{ {
...@@ -399,7 +399,7 @@ void cache_unregister(struct cache_detail *cd) ...@@ -399,7 +399,7 @@ void cache_unregister(struct cache_detail *cd)
out: out:
printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
} }
EXPORT_SYMBOL(cache_unregister); EXPORT_SYMBOL_GPL(cache_unregister);
/* clean cache tries to find something to clean /* clean cache tries to find something to clean
* and cleans it. * and cleans it.
...@@ -514,7 +514,7 @@ void cache_flush(void) ...@@ -514,7 +514,7 @@ void cache_flush(void)
while (cache_clean() != -1) while (cache_clean() != -1)
cond_resched(); cond_resched();
} }
EXPORT_SYMBOL(cache_flush); EXPORT_SYMBOL_GPL(cache_flush);
void cache_purge(struct cache_detail *detail) void cache_purge(struct cache_detail *detail)
{ {
...@@ -523,7 +523,7 @@ void cache_purge(struct cache_detail *detail) ...@@ -523,7 +523,7 @@ void cache_purge(struct cache_detail *detail)
cache_flush(); cache_flush();
detail->flush_time = 1; detail->flush_time = 1;
} }
EXPORT_SYMBOL(cache_purge); EXPORT_SYMBOL_GPL(cache_purge);
/* /*
...@@ -988,7 +988,7 @@ void qword_add(char **bpp, int *lp, char *str) ...@@ -988,7 +988,7 @@ void qword_add(char **bpp, int *lp, char *str)
*bpp = bp; *bpp = bp;
*lp = len; *lp = len;
} }
EXPORT_SYMBOL(qword_add); EXPORT_SYMBOL_GPL(qword_add);
void qword_addhex(char **bpp, int *lp, char *buf, int blen) void qword_addhex(char **bpp, int *lp, char *buf, int blen)
{ {
...@@ -1017,7 +1017,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen) ...@@ -1017,7 +1017,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
*bpp = bp; *bpp = bp;
*lp = len; *lp = len;
} }
EXPORT_SYMBOL(qword_addhex); EXPORT_SYMBOL_GPL(qword_addhex);
static void warn_no_listener(struct cache_detail *detail) static void warn_no_listener(struct cache_detail *detail)
{ {
...@@ -1140,7 +1140,7 @@ int qword_get(char **bpp, char *dest, int bufsize) ...@@ -1140,7 +1140,7 @@ int qword_get(char **bpp, char *dest, int bufsize)
*dest = '\0'; *dest = '\0';
return len; return len;
} }
EXPORT_SYMBOL(qword_get); EXPORT_SYMBOL_GPL(qword_get);
/* /*
......
...@@ -106,7 +106,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) { ...@@ -106,7 +106,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
seq_putc(seq, '\n'); seq_putc(seq, '\n');
} }
} }
EXPORT_SYMBOL(svc_seq_show); EXPORT_SYMBOL_GPL(svc_seq_show);
/** /**
* rpc_alloc_iostats - allocate an rpc_iostats structure * rpc_alloc_iostats - allocate an rpc_iostats structure
...@@ -249,14 +249,14 @@ svc_proc_register(struct svc_stat *statp, const struct file_operations *fops) ...@@ -249,14 +249,14 @@ svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
{ {
return do_register(statp->program->pg_name, statp, fops); return do_register(statp->program->pg_name, statp, fops);
} }
EXPORT_SYMBOL(svc_proc_register); EXPORT_SYMBOL_GPL(svc_proc_register);
void void
svc_proc_unregister(const char *name) svc_proc_unregister(const char *name)
{ {
remove_proc_entry(name, proc_net_rpc); remove_proc_entry(name, proc_net_rpc);
} }
EXPORT_SYMBOL(svc_proc_unregister); EXPORT_SYMBOL_GPL(svc_proc_unregister);
void void
rpc_proc_init(void) rpc_proc_init(void)
......
...@@ -431,7 +431,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize, ...@@ -431,7 +431,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
{ {
return __svc_create(prog, bufsize, /*npools*/1, family, shutdown); return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
} }
EXPORT_SYMBOL(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,
...@@ -450,7 +450,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, ...@@ -450,7 +450,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
return serv; return serv;
} }
EXPORT_SYMBOL(svc_create_pooled); EXPORT_SYMBOL_GPL(svc_create_pooled);
/* /*
* Destroy an RPC service. Should be called with appropriate locking to * Destroy an RPC service. Should be called with appropriate locking to
...@@ -492,7 +492,7 @@ svc_destroy(struct svc_serv *serv) ...@@ -492,7 +492,7 @@ svc_destroy(struct svc_serv *serv)
kfree(serv->sv_pools); kfree(serv->sv_pools);
kfree(serv); kfree(serv);
} }
EXPORT_SYMBOL(svc_destroy); EXPORT_SYMBOL_GPL(svc_destroy);
/* /*
* Allocate an RPC server's buffer space. * Allocate an RPC server's buffer space.
...@@ -567,7 +567,7 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool) ...@@ -567,7 +567,7 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
out_enomem: out_enomem:
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
EXPORT_SYMBOL(svc_prepare_thread); EXPORT_SYMBOL_GPL(svc_prepare_thread);
/* /*
* Choose a pool in which to create a new thread, for svc_set_num_threads * Choose a pool in which to create a new thread, for svc_set_num_threads
...@@ -689,7 +689,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) ...@@ -689,7 +689,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
return error; return error;
} }
EXPORT_SYMBOL(svc_set_num_threads); EXPORT_SYMBOL_GPL(svc_set_num_threads);
/* /*
* Called from a server thread as it's exiting. Caller must hold the BKL or * Called from a server thread as it's exiting. Caller must hold the BKL or
...@@ -717,7 +717,7 @@ svc_exit_thread(struct svc_rqst *rqstp) ...@@ -717,7 +717,7 @@ svc_exit_thread(struct svc_rqst *rqstp)
if (serv) if (serv)
svc_destroy(serv); svc_destroy(serv);
} }
EXPORT_SYMBOL(svc_exit_thread); EXPORT_SYMBOL_GPL(svc_exit_thread);
#ifdef CONFIG_SUNRPC_REGISTER_V4 #ifdef CONFIG_SUNRPC_REGISTER_V4
...@@ -1231,7 +1231,7 @@ svc_process(struct svc_rqst *rqstp) ...@@ -1231,7 +1231,7 @@ svc_process(struct svc_rqst *rqstp)
svc_putnl(resv, ntohl(rpc_stat)); svc_putnl(resv, ntohl(rpc_stat));
goto sendit; goto sendit;
} }
EXPORT_SYMBOL(svc_process); EXPORT_SYMBOL_GPL(svc_process);
/* /*
* Return (transport-specific) limit on the rpc payload. * Return (transport-specific) limit on the rpc payload.
......
...@@ -440,7 +440,7 @@ void svc_reserve(struct svc_rqst *rqstp, int space) ...@@ -440,7 +440,7 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
svc_xprt_enqueue(xprt); svc_xprt_enqueue(xprt);
} }
} }
EXPORT_SYMBOL(svc_reserve); EXPORT_SYMBOL_GPL(svc_reserve);
static void svc_xprt_release(struct svc_rqst *rqstp) static void svc_xprt_release(struct svc_rqst *rqstp)
{ {
...@@ -448,6 +448,9 @@ static void svc_xprt_release(struct svc_rqst *rqstp) ...@@ -448,6 +448,9 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp); rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
kfree(rqstp->rq_deferred);
rqstp->rq_deferred = NULL;
svc_free_res_pages(rqstp); svc_free_res_pages(rqstp);
rqstp->rq_res.page_len = 0; rqstp->rq_res.page_len = 0;
rqstp->rq_res.page_base = 0; rqstp->rq_res.page_base = 0;
...@@ -498,7 +501,7 @@ void svc_wake_up(struct svc_serv *serv) ...@@ -498,7 +501,7 @@ void svc_wake_up(struct svc_serv *serv)
spin_unlock_bh(&pool->sp_lock); spin_unlock_bh(&pool->sp_lock);
} }
} }
EXPORT_SYMBOL(svc_wake_up); EXPORT_SYMBOL_GPL(svc_wake_up);
int svc_port_is_privileged(struct sockaddr *sin) int svc_port_is_privileged(struct sockaddr *sin)
{ {
...@@ -515,8 +518,10 @@ int svc_port_is_privileged(struct sockaddr *sin) ...@@ -515,8 +518,10 @@ int svc_port_is_privileged(struct sockaddr *sin)
} }
/* /*
* Make sure that we don't have too many active connections. If we * Make sure that we don't have too many active connections. If we have,
* have, something must be dropped. * something must be dropped. It's not clear what will happen if we allow
* "too many" connections, but when dealing with network-facing software,
* we have to code defensively. Here we do that by imposing hard limits.
* *
* There's no point in trying to do random drop here for DoS * There's no point in trying to do random drop here for DoS
* prevention. The NFS clients does 1 reconnect in 15 seconds. An * prevention. The NFS clients does 1 reconnect in 15 seconds. An
...@@ -525,19 +530,27 @@ int svc_port_is_privileged(struct sockaddr *sin) ...@@ -525,19 +530,27 @@ int svc_port_is_privileged(struct sockaddr *sin)
* The only somewhat efficient mechanism would be if drop old * The only somewhat efficient mechanism would be if drop old
* connections from the same IP first. But right now we don't even * connections from the same IP first. But right now we don't even
* record the client IP in svc_sock. * record the client IP in svc_sock.
*
* single-threaded services that expect a lot of clients will probably
* need to set sv_maxconn to override the default value which is based
* on the number of threads
*/ */
static void svc_check_conn_limits(struct svc_serv *serv) static void svc_check_conn_limits(struct svc_serv *serv)
{ {
if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) { unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn :
(serv->sv_nrthreads+3) * 20;
if (serv->sv_tmpcnt > limit) {
struct svc_xprt *xprt = NULL; struct svc_xprt *xprt = NULL;
spin_lock_bh(&serv->sv_lock); spin_lock_bh(&serv->sv_lock);
if (!list_empty(&serv->sv_tempsocks)) { if (!list_empty(&serv->sv_tempsocks)) {
if (net_ratelimit()) { if (net_ratelimit()) {
/* Try to help the admin */ /* Try to help the admin */
printk(KERN_NOTICE "%s: too many open " printk(KERN_NOTICE "%s: too many open "
"connections, consider increasing the " "connections, consider increasing %s\n",
"number of nfsd threads\n", serv->sv_name, serv->sv_maxconn ?
serv->sv_name); "the max number of connections." :
"the number of threads.");
} }
/* /*
* Always select the oldest connection. It's not fair, * Always select the oldest connection. It's not fair,
...@@ -730,7 +743,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -730,7 +743,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
serv->sv_stats->netcnt++; serv->sv_stats->netcnt++;
return len; return len;
} }
EXPORT_SYMBOL(svc_recv); EXPORT_SYMBOL_GPL(svc_recv);
/* /*
* Drop request * Drop request
...@@ -740,7 +753,7 @@ void svc_drop(struct svc_rqst *rqstp) ...@@ -740,7 +753,7 @@ void svc_drop(struct svc_rqst *rqstp)
dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt); dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
svc_xprt_release(rqstp); svc_xprt_release(rqstp);
} }
EXPORT_SYMBOL(svc_drop); EXPORT_SYMBOL_GPL(svc_drop);
/* /*
* Return reply to client. * Return reply to client.
...@@ -837,6 +850,11 @@ static void svc_age_temp_xprts(unsigned long closure) ...@@ -837,6 +850,11 @@ static void svc_age_temp_xprts(unsigned long closure)
void svc_delete_xprt(struct svc_xprt *xprt) void svc_delete_xprt(struct svc_xprt *xprt)
{ {
struct svc_serv *serv = xprt->xpt_server; struct svc_serv *serv = xprt->xpt_server;
struct svc_deferred_req *dr;
/* Only do this once */
if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
return;
dprintk("svc: svc_delete_xprt(%p)\n", xprt); dprintk("svc: svc_delete_xprt(%p)\n", xprt);
xprt->xpt_ops->xpo_detach(xprt); xprt->xpt_ops->xpo_detach(xprt);
...@@ -851,12 +869,16 @@ void svc_delete_xprt(struct svc_xprt *xprt) ...@@ -851,12 +869,16 @@ void svc_delete_xprt(struct svc_xprt *xprt)
* while still attached to a queue, the queue itself * while still attached to a queue, the queue itself
* is about to be destroyed (in svc_destroy). * is about to be destroyed (in svc_destroy).
*/ */
if (!test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) { if (test_bit(XPT_TEMP, &xprt->xpt_flags))
BUG_ON(atomic_read(&xprt->xpt_ref.refcount) < 2); serv->sv_tmpcnt--;
if (test_bit(XPT_TEMP, &xprt->xpt_flags))
serv->sv_tmpcnt--; for (dr = svc_deferred_dequeue(xprt); dr;
dr = svc_deferred_dequeue(xprt)) {
svc_xprt_put(xprt); svc_xprt_put(xprt);
kfree(dr);
} }
svc_xprt_put(xprt);
spin_unlock_bh(&serv->sv_lock); spin_unlock_bh(&serv->sv_lock);
} }
...@@ -902,17 +924,19 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many) ...@@ -902,17 +924,19 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
container_of(dreq, struct svc_deferred_req, handle); container_of(dreq, struct svc_deferred_req, handle);
struct svc_xprt *xprt = dr->xprt; struct svc_xprt *xprt = dr->xprt;
if (too_many) { spin_lock(&xprt->xpt_lock);
set_bit(XPT_DEFERRED, &xprt->xpt_flags);
if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) {
spin_unlock(&xprt->xpt_lock);
dprintk("revisit canceled\n");
svc_xprt_put(xprt); svc_xprt_put(xprt);
kfree(dr); kfree(dr);
return; return;
} }
dprintk("revisit queued\n"); dprintk("revisit queued\n");
dr->xprt = NULL; dr->xprt = NULL;
spin_lock(&xprt->xpt_lock);
list_add(&dr->handle.recent, &xprt->xpt_deferred); list_add(&dr->handle.recent, &xprt->xpt_deferred);
spin_unlock(&xprt->xpt_lock); spin_unlock(&xprt->xpt_lock);
set_bit(XPT_DEFERRED, &xprt->xpt_flags);
svc_xprt_enqueue(xprt); svc_xprt_enqueue(xprt);
svc_xprt_put(xprt); svc_xprt_put(xprt);
} }
......
...@@ -57,13 +57,13 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) ...@@ -57,13 +57,13 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
rqstp->rq_authop = aops; rqstp->rq_authop = aops;
return aops->accept(rqstp, authp); return aops->accept(rqstp, authp);
} }
EXPORT_SYMBOL(svc_authenticate); EXPORT_SYMBOL_GPL(svc_authenticate);
int svc_set_client(struct svc_rqst *rqstp) int svc_set_client(struct svc_rqst *rqstp)
{ {
return rqstp->rq_authop->set_client(rqstp); return rqstp->rq_authop->set_client(rqstp);
} }
EXPORT_SYMBOL(svc_set_client); EXPORT_SYMBOL_GPL(svc_set_client);
/* A request, which was authenticated, has now executed. /* A request, which was authenticated, has now executed.
* Time to finalise the credentials and verifier * Time to finalise the credentials and verifier
...@@ -95,7 +95,7 @@ svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops) ...@@ -95,7 +95,7 @@ svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
spin_unlock(&authtab_lock); spin_unlock(&authtab_lock);
return rv; return rv;
} }
EXPORT_SYMBOL(svc_auth_register); EXPORT_SYMBOL_GPL(svc_auth_register);
void void
svc_auth_unregister(rpc_authflavor_t flavor) svc_auth_unregister(rpc_authflavor_t flavor)
...@@ -105,7 +105,7 @@ svc_auth_unregister(rpc_authflavor_t flavor) ...@@ -105,7 +105,7 @@ svc_auth_unregister(rpc_authflavor_t flavor)
authtab[flavor] = NULL; authtab[flavor] = NULL;
spin_unlock(&authtab_lock); spin_unlock(&authtab_lock);
} }
EXPORT_SYMBOL(svc_auth_unregister); EXPORT_SYMBOL_GPL(svc_auth_unregister);
/************************************************** /**************************************************
* 'auth_domains' are stored in a hash table indexed by name. * 'auth_domains' are stored in a hash table indexed by name.
...@@ -132,7 +132,7 @@ void auth_domain_put(struct auth_domain *dom) ...@@ -132,7 +132,7 @@ void auth_domain_put(struct auth_domain *dom)
spin_unlock(&auth_domain_lock); spin_unlock(&auth_domain_lock);
} }
} }
EXPORT_SYMBOL(auth_domain_put); EXPORT_SYMBOL_GPL(auth_domain_put);
struct auth_domain * struct auth_domain *
auth_domain_lookup(char *name, struct auth_domain *new) auth_domain_lookup(char *name, struct auth_domain *new)
...@@ -157,10 +157,10 @@ auth_domain_lookup(char *name, struct auth_domain *new) ...@@ -157,10 +157,10 @@ auth_domain_lookup(char *name, struct auth_domain *new)
spin_unlock(&auth_domain_lock); spin_unlock(&auth_domain_lock);
return new; return new;
} }
EXPORT_SYMBOL(auth_domain_lookup); EXPORT_SYMBOL_GPL(auth_domain_lookup);
struct auth_domain *auth_domain_find(char *name) struct auth_domain *auth_domain_find(char *name)
{ {
return auth_domain_lookup(name, NULL); return auth_domain_lookup(name, NULL);
} }
EXPORT_SYMBOL(auth_domain_find); EXPORT_SYMBOL_GPL(auth_domain_find);
...@@ -64,7 +64,7 @@ struct auth_domain *unix_domain_find(char *name) ...@@ -64,7 +64,7 @@ struct auth_domain *unix_domain_find(char *name)
rv = auth_domain_lookup(name, &new->h); rv = auth_domain_lookup(name, &new->h);
} }
} }
EXPORT_SYMBOL(unix_domain_find); EXPORT_SYMBOL_GPL(unix_domain_find);
static void svcauth_unix_domain_release(struct auth_domain *dom) static void svcauth_unix_domain_release(struct auth_domain *dom)
{ {
...@@ -358,7 +358,7 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom) ...@@ -358,7 +358,7 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
else else
return -ENOMEM; return -ENOMEM;
} }
EXPORT_SYMBOL(auth_unix_add_addr); EXPORT_SYMBOL_GPL(auth_unix_add_addr);
int auth_unix_forget_old(struct auth_domain *dom) int auth_unix_forget_old(struct auth_domain *dom)
{ {
...@@ -370,7 +370,7 @@ int auth_unix_forget_old(struct auth_domain *dom) ...@@ -370,7 +370,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
udom->addr_changes++; udom->addr_changes++;
return 0; return 0;
} }
EXPORT_SYMBOL(auth_unix_forget_old); EXPORT_SYMBOL_GPL(auth_unix_forget_old);
struct auth_domain *auth_unix_lookup(struct in6_addr *addr) struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
{ {
...@@ -395,13 +395,13 @@ struct auth_domain *auth_unix_lookup(struct in6_addr *addr) ...@@ -395,13 +395,13 @@ struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
cache_put(&ipm->h, &ip_map_cache); cache_put(&ipm->h, &ip_map_cache);
return rv; return rv;
} }
EXPORT_SYMBOL(auth_unix_lookup); EXPORT_SYMBOL_GPL(auth_unix_lookup);
void svcauth_unix_purge(void) void svcauth_unix_purge(void)
{ {
cache_purge(&ip_map_cache); cache_purge(&ip_map_cache);
} }
EXPORT_SYMBOL(svcauth_unix_purge); EXPORT_SYMBOL_GPL(svcauth_unix_purge);
static inline struct ip_map * static inline struct ip_map *
ip_map_cached_get(struct svc_rqst *rqstp) ip_map_cached_get(struct svc_rqst *rqstp)
...@@ -714,7 +714,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) ...@@ -714,7 +714,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
return SVC_OK; return SVC_OK;
} }
EXPORT_SYMBOL(svcauth_unix_set_client); EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
static int static int
svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
......
...@@ -59,6 +59,7 @@ static void svc_udp_data_ready(struct sock *, int); ...@@ -59,6 +59,7 @@ static void svc_udp_data_ready(struct sock *, int);
static int svc_udp_recvfrom(struct svc_rqst *); static int svc_udp_recvfrom(struct svc_rqst *);
static int svc_udp_sendto(struct svc_rqst *); static int svc_udp_sendto(struct svc_rqst *);
static void svc_sock_detach(struct svc_xprt *); static void svc_sock_detach(struct svc_xprt *);
static void svc_tcp_sock_detach(struct svc_xprt *);
static void svc_sock_free(struct svc_xprt *); static void svc_sock_free(struct svc_xprt *);
static struct svc_xprt *svc_create_socket(struct svc_serv *, int, static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
...@@ -102,7 +103,6 @@ static void svc_reclassify_socket(struct socket *sock) ...@@ -102,7 +103,6 @@ static void svc_reclassify_socket(struct socket *sock)
static void svc_release_skb(struct svc_rqst *rqstp) static void svc_release_skb(struct svc_rqst *rqstp)
{ {
struct sk_buff *skb = rqstp->rq_xprt_ctxt; struct sk_buff *skb = rqstp->rq_xprt_ctxt;
struct svc_deferred_req *dr = rqstp->rq_deferred;
if (skb) { if (skb) {
struct svc_sock *svsk = struct svc_sock *svsk =
...@@ -112,10 +112,6 @@ static void svc_release_skb(struct svc_rqst *rqstp) ...@@ -112,10 +112,6 @@ static void svc_release_skb(struct svc_rqst *rqstp)
dprintk("svc: service %p, releasing skb %p\n", rqstp, skb); dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
skb_free_datagram(svsk->sk_sk, skb); skb_free_datagram(svsk->sk_sk, skb);
} }
if (dr) {
rqstp->rq_deferred = NULL;
kfree(dr);
}
} }
union svc_pktinfo_u { union svc_pktinfo_u {
...@@ -289,7 +285,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) ...@@ -289,7 +285,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
return -ENOENT; return -ENOENT;
return len; return len;
} }
EXPORT_SYMBOL(svc_sock_names); EXPORT_SYMBOL_GPL(svc_sock_names);
/* /*
* Check input queue length * Check input queue length
...@@ -1017,7 +1013,7 @@ static struct svc_xprt_ops svc_tcp_ops = { ...@@ -1017,7 +1013,7 @@ static struct svc_xprt_ops svc_tcp_ops = {
.xpo_recvfrom = svc_tcp_recvfrom, .xpo_recvfrom = svc_tcp_recvfrom,
.xpo_sendto = svc_tcp_sendto, .xpo_sendto = svc_tcp_sendto,
.xpo_release_rqst = svc_release_skb, .xpo_release_rqst = svc_release_skb,
.xpo_detach = svc_sock_detach, .xpo_detach = svc_tcp_sock_detach,
.xpo_free = svc_sock_free, .xpo_free = svc_sock_free,
.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr, .xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
.xpo_has_wspace = svc_tcp_has_wspace, .xpo_has_wspace = svc_tcp_has_wspace,
...@@ -1101,7 +1097,7 @@ void svc_sock_update_bufs(struct svc_serv *serv) ...@@ -1101,7 +1097,7 @@ void svc_sock_update_bufs(struct svc_serv *serv)
} }
spin_unlock_bh(&serv->sv_lock); spin_unlock_bh(&serv->sv_lock);
} }
EXPORT_SYMBOL(svc_sock_update_bufs); EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
/* /*
* Initialize socket for RPC use and create svc_sock struct * Initialize socket for RPC use and create svc_sock struct
...@@ -1287,6 +1283,24 @@ static void svc_sock_detach(struct svc_xprt *xprt) ...@@ -1287,6 +1283,24 @@ static void svc_sock_detach(struct svc_xprt *xprt)
sk->sk_state_change = svsk->sk_ostate; sk->sk_state_change = svsk->sk_ostate;
sk->sk_data_ready = svsk->sk_odata; sk->sk_data_ready = svsk->sk_odata;
sk->sk_write_space = svsk->sk_owspace; sk->sk_write_space = svsk->sk_owspace;
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
wake_up_interruptible(sk->sk_sleep);
}
/*
* Disconnect the socket, and reset the callbacks
*/
static void svc_tcp_sock_detach(struct svc_xprt *xprt)
{
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
dprintk("svc: svc_tcp_sock_detach(%p)\n", svsk);
svc_sock_detach(xprt);
if (!test_bit(XPT_LISTENER, &xprt->xpt_flags))
kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
} }
/* /*
......
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