aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-01-07 20:21:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-07 20:21:24 -0500
commit713404d6082fee34a829a0c6d511e4aec72d7654 (patch)
treedccfa03988c763b0b39241181f37cdffb5b0fdcc
parentd599edcaea987e233fad808f88850f725e8a5530 (diff)
parentdb43910cb42285a99f45f7e0a0a32e32d0b61dcf (diff)
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 ...
-rw-r--r--fs/lockd/clntproc.c7
-rw-r--r--fs/lockd/host.c170
-rw-r--r--fs/lockd/mon.c569
-rw-r--r--fs/lockd/svc.c72
-rw-r--r--fs/lockd/svc4proc.c13
-rw-r--r--fs/lockd/svcproc.c13
-rw-r--r--fs/lockd/svcsubs.c1
-rw-r--r--fs/lockd/xdr.c5
-rw-r--r--fs/lockd/xdr4.c5
-rw-r--r--fs/nfsd/auth.c4
-rw-r--r--fs/nfsd/nfs4callback.c3
-rw-r--r--fs/nfsd/nfs4proc.c5
-rw-r--r--fs/nfsd/nfs4recover.c2
-rw-r--r--fs/nfsd/nfs4state.c79
-rw-r--r--fs/nfsd/nfs4xdr.c2
-rw-r--r--fs/nfsd/nfsctl.c479
-rw-r--r--fs/nfsd/nfsfh.c36
-rw-r--r--fs/nfsd/nfsproc.c1
-rw-r--r--fs/nfsd/vfs.c34
-rw-r--r--include/linux/lockd/lockd.h68
-rw-r--r--include/linux/lockd/sm_inter.h48
-rw-r--r--include/linux/lockd/xdr.h15
-rw-r--r--include/linux/nfs4.h2
-rw-r--r--include/linux/nfsd/nfsd.h1
-rw-r--r--include/linux/nfsd/nfsfh.h4
-rw-r--r--include/linux/sunrpc/svc.h5
-rw-r--r--net/sunrpc/cache.c20
-rw-r--r--net/sunrpc/stats.c6
-rw-r--r--net/sunrpc/svc.c14
-rw-r--r--net/sunrpc/svc_xprt.c58
-rw-r--r--net/sunrpc/svcauth.c14
-rw-r--r--net/sunrpc/svcauth_unix.c12
-rw-r--r--net/sunrpc/svcsock.c30
33 files changed, 1225 insertions, 572 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 31668b690e03..dd7957064a8c 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -16,7 +16,6 @@
16#include <linux/sunrpc/clnt.h> 16#include <linux/sunrpc/clnt.h>
17#include <linux/sunrpc/svc.h> 17#include <linux/sunrpc/svc.h>
18#include <linux/lockd/lockd.h> 18#include <linux/lockd/lockd.h>
19#include <linux/lockd/sm_inter.h>
20 19
21#define NLMDBG_FACILITY NLMDBG_CLIENT 20#define NLMDBG_FACILITY NLMDBG_CLIENT
22#define NLMCLNT_GRACE_WAIT (5*HZ) 21#define NLMCLNT_GRACE_WAIT (5*HZ)
@@ -518,11 +517,9 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
518 unsigned char fl_type; 517 unsigned char fl_type;
519 int status = -ENOLCK; 518 int status = -ENOLCK;
520 519
521 if (nsm_monitor(host) < 0) { 520 if (nsm_monitor(host) < 0)
522 printk(KERN_NOTICE "lockd: failed to monitor %s\n",
523 host->h_name);
524 goto out; 521 goto out;
525 } 522
526 fl->fl_flags |= FL_ACCESS; 523 fl->fl_flags |= FL_ACCESS;
527 status = do_vfs_lock(fl); 524 status = do_vfs_lock(fl);
528 fl->fl_flags = fl_flags; 525 fl->fl_flags = fl_flags;
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index abdebf76b820..99d737bd4325 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -15,7 +15,6 @@
15#include <linux/sunrpc/clnt.h> 15#include <linux/sunrpc/clnt.h>
16#include <linux/sunrpc/svc.h> 16#include <linux/sunrpc/svc.h>
17#include <linux/lockd/lockd.h> 17#include <linux/lockd/lockd.h>
18#include <linux/lockd/sm_inter.h>
19#include <linux/mutex.h> 18#include <linux/mutex.h>
20 19
21#include <net/ipv6.h> 20#include <net/ipv6.h>
@@ -32,11 +31,6 @@ static int nrhosts;
32static DEFINE_MUTEX(nlm_host_mutex); 31static DEFINE_MUTEX(nlm_host_mutex);
33 32
34static void nlm_gc_hosts(void); 33static void nlm_gc_hosts(void);
35static struct nsm_handle *nsm_find(const struct sockaddr *sap,
36 const size_t salen,
37 const char *hostname,
38 const size_t hostname_len,
39 const int create);
40 34
41struct nlm_lookup_host_info { 35struct nlm_lookup_host_info {
42 const int server; /* search for server|client */ 36 const int server; /* search for server|client */
@@ -105,32 +99,6 @@ static void nlm_clear_port(struct sockaddr *sap)
105 } 99 }
106} 100}
107 101
108static void nlm_display_address(const struct sockaddr *sap,
109 char *buf, const size_t len)
110{
111 const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
112 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
113
114 switch (sap->sa_family) {
115 case AF_UNSPEC:
116 snprintf(buf, len, "unspecified");
117 break;
118 case AF_INET:
119 snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
120 break;
121 case AF_INET6:
122 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
123 snprintf(buf, len, "%pI4",
124 &sin6->sin6_addr.s6_addr32[3]);
125 else
126 snprintf(buf, len, "%pI6", &sin6->sin6_addr);
127 break;
128 default:
129 snprintf(buf, len, "unsupported address family");
130 break;
131 }
132}
133
134/* 102/*
135 * Common host lookup routine for server & client 103 * Common host lookup routine for server & client
136 */ 104 */
@@ -190,8 +158,8 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
190 atomic_inc(&nsm->sm_count); 158 atomic_inc(&nsm->sm_count);
191 else { 159 else {
192 host = NULL; 160 host = NULL;
193 nsm = nsm_find(ni->sap, ni->salen, 161 nsm = nsm_get_handle(ni->sap, ni->salen,
194 ni->hostname, ni->hostname_len, 1); 162 ni->hostname, ni->hostname_len);
195 if (!nsm) { 163 if (!nsm) {
196 dprintk("lockd: nlm_lookup_host failed; " 164 dprintk("lockd: nlm_lookup_host failed; "
197 "no nsm handle\n"); 165 "no nsm handle\n");
@@ -206,6 +174,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
206 goto out; 174 goto out;
207 } 175 }
208 host->h_name = nsm->sm_name; 176 host->h_name = nsm->sm_name;
177 host->h_addrbuf = nsm->sm_addrbuf;
209 memcpy(nlm_addr(host), ni->sap, ni->salen); 178 memcpy(nlm_addr(host), ni->sap, ni->salen);
210 host->h_addrlen = ni->salen; 179 host->h_addrlen = ni->salen;
211 nlm_clear_port(nlm_addr(host)); 180 nlm_clear_port(nlm_addr(host));
@@ -232,11 +201,6 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
232 201
233 nrhosts++; 202 nrhosts++;
234 203
235 nlm_display_address((struct sockaddr *)&host->h_addr,
236 host->h_addrbuf, sizeof(host->h_addrbuf));
237 nlm_display_address((struct sockaddr *)&host->h_srcaddr,
238 host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
239
240 dprintk("lockd: nlm_lookup_host created host %s\n", 204 dprintk("lockd: nlm_lookup_host created host %s\n",
241 host->h_name); 205 host->h_name);
242 206
@@ -256,10 +220,8 @@ nlm_destroy_host(struct nlm_host *host)
256 BUG_ON(!list_empty(&host->h_lockowners)); 220 BUG_ON(!list_empty(&host->h_lockowners));
257 BUG_ON(atomic_read(&host->h_count)); 221 BUG_ON(atomic_read(&host->h_count));
258 222
259 /*
260 * Release NSM handle and unmonitor host.
261 */
262 nsm_unmonitor(host); 223 nsm_unmonitor(host);
224 nsm_release(host->h_nsmhandle);
263 225
264 clnt = host->h_rpcclnt; 226 clnt = host->h_rpcclnt;
265 if (clnt != NULL) 227 if (clnt != NULL)
@@ -378,8 +340,8 @@ nlm_bind_host(struct nlm_host *host)
378{ 340{
379 struct rpc_clnt *clnt; 341 struct rpc_clnt *clnt;
380 342
381 dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n", 343 dprintk("lockd: nlm_bind_host %s (%s)\n",
382 host->h_name, host->h_addrbuf, host->h_srcaddrbuf); 344 host->h_name, host->h_addrbuf);
383 345
384 /* Lock host handle */ 346 /* Lock host handle */
385 mutex_lock(&host->h_mutex); 347 mutex_lock(&host->h_mutex);
@@ -481,35 +443,23 @@ void nlm_release_host(struct nlm_host *host)
481 } 443 }
482} 444}
483 445
484/* 446/**
485 * We were notified that the host indicated by address &sin 447 * nlm_host_rebooted - Release all resources held by rebooted host
486 * has rebooted. 448 * @info: pointer to decoded results of NLM_SM_NOTIFY call
487 * Release all resources held by that peer. 449 *
450 * We were notified that the specified host has rebooted. Release
451 * all resources held by that peer.
488 */ 452 */
489void nlm_host_rebooted(const struct sockaddr_in *sin, 453void nlm_host_rebooted(const struct nlm_reboot *info)
490 const char *hostname,
491 unsigned int hostname_len,
492 u32 new_state)
493{ 454{
494 struct hlist_head *chain; 455 struct hlist_head *chain;
495 struct hlist_node *pos; 456 struct hlist_node *pos;
496 struct nsm_handle *nsm; 457 struct nsm_handle *nsm;
497 struct nlm_host *host; 458 struct nlm_host *host;
498 459
499 nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin), 460 nsm = nsm_reboot_lookup(info);
500 hostname, hostname_len, 0); 461 if (unlikely(nsm == NULL))
501 if (nsm == NULL) {
502 dprintk("lockd: never saw rebooted peer '%.*s' before\n",
503 hostname_len, hostname);
504 return; 462 return;
505 }
506
507 dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
508 hostname_len, hostname, nsm->sm_addrbuf);
509
510 /* When reclaiming locks on this peer, make sure that
511 * we set up a new notification */
512 nsm->sm_monitored = 0;
513 463
514 /* Mark all hosts tied to this NSM state as having rebooted. 464 /* Mark all hosts tied to this NSM state as having rebooted.
515 * We run the loop repeatedly, because we drop the host table 465 * We run the loop repeatedly, because we drop the host table
@@ -520,8 +470,8 @@ again: mutex_lock(&nlm_host_mutex);
520 for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { 470 for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
521 hlist_for_each_entry(host, pos, chain, h_hash) { 471 hlist_for_each_entry(host, pos, chain, h_hash) {
522 if (host->h_nsmhandle == nsm 472 if (host->h_nsmhandle == nsm
523 && host->h_nsmstate != new_state) { 473 && host->h_nsmstate != info->state) {
524 host->h_nsmstate = new_state; 474 host->h_nsmstate = info->state;
525 host->h_state++; 475 host->h_state++;
526 476
527 nlm_get_host(host); 477 nlm_get_host(host);
@@ -629,89 +579,3 @@ nlm_gc_hosts(void)
629 579
630 next_gc = jiffies + NLM_HOST_COLLECT; 580 next_gc = jiffies + NLM_HOST_COLLECT;
631} 581}
632
633
634/*
635 * Manage NSM handles
636 */
637static LIST_HEAD(nsm_handles);
638static DEFINE_SPINLOCK(nsm_lock);
639
640static struct nsm_handle *nsm_find(const struct sockaddr *sap,
641 const size_t salen,
642 const char *hostname,
643 const size_t hostname_len,
644 const int create)
645{
646 struct nsm_handle *nsm = NULL;
647 struct nsm_handle *pos;
648
649 if (!sap)
650 return NULL;
651
652 if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
653 if (printk_ratelimit()) {
654 printk(KERN_WARNING "Invalid hostname \"%.*s\" "
655 "in NFS lock request\n",
656 (int)hostname_len, hostname);
657 }
658 return NULL;
659 }
660
661retry:
662 spin_lock(&nsm_lock);
663 list_for_each_entry(pos, &nsm_handles, sm_link) {
664
665 if (hostname && nsm_use_hostnames) {
666 if (strlen(pos->sm_name) != hostname_len
667 || memcmp(pos->sm_name, hostname, hostname_len))
668 continue;
669 } else if (!nlm_cmp_addr(nsm_addr(pos), sap))
670 continue;
671 atomic_inc(&pos->sm_count);
672 kfree(nsm);
673 nsm = pos;
674 goto found;
675 }
676 if (nsm) {
677 list_add(&nsm->sm_link, &nsm_handles);
678 goto found;
679 }
680 spin_unlock(&nsm_lock);
681
682 if (!create)
683 return NULL;
684
685 nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
686 if (nsm == NULL)
687 return NULL;
688
689 memcpy(nsm_addr(nsm), sap, salen);
690 nsm->sm_addrlen = salen;
691 nsm->sm_name = (char *) (nsm + 1);
692 memcpy(nsm->sm_name, hostname, hostname_len);
693 nsm->sm_name[hostname_len] = '\0';
694 nlm_display_address((struct sockaddr *)&nsm->sm_addr,
695 nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
696 atomic_set(&nsm->sm_count, 1);
697 goto retry;
698
699found:
700 spin_unlock(&nsm_lock);
701 return nsm;
702}
703
704/*
705 * Release an NSM handle
706 */
707void
708nsm_release(struct nsm_handle *nsm)
709{
710 if (!nsm)
711 return;
712 if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
713 list_del(&nsm->sm_link);
714 spin_unlock(&nsm_lock);
715 kfree(nsm);
716 }
717}
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index ffd3461f75ef..5e2c4d5ac827 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -9,35 +9,123 @@
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/utsname.h> 10#include <linux/utsname.h>
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/ktime.h>
13
12#include <linux/sunrpc/clnt.h> 14#include <linux/sunrpc/clnt.h>
13#include <linux/sunrpc/xprtsock.h> 15#include <linux/sunrpc/xprtsock.h>
14#include <linux/sunrpc/svc.h> 16#include <linux/sunrpc/svc.h>
15#include <linux/lockd/lockd.h> 17#include <linux/lockd/lockd.h>
16#include <linux/lockd/sm_inter.h>
17
18 18
19#define NLMDBG_FACILITY NLMDBG_MONITOR 19#define NLMDBG_FACILITY NLMDBG_MONITOR
20#define NSM_PROGRAM 100024
21#define NSM_VERSION 1
22
23enum {
24 NSMPROC_NULL,
25 NSMPROC_STAT,
26 NSMPROC_MON,
27 NSMPROC_UNMON,
28 NSMPROC_UNMON_ALL,
29 NSMPROC_SIMU_CRASH,
30 NSMPROC_NOTIFY,
31};
32
33struct nsm_args {
34 struct nsm_private *priv;
35 u32 prog; /* RPC callback info */
36 u32 vers;
37 u32 proc;
20 38
21#define XDR_ADDRBUF_LEN (20) 39 char *mon_name;
40};
22 41
23static struct rpc_clnt * nsm_create(void); 42struct nsm_res {
43 u32 status;
44 u32 state;
45};
24 46
25static struct rpc_program nsm_program; 47static struct rpc_program nsm_program;
48static LIST_HEAD(nsm_handles);
49static DEFINE_SPINLOCK(nsm_lock);
26 50
27/* 51/*
28 * Local NSM state 52 * Local NSM state
29 */ 53 */
30int nsm_local_state; 54int __read_mostly nsm_local_state;
55int __read_mostly nsm_use_hostnames;
31 56
32/* 57static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
33 * Common procedure for SM_MON/SM_UNMON calls 58{
34 */ 59 return (struct sockaddr *)&nsm->sm_addr;
35static int 60}
36nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) 61
62static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf,
63 const size_t len)
64{
65 const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
66 snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
67}
68
69static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf,
70 const size_t len)
71{
72 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
73
74 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
75 snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]);
76 else if (sin6->sin6_scope_id != 0)
77 snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr,
78 sin6->sin6_scope_id);
79 else
80 snprintf(buf, len, "%pI6", &sin6->sin6_addr);
81}
82
83static void nsm_display_address(const struct sockaddr *sap,
84 char *buf, const size_t len)
85{
86 switch (sap->sa_family) {
87 case AF_INET:
88 nsm_display_ipv4_address(sap, buf, len);
89 break;
90 case AF_INET6:
91 nsm_display_ipv6_address(sap, buf, len);
92 break;
93 default:
94 snprintf(buf, len, "unsupported address family");
95 break;
96 }
97}
98
99static struct rpc_clnt *nsm_create(void)
100{
101 struct sockaddr_in sin = {
102 .sin_family = AF_INET,
103 .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
104 };
105 struct rpc_create_args args = {
106 .protocol = XPRT_TRANSPORT_UDP,
107 .address = (struct sockaddr *)&sin,
108 .addrsize = sizeof(sin),
109 .servername = "rpc.statd",
110 .program = &nsm_program,
111 .version = NSM_VERSION,
112 .authflavor = RPC_AUTH_NULL,
113 };
114
115 return rpc_create(&args);
116}
117
118static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
37{ 119{
38 struct rpc_clnt *clnt; 120 struct rpc_clnt *clnt;
39 int status; 121 int status;
40 struct nsm_args args; 122 struct nsm_args args = {
123 .priv = &nsm->sm_priv,
124 .prog = NLM_PROGRAM,
125 .vers = 3,
126 .proc = NLMPROC_NSM_NOTIFY,
127 .mon_name = nsm->sm_mon_name,
128 };
41 struct rpc_message msg = { 129 struct rpc_message msg = {
42 .rpc_argp = &args, 130 .rpc_argp = &args,
43 .rpc_resp = res, 131 .rpc_resp = res,
@@ -46,22 +134,18 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
46 clnt = nsm_create(); 134 clnt = nsm_create();
47 if (IS_ERR(clnt)) { 135 if (IS_ERR(clnt)) {
48 status = PTR_ERR(clnt); 136 status = PTR_ERR(clnt);
137 dprintk("lockd: failed to create NSM upcall transport, "
138 "status=%d\n", status);
49 goto out; 139 goto out;
50 } 140 }
51 141
52 memset(&args, 0, sizeof(args));
53 args.mon_name = nsm->sm_name;
54 args.addr = nsm_addr_in(nsm)->sin_addr.s_addr;
55 args.prog = NLM_PROGRAM;
56 args.vers = 3;
57 args.proc = NLMPROC_NSM_NOTIFY;
58 memset(res, 0, sizeof(*res)); 142 memset(res, 0, sizeof(*res));
59 143
60 msg.rpc_proc = &clnt->cl_procinfo[proc]; 144 msg.rpc_proc = &clnt->cl_procinfo[proc];
61 status = rpc_call_sync(clnt, &msg, 0); 145 status = rpc_call_sync(clnt, &msg, 0);
62 if (status < 0) 146 if (status < 0)
63 printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n", 147 dprintk("lockd: NSM upcall RPC failed, status=%d\n",
64 status); 148 status);
65 else 149 else
66 status = 0; 150 status = 0;
67 rpc_shutdown_client(clnt); 151 rpc_shutdown_client(clnt);
@@ -69,82 +153,272 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
69 return status; 153 return status;
70} 154}
71 155
72/* 156/**
73 * Set up monitoring of a remote host 157 * nsm_monitor - Notify a peer in case we reboot
158 * @host: pointer to nlm_host of peer to notify
159 *
160 * If this peer is not already monitored, this function sends an
161 * upcall to the local rpc.statd to record the name/address of
162 * the peer to notify in case we reboot.
163 *
164 * Returns zero if the peer is monitored by the local rpc.statd;
165 * otherwise a negative errno value is returned.
74 */ 166 */
75int 167int nsm_monitor(const struct nlm_host *host)
76nsm_monitor(struct nlm_host *host)
77{ 168{
78 struct nsm_handle *nsm = host->h_nsmhandle; 169 struct nsm_handle *nsm = host->h_nsmhandle;
79 struct nsm_res res; 170 struct nsm_res res;
80 int status; 171 int status;
81 172
82 dprintk("lockd: nsm_monitor(%s)\n", host->h_name); 173 dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
83 BUG_ON(nsm == NULL);
84 174
85 if (nsm->sm_monitored) 175 if (nsm->sm_monitored)
86 return 0; 176 return 0;
87 177
88 status = nsm_mon_unmon(nsm, SM_MON, &res); 178 /*
179 * Choose whether to record the caller_name or IP address of
180 * this peer in the local rpc.statd's database.
181 */
182 nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
89 183
90 if (status < 0 || res.status != 0) 184 status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
91 printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name); 185 if (res.status != 0)
186 status = -EIO;
187 if (status < 0)
188 printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name);
92 else 189 else
93 nsm->sm_monitored = 1; 190 nsm->sm_monitored = 1;
94 return status; 191 return status;
95} 192}
96 193
97/* 194/**
98 * Cease to monitor remote host 195 * nsm_unmonitor - Unregister peer notification
196 * @host: pointer to nlm_host of peer to stop monitoring
197 *
198 * If this peer is monitored, this function sends an upcall to
199 * tell the local rpc.statd not to send this peer a notification
200 * when we reboot.
99 */ 201 */
100int 202void nsm_unmonitor(const struct nlm_host *host)
101nsm_unmonitor(struct nlm_host *host)
102{ 203{
103 struct nsm_handle *nsm = host->h_nsmhandle; 204 struct nsm_handle *nsm = host->h_nsmhandle;
104 struct nsm_res res; 205 struct nsm_res res;
105 int status = 0; 206 int status;
106
107 if (nsm == NULL)
108 return 0;
109 host->h_nsmhandle = NULL;
110 207
111 if (atomic_read(&nsm->sm_count) == 1 208 if (atomic_read(&nsm->sm_count) == 1
112 && nsm->sm_monitored && !nsm->sm_sticky) { 209 && nsm->sm_monitored && !nsm->sm_sticky) {
113 dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name); 210 dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
114 211
115 status = nsm_mon_unmon(nsm, SM_UNMON, &res); 212 status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
213 if (res.status != 0)
214 status = -EIO;
116 if (status < 0) 215 if (status < 0)
117 printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", 216 printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
118 host->h_name); 217 nsm->sm_name);
119 else 218 else
120 nsm->sm_monitored = 0; 219 nsm->sm_monitored = 0;
121 } 220 }
122 nsm_release(nsm); 221}
123 return status; 222
223static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
224 const size_t len)
225{
226 struct nsm_handle *nsm;
227
228 list_for_each_entry(nsm, &nsm_handles, sm_link)
229 if (strlen(nsm->sm_name) == len &&
230 memcmp(nsm->sm_name, hostname, len) == 0)
231 return nsm;
232 return NULL;
233}
234
235static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
236{
237 struct nsm_handle *nsm;
238
239 list_for_each_entry(nsm, &nsm_handles, sm_link)
240 if (nlm_cmp_addr(nsm_addr(nsm), sap))
241 return nsm;
242 return NULL;
243}
244
245static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
246{
247 struct nsm_handle *nsm;
248
249 list_for_each_entry(nsm, &nsm_handles, sm_link)
250 if (memcmp(nsm->sm_priv.data, priv->data,
251 sizeof(priv->data)) == 0)
252 return nsm;
253 return NULL;
124} 254}
125 255
126/* 256/*
127 * Create NSM client for the local host 257 * Construct a unique cookie to match this nsm_handle to this monitored
258 * host. It is passed to the local rpc.statd via NSMPROC_MON, and
259 * returned via NLMPROC_SM_NOTIFY, in the "priv" field of these
260 * requests.
261 *
262 * The NSM protocol requires that these cookies be unique while the
263 * system is running. We prefer a stronger requirement of making them
264 * unique across reboots. If user space bugs cause a stale cookie to
265 * be sent to the kernel, it could cause the wrong host to lose its
266 * lock state if cookies were not unique across reboots.
267 *
268 * The cookies are exposed only to local user space via loopback. They
269 * do not appear on the physical network. If we want greater security
270 * for some reason, nsm_init_private() could perform a one-way hash to
271 * obscure the contents of the cookie.
128 */ 272 */
129static struct rpc_clnt * 273static void nsm_init_private(struct nsm_handle *nsm)
130nsm_create(void)
131{ 274{
132 struct sockaddr_in sin = { 275 u64 *p = (u64 *)&nsm->sm_priv.data;
133 .sin_family = AF_INET, 276 struct timespec ts;
134 .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
135 .sin_port = 0,
136 };
137 struct rpc_create_args args = {
138 .protocol = XPRT_TRANSPORT_UDP,
139 .address = (struct sockaddr *)&sin,
140 .addrsize = sizeof(sin),
141 .servername = "localhost",
142 .program = &nsm_program,
143 .version = SM_VERSION,
144 .authflavor = RPC_AUTH_NULL,
145 };
146 277
147 return rpc_create(&args); 278 ktime_get_ts(&ts);
279 *p++ = timespec_to_ns(&ts);
280 *p = (unsigned long)nsm;
281}
282
283static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
284 const size_t salen,
285 const char *hostname,
286 const size_t hostname_len)
287{
288 struct nsm_handle *new;
289
290 new = kzalloc(sizeof(*new) + hostname_len + 1, GFP_KERNEL);
291 if (unlikely(new == NULL))
292 return NULL;
293
294 atomic_set(&new->sm_count, 1);
295 new->sm_name = (char *)(new + 1);
296 memcpy(nsm_addr(new), sap, salen);
297 new->sm_addrlen = salen;
298 nsm_init_private(new);
299 nsm_display_address((const struct sockaddr *)&new->sm_addr,
300 new->sm_addrbuf, sizeof(new->sm_addrbuf));
301 memcpy(new->sm_name, hostname, hostname_len);
302 new->sm_name[hostname_len] = '\0';
303
304 return new;
305}
306
307/**
308 * nsm_get_handle - Find or create a cached nsm_handle
309 * @sap: pointer to socket address of handle to find
310 * @salen: length of socket address
311 * @hostname: pointer to C string containing hostname to find
312 * @hostname_len: length of C string
313 *
314 * Behavior is modulated by the global nsm_use_hostnames variable.
315 *
316 * Returns a cached nsm_handle after bumping its ref count, or
317 * returns a fresh nsm_handle if a handle that matches @sap and/or
318 * @hostname cannot be found in the handle cache. Returns NULL if
319 * an error occurs.
320 */
321struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
322 const size_t salen, const char *hostname,
323 const size_t hostname_len)
324{
325 struct nsm_handle *cached, *new = NULL;
326
327 if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
328 if (printk_ratelimit()) {
329 printk(KERN_WARNING "Invalid hostname \"%.*s\" "
330 "in NFS lock request\n",
331 (int)hostname_len, hostname);
332 }
333 return NULL;
334 }
335
336retry:
337 spin_lock(&nsm_lock);
338
339 if (nsm_use_hostnames && hostname != NULL)
340 cached = nsm_lookup_hostname(hostname, hostname_len);
341 else
342 cached = nsm_lookup_addr(sap);
343
344 if (cached != NULL) {
345 atomic_inc(&cached->sm_count);
346 spin_unlock(&nsm_lock);
347 kfree(new);
348 dprintk("lockd: found nsm_handle for %s (%s), "
349 "cnt %d\n", cached->sm_name,
350 cached->sm_addrbuf,
351 atomic_read(&cached->sm_count));
352 return cached;
353 }
354
355 if (new != NULL) {
356 list_add(&new->sm_link, &nsm_handles);
357 spin_unlock(&nsm_lock);
358 dprintk("lockd: created nsm_handle for %s (%s)\n",
359 new->sm_name, new->sm_addrbuf);
360 return new;
361 }
362
363 spin_unlock(&nsm_lock);
364
365 new = nsm_create_handle(sap, salen, hostname, hostname_len);
366 if (unlikely(new == NULL))
367 return NULL;
368 goto retry;
369}
370
371/**
372 * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
373 * @info: pointer to NLMPROC_SM_NOTIFY arguments
374 *
375 * Returns a matching nsm_handle if found in the nsm cache; the returned
376 * nsm_handle's reference count is bumped and sm_monitored is cleared.
377 * Otherwise returns NULL if some error occurred.
378 */
379struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
380{
381 struct nsm_handle *cached;
382
383 spin_lock(&nsm_lock);
384
385 cached = nsm_lookup_priv(&info->priv);
386 if (unlikely(cached == NULL)) {
387 spin_unlock(&nsm_lock);
388 dprintk("lockd: never saw rebooted peer '%.*s' before\n",
389 info->len, info->mon);
390 return cached;
391 }
392
393 atomic_inc(&cached->sm_count);
394 spin_unlock(&nsm_lock);
395
396 /*
397 * During subsequent lock activity, force a fresh
398 * notification to be set up for this host.
399 */
400 cached->sm_monitored = 0;
401
402 dprintk("lockd: host %s (%s) rebooted, cnt %d\n",
403 cached->sm_name, cached->sm_addrbuf,
404 atomic_read(&cached->sm_count));
405 return cached;
406}
407
408/**
409 * nsm_release - Release an NSM handle
410 * @nsm: pointer to handle to be released
411 *
412 */
413void nsm_release(struct nsm_handle *nsm)
414{
415 if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
416 list_del(&nsm->sm_link);
417 spin_unlock(&nsm_lock);
418 dprintk("lockd: destroyed nsm_handle for %s (%s)\n",
419 nsm->sm_name, nsm->sm_addrbuf);
420 kfree(nsm);
421 }
148} 422}
149 423
150/* 424/*
@@ -154,127 +428,132 @@ nsm_create(void)
154 * Status Monitor wire protocol. 428 * Status Monitor wire protocol.
155 */ 429 */
156 430
157static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) 431static int encode_nsm_string(struct xdr_stream *xdr, const char *string)
158{ 432{
159 size_t len = strlen(string); 433 const u32 len = strlen(string);
160 434 __be32 *p;
161 if (len > SM_MAXSTRLEN) 435
162 len = SM_MAXSTRLEN; 436 if (unlikely(len > SM_MAXSTRLEN))
163 return xdr_encode_opaque(p, string, len); 437 return -EIO;
438 p = xdr_reserve_space(xdr, sizeof(u32) + len);
439 if (unlikely(p == NULL))
440 return -EIO;
441 xdr_encode_opaque(p, string, len);
442 return 0;
164} 443}
165 444
166/* 445/*
167 * "mon_name" specifies the host to be monitored. 446 * "mon_name" specifies the host to be monitored.
168 *
169 * Linux uses a text version of the IP address of the remote
170 * host as the host identifier (the "mon_name" argument).
171 *
172 * Linux statd always looks up the canonical hostname first for
173 * whatever remote hostname it receives, so this works alright.
174 */ 447 */
175static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) 448static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp)
176{ 449{
177 char buffer[XDR_ADDRBUF_LEN + 1]; 450 return encode_nsm_string(xdr, argp->mon_name);
178 char *name = argp->mon_name;
179
180 if (!nsm_use_hostnames) {
181 snprintf(buffer, XDR_ADDRBUF_LEN,
182 "%pI4", &argp->addr);
183 name = buffer;
184 }
185
186 return xdr_encode_nsm_string(p, name);
187} 451}
188 452
189/* 453/*
190 * The "my_id" argument specifies the hostname and RPC procedure 454 * The "my_id" argument specifies the hostname and RPC procedure
191 * to be called when the status manager receives notification 455 * to be called when the status manager receives notification
192 * (via the SM_NOTIFY call) that the state of host "mon_name" 456 * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name"
193 * has changed. 457 * has changed.
194 */ 458 */
195static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) 459static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
196{ 460{
197 p = xdr_encode_nsm_string(p, utsname()->nodename); 461 int status;
198 if (!p) 462 __be32 *p;
199 return ERR_PTR(-EIO); 463
200 464 status = encode_nsm_string(xdr, utsname()->nodename);
465 if (unlikely(status != 0))
466 return status;
467 p = xdr_reserve_space(xdr, 3 * sizeof(u32));
468 if (unlikely(p == NULL))
469 return -EIO;
201 *p++ = htonl(argp->prog); 470 *p++ = htonl(argp->prog);
202 *p++ = htonl(argp->vers); 471 *p++ = htonl(argp->vers);
203 *p++ = htonl(argp->proc); 472 *p++ = htonl(argp->proc);
204 473 return 0;
205 return p;
206} 474}
207 475
208/* 476/*
209 * The "mon_id" argument specifies the non-private arguments 477 * The "mon_id" argument specifies the non-private arguments
210 * of an SM_MON or SM_UNMON call. 478 * of an NSMPROC_MON or NSMPROC_UNMON call.
211 */ 479 */
212static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) 480static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp)
213{ 481{
214 p = xdr_encode_mon_name(p, argp); 482 int status;
215 if (!p)
216 return ERR_PTR(-EIO);
217 483
218 return xdr_encode_my_id(p, argp); 484 status = encode_mon_name(xdr, argp);
485 if (unlikely(status != 0))
486 return status;
487 return encode_my_id(xdr, argp);
219} 488}
220 489
221/* 490/*
222 * The "priv" argument may contain private information required 491 * The "priv" argument may contain private information required
223 * by the SM_MON call. This information will be supplied in the 492 * by the NSMPROC_MON call. This information will be supplied in the
224 * SM_NOTIFY call. 493 * NLMPROC_SM_NOTIFY call.
225 *
226 * Linux provides the raw IP address of the monitored host,
227 * left in network byte order.
228 */ 494 */
229static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) 495static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp)
230{ 496{
231 *p++ = argp->addr; 497 __be32 *p;
232 *p++ = 0;
233 *p++ = 0;
234 *p++ = 0;
235 498
236 return p; 499 p = xdr_reserve_space(xdr, SM_PRIV_SIZE);
500 if (unlikely(p == NULL))
501 return -EIO;
502 xdr_encode_opaque_fixed(p, argp->priv->data, SM_PRIV_SIZE);
503 return 0;
237} 504}
238 505
239static int 506static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p,
240xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 507 const struct nsm_args *argp)
241{ 508{
242 p = xdr_encode_mon_id(p, argp); 509 struct xdr_stream xdr;
243 if (IS_ERR(p)) 510 int status;
244 return PTR_ERR(p); 511
245 512 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
246 p = xdr_encode_priv(p, argp); 513 status = encode_mon_id(&xdr, argp);
247 if (IS_ERR(p)) 514 if (unlikely(status))
248 return PTR_ERR(p); 515 return status;
249 516 return encode_priv(&xdr, argp);
250 rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
251 return 0;
252} 517}
253 518
254static int 519static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p,
255xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 520 const struct nsm_args *argp)
256{ 521{
257 p = xdr_encode_mon_id(p, argp); 522 struct xdr_stream xdr;
258 if (IS_ERR(p)) 523
259 return PTR_ERR(p); 524 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
260 rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); 525 return encode_mon_id(&xdr, argp);
261 return 0;
262} 526}
263 527
264static int 528static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p,
265xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 529 struct nsm_res *resp)
266{ 530{
531 struct xdr_stream xdr;
532
533 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
534 p = xdr_inline_decode(&xdr, 2 * sizeof(u32));
535 if (unlikely(p == NULL))
536 return -EIO;
267 resp->status = ntohl(*p++); 537 resp->status = ntohl(*p++);
268 resp->state = ntohl(*p++); 538 resp->state = ntohl(*p);
269 dprintk("nsm: xdr_decode_stat_res status %d state %d\n", 539
540 dprintk("lockd: xdr_dec_stat_res status %d state %d\n",
270 resp->status, resp->state); 541 resp->status, resp->state);
271 return 0; 542 return 0;
272} 543}
273 544
274static int 545static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p,
275xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) 546 struct nsm_res *resp)
276{ 547{
277 resp->state = ntohl(*p++); 548 struct xdr_stream xdr;
549
550 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
551 p = xdr_inline_decode(&xdr, sizeof(u32));
552 if (unlikely(p == NULL))
553 return -EIO;
554 resp->state = ntohl(*p);
555
556 dprintk("lockd: xdr_dec_stat state %d\n", resp->state);
278 return 0; 557 return 0;
279} 558}
280 559
@@ -288,22 +567,22 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
288#define SM_unmonres_sz 1 567#define SM_unmonres_sz 1
289 568
290static struct rpc_procinfo nsm_procedures[] = { 569static struct rpc_procinfo nsm_procedures[] = {
291[SM_MON] = { 570[NSMPROC_MON] = {
292 .p_proc = SM_MON, 571 .p_proc = NSMPROC_MON,
293 .p_encode = (kxdrproc_t) xdr_encode_mon, 572 .p_encode = (kxdrproc_t)xdr_enc_mon,
294 .p_decode = (kxdrproc_t) xdr_decode_stat_res, 573 .p_decode = (kxdrproc_t)xdr_dec_stat_res,
295 .p_arglen = SM_mon_sz, 574 .p_arglen = SM_mon_sz,
296 .p_replen = SM_monres_sz, 575 .p_replen = SM_monres_sz,
297 .p_statidx = SM_MON, 576 .p_statidx = NSMPROC_MON,
298 .p_name = "MONITOR", 577 .p_name = "MONITOR",
299 }, 578 },
300[SM_UNMON] = { 579[NSMPROC_UNMON] = {
301 .p_proc = SM_UNMON, 580 .p_proc = NSMPROC_UNMON,
302 .p_encode = (kxdrproc_t) xdr_encode_unmon, 581 .p_encode = (kxdrproc_t)xdr_enc_unmon,
303 .p_decode = (kxdrproc_t) xdr_decode_stat, 582 .p_decode = (kxdrproc_t)xdr_dec_stat,
304 .p_arglen = SM_mon_id_sz, 583 .p_arglen = SM_mon_id_sz,
305 .p_replen = SM_unmonres_sz, 584 .p_replen = SM_unmonres_sz,
306 .p_statidx = SM_UNMON, 585 .p_statidx = NSMPROC_UNMON,
307 .p_name = "UNMONITOR", 586 .p_name = "UNMONITOR",
308 }, 587 },
309}; 588};
@@ -322,7 +601,7 @@ static struct rpc_stat nsm_stats;
322 601
323static struct rpc_program nsm_program = { 602static struct rpc_program nsm_program = {
324 .name = "statd", 603 .name = "statd",
325 .number = SM_PROGRAM, 604 .number = NSM_PROGRAM,
326 .nrvers = ARRAY_SIZE(nsm_version), 605 .nrvers = ARRAY_SIZE(nsm_version),
327 .version = nsm_version, 606 .version = nsm_version,
328 .stats = &nsm_stats 607 .stats = &nsm_stats
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 252d80163d02..64f1c31b5853 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -35,7 +35,6 @@
35#include <linux/sunrpc/svcsock.h> 35#include <linux/sunrpc/svcsock.h>
36#include <net/ip.h> 36#include <net/ip.h>
37#include <linux/lockd/lockd.h> 37#include <linux/lockd/lockd.h>
38#include <linux/lockd/sm_inter.h>
39#include <linux/nfs.h> 38#include <linux/nfs.h>
40 39
41#define NLMDBG_FACILITY NLMDBG_SVC 40#define NLMDBG_FACILITY NLMDBG_SVC
@@ -54,13 +53,26 @@ static struct svc_rqst *nlmsvc_rqst;
54unsigned long nlmsvc_timeout; 53unsigned long nlmsvc_timeout;
55 54
56/* 55/*
56 * If the kernel has IPv6 support available, always listen for
57 * both AF_INET and AF_INET6 requests.
58 */
59#if (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) && \
60 defined(CONFIG_SUNRPC_REGISTER_V4)
61static const sa_family_t nlmsvc_family = AF_INET6;
62#else /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
63static const sa_family_t nlmsvc_family = AF_INET;
64#endif /* (CONFIG_IPV6 || CONFIG_IPV6_MODULE) && CONFIG_SUNRPC_REGISTER_V4 */
65
66/*
57 * These can be set at insmod time (useful for NFS as root filesystem), 67 * These can be set at insmod time (useful for NFS as root filesystem),
58 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 68 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
59 */ 69 */
60static unsigned long nlm_grace_period; 70static unsigned long nlm_grace_period;
61static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; 71static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
62static int nlm_udpport, nlm_tcpport; 72static int nlm_udpport, nlm_tcpport;
63int nsm_use_hostnames = 0; 73
74/* RLIM_NOFILE defaults to 1024. That seems like a reasonable default here. */
75static unsigned int nlm_max_connections = 1024;
64 76
65/* 77/*
66 * Constants needed for the sysctl interface. 78 * Constants needed for the sysctl interface.
@@ -143,6 +155,9 @@ lockd(void *vrqstp)
143 long timeout = MAX_SCHEDULE_TIMEOUT; 155 long timeout = MAX_SCHEDULE_TIMEOUT;
144 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 156 RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
145 157
158 /* update sv_maxconn if it has changed */
159 rqstp->rq_server->sv_maxconn = nlm_max_connections;
160
146 if (signalled()) { 161 if (signalled()) {
147 flush_signals(current); 162 flush_signals(current);
148 if (nlmsvc_ops) { 163 if (nlmsvc_ops) {
@@ -189,6 +204,19 @@ lockd(void *vrqstp)
189 return 0; 204 return 0;
190} 205}
191 206
207static int create_lockd_listener(struct svc_serv *serv, char *name,
208 unsigned short port)
209{
210 struct svc_xprt *xprt;
211
212 xprt = svc_find_xprt(serv, name, 0, 0);
213 if (xprt == NULL)
214 return svc_create_xprt(serv, name, port, SVC_SOCK_DEFAULTS);
215
216 svc_xprt_put(xprt);
217 return 0;
218}
219
192/* 220/*
193 * Ensure there are active UDP and TCP listeners for lockd. 221 * Ensure there are active UDP and TCP listeners for lockd.
194 * 222 *
@@ -202,29 +230,23 @@ lockd(void *vrqstp)
202static int make_socks(struct svc_serv *serv) 230static int make_socks(struct svc_serv *serv)
203{ 231{
204 static int warned; 232 static int warned;
205 struct svc_xprt *xprt; 233 int err;
206 int err = 0;
207 234
208 xprt = svc_find_xprt(serv, "udp", 0, 0); 235 err = create_lockd_listener(serv, "udp", nlm_udpport);
209 if (!xprt) 236 if (err < 0)
210 err = svc_create_xprt(serv, "udp", nlm_udpport, 237 goto out_err;
211 SVC_SOCK_DEFAULTS); 238
212 else 239 err = create_lockd_listener(serv, "tcp", nlm_tcpport);
213 svc_xprt_put(xprt); 240 if (err < 0)
214 if (err >= 0) { 241 goto out_err;
215 xprt = svc_find_xprt(serv, "tcp", 0, 0); 242
216 if (!xprt) 243 warned = 0;
217 err = svc_create_xprt(serv, "tcp", nlm_tcpport, 244 return 0;
218 SVC_SOCK_DEFAULTS); 245
219 else 246out_err:
220 svc_xprt_put(xprt); 247 if (warned++ == 0)
221 }
222 if (err >= 0) {
223 warned = 0;
224 err = 0;
225 } else if (warned++ == 0)
226 printk(KERN_WARNING 248 printk(KERN_WARNING
227 "lockd_up: makesock failed, error=%d\n", err); 249 "lockd_up: makesock failed, error=%d\n", err);
228 return err; 250 return err;
229} 251}
230 252
@@ -252,7 +274,7 @@ int lockd_up(void)
252 "lockd_up: no pid, %d users??\n", nlmsvc_users); 274 "lockd_up: no pid, %d users??\n", nlmsvc_users);
253 275
254 error = -ENOMEM; 276 error = -ENOMEM;
255 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL); 277 serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, nlmsvc_family, NULL);
256 if (!serv) { 278 if (!serv) {
257 printk(KERN_WARNING "lockd_up: create service failed\n"); 279 printk(KERN_WARNING "lockd_up: create service failed\n");
258 goto out; 280 goto out;
@@ -276,6 +298,7 @@ int lockd_up(void)
276 } 298 }
277 299
278 svc_sock_update_bufs(serv); 300 svc_sock_update_bufs(serv);
301 serv->sv_maxconn = nlm_max_connections;
279 302
280 nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); 303 nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
281 if (IS_ERR(nlmsvc_task)) { 304 if (IS_ERR(nlmsvc_task)) {
@@ -485,6 +508,7 @@ module_param_call(nlm_udpport, param_set_port, param_get_int,
485module_param_call(nlm_tcpport, param_set_port, param_get_int, 508module_param_call(nlm_tcpport, param_set_port, param_get_int,
486 &nlm_tcpport, 0644); 509 &nlm_tcpport, 0644);
487module_param(nsm_use_hostnames, bool, 0644); 510module_param(nsm_use_hostnames, bool, 0644);
511module_param(nlm_max_connections, uint, 0644);
488 512
489/* 513/*
490 * Initialising and terminating the module. 514 * Initialising and terminating the module.
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 4dfdcbc6bf68..1725037374c5 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -16,8 +16,6 @@
16#include <linux/nfsd/nfsd.h> 16#include <linux/nfsd/nfsd.h>
17#include <linux/lockd/lockd.h> 17#include <linux/lockd/lockd.h>
18#include <linux/lockd/share.h> 18#include <linux/lockd/share.h>
19#include <linux/lockd/sm_inter.h>
20
21 19
22#define NLMDBG_FACILITY NLMDBG_CLIENT 20#define NLMDBG_FACILITY NLMDBG_CLIENT
23 21
@@ -419,8 +417,6 @@ static __be32
419nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, 417nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
420 void *resp) 418 void *resp)
421{ 419{
422 struct sockaddr_in saddr;
423
424 dprintk("lockd: SM_NOTIFY called\n"); 420 dprintk("lockd: SM_NOTIFY called\n");
425 421
426 if (!nlm_privileged_requester(rqstp)) { 422 if (!nlm_privileged_requester(rqstp)) {
@@ -430,14 +426,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
430 return rpc_system_err; 426 return rpc_system_err;
431 } 427 }
432 428
433 /* Obtain the host pointer for this NFS server and try to 429 nlm_host_rebooted(argp);
434 * reclaim all locks we hold on this server.
435 */
436 memset(&saddr, 0, sizeof(saddr));
437 saddr.sin_family = AF_INET;
438 saddr.sin_addr.s_addr = argp->addr;
439 nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
440
441 return rpc_success; 430 return rpc_success;
442} 431}
443 432
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 3ca89e2a9381..3688e55901fc 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -16,8 +16,6 @@
16#include <linux/nfsd/nfsd.h> 16#include <linux/nfsd/nfsd.h>
17#include <linux/lockd/lockd.h> 17#include <linux/lockd/lockd.h>
18#include <linux/lockd/share.h> 18#include <linux/lockd/share.h>
19#include <linux/lockd/sm_inter.h>
20
21 19
22#define NLMDBG_FACILITY NLMDBG_CLIENT 20#define NLMDBG_FACILITY NLMDBG_CLIENT
23 21
@@ -451,8 +449,6 @@ static __be32
451nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, 449nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
452 void *resp) 450 void *resp)
453{ 451{
454 struct sockaddr_in saddr;
455
456 dprintk("lockd: SM_NOTIFY called\n"); 452 dprintk("lockd: SM_NOTIFY called\n");
457 453
458 if (!nlm_privileged_requester(rqstp)) { 454 if (!nlm_privileged_requester(rqstp)) {
@@ -462,14 +458,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
462 return rpc_system_err; 458 return rpc_system_err;
463 } 459 }
464 460
465 /* Obtain the host pointer for this NFS server and try to 461 nlm_host_rebooted(argp);
466 * reclaim all locks we hold on this server.
467 */
468 memset(&saddr, 0, sizeof(saddr));
469 saddr.sin_family = AF_INET;
470 saddr.sin_addr.s_addr = argp->addr;
471 nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
472
473 return rpc_success; 462 return rpc_success;
474} 463}
475 464
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 34c2766e27c7..9e4d6aab611b 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -17,7 +17,6 @@
17#include <linux/nfsd/export.h> 17#include <linux/nfsd/export.h>
18#include <linux/lockd/lockd.h> 18#include <linux/lockd/lockd.h>
19#include <linux/lockd/share.h> 19#include <linux/lockd/share.h>
20#include <linux/lockd/sm_inter.h>
21#include <linux/module.h> 20#include <linux/module.h>
22#include <linux/mount.h> 21#include <linux/mount.h>
23 22
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 1f226290c67c..0336f2beacde 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -16,7 +16,6 @@
16#include <linux/sunrpc/svc.h> 16#include <linux/sunrpc/svc.h>
17#include <linux/sunrpc/stats.h> 17#include <linux/sunrpc/stats.h>
18#include <linux/lockd/lockd.h> 18#include <linux/lockd/lockd.h>
19#include <linux/lockd/sm_inter.h>
20 19
21#define NLMDBG_FACILITY NLMDBG_XDR 20#define NLMDBG_FACILITY NLMDBG_XDR
22 21
@@ -349,8 +348,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
349 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) 348 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
350 return 0; 349 return 0;
351 argp->state = ntohl(*p++); 350 argp->state = ntohl(*p++);
352 /* Preserve the address in network byte order */ 351 memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
353 argp->addr = *p++; 352 p += XDR_QUADLEN(SM_PRIV_SIZE);
354 return xdr_argsize_check(rqstp, p); 353 return xdr_argsize_check(rqstp, p);
355} 354}
356 355
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 50c493a8ad8e..e1d528653192 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -17,7 +17,6 @@
17#include <linux/sunrpc/svc.h> 17#include <linux/sunrpc/svc.h>
18#include <linux/sunrpc/stats.h> 18#include <linux/sunrpc/stats.h>
19#include <linux/lockd/lockd.h> 19#include <linux/lockd/lockd.h>
20#include <linux/lockd/sm_inter.h>
21 20
22#define NLMDBG_FACILITY NLMDBG_XDR 21#define NLMDBG_FACILITY NLMDBG_XDR
23 22
@@ -356,8 +355,8 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
356 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) 355 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
357 return 0; 356 return 0;
358 argp->state = ntohl(*p++); 357 argp->state = ntohl(*p++);
359 /* Preserve the address in network byte order */ 358 memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
360 argp->addr = *p++; 359 p += XDR_QUADLEN(SM_PRIV_SIZE);
361 return xdr_argsize_check(rqstp, p); 360 return xdr_argsize_check(rqstp, p);
362} 361}
363 362
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 0184fe9b514c..c903e04aa217 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -76,10 +76,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
76 76
77 ret = set_groups(new, gi); 77 ret = set_groups(new, gi);
78 put_group_info(gi); 78 put_group_info(gi);
79 if (!ret) 79 if (ret < 0)
80 goto error; 80 goto error;
81 81
82 if (new->uid) 82 if (new->fsuid)
83 new->cap_effective = cap_drop_nfsd_set(new->cap_effective); 83 new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
84 else 84 else
85 new->cap_effective = cap_raise_nfsd_set(new->cap_effective, 85 new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 6d7d8c02c197..c464181b5994 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -53,9 +53,6 @@
53#define NFSPROC4_CB_NULL 0 53#define NFSPROC4_CB_NULL 0
54#define NFSPROC4_CB_COMPOUND 1 54#define NFSPROC4_CB_COMPOUND 1
55 55
56/* declarations */
57static const struct rpc_call_ops nfs4_cb_null_ops;
58
59/* Index of predefined Linux callback client operations */ 56/* Index of predefined Linux callback client operations */
60 57
61enum { 58enum {
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 669461e291ae..9fa60a3ad48c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -946,6 +946,11 @@ encode_op:
946 nfsd4_encode_operation(resp, op); 946 nfsd4_encode_operation(resp, op);
947 status = op->status; 947 status = op->status;
948 } 948 }
949
950 dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
951 args->ops, args->opcnt, resp->opcnt, op->opnum,
952 be32_to_cpu(status));
953
949 if (cstate->replay_owner) { 954 if (cstate->replay_owner) {
950 nfs4_put_stateowner(cstate->replay_owner); 955 nfs4_put_stateowner(cstate->replay_owner);
951 cstate->replay_owner = NULL; 956 cstate->replay_owner = NULL;
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 0f9d6efaa62b..74f7b67567fd 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -116,9 +116,9 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
116 116
117 md5_to_hex(dname, cksum.data); 117 md5_to_hex(dname, cksum.data);
118 118
119 kfree(cksum.data);
120 status = nfs_ok; 119 status = nfs_ok;
121out: 120out:
121 kfree(cksum.data);
122 crypto_free_hash(desc.tfm); 122 crypto_free_hash(desc.tfm);
123out_no_tfm: 123out_no_tfm:
124 return status; 124 return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 13e0e074dbb8..88db7d3ec120 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2416,6 +2416,26 @@ out:
2416#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) 2416#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS)
2417#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) 2417#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1)
2418 2418
2419static inline u64
2420end_offset(u64 start, u64 len)
2421{
2422 u64 end;
2423
2424 end = start + len;
2425 return end >= start ? end: NFS4_MAX_UINT64;
2426}
2427
2428/* last octet in a range */
2429static inline u64
2430last_byte_offset(u64 start, u64 len)
2431{
2432 u64 end;
2433
2434 BUG_ON(!len);
2435 end = start + len;
2436 return end > start ? end - 1: NFS4_MAX_UINT64;
2437}
2438
2419#define lockownerid_hashval(id) \ 2439#define lockownerid_hashval(id) \
2420 ((id) & LOCK_HASH_MASK) 2440 ((id) & LOCK_HASH_MASK)
2421 2441
@@ -2435,13 +2455,13 @@ static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
2435static struct nfs4_stateid * 2455static struct nfs4_stateid *
2436find_stateid(stateid_t *stid, int flags) 2456find_stateid(stateid_t *stid, int flags)
2437{ 2457{
2438 struct nfs4_stateid *local = NULL; 2458 struct nfs4_stateid *local;
2439 u32 st_id = stid->si_stateownerid; 2459 u32 st_id = stid->si_stateownerid;
2440 u32 f_id = stid->si_fileid; 2460 u32 f_id = stid->si_fileid;
2441 unsigned int hashval; 2461 unsigned int hashval;
2442 2462
2443 dprintk("NFSD: find_stateid flags 0x%x\n",flags); 2463 dprintk("NFSD: find_stateid flags 0x%x\n",flags);
2444 if ((flags & LOCK_STATE) || (flags & RD_STATE) || (flags & WR_STATE)) { 2464 if (flags & (LOCK_STATE | RD_STATE | WR_STATE)) {
2445 hashval = stateid_hashval(st_id, f_id); 2465 hashval = stateid_hashval(st_id, f_id);
2446 list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { 2466 list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
2447 if ((local->st_stateid.si_stateownerid == st_id) && 2467 if ((local->st_stateid.si_stateownerid == st_id) &&
@@ -2449,7 +2469,8 @@ find_stateid(stateid_t *stid, int flags)
2449 return local; 2469 return local;
2450 } 2470 }
2451 } 2471 }
2452 if ((flags & OPEN_STATE) || (flags & RD_STATE) || (flags & WR_STATE)) { 2472
2473 if (flags & (OPEN_STATE | RD_STATE | WR_STATE)) {
2453 hashval = stateid_hashval(st_id, f_id); 2474 hashval = stateid_hashval(st_id, f_id);
2454 list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { 2475 list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
2455 if ((local->st_stateid.si_stateownerid == st_id) && 2476 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 deny->ld_clientid.cl_id = 0; 2539 deny->ld_clientid.cl_id = 0;
2519 } 2540 }
2520 deny->ld_start = fl->fl_start; 2541 deny->ld_start = fl->fl_start;
2521 deny->ld_length = ~(u64)0; 2542 deny->ld_length = NFS4_MAX_UINT64;
2522 if (fl->fl_end != ~(u64)0) 2543 if (fl->fl_end != NFS4_MAX_UINT64)
2523 deny->ld_length = fl->fl_end - fl->fl_start + 1; 2544 deny->ld_length = fl->fl_end - fl->fl_start + 1;
2524 deny->ld_type = NFS4_READ_LT; 2545 deny->ld_type = NFS4_READ_LT;
2525 if (fl->fl_type != F_RDLCK) 2546 if (fl->fl_type != F_RDLCK)
@@ -2616,7 +2637,7 @@ out:
2616static int 2637static int
2617check_lock_length(u64 offset, u64 length) 2638check_lock_length(u64 offset, u64 length)
2618{ 2639{
2619 return ((length == 0) || ((length != ~(u64)0) && 2640 return ((length == 0) || ((length != NFS4_MAX_UINT64) &&
2620 LOFF_OVERFLOW(offset, length))); 2641 LOFF_OVERFLOW(offset, length)));
2621} 2642}
2622 2643
@@ -2736,11 +2757,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2736 file_lock.fl_lmops = &nfsd_posix_mng_ops; 2757 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2737 2758
2738 file_lock.fl_start = lock->lk_offset; 2759 file_lock.fl_start = lock->lk_offset;
2739 if ((lock->lk_length == ~(u64)0) || 2760 file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
2740 LOFF_OVERFLOW(lock->lk_offset, lock->lk_length))
2741 file_lock.fl_end = ~(u64)0;
2742 else
2743 file_lock.fl_end = lock->lk_offset + lock->lk_length - 1;
2744 nfs4_transform_lock_offset(&file_lock); 2761 nfs4_transform_lock_offset(&file_lock);
2745 2762
2746 /* 2763 /*
@@ -2781,6 +2798,25 @@ out:
2781} 2798}
2782 2799
2783/* 2800/*
2801 * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
2802 * so we do a temporary open here just to get an open file to pass to
2803 * vfs_test_lock. (Arguably perhaps test_lock should be done with an
2804 * inode operation.)
2805 */
2806static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
2807{
2808 struct file *file;
2809 int err;
2810
2811 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
2812 if (err)
2813 return err;
2814 err = vfs_test_lock(file, lock);
2815 nfsd_close(file);
2816 return err;
2817}
2818
2819/*
2784 * LOCKT operation 2820 * LOCKT operation
2785 */ 2821 */
2786__be32 2822__be32
@@ -2788,7 +2824,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2788 struct nfsd4_lockt *lockt) 2824 struct nfsd4_lockt *lockt)
2789{ 2825{
2790 struct inode *inode; 2826 struct inode *inode;
2791 struct file file;
2792 struct file_lock file_lock; 2827 struct file_lock file_lock;
2793 int error; 2828 int error;
2794 __be32 status; 2829 __be32 status;
@@ -2839,23 +2874,12 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2839 file_lock.fl_lmops = &nfsd_posix_mng_ops; 2874 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2840 2875
2841 file_lock.fl_start = lockt->lt_offset; 2876 file_lock.fl_start = lockt->lt_offset;
2842 if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length)) 2877 file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
2843 file_lock.fl_end = ~(u64)0;
2844 else
2845 file_lock.fl_end = lockt->lt_offset + lockt->lt_length - 1;
2846 2878
2847 nfs4_transform_lock_offset(&file_lock); 2879 nfs4_transform_lock_offset(&file_lock);
2848 2880
2849 /* vfs_test_lock uses the struct file _only_ to resolve the inode.
2850 * since LOCKT doesn't require an OPEN, and therefore a struct
2851 * file may not exist, pass vfs_test_lock a struct file with
2852 * only the dentry:inode set.
2853 */
2854 memset(&file, 0, sizeof (struct file));
2855 file.f_path.dentry = cstate->current_fh.fh_dentry;
2856
2857 status = nfs_ok; 2881 status = nfs_ok;
2858 error = vfs_test_lock(&file, &file_lock); 2882 error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
2859 if (error) { 2883 if (error) {
2860 status = nfserrno(error); 2884 status = nfserrno(error);
2861 goto out; 2885 goto out;
@@ -2906,10 +2930,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2906 file_lock.fl_lmops = &nfsd_posix_mng_ops; 2930 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2907 file_lock.fl_start = locku->lu_offset; 2931 file_lock.fl_start = locku->lu_offset;
2908 2932
2909 if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length)) 2933 file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
2910 file_lock.fl_end = ~(u64)0;
2911 else
2912 file_lock.fl_end = locku->lu_offset + locku->lu_length - 1;
2913 nfs4_transform_lock_offset(&file_lock); 2934 nfs4_transform_lock_offset(&file_lock);
2914 2935
2915 /* 2936 /*
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index afcdf4b76843..f65953be39c0 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1,6 +1,4 @@
1/* 1/*
2 * fs/nfs/nfs4xdr.c
3 *
4 * Server-side XDR for NFSv4 2 * Server-side XDR for NFSv4
5 * 3 *
6 * Copyright (c) 2002 The Regents of the University of Michigan. 4 * Copyright (c) 2002 The Regents of the University of Michigan.
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 77d7b8c531a6..3d93b2064ce5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -84,6 +84,8 @@ static ssize_t write_unexport(struct file *file, char *buf, size_t size);
84static ssize_t write_getfd(struct file *file, char *buf, size_t size); 84static ssize_t write_getfd(struct file *file, char *buf, size_t size);
85static ssize_t write_getfs(struct file *file, char *buf, size_t size); 85static ssize_t write_getfs(struct file *file, char *buf, size_t size);
86static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 86static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
87static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
88static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
87static ssize_t write_threads(struct file *file, char *buf, size_t size); 89static ssize_t write_threads(struct file *file, char *buf, size_t size);
88static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); 90static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
89static ssize_t write_versions(struct file *file, char *buf, size_t size); 91static ssize_t write_versions(struct file *file, char *buf, size_t size);
@@ -94,9 +96,6 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
94static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); 96static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
95#endif 97#endif
96 98
97static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size);
98static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size);
99
100static ssize_t (*write_op[])(struct file *, char *, size_t) = { 99static ssize_t (*write_op[])(struct file *, char *, size_t) = {
101 [NFSD_Svc] = write_svc, 100 [NFSD_Svc] = write_svc,
102 [NFSD_Add] = write_add, 101 [NFSD_Add] = write_add,
@@ -106,8 +105,8 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
106 [NFSD_Getfd] = write_getfd, 105 [NFSD_Getfd] = write_getfd,
107 [NFSD_Getfs] = write_getfs, 106 [NFSD_Getfs] = write_getfs,
108 [NFSD_Fh] = write_filehandle, 107 [NFSD_Fh] = write_filehandle,
109 [NFSD_FO_UnlockIP] = failover_unlock_ip, 108 [NFSD_FO_UnlockIP] = write_unlock_ip,
110 [NFSD_FO_UnlockFS] = failover_unlock_fs, 109 [NFSD_FO_UnlockFS] = write_unlock_fs,
111 [NFSD_Threads] = write_threads, 110 [NFSD_Threads] = write_threads,
112 [NFSD_Pool_Threads] = write_pool_threads, 111 [NFSD_Pool_Threads] = write_pool_threads,
113 [NFSD_Versions] = write_versions, 112 [NFSD_Versions] = write_versions,
@@ -176,10 +175,24 @@ static const struct file_operations exports_operations = {
176/*----------------------------------------------------------------------------*/ 175/*----------------------------------------------------------------------------*/
177/* 176/*
178 * payload - write methods 177 * payload - write methods
179 * If the method has a response, the response should be put in buf,
180 * and the length returned. Otherwise return 0 or and -error.
181 */ 178 */
182 179
180/**
181 * write_svc - Start kernel's NFSD server
182 *
183 * Deprecated. /proc/fs/nfsd/threads is preferred.
184 * Function remains to support old versions of nfs-utils.
185 *
186 * Input:
187 * buf: struct nfsctl_svc
188 * svc_port: port number of this
189 * server's listener
190 * svc_nthreads: number of threads to start
191 * size: size in bytes of passed in nfsctl_svc
192 * Output:
193 * On success: returns zero
194 * On error: return code is negative errno value
195 */
183static ssize_t write_svc(struct file *file, char *buf, size_t size) 196static ssize_t write_svc(struct file *file, char *buf, size_t size)
184{ 197{
185 struct nfsctl_svc *data; 198 struct nfsctl_svc *data;
@@ -189,6 +202,30 @@ static ssize_t write_svc(struct file *file, char *buf, size_t size)
189 return nfsd_svc(data->svc_port, data->svc_nthreads); 202 return nfsd_svc(data->svc_port, data->svc_nthreads);
190} 203}
191 204
205/**
206 * write_add - Add or modify client entry in auth unix cache
207 *
208 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
209 * Function remains to support old versions of nfs-utils.
210 *
211 * Input:
212 * buf: struct nfsctl_client
213 * cl_ident: '\0'-terminated C string
214 * containing domain name
215 * of client
216 * cl_naddr: no. of items in cl_addrlist
217 * cl_addrlist: array of client addresses
218 * cl_fhkeytype: ignored
219 * cl_fhkeylen: ignored
220 * cl_fhkey: ignored
221 * size: size in bytes of passed in nfsctl_client
222 * Output:
223 * On success: returns zero
224 * On error: return code is negative errno value
225 *
226 * Note: Only AF_INET client addresses are passed in, since
227 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
228 */
192static ssize_t write_add(struct file *file, char *buf, size_t size) 229static ssize_t write_add(struct file *file, char *buf, size_t size)
193{ 230{
194 struct nfsctl_client *data; 231 struct nfsctl_client *data;
@@ -198,6 +235,30 @@ static ssize_t write_add(struct file *file, char *buf, size_t size)
198 return exp_addclient(data); 235 return exp_addclient(data);
199} 236}
200 237
238/**
239 * write_del - Remove client from auth unix cache
240 *
241 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
242 * Function remains to support old versions of nfs-utils.
243 *
244 * Input:
245 * buf: struct nfsctl_client
246 * cl_ident: '\0'-terminated C string
247 * containing domain name
248 * of client
249 * cl_naddr: ignored
250 * cl_addrlist: ignored
251 * cl_fhkeytype: ignored
252 * cl_fhkeylen: ignored
253 * cl_fhkey: ignored
254 * size: size in bytes of passed in nfsctl_client
255 * Output:
256 * On success: returns zero
257 * On error: return code is negative errno value
258 *
259 * Note: Only AF_INET client addresses are passed in, since
260 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
261 */
201static ssize_t write_del(struct file *file, char *buf, size_t size) 262static ssize_t write_del(struct file *file, char *buf, size_t size)
202{ 263{
203 struct nfsctl_client *data; 264 struct nfsctl_client *data;
@@ -207,6 +268,33 @@ static ssize_t write_del(struct file *file, char *buf, size_t size)
207 return exp_delclient(data); 268 return exp_delclient(data);
208} 269}
209 270
271/**
272 * write_export - Export part or all of a local file system
273 *
274 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
275 * Function remains to support old versions of nfs-utils.
276 *
277 * Input:
278 * buf: struct nfsctl_export
279 * ex_client: '\0'-terminated C string
280 * containing domain name
281 * of client allowed to access
282 * this export
283 * ex_path: '\0'-terminated C string
284 * containing pathname of
285 * directory in local file system
286 * ex_dev: fsid to use for this export
287 * ex_ino: ignored
288 * ex_flags: export flags for this export
289 * ex_anon_uid: UID to use for anonymous
290 * requests
291 * ex_anon_gid: GID to use for anonymous
292 * requests
293 * size: size in bytes of passed in nfsctl_export
294 * Output:
295 * On success: returns zero
296 * On error: return code is negative errno value
297 */
210static ssize_t write_export(struct file *file, char *buf, size_t size) 298static ssize_t write_export(struct file *file, char *buf, size_t size)
211{ 299{
212 struct nfsctl_export *data; 300 struct nfsctl_export *data;
@@ -216,6 +304,31 @@ static ssize_t write_export(struct file *file, char *buf, size_t size)
216 return exp_export(data); 304 return exp_export(data);
217} 305}
218 306
307/**
308 * write_unexport - Unexport a previously exported file system
309 *
310 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
311 * Function remains to support old versions of nfs-utils.
312 *
313 * Input:
314 * buf: struct nfsctl_export
315 * ex_client: '\0'-terminated C string
316 * containing domain name
317 * of client no longer allowed
318 * to access this export
319 * ex_path: '\0'-terminated C string
320 * containing pathname of
321 * directory in local file system
322 * ex_dev: ignored
323 * ex_ino: ignored
324 * ex_flags: ignored
325 * ex_anon_uid: ignored
326 * ex_anon_gid: ignored
327 * size: size in bytes of passed in nfsctl_export
328 * Output:
329 * On success: returns zero
330 * On error: return code is negative errno value
331 */
219static ssize_t write_unexport(struct file *file, char *buf, size_t size) 332static ssize_t write_unexport(struct file *file, char *buf, size_t size)
220{ 333{
221 struct nfsctl_export *data; 334 struct nfsctl_export *data;
@@ -226,6 +339,30 @@ static ssize_t write_unexport(struct file *file, char *buf, size_t size)
226 return exp_unexport(data); 339 return exp_unexport(data);
227} 340}
228 341
342/**
343 * write_getfs - Get a variable-length NFS file handle by path
344 *
345 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
346 * Function remains to support old versions of nfs-utils.
347 *
348 * Input:
349 * buf: struct nfsctl_fsparm
350 * gd_addr: socket address of client
351 * gd_path: '\0'-terminated C string
352 * containing pathname of
353 * directory in local file system
354 * gd_maxlen: maximum size of returned file
355 * handle
356 * size: size in bytes of passed in nfsctl_fsparm
357 * Output:
358 * On success: passed-in buffer filled with a knfsd_fh structure
359 * (a variable-length raw NFS file handle);
360 * return code is the size in bytes of the file handle
361 * On error: return code is negative errno value
362 *
363 * Note: Only AF_INET client addresses are passed in, since gd_addr
364 * is the same size as a struct sockaddr_in.
365 */
229static ssize_t write_getfs(struct file *file, char *buf, size_t size) 366static ssize_t write_getfs(struct file *file, char *buf, size_t size)
230{ 367{
231 struct nfsctl_fsparm *data; 368 struct nfsctl_fsparm *data;
@@ -265,6 +402,29 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
265 return err; 402 return err;
266} 403}
267 404
405/**
406 * write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
407 *
408 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
409 * Function remains to support old versions of nfs-utils.
410 *
411 * Input:
412 * buf: struct nfsctl_fdparm
413 * gd_addr: socket address of client
414 * gd_path: '\0'-terminated C string
415 * containing pathname of
416 * directory in local file system
417 * gd_version: fdparm structure version
418 * size: size in bytes of passed in nfsctl_fdparm
419 * Output:
420 * On success: passed-in buffer filled with nfsctl_res
421 * (a fixed-length raw NFS file handle);
422 * return code is the size in bytes of the file handle
423 * On error: return code is negative errno value
424 *
425 * Note: Only AF_INET client addresses are passed in, since gd_addr
426 * is the same size as a struct sockaddr_in.
427 */
268static ssize_t write_getfd(struct file *file, char *buf, size_t size) 428static ssize_t write_getfd(struct file *file, char *buf, size_t size)
269{ 429{
270 struct nfsctl_fdparm *data; 430 struct nfsctl_fdparm *data;
@@ -309,7 +469,23 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
309 return err; 469 return err;
310} 470}
311 471
312static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) 472/**
473 * write_unlock_ip - Release all locks used by a client
474 *
475 * Experimental.
476 *
477 * Input:
478 * buf: '\n'-terminated C string containing a
479 * presentation format IPv4 address
480 * size: length of C string in @buf
481 * Output:
482 * On success: returns zero if all specified locks were released;
483 * returns one if one or more locks were not released
484 * On error: return code is negative errno value
485 *
486 * Note: Only AF_INET client addresses are passed in
487 */
488static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
313{ 489{
314 struct sockaddr_in sin = { 490 struct sockaddr_in sin = {
315 .sin_family = AF_INET, 491 .sin_family = AF_INET,
@@ -339,7 +515,21 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
339 return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin); 515 return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin);
340} 516}
341 517
342static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) 518/**
519 * write_unlock_fs - Release all locks on a local file system
520 *
521 * Experimental.
522 *
523 * Input:
524 * buf: '\n'-terminated C string containing the
525 * absolute pathname of a local file system
526 * size: length of C string in @buf
527 * Output:
528 * On success: returns zero if all specified locks were released;
529 * returns one if one or more locks were not released
530 * On error: return code is negative errno value
531 */
532static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
343{ 533{
344 struct path path; 534 struct path path;
345 char *fo_path; 535 char *fo_path;
@@ -360,21 +550,44 @@ static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
360 if (error) 550 if (error)
361 return error; 551 return error;
362 552
553 /*
554 * XXX: Needs better sanity checking. Otherwise we could end up
555 * releasing locks on the wrong file system.
556 *
557 * For example:
558 * 1. Does the path refer to a directory?
559 * 2. Is that directory a mount point, or
560 * 3. Is that directory the root of an exported file system?
561 */
363 error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb); 562 error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
364 563
365 path_put(&path); 564 path_put(&path);
366 return error; 565 return error;
367} 566}
368 567
568/**
569 * write_filehandle - Get a variable-length NFS file handle by path
570 *
571 * On input, the buffer contains a '\n'-terminated C string comprised of
572 * three alphanumeric words separated by whitespace. The string may
573 * contain escape sequences.
574 *
575 * Input:
576 * buf:
577 * domain: client domain name
578 * path: export pathname
579 * maxsize: numeric maximum size of
580 * @buf
581 * size: length of C string in @buf
582 * Output:
583 * On success: passed-in buffer filled with '\n'-terminated C
584 * string containing a ASCII hex text version
585 * of the NFS file handle;
586 * return code is the size in bytes of the string
587 * On error: return code is negative errno value
588 */
369static ssize_t write_filehandle(struct file *file, char *buf, size_t size) 589static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
370{ 590{
371 /* request is:
372 * domain path maxsize
373 * response is
374 * filehandle
375 *
376 * qword quoting is used, so filehandle will be \x....
377 */
378 char *dname, *path; 591 char *dname, *path;
379 int uninitialized_var(maxsize); 592 int uninitialized_var(maxsize);
380 char *mesg = buf; 593 char *mesg = buf;
@@ -391,11 +604,13 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
391 604
392 dname = mesg; 605 dname = mesg;
393 len = qword_get(&mesg, dname, size); 606 len = qword_get(&mesg, dname, size);
394 if (len <= 0) return -EINVAL; 607 if (len <= 0)
608 return -EINVAL;
395 609
396 path = dname+len+1; 610 path = dname+len+1;
397 len = qword_get(&mesg, path, size); 611 len = qword_get(&mesg, path, size);
398 if (len <= 0) return -EINVAL; 612 if (len <= 0)
613 return -EINVAL;
399 614
400 len = get_int(&mesg, &maxsize); 615 len = get_int(&mesg, &maxsize);
401 if (len) 616 if (len)
@@ -419,17 +634,43 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
419 if (len) 634 if (len)
420 return len; 635 return len;
421 636
422 mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; 637 mesg = buf;
638 len = SIMPLE_TRANSACTION_LIMIT;
423 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); 639 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
424 mesg[-1] = '\n'; 640 mesg[-1] = '\n';
425 return mesg - buf; 641 return mesg - buf;
426} 642}
427 643
644/**
645 * write_threads - Start NFSD, or report the current number of running threads
646 *
647 * Input:
648 * buf: ignored
649 * size: zero
650 * Output:
651 * On success: passed-in buffer filled with '\n'-terminated C
652 * string numeric value representing the number of
653 * running NFSD threads;
654 * return code is the size in bytes of the string
655 * On error: return code is zero
656 *
657 * OR
658 *
659 * Input:
660 * buf: C string containing an unsigned
661 * integer value representing the
662 * number of NFSD threads to start
663 * size: non-zero length of C string in @buf
664 * Output:
665 * On success: NFS service is started;
666 * passed-in buffer filled with '\n'-terminated C
667 * string numeric value representing the number of
668 * running NFSD threads;
669 * return code is the size in bytes of the string
670 * On error: return code is zero or a negative errno value
671 */
428static ssize_t write_threads(struct file *file, char *buf, size_t size) 672static ssize_t write_threads(struct file *file, char *buf, size_t size)
429{ 673{
430 /* if size > 0, look for a number of threads and call nfsd_svc
431 * then write out number of threads as reply
432 */
433 char *mesg = buf; 674 char *mesg = buf;
434 int rv; 675 int rv;
435 if (size > 0) { 676 if (size > 0) {
@@ -437,9 +678,9 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
437 rv = get_int(&mesg, &newthreads); 678 rv = get_int(&mesg, &newthreads);
438 if (rv) 679 if (rv)
439 return rv; 680 return rv;
440 if (newthreads <0) 681 if (newthreads < 0)
441 return -EINVAL; 682 return -EINVAL;
442 rv = nfsd_svc(2049, newthreads); 683 rv = nfsd_svc(NFS_PORT, newthreads);
443 if (rv) 684 if (rv)
444 return rv; 685 return rv;
445 } 686 }
@@ -447,6 +688,28 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
447 return strlen(buf); 688 return strlen(buf);
448} 689}
449 690
691/**
692 * write_pool_threads - Set or report the current number of threads per pool
693 *
694 * Input:
695 * buf: ignored
696 * size: zero
697 *
698 * OR
699 *
700 * Input:
701 * buf: C string containing whitespace-
702 * separated unsigned integer values
703 * representing the number of NFSD
704 * threads to start in each pool
705 * size: non-zero length of C string in @buf
706 * Output:
707 * On success: passed-in buffer filled with '\n'-terminated C
708 * string containing integer values representing the
709 * number of NFSD threads in each pool;
710 * return code is the size in bytes of the string
711 * On error: return code is zero or a negative errno value
712 */
450static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) 713static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
451{ 714{
452 /* if size > 0, look for an array of number of threads per node 715 /* if size > 0, look for an array of number of threads per node
@@ -517,10 +780,6 @@ out_free:
517 780
518static ssize_t __write_versions(struct file *file, char *buf, size_t size) 781static ssize_t __write_versions(struct file *file, char *buf, size_t size)
519{ 782{
520 /*
521 * Format:
522 * [-/+]vers [-/+]vers ...
523 */
524 char *mesg = buf; 783 char *mesg = buf;
525 char *vers, sign; 784 char *vers, sign;
526 int len, num; 785 int len, num;
@@ -578,6 +837,38 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
578 return len; 837 return len;
579} 838}
580 839
840/**
841 * write_versions - Set or report the available NFS protocol versions
842 *
843 * Input:
844 * buf: ignored
845 * size: zero
846 * Output:
847 * On success: passed-in buffer filled with '\n'-terminated C
848 * string containing positive or negative integer
849 * values representing the current status of each
850 * protocol version;
851 * return code is the size in bytes of the string
852 * On error: return code is zero or a negative errno value
853 *
854 * OR
855 *
856 * Input:
857 * buf: C string containing whitespace-
858 * separated positive or negative
859 * integer values representing NFS
860 * protocol versions to enable ("+n")
861 * or disable ("-n")
862 * size: non-zero length of C string in @buf
863 * Output:
864 * On success: status of zero or more protocol versions has
865 * been updated; passed-in buffer filled with
866 * '\n'-terminated C string containing positive
867 * or negative integer values representing the
868 * current status of each protocol version;
869 * return code is the size in bytes of the string
870 * On error: return code is zero or a negative errno value
871 */
581static ssize_t write_versions(struct file *file, char *buf, size_t size) 872static ssize_t write_versions(struct file *file, char *buf, size_t size)
582{ 873{
583 ssize_t rv; 874 ssize_t rv;
@@ -687,6 +978,75 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
687 return -EINVAL; 978 return -EINVAL;
688} 979}
689 980
981/**
982 * write_ports - Pass a socket file descriptor or transport name to listen on
983 *
984 * Input:
985 * buf: ignored
986 * size: zero
987 * Output:
988 * On success: passed-in buffer filled with a '\n'-terminated C
989 * string containing a whitespace-separated list of
990 * named NFSD listeners;
991 * return code is the size in bytes of the string
992 * On error: return code is zero or a negative errno value
993 *
994 * OR
995 *
996 * Input:
997 * buf: C string containing an unsigned
998 * integer value representing a bound
999 * but unconnected socket that is to be
1000 * used as an NFSD listener
1001 * size: non-zero length of C string in @buf
1002 * Output:
1003 * On success: NFS service is started;
1004 * passed-in buffer filled with a '\n'-terminated C
1005 * string containing a unique alphanumeric name of
1006 * the listener;
1007 * return code is the size in bytes of the string
1008 * On error: return code is a negative errno value
1009 *
1010 * OR
1011 *
1012 * Input:
1013 * buf: C string containing a "-" followed
1014 * by an integer value representing a
1015 * previously passed in socket file
1016 * descriptor
1017 * size: non-zero length of C string in @buf
1018 * Output:
1019 * On success: NFS service no longer listens on that socket;
1020 * passed-in buffer filled with a '\n'-terminated C
1021 * string containing a unique name of the listener;
1022 * return code is the size in bytes of the string
1023 * On error: return code is a negative errno value
1024 *
1025 * OR
1026 *
1027 * Input:
1028 * buf: C string containing a transport
1029 * name and an unsigned integer value
1030 * representing the port to listen on,
1031 * separated by whitespace
1032 * size: non-zero length of C string in @buf
1033 * Output:
1034 * On success: returns zero; NFS service is started
1035 * On error: return code is a negative errno value
1036 *
1037 * OR
1038 *
1039 * Input:
1040 * buf: C string containing a "-" followed
1041 * by a transport name and an unsigned
1042 * integer value representing the port
1043 * to listen on, separated by whitespace
1044 * size: non-zero length of C string in @buf
1045 * Output:
1046 * On success: returns zero; NFS service no longer listens
1047 * on that transport
1048 * On error: return code is a negative errno value
1049 */
690static ssize_t write_ports(struct file *file, char *buf, size_t size) 1050static ssize_t write_ports(struct file *file, char *buf, size_t size)
691{ 1051{
692 ssize_t rv; 1052 ssize_t rv;
@@ -700,6 +1060,27 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
700 1060
701int nfsd_max_blksize; 1061int nfsd_max_blksize;
702 1062
1063/**
1064 * write_maxblksize - Set or report the current NFS blksize
1065 *
1066 * Input:
1067 * buf: ignored
1068 * size: zero
1069 *
1070 * OR
1071 *
1072 * Input:
1073 * buf: C string containing an unsigned
1074 * integer value representing the new
1075 * NFS blksize
1076 * size: non-zero length of C string in @buf
1077 * Output:
1078 * On success: passed-in buffer filled with '\n'-terminated C string
1079 * containing numeric value of the current NFS blksize
1080 * setting;
1081 * return code is the size in bytes of the string
1082 * On error: return code is zero or a negative errno value
1083 */
703static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) 1084static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
704{ 1085{
705 char *mesg = buf; 1086 char *mesg = buf;
@@ -752,6 +1133,27 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size)
752 return strlen(buf); 1133 return strlen(buf);
753} 1134}
754 1135
1136/**
1137 * write_leasetime - Set or report the current NFSv4 lease time
1138 *
1139 * Input:
1140 * buf: ignored
1141 * size: zero
1142 *
1143 * OR
1144 *
1145 * Input:
1146 * buf: C string containing an unsigned
1147 * integer value representing the new
1148 * NFSv4 lease expiry time
1149 * size: non-zero length of C string in @buf
1150 * Output:
1151 * On success: passed-in buffer filled with '\n'-terminated C
1152 * string containing unsigned integer value of the
1153 * current lease expiry time;
1154 * return code is the size in bytes of the string
1155 * On error: return code is zero or a negative errno value
1156 */
755static ssize_t write_leasetime(struct file *file, char *buf, size_t size) 1157static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
756{ 1158{
757 ssize_t rv; 1159 ssize_t rv;
@@ -788,6 +1190,27 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
788 return strlen(buf); 1190 return strlen(buf);
789} 1191}
790 1192
1193/**
1194 * write_recoverydir - Set or report the pathname of the recovery directory
1195 *
1196 * Input:
1197 * buf: ignored
1198 * size: zero
1199 *
1200 * OR
1201 *
1202 * Input:
1203 * buf: C string containing the pathname
1204 * of the directory on a local file
1205 * system containing permanent NFSv4
1206 * recovery data
1207 * size: non-zero length of C string in @buf
1208 * Output:
1209 * On success: passed-in buffer filled with '\n'-terminated C string
1210 * containing the current recovery pathname setting;
1211 * return code is the size in bytes of the string
1212 * On error: return code is zero or a negative errno value
1213 */
791static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) 1214static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
792{ 1215{
793 ssize_t rv; 1216 ssize_t rv;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index f0da7d9c3a92..9f1ca17293d3 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -258,14 +258,32 @@ out:
258 return error; 258 return error;
259} 259}
260 260
261/* 261/**
262 * Perform sanity checks on the dentry in a client's file handle. 262 * fh_verify - filehandle lookup and access checking
263 * @rqstp: pointer to current rpc request
264 * @fhp: filehandle to be verified
265 * @type: expected type of object pointed to by filehandle
266 * @access: type of access needed to object
267 *
268 * Look up a dentry from the on-the-wire filehandle, check the client's
269 * access to the export, and set the current task's credentials.
270 *
271 * Regardless of success or failure of fh_verify(), fh_put() should be
272 * called on @fhp when the caller is finished with the filehandle.
263 * 273 *
264 * Note that the file handle dentry may need to be freed even after 274 * fh_verify() may be called multiple times on a given filehandle, for
265 * an error return. 275 * example, when processing an NFSv4 compound. The first call will look
276 * up a dentry using the on-the-wire filehandle. Subsequent calls will
277 * skip the lookup and just perform the other checks and possibly change
278 * the current task's credentials.
266 * 279 *
267 * This is only called at the start of an nfsproc call, so fhp points to 280 * @type specifies the type of object expected using one of the S_IF*
268 * a svc_fh which is all 0 except for the over-the-wire file handle. 281 * constants defined in include/linux/stat.h. The caller may use zero
282 * to indicate that it doesn't care, or a negative integer to indicate
283 * that it expects something not of the given type.
284 *
285 * @access is formed from the NFSD_MAY_* constants defined in
286 * include/linux/nfsd/nfsd.h.
269 */ 287 */
270__be32 288__be32
271fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) 289fh_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 goto retry; 484 goto retry;
467 break; 485 break;
468 } 486 }
487 } else if (exp->ex_flags & NFSEXP_FSID) {
488 fsid_type = FSID_NUM;
469 } else if (exp->ex_uuid) { 489 } else if (exp->ex_uuid) {
470 if (fhp->fh_maxsize >= 64) { 490 if (fhp->fh_maxsize >= 64) {
471 if (root_export) 491 if (root_export)
@@ -478,9 +498,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
478 else 498 else
479 fsid_type = FSID_UUID4_INUM; 499 fsid_type = FSID_UUID4_INUM;
480 } 500 }
481 } else if (exp->ex_flags & NFSEXP_FSID) 501 } else if (!old_valid_dev(ex_dev))
482 fsid_type = FSID_NUM;
483 else if (!old_valid_dev(ex_dev))
484 /* for newer device numbers, we must use a newer fsid format */ 502 /* for newer device numbers, we must use a newer fsid format */
485 fsid_type = FSID_ENCODE_DEV; 503 fsid_type = FSID_ENCODE_DEV;
486 else 504 else
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 5cffeca7acef..6f7f26351227 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -622,6 +622,7 @@ nfserrno (int errno)
622 { nfserr_badname, -ESRCH }, 622 { nfserr_badname, -ESRCH },
623 { nfserr_io, -ETXTBSY }, 623 { nfserr_io, -ETXTBSY },
624 { nfserr_notsupp, -EOPNOTSUPP }, 624 { nfserr_notsupp, -EOPNOTSUPP },
625 { nfserr_toosmall, -ETOOSMALL },
625 }; 626 };
626 int i; 627 int i;
627 628
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 44aa92aba891..6e50aaa56ca2 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -744,16 +744,44 @@ nfsd_close(struct file *filp)
744 fput(filp); 744 fput(filp);
745} 745}
746 746
747/*
748 * Sync a file
749 * As this calls fsync (not fdatasync) there is no need for a write_inode
750 * after it.
751 */
752static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
753 const struct file_operations *fop)
754{
755 struct inode *inode = dp->d_inode;
756 int (*fsync) (struct file *, struct dentry *, int);
757 int err;
758
759 err = filemap_fdatawrite(inode->i_mapping);
760 if (err == 0 && fop && (fsync = fop->fsync))
761 err = fsync(filp, dp, 0);
762 if (err == 0)
763 err = filemap_fdatawait(inode->i_mapping);
764
765 return err;
766}
767
747static int 768static int
748nfsd_sync(struct file *filp) 769nfsd_sync(struct file *filp)
749{ 770{
750 return vfs_fsync(filp, filp->f_path.dentry, 0); 771 int err;
772 struct inode *inode = filp->f_path.dentry->d_inode;
773 dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
774 mutex_lock(&inode->i_mutex);
775 err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
776 mutex_unlock(&inode->i_mutex);
777
778 return err;
751} 779}
752 780
753int 781int
754nfsd_sync_dir(struct dentry *dentry) 782nfsd_sync_dir(struct dentry *dp)
755{ 783{
756 return vfs_fsync(NULL, dentry, 0); 784 return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
757} 785}
758 786
759/* 787/*
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 23da3fa69efa..aa6fe7026de7 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -43,8 +43,8 @@ struct nlm_host {
43 struct sockaddr_storage h_addr; /* peer address */ 43 struct sockaddr_storage h_addr; /* peer address */
44 size_t h_addrlen; 44 size_t h_addrlen;
45 struct sockaddr_storage h_srcaddr; /* our address (optional) */ 45 struct sockaddr_storage h_srcaddr; /* our address (optional) */
46 struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ 46 struct rpc_clnt *h_rpcclnt; /* RPC client to talk to peer */
47 char * h_name; /* remote hostname */ 47 char *h_name; /* remote hostname */
48 u32 h_version; /* interface version */ 48 u32 h_version; /* interface version */
49 unsigned short h_proto; /* transport proto */ 49 unsigned short h_proto; /* transport proto */
50 unsigned short h_reclaiming : 1, 50 unsigned short h_reclaiming : 1,
@@ -64,21 +64,29 @@ struct nlm_host {
64 spinlock_t h_lock; 64 spinlock_t h_lock;
65 struct list_head h_granted; /* Locks in GRANTED state */ 65 struct list_head h_granted; /* Locks in GRANTED state */
66 struct list_head h_reclaim; /* Locks in RECLAIM state */ 66 struct list_head h_reclaim; /* Locks in RECLAIM state */
67 struct nsm_handle * h_nsmhandle; /* NSM status handle */ 67 struct nsm_handle *h_nsmhandle; /* NSM status handle */
68 68 char *h_addrbuf; /* address eyecatcher */
69 char h_addrbuf[48], /* address eyecatchers */
70 h_srcaddrbuf[48];
71}; 69};
72 70
71/*
72 * The largest string sm_addrbuf should hold is a full-size IPv6 address
73 * (no "::" anywhere) with a scope ID. The buffer size is computed to
74 * hold eight groups of colon-separated four-hex-digit numbers, a
75 * percent sign, a scope id (at most 32 bits, in decimal), and NUL.
76 */
77#define NSM_ADDRBUF ((8 * 4 + 7) + (1 + 10) + 1)
78
73struct nsm_handle { 79struct nsm_handle {
74 struct list_head sm_link; 80 struct list_head sm_link;
75 atomic_t sm_count; 81 atomic_t sm_count;
76 char * sm_name; 82 char *sm_mon_name;
83 char *sm_name;
77 struct sockaddr_storage sm_addr; 84 struct sockaddr_storage sm_addr;
78 size_t sm_addrlen; 85 size_t sm_addrlen;
79 unsigned int sm_monitored : 1, 86 unsigned int sm_monitored : 1,
80 sm_sticky : 1; /* don't unmonitor */ 87 sm_sticky : 1; /* don't unmonitor */
81 char sm_addrbuf[48]; /* address eyecatcher */ 88 struct nsm_private sm_priv;
89 char sm_addrbuf[NSM_ADDRBUF];
82}; 90};
83 91
84/* 92/*
@@ -104,16 +112,6 @@ static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
104 return (struct sockaddr *)&host->h_srcaddr; 112 return (struct sockaddr *)&host->h_srcaddr;
105} 113}
106 114
107static inline struct sockaddr_in *nsm_addr_in(const struct nsm_handle *handle)
108{
109 return (struct sockaddr_in *)&handle->sm_addr;
110}
111
112static inline struct sockaddr *nsm_addr(const struct nsm_handle *handle)
113{
114 return (struct sockaddr *)&handle->sm_addr;
115}
116
117/* 115/*
118 * Map an fl_owner_t into a unique 32-bit "pid" 116 * Map an fl_owner_t into a unique 32-bit "pid"
119 */ 117 */
@@ -197,6 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[];
197extern int nlmsvc_grace_period; 195extern int nlmsvc_grace_period;
198extern unsigned long nlmsvc_timeout; 196extern unsigned long nlmsvc_timeout;
199extern int nsm_use_hostnames; 197extern int nsm_use_hostnames;
198extern int nsm_local_state;
200 199
201/* 200/*
202 * Lockd client functions 201 * Lockd client functions
@@ -231,10 +230,20 @@ void nlm_rebind_host(struct nlm_host *);
231struct nlm_host * nlm_get_host(struct nlm_host *); 230struct nlm_host * nlm_get_host(struct nlm_host *);
232void nlm_release_host(struct nlm_host *); 231void nlm_release_host(struct nlm_host *);
233void nlm_shutdown_hosts(void); 232void nlm_shutdown_hosts(void);
234extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, 233void nlm_host_rebooted(const struct nlm_reboot *);
235 unsigned int, u32);
236void nsm_release(struct nsm_handle *);
237 234
235/*
236 * Host monitoring
237 */
238int nsm_monitor(const struct nlm_host *host);
239void nsm_unmonitor(const struct nlm_host *host);
240
241struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
242 const size_t salen,
243 const char *hostname,
244 const size_t hostname_len);
245struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info);
246void nsm_release(struct nsm_handle *nsm);
238 247
239/* 248/*
240 * This is used in garbage collection and resource reclaim 249 * This is used in garbage collection and resource reclaim
@@ -282,16 +291,25 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
282static inline int __nlm_privileged_request4(const struct sockaddr *sap) 291static inline int __nlm_privileged_request4(const struct sockaddr *sap)
283{ 292{
284 const struct sockaddr_in *sin = (struct sockaddr_in *)sap; 293 const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
285 return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) && 294
286 (ntohs(sin->sin_port) < 1024); 295 if (ntohs(sin->sin_port) > 1023)
296 return 0;
297
298 return ipv4_is_loopback(sin->sin_addr.s_addr);
287} 299}
288 300
289#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 301#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
290static inline int __nlm_privileged_request6(const struct sockaddr *sap) 302static inline int __nlm_privileged_request6(const struct sockaddr *sap)
291{ 303{
292 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 304 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
293 return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) && 305
294 (ntohs(sin6->sin6_port) < 1024); 306 if (ntohs(sin6->sin6_port) > 1023)
307 return 0;
308
309 if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_MAPPED)
310 return ipv4_is_loopback(sin6->sin6_addr.s6_addr32[3]);
311
312 return ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK;
295} 313}
296#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ 314#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
297static inline int __nlm_privileged_request6(const struct sockaddr *sap) 315static inline int __nlm_privileged_request6(const struct sockaddr *sap)
diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
deleted file mode 100644
index 5a5448bdb17d..000000000000
--- a/include/linux/lockd/sm_inter.h
+++ /dev/null
@@ -1,48 +0,0 @@
1/*
2 * linux/include/linux/lockd/sm_inter.h
3 *
4 * Declarations for the kernel statd client.
5 *
6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
7 */
8
9#ifndef LINUX_LOCKD_SM_INTER_H
10#define LINUX_LOCKD_SM_INTER_H
11
12#define SM_PROGRAM 100024
13#define SM_VERSION 1
14#define SM_STAT 1
15#define SM_MON 2
16#define SM_UNMON 3
17#define SM_UNMON_ALL 4
18#define SM_SIMU_CRASH 5
19#define SM_NOTIFY 6
20
21#define SM_MAXSTRLEN 1024
22#define SM_PRIV_SIZE 16
23
24/*
25 * Arguments for all calls to statd
26 */
27struct nsm_args {
28 __be32 addr; /* remote address */
29 u32 prog; /* RPC callback info */
30 u32 vers;
31 u32 proc;
32
33 char * mon_name;
34};
35
36/*
37 * Result returned by statd
38 */
39struct nsm_res {
40 u32 status;
41 u32 state;
42};
43
44int nsm_monitor(struct nlm_host *);
45int nsm_unmonitor(struct nlm_host *);
46extern int nsm_local_state;
47
48#endif /* LINUX_LOCKD_SM_INTER_H */
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index d6b3a802c046..7dc5b6cb44cd 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -13,6 +13,13 @@
13#include <linux/nfs.h> 13#include <linux/nfs.h>
14#include <linux/sunrpc/xdr.h> 14#include <linux/sunrpc/xdr.h>
15 15
16#define SM_MAXSTRLEN 1024
17#define SM_PRIV_SIZE 16
18
19struct nsm_private {
20 unsigned char data[SM_PRIV_SIZE];
21};
22
16struct svc_rqst; 23struct svc_rqst;
17 24
18#define NLM_MAXCOOKIELEN 32 25#define NLM_MAXCOOKIELEN 32
@@ -77,10 +84,10 @@ struct nlm_res {
77 * statd callback when client has rebooted 84 * statd callback when client has rebooted
78 */ 85 */
79struct nlm_reboot { 86struct nlm_reboot {
80 char * mon; 87 char *mon;
81 unsigned int len; 88 unsigned int len;
82 u32 state; 89 u32 state;
83 __be32 addr; 90 struct nsm_private priv;
84}; 91};
85 92
86/* 93/*
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index ea0366769484..b912311a56b1 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -88,6 +88,8 @@
88#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0 88#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0
89#define NFS4_ACE_MASK_ALL 0x001F01FF 89#define NFS4_ACE_MASK_ALL 0x001F01FF
90 90
91#define NFS4_MAX_UINT64 (~(u64)0)
92
91enum nfs4_acl_whotype { 93enum nfs4_acl_whotype {
92 NFS4_ACL_WHO_NAMED = 0, 94 NFS4_ACL_WHO_NAMED = 0,
93 NFS4_ACL_WHO_OWNER, 95 NFS4_ACL_WHO_OWNER,
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 21269405ffe2..e19f45991b2e 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -23,7 +23,6 @@
23/* 23/*
24 * nfsd version 24 * nfsd version
25 */ 25 */
26#define NFSD_VERSION "0.5"
27#define NFSD_SUPPORTED_MINOR_VERSION 0 26#define NFSD_SUPPORTED_MINOR_VERSION 0
28 27
29/* 28/*
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index d1941cb965e9..b2e093870bc6 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -68,6 +68,10 @@ struct nfs_fhbase_old {
68 * 1 - 4 byte user specified identifier 68 * 1 - 4 byte user specified identifier
69 * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED 69 * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
70 * 3 - 4 byte device id, encoded for user-space, 4 byte inode number 70 * 3 - 4 byte device id, encoded for user-space, 4 byte inode number
71 * 4 - 4 byte inode number and 4 byte uuid
72 * 5 - 8 byte uuid
73 * 6 - 16 byte uuid
74 * 7 - 8 byte inode number and 16 byte uuid
71 * 75 *
72 * The fileid_type identified how the file within the filesystem is encoded. 76 * The fileid_type identified how the file within the filesystem is encoded.
73 * This is (will be) passed to, and set by, the underlying filesystem if it supports 77 * This is (will be) passed to, and set by, the underlying filesystem if it supports
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 3afe7fb403b2..3435d24bfe55 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -58,10 +58,13 @@ struct svc_serv {
58 struct svc_stat * sv_stats; /* RPC statistics */ 58 struct svc_stat * sv_stats; /* RPC statistics */
59 spinlock_t sv_lock; 59 spinlock_t sv_lock;
60 unsigned int sv_nrthreads; /* # of server threads */ 60 unsigned int sv_nrthreads; /* # of server threads */
61 unsigned int sv_maxconn; /* max connections allowed or
62 * '0' causing max to be based
63 * on number of threads. */
64
61 unsigned int sv_max_payload; /* datagram payload size */ 65 unsigned int sv_max_payload; /* datagram payload size */
62 unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */ 66 unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
63 unsigned int sv_xdrsize; /* XDR buffer size */ 67 unsigned int sv_xdrsize; /* XDR buffer size */
64
65 struct list_head sv_permsocks; /* all permanent sockets */ 68 struct list_head sv_permsocks; /* all permanent sockets */
66 struct list_head sv_tempsocks; /* all temporary sockets */ 69 struct list_head sv_tempsocks; /* all temporary sockets */
67 int sv_tmpcnt; /* count of temporary sockets */ 70 int sv_tmpcnt; /* count of temporary sockets */
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index c9966713282a..4735caad26ed 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -98,7 +98,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
98 98
99 return new; 99 return new;
100} 100}
101EXPORT_SYMBOL(sunrpc_cache_lookup); 101EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
102 102
103 103
104static void queue_loose(struct cache_detail *detail, struct cache_head *ch); 104static 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 cache_put(old, detail); 173 cache_put(old, detail);
174 return tmp; 174 return tmp;
175} 175}
176EXPORT_SYMBOL(sunrpc_cache_update); 176EXPORT_SYMBOL_GPL(sunrpc_cache_update);
177 177
178static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); 178static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
179/* 179/*
@@ -245,7 +245,7 @@ int cache_check(struct cache_detail *detail,
245 cache_put(h, detail); 245 cache_put(h, detail);
246 return rv; 246 return rv;
247} 247}
248EXPORT_SYMBOL(cache_check); 248EXPORT_SYMBOL_GPL(cache_check);
249 249
250/* 250/*
251 * caches need to be periodically cleaned. 251 * caches need to be periodically cleaned.
@@ -373,7 +373,7 @@ int cache_register(struct cache_detail *cd)
373 schedule_delayed_work(&cache_cleaner, 0); 373 schedule_delayed_work(&cache_cleaner, 0);
374 return 0; 374 return 0;
375} 375}
376EXPORT_SYMBOL(cache_register); 376EXPORT_SYMBOL_GPL(cache_register);
377 377
378void cache_unregister(struct cache_detail *cd) 378void cache_unregister(struct cache_detail *cd)
379{ 379{
@@ -399,7 +399,7 @@ void cache_unregister(struct cache_detail *cd)
399out: 399out:
400 printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name); 400 printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
401} 401}
402EXPORT_SYMBOL(cache_unregister); 402EXPORT_SYMBOL_GPL(cache_unregister);
403 403
404/* clean cache tries to find something to clean 404/* clean cache tries to find something to clean
405 * and cleans it. 405 * and cleans it.
@@ -514,7 +514,7 @@ void cache_flush(void)
514 while (cache_clean() != -1) 514 while (cache_clean() != -1)
515 cond_resched(); 515 cond_resched();
516} 516}
517EXPORT_SYMBOL(cache_flush); 517EXPORT_SYMBOL_GPL(cache_flush);
518 518
519void cache_purge(struct cache_detail *detail) 519void cache_purge(struct cache_detail *detail)
520{ 520{
@@ -523,7 +523,7 @@ void cache_purge(struct cache_detail *detail)
523 cache_flush(); 523 cache_flush();
524 detail->flush_time = 1; 524 detail->flush_time = 1;
525} 525}
526EXPORT_SYMBOL(cache_purge); 526EXPORT_SYMBOL_GPL(cache_purge);
527 527
528 528
529/* 529/*
@@ -988,7 +988,7 @@ void qword_add(char **bpp, int *lp, char *str)
988 *bpp = bp; 988 *bpp = bp;
989 *lp = len; 989 *lp = len;
990} 990}
991EXPORT_SYMBOL(qword_add); 991EXPORT_SYMBOL_GPL(qword_add);
992 992
993void qword_addhex(char **bpp, int *lp, char *buf, int blen) 993void qword_addhex(char **bpp, int *lp, char *buf, int blen)
994{ 994{
@@ -1017,7 +1017,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
1017 *bpp = bp; 1017 *bpp = bp;
1018 *lp = len; 1018 *lp = len;
1019} 1019}
1020EXPORT_SYMBOL(qword_addhex); 1020EXPORT_SYMBOL_GPL(qword_addhex);
1021 1021
1022static void warn_no_listener(struct cache_detail *detail) 1022static void warn_no_listener(struct cache_detail *detail)
1023{ 1023{
@@ -1140,7 +1140,7 @@ int qword_get(char **bpp, char *dest, int bufsize)
1140 *dest = '\0'; 1140 *dest = '\0';
1141 return len; 1141 return len;
1142} 1142}
1143EXPORT_SYMBOL(qword_get); 1143EXPORT_SYMBOL_GPL(qword_get);
1144 1144
1145 1145
1146/* 1146/*
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 50b049c6598a..085372ef4feb 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -106,7 +106,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
106 seq_putc(seq, '\n'); 106 seq_putc(seq, '\n');
107 } 107 }
108} 108}
109EXPORT_SYMBOL(svc_seq_show); 109EXPORT_SYMBOL_GPL(svc_seq_show);
110 110
111/** 111/**
112 * rpc_alloc_iostats - allocate an rpc_iostats structure 112 * 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{ 249{
250 return do_register(statp->program->pg_name, statp, fops); 250 return do_register(statp->program->pg_name, statp, fops);
251} 251}
252EXPORT_SYMBOL(svc_proc_register); 252EXPORT_SYMBOL_GPL(svc_proc_register);
253 253
254void 254void
255svc_proc_unregister(const char *name) 255svc_proc_unregister(const char *name)
256{ 256{
257 remove_proc_entry(name, proc_net_rpc); 257 remove_proc_entry(name, proc_net_rpc);
258} 258}
259EXPORT_SYMBOL(svc_proc_unregister); 259EXPORT_SYMBOL_GPL(svc_proc_unregister);
260 260
261void 261void
262rpc_proc_init(void) 262rpc_proc_init(void)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 54c98d876847..c51fed4d1af1 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -431,7 +431,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
431{ 431{
432 return __svc_create(prog, bufsize, /*npools*/1, family, shutdown); 432 return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
433} 433}
434EXPORT_SYMBOL(svc_create); 434EXPORT_SYMBOL_GPL(svc_create);
435 435
436struct svc_serv * 436struct svc_serv *
437svc_create_pooled(struct svc_program *prog, unsigned int bufsize, 437svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
@@ -450,7 +450,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
450 450
451 return serv; 451 return serv;
452} 452}
453EXPORT_SYMBOL(svc_create_pooled); 453EXPORT_SYMBOL_GPL(svc_create_pooled);
454 454
455/* 455/*
456 * Destroy an RPC service. Should be called with appropriate locking to 456 * Destroy an RPC service. Should be called with appropriate locking to
@@ -492,7 +492,7 @@ svc_destroy(struct svc_serv *serv)
492 kfree(serv->sv_pools); 492 kfree(serv->sv_pools);
493 kfree(serv); 493 kfree(serv);
494} 494}
495EXPORT_SYMBOL(svc_destroy); 495EXPORT_SYMBOL_GPL(svc_destroy);
496 496
497/* 497/*
498 * Allocate an RPC server's buffer space. 498 * Allocate an RPC server's buffer space.
@@ -567,7 +567,7 @@ out_thread:
567out_enomem: 567out_enomem:
568 return ERR_PTR(-ENOMEM); 568 return ERR_PTR(-ENOMEM);
569} 569}
570EXPORT_SYMBOL(svc_prepare_thread); 570EXPORT_SYMBOL_GPL(svc_prepare_thread);
571 571
572/* 572/*
573 * Choose a pool in which to create a new thread, for svc_set_num_threads 573 * 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 689
690 return error; 690 return error;
691} 691}
692EXPORT_SYMBOL(svc_set_num_threads); 692EXPORT_SYMBOL_GPL(svc_set_num_threads);
693 693
694/* 694/*
695 * Called from a server thread as it's exiting. Caller must hold the BKL or 695 * 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 if (serv) 717 if (serv)
718 svc_destroy(serv); 718 svc_destroy(serv);
719} 719}
720EXPORT_SYMBOL(svc_exit_thread); 720EXPORT_SYMBOL_GPL(svc_exit_thread);
721 721
722#ifdef CONFIG_SUNRPC_REGISTER_V4 722#ifdef CONFIG_SUNRPC_REGISTER_V4
723 723
@@ -1231,7 +1231,7 @@ err_bad:
1231 svc_putnl(resv, ntohl(rpc_stat)); 1231 svc_putnl(resv, ntohl(rpc_stat));
1232 goto sendit; 1232 goto sendit;
1233} 1233}
1234EXPORT_SYMBOL(svc_process); 1234EXPORT_SYMBOL_GPL(svc_process);
1235 1235
1236/* 1236/*
1237 * Return (transport-specific) limit on the rpc payload. 1237 * Return (transport-specific) limit on the rpc payload.
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index bf5b5cdafebf..e588df5d6b34 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -440,7 +440,7 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
440 svc_xprt_enqueue(xprt); 440 svc_xprt_enqueue(xprt);
441 } 441 }
442} 442}
443EXPORT_SYMBOL(svc_reserve); 443EXPORT_SYMBOL_GPL(svc_reserve);
444 444
445static void svc_xprt_release(struct svc_rqst *rqstp) 445static void svc_xprt_release(struct svc_rqst *rqstp)
446{ 446{
@@ -448,6 +448,9 @@ static void svc_xprt_release(struct svc_rqst *rqstp)
448 448
449 rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp); 449 rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
450 450
451 kfree(rqstp->rq_deferred);
452 rqstp->rq_deferred = NULL;
453
451 svc_free_res_pages(rqstp); 454 svc_free_res_pages(rqstp);
452 rqstp->rq_res.page_len = 0; 455 rqstp->rq_res.page_len = 0;
453 rqstp->rq_res.page_base = 0; 456 rqstp->rq_res.page_base = 0;
@@ -498,7 +501,7 @@ void svc_wake_up(struct svc_serv *serv)
498 spin_unlock_bh(&pool->sp_lock); 501 spin_unlock_bh(&pool->sp_lock);
499 } 502 }
500} 503}
501EXPORT_SYMBOL(svc_wake_up); 504EXPORT_SYMBOL_GPL(svc_wake_up);
502 505
503int svc_port_is_privileged(struct sockaddr *sin) 506int svc_port_is_privileged(struct sockaddr *sin)
504{ 507{
@@ -515,8 +518,10 @@ int svc_port_is_privileged(struct sockaddr *sin)
515} 518}
516 519
517/* 520/*
518 * Make sure that we don't have too many active connections. If we 521 * Make sure that we don't have too many active connections. If we have,
519 * have, something must be dropped. 522 * something must be dropped. It's not clear what will happen if we allow
523 * "too many" connections, but when dealing with network-facing software,
524 * we have to code defensively. Here we do that by imposing hard limits.
520 * 525 *
521 * There's no point in trying to do random drop here for DoS 526 * There's no point in trying to do random drop here for DoS
522 * prevention. The NFS clients does 1 reconnect in 15 seconds. An 527 * prevention. The NFS clients does 1 reconnect in 15 seconds. An
@@ -525,19 +530,27 @@ int svc_port_is_privileged(struct sockaddr *sin)
525 * The only somewhat efficient mechanism would be if drop old 530 * The only somewhat efficient mechanism would be if drop old
526 * connections from the same IP first. But right now we don't even 531 * connections from the same IP first. But right now we don't even
527 * record the client IP in svc_sock. 532 * record the client IP in svc_sock.
533 *
534 * single-threaded services that expect a lot of clients will probably
535 * need to set sv_maxconn to override the default value which is based
536 * on the number of threads
528 */ 537 */
529static void svc_check_conn_limits(struct svc_serv *serv) 538static void svc_check_conn_limits(struct svc_serv *serv)
530{ 539{
531 if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) { 540 unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn :
541 (serv->sv_nrthreads+3) * 20;
542
543 if (serv->sv_tmpcnt > limit) {
532 struct svc_xprt *xprt = NULL; 544 struct svc_xprt *xprt = NULL;
533 spin_lock_bh(&serv->sv_lock); 545 spin_lock_bh(&serv->sv_lock);
534 if (!list_empty(&serv->sv_tempsocks)) { 546 if (!list_empty(&serv->sv_tempsocks)) {
535 if (net_ratelimit()) { 547 if (net_ratelimit()) {
536 /* Try to help the admin */ 548 /* Try to help the admin */
537 printk(KERN_NOTICE "%s: too many open " 549 printk(KERN_NOTICE "%s: too many open "
538 "connections, consider increasing the " 550 "connections, consider increasing %s\n",
539 "number of nfsd threads\n", 551 serv->sv_name, serv->sv_maxconn ?
540 serv->sv_name); 552 "the max number of connections." :
553 "the number of threads.");
541 } 554 }
542 /* 555 /*
543 * Always select the oldest connection. It's not fair, 556 * Always select the oldest connection. It's not fair,
@@ -730,7 +743,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
730 serv->sv_stats->netcnt++; 743 serv->sv_stats->netcnt++;
731 return len; 744 return len;
732} 745}
733EXPORT_SYMBOL(svc_recv); 746EXPORT_SYMBOL_GPL(svc_recv);
734 747
735/* 748/*
736 * Drop request 749 * Drop request
@@ -740,7 +753,7 @@ void svc_drop(struct svc_rqst *rqstp)
740 dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt); 753 dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
741 svc_xprt_release(rqstp); 754 svc_xprt_release(rqstp);
742} 755}
743EXPORT_SYMBOL(svc_drop); 756EXPORT_SYMBOL_GPL(svc_drop);
744 757
745/* 758/*
746 * Return reply to client. 759 * Return reply to client.
@@ -837,6 +850,11 @@ static void svc_age_temp_xprts(unsigned long closure)
837void svc_delete_xprt(struct svc_xprt *xprt) 850void svc_delete_xprt(struct svc_xprt *xprt)
838{ 851{
839 struct svc_serv *serv = xprt->xpt_server; 852 struct svc_serv *serv = xprt->xpt_server;
853 struct svc_deferred_req *dr;
854
855 /* Only do this once */
856 if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
857 return;
840 858
841 dprintk("svc: svc_delete_xprt(%p)\n", xprt); 859 dprintk("svc: svc_delete_xprt(%p)\n", xprt);
842 xprt->xpt_ops->xpo_detach(xprt); 860 xprt->xpt_ops->xpo_detach(xprt);
@@ -851,12 +869,16 @@ void svc_delete_xprt(struct svc_xprt *xprt)
851 * while still attached to a queue, the queue itself 869 * while still attached to a queue, the queue itself
852 * is about to be destroyed (in svc_destroy). 870 * is about to be destroyed (in svc_destroy).
853 */ 871 */
854 if (!test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) { 872 if (test_bit(XPT_TEMP, &xprt->xpt_flags))
855 BUG_ON(atomic_read(&xprt->xpt_ref.refcount) < 2); 873 serv->sv_tmpcnt--;
856 if (test_bit(XPT_TEMP, &xprt->xpt_flags)) 874
857 serv->sv_tmpcnt--; 875 for (dr = svc_deferred_dequeue(xprt); dr;
876 dr = svc_deferred_dequeue(xprt)) {
858 svc_xprt_put(xprt); 877 svc_xprt_put(xprt);
878 kfree(dr);
859 } 879 }
880
881 svc_xprt_put(xprt);
860 spin_unlock_bh(&serv->sv_lock); 882 spin_unlock_bh(&serv->sv_lock);
861} 883}
862 884
@@ -902,17 +924,19 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
902 container_of(dreq, struct svc_deferred_req, handle); 924 container_of(dreq, struct svc_deferred_req, handle);
903 struct svc_xprt *xprt = dr->xprt; 925 struct svc_xprt *xprt = dr->xprt;
904 926
905 if (too_many) { 927 spin_lock(&xprt->xpt_lock);
928 set_bit(XPT_DEFERRED, &xprt->xpt_flags);
929 if (too_many || test_bit(XPT_DEAD, &xprt->xpt_flags)) {
930 spin_unlock(&xprt->xpt_lock);
931 dprintk("revisit canceled\n");
906 svc_xprt_put(xprt); 932 svc_xprt_put(xprt);
907 kfree(dr); 933 kfree(dr);
908 return; 934 return;
909 } 935 }
910 dprintk("revisit queued\n"); 936 dprintk("revisit queued\n");
911 dr->xprt = NULL; 937 dr->xprt = NULL;
912 spin_lock(&xprt->xpt_lock);
913 list_add(&dr->handle.recent, &xprt->xpt_deferred); 938 list_add(&dr->handle.recent, &xprt->xpt_deferred);
914 spin_unlock(&xprt->xpt_lock); 939 spin_unlock(&xprt->xpt_lock);
915 set_bit(XPT_DEFERRED, &xprt->xpt_flags);
916 svc_xprt_enqueue(xprt); 940 svc_xprt_enqueue(xprt);
917 svc_xprt_put(xprt); 941 svc_xprt_put(xprt);
918} 942}
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index 8a73cbb16052..e64109b02aee 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -57,13 +57,13 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
57 rqstp->rq_authop = aops; 57 rqstp->rq_authop = aops;
58 return aops->accept(rqstp, authp); 58 return aops->accept(rqstp, authp);
59} 59}
60EXPORT_SYMBOL(svc_authenticate); 60EXPORT_SYMBOL_GPL(svc_authenticate);
61 61
62int svc_set_client(struct svc_rqst *rqstp) 62int svc_set_client(struct svc_rqst *rqstp)
63{ 63{
64 return rqstp->rq_authop->set_client(rqstp); 64 return rqstp->rq_authop->set_client(rqstp);
65} 65}
66EXPORT_SYMBOL(svc_set_client); 66EXPORT_SYMBOL_GPL(svc_set_client);
67 67
68/* A request, which was authenticated, has now executed. 68/* A request, which was authenticated, has now executed.
69 * Time to finalise the credentials and verifier 69 * Time to finalise the credentials and verifier
@@ -95,7 +95,7 @@ svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
95 spin_unlock(&authtab_lock); 95 spin_unlock(&authtab_lock);
96 return rv; 96 return rv;
97} 97}
98EXPORT_SYMBOL(svc_auth_register); 98EXPORT_SYMBOL_GPL(svc_auth_register);
99 99
100void 100void
101svc_auth_unregister(rpc_authflavor_t flavor) 101svc_auth_unregister(rpc_authflavor_t flavor)
@@ -105,7 +105,7 @@ svc_auth_unregister(rpc_authflavor_t flavor)
105 authtab[flavor] = NULL; 105 authtab[flavor] = NULL;
106 spin_unlock(&authtab_lock); 106 spin_unlock(&authtab_lock);
107} 107}
108EXPORT_SYMBOL(svc_auth_unregister); 108EXPORT_SYMBOL_GPL(svc_auth_unregister);
109 109
110/************************************************** 110/**************************************************
111 * 'auth_domains' are stored in a hash table indexed by name. 111 * 'auth_domains' are stored in a hash table indexed by name.
@@ -132,7 +132,7 @@ void auth_domain_put(struct auth_domain *dom)
132 spin_unlock(&auth_domain_lock); 132 spin_unlock(&auth_domain_lock);
133 } 133 }
134} 134}
135EXPORT_SYMBOL(auth_domain_put); 135EXPORT_SYMBOL_GPL(auth_domain_put);
136 136
137struct auth_domain * 137struct auth_domain *
138auth_domain_lookup(char *name, struct auth_domain *new) 138auth_domain_lookup(char *name, struct auth_domain *new)
@@ -157,10 +157,10 @@ auth_domain_lookup(char *name, struct auth_domain *new)
157 spin_unlock(&auth_domain_lock); 157 spin_unlock(&auth_domain_lock);
158 return new; 158 return new;
159} 159}
160EXPORT_SYMBOL(auth_domain_lookup); 160EXPORT_SYMBOL_GPL(auth_domain_lookup);
161 161
162struct auth_domain *auth_domain_find(char *name) 162struct auth_domain *auth_domain_find(char *name)
163{ 163{
164 return auth_domain_lookup(name, NULL); 164 return auth_domain_lookup(name, NULL);
165} 165}
166EXPORT_SYMBOL(auth_domain_find); 166EXPORT_SYMBOL_GPL(auth_domain_find);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 82240e6127b2..5c865e2d299e 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -64,7 +64,7 @@ struct auth_domain *unix_domain_find(char *name)
64 rv = auth_domain_lookup(name, &new->h); 64 rv = auth_domain_lookup(name, &new->h);
65 } 65 }
66} 66}
67EXPORT_SYMBOL(unix_domain_find); 67EXPORT_SYMBOL_GPL(unix_domain_find);
68 68
69static void svcauth_unix_domain_release(struct auth_domain *dom) 69static void svcauth_unix_domain_release(struct auth_domain *dom)
70{ 70{
@@ -358,7 +358,7 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
358 else 358 else
359 return -ENOMEM; 359 return -ENOMEM;
360} 360}
361EXPORT_SYMBOL(auth_unix_add_addr); 361EXPORT_SYMBOL_GPL(auth_unix_add_addr);
362 362
363int auth_unix_forget_old(struct auth_domain *dom) 363int auth_unix_forget_old(struct auth_domain *dom)
364{ 364{
@@ -370,7 +370,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
370 udom->addr_changes++; 370 udom->addr_changes++;
371 return 0; 371 return 0;
372} 372}
373EXPORT_SYMBOL(auth_unix_forget_old); 373EXPORT_SYMBOL_GPL(auth_unix_forget_old);
374 374
375struct auth_domain *auth_unix_lookup(struct in6_addr *addr) 375struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
376{ 376{
@@ -395,13 +395,13 @@ struct auth_domain *auth_unix_lookup(struct in6_addr *addr)
395 cache_put(&ipm->h, &ip_map_cache); 395 cache_put(&ipm->h, &ip_map_cache);
396 return rv; 396 return rv;
397} 397}
398EXPORT_SYMBOL(auth_unix_lookup); 398EXPORT_SYMBOL_GPL(auth_unix_lookup);
399 399
400void svcauth_unix_purge(void) 400void svcauth_unix_purge(void)
401{ 401{
402 cache_purge(&ip_map_cache); 402 cache_purge(&ip_map_cache);
403} 403}
404EXPORT_SYMBOL(svcauth_unix_purge); 404EXPORT_SYMBOL_GPL(svcauth_unix_purge);
405 405
406static inline struct ip_map * 406static inline struct ip_map *
407ip_map_cached_get(struct svc_rqst *rqstp) 407ip_map_cached_get(struct svc_rqst *rqstp)
@@ -714,7 +714,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
714 return SVC_OK; 714 return SVC_OK;
715} 715}
716 716
717EXPORT_SYMBOL(svcauth_unix_set_client); 717EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
718 718
719static int 719static int
720svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) 720svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index ef3238d665ee..5763e6460fea 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -59,6 +59,7 @@ static void svc_udp_data_ready(struct sock *, int);
59static int svc_udp_recvfrom(struct svc_rqst *); 59static int svc_udp_recvfrom(struct svc_rqst *);
60static int svc_udp_sendto(struct svc_rqst *); 60static int svc_udp_sendto(struct svc_rqst *);
61static void svc_sock_detach(struct svc_xprt *); 61static void svc_sock_detach(struct svc_xprt *);
62static void svc_tcp_sock_detach(struct svc_xprt *);
62static void svc_sock_free(struct svc_xprt *); 63static void svc_sock_free(struct svc_xprt *);
63 64
64static struct svc_xprt *svc_create_socket(struct svc_serv *, int, 65static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
@@ -102,7 +103,6 @@ static void svc_reclassify_socket(struct socket *sock)
102static void svc_release_skb(struct svc_rqst *rqstp) 103static void svc_release_skb(struct svc_rqst *rqstp)
103{ 104{
104 struct sk_buff *skb = rqstp->rq_xprt_ctxt; 105 struct sk_buff *skb = rqstp->rq_xprt_ctxt;
105 struct svc_deferred_req *dr = rqstp->rq_deferred;
106 106
107 if (skb) { 107 if (skb) {
108 struct svc_sock *svsk = 108 struct svc_sock *svsk =
@@ -112,10 +112,6 @@ static void svc_release_skb(struct svc_rqst *rqstp)
112 dprintk("svc: service %p, releasing skb %p\n", rqstp, skb); 112 dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
113 skb_free_datagram(svsk->sk_sk, skb); 113 skb_free_datagram(svsk->sk_sk, skb);
114 } 114 }
115 if (dr) {
116 rqstp->rq_deferred = NULL;
117 kfree(dr);
118 }
119} 115}
120 116
121union svc_pktinfo_u { 117union svc_pktinfo_u {
@@ -289,7 +285,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
289 return -ENOENT; 285 return -ENOENT;
290 return len; 286 return len;
291} 287}
292EXPORT_SYMBOL(svc_sock_names); 288EXPORT_SYMBOL_GPL(svc_sock_names);
293 289
294/* 290/*
295 * Check input queue length 291 * Check input queue length
@@ -1017,7 +1013,7 @@ static struct svc_xprt_ops svc_tcp_ops = {
1017 .xpo_recvfrom = svc_tcp_recvfrom, 1013 .xpo_recvfrom = svc_tcp_recvfrom,
1018 .xpo_sendto = svc_tcp_sendto, 1014 .xpo_sendto = svc_tcp_sendto,
1019 .xpo_release_rqst = svc_release_skb, 1015 .xpo_release_rqst = svc_release_skb,
1020 .xpo_detach = svc_sock_detach, 1016 .xpo_detach = svc_tcp_sock_detach,
1021 .xpo_free = svc_sock_free, 1017 .xpo_free = svc_sock_free,
1022 .xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr, 1018 .xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
1023 .xpo_has_wspace = svc_tcp_has_wspace, 1019 .xpo_has_wspace = svc_tcp_has_wspace,
@@ -1101,7 +1097,7 @@ void svc_sock_update_bufs(struct svc_serv *serv)
1101 } 1097 }
1102 spin_unlock_bh(&serv->sv_lock); 1098 spin_unlock_bh(&serv->sv_lock);
1103} 1099}
1104EXPORT_SYMBOL(svc_sock_update_bufs); 1100EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
1105 1101
1106/* 1102/*
1107 * Initialize socket for RPC use and create svc_sock struct 1103 * Initialize socket for RPC use and create svc_sock struct
@@ -1287,6 +1283,24 @@ static void svc_sock_detach(struct svc_xprt *xprt)
1287 sk->sk_state_change = svsk->sk_ostate; 1283 sk->sk_state_change = svsk->sk_ostate;
1288 sk->sk_data_ready = svsk->sk_odata; 1284 sk->sk_data_ready = svsk->sk_odata;
1289 sk->sk_write_space = svsk->sk_owspace; 1285 sk->sk_write_space = svsk->sk_owspace;
1286
1287 if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
1288 wake_up_interruptible(sk->sk_sleep);
1289}
1290
1291/*
1292 * Disconnect the socket, and reset the callbacks
1293 */
1294static void svc_tcp_sock_detach(struct svc_xprt *xprt)
1295{
1296 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
1297
1298 dprintk("svc: svc_tcp_sock_detach(%p)\n", svsk);
1299
1300 svc_sock_detach(xprt);
1301
1302 if (!test_bit(XPT_LISTENER, &xprt->xpt_flags))
1303 kernel_sock_shutdown(svsk->sk_sock, SHUT_RDWR);
1290} 1304}
1291 1305
1292/* 1306/*