aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 22:31:28 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 22:31:28 -0500
commit63e9b66e29357dd12e8b1d3ebf7036e7591f81e3 (patch)
tree5aa6a70a8f4bbf306e2825a1e2fa2660c2c1c187 /fs
parent687fcdf741e4a268c2c7bac8b3734de761bb9719 (diff)
parentea339d46b93c7b16e067a29aad1812f7a389815a (diff)
Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux
* 'for-linus' of git://linux-nfs.org/~bfields/linux: (100 commits) SUNRPC: RPC program information is stored in unsigned integers SUNRPC: Move exported symbol definitions after function declaration part 2 NLM: tear down RPC clients in nlm_shutdown_hosts SUNRPC: spin svc_rqst initialization to its own function nfsd: more careful input validation in nfsctl write methods lockd: minor log message fix knfsd: don't bother mapping putrootfh enoent to eperm rdma: makefile rdma: ONCRPC RDMA protocol marshalling rdma: SVCRDMA sendto rdma: SVCRDMA recvfrom rdma: SVCRDMA Core Transport Services rdma: SVCRDMA Transport Module rdma: SVCRMDA Header File svc: Add svc_xprt_names service to replace svc_sock_names knfsd: Support adding transports by writing portlist file svc: Add svc API that queries for a transport instance svc: Add /proc/sys/sunrpc/transport files svc: Add transport hdr size for defer/revisit svc: Move the xprt independent code to the svc_xprt.c file ...
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/lockd/host.c26
-rw-r--r--fs/lockd/svc.c39
-rw-r--r--fs/lockd/svc4proc.c20
-rw-r--r--fs/lockd/svclock.c20
-rw-r--r--fs/lockd/svcproc.c22
-rw-r--r--fs/lockd/svcsubs.c2
-rw-r--r--fs/nfs/callback.c4
-rw-r--r--fs/nfsd/auth.h22
-rw-r--r--fs/nfsd/export.c20
-rw-r--r--fs/nfsd/nfs2acl.c7
-rw-r--r--fs/nfsd/nfs3xdr.c21
-rw-r--r--fs/nfsd/nfs4callback.c92
-rw-r--r--fs/nfsd/nfs4idmap.c28
-rw-r--r--fs/nfsd/nfs4proc.c2
-rw-r--r--fs/nfsd/nfs4state.c257
-rw-r--r--fs/nfsd/nfs4xdr.c36
-rw-r--r--fs/nfsd/nfscache.c28
-rw-r--r--fs/nfsd/nfsctl.c124
-rw-r--r--fs/nfsd/nfsfh.c1
-rw-r--r--fs/nfsd/nfssvc.c8
-rw-r--r--fs/nfsd/nfsxdr.c9
-rw-r--r--fs/nfsd/vfs.c51
23 files changed, 466 insertions, 375 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 219ec06a8c7e..987b5d7cb21a 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1674,6 +1674,8 @@ config NFSD
1674 select CRYPTO_MD5 if NFSD_V4 1674 select CRYPTO_MD5 if NFSD_V4
1675 select CRYPTO if NFSD_V4 1675 select CRYPTO if NFSD_V4
1676 select FS_POSIX_ACL if NFSD_V4 1676 select FS_POSIX_ACL if NFSD_V4
1677 select PROC_FS if NFSD_V4
1678 select PROC_FS if SUNRPC_GSS
1677 help 1679 help
1678 If you want your Linux box to act as an NFS *server*, so that other 1680 If you want your Linux box to act as an NFS *server*, so that other
1679 computers on your local network which support NFS can access certain 1681 computers on your local network which support NFS can access certain
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 572601e98dcd..ca6b16fc3101 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -34,10 +34,10 @@ static DEFINE_MUTEX(nlm_host_mutex);
34 34
35static void nlm_gc_hosts(void); 35static void nlm_gc_hosts(void);
36static struct nsm_handle * __nsm_find(const struct sockaddr_in *, 36static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
37 const char *, int, int); 37 const char *, unsigned int, int);
38static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, 38static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
39 const char *hostname, 39 const char *hostname,
40 int hostname_len); 40 unsigned int hostname_len);
41 41
42/* 42/*
43 * Common host lookup routine for server & client 43 * Common host lookup routine for server & client
@@ -45,7 +45,8 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
45static struct nlm_host * 45static struct nlm_host *
46nlm_lookup_host(int server, const struct sockaddr_in *sin, 46nlm_lookup_host(int server, const struct sockaddr_in *sin,
47 int proto, int version, const char *hostname, 47 int proto, int version, const char *hostname,
48 int hostname_len, const struct sockaddr_in *ssin) 48 unsigned int hostname_len,
49 const struct sockaddr_in *ssin)
49{ 50{
50 struct hlist_head *chain; 51 struct hlist_head *chain;
51 struct hlist_node *pos; 52 struct hlist_node *pos;
@@ -176,7 +177,7 @@ nlm_destroy_host(struct nlm_host *host)
176 */ 177 */
177struct nlm_host * 178struct nlm_host *
178nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, 179nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
179 const char *hostname, int hostname_len) 180 const char *hostname, unsigned int hostname_len)
180{ 181{
181 struct sockaddr_in ssin = {0}; 182 struct sockaddr_in ssin = {0};
182 183
@@ -189,7 +190,7 @@ nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
189 */ 190 */
190struct nlm_host * 191struct nlm_host *
191nlmsvc_lookup_host(struct svc_rqst *rqstp, 192nlmsvc_lookup_host(struct svc_rqst *rqstp,
192 const char *hostname, int hostname_len) 193 const char *hostname, unsigned int hostname_len)
193{ 194{
194 struct sockaddr_in ssin = {0}; 195 struct sockaddr_in ssin = {0};
195 196
@@ -307,7 +308,8 @@ void nlm_release_host(struct nlm_host *host)
307 * Release all resources held by that peer. 308 * Release all resources held by that peer.
308 */ 309 */
309void nlm_host_rebooted(const struct sockaddr_in *sin, 310void nlm_host_rebooted(const struct sockaddr_in *sin,
310 const char *hostname, int hostname_len, 311 const char *hostname,
312 unsigned int hostname_len,
311 u32 new_state) 313 u32 new_state)
312{ 314{
313 struct hlist_head *chain; 315 struct hlist_head *chain;
@@ -377,8 +379,13 @@ nlm_shutdown_hosts(void)
377 /* First, make all hosts eligible for gc */ 379 /* First, make all hosts eligible for gc */
378 dprintk("lockd: nuking all hosts...\n"); 380 dprintk("lockd: nuking all hosts...\n");
379 for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) { 381 for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
380 hlist_for_each_entry(host, pos, chain, h_hash) 382 hlist_for_each_entry(host, pos, chain, h_hash) {
381 host->h_expires = jiffies - 1; 383 host->h_expires = jiffies - 1;
384 if (host->h_rpcclnt) {
385 rpc_shutdown_client(host->h_rpcclnt);
386 host->h_rpcclnt = NULL;
387 }
388 }
382 } 389 }
383 390
384 /* Then, perform a garbage collection pass */ 391 /* Then, perform a garbage collection pass */
@@ -449,7 +456,7 @@ static DEFINE_MUTEX(nsm_mutex);
449 456
450static struct nsm_handle * 457static struct nsm_handle *
451__nsm_find(const struct sockaddr_in *sin, 458__nsm_find(const struct sockaddr_in *sin,
452 const char *hostname, int hostname_len, 459 const char *hostname, unsigned int hostname_len,
453 int create) 460 int create)
454{ 461{
455 struct nsm_handle *nsm = NULL; 462 struct nsm_handle *nsm = NULL;
@@ -503,7 +510,8 @@ out:
503} 510}
504 511
505static struct nsm_handle * 512static struct nsm_handle *
506nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len) 513nsm_find(const struct sockaddr_in *sin, const char *hostname,
514 unsigned int hostname_len)
507{ 515{
508 return __nsm_find(sin, hostname, hostname_len, 1); 516 return __nsm_find(sin, hostname, hostname_len, 1);
509} 517}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 82e2192a0d5c..08226464e563 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -219,19 +219,6 @@ lockd(struct svc_rqst *rqstp)
219 module_put_and_exit(0); 219 module_put_and_exit(0);
220} 220}
221 221
222
223static int find_socket(struct svc_serv *serv, int proto)
224{
225 struct svc_sock *svsk;
226 int found = 0;
227 list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
228 if (svsk->sk_sk->sk_protocol == proto) {
229 found = 1;
230 break;
231 }
232 return found;
233}
234
235/* 222/*
236 * Make any sockets that are needed but not present. 223 * Make any sockets that are needed but not present.
237 * If nlm_udpport or nlm_tcpport were set as module 224 * If nlm_udpport or nlm_tcpport were set as module
@@ -240,17 +227,25 @@ static int find_socket(struct svc_serv *serv, int proto)
240static int make_socks(struct svc_serv *serv, int proto) 227static int make_socks(struct svc_serv *serv, int proto)
241{ 228{
242 static int warned; 229 static int warned;
230 struct svc_xprt *xprt;
243 int err = 0; 231 int err = 0;
244 232
245 if (proto == IPPROTO_UDP || nlm_udpport) 233 if (proto == IPPROTO_UDP || nlm_udpport) {
246 if (!find_socket(serv, IPPROTO_UDP)) 234 xprt = svc_find_xprt(serv, "udp", 0, 0);
247 err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport, 235 if (!xprt)
248 SVC_SOCK_DEFAULTS); 236 err = svc_create_xprt(serv, "udp", nlm_udpport,
249 if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) 237 SVC_SOCK_DEFAULTS);
250 if (!find_socket(serv, IPPROTO_TCP)) 238 else
251 err = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport, 239 svc_xprt_put(xprt);
252 SVC_SOCK_DEFAULTS); 240 }
253 241 if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
242 xprt = svc_find_xprt(serv, "tcp", 0, 0);
243 if (!xprt)
244 err = svc_create_xprt(serv, "tcp", nlm_tcpport,
245 SVC_SOCK_DEFAULTS);
246 else
247 svc_xprt_put(xprt);
248 }
254 if (err >= 0) { 249 if (err >= 0) {
255 warned = 0; 250 warned = 0;
256 err = 0; 251 err = 0;
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index bf27b6c6cb6b..385437e3387d 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -84,6 +84,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
84{ 84{
85 struct nlm_host *host; 85 struct nlm_host *host;
86 struct nlm_file *file; 86 struct nlm_file *file;
87 int rc = rpc_success;
87 88
88 dprintk("lockd: TEST4 called\n"); 89 dprintk("lockd: TEST4 called\n");
89 resp->cookie = argp->cookie; 90 resp->cookie = argp->cookie;
@@ -91,7 +92,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
91 /* Don't accept test requests during grace period */ 92 /* Don't accept test requests during grace period */
92 if (nlmsvc_grace_period) { 93 if (nlmsvc_grace_period) {
93 resp->status = nlm_lck_denied_grace_period; 94 resp->status = nlm_lck_denied_grace_period;
94 return rpc_success; 95 return rc;
95 } 96 }
96 97
97 /* Obtain client and file */ 98 /* Obtain client and file */
@@ -101,12 +102,13 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
101 /* Now check for conflicting locks */ 102 /* Now check for conflicting locks */
102 resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie); 103 resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
103 if (resp->status == nlm_drop_reply) 104 if (resp->status == nlm_drop_reply)
104 return rpc_drop_reply; 105 rc = rpc_drop_reply;
106 else
107 dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
105 108
106 dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
107 nlm_release_host(host); 109 nlm_release_host(host);
108 nlm_release_file(file); 110 nlm_release_file(file);
109 return rpc_success; 111 return rc;
110} 112}
111 113
112static __be32 114static __be32
@@ -115,6 +117,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
115{ 117{
116 struct nlm_host *host; 118 struct nlm_host *host;
117 struct nlm_file *file; 119 struct nlm_file *file;
120 int rc = rpc_success;
118 121
119 dprintk("lockd: LOCK called\n"); 122 dprintk("lockd: LOCK called\n");
120 123
@@ -123,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
123 /* Don't accept new lock requests during grace period */ 126 /* Don't accept new lock requests during grace period */
124 if (nlmsvc_grace_period && !argp->reclaim) { 127 if (nlmsvc_grace_period && !argp->reclaim) {
125 resp->status = nlm_lck_denied_grace_period; 128 resp->status = nlm_lck_denied_grace_period;
126 return rpc_success; 129 return rc;
127 } 130 }
128 131
129 /* Obtain client and file */ 132 /* Obtain client and file */
@@ -146,12 +149,13 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
146 resp->status = nlmsvc_lock(rqstp, file, &argp->lock, 149 resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
147 argp->block, &argp->cookie); 150 argp->block, &argp->cookie);
148 if (resp->status == nlm_drop_reply) 151 if (resp->status == nlm_drop_reply)
149 return rpc_drop_reply; 152 rc = rpc_drop_reply;
153 else
154 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
150 155
151 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
152 nlm_release_host(host); 156 nlm_release_host(host);
153 nlm_release_file(file); 157 nlm_release_file(file);
154 return rpc_success; 158 return rc;
155} 159}
156 160
157static __be32 161static __be32
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index d120ec39bcb0..2f4d8fa66689 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -501,25 +501,29 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
501 block, block->b_flags, block->b_fl); 501 block, block->b_flags, block->b_fl);
502 if (block->b_flags & B_TIMED_OUT) { 502 if (block->b_flags & B_TIMED_OUT) {
503 nlmsvc_unlink_block(block); 503 nlmsvc_unlink_block(block);
504 return nlm_lck_denied; 504 ret = nlm_lck_denied;
505 goto out;
505 } 506 }
506 if (block->b_flags & B_GOT_CALLBACK) { 507 if (block->b_flags & B_GOT_CALLBACK) {
508 nlmsvc_unlink_block(block);
507 if (block->b_fl != NULL 509 if (block->b_fl != NULL
508 && block->b_fl->fl_type != F_UNLCK) { 510 && block->b_fl->fl_type != F_UNLCK) {
509 lock->fl = *block->b_fl; 511 lock->fl = *block->b_fl;
510 goto conf_lock; 512 goto conf_lock;
511 } 513 } else {
512 else { 514 ret = nlm_granted;
513 nlmsvc_unlink_block(block); 515 goto out;
514 return nlm_granted;
515 } 516 }
516 } 517 }
517 return nlm_drop_reply; 518 ret = nlm_drop_reply;
519 goto out;
518 } 520 }
519 521
520 error = vfs_test_lock(file->f_file, &lock->fl); 522 error = vfs_test_lock(file->f_file, &lock->fl);
521 if (error == -EINPROGRESS) 523 if (error == -EINPROGRESS) {
522 return nlmsvc_defer_lock_rqst(rqstp, block); 524 ret = nlmsvc_defer_lock_rqst(rqstp, block);
525 goto out;
526 }
523 if (error) { 527 if (error) {
524 ret = nlm_lck_denied_nolocks; 528 ret = nlm_lck_denied_nolocks;
525 goto out; 529 goto out;
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 9cd5c8b37593..88379cc6e0b1 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -113,6 +113,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
113{ 113{
114 struct nlm_host *host; 114 struct nlm_host *host;
115 struct nlm_file *file; 115 struct nlm_file *file;
116 int rc = rpc_success;
116 117
117 dprintk("lockd: TEST called\n"); 118 dprintk("lockd: TEST called\n");
118 resp->cookie = argp->cookie; 119 resp->cookie = argp->cookie;
@@ -120,7 +121,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
120 /* Don't accept test requests during grace period */ 121 /* Don't accept test requests during grace period */
121 if (nlmsvc_grace_period) { 122 if (nlmsvc_grace_period) {
122 resp->status = nlm_lck_denied_grace_period; 123 resp->status = nlm_lck_denied_grace_period;
123 return rpc_success; 124 return rc;
124 } 125 }
125 126
126 /* Obtain client and file */ 127 /* Obtain client and file */
@@ -130,13 +131,14 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
130 /* Now check for conflicting locks */ 131 /* Now check for conflicting locks */
131 resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie)); 132 resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
132 if (resp->status == nlm_drop_reply) 133 if (resp->status == nlm_drop_reply)
133 return rpc_drop_reply; 134 rc = rpc_drop_reply;
135 else
136 dprintk("lockd: TEST status %d vers %d\n",
137 ntohl(resp->status), rqstp->rq_vers);
134 138
135 dprintk("lockd: TEST status %d vers %d\n",
136 ntohl(resp->status), rqstp->rq_vers);
137 nlm_release_host(host); 139 nlm_release_host(host);
138 nlm_release_file(file); 140 nlm_release_file(file);
139 return rpc_success; 141 return rc;
140} 142}
141 143
142static __be32 144static __be32
@@ -145,6 +147,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
145{ 147{
146 struct nlm_host *host; 148 struct nlm_host *host;
147 struct nlm_file *file; 149 struct nlm_file *file;
150 int rc = rpc_success;
148 151
149 dprintk("lockd: LOCK called\n"); 152 dprintk("lockd: LOCK called\n");
150 153
@@ -153,7 +156,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
153 /* Don't accept new lock requests during grace period */ 156 /* Don't accept new lock requests during grace period */
154 if (nlmsvc_grace_period && !argp->reclaim) { 157 if (nlmsvc_grace_period && !argp->reclaim) {
155 resp->status = nlm_lck_denied_grace_period; 158 resp->status = nlm_lck_denied_grace_period;
156 return rpc_success; 159 return rc;
157 } 160 }
158 161
159 /* Obtain client and file */ 162 /* Obtain client and file */
@@ -176,12 +179,13 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
176 resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, 179 resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
177 argp->block, &argp->cookie)); 180 argp->block, &argp->cookie));
178 if (resp->status == nlm_drop_reply) 181 if (resp->status == nlm_drop_reply)
179 return rpc_drop_reply; 182 rc = rpc_drop_reply;
183 else
184 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
180 185
181 dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
182 nlm_release_host(host); 186 nlm_release_host(host);
183 nlm_release_file(file); 187 nlm_release_file(file);
184 return rpc_success; 188 return rc;
185} 189}
186 190
187static __be32 191static __be32
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 84ebba33b98d..dbbefbcd6712 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -87,7 +87,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
87 unsigned int hash; 87 unsigned int hash;
88 __be32 nfserr; 88 __be32 nfserr;
89 89
90 nlm_debug_print_fh("nlm_file_lookup", f); 90 nlm_debug_print_fh("nlm_lookup_file", f);
91 91
92 hash = file_hash(f); 92 hash = file_hash(f);
93 93
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 9b6bbf1b9787..bd185a572a23 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -119,8 +119,8 @@ int nfs_callback_up(void)
119 if (!serv) 119 if (!serv)
120 goto out_err; 120 goto out_err;
121 121
122 ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport, 122 ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
123 SVC_SOCK_ANONYMOUS); 123 SVC_SOCK_ANONYMOUS);
124 if (ret <= 0) 124 if (ret <= 0)
125 goto out_destroy; 125 goto out_destroy;
126 nfs_callback_tcpport = ret; 126 nfs_callback_tcpport = ret;
diff --git a/fs/nfsd/auth.h b/fs/nfsd/auth.h
new file mode 100644
index 000000000000..78b3c0e93822
--- /dev/null
+++ b/fs/nfsd/auth.h
@@ -0,0 +1,22 @@
1/*
2 * nfsd-specific authentication stuff.
3 * uid/gid mapping not yet implemented.
4 *
5 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
6 */
7
8#ifndef LINUX_NFSD_AUTH_H
9#define LINUX_NFSD_AUTH_H
10
11#define nfsd_luid(rq, uid) ((u32)(uid))
12#define nfsd_lgid(rq, gid) ((u32)(gid))
13#define nfsd_ruid(rq, uid) ((u32)(uid))
14#define nfsd_rgid(rq, gid) ((u32)(gid))
15
16/*
17 * Set the current process's fsuid/fsgid etc to those of the NFS
18 * client user
19 */
20int nfsd_setuser(struct svc_rqst *, struct svc_export *);
21
22#endif /* LINUX_NFSD_AUTH_H */
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 66d0aeb32a47..79b4bf812960 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1357,8 +1357,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1357 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); 1357 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1358 1358
1359 exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); 1359 exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
1360 if (PTR_ERR(exp) == -ENOENT)
1361 return nfserr_perm;
1362 if (IS_ERR(exp)) 1360 if (IS_ERR(exp))
1363 return nfserrno(PTR_ERR(exp)); 1361 return nfserrno(PTR_ERR(exp));
1364 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); 1362 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
@@ -1637,13 +1635,19 @@ exp_verify_string(char *cp, int max)
1637/* 1635/*
1638 * Initialize the exports module. 1636 * Initialize the exports module.
1639 */ 1637 */
1640void 1638int
1641nfsd_export_init(void) 1639nfsd_export_init(void)
1642{ 1640{
1641 int rv;
1643 dprintk("nfsd: initializing export module.\n"); 1642 dprintk("nfsd: initializing export module.\n");
1644 1643
1645 cache_register(&svc_export_cache); 1644 rv = cache_register(&svc_export_cache);
1646 cache_register(&svc_expkey_cache); 1645 if (rv)
1646 return rv;
1647 rv = cache_register(&svc_expkey_cache);
1648 if (rv)
1649 cache_unregister(&svc_export_cache);
1650 return rv;
1647 1651
1648} 1652}
1649 1653
@@ -1670,10 +1674,8 @@ nfsd_export_shutdown(void)
1670 1674
1671 exp_writelock(); 1675 exp_writelock();
1672 1676
1673 if (cache_unregister(&svc_expkey_cache)) 1677 cache_unregister(&svc_expkey_cache);
1674 printk(KERN_ERR "nfsd: failed to unregister expkey cache\n"); 1678 cache_unregister(&svc_export_cache);
1675 if (cache_unregister(&svc_export_cache))
1676 printk(KERN_ERR "nfsd: failed to unregister export cache\n");
1677 svcauth_unix_purge(); 1679 svcauth_unix_purge();
1678 1680
1679 exp_writeunlock(); 1681 exp_writeunlock();
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 0e5fa11e6b44..1c3b7654e966 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -221,12 +221,17 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
221 struct nfsd3_getaclres *resp) 221 struct nfsd3_getaclres *resp)
222{ 222{
223 struct dentry *dentry = resp->fh.fh_dentry; 223 struct dentry *dentry = resp->fh.fh_dentry;
224 struct inode *inode = dentry->d_inode; 224 struct inode *inode;
225 struct kvec *head = rqstp->rq_res.head; 225 struct kvec *head = rqstp->rq_res.head;
226 unsigned int base; 226 unsigned int base;
227 int n; 227 int n;
228 int w; 228 int w;
229 229
230 /*
231 * Since this is version 2, the check for nfserr in
232 * nfsd_dispatch actually ensures the following cannot happen.
233 * However, it seems fragile to depend on that.
234 */
230 if (dentry == NULL || dentry->d_inode == NULL) 235 if (dentry == NULL || dentry->d_inode == NULL)
231 return 0; 236 return 0;
232 inode = dentry->d_inode; 237 inode = dentry->d_inode;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index f917fd25858a..d7647f70e02b 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -21,6 +21,7 @@
21#include <linux/sunrpc/svc.h> 21#include <linux/sunrpc/svc.h>
22#include <linux/nfsd/nfsd.h> 22#include <linux/nfsd/nfsd.h>
23#include <linux/nfsd/xdr3.h> 23#include <linux/nfsd/xdr3.h>
24#include "auth.h"
24 25
25#define NFSDDBG_FACILITY NFSDDBG_XDR 26#define NFSDDBG_FACILITY NFSDDBG_XDR
26 27
@@ -88,10 +89,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
88 * no slashes or null bytes. 89 * no slashes or null bytes.
89 */ 90 */
90static __be32 * 91static __be32 *
91decode_filename(__be32 *p, char **namp, int *lenp) 92decode_filename(__be32 *p, char **namp, unsigned int *lenp)
92{ 93{
93 char *name; 94 char *name;
94 int i; 95 unsigned int i;
95 96
96 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { 97 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
97 for (i = 0, name = *namp; i < *lenp; i++, name++) { 98 for (i = 0, name = *namp; i < *lenp; i++, name++) {
@@ -452,8 +453,7 @@ int
452nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, 453nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
453 struct nfsd3_symlinkargs *args) 454 struct nfsd3_symlinkargs *args)
454{ 455{
455 unsigned int len; 456 unsigned int len, avail;
456 int avail;
457 char *old, *new; 457 char *old, *new;
458 struct kvec *vec; 458 struct kvec *vec;
459 459
@@ -486,7 +486,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
486 /* now copy next page if there is one */ 486 /* now copy next page if there is one */
487 if (len && !avail && rqstp->rq_arg.page_len) { 487 if (len && !avail && rqstp->rq_arg.page_len) {
488 avail = rqstp->rq_arg.page_len; 488 avail = rqstp->rq_arg.page_len;
489 if (avail > PAGE_SIZE) avail = PAGE_SIZE; 489 if (avail > PAGE_SIZE)
490 avail = PAGE_SIZE;
490 old = page_address(rqstp->rq_arg.pages[0]); 491 old = page_address(rqstp->rq_arg.pages[0]);
491 } 492 }
492 while (len && avail && *old) { 493 while (len && avail && *old) {
@@ -816,11 +817,11 @@ static __be32 *
816encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, 817encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
817 struct svc_fh *fhp) 818 struct svc_fh *fhp)
818{ 819{
819 p = encode_post_op_attr(cd->rqstp, p, fhp); 820 p = encode_post_op_attr(cd->rqstp, p, fhp);
820 *p++ = xdr_one; /* yes, a file handle follows */ 821 *p++ = xdr_one; /* yes, a file handle follows */
821 p = encode_fh(p, fhp); 822 p = encode_fh(p, fhp);
822 fh_put(fhp); 823 fh_put(fhp);
823 return p; 824 return p;
824} 825}
825 826
826static int 827static int
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 9d536a8cb379..aae2b29ae2c9 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -350,30 +350,6 @@ static struct rpc_version * nfs_cb_version[] = {
350static int do_probe_callback(void *data) 350static int do_probe_callback(void *data)
351{ 351{
352 struct nfs4_client *clp = data; 352 struct nfs4_client *clp = data;
353 struct nfs4_callback *cb = &clp->cl_callback;
354 struct rpc_message msg = {
355 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
356 .rpc_argp = clp,
357 };
358 int status;
359
360 status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
361
362 if (status) {
363 rpc_shutdown_client(cb->cb_client);
364 cb->cb_client = NULL;
365 } else
366 atomic_set(&cb->cb_set, 1);
367 put_nfs4_client(clp);
368 return 0;
369}
370
371/*
372 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
373 */
374void
375nfsd4_probe_callback(struct nfs4_client *clp)
376{
377 struct sockaddr_in addr; 353 struct sockaddr_in addr;
378 struct nfs4_callback *cb = &clp->cl_callback; 354 struct nfs4_callback *cb = &clp->cl_callback;
379 struct rpc_timeout timeparms = { 355 struct rpc_timeout timeparms = {
@@ -390,13 +366,15 @@ nfsd4_probe_callback(struct nfs4_client *clp)
390 .timeout = &timeparms, 366 .timeout = &timeparms,
391 .program = program, 367 .program = program,
392 .version = nfs_cb_version[1]->number, 368 .version = nfs_cb_version[1]->number,
393 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ 369 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
394 .flags = (RPC_CLNT_CREATE_NOPING), 370 .flags = (RPC_CLNT_CREATE_NOPING),
395 }; 371 };
396 struct task_struct *t; 372 struct rpc_message msg = {
397 373 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
398 if (atomic_read(&cb->cb_set)) 374 .rpc_argp = clp,
399 return; 375 };
376 struct rpc_clnt *client;
377 int status;
400 378
401 /* Initialize address */ 379 /* Initialize address */
402 memset(&addr, 0, sizeof(addr)); 380 memset(&addr, 0, sizeof(addr));
@@ -416,29 +394,50 @@ nfsd4_probe_callback(struct nfs4_client *clp)
416 program->stats->program = program; 394 program->stats->program = program;
417 395
418 /* Create RPC client */ 396 /* Create RPC client */
419 cb->cb_client = rpc_create(&args); 397 client = rpc_create(&args);
420 if (IS_ERR(cb->cb_client)) { 398 if (IS_ERR(client)) {
421 dprintk("NFSD: couldn't create callback client\n"); 399 dprintk("NFSD: couldn't create callback client\n");
400 status = PTR_ERR(client);
422 goto out_err; 401 goto out_err;
423 } 402 }
424 403
404 status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
405
406 if (status)
407 goto out_release_client;
408
409 cb->cb_client = client;
410 atomic_set(&cb->cb_set, 1);
411 put_nfs4_client(clp);
412 return 0;
413out_release_client:
414 rpc_shutdown_client(client);
415out_err:
416 put_nfs4_client(clp);
417 dprintk("NFSD: warning: no callback path to client %.*s\n",
418 (int)clp->cl_name.len, clp->cl_name.data);
419 return status;
420}
421
422/*
423 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
424 */
425void
426nfsd4_probe_callback(struct nfs4_client *clp)
427{
428 struct task_struct *t;
429
430 BUG_ON(atomic_read(&clp->cl_callback.cb_set));
431
425 /* the task holds a reference to the nfs4_client struct */ 432 /* the task holds a reference to the nfs4_client struct */
426 atomic_inc(&clp->cl_count); 433 atomic_inc(&clp->cl_count);
427 434
428 t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); 435 t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
429 436
430 if (IS_ERR(t)) 437 if (IS_ERR(t))
431 goto out_release_clp; 438 atomic_dec(&clp->cl_count);
432 439
433 return; 440 return;
434
435out_release_clp:
436 atomic_dec(&clp->cl_count);
437 rpc_shutdown_client(cb->cb_client);
438out_err:
439 cb->cb_client = NULL;
440 dprintk("NFSD: warning: no callback path to client %.*s\n",
441 (int)clp->cl_name.len, clp->cl_name.data);
442} 441}
443 442
444/* 443/*
@@ -458,9 +457,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
458 int retries = 1; 457 int retries = 1;
459 int status = 0; 458 int status = 0;
460 459
461 if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
462 return;
463
464 cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ 460 cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
465 cbr->cbr_dp = dp; 461 cbr->cbr_dp = dp;
466 462
@@ -469,6 +465,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
469 switch (status) { 465 switch (status) {
470 case -EIO: 466 case -EIO:
471 /* Network partition? */ 467 /* Network partition? */
468 atomic_set(&clp->cl_callback.cb_set, 0);
472 case -EBADHANDLE: 469 case -EBADHANDLE:
473 case -NFS4ERR_BAD_STATEID: 470 case -NFS4ERR_BAD_STATEID:
474 /* Race: client probably got cb_recall 471 /* Race: client probably got cb_recall
@@ -481,11 +478,10 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
481 status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); 478 status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
482 } 479 }
483out_put_cred: 480out_put_cred:
484 if (status == -EIO) 481 /*
485 atomic_set(&clp->cl_callback.cb_set, 0); 482 * Success or failure, now we're either waiting for lease expiration
486 /* Success or failure, now we're either waiting for lease expiration 483 * or deleg_return.
487 * or deleg_return. */ 484 */
488 dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
489 put_nfs4_client(clp); 485 put_nfs4_client(clp);
490 nfs4_put_delegation(dp); 486 nfs4_put_delegation(dp);
491 return; 487 return;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 4c0c683ce07a..996bd88b75ba 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -255,13 +255,10 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
255 goto out; 255 goto out;
256 if (len == 0) 256 if (len == 0)
257 set_bit(CACHE_NEGATIVE, &ent.h.flags); 257 set_bit(CACHE_NEGATIVE, &ent.h.flags);
258 else { 258 else if (len >= IDMAP_NAMESZ)
259 if (error >= IDMAP_NAMESZ) { 259 goto out;
260 error = -EINVAL; 260 else
261 goto out;
262 }
263 memcpy(ent.name, buf1, sizeof(ent.name)); 261 memcpy(ent.name, buf1, sizeof(ent.name));
264 }
265 error = -ENOMEM; 262 error = -ENOMEM;
266 res = idtoname_update(&ent, res); 263 res = idtoname_update(&ent, res);
267 if (res == NULL) 264 if (res == NULL)
@@ -467,20 +464,25 @@ nametoid_update(struct ent *new, struct ent *old)
467 * Exported API 464 * Exported API
468 */ 465 */
469 466
470void 467int
471nfsd_idmap_init(void) 468nfsd_idmap_init(void)
472{ 469{
473 cache_register(&idtoname_cache); 470 int rv;
474 cache_register(&nametoid_cache); 471
472 rv = cache_register(&idtoname_cache);
473 if (rv)
474 return rv;
475 rv = cache_register(&nametoid_cache);
476 if (rv)
477 cache_unregister(&idtoname_cache);
478 return rv;
475} 479}
476 480
477void 481void
478nfsd_idmap_shutdown(void) 482nfsd_idmap_shutdown(void)
479{ 483{
480 if (cache_unregister(&idtoname_cache)) 484 cache_unregister(&idtoname_cache);
481 printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n"); 485 cache_unregister(&nametoid_cache);
482 if (cache_unregister(&nametoid_cache))
483 printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
484} 486}
485 487
486/* 488/*
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 18ead1790bb3..c593db047d8b 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -750,7 +750,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
750 cstate->current_fh.fh_export, 750 cstate->current_fh.fh_export,
751 cstate->current_fh.fh_dentry, buf, 751 cstate->current_fh.fh_dentry, buf,
752 &count, verify->ve_bmval, 752 &count, verify->ve_bmval,
753 rqstp); 753 rqstp, 0);
754 754
755 /* this means that nfsd4_encode_fattr() ran out of space */ 755 /* this means that nfsd4_encode_fattr() ran out of space */
756 if (status == nfserr_resource && count == 0) 756 if (status == nfserr_resource && count == 0)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 31673cd251c3..f6744bc03dae 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -61,7 +61,6 @@ static time_t lease_time = 90; /* default lease time */
61static time_t user_lease_time = 90; 61static time_t user_lease_time = 90;
62static time_t boot_time; 62static time_t boot_time;
63static int in_grace = 1; 63static int in_grace = 1;
64static u32 current_clientid = 1;
65static u32 current_ownerid = 1; 64static u32 current_ownerid = 1;
66static u32 current_fileid = 1; 65static u32 current_fileid = 1;
67static u32 current_delegid = 1; 66static u32 current_delegid = 1;
@@ -340,21 +339,20 @@ STALE_CLIENTID(clientid_t *clid)
340 * This type of memory management is somewhat inefficient, but we use it 339 * This type of memory management is somewhat inefficient, but we use it
341 * anyway since SETCLIENTID is not a common operation. 340 * anyway since SETCLIENTID is not a common operation.
342 */ 341 */
343static inline struct nfs4_client * 342static struct nfs4_client *alloc_client(struct xdr_netobj name)
344alloc_client(struct xdr_netobj name)
345{ 343{
346 struct nfs4_client *clp; 344 struct nfs4_client *clp;
347 345
348 if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) { 346 clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
349 if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) { 347 if (clp == NULL)
350 memcpy(clp->cl_name.data, name.data, name.len); 348 return NULL;
351 clp->cl_name.len = name.len; 349 clp->cl_name.data = kmalloc(name.len, GFP_KERNEL);
352 } 350 if (clp->cl_name.data == NULL) {
353 else { 351 kfree(clp);
354 kfree(clp); 352 return NULL;
355 clp = NULL;
356 }
357 } 353 }
354 memcpy(clp->cl_name.data, name.data, name.len);
355 clp->cl_name.len = name.len;
358 return clp; 356 return clp;
359} 357}
360 358
@@ -363,8 +361,11 @@ shutdown_callback_client(struct nfs4_client *clp)
363{ 361{
364 struct rpc_clnt *clnt = clp->cl_callback.cb_client; 362 struct rpc_clnt *clnt = clp->cl_callback.cb_client;
365 363
366 /* shutdown rpc client, ending any outstanding recall rpcs */
367 if (clnt) { 364 if (clnt) {
365 /*
366 * Callback threads take a reference on the client, so there
367 * should be no outstanding callbacks at this point.
368 */
368 clp->cl_callback.cb_client = NULL; 369 clp->cl_callback.cb_client = NULL;
369 rpc_shutdown_client(clnt); 370 rpc_shutdown_client(clnt);
370 } 371 }
@@ -422,12 +423,13 @@ expire_client(struct nfs4_client *clp)
422 put_nfs4_client(clp); 423 put_nfs4_client(clp);
423} 424}
424 425
425static struct nfs4_client * 426static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir)
426create_client(struct xdr_netobj name, char *recdir) { 427{
427 struct nfs4_client *clp; 428 struct nfs4_client *clp;
428 429
429 if (!(clp = alloc_client(name))) 430 clp = alloc_client(name);
430 goto out; 431 if (clp == NULL)
432 return NULL;
431 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); 433 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
432 atomic_set(&clp->cl_count, 1); 434 atomic_set(&clp->cl_count, 1);
433 atomic_set(&clp->cl_callback.cb_set, 0); 435 atomic_set(&clp->cl_callback.cb_set, 0);
@@ -436,32 +438,30 @@ create_client(struct xdr_netobj name, char *recdir) {
436 INIT_LIST_HEAD(&clp->cl_openowners); 438 INIT_LIST_HEAD(&clp->cl_openowners);
437 INIT_LIST_HEAD(&clp->cl_delegations); 439 INIT_LIST_HEAD(&clp->cl_delegations);
438 INIT_LIST_HEAD(&clp->cl_lru); 440 INIT_LIST_HEAD(&clp->cl_lru);
439out:
440 return clp; 441 return clp;
441} 442}
442 443
443static void 444static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
444copy_verf(struct nfs4_client *target, nfs4_verifier *source) { 445{
445 memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data)); 446 memcpy(target->cl_verifier.data, source->data,
447 sizeof(target->cl_verifier.data));
446} 448}
447 449
448static void 450static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
449copy_clid(struct nfs4_client *target, struct nfs4_client *source) { 451{
450 target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 452 target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
451 target->cl_clientid.cl_id = source->cl_clientid.cl_id; 453 target->cl_clientid.cl_id = source->cl_clientid.cl_id;
452} 454}
453 455
454static void 456static void copy_cred(struct svc_cred *target, struct svc_cred *source)
455copy_cred(struct svc_cred *target, struct svc_cred *source) { 457{
456
457 target->cr_uid = source->cr_uid; 458 target->cr_uid = source->cr_uid;
458 target->cr_gid = source->cr_gid; 459 target->cr_gid = source->cr_gid;
459 target->cr_group_info = source->cr_group_info; 460 target->cr_group_info = source->cr_group_info;
460 get_group_info(target->cr_group_info); 461 get_group_info(target->cr_group_info);
461} 462}
462 463
463static inline int 464static int same_name(const char *n1, const char *n2)
464same_name(const char *n1, const char *n2)
465{ 465{
466 return 0 == memcmp(n1, n2, HEXDIR_LEN); 466 return 0 == memcmp(n1, n2, HEXDIR_LEN);
467} 467}
@@ -485,26 +485,26 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
485 return cr1->cr_uid == cr2->cr_uid; 485 return cr1->cr_uid == cr2->cr_uid;
486} 486}
487 487
488static void 488static void gen_clid(struct nfs4_client *clp)
489gen_clid(struct nfs4_client *clp) { 489{
490 static u32 current_clientid = 1;
491
490 clp->cl_clientid.cl_boot = boot_time; 492 clp->cl_clientid.cl_boot = boot_time;
491 clp->cl_clientid.cl_id = current_clientid++; 493 clp->cl_clientid.cl_id = current_clientid++;
492} 494}
493 495
494static void 496static void gen_confirm(struct nfs4_client *clp)
495gen_confirm(struct nfs4_client *clp) { 497{
496 struct timespec tv; 498 static u32 i;
497 u32 * p; 499 u32 *p;
498 500
499 tv = CURRENT_TIME;
500 p = (u32 *)clp->cl_confirm.data; 501 p = (u32 *)clp->cl_confirm.data;
501 *p++ = tv.tv_sec; 502 *p++ = get_seconds();
502 *p++ = tv.tv_nsec; 503 *p++ = i++;
503} 504}
504 505
505static int 506static int check_name(struct xdr_netobj name)
506check_name(struct xdr_netobj name) { 507{
507
508 if (name.len == 0) 508 if (name.len == 0)
509 return 0; 509 return 0;
510 if (name.len > NFS4_OPAQUE_LIMIT) { 510 if (name.len > NFS4_OPAQUE_LIMIT) {
@@ -683,39 +683,6 @@ out_err:
683 return; 683 return;
684} 684}
685 685
686/*
687 * RFC 3010 has a complex implmentation description of processing a
688 * SETCLIENTID request consisting of 5 bullets, labeled as
689 * CASE0 - CASE4 below.
690 *
691 * NOTES:
692 * callback information will be processed in a future patch
693 *
694 * an unconfirmed record is added when:
695 * NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record.
696 * CASE 1: confirmed record found with matching name, principal,
697 * verifier, and clientid.
698 * CASE 2: confirmed record found with matching name, principal,
699 * and there is no unconfirmed record with matching
700 * name and principal
701 *
702 * an unconfirmed record is replaced when:
703 * CASE 3: confirmed record found with matching name, principal,
704 * and an unconfirmed record is found with matching
705 * name, principal, and with clientid and
706 * confirm that does not match the confirmed record.
707 * CASE 4: there is no confirmed record with matching name and
708 * principal. there is an unconfirmed record with
709 * matching name, principal.
710 *
711 * an unconfirmed record is deleted when:
712 * CASE 1: an unconfirmed record that matches input name, verifier,
713 * and confirmed clientid.
714 * CASE 4: any unconfirmed records with matching name and principal
715 * that exist after an unconfirmed record has been replaced
716 * as described above.
717 *
718 */
719__be32 686__be32
720nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 687nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
721 struct nfsd4_setclientid *setclid) 688 struct nfsd4_setclientid *setclid)
@@ -748,11 +715,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
748 nfs4_lock_state(); 715 nfs4_lock_state();
749 conf = find_confirmed_client_by_str(dname, strhashval); 716 conf = find_confirmed_client_by_str(dname, strhashval);
750 if (conf) { 717 if (conf) {
751 /* 718 /* RFC 3530 14.2.33 CASE 0: */
752 * CASE 0:
753 * clname match, confirmed, different principal
754 * or different ip_address
755 */
756 status = nfserr_clid_inuse; 719 status = nfserr_clid_inuse;
757 if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) 720 if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
758 || conf->cl_addr != sin->sin_addr.s_addr) { 721 || conf->cl_addr != sin->sin_addr.s_addr) {
@@ -761,12 +724,17 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
761 goto out; 724 goto out;
762 } 725 }
763 } 726 }
727 /*
728 * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
729 * has a description of SETCLIENTID request processing consisting
730 * of 5 bullet points, labeled as CASE0 - CASE4 below.
731 */
764 unconf = find_unconfirmed_client_by_str(dname, strhashval); 732 unconf = find_unconfirmed_client_by_str(dname, strhashval);
765 status = nfserr_resource; 733 status = nfserr_resource;
766 if (!conf) { 734 if (!conf) {
767 /* 735 /*
768 * CASE 4: 736 * RFC 3530 14.2.33 CASE 4:
769 * placed first, because it is the normal case. 737 * placed first, because it is the normal case
770 */ 738 */
771 if (unconf) 739 if (unconf)
772 expire_client(unconf); 740 expire_client(unconf);
@@ -776,17 +744,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
776 gen_clid(new); 744 gen_clid(new);
777 } else if (same_verf(&conf->cl_verifier, &clverifier)) { 745 } else if (same_verf(&conf->cl_verifier, &clverifier)) {
778 /* 746 /*
779 * CASE 1: 747 * RFC 3530 14.2.33 CASE 1:
780 * cl_name match, confirmed, principal match 748 * probable callback update
781 * verifier match: probable callback update
782 *
783 * remove any unconfirmed nfs4_client with
784 * matching cl_name, cl_verifier, and cl_clientid
785 *
786 * create and insert an unconfirmed nfs4_client with same
787 * cl_name, cl_verifier, and cl_clientid as existing
788 * nfs4_client, but with the new callback info and a
789 * new cl_confirm
790 */ 749 */
791 if (unconf) { 750 if (unconf) {
792 /* Note this is removing unconfirmed {*x***}, 751 /* Note this is removing unconfirmed {*x***},
@@ -802,43 +761,25 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
802 copy_clid(new, conf); 761 copy_clid(new, conf);
803 } else if (!unconf) { 762 } else if (!unconf) {
804 /* 763 /*
805 * CASE 2: 764 * RFC 3530 14.2.33 CASE 2:
806 * clname match, confirmed, principal match 765 * probable client reboot; state will be removed if
807 * verfier does not match 766 * confirmed.
808 * no unconfirmed. create a new unconfirmed nfs4_client
809 * using input clverifier, clname, and callback info
810 * and generate a new cl_clientid and cl_confirm.
811 */ 767 */
812 new = create_client(clname, dname); 768 new = create_client(clname, dname);
813 if (new == NULL) 769 if (new == NULL)
814 goto out; 770 goto out;
815 gen_clid(new); 771 gen_clid(new);
816 } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) { 772 } else {
817 /* 773 /*
818 * CASE3: 774 * RFC 3530 14.2.33 CASE 3:
819 * confirmed found (name, principal match) 775 * probable client reboot; state will be removed if
820 * confirmed verifier does not match input clverifier 776 * confirmed.
821 *
822 * unconfirmed found (name match)
823 * confirmed->cl_confirm != unconfirmed->cl_confirm
824 *
825 * remove unconfirmed.
826 *
827 * create an unconfirmed nfs4_client
828 * with same cl_name as existing confirmed nfs4_client,
829 * but with new callback info, new cl_clientid,
830 * new cl_verifier and a new cl_confirm
831 */ 777 */
832 expire_client(unconf); 778 expire_client(unconf);
833 new = create_client(clname, dname); 779 new = create_client(clname, dname);
834 if (new == NULL) 780 if (new == NULL)
835 goto out; 781 goto out;
836 gen_clid(new); 782 gen_clid(new);
837 } else {
838 /* No cases hit !!! */
839 status = nfserr_inval;
840 goto out;
841
842 } 783 }
843 copy_verf(new, &clverifier); 784 copy_verf(new, &clverifier);
844 new->cl_addr = sin->sin_addr.s_addr; 785 new->cl_addr = sin->sin_addr.s_addr;
@@ -857,11 +798,9 @@ out:
857 798
858 799
859/* 800/*
860 * RFC 3010 has a complex implmentation description of processing a 801 * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
861 * SETCLIENTID_CONFIRM request consisting of 4 bullets describing 802 * a description of SETCLIENTID_CONFIRM request processing consisting of 4
862 * processing on a DRC miss, labeled as CASE1 - CASE4 below. 803 * bullets, labeled as CASE1 - CASE4 below.
863 *
864 * NOTE: callback information will be processed here in a future patch
865 */ 804 */
866__be32 805__be32
867nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 806nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
@@ -892,16 +831,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
892 if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) 831 if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)
893 goto out; 832 goto out;
894 833
895 if ((conf && unconf) && 834 /*
896 (same_verf(&unconf->cl_confirm, &confirm)) && 835 * section 14.2.34 of RFC 3530 has a description of
897 (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) && 836 * SETCLIENTID_CONFIRM request processing consisting
898 (same_name(conf->cl_recdir,unconf->cl_recdir)) && 837 * of 4 bullet points, labeled as CASE1 - CASE4 below.
899 (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) { 838 */
900 /* CASE 1: 839 if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
901 * unconf record that matches input clientid and input confirm. 840 /*
902 * conf record that matches input clientid. 841 * RFC 3530 14.2.34 CASE 1:
903 * conf and unconf records match names, verifiers 842 * callback update
904 */ 843 */
905 if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) 844 if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
906 status = nfserr_clid_inuse; 845 status = nfserr_clid_inuse;
907 else { 846 else {
@@ -914,15 +853,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
914 status = nfs_ok; 853 status = nfs_ok;
915 854
916 } 855 }
917 } else if ((conf && !unconf) || 856 } else if (conf && !unconf) {
918 ((conf && unconf) && 857 /*
919 (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) || 858 * RFC 3530 14.2.34 CASE 2:
920 !same_name(conf->cl_recdir, unconf->cl_recdir)))) { 859 * probable retransmitted request; play it safe and
921 /* CASE 2: 860 * do nothing.
922 * conf record that matches input clientid.
923 * if unconf record matches input clientid, then
924 * unconf->cl_name or unconf->cl_verifier don't match the
925 * conf record.
926 */ 861 */
927 if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) 862 if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
928 status = nfserr_clid_inuse; 863 status = nfserr_clid_inuse;
@@ -930,10 +865,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
930 status = nfs_ok; 865 status = nfs_ok;
931 } else if (!conf && unconf 866 } else if (!conf && unconf
932 && same_verf(&unconf->cl_confirm, &confirm)) { 867 && same_verf(&unconf->cl_confirm, &confirm)) {
933 /* CASE 3: 868 /*
934 * conf record not found. 869 * RFC 3530 14.2.34 CASE 3:
935 * unconf record found. 870 * Normal case; new or rebooted client:
936 * unconf->cl_confirm matches input confirm
937 */ 871 */
938 if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { 872 if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
939 status = nfserr_clid_inuse; 873 status = nfserr_clid_inuse;
@@ -948,16 +882,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
948 } 882 }
949 move_to_confirmed(unconf); 883 move_to_confirmed(unconf);
950 conf = unconf; 884 conf = unconf;
885 nfsd4_probe_callback(conf);
951 status = nfs_ok; 886 status = nfs_ok;
952 } 887 }
953 } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) 888 } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
954 && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, 889 && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
955 &confirm)))) { 890 &confirm)))) {
956 /* CASE 4: 891 /*
957 * conf record not found, or if conf, conf->cl_confirm does not 892 * RFC 3530 14.2.34 CASE 4:
958 * match input confirm. 893 * Client probably hasn't noticed that we rebooted yet.
959 * unconf record not found, or if unconf, unconf->cl_confirm
960 * does not match input confirm.
961 */ 894 */
962 status = nfserr_stale_clientid; 895 status = nfserr_stale_clientid;
963 } else { 896 } else {
@@ -965,8 +898,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
965 status = nfserr_clid_inuse; 898 status = nfserr_clid_inuse;
966 } 899 }
967out: 900out:
968 if (!status)
969 nfsd4_probe_callback(conf);
970 nfs4_unlock_state(); 901 nfs4_unlock_state();
971 return status; 902 return status;
972} 903}
@@ -1226,14 +1157,19 @@ find_file(struct inode *ino)
1226 return NULL; 1157 return NULL;
1227} 1158}
1228 1159
1229static int access_valid(u32 x) 1160static inline int access_valid(u32 x)
1230{ 1161{
1231 return (x > 0 && x < 4); 1162 if (x < NFS4_SHARE_ACCESS_READ)
1163 return 0;
1164 if (x > NFS4_SHARE_ACCESS_BOTH)
1165 return 0;
1166 return 1;
1232} 1167}
1233 1168
1234static int deny_valid(u32 x) 1169static inline int deny_valid(u32 x)
1235{ 1170{
1236 return (x >= 0 && x < 5); 1171 /* Note: unlike access bits, deny bits may be zero. */
1172 return x <= NFS4_SHARE_DENY_BOTH;
1237} 1173}
1238 1174
1239static void 1175static void
@@ -2162,8 +2098,10 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2162 goto check_replay; 2098 goto check_replay;
2163 } 2099 }
2164 2100
2101 *stpp = stp;
2102 *sopp = sop = stp->st_stateowner;
2103
2165 if (lock) { 2104 if (lock) {
2166 struct nfs4_stateowner *sop = stp->st_stateowner;
2167 clientid_t *lockclid = &lock->v.new.clientid; 2105 clientid_t *lockclid = &lock->v.new.clientid;
2168 struct nfs4_client *clp = sop->so_client; 2106 struct nfs4_client *clp = sop->so_client;
2169 int lkflg = 0; 2107 int lkflg = 0;
@@ -2193,9 +2131,6 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2193 return nfserr_bad_stateid; 2131 return nfserr_bad_stateid;
2194 } 2132 }
2195 2133
2196 *stpp = stp;
2197 *sopp = sop = stp->st_stateowner;
2198
2199 /* 2134 /*
2200 * We now validate the seqid and stateid generation numbers. 2135 * We now validate the seqid and stateid generation numbers.
2201 * For the moment, we ignore the possibility of 2136 * For the moment, we ignore the possibility of
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 57333944af7f..b0592e7c378d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -148,12 +148,12 @@ xdr_error: \
148 } \ 148 } \
149} while (0) 149} while (0)
150 150
151static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) 151static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
152{ 152{
153 /* We want more bytes than seem to be available. 153 /* We want more bytes than seem to be available.
154 * Maybe we need a new page, maybe we have just run out 154 * Maybe we need a new page, maybe we have just run out
155 */ 155 */
156 int avail = (char*)argp->end - (char*)argp->p; 156 unsigned int avail = (char *)argp->end - (char *)argp->p;
157 __be32 *p; 157 __be32 *p;
158 if (avail + argp->pagelen < nbytes) 158 if (avail + argp->pagelen < nbytes)
159 return NULL; 159 return NULL;
@@ -169,6 +169,11 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
169 return NULL; 169 return NULL;
170 170
171 } 171 }
172 /*
173 * The following memcpy is safe because read_buf is always
174 * called with nbytes > avail, and the two cases above both
175 * guarantee p points to at least nbytes bytes.
176 */
172 memcpy(p, argp->p, avail); 177 memcpy(p, argp->p, avail);
173 /* step to next page */ 178 /* step to next page */
174 argp->p = page_address(argp->pagelist[0]); 179 argp->p = page_address(argp->pagelist[0]);
@@ -1448,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
1448__be32 1453__be32
1449nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, 1454nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
1450 struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval, 1455 struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
1451 struct svc_rqst *rqstp) 1456 struct svc_rqst *rqstp, int ignore_crossmnt)
1452{ 1457{
1453 u32 bmval0 = bmval[0]; 1458 u32 bmval0 = bmval[0];
1454 u32 bmval1 = bmval[1]; 1459 u32 bmval1 = bmval[1];
@@ -1828,7 +1833,12 @@ out_acl:
1828 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { 1833 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
1829 if ((buflen -= 8) < 0) 1834 if ((buflen -= 8) < 0)
1830 goto out_resource; 1835 goto out_resource;
1831 if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { 1836 /*
1837 * Get parent's attributes if not ignoring crossmount
1838 * and this is the root of a cross-mounted filesystem.
1839 */
1840 if (ignore_crossmnt == 0 &&
1841 exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
1832 err = vfs_getattr(exp->ex_mnt->mnt_parent, 1842 err = vfs_getattr(exp->ex_mnt->mnt_parent,
1833 exp->ex_mnt->mnt_mountpoint, &stat); 1843 exp->ex_mnt->mnt_mountpoint, &stat);
1834 if (err) 1844 if (err)
@@ -1864,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1864 struct svc_export *exp = cd->rd_fhp->fh_export; 1874 struct svc_export *exp = cd->rd_fhp->fh_export;
1865 struct dentry *dentry; 1875 struct dentry *dentry;
1866 __be32 nfserr; 1876 __be32 nfserr;
1877 int ignore_crossmnt = 0;
1867 1878
1868 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); 1879 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
1869 if (IS_ERR(dentry)) 1880 if (IS_ERR(dentry))
1870 return nfserrno(PTR_ERR(dentry)); 1881 return nfserrno(PTR_ERR(dentry));
1871 1882
1872 exp_get(exp); 1883 exp_get(exp);
1873 if (d_mountpoint(dentry)) { 1884 /*
1885 * In the case of a mountpoint, the client may be asking for
1886 * attributes that are only properties of the underlying filesystem
1887 * as opposed to the cross-mounted file system. In such a case,
1888 * we will not follow the cross mount and will fill the attribtutes
1889 * directly from the mountpoint dentry.
1890 */
1891 if (d_mountpoint(dentry) &&
1892 (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
1893 (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
1894 ignore_crossmnt = 1;
1895 else if (d_mountpoint(dentry)) {
1874 int err; 1896 int err;
1875 1897
1876 /* 1898 /*
@@ -1889,7 +1911,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1889 1911
1890 } 1912 }
1891 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, 1913 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
1892 cd->rd_rqstp); 1914 cd->rd_rqstp, ignore_crossmnt);
1893out_put: 1915out_put:
1894 dput(dentry); 1916 dput(dentry);
1895 exp_put(exp); 1917 exp_put(exp);
@@ -2043,7 +2065,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
2043 buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); 2065 buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
2044 nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, 2066 nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
2045 resp->p, &buflen, getattr->ga_bmval, 2067 resp->p, &buflen, getattr->ga_bmval,
2046 resp->rqstp); 2068 resp->rqstp, 0);
2047 if (!nfserr) 2069 if (!nfserr)
2048 resp->p += buflen; 2070 resp->p += buflen;
2049 return nfserr; 2071 return nfserr;
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 578f2c9d56be..5bfc2ac60d54 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -44,17 +44,17 @@ static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
44 */ 44 */
45static DEFINE_SPINLOCK(cache_lock); 45static DEFINE_SPINLOCK(cache_lock);
46 46
47void 47int nfsd_reply_cache_init(void)
48nfsd_cache_init(void)
49{ 48{
50 struct svc_cacherep *rp; 49 struct svc_cacherep *rp;
51 int i; 50 int i;
52 51
53 INIT_LIST_HEAD(&lru_head); 52 INIT_LIST_HEAD(&lru_head);
54 i = CACHESIZE; 53 i = CACHESIZE;
55 while(i) { 54 while (i) {
56 rp = kmalloc(sizeof(*rp), GFP_KERNEL); 55 rp = kmalloc(sizeof(*rp), GFP_KERNEL);
57 if (!rp) break; 56 if (!rp)
57 goto out_nomem;
58 list_add(&rp->c_lru, &lru_head); 58 list_add(&rp->c_lru, &lru_head);
59 rp->c_state = RC_UNUSED; 59 rp->c_state = RC_UNUSED;
60 rp->c_type = RC_NOCACHE; 60 rp->c_type = RC_NOCACHE;
@@ -62,23 +62,19 @@ nfsd_cache_init(void)
62 i--; 62 i--;
63 } 63 }
64 64
65 if (i)
66 printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
67 CACHESIZE, CACHESIZE-i);
68
69 hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); 65 hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
70 if (!hash_list) { 66 if (!hash_list)
71 nfsd_cache_shutdown(); 67 goto out_nomem;
72 printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
73 HASHSIZE * sizeof(struct hlist_head));
74 return;
75 }
76 68
77 cache_disabled = 0; 69 cache_disabled = 0;
70 return 0;
71out_nomem:
72 printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
73 nfsd_reply_cache_shutdown();
74 return -ENOMEM;
78} 75}
79 76
80void 77void nfsd_reply_cache_shutdown(void)
81nfsd_cache_shutdown(void)
82{ 78{
83 struct svc_cacherep *rp; 79 struct svc_cacherep *rp;
84 80
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 77dc9893b7ba..8516137cdbb0 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -304,6 +304,9 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
304 struct auth_domain *dom; 304 struct auth_domain *dom;
305 struct knfsd_fh fh; 305 struct knfsd_fh fh;
306 306
307 if (size == 0)
308 return -EINVAL;
309
307 if (buf[size-1] != '\n') 310 if (buf[size-1] != '\n')
308 return -EINVAL; 311 return -EINVAL;
309 buf[size-1] = 0; 312 buf[size-1] = 0;
@@ -503,7 +506,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
503 int len = 0; 506 int len = 0;
504 lock_kernel(); 507 lock_kernel();
505 if (nfsd_serv) 508 if (nfsd_serv)
506 len = svc_sock_names(buf, nfsd_serv, NULL); 509 len = svc_xprt_names(nfsd_serv, buf, 0);
507 unlock_kernel(); 510 unlock_kernel();
508 return len; 511 return len;
509 } 512 }
@@ -540,7 +543,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
540 } 543 }
541 return err < 0 ? err : 0; 544 return err < 0 ? err : 0;
542 } 545 }
543 if (buf[0] == '-') { 546 if (buf[0] == '-' && isdigit(buf[1])) {
544 char *toclose = kstrdup(buf+1, GFP_KERNEL); 547 char *toclose = kstrdup(buf+1, GFP_KERNEL);
545 int len = 0; 548 int len = 0;
546 if (!toclose) 549 if (!toclose)
@@ -554,6 +557,53 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
554 kfree(toclose); 557 kfree(toclose);
555 return len; 558 return len;
556 } 559 }
560 /*
561 * Add a transport listener by writing it's transport name
562 */
563 if (isalpha(buf[0])) {
564 int err;
565 char transport[16];
566 int port;
567 if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
568 err = nfsd_create_serv();
569 if (!err) {
570 err = svc_create_xprt(nfsd_serv,
571 transport, port,
572 SVC_SOCK_ANONYMOUS);
573 if (err == -ENOENT)
574 /* Give a reasonable perror msg for
575 * bad transport string */
576 err = -EPROTONOSUPPORT;
577 }
578 return err < 0 ? err : 0;
579 }
580 }
581 /*
582 * Remove a transport by writing it's transport name and port number
583 */
584 if (buf[0] == '-' && isalpha(buf[1])) {
585 struct svc_xprt *xprt;
586 int err = -EINVAL;
587 char transport[16];
588 int port;
589 if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
590 if (port == 0)
591 return -EINVAL;
592 lock_kernel();
593 if (nfsd_serv) {
594 xprt = svc_find_xprt(nfsd_serv, transport,
595 AF_UNSPEC, port);
596 if (xprt) {
597 svc_close_xprt(xprt);
598 svc_xprt_put(xprt);
599 err = 0;
600 } else
601 err = -ENOTCONN;
602 }
603 unlock_kernel();
604 return err < 0 ? err : 0;
605 }
606 }
557 return -EINVAL; 607 return -EINVAL;
558} 608}
559 609
@@ -616,7 +666,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
616 char *recdir; 666 char *recdir;
617 int len, status; 667 int len, status;
618 668
619 if (size > PATH_MAX || buf[size-1] != '\n') 669 if (size == 0 || size > PATH_MAX || buf[size-1] != '\n')
620 return -EINVAL; 670 return -EINVAL;
621 buf[size-1] = 0; 671 buf[size-1] = 0;
622 672
@@ -674,6 +724,27 @@ static struct file_system_type nfsd_fs_type = {
674 .kill_sb = kill_litter_super, 724 .kill_sb = kill_litter_super,
675}; 725};
676 726
727#ifdef CONFIG_PROC_FS
728static int create_proc_exports_entry(void)
729{
730 struct proc_dir_entry *entry;
731
732 entry = proc_mkdir("fs/nfs", NULL);
733 if (!entry)
734 return -ENOMEM;
735 entry = create_proc_entry("fs/nfs/exports", 0, NULL);
736 if (!entry)
737 return -ENOMEM;
738 entry->proc_fops = &exports_operations;
739 return 0;
740}
741#else /* CONFIG_PROC_FS */
742static int create_proc_exports_entry(void)
743{
744 return 0;
745}
746#endif
747
677static int __init init_nfsd(void) 748static int __init init_nfsd(void)
678{ 749{
679 int retval; 750 int retval;
@@ -683,32 +754,43 @@ static int __init init_nfsd(void)
683 if (retval) 754 if (retval)
684 return retval; 755 return retval;
685 nfsd_stat_init(); /* Statistics */ 756 nfsd_stat_init(); /* Statistics */
686 nfsd_cache_init(); /* RPC reply cache */ 757 retval = nfsd_reply_cache_init();
687 nfsd_export_init(); /* Exports table */ 758 if (retval)
759 goto out_free_stat;
760 retval = nfsd_export_init();
761 if (retval)
762 goto out_free_cache;
688 nfsd_lockd_init(); /* lockd->nfsd callbacks */ 763 nfsd_lockd_init(); /* lockd->nfsd callbacks */
689 nfsd_idmap_init(); /* Name to ID mapping */ 764 retval = nfsd_idmap_init();
690 if (proc_mkdir("fs/nfs", NULL)) { 765 if (retval)
691 struct proc_dir_entry *entry; 766 goto out_free_lockd;
692 entry = create_proc_entry("fs/nfs/exports", 0, NULL); 767 retval = create_proc_exports_entry();
693 if (entry) 768 if (retval)
694 entry->proc_fops = &exports_operations; 769 goto out_free_idmap;
695 }
696 retval = register_filesystem(&nfsd_fs_type); 770 retval = register_filesystem(&nfsd_fs_type);
697 if (retval) { 771 if (retval)
698 nfsd_export_shutdown(); 772 goto out_free_all;
699 nfsd_cache_shutdown(); 773 return 0;
700 remove_proc_entry("fs/nfs/exports", NULL); 774out_free_all:
701 remove_proc_entry("fs/nfs", NULL); 775 remove_proc_entry("fs/nfs/exports", NULL);
702 nfsd_stat_shutdown(); 776 remove_proc_entry("fs/nfs", NULL);
703 nfsd_lockd_shutdown(); 777out_free_idmap:
704 } 778 nfsd_idmap_shutdown();
779out_free_lockd:
780 nfsd_lockd_shutdown();
781 nfsd_export_shutdown();
782out_free_cache:
783 nfsd_reply_cache_shutdown();
784out_free_stat:
785 nfsd_stat_shutdown();
786 nfsd4_free_slabs();
705 return retval; 787 return retval;
706} 788}
707 789
708static void __exit exit_nfsd(void) 790static void __exit exit_nfsd(void)
709{ 791{
710 nfsd_export_shutdown(); 792 nfsd_export_shutdown();
711 nfsd_cache_shutdown(); 793 nfsd_reply_cache_shutdown();
712 remove_proc_entry("fs/nfs/exports", NULL); 794 remove_proc_entry("fs/nfs/exports", NULL);
713 remove_proc_entry("fs/nfs", NULL); 795 remove_proc_entry("fs/nfs", NULL);
714 nfsd_stat_shutdown(); 796 nfsd_stat_shutdown();
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 468f17a78441..8fbd2dc08a92 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -22,6 +22,7 @@
22#include <linux/sunrpc/svc.h> 22#include <linux/sunrpc/svc.h>
23#include <linux/sunrpc/svcauth_gss.h> 23#include <linux/sunrpc/svcauth_gss.h>
24#include <linux/nfsd/nfsd.h> 24#include <linux/nfsd/nfsd.h>
25#include "auth.h"
25 26
26#define NFSDDBG_FACILITY NFSDDBG_FH 27#define NFSDDBG_FACILITY NFSDDBG_FH
27 28
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 1190aeaa92be..9647b0f7bc0c 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -155,8 +155,8 @@ static int killsig; /* signal that was used to kill last nfsd */
155static void nfsd_last_thread(struct svc_serv *serv) 155static void nfsd_last_thread(struct svc_serv *serv)
156{ 156{
157 /* When last nfsd thread exits we need to do some clean-up */ 157 /* When last nfsd thread exits we need to do some clean-up */
158 struct svc_sock *svsk; 158 struct svc_xprt *xprt;
159 list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) 159 list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
160 lockd_down(); 160 lockd_down();
161 nfsd_serv = NULL; 161 nfsd_serv = NULL;
162 nfsd_racache_shutdown(); 162 nfsd_racache_shutdown();
@@ -236,7 +236,7 @@ static int nfsd_init_socks(int port)
236 236
237 error = lockd_up(IPPROTO_UDP); 237 error = lockd_up(IPPROTO_UDP);
238 if (error >= 0) { 238 if (error >= 0) {
239 error = svc_makesock(nfsd_serv, IPPROTO_UDP, port, 239 error = svc_create_xprt(nfsd_serv, "udp", port,
240 SVC_SOCK_DEFAULTS); 240 SVC_SOCK_DEFAULTS);
241 if (error < 0) 241 if (error < 0)
242 lockd_down(); 242 lockd_down();
@@ -247,7 +247,7 @@ static int nfsd_init_socks(int port)
247#ifdef CONFIG_NFSD_TCP 247#ifdef CONFIG_NFSD_TCP
248 error = lockd_up(IPPROTO_TCP); 248 error = lockd_up(IPPROTO_TCP);
249 if (error >= 0) { 249 if (error >= 0) {
250 error = svc_makesock(nfsd_serv, IPPROTO_TCP, port, 250 error = svc_create_xprt(nfsd_serv, "tcp", port,
251 SVC_SOCK_DEFAULTS); 251 SVC_SOCK_DEFAULTS);
252 if (error < 0) 252 if (error < 0)
253 lockd_down(); 253 lockd_down();
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index b86e3658a0af..61ad61743d94 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -15,6 +15,7 @@
15#include <linux/nfsd/nfsd.h> 15#include <linux/nfsd/nfsd.h>
16#include <linux/nfsd/xdr.h> 16#include <linux/nfsd/xdr.h>
17#include <linux/mm.h> 17#include <linux/mm.h>
18#include "auth.h"
18 19
19#define NFSDDBG_FACILITY NFSDDBG_XDR 20#define NFSDDBG_FACILITY NFSDDBG_XDR
20 21
@@ -62,10 +63,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
62 * no slashes or null bytes. 63 * no slashes or null bytes.
63 */ 64 */
64static __be32 * 65static __be32 *
65decode_filename(__be32 *p, char **namp, int *lenp) 66decode_filename(__be32 *p, char **namp, unsigned int *lenp)
66{ 67{
67 char *name; 68 char *name;
68 int i; 69 unsigned int i;
69 70
70 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) { 71 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
71 for (i = 0, name = *namp; i < *lenp; i++, name++) { 72 for (i = 0, name = *namp; i < *lenp; i++, name++) {
@@ -78,10 +79,10 @@ decode_filename(__be32 *p, char **namp, int *lenp)
78} 79}
79 80
80static __be32 * 81static __be32 *
81decode_pathname(__be32 *p, char **namp, int *lenp) 82decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
82{ 83{
83 char *name; 84 char *name;
84 int i; 85 unsigned int i;
85 86
86 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) { 87 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
87 for (i = 0, name = *namp; i < *lenp; i++, name++) { 88 for (i = 0, name = *namp; i < *lenp; i++, name++) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index d0199189924c..cc75e4fcd02b 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -132,7 +132,7 @@ out:
132 132
133__be32 133__be32
134nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, 134nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
135 const char *name, int len, 135 const char *name, unsigned int len,
136 struct svc_export **exp_ret, struct dentry **dentry_ret) 136 struct svc_export **exp_ret, struct dentry **dentry_ret)
137{ 137{
138 struct svc_export *exp; 138 struct svc_export *exp;
@@ -226,7 +226,7 @@ out_nfserr:
226 */ 226 */
227__be32 227__be32
228nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 228nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
229 int len, struct svc_fh *resfh) 229 unsigned int len, struct svc_fh *resfh)
230{ 230{
231 struct svc_export *exp; 231 struct svc_export *exp;
232 struct dentry *dentry; 232 struct dentry *dentry;
@@ -1151,6 +1151,26 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1151} 1151}
1152#endif /* CONFIG_NFSD_V3 */ 1152#endif /* CONFIG_NFSD_V3 */
1153 1153
1154__be32
1155nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
1156 struct iattr *iap)
1157{
1158 /*
1159 * Mode has already been set earlier in create:
1160 */
1161 iap->ia_valid &= ~ATTR_MODE;
1162 /*
1163 * Setting uid/gid works only for root. Irix appears to
1164 * send along the gid on create when it tries to implement
1165 * setgid directories via NFS:
1166 */
1167 if (current->fsuid != 0)
1168 iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
1169 if (iap->ia_valid)
1170 return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
1171 return 0;
1172}
1173
1154/* 1174/*
1155 * Create a file (regular, directory, device, fifo); UNIX sockets 1175 * Create a file (regular, directory, device, fifo); UNIX sockets
1156 * not yet implemented. 1176 * not yet implemented.
@@ -1167,6 +1187,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1167 struct dentry *dentry, *dchild = NULL; 1187 struct dentry *dentry, *dchild = NULL;
1168 struct inode *dirp; 1188 struct inode *dirp;
1169 __be32 err; 1189 __be32 err;
1190 __be32 err2;
1170 int host_err; 1191 int host_err;
1171 1192
1172 err = nfserr_perm; 1193 err = nfserr_perm;
@@ -1257,16 +1278,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1257 } 1278 }
1258 1279
1259 1280
1260 /* Set file attributes. Mode has already been set and 1281 err2 = nfsd_create_setattr(rqstp, resfhp, iap);
1261 * setting uid/gid works only for root. Irix appears to 1282 if (err2)
1262 * send along the gid when it tries to implement setgid 1283 err = err2;
1263 * directories via NFS.
1264 */
1265 if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
1266 __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
1267 if (err2)
1268 err = err2;
1269 }
1270 /* 1284 /*
1271 * Update the file handle to get the new inode info. 1285 * Update the file handle to get the new inode info.
1272 */ 1286 */
@@ -1295,6 +1309,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1295 struct dentry *dentry, *dchild = NULL; 1309 struct dentry *dentry, *dchild = NULL;
1296 struct inode *dirp; 1310 struct inode *dirp;
1297 __be32 err; 1311 __be32 err;
1312 __be32 err2;
1298 int host_err; 1313 int host_err;
1299 __u32 v_mtime=0, v_atime=0; 1314 __u32 v_mtime=0, v_atime=0;
1300 1315
@@ -1399,16 +1414,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1399 iap->ia_atime.tv_nsec = 0; 1414 iap->ia_atime.tv_nsec = 0;
1400 } 1415 }
1401 1416
1402 /* Set file attributes.
1403 * Irix appears to send along the gid when it tries to
1404 * implement setgid directories via NFS. Clear out all that cruft.
1405 */
1406 set_attr: 1417 set_attr:
1407 if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { 1418 err2 = nfsd_create_setattr(rqstp, resfhp, iap);
1408 __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); 1419 if (err2)
1409 if (err2) 1420 err = err2;
1410 err = err2;
1411 }
1412 1421
1413 /* 1422 /*
1414 * Update the filehandle to get the new inode info. 1423 * Update the filehandle to get the new inode info.