diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 11:32:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 11:32:58 -0400 |
commit | 419f4319495043a9507ac3e616be9ca60af09744 (patch) | |
tree | 0f747d80d11a6d4cd726ad6556839d5cd40b23ac | |
parent | fb21affa49204acd409328415b49bfe90136653c (diff) | |
parent | 6eccece90b6addf80ef9e6db79b0bc873301034b (diff) |
Merge branch 'for-3.5' of git://linux-nfs.org/~bfields/linux
Pull the rest of the nfsd commits from Bruce Fields:
"... and then I cherry-picked the remainder of the patches from the
head of my previous branch"
This is the rest of the original nfsd branch, rebased without the
delegation stuff that I thought really needed to be redone.
I don't like rebasing things like this in general, but in this situation
this was the lesser of two evils.
* 'for-3.5' of git://linux-nfs.org/~bfields/linux: (50 commits)
nfsd4: fix, consolidate client_has_state
nfsd4: don't remove rebooted client record until confirmation
nfsd4: remove some dprintk's and a comment
nfsd4: return "real" sequence id in confirmed case
nfsd4: fix exchange_id to return confirm flag
nfsd4: clarify that renewing expired client is a bug
nfsd4: simpler ordering of setclientid_confirm checks
nfsd4: setclientid: remove pointless assignment
nfsd4: fix error return in non-matching-creds case
nfsd4: fix setclientid_confirm same_cred check
nfsd4: merge 3 setclientid cases to 2
nfsd4: pull out common code from setclientid cases
nfsd4: merge last two setclientid cases
nfsd4: setclientid/confirm comment cleanup
nfsd4: setclientid remove unnecessary terms from a logical expression
nfsd4: move rq_flavor into svc_cred
nfsd4: stricter cred comparison for setclientid/exchange_id
nfsd4: move principal name into svc_cred
nfsd4: allow removing clients not holding state
nfsd4: rearrange exchange_id logic to simplify
...
-rw-r--r-- | fs/lockd/svc.c | 145 | ||||
-rw-r--r-- | fs/nfs/callback.c | 13 | ||||
-rw-r--r-- | fs/nfsd/auth.c | 2 | ||||
-rw-r--r-- | fs/nfsd/export.c | 8 | ||||
-rw-r--r-- | fs/nfsd/fault_inject.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 525 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 62 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 12 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 23 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 6 | ||||
-rw-r--r-- | include/linux/sunrpc/svc.h | 2 | ||||
-rw-r--r-- | include/linux/sunrpc/svcauth.h | 10 | ||||
-rw-r--r-- | include/linux/sunrpc/svcauth_gss.h | 1 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_wrap.c | 61 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 27 | ||||
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 12 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 23 | ||||
-rw-r--r-- | net/sunrpc/svc_xprt.c | 4 | ||||
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 6 |
23 files changed, 522 insertions, 435 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1ead0750cdbb..80938fda67e0 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -251,39 +251,40 @@ out_err: | |||
251 | return err; | 251 | return err; |
252 | } | 252 | } |
253 | 253 | ||
254 | static int lockd_up_net(struct net *net) | 254 | static int lockd_up_net(struct svc_serv *serv, struct net *net) |
255 | { | 255 | { |
256 | struct lockd_net *ln = net_generic(net, lockd_net_id); | 256 | struct lockd_net *ln = net_generic(net, lockd_net_id); |
257 | struct svc_serv *serv = nlmsvc_rqst->rq_server; | ||
258 | int error; | 257 | int error; |
259 | 258 | ||
260 | if (ln->nlmsvc_users) | 259 | if (ln->nlmsvc_users++) |
261 | return 0; | 260 | return 0; |
262 | 261 | ||
263 | error = svc_rpcb_setup(serv, net); | 262 | error = svc_bind(serv, net); |
264 | if (error) | 263 | if (error) |
265 | goto err_rpcb; | 264 | goto err_bind; |
266 | 265 | ||
267 | error = make_socks(serv, net); | 266 | error = make_socks(serv, net); |
268 | if (error < 0) | 267 | if (error < 0) |
269 | goto err_socks; | 268 | goto err_socks; |
269 | dprintk("lockd_up_net: per-net data created; net=%p\n", net); | ||
270 | return 0; | 270 | return 0; |
271 | 271 | ||
272 | err_socks: | 272 | err_socks: |
273 | svc_rpcb_cleanup(serv, net); | 273 | svc_rpcb_cleanup(serv, net); |
274 | err_rpcb: | 274 | err_bind: |
275 | ln->nlmsvc_users--; | ||
275 | return error; | 276 | return error; |
276 | } | 277 | } |
277 | 278 | ||
278 | static void lockd_down_net(struct net *net) | 279 | static void lockd_down_net(struct svc_serv *serv, struct net *net) |
279 | { | 280 | { |
280 | struct lockd_net *ln = net_generic(net, lockd_net_id); | 281 | struct lockd_net *ln = net_generic(net, lockd_net_id); |
281 | struct svc_serv *serv = nlmsvc_rqst->rq_server; | ||
282 | 282 | ||
283 | if (ln->nlmsvc_users) { | 283 | if (ln->nlmsvc_users) { |
284 | if (--ln->nlmsvc_users == 0) { | 284 | if (--ln->nlmsvc_users == 0) { |
285 | nlm_shutdown_hosts_net(net); | 285 | nlm_shutdown_hosts_net(net); |
286 | svc_shutdown_net(serv, net); | 286 | svc_shutdown_net(serv, net); |
287 | dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net); | ||
287 | } | 288 | } |
288 | } else { | 289 | } else { |
289 | printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n", | 290 | printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n", |
@@ -292,21 +293,60 @@ static void lockd_down_net(struct net *net) | |||
292 | } | 293 | } |
293 | } | 294 | } |
294 | 295 | ||
295 | /* | 296 | static int lockd_start_svc(struct svc_serv *serv) |
296 | * Bring up the lockd process if it's not already up. | 297 | { |
297 | */ | 298 | int error; |
298 | int lockd_up(struct net *net) | 299 | |
300 | if (nlmsvc_rqst) | ||
301 | return 0; | ||
302 | |||
303 | /* | ||
304 | * Create the kernel thread and wait for it to start. | ||
305 | */ | ||
306 | nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); | ||
307 | if (IS_ERR(nlmsvc_rqst)) { | ||
308 | error = PTR_ERR(nlmsvc_rqst); | ||
309 | printk(KERN_WARNING | ||
310 | "lockd_up: svc_rqst allocation failed, error=%d\n", | ||
311 | error); | ||
312 | goto out_rqst; | ||
313 | } | ||
314 | |||
315 | svc_sock_update_bufs(serv); | ||
316 | serv->sv_maxconn = nlm_max_connections; | ||
317 | |||
318 | nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); | ||
319 | if (IS_ERR(nlmsvc_task)) { | ||
320 | error = PTR_ERR(nlmsvc_task); | ||
321 | printk(KERN_WARNING | ||
322 | "lockd_up: kthread_run failed, error=%d\n", error); | ||
323 | goto out_task; | ||
324 | } | ||
325 | dprintk("lockd_up: service started\n"); | ||
326 | return 0; | ||
327 | |||
328 | out_task: | ||
329 | svc_exit_thread(nlmsvc_rqst); | ||
330 | nlmsvc_task = NULL; | ||
331 | out_rqst: | ||
332 | nlmsvc_rqst = NULL; | ||
333 | return error; | ||
334 | } | ||
335 | |||
336 | static struct svc_serv *lockd_create_svc(void) | ||
299 | { | 337 | { |
300 | struct svc_serv *serv; | 338 | struct svc_serv *serv; |
301 | int error = 0; | ||
302 | 339 | ||
303 | mutex_lock(&nlmsvc_mutex); | ||
304 | /* | 340 | /* |
305 | * Check whether we're already up and running. | 341 | * Check whether we're already up and running. |
306 | */ | 342 | */ |
307 | if (nlmsvc_rqst) { | 343 | if (nlmsvc_rqst) { |
308 | error = lockd_up_net(net); | 344 | /* |
309 | goto out; | 345 | * Note: increase service usage, because later in case of error |
346 | * svc_destroy() will be called. | ||
347 | */ | ||
348 | svc_get(nlmsvc_rqst->rq_server); | ||
349 | return nlmsvc_rqst->rq_server; | ||
310 | } | 350 | } |
311 | 351 | ||
312 | /* | 352 | /* |
@@ -317,59 +357,53 @@ int lockd_up(struct net *net) | |||
317 | printk(KERN_WARNING | 357 | printk(KERN_WARNING |
318 | "lockd_up: no pid, %d users??\n", nlmsvc_users); | 358 | "lockd_up: no pid, %d users??\n", nlmsvc_users); |
319 | 359 | ||
320 | error = -ENOMEM; | ||
321 | serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL); | 360 | serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL); |
322 | if (!serv) { | 361 | if (!serv) { |
323 | printk(KERN_WARNING "lockd_up: create service failed\n"); | 362 | printk(KERN_WARNING "lockd_up: create service failed\n"); |
324 | goto out; | 363 | return ERR_PTR(-ENOMEM); |
325 | } | 364 | } |
365 | dprintk("lockd_up: service created\n"); | ||
366 | return serv; | ||
367 | } | ||
326 | 368 | ||
327 | error = make_socks(serv, net); | 369 | /* |
328 | if (error < 0) | 370 | * Bring up the lockd process if it's not already up. |
329 | goto destroy_and_out; | 371 | */ |
372 | int lockd_up(struct net *net) | ||
373 | { | ||
374 | struct svc_serv *serv; | ||
375 | int error; | ||
330 | 376 | ||
331 | /* | 377 | mutex_lock(&nlmsvc_mutex); |
332 | * Create the kernel thread and wait for it to start. | 378 | |
333 | */ | 379 | serv = lockd_create_svc(); |
334 | nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); | 380 | if (IS_ERR(serv)) { |
335 | if (IS_ERR(nlmsvc_rqst)) { | 381 | error = PTR_ERR(serv); |
336 | error = PTR_ERR(nlmsvc_rqst); | 382 | goto err_create; |
337 | nlmsvc_rqst = NULL; | ||
338 | printk(KERN_WARNING | ||
339 | "lockd_up: svc_rqst allocation failed, error=%d\n", | ||
340 | error); | ||
341 | goto destroy_and_out; | ||
342 | } | 383 | } |
343 | 384 | ||
344 | svc_sock_update_bufs(serv); | 385 | error = lockd_up_net(serv, net); |
345 | serv->sv_maxconn = nlm_max_connections; | 386 | if (error < 0) |
387 | goto err_net; | ||
346 | 388 | ||
347 | nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name); | 389 | error = lockd_start_svc(serv); |
348 | if (IS_ERR(nlmsvc_task)) { | 390 | if (error < 0) |
349 | error = PTR_ERR(nlmsvc_task); | 391 | goto err_start; |
350 | svc_exit_thread(nlmsvc_rqst); | ||
351 | nlmsvc_task = NULL; | ||
352 | nlmsvc_rqst = NULL; | ||
353 | printk(KERN_WARNING | ||
354 | "lockd_up: kthread_run failed, error=%d\n", error); | ||
355 | goto destroy_and_out; | ||
356 | } | ||
357 | 392 | ||
393 | nlmsvc_users++; | ||
358 | /* | 394 | /* |
359 | * Note: svc_serv structures have an initial use count of 1, | 395 | * Note: svc_serv structures have an initial use count of 1, |
360 | * so we exit through here on both success and failure. | 396 | * so we exit through here on both success and failure. |
361 | */ | 397 | */ |
362 | destroy_and_out: | 398 | err_net: |
363 | svc_destroy(serv); | 399 | svc_destroy(serv); |
364 | out: | 400 | err_create: |
365 | if (!error) { | ||
366 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
367 | |||
368 | ln->nlmsvc_users++; | ||
369 | nlmsvc_users++; | ||
370 | } | ||
371 | mutex_unlock(&nlmsvc_mutex); | 401 | mutex_unlock(&nlmsvc_mutex); |
372 | return error; | 402 | return error; |
403 | |||
404 | err_start: | ||
405 | lockd_down_net(serv, net); | ||
406 | goto err_net; | ||
373 | } | 407 | } |
374 | EXPORT_SYMBOL_GPL(lockd_up); | 408 | EXPORT_SYMBOL_GPL(lockd_up); |
375 | 409 | ||
@@ -380,11 +414,10 @@ void | |||
380 | lockd_down(struct net *net) | 414 | lockd_down(struct net *net) |
381 | { | 415 | { |
382 | mutex_lock(&nlmsvc_mutex); | 416 | mutex_lock(&nlmsvc_mutex); |
417 | lockd_down_net(nlmsvc_rqst->rq_server, net); | ||
383 | if (nlmsvc_users) { | 418 | if (nlmsvc_users) { |
384 | if (--nlmsvc_users) { | 419 | if (--nlmsvc_users) |
385 | lockd_down_net(net); | ||
386 | goto out; | 420 | goto out; |
387 | } | ||
388 | } else { | 421 | } else { |
389 | printk(KERN_ERR "lockd_down: no users! task=%p\n", | 422 | printk(KERN_ERR "lockd_down: no users! task=%p\n", |
390 | nlmsvc_task); | 423 | nlmsvc_task); |
@@ -396,7 +429,9 @@ lockd_down(struct net *net) | |||
396 | BUG(); | 429 | BUG(); |
397 | } | 430 | } |
398 | kthread_stop(nlmsvc_task); | 431 | kthread_stop(nlmsvc_task); |
432 | dprintk("lockd_down: service stopped\n"); | ||
399 | svc_exit_thread(nlmsvc_rqst); | 433 | svc_exit_thread(nlmsvc_rqst); |
434 | dprintk("lockd_down: service destroyed\n"); | ||
400 | nlmsvc_task = NULL; | 435 | nlmsvc_task = NULL; |
401 | nlmsvc_rqst = NULL; | 436 | nlmsvc_rqst = NULL; |
402 | out: | 437 | out: |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index eb95f5091c1a..970659daa323 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/kthread.h> | 17 | #include <linux/kthread.h> |
18 | #include <linux/sunrpc/svcauth_gss.h> | 18 | #include <linux/sunrpc/svcauth_gss.h> |
19 | #include <linux/sunrpc/bc_xprt.h> | 19 | #include <linux/sunrpc/bc_xprt.h> |
20 | #include <linux/nsproxy.h> | ||
20 | 21 | ||
21 | #include <net/inet_sock.h> | 22 | #include <net/inet_sock.h> |
22 | 23 | ||
@@ -253,6 +254,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | |||
253 | char svc_name[12]; | 254 | char svc_name[12]; |
254 | int ret = 0; | 255 | int ret = 0; |
255 | int minorversion_setup; | 256 | int minorversion_setup; |
257 | struct net *net = current->nsproxy->net_ns; | ||
256 | 258 | ||
257 | mutex_lock(&nfs_callback_mutex); | 259 | mutex_lock(&nfs_callback_mutex); |
258 | if (cb_info->users++ || cb_info->task != NULL) { | 260 | if (cb_info->users++ || cb_info->task != NULL) { |
@@ -265,6 +267,12 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | |||
265 | goto out_err; | 267 | goto out_err; |
266 | } | 268 | } |
267 | 269 | ||
270 | ret = svc_bind(serv, net); | ||
271 | if (ret < 0) { | ||
272 | printk(KERN_WARNING "NFS: bind callback service failed\n"); | ||
273 | goto out_err; | ||
274 | } | ||
275 | |||
268 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, | 276 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, |
269 | serv, xprt, &rqstp, &callback_svc); | 277 | serv, xprt, &rqstp, &callback_svc); |
270 | if (!minorversion_setup) { | 278 | if (!minorversion_setup) { |
@@ -306,6 +314,8 @@ out_err: | |||
306 | dprintk("NFS: Couldn't create callback socket or server thread; " | 314 | dprintk("NFS: Couldn't create callback socket or server thread; " |
307 | "err = %d\n", ret); | 315 | "err = %d\n", ret); |
308 | cb_info->users--; | 316 | cb_info->users--; |
317 | if (serv) | ||
318 | svc_shutdown_net(serv, net); | ||
309 | goto out; | 319 | goto out; |
310 | } | 320 | } |
311 | 321 | ||
@@ -320,6 +330,7 @@ void nfs_callback_down(int minorversion) | |||
320 | cb_info->users--; | 330 | cb_info->users--; |
321 | if (cb_info->users == 0 && cb_info->task != NULL) { | 331 | if (cb_info->users == 0 && cb_info->task != NULL) { |
322 | kthread_stop(cb_info->task); | 332 | kthread_stop(cb_info->task); |
333 | svc_shutdown_net(cb_info->serv, current->nsproxy->net_ns); | ||
323 | svc_exit_thread(cb_info->rqst); | 334 | svc_exit_thread(cb_info->rqst); |
324 | cb_info->serv = NULL; | 335 | cb_info->serv = NULL; |
325 | cb_info->rqst = NULL; | 336 | cb_info->rqst = NULL; |
@@ -332,7 +343,7 @@ void nfs_callback_down(int minorversion) | |||
332 | int | 343 | int |
333 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | 344 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) |
334 | { | 345 | { |
335 | char *p = svc_gss_principal(rqstp); | 346 | char *p = rqstp->rq_cred.cr_principal; |
336 | 347 | ||
337 | if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) | 348 | if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) |
338 | return 1; | 349 | return 1; |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 204438cc914e..34a10d78b839 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -11,7 +11,7 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | |||
11 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | 11 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; |
12 | 12 | ||
13 | for (f = exp->ex_flavors; f < end; f++) { | 13 | for (f = exp->ex_flavors; f < end; f++) { |
14 | if (f->pseudoflavor == rqstp->rq_flavor) | 14 | if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) |
15 | return f->flags; | 15 | return f->flags; |
16 | } | 16 | } |
17 | return exp->ex_flags; | 17 | return exp->ex_flags; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index dcb52b884519..ba233499b9a5 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -706,7 +706,7 @@ static struct cache_head *svc_export_alloc(void) | |||
706 | return NULL; | 706 | return NULL; |
707 | } | 707 | } |
708 | 708 | ||
709 | struct cache_detail svc_export_cache_template = { | 709 | static struct cache_detail svc_export_cache_template = { |
710 | .owner = THIS_MODULE, | 710 | .owner = THIS_MODULE, |
711 | .hash_size = EXPORT_HASHMAX, | 711 | .hash_size = EXPORT_HASHMAX, |
712 | .name = "nfsd.export", | 712 | .name = "nfsd.export", |
@@ -904,13 +904,13 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) | |||
904 | return 0; | 904 | return 0; |
905 | /* ip-address based client; check sec= export option: */ | 905 | /* ip-address based client; check sec= export option: */ |
906 | for (f = exp->ex_flavors; f < end; f++) { | 906 | for (f = exp->ex_flavors; f < end; f++) { |
907 | if (f->pseudoflavor == rqstp->rq_flavor) | 907 | if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) |
908 | return 0; | 908 | return 0; |
909 | } | 909 | } |
910 | /* defaults in absence of sec= options: */ | 910 | /* defaults in absence of sec= options: */ |
911 | if (exp->ex_nflavors == 0) { | 911 | if (exp->ex_nflavors == 0) { |
912 | if (rqstp->rq_flavor == RPC_AUTH_NULL || | 912 | if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL || |
913 | rqstp->rq_flavor == RPC_AUTH_UNIX) | 913 | rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX) |
914 | return 0; | 914 | return 0; |
915 | } | 915 | } |
916 | return nfserr_wrongsec; | 916 | return nfserr_wrongsec; |
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 9559ce468732..e6c38159622f 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
@@ -58,6 +58,7 @@ static int nfsd_inject_set(void *op_ptr, u64 val) | |||
58 | 58 | ||
59 | static int nfsd_inject_get(void *data, u64 *val) | 59 | static int nfsd_inject_get(void *data, u64 *val) |
60 | { | 60 | { |
61 | *val = 0; | ||
61 | return 0; | 62 | return 0; |
62 | } | 63 | } |
63 | 64 | ||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index c8e9f637153a..a5fd6b982f27 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -650,9 +650,10 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c | |||
650 | struct rpc_clnt *client; | 650 | struct rpc_clnt *client; |
651 | 651 | ||
652 | if (clp->cl_minorversion == 0) { | 652 | if (clp->cl_minorversion == 0) { |
653 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 653 | if (!clp->cl_cred.cr_principal && |
654 | (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | ||
654 | return -EINVAL; | 655 | return -EINVAL; |
655 | args.client_name = clp->cl_principal; | 656 | args.client_name = clp->cl_cred.cr_principal; |
656 | args.prognumber = conn->cb_prog, | 657 | args.prognumber = conn->cb_prog, |
657 | args.protocol = XPRT_TRANSPORT_TCP; | 658 | args.protocol = XPRT_TRANSPORT_TCP; |
658 | args.authflavor = clp->cl_flavor; | 659 | args.authflavor = clp->cl_flavor; |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 286a7f8f2024..dae36f1dee95 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -605,7 +605,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel | |||
605 | static __be32 | 605 | static __be32 |
606 | do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) | 606 | do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, uid_t *id) |
607 | { | 607 | { |
608 | if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS) | 608 | if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) |
609 | if (numeric_name_to_id(rqstp, type, name, namelen, id)) | 609 | if (numeric_name_to_id(rqstp, type, name, namelen, id)) |
610 | return 0; | 610 | return 0; |
611 | /* | 611 | /* |
@@ -618,7 +618,7 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u | |||
618 | static int | 618 | static int |
619 | do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | 619 | do_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) |
620 | { | 620 | { |
621 | if (nfs4_disable_idmapping && rqstp->rq_flavor < RPC_AUTH_GSS) | 621 | if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) |
622 | return sprintf(name, "%u", id); | 622 | return sprintf(name, "%u", id); |
623 | return idmap_id_to_name(rqstp, type, id, name); | 623 | return idmap_id_to_name(rqstp, type, id, name); |
624 | } | 624 | } |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index ed3f9206a0ee..5ff0b7b9fc08 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -570,7 +570,7 @@ static ssize_t | |||
570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 570 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
571 | { | 571 | { |
572 | struct cld_upcall *tmp, *cup; | 572 | struct cld_upcall *tmp, *cup; |
573 | struct cld_msg *cmsg = (struct cld_msg *)src; | 573 | struct cld_msg __user *cmsg = (struct cld_msg __user *)src; |
574 | uint32_t xid; | 574 | uint32_t xid; |
575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, | 575 | struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, |
576 | nfsd_net_id); | 576 | nfsd_net_id); |
@@ -1029,7 +1029,7 @@ rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) | |||
1029 | return ret; | 1029 | return ret; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | struct notifier_block nfsd4_cld_block = { | 1032 | static struct notifier_block nfsd4_cld_block = { |
1033 | .notifier_call = rpc_pipefs_event, | 1033 | .notifier_call = rpc_pipefs_event, |
1034 | }; | 1034 | }; |
1035 | 1035 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 03f82c0bc35d..8fdc9ec5c5d3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
43 | #include "xdr4.h" | 43 | #include "xdr4.h" |
44 | #include "vfs.h" | 44 | #include "vfs.h" |
45 | #include "current_stateid.h" | ||
45 | 46 | ||
46 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 47 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
47 | 48 | ||
@@ -447,37 +448,69 @@ static struct list_head close_lru; | |||
447 | * | 448 | * |
448 | * which we should reject. | 449 | * which we should reject. |
449 | */ | 450 | */ |
450 | static void | 451 | static unsigned int |
451 | set_access(unsigned int *access, unsigned long bmap) { | 452 | bmap_to_share_mode(unsigned long bmap) { |
452 | int i; | 453 | int i; |
454 | unsigned int access = 0; | ||
453 | 455 | ||
454 | *access = 0; | ||
455 | for (i = 1; i < 4; i++) { | 456 | for (i = 1; i < 4; i++) { |
456 | if (test_bit(i, &bmap)) | 457 | if (test_bit(i, &bmap)) |
457 | *access |= i; | 458 | access |= i; |
458 | } | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
463 | int i; | ||
464 | |||
465 | *deny = 0; | ||
466 | for (i = 0; i < 4; i++) { | ||
467 | if (test_bit(i, &bmap)) | ||
468 | *deny |= i ; | ||
469 | } | 459 | } |
460 | return access; | ||
470 | } | 461 | } |
471 | 462 | ||
472 | static int | 463 | static bool |
473 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { | 464 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { |
474 | unsigned int access, deny; | 465 | unsigned int access, deny; |
475 | 466 | ||
476 | set_access(&access, stp->st_access_bmap); | 467 | access = bmap_to_share_mode(stp->st_access_bmap); |
477 | set_deny(&deny, stp->st_deny_bmap); | 468 | deny = bmap_to_share_mode(stp->st_deny_bmap); |
478 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | 469 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) |
479 | return 0; | 470 | return false; |
480 | return 1; | 471 | return true; |
472 | } | ||
473 | |||
474 | /* set share access for a given stateid */ | ||
475 | static inline void | ||
476 | set_access(u32 access, struct nfs4_ol_stateid *stp) | ||
477 | { | ||
478 | __set_bit(access, &stp->st_access_bmap); | ||
479 | } | ||
480 | |||
481 | /* clear share access for a given stateid */ | ||
482 | static inline void | ||
483 | clear_access(u32 access, struct nfs4_ol_stateid *stp) | ||
484 | { | ||
485 | __clear_bit(access, &stp->st_access_bmap); | ||
486 | } | ||
487 | |||
488 | /* test whether a given stateid has access */ | ||
489 | static inline bool | ||
490 | test_access(u32 access, struct nfs4_ol_stateid *stp) | ||
491 | { | ||
492 | return test_bit(access, &stp->st_access_bmap); | ||
493 | } | ||
494 | |||
495 | /* set share deny for a given stateid */ | ||
496 | static inline void | ||
497 | set_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
498 | { | ||
499 | __set_bit(access, &stp->st_deny_bmap); | ||
500 | } | ||
501 | |||
502 | /* clear share deny for a given stateid */ | ||
503 | static inline void | ||
504 | clear_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
505 | { | ||
506 | __clear_bit(access, &stp->st_deny_bmap); | ||
507 | } | ||
508 | |||
509 | /* test whether a given stateid is denying specific access */ | ||
510 | static inline bool | ||
511 | test_deny(u32 access, struct nfs4_ol_stateid *stp) | ||
512 | { | ||
513 | return test_bit(access, &stp->st_deny_bmap); | ||
481 | } | 514 | } |
482 | 515 | ||
483 | static int nfs4_access_to_omode(u32 access) | 516 | static int nfs4_access_to_omode(u32 access) |
@@ -493,6 +526,20 @@ static int nfs4_access_to_omode(u32 access) | |||
493 | BUG(); | 526 | BUG(); |
494 | } | 527 | } |
495 | 528 | ||
529 | /* release all access and file references for a given stateid */ | ||
530 | static void | ||
531 | release_all_access(struct nfs4_ol_stateid *stp) | ||
532 | { | ||
533 | int i; | ||
534 | |||
535 | for (i = 1; i < 4; i++) { | ||
536 | if (test_access(i, stp)) | ||
537 | nfs4_file_put_access(stp->st_file, | ||
538 | nfs4_access_to_omode(i)); | ||
539 | clear_access(i, stp); | ||
540 | } | ||
541 | } | ||
542 | |||
496 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | 543 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) |
497 | { | 544 | { |
498 | list_del(&stp->st_perfile); | 545 | list_del(&stp->st_perfile); |
@@ -501,16 +548,7 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | |||
501 | 548 | ||
502 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) | 549 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) |
503 | { | 550 | { |
504 | int i; | 551 | release_all_access(stp); |
505 | |||
506 | if (stp->st_access_bmap) { | ||
507 | for (i = 1; i < 4; i++) { | ||
508 | if (test_bit(i, &stp->st_access_bmap)) | ||
509 | nfs4_file_put_access(stp->st_file, | ||
510 | nfs4_access_to_omode(i)); | ||
511 | __clear_bit(i, &stp->st_access_bmap); | ||
512 | } | ||
513 | } | ||
514 | put_nfs4_file(stp->st_file); | 552 | put_nfs4_file(stp->st_file); |
515 | stp->st_file = NULL; | 553 | stp->st_file = NULL; |
516 | } | 554 | } |
@@ -885,7 +923,7 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
885 | struct nfsd4_session *new; | 923 | struct nfsd4_session *new; |
886 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; | 924 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; |
887 | int numslots, slotsize; | 925 | int numslots, slotsize; |
888 | int status; | 926 | __be32 status; |
889 | int idx; | 927 | int idx; |
890 | 928 | ||
891 | /* | 929 | /* |
@@ -984,7 +1022,8 @@ static inline void | |||
984 | renew_client_locked(struct nfs4_client *clp) | 1022 | renew_client_locked(struct nfs4_client *clp) |
985 | { | 1023 | { |
986 | if (is_client_expired(clp)) { | 1024 | if (is_client_expired(clp)) { |
987 | dprintk("%s: client (clientid %08x/%08x) already expired\n", | 1025 | WARN_ON(1); |
1026 | printk("%s: client (clientid %08x/%08x) already expired\n", | ||
988 | __func__, | 1027 | __func__, |
989 | clp->cl_clientid.cl_boot, | 1028 | clp->cl_clientid.cl_boot, |
990 | clp->cl_clientid.cl_id); | 1029 | clp->cl_clientid.cl_id); |
@@ -1049,9 +1088,7 @@ free_client(struct nfs4_client *clp) | |||
1049 | list_del(&ses->se_perclnt); | 1088 | list_del(&ses->se_perclnt); |
1050 | nfsd4_put_session_locked(ses); | 1089 | nfsd4_put_session_locked(ses); |
1051 | } | 1090 | } |
1052 | if (clp->cl_cred.cr_group_info) | 1091 | free_svc_cred(&clp->cl_cred); |
1053 | put_group_info(clp->cl_cred.cr_group_info); | ||
1054 | kfree(clp->cl_principal); | ||
1055 | kfree(clp->cl_name.data); | 1092 | kfree(clp->cl_name.data); |
1056 | kfree(clp); | 1093 | kfree(clp); |
1057 | } | 1094 | } |
@@ -1132,12 +1169,21 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) | |||
1132 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 1169 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
1133 | } | 1170 | } |
1134 | 1171 | ||
1135 | static void copy_cred(struct svc_cred *target, struct svc_cred *source) | 1172 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) |
1136 | { | 1173 | { |
1174 | if (source->cr_principal) { | ||
1175 | target->cr_principal = | ||
1176 | kstrdup(source->cr_principal, GFP_KERNEL); | ||
1177 | if (target->cr_principal == NULL) | ||
1178 | return -ENOMEM; | ||
1179 | } else | ||
1180 | target->cr_principal = NULL; | ||
1181 | target->cr_flavor = source->cr_flavor; | ||
1137 | target->cr_uid = source->cr_uid; | 1182 | target->cr_uid = source->cr_uid; |
1138 | target->cr_gid = source->cr_gid; | 1183 | target->cr_gid = source->cr_gid; |
1139 | target->cr_group_info = source->cr_group_info; | 1184 | target->cr_group_info = source->cr_group_info; |
1140 | get_group_info(target->cr_group_info); | 1185 | get_group_info(target->cr_group_info); |
1186 | return 0; | ||
1141 | } | 1187 | } |
1142 | 1188 | ||
1143 | static int same_name(const char *n1, const char *n2) | 1189 | static int same_name(const char *n1, const char *n2) |
@@ -1157,11 +1203,31 @@ same_clid(clientid_t *cl1, clientid_t *cl2) | |||
1157 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); | 1203 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); |
1158 | } | 1204 | } |
1159 | 1205 | ||
1160 | /* XXX what about NGROUP */ | 1206 | static bool groups_equal(struct group_info *g1, struct group_info *g2) |
1207 | { | ||
1208 | int i; | ||
1209 | |||
1210 | if (g1->ngroups != g2->ngroups) | ||
1211 | return false; | ||
1212 | for (i=0; i<g1->ngroups; i++) | ||
1213 | if (GROUP_AT(g1, i) != GROUP_AT(g2, i)) | ||
1214 | return false; | ||
1215 | return true; | ||
1216 | } | ||
1217 | |||
1161 | static int | 1218 | static int |
1162 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | 1219 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) |
1163 | { | 1220 | { |
1164 | return cr1->cr_uid == cr2->cr_uid; | 1221 | if ((cr1->cr_flavor != cr2->cr_flavor) |
1222 | || (cr1->cr_uid != cr2->cr_uid) | ||
1223 | || (cr1->cr_gid != cr2->cr_gid) | ||
1224 | || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) | ||
1225 | return false; | ||
1226 | if (cr1->cr_principal == cr2->cr_principal) | ||
1227 | return true; | ||
1228 | if (!cr1->cr_principal || !cr2->cr_principal) | ||
1229 | return false; | ||
1230 | return 0 == strcmp(cr1->cr_principal, cr1->cr_principal); | ||
1165 | } | 1231 | } |
1166 | 1232 | ||
1167 | static void gen_clid(struct nfs4_client *clp) | 1233 | static void gen_clid(struct nfs4_client *clp) |
@@ -1204,25 +1270,20 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1204 | { | 1270 | { |
1205 | struct nfs4_client *clp; | 1271 | struct nfs4_client *clp; |
1206 | struct sockaddr *sa = svc_addr(rqstp); | 1272 | struct sockaddr *sa = svc_addr(rqstp); |
1207 | char *princ; | 1273 | int ret; |
1208 | 1274 | ||
1209 | clp = alloc_client(name); | 1275 | clp = alloc_client(name); |
1210 | if (clp == NULL) | 1276 | if (clp == NULL) |
1211 | return NULL; | 1277 | return NULL; |
1212 | 1278 | ||
1213 | INIT_LIST_HEAD(&clp->cl_sessions); | 1279 | INIT_LIST_HEAD(&clp->cl_sessions); |
1214 | 1280 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | |
1215 | princ = svc_gss_principal(rqstp); | 1281 | if (ret) { |
1216 | if (princ) { | 1282 | spin_lock(&client_lock); |
1217 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | 1283 | free_client(clp); |
1218 | if (clp->cl_principal == NULL) { | 1284 | spin_unlock(&client_lock); |
1219 | spin_lock(&client_lock); | 1285 | return NULL; |
1220 | free_client(clp); | ||
1221 | spin_unlock(&client_lock); | ||
1222 | return NULL; | ||
1223 | } | ||
1224 | } | 1286 | } |
1225 | |||
1226 | idr_init(&clp->cl_stateids); | 1287 | idr_init(&clp->cl_stateids); |
1227 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1288 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
1228 | atomic_set(&clp->cl_refcount, 0); | 1289 | atomic_set(&clp->cl_refcount, 0); |
@@ -1240,8 +1301,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1240 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1301 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
1241 | copy_verf(clp, verf); | 1302 | copy_verf(clp, verf); |
1242 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1303 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
1243 | clp->cl_flavor = rqstp->rq_flavor; | ||
1244 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
1245 | gen_confirm(clp); | 1304 | gen_confirm(clp); |
1246 | clp->cl_cb_session = NULL; | 1305 | clp->cl_cb_session = NULL; |
1247 | return clp; | 1306 | return clp; |
@@ -1470,18 +1529,32 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | |||
1470 | clid->flags = new->cl_exchange_flags; | 1529 | clid->flags = new->cl_exchange_flags; |
1471 | } | 1530 | } |
1472 | 1531 | ||
1532 | static bool client_has_state(struct nfs4_client *clp) | ||
1533 | { | ||
1534 | /* | ||
1535 | * Note clp->cl_openowners check isn't quite right: there's no | ||
1536 | * need to count owners without stateid's. | ||
1537 | * | ||
1538 | * Also note we should probably be using this in 4.0 case too. | ||
1539 | */ | ||
1540 | return !list_empty(&clp->cl_openowners) | ||
1541 | || !list_empty(&clp->cl_delegations) | ||
1542 | || !list_empty(&clp->cl_sessions); | ||
1543 | } | ||
1544 | |||
1473 | __be32 | 1545 | __be32 |
1474 | nfsd4_exchange_id(struct svc_rqst *rqstp, | 1546 | nfsd4_exchange_id(struct svc_rqst *rqstp, |
1475 | struct nfsd4_compound_state *cstate, | 1547 | struct nfsd4_compound_state *cstate, |
1476 | struct nfsd4_exchange_id *exid) | 1548 | struct nfsd4_exchange_id *exid) |
1477 | { | 1549 | { |
1478 | struct nfs4_client *unconf, *conf, *new; | 1550 | struct nfs4_client *unconf, *conf, *new; |
1479 | int status; | 1551 | __be32 status; |
1480 | unsigned int strhashval; | 1552 | unsigned int strhashval; |
1481 | char dname[HEXDIR_LEN]; | 1553 | char dname[HEXDIR_LEN]; |
1482 | char addr_str[INET6_ADDRSTRLEN]; | 1554 | char addr_str[INET6_ADDRSTRLEN]; |
1483 | nfs4_verifier verf = exid->verifier; | 1555 | nfs4_verifier verf = exid->verifier; |
1484 | struct sockaddr *sa = svc_addr(rqstp); | 1556 | struct sockaddr *sa = svc_addr(rqstp); |
1557 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | ||
1485 | 1558 | ||
1486 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1559 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
1487 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1560 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
@@ -1507,71 +1580,63 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1507 | status = nfs4_make_rec_clidname(dname, &exid->clname); | 1580 | status = nfs4_make_rec_clidname(dname, &exid->clname); |
1508 | 1581 | ||
1509 | if (status) | 1582 | if (status) |
1510 | goto error; | 1583 | return status; |
1511 | 1584 | ||
1512 | strhashval = clientstr_hashval(dname); | 1585 | strhashval = clientstr_hashval(dname); |
1513 | 1586 | ||
1587 | /* Cases below refer to rfc 5661 section 18.35.4: */ | ||
1514 | nfs4_lock_state(); | 1588 | nfs4_lock_state(); |
1515 | status = nfs_ok; | ||
1516 | |||
1517 | conf = find_confirmed_client_by_str(dname, strhashval); | 1589 | conf = find_confirmed_client_by_str(dname, strhashval); |
1518 | if (conf) { | 1590 | if (conf) { |
1519 | if (!clp_used_exchangeid(conf)) { | 1591 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); |
1520 | status = nfserr_clid_inuse; /* XXX: ? */ | 1592 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); |
1521 | goto out; | 1593 | |
1522 | } | 1594 | if (update) { |
1523 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1595 | if (!clp_used_exchangeid(conf)) { /* buggy client */ |
1524 | /* 18.35.4 case 8 */ | 1596 | status = nfserr_inval; |
1525 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1597 | goto out; |
1598 | } | ||
1599 | if (!creds_match) { /* case 9 */ | ||
1600 | status = nfserr_perm; | ||
1601 | goto out; | ||
1602 | } | ||
1603 | if (!verfs_match) { /* case 8 */ | ||
1526 | status = nfserr_not_same; | 1604 | status = nfserr_not_same; |
1527 | goto out; | 1605 | goto out; |
1528 | } | 1606 | } |
1529 | /* Client reboot: destroy old state */ | 1607 | /* case 6 */ |
1530 | expire_client(conf); | 1608 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1531 | goto out_new; | 1609 | new = conf; |
1610 | goto out_copy; | ||
1532 | } | 1611 | } |
1533 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1612 | if (!creds_match) { /* case 3 */ |
1534 | /* 18.35.4 case 9 */ | 1613 | if (client_has_state(conf)) { |
1535 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1614 | status = nfserr_clid_inuse; |
1536 | status = nfserr_perm; | ||
1537 | goto out; | 1615 | goto out; |
1538 | } | 1616 | } |
1539 | expire_client(conf); | 1617 | expire_client(conf); |
1540 | goto out_new; | 1618 | goto out_new; |
1541 | } | 1619 | } |
1542 | /* | 1620 | if (verfs_match) { /* case 2 */ |
1543 | * Set bit when the owner id and verifier map to an already | 1621 | conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1544 | * confirmed client id (18.35.3). | 1622 | new = conf; |
1545 | */ | 1623 | goto out_copy; |
1546 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | 1624 | } |
1547 | 1625 | /* case 5, client reboot */ | |
1548 | /* | 1626 | goto out_new; |
1549 | * Falling into 18.35.4 case 2, possible router replay. | ||
1550 | * Leave confirmed record intact and return same result. | ||
1551 | */ | ||
1552 | copy_verf(conf, &verf); | ||
1553 | new = conf; | ||
1554 | goto out_copy; | ||
1555 | } | 1627 | } |
1556 | 1628 | ||
1557 | /* 18.35.4 case 7 */ | 1629 | if (update) { /* case 7 */ |
1558 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1559 | status = nfserr_noent; | 1630 | status = nfserr_noent; |
1560 | goto out; | 1631 | goto out; |
1561 | } | 1632 | } |
1562 | 1633 | ||
1563 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1634 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1564 | if (unconf) { | 1635 | if (unconf) /* case 4, possible retry or client restart */ |
1565 | /* | ||
1566 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
1567 | * a new unconfirmed record should be generated regardless | ||
1568 | * of whether any properties have changed. | ||
1569 | */ | ||
1570 | expire_client(unconf); | 1636 | expire_client(unconf); |
1571 | } | ||
1572 | 1637 | ||
1638 | /* case 1 (normal case) */ | ||
1573 | out_new: | 1639 | out_new: |
1574 | /* Normal case */ | ||
1575 | new = create_client(exid->clname, dname, rqstp, &verf); | 1640 | new = create_client(exid->clname, dname, rqstp, &verf); |
1576 | if (new == NULL) { | 1641 | if (new == NULL) { |
1577 | status = nfserr_jukebox; | 1642 | status = nfserr_jukebox; |
@@ -1584,7 +1649,7 @@ out_copy: | |||
1584 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1649 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1585 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1650 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
1586 | 1651 | ||
1587 | exid->seqid = 1; | 1652 | exid->seqid = new->cl_cs_slot.sl_seqid + 1; |
1588 | nfsd4_set_ex_flags(new, exid); | 1653 | nfsd4_set_ex_flags(new, exid); |
1589 | 1654 | ||
1590 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1655 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
@@ -1593,12 +1658,10 @@ out_copy: | |||
1593 | 1658 | ||
1594 | out: | 1659 | out: |
1595 | nfs4_unlock_state(); | 1660 | nfs4_unlock_state(); |
1596 | error: | ||
1597 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
1598 | return status; | 1661 | return status; |
1599 | } | 1662 | } |
1600 | 1663 | ||
1601 | static int | 1664 | static __be32 |
1602 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | 1665 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
1603 | { | 1666 | { |
1604 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, | 1667 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
@@ -1626,7 +1689,7 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
1626 | */ | 1689 | */ |
1627 | static void | 1690 | static void |
1628 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | 1691 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, |
1629 | struct nfsd4_clid_slot *slot, int nfserr) | 1692 | struct nfsd4_clid_slot *slot, __be32 nfserr) |
1630 | { | 1693 | { |
1631 | slot->sl_status = nfserr; | 1694 | slot->sl_status = nfserr; |
1632 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | 1695 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); |
@@ -1657,7 +1720,7 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
1657 | /* seqid, slotID, slotID, slotID, status */ \ | 1720 | /* seqid, slotID, slotID, slotID, status */ \ |
1658 | 5 ) * sizeof(__be32)) | 1721 | 5 ) * sizeof(__be32)) |
1659 | 1722 | ||
1660 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) | 1723 | static bool check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) |
1661 | { | 1724 | { |
1662 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ | 1725 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ |
1663 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; | 1726 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; |
@@ -1673,7 +1736,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1673 | struct nfsd4_session *new; | 1736 | struct nfsd4_session *new; |
1674 | struct nfsd4_clid_slot *cs_slot = NULL; | 1737 | struct nfsd4_clid_slot *cs_slot = NULL; |
1675 | bool confirm_me = false; | 1738 | bool confirm_me = false; |
1676 | int status = 0; | 1739 | __be32 status = 0; |
1677 | 1740 | ||
1678 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1741 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1679 | return nfserr_inval; | 1742 | return nfserr_inval; |
@@ -1686,16 +1749,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1686 | cs_slot = &conf->cl_cs_slot; | 1749 | cs_slot = &conf->cl_cs_slot; |
1687 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1750 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1688 | if (status == nfserr_replay_cache) { | 1751 | if (status == nfserr_replay_cache) { |
1689 | dprintk("Got a create_session replay! seqid= %d\n", | ||
1690 | cs_slot->sl_seqid); | ||
1691 | /* Return the cached reply status */ | ||
1692 | status = nfsd4_replay_create_session(cr_ses, cs_slot); | 1752 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
1693 | goto out; | 1753 | goto out; |
1694 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { | 1754 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
1695 | status = nfserr_seq_misordered; | 1755 | status = nfserr_seq_misordered; |
1696 | dprintk("Sequence misordered!\n"); | ||
1697 | dprintk("Expected seqid= %d but got seqid= %d\n", | ||
1698 | cs_slot->sl_seqid, cr_ses->seqid); | ||
1699 | goto out; | 1756 | goto out; |
1700 | } | 1757 | } |
1701 | } else if (unconf) { | 1758 | } else if (unconf) { |
@@ -1704,7 +1761,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1704 | status = nfserr_clid_inuse; | 1761 | status = nfserr_clid_inuse; |
1705 | goto out; | 1762 | goto out; |
1706 | } | 1763 | } |
1707 | |||
1708 | cs_slot = &unconf->cl_cs_slot; | 1764 | cs_slot = &unconf->cl_cs_slot; |
1709 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1765 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1710 | if (status) { | 1766 | if (status) { |
@@ -1712,7 +1768,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1712 | status = nfserr_seq_misordered; | 1768 | status = nfserr_seq_misordered; |
1713 | goto out; | 1769 | goto out; |
1714 | } | 1770 | } |
1715 | |||
1716 | confirm_me = true; | 1771 | confirm_me = true; |
1717 | conf = unconf; | 1772 | conf = unconf; |
1718 | } else { | 1773 | } else { |
@@ -1749,8 +1804,14 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1749 | 1804 | ||
1750 | /* cache solo and embedded create sessions under the state lock */ | 1805 | /* cache solo and embedded create sessions under the state lock */ |
1751 | nfsd4_cache_create_session(cr_ses, cs_slot, status); | 1806 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1752 | if (confirm_me) | 1807 | if (confirm_me) { |
1808 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
1809 | struct nfs4_client *old = | ||
1810 | find_confirmed_client_by_str(conf->cl_recdir, hash); | ||
1811 | if (old) | ||
1812 | expire_client(old); | ||
1753 | move_to_confirmed(conf); | 1813 | move_to_confirmed(conf); |
1814 | } | ||
1754 | out: | 1815 | out: |
1755 | nfs4_unlock_state(); | 1816 | nfs4_unlock_state(); |
1756 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1817 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1818,7 +1879,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1818 | struct nfsd4_destroy_session *sessionid) | 1879 | struct nfsd4_destroy_session *sessionid) |
1819 | { | 1880 | { |
1820 | struct nfsd4_session *ses; | 1881 | struct nfsd4_session *ses; |
1821 | u32 status = nfserr_badsession; | 1882 | __be32 status = nfserr_badsession; |
1822 | 1883 | ||
1823 | /* Notes: | 1884 | /* Notes: |
1824 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1885 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
@@ -1914,7 +1975,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1914 | struct nfsd4_session *session; | 1975 | struct nfsd4_session *session; |
1915 | struct nfsd4_slot *slot; | 1976 | struct nfsd4_slot *slot; |
1916 | struct nfsd4_conn *conn; | 1977 | struct nfsd4_conn *conn; |
1917 | int status; | 1978 | __be32 status; |
1918 | 1979 | ||
1919 | if (resp->opcnt != 1) | 1980 | if (resp->opcnt != 1) |
1920 | return nfserr_sequence_pos; | 1981 | return nfserr_sequence_pos; |
@@ -2008,18 +2069,11 @@ out: | |||
2008 | return status; | 2069 | return status; |
2009 | } | 2070 | } |
2010 | 2071 | ||
2011 | static inline bool has_resources(struct nfs4_client *clp) | ||
2012 | { | ||
2013 | return !list_empty(&clp->cl_openowners) | ||
2014 | || !list_empty(&clp->cl_delegations) | ||
2015 | || !list_empty(&clp->cl_sessions); | ||
2016 | } | ||
2017 | |||
2018 | __be32 | 2072 | __be32 |
2019 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) | 2073 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) |
2020 | { | 2074 | { |
2021 | struct nfs4_client *conf, *unconf, *clp; | 2075 | struct nfs4_client *conf, *unconf, *clp; |
2022 | int status = 0; | 2076 | __be32 status = 0; |
2023 | 2077 | ||
2024 | nfs4_lock_state(); | 2078 | nfs4_lock_state(); |
2025 | unconf = find_unconfirmed_client(&dc->clientid); | 2079 | unconf = find_unconfirmed_client(&dc->clientid); |
@@ -2028,7 +2082,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2028 | if (conf) { | 2082 | if (conf) { |
2029 | clp = conf; | 2083 | clp = conf; |
2030 | 2084 | ||
2031 | if (!is_client_expired(conf) && has_resources(conf)) { | 2085 | if (!is_client_expired(conf) && client_has_state(conf)) { |
2032 | status = nfserr_clientid_busy; | 2086 | status = nfserr_clientid_busy; |
2033 | goto out; | 2087 | goto out; |
2034 | } | 2088 | } |
@@ -2055,7 +2109,7 @@ out: | |||
2055 | __be32 | 2109 | __be32 |
2056 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 2110 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
2057 | { | 2111 | { |
2058 | int status = 0; | 2112 | __be32 status = 0; |
2059 | 2113 | ||
2060 | if (rc->rca_one_fs) { | 2114 | if (rc->rca_one_fs) { |
2061 | if (!cstate->current_fh.fh_dentry) | 2115 | if (!cstate->current_fh.fh_dentry) |
@@ -2106,17 +2160,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2106 | if (status) | 2160 | if (status) |
2107 | return status; | 2161 | return status; |
2108 | 2162 | ||
2109 | /* | ||
2110 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2111 | * We get here on a DRC miss. | ||
2112 | */ | ||
2113 | |||
2114 | strhashval = clientstr_hashval(dname); | 2163 | strhashval = clientstr_hashval(dname); |
2115 | 2164 | ||
2165 | /* Cases below refer to rfc 3530 section 14.2.33: */ | ||
2116 | nfs4_lock_state(); | 2166 | nfs4_lock_state(); |
2117 | conf = find_confirmed_client_by_str(dname, strhashval); | 2167 | conf = find_confirmed_client_by_str(dname, strhashval); |
2118 | if (conf) { | 2168 | if (conf) { |
2119 | /* RFC 3530 14.2.33 CASE 0: */ | 2169 | /* case 0: */ |
2120 | status = nfserr_clid_inuse; | 2170 | status = nfserr_clid_inuse; |
2121 | if (clp_used_exchangeid(conf)) | 2171 | if (clp_used_exchangeid(conf)) |
2122 | goto out; | 2172 | goto out; |
@@ -2129,63 +2179,18 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2129 | goto out; | 2179 | goto out; |
2130 | } | 2180 | } |
2131 | } | 2181 | } |
2132 | /* | ||
2133 | * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") | ||
2134 | * has a description of SETCLIENTID request processing consisting | ||
2135 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | ||
2136 | */ | ||
2137 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2182 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
2183 | if (unconf) | ||
2184 | expire_client(unconf); | ||
2138 | status = nfserr_jukebox; | 2185 | status = nfserr_jukebox; |
2139 | if (!conf) { | 2186 | new = create_client(clname, dname, rqstp, &clverifier); |
2140 | /* | 2187 | if (new == NULL) |
2141 | * RFC 3530 14.2.33 CASE 4: | 2188 | goto out; |
2142 | * placed first, because it is the normal case | 2189 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) |
2143 | */ | 2190 | /* case 1: probable callback update */ |
2144 | if (unconf) | ||
2145 | expire_client(unconf); | ||
2146 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2147 | if (new == NULL) | ||
2148 | goto out; | ||
2149 | gen_clid(new); | ||
2150 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { | ||
2151 | /* | ||
2152 | * RFC 3530 14.2.33 CASE 1: | ||
2153 | * probable callback update | ||
2154 | */ | ||
2155 | if (unconf) { | ||
2156 | /* Note this is removing unconfirmed {*x***}, | ||
2157 | * which is stronger than RFC recommended {vxc**}. | ||
2158 | * This has the advantage that there is at most | ||
2159 | * one {*x***} in either list at any time. | ||
2160 | */ | ||
2161 | expire_client(unconf); | ||
2162 | } | ||
2163 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2164 | if (new == NULL) | ||
2165 | goto out; | ||
2166 | copy_clid(new, conf); | 2191 | copy_clid(new, conf); |
2167 | } else if (!unconf) { | 2192 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ |
2168 | /* | ||
2169 | * RFC 3530 14.2.33 CASE 2: | ||
2170 | * probable client reboot; state will be removed if | ||
2171 | * confirmed. | ||
2172 | */ | ||
2173 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2174 | if (new == NULL) | ||
2175 | goto out; | ||
2176 | gen_clid(new); | ||
2177 | } else { | ||
2178 | /* | ||
2179 | * RFC 3530 14.2.33 CASE 3: | ||
2180 | * probable client reboot; state will be removed if | ||
2181 | * confirmed. | ||
2182 | */ | ||
2183 | expire_client(unconf); | ||
2184 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2185 | if (new == NULL) | ||
2186 | goto out; | ||
2187 | gen_clid(new); | 2193 | gen_clid(new); |
2188 | } | ||
2189 | /* | 2194 | /* |
2190 | * XXX: we should probably set this at creation time, and check | 2195 | * XXX: we should probably set this at creation time, and check |
2191 | * for consistent minorversion use throughout: | 2196 | * for consistent minorversion use throughout: |
@@ -2203,17 +2208,11 @@ out: | |||
2203 | } | 2208 | } |
2204 | 2209 | ||
2205 | 2210 | ||
2206 | /* | ||
2207 | * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has | ||
2208 | * a description of SETCLIENTID_CONFIRM request processing consisting of 4 | ||
2209 | * bullets, labeled as CASE1 - CASE4 below. | ||
2210 | */ | ||
2211 | __be32 | 2211 | __be32 |
2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | 2212 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, |
2213 | struct nfsd4_compound_state *cstate, | 2213 | struct nfsd4_compound_state *cstate, |
2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 2214 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
2215 | { | 2215 | { |
2216 | struct sockaddr *sa = svc_addr(rqstp); | ||
2217 | struct nfs4_client *conf, *unconf; | 2216 | struct nfs4_client *conf, *unconf; |
2218 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2217 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
2219 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2218 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
@@ -2221,84 +2220,44 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
2221 | 2220 | ||
2222 | if (STALE_CLIENTID(clid)) | 2221 | if (STALE_CLIENTID(clid)) |
2223 | return nfserr_stale_clientid; | 2222 | return nfserr_stale_clientid; |
2224 | /* | ||
2225 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2226 | * We get here on a DRC miss. | ||
2227 | */ | ||
2228 | |||
2229 | nfs4_lock_state(); | 2223 | nfs4_lock_state(); |
2230 | 2224 | ||
2231 | conf = find_confirmed_client(clid); | 2225 | conf = find_confirmed_client(clid); |
2232 | unconf = find_unconfirmed_client(clid); | 2226 | unconf = find_unconfirmed_client(clid); |
2233 | |||
2234 | status = nfserr_clid_inuse; | ||
2235 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) | ||
2236 | goto out; | ||
2237 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) | ||
2238 | goto out; | ||
2239 | |||
2240 | /* | 2227 | /* |
2241 | * section 14.2.34 of RFC 3530 has a description of | 2228 | * We try hard to give out unique clientid's, so if we get an |
2242 | * SETCLIENTID_CONFIRM request processing consisting | 2229 | * attempt to confirm the same clientid with a different cred, |
2243 | * of 4 bullet points, labeled as CASE1 - CASE4 below. | 2230 | * there's a bug somewhere. Let's charitably assume it's our |
2231 | * bug. | ||
2244 | */ | 2232 | */ |
2245 | if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { | 2233 | status = nfserr_serverfault; |
2246 | /* | 2234 | if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) |
2247 | * RFC 3530 14.2.34 CASE 1: | 2235 | goto out; |
2248 | * callback update | 2236 | if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) |
2249 | */ | 2237 | goto out; |
2250 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2238 | /* cases below refer to rfc 3530 section 14.2.34: */ |
2251 | status = nfserr_clid_inuse; | 2239 | if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { |
2252 | else { | 2240 | if (conf && !unconf) /* case 2: probable retransmit */ |
2253 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2254 | nfsd4_probe_callback(conf); | ||
2255 | expire_client(unconf); | ||
2256 | status = nfs_ok; | 2241 | status = nfs_ok; |
2242 | else /* case 4: client hasn't noticed we rebooted yet? */ | ||
2243 | status = nfserr_stale_clientid; | ||
2244 | goto out; | ||
2245 | } | ||
2246 | status = nfs_ok; | ||
2247 | if (conf) { /* case 1: callback update */ | ||
2248 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2249 | nfsd4_probe_callback(conf); | ||
2250 | expire_client(unconf); | ||
2251 | } else { /* case 3: normal case; new or rebooted client */ | ||
2252 | unsigned int hash = clientstr_hashval(unconf->cl_recdir); | ||
2257 | 2253 | ||
2254 | conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); | ||
2255 | if (conf) { | ||
2256 | nfsd4_client_record_remove(conf); | ||
2257 | expire_client(conf); | ||
2258 | } | 2258 | } |
2259 | } else if (conf && !unconf) { | 2259 | move_to_confirmed(unconf); |
2260 | /* | 2260 | nfsd4_probe_callback(unconf); |
2261 | * RFC 3530 14.2.34 CASE 2: | ||
2262 | * probable retransmitted request; play it safe and | ||
2263 | * do nothing. | ||
2264 | */ | ||
2265 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) | ||
2266 | status = nfserr_clid_inuse; | ||
2267 | else | ||
2268 | status = nfs_ok; | ||
2269 | } else if (!conf && unconf | ||
2270 | && same_verf(&unconf->cl_confirm, &confirm)) { | ||
2271 | /* | ||
2272 | * RFC 3530 14.2.34 CASE 3: | ||
2273 | * Normal case; new or rebooted client: | ||
2274 | */ | ||
2275 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | ||
2276 | status = nfserr_clid_inuse; | ||
2277 | } else { | ||
2278 | unsigned int hash = | ||
2279 | clientstr_hashval(unconf->cl_recdir); | ||
2280 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
2281 | hash); | ||
2282 | if (conf) { | ||
2283 | nfsd4_client_record_remove(conf); | ||
2284 | expire_client(conf); | ||
2285 | } | ||
2286 | move_to_confirmed(unconf); | ||
2287 | conf = unconf; | ||
2288 | nfsd4_probe_callback(conf); | ||
2289 | status = nfs_ok; | ||
2290 | } | ||
2291 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | ||
2292 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, | ||
2293 | &confirm)))) { | ||
2294 | /* | ||
2295 | * RFC 3530 14.2.34 CASE 4: | ||
2296 | * Client probably hasn't noticed that we rebooted yet. | ||
2297 | */ | ||
2298 | status = nfserr_stale_clientid; | ||
2299 | } else { | ||
2300 | /* check that we have hit one of the cases...*/ | ||
2301 | status = nfserr_clid_inuse; | ||
2302 | } | 2261 | } |
2303 | out: | 2262 | out: |
2304 | nfs4_unlock_state(); | 2263 | nfs4_unlock_state(); |
@@ -2454,8 +2413,8 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
2454 | stp->st_file = fp; | 2413 | stp->st_file = fp; |
2455 | stp->st_access_bmap = 0; | 2414 | stp->st_access_bmap = 0; |
2456 | stp->st_deny_bmap = 0; | 2415 | stp->st_deny_bmap = 0; |
2457 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2416 | set_access(open->op_share_access, stp); |
2458 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2417 | set_deny(open->op_share_deny, stp); |
2459 | stp->st_openstp = NULL; | 2418 | stp->st_openstp = NULL; |
2460 | } | 2419 | } |
2461 | 2420 | ||
@@ -2534,8 +2493,8 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
2534 | ret = nfserr_locked; | 2493 | ret = nfserr_locked; |
2535 | /* Search for conflicting share reservations */ | 2494 | /* Search for conflicting share reservations */ |
2536 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { | 2495 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
2537 | if (test_bit(deny_type, &stp->st_deny_bmap) || | 2496 | if (test_deny(deny_type, stp) || |
2538 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) | 2497 | test_deny(NFS4_SHARE_DENY_BOTH, stp)) |
2539 | goto out; | 2498 | goto out; |
2540 | } | 2499 | } |
2541 | ret = nfs_ok; | 2500 | ret = nfs_ok; |
@@ -2791,7 +2750,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2791 | bool new_access; | 2750 | bool new_access; |
2792 | __be32 status; | 2751 | __be32 status; |
2793 | 2752 | ||
2794 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); | 2753 | new_access = !test_access(op_share_access, stp); |
2795 | if (new_access) { | 2754 | if (new_access) { |
2796 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | 2755 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
2797 | if (status) | 2756 | if (status) |
@@ -2806,8 +2765,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2806 | return status; | 2765 | return status; |
2807 | } | 2766 | } |
2808 | /* remember the open */ | 2767 | /* remember the open */ |
2809 | __set_bit(op_share_access, &stp->st_access_bmap); | 2768 | set_access(op_share_access, stp); |
2810 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2769 | set_deny(open->op_share_deny, stp); |
2811 | 2770 | ||
2812 | return nfs_ok; | 2771 | return nfs_ok; |
2813 | } | 2772 | } |
@@ -3282,18 +3241,18 @@ STALE_STATEID(stateid_t *stateid) | |||
3282 | } | 3241 | } |
3283 | 3242 | ||
3284 | static inline int | 3243 | static inline int |
3285 | access_permit_read(unsigned long access_bmap) | 3244 | access_permit_read(struct nfs4_ol_stateid *stp) |
3286 | { | 3245 | { |
3287 | return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || | 3246 | return test_access(NFS4_SHARE_ACCESS_READ, stp) || |
3288 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || | 3247 | test_access(NFS4_SHARE_ACCESS_BOTH, stp) || |
3289 | test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap); | 3248 | test_access(NFS4_SHARE_ACCESS_WRITE, stp); |
3290 | } | 3249 | } |
3291 | 3250 | ||
3292 | static inline int | 3251 | static inline int |
3293 | access_permit_write(unsigned long access_bmap) | 3252 | access_permit_write(struct nfs4_ol_stateid *stp) |
3294 | { | 3253 | { |
3295 | return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || | 3254 | return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || |
3296 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); | 3255 | test_access(NFS4_SHARE_ACCESS_BOTH, stp); |
3297 | } | 3256 | } |
3298 | 3257 | ||
3299 | static | 3258 | static |
@@ -3304,9 +3263,9 @@ __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) | |||
3304 | /* For lock stateid's, we test the parent open, not the lock: */ | 3263 | /* For lock stateid's, we test the parent open, not the lock: */ |
3305 | if (stp->st_openstp) | 3264 | if (stp->st_openstp) |
3306 | stp = stp->st_openstp; | 3265 | stp = stp->st_openstp; |
3307 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 3266 | if ((flags & WR_STATE) && !access_permit_write(stp)) |
3308 | goto out; | 3267 | goto out; |
3309 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 3268 | if ((flags & RD_STATE) && !access_permit_read(stp)) |
3310 | goto out; | 3269 | goto out; |
3311 | status = nfs_ok; | 3270 | status = nfs_ok; |
3312 | out: | 3271 | out: |
@@ -3346,7 +3305,7 @@ static bool stateid_generation_after(stateid_t *a, stateid_t *b) | |||
3346 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3305 | return (s32)a->si_generation - (s32)b->si_generation > 0; |
3347 | } | 3306 | } |
3348 | 3307 | ||
3349 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3308 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
3350 | { | 3309 | { |
3351 | /* | 3310 | /* |
3352 | * When sessions are used the stateid generation number is ignored | 3311 | * When sessions are used the stateid generation number is ignored |
@@ -3655,10 +3614,10 @@ out: | |||
3655 | 3614 | ||
3656 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) | 3615 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) |
3657 | { | 3616 | { |
3658 | if (!test_bit(access, &stp->st_access_bmap)) | 3617 | if (!test_access(access, stp)) |
3659 | return; | 3618 | return; |
3660 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); | 3619 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); |
3661 | __clear_bit(access, &stp->st_access_bmap); | 3620 | clear_access(access, stp); |
3662 | } | 3621 | } |
3663 | 3622 | ||
3664 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) | 3623 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) |
@@ -3680,12 +3639,12 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac | |||
3680 | } | 3639 | } |
3681 | 3640 | ||
3682 | static void | 3641 | static void |
3683 | reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) | 3642 | reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp) |
3684 | { | 3643 | { |
3685 | int i; | 3644 | int i; |
3686 | for (i = 0; i < 4; i++) { | 3645 | for (i = 0; i < 4; i++) { |
3687 | if ((i & deny) != i) | 3646 | if ((i & deny) != i) |
3688 | __clear_bit(i, bmap); | 3647 | clear_deny(i, stp); |
3689 | } | 3648 | } |
3690 | } | 3649 | } |
3691 | 3650 | ||
@@ -3712,19 +3671,19 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3712 | if (status) | 3671 | if (status) |
3713 | goto out; | 3672 | goto out; |
3714 | status = nfserr_inval; | 3673 | status = nfserr_inval; |
3715 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { | 3674 | if (!test_access(od->od_share_access, stp)) { |
3716 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", | 3675 | dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n", |
3717 | stp->st_access_bmap, od->od_share_access); | 3676 | stp->st_access_bmap, od->od_share_access); |
3718 | goto out; | 3677 | goto out; |
3719 | } | 3678 | } |
3720 | if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { | 3679 | if (!test_deny(od->od_share_deny, stp)) { |
3721 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", | 3680 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", |
3722 | stp->st_deny_bmap, od->od_share_deny); | 3681 | stp->st_deny_bmap, od->od_share_deny); |
3723 | goto out; | 3682 | goto out; |
3724 | } | 3683 | } |
3725 | nfs4_stateid_downgrade(stp, od->od_share_access); | 3684 | nfs4_stateid_downgrade(stp, od->od_share_access); |
3726 | 3685 | ||
3727 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3686 | reset_union_bmap_deny(od->od_share_deny, stp); |
3728 | 3687 | ||
3729 | update_stateid(&stp->st_stid.sc_stateid); | 3688 | update_stateid(&stp->st_stid.sc_stateid); |
3730 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3689 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
@@ -4014,13 +3973,13 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | |||
4014 | struct nfs4_file *fp = lock_stp->st_file; | 3973 | struct nfs4_file *fp = lock_stp->st_file; |
4015 | int oflag = nfs4_access_to_omode(access); | 3974 | int oflag = nfs4_access_to_omode(access); |
4016 | 3975 | ||
4017 | if (test_bit(access, &lock_stp->st_access_bmap)) | 3976 | if (test_access(access, lock_stp)) |
4018 | return; | 3977 | return; |
4019 | nfs4_file_get_access(fp, oflag); | 3978 | nfs4_file_get_access(fp, oflag); |
4020 | __set_bit(access, &lock_stp->st_access_bmap); | 3979 | set_access(access, lock_stp); |
4021 | } | 3980 | } |
4022 | 3981 | ||
4023 | __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | 3982 | static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) |
4024 | { | 3983 | { |
4025 | struct nfs4_file *fi = ost->st_file; | 3984 | struct nfs4_file *fi = ost->st_file; |
4026 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | 3985 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 74c00bc92b9a..4949667c84ea 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1674,12 +1674,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1674 | 1674 | ||
1675 | static void write32(__be32 **p, u32 n) | 1675 | static void write32(__be32 **p, u32 n) |
1676 | { | 1676 | { |
1677 | *(*p)++ = n; | 1677 | *(*p)++ = htonl(n); |
1678 | } | 1678 | } |
1679 | 1679 | ||
1680 | static void write64(__be32 **p, u64 n) | 1680 | static void write64(__be32 **p, u64 n) |
1681 | { | 1681 | { |
1682 | write32(p, (u32)(n >> 32)); | 1682 | write32(p, (n >> 32)); |
1683 | write32(p, (u32)n); | 1683 | write32(p, (u32)n); |
1684 | } | 1684 | } |
1685 | 1685 | ||
@@ -1744,15 +1744,16 @@ static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, _ | |||
1744 | } | 1744 | } |
1745 | 1745 | ||
1746 | /* Encode as an array of strings the string given with components | 1746 | /* Encode as an array of strings the string given with components |
1747 | * separated @sep. | 1747 | * separated @sep, escaped with esc_enter and esc_exit. |
1748 | */ | 1748 | */ |
1749 | static __be32 nfsd4_encode_components(char sep, char *components, | 1749 | static __be32 nfsd4_encode_components_esc(char sep, char *components, |
1750 | __be32 **pp, int *buflen) | 1750 | __be32 **pp, int *buflen, |
1751 | char esc_enter, char esc_exit) | ||
1751 | { | 1752 | { |
1752 | __be32 *p = *pp; | 1753 | __be32 *p = *pp; |
1753 | __be32 *countp = p; | 1754 | __be32 *countp = p; |
1754 | int strlen, count=0; | 1755 | int strlen, count=0; |
1755 | char *str, *end; | 1756 | char *str, *end, *next; |
1756 | 1757 | ||
1757 | dprintk("nfsd4_encode_components(%s)\n", components); | 1758 | dprintk("nfsd4_encode_components(%s)\n", components); |
1758 | if ((*buflen -= 4) < 0) | 1759 | if ((*buflen -= 4) < 0) |
@@ -1760,8 +1761,23 @@ static __be32 nfsd4_encode_components(char sep, char *components, | |||
1760 | WRITE32(0); /* We will fill this in with @count later */ | 1761 | WRITE32(0); /* We will fill this in with @count later */ |
1761 | end = str = components; | 1762 | end = str = components; |
1762 | while (*end) { | 1763 | while (*end) { |
1763 | for (; *end && (*end != sep); end++) | 1764 | bool found_esc = false; |
1764 | ; /* Point to end of component */ | 1765 | |
1766 | /* try to parse as esc_start, ..., esc_end, sep */ | ||
1767 | if (*str == esc_enter) { | ||
1768 | for (; *end && (*end != esc_exit); end++) | ||
1769 | /* find esc_exit or end of string */; | ||
1770 | next = end + 1; | ||
1771 | if (*end && (!*next || *next == sep)) { | ||
1772 | str++; | ||
1773 | found_esc = true; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | if (!found_esc) | ||
1778 | for (; *end && (*end != sep); end++) | ||
1779 | /* find sep or end of string */; | ||
1780 | |||
1765 | strlen = end - str; | 1781 | strlen = end - str; |
1766 | if (strlen) { | 1782 | if (strlen) { |
1767 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) | 1783 | if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0) |
@@ -1780,6 +1796,15 @@ static __be32 nfsd4_encode_components(char sep, char *components, | |||
1780 | return 0; | 1796 | return 0; |
1781 | } | 1797 | } |
1782 | 1798 | ||
1799 | /* Encode as an array of strings the string given with components | ||
1800 | * separated @sep. | ||
1801 | */ | ||
1802 | static __be32 nfsd4_encode_components(char sep, char *components, | ||
1803 | __be32 **pp, int *buflen) | ||
1804 | { | ||
1805 | return nfsd4_encode_components_esc(sep, components, pp, buflen, 0, 0); | ||
1806 | } | ||
1807 | |||
1783 | /* | 1808 | /* |
1784 | * encode a location element of a fs_locations structure | 1809 | * encode a location element of a fs_locations structure |
1785 | */ | 1810 | */ |
@@ -1789,7 +1814,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, | |||
1789 | __be32 status; | 1814 | __be32 status; |
1790 | __be32 *p = *pp; | 1815 | __be32 *p = *pp; |
1791 | 1816 | ||
1792 | status = nfsd4_encode_components(':', location->hosts, &p, buflen); | 1817 | status = nfsd4_encode_components_esc(':', location->hosts, &p, buflen, |
1818 | '[', ']'); | ||
1793 | if (status) | 1819 | if (status) |
1794 | return status; | 1820 | return status; |
1795 | status = nfsd4_encode_components('/', location->path, &p, buflen); | 1821 | status = nfsd4_encode_components('/', location->path, &p, buflen); |
@@ -3251,7 +3277,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3251 | } | 3277 | } |
3252 | 3278 | ||
3253 | static __be32 | 3279 | static __be32 |
3254 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 3280 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3255 | struct nfsd4_exchange_id *exid) | 3281 | struct nfsd4_exchange_id *exid) |
3256 | { | 3282 | { |
3257 | __be32 *p; | 3283 | __be32 *p; |
@@ -3306,7 +3332,7 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | |||
3306 | } | 3332 | } |
3307 | 3333 | ||
3308 | static __be32 | 3334 | static __be32 |
3309 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 3335 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, |
3310 | struct nfsd4_create_session *sess) | 3336 | struct nfsd4_create_session *sess) |
3311 | { | 3337 | { |
3312 | __be32 *p; | 3338 | __be32 *p; |
@@ -3355,14 +3381,14 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | |||
3355 | } | 3381 | } |
3356 | 3382 | ||
3357 | static __be32 | 3383 | static __be32 |
3358 | nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, | 3384 | nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr, |
3359 | struct nfsd4_destroy_session *destroy_session) | 3385 | struct nfsd4_destroy_session *destroy_session) |
3360 | { | 3386 | { |
3361 | return nfserr; | 3387 | return nfserr; |
3362 | } | 3388 | } |
3363 | 3389 | ||
3364 | static __be32 | 3390 | static __be32 |
3365 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3391 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, |
3366 | struct nfsd4_free_stateid *free_stateid) | 3392 | struct nfsd4_free_stateid *free_stateid) |
3367 | { | 3393 | { |
3368 | __be32 *p; | 3394 | __be32 *p; |
@@ -3371,13 +3397,13 @@ nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | |||
3371 | return nfserr; | 3397 | return nfserr; |
3372 | 3398 | ||
3373 | RESERVE_SPACE(4); | 3399 | RESERVE_SPACE(4); |
3374 | WRITE32(nfserr); | 3400 | *p++ = nfserr; |
3375 | ADJUST_ARGS(); | 3401 | ADJUST_ARGS(); |
3376 | return nfserr; | 3402 | return nfserr; |
3377 | } | 3403 | } |
3378 | 3404 | ||
3379 | static __be32 | 3405 | static __be32 |
3380 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3406 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, |
3381 | struct nfsd4_sequence *seq) | 3407 | struct nfsd4_sequence *seq) |
3382 | { | 3408 | { |
3383 | __be32 *p; | 3409 | __be32 *p; |
@@ -3399,8 +3425,8 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3399 | return 0; | 3425 | return 0; |
3400 | } | 3426 | } |
3401 | 3427 | ||
3402 | __be32 | 3428 | static __be32 |
3403 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, | 3429 | nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, |
3404 | struct nfsd4_test_stateid *test_stateid) | 3430 | struct nfsd4_test_stateid *test_stateid) |
3405 | { | 3431 | { |
3406 | struct nfsd4_test_stateid_id *stateid, *next; | 3432 | struct nfsd4_test_stateid_id *stateid, *next; |
@@ -3503,7 +3529,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3503 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | 3529 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so |
3504 | * will be at least a page and will therefore hold the xdr_buf head. | 3530 | * will be at least a page and will therefore hold the xdr_buf head. |
3505 | */ | 3531 | */ |
3506 | int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) | 3532 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) |
3507 | { | 3533 | { |
3508 | struct xdr_buf *xb = &resp->rqstp->rq_res; | 3534 | struct xdr_buf *xb = &resp->rqstp->rq_res; |
3509 | struct nfsd4_session *session = NULL; | 3535 | struct nfsd4_session *session = NULL; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 72699885ac48..c55298ed5772 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -661,6 +661,7 @@ static ssize_t __write_ports_addfd(char *buf) | |||
661 | { | 661 | { |
662 | char *mesg = buf; | 662 | char *mesg = buf; |
663 | int fd, err; | 663 | int fd, err; |
664 | struct net *net = &init_net; | ||
664 | 665 | ||
665 | err = get_int(&mesg, &fd); | 666 | err = get_int(&mesg, &fd); |
666 | if (err != 0 || fd < 0) | 667 | if (err != 0 || fd < 0) |
@@ -672,6 +673,8 @@ static ssize_t __write_ports_addfd(char *buf) | |||
672 | 673 | ||
673 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); | 674 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
674 | if (err < 0) { | 675 | if (err < 0) { |
676 | if (nfsd_serv->sv_nrthreads == 1) | ||
677 | svc_shutdown_net(nfsd_serv, net); | ||
675 | svc_destroy(nfsd_serv); | 678 | svc_destroy(nfsd_serv); |
676 | return err; | 679 | return err; |
677 | } | 680 | } |
@@ -709,6 +712,7 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
709 | char transport[16]; | 712 | char transport[16]; |
710 | struct svc_xprt *xprt; | 713 | struct svc_xprt *xprt; |
711 | int port, err; | 714 | int port, err; |
715 | struct net *net = &init_net; | ||
712 | 716 | ||
713 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) | 717 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
714 | return -EINVAL; | 718 | return -EINVAL; |
@@ -720,12 +724,12 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
720 | if (err != 0) | 724 | if (err != 0) |
721 | return err; | 725 | return err; |
722 | 726 | ||
723 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 727 | err = svc_create_xprt(nfsd_serv, transport, net, |
724 | PF_INET, port, SVC_SOCK_ANONYMOUS); | 728 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
725 | if (err < 0) | 729 | if (err < 0) |
726 | goto out_err; | 730 | goto out_err; |
727 | 731 | ||
728 | err = svc_create_xprt(nfsd_serv, transport, &init_net, | 732 | err = svc_create_xprt(nfsd_serv, transport, net, |
729 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 733 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
730 | if (err < 0 && err != -EAFNOSUPPORT) | 734 | if (err < 0 && err != -EAFNOSUPPORT) |
731 | goto out_close; | 735 | goto out_close; |
@@ -734,12 +738,14 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
734 | nfsd_serv->sv_nrthreads--; | 738 | nfsd_serv->sv_nrthreads--; |
735 | return 0; | 739 | return 0; |
736 | out_close: | 740 | out_close: |
737 | xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port); | 741 | xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port); |
738 | if (xprt != NULL) { | 742 | if (xprt != NULL) { |
739 | svc_close_xprt(xprt); | 743 | svc_close_xprt(xprt); |
740 | svc_xprt_put(xprt); | 744 | svc_xprt_put(xprt); |
741 | } | 745 | } |
742 | out_err: | 746 | out_err: |
747 | if (nfsd_serv->sv_nrthreads == 1) | ||
748 | svc_shutdown_net(nfsd_serv, net); | ||
743 | svc_destroy(nfsd_serv); | 749 | svc_destroy(nfsd_serv); |
744 | return err; | 750 | return err; |
745 | } | 751 | } |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cb4d51d8cbdb..ee709fc8f58b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
13 | #include <linux/swap.h> | 13 | #include <linux/swap.h> |
14 | #include <linux/nsproxy.h> | ||
14 | 15 | ||
15 | #include <linux/sunrpc/stats.h> | 16 | #include <linux/sunrpc/stats.h> |
16 | #include <linux/sunrpc/svcsock.h> | 17 | #include <linux/sunrpc/svcsock.h> |
@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void) | |||
330 | 331 | ||
331 | int nfsd_create_serv(void) | 332 | int nfsd_create_serv(void) |
332 | { | 333 | { |
334 | int error; | ||
335 | |||
333 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 336 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
334 | if (nfsd_serv) { | 337 | if (nfsd_serv) { |
335 | svc_get(nfsd_serv); | 338 | svc_get(nfsd_serv); |
@@ -343,6 +346,12 @@ int nfsd_create_serv(void) | |||
343 | if (nfsd_serv == NULL) | 346 | if (nfsd_serv == NULL) |
344 | return -ENOMEM; | 347 | return -ENOMEM; |
345 | 348 | ||
349 | error = svc_bind(nfsd_serv, current->nsproxy->net_ns); | ||
350 | if (error < 0) { | ||
351 | svc_destroy(nfsd_serv); | ||
352 | return error; | ||
353 | } | ||
354 | |||
346 | set_max_drc(); | 355 | set_max_drc(); |
347 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 356 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
348 | return 0; | 357 | return 0; |
@@ -373,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
373 | int i = 0; | 382 | int i = 0; |
374 | int tot = 0; | 383 | int tot = 0; |
375 | int err = 0; | 384 | int err = 0; |
385 | struct net *net = &init_net; | ||
376 | 386 | ||
377 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 387 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
378 | 388 | ||
@@ -417,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
417 | if (err) | 427 | if (err) |
418 | break; | 428 | break; |
419 | } | 429 | } |
430 | |||
431 | if (nfsd_serv->sv_nrthreads == 1) | ||
432 | svc_shutdown_net(nfsd_serv, net); | ||
420 | svc_destroy(nfsd_serv); | 433 | svc_destroy(nfsd_serv); |
421 | 434 | ||
422 | return err; | 435 | return err; |
@@ -432,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs) | |||
432 | { | 445 | { |
433 | int error; | 446 | int error; |
434 | bool nfsd_up_before; | 447 | bool nfsd_up_before; |
448 | struct net *net = &init_net; | ||
435 | 449 | ||
436 | mutex_lock(&nfsd_mutex); | 450 | mutex_lock(&nfsd_mutex); |
437 | dprintk("nfsd: creating service\n"); | 451 | dprintk("nfsd: creating service\n"); |
@@ -464,6 +478,8 @@ out_shutdown: | |||
464 | if (error < 0 && !nfsd_up_before) | 478 | if (error < 0 && !nfsd_up_before) |
465 | nfsd_shutdown(); | 479 | nfsd_shutdown(); |
466 | out_destroy: | 480 | out_destroy: |
481 | if (nfsd_serv->sv_nrthreads == 1) | ||
482 | svc_shutdown_net(nfsd_serv, net); | ||
467 | svc_destroy(nfsd_serv); /* Release server */ | 483 | svc_destroy(nfsd_serv); /* Release server */ |
468 | out: | 484 | out: |
469 | mutex_unlock(&nfsd_mutex); | 485 | mutex_unlock(&nfsd_mutex); |
@@ -547,6 +563,9 @@ nfsd(void *vrqstp) | |||
547 | nfsdstats.th_cnt --; | 563 | nfsdstats.th_cnt --; |
548 | 564 | ||
549 | out: | 565 | out: |
566 | if (rqstp->rq_server->sv_nrthreads == 1) | ||
567 | svc_shutdown_net(rqstp->rq_server, &init_net); | ||
568 | |||
550 | /* Release the thread */ | 569 | /* Release the thread */ |
551 | svc_exit_thread(rqstp); | 570 | svc_exit_thread(rqstp); |
552 | 571 | ||
@@ -659,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) | |||
659 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) | 678 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) |
660 | { | 679 | { |
661 | int ret = seq_release(inode, file); | 680 | int ret = seq_release(inode, file); |
681 | struct net *net = &init_net; | ||
682 | |||
662 | mutex_lock(&nfsd_mutex); | 683 | mutex_lock(&nfsd_mutex); |
663 | /* this function really, really should have been called svc_put() */ | 684 | /* this function really, really should have been called svc_put() */ |
685 | if (nfsd_serv->sv_nrthreads == 1) | ||
686 | svc_shutdown_net(nfsd_serv, net); | ||
664 | svc_destroy(nfsd_serv); | 687 | svc_destroy(nfsd_serv); |
665 | mutex_unlock(&nfsd_mutex); | 688 | mutex_unlock(&nfsd_mutex); |
666 | return ret; | 689 | return ret; |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 89ab137d379a..849091e16ea6 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -232,7 +232,6 @@ struct nfs4_client { | |||
232 | time_t cl_time; /* time of last lease renewal */ | 232 | time_t cl_time; /* time of last lease renewal */ |
233 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 233 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
234 | u32 cl_flavor; /* setclientid pseudoflavor */ | 234 | u32 cl_flavor; /* setclientid pseudoflavor */ |
235 | char *cl_principal; /* setclientid principal name */ | ||
236 | struct svc_cred cl_cred; /* setclientid principal */ | 235 | struct svc_cred cl_cred; /* setclientid principal */ |
237 | clientid_t cl_clientid; /* generated by server */ | 236 | clientid_t cl_clientid; /* generated by server */ |
238 | nfs4_verifier cl_confirm; /* generated by server */ | 237 | nfs4_verifier cl_confirm; /* generated by server */ |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1b3501598ab5..acd127d4ee82 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -60,7 +60,7 @@ struct nfsd4_compound_state { | |||
60 | __be32 *datap; | 60 | __be32 *datap; |
61 | size_t iovlen; | 61 | size_t iovlen; |
62 | u32 minorversion; | 62 | u32 minorversion; |
63 | u32 status; | 63 | __be32 status; |
64 | stateid_t current_stateid; | 64 | stateid_t current_stateid; |
65 | stateid_t save_stateid; | 65 | stateid_t save_stateid; |
66 | /* to indicate current and saved state id presents */ | 66 | /* to indicate current and saved state id presents */ |
@@ -364,7 +364,7 @@ struct nfsd4_test_stateid_id { | |||
364 | }; | 364 | }; |
365 | 365 | ||
366 | struct nfsd4_test_stateid { | 366 | struct nfsd4_test_stateid { |
367 | __be32 ts_num_ids; | 367 | u32 ts_num_ids; |
368 | struct list_head ts_stateid_list; | 368 | struct list_head ts_stateid_list; |
369 | }; | 369 | }; |
370 | 370 | ||
@@ -549,7 +549,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, | |||
549 | struct nfsd4_compoundargs *); | 549 | struct nfsd4_compoundargs *); |
550 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, | 550 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, |
551 | struct nfsd4_compoundres *); | 551 | struct nfsd4_compoundres *); |
552 | int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); | 552 | __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); |
553 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); | 553 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); |
554 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); | 554 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); |
555 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 555 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 51b29ac45a8e..40e0a273faea 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -232,7 +232,6 @@ struct svc_rqst { | |||
232 | struct svc_pool * rq_pool; /* thread pool */ | 232 | struct svc_pool * rq_pool; /* thread pool */ |
233 | struct svc_procedure * rq_procinfo; /* procedure info */ | 233 | struct svc_procedure * rq_procinfo; /* procedure info */ |
234 | struct auth_ops * rq_authop; /* authentication flavour */ | 234 | struct auth_ops * rq_authop; /* authentication flavour */ |
235 | u32 rq_flavor; /* pseudoflavor */ | ||
236 | struct svc_cred rq_cred; /* auth info */ | 235 | struct svc_cred rq_cred; /* auth info */ |
237 | void * rq_xprt_ctxt; /* transport specific context ptr */ | 236 | void * rq_xprt_ctxt; /* transport specific context ptr */ |
238 | struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ | 237 | struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ |
@@ -416,6 +415,7 @@ struct svc_procedure { | |||
416 | */ | 415 | */ |
417 | int svc_rpcb_setup(struct svc_serv *serv, struct net *net); | 416 | int svc_rpcb_setup(struct svc_serv *serv, struct net *net); |
418 | void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); | 417 | void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); |
418 | int svc_bind(struct svc_serv *serv, struct net *net); | ||
419 | struct svc_serv *svc_create(struct svc_program *, unsigned int, | 419 | struct svc_serv *svc_create(struct svc_program *, unsigned int, |
420 | void (*shutdown)(struct svc_serv *, struct net *net)); | 420 | void (*shutdown)(struct svc_serv *, struct net *net)); |
421 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, | 421 | struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, |
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 2c54683b91de..dd74084a9799 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h | |||
@@ -15,13 +15,23 @@ | |||
15 | #include <linux/sunrpc/msg_prot.h> | 15 | #include <linux/sunrpc/msg_prot.h> |
16 | #include <linux/sunrpc/cache.h> | 16 | #include <linux/sunrpc/cache.h> |
17 | #include <linux/hash.h> | 17 | #include <linux/hash.h> |
18 | #include <linux/cred.h> | ||
18 | 19 | ||
19 | struct svc_cred { | 20 | struct svc_cred { |
20 | uid_t cr_uid; | 21 | uid_t cr_uid; |
21 | gid_t cr_gid; | 22 | gid_t cr_gid; |
22 | struct group_info *cr_group_info; | 23 | struct group_info *cr_group_info; |
24 | u32 cr_flavor; /* pseudoflavor */ | ||
25 | char *cr_principal; /* for gss */ | ||
23 | }; | 26 | }; |
24 | 27 | ||
28 | static inline void free_svc_cred(struct svc_cred *cred) | ||
29 | { | ||
30 | if (cred->cr_group_info) | ||
31 | put_group_info(cred->cr_group_info); | ||
32 | kfree(cred->cr_principal); | ||
33 | } | ||
34 | |||
25 | struct svc_rqst; /* forward decl */ | 35 | struct svc_rqst; /* forward decl */ |
26 | struct in6_addr; | 36 | struct in6_addr; |
27 | 37 | ||
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h index 7c32daa025eb..726aff1a5201 100644 --- a/include/linux/sunrpc/svcauth_gss.h +++ b/include/linux/sunrpc/svcauth_gss.h | |||
@@ -22,7 +22,6 @@ int gss_svc_init_net(struct net *net); | |||
22 | void gss_svc_shutdown_net(struct net *net); | 22 | void gss_svc_shutdown_net(struct net *net); |
23 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); | 23 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); |
24 | u32 svcauth_gss_flavor(struct auth_domain *dom); | 24 | u32 svcauth_gss_flavor(struct auth_domain *dom); |
25 | char *svc_gss_principal(struct svc_rqst *); | ||
26 | 25 | ||
27 | #endif /* __KERNEL__ */ | 26 | #endif /* __KERNEL__ */ |
28 | #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ | 27 | #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ |
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 38f388c39dce..107c4528654f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
@@ -381,21 +381,53 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
381 | } | 381 | } |
382 | 382 | ||
383 | /* | 383 | /* |
384 | * We cannot currently handle tokens with rotated data. We need a | 384 | * We can shift data by up to LOCAL_BUF_LEN bytes in a pass. If we need |
385 | * generalized routine to rotate the data in place. It is anticipated | 385 | * to do more than that, we shift repeatedly. Kevin Coffman reports |
386 | * that we won't encounter rotated data in the general case. | 386 | * seeing 28 bytes as the value used by Microsoft clients and servers |
387 | * with AES, so this constant is chosen to allow handling 28 in one pass | ||
388 | * without using too much stack space. | ||
389 | * | ||
390 | * If that proves to a problem perhaps we could use a more clever | ||
391 | * algorithm. | ||
387 | */ | 392 | */ |
388 | static u32 | 393 | #define LOCAL_BUF_LEN 32u |
389 | rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc) | 394 | |
395 | static void rotate_buf_a_little(struct xdr_buf *buf, unsigned int shift) | ||
390 | { | 396 | { |
391 | unsigned int realrrc = rrc % (buf->len - offset - GSS_KRB5_TOK_HDR_LEN); | 397 | char head[LOCAL_BUF_LEN]; |
398 | char tmp[LOCAL_BUF_LEN]; | ||
399 | unsigned int this_len, i; | ||
400 | |||
401 | BUG_ON(shift > LOCAL_BUF_LEN); | ||
392 | 402 | ||
393 | if (realrrc == 0) | 403 | read_bytes_from_xdr_buf(buf, 0, head, shift); |
394 | return 0; | 404 | for (i = 0; i + shift < buf->len; i += LOCAL_BUF_LEN) { |
405 | this_len = min(LOCAL_BUF_LEN, buf->len - (i + shift)); | ||
406 | read_bytes_from_xdr_buf(buf, i+shift, tmp, this_len); | ||
407 | write_bytes_to_xdr_buf(buf, i, tmp, this_len); | ||
408 | } | ||
409 | write_bytes_to_xdr_buf(buf, buf->len - shift, head, shift); | ||
410 | } | ||
395 | 411 | ||
396 | dprintk("%s: cannot process token with rotated data: " | 412 | static void _rotate_left(struct xdr_buf *buf, unsigned int shift) |
397 | "rrc %u, realrrc %u\n", __func__, rrc, realrrc); | 413 | { |
398 | return 1; | 414 | int shifted = 0; |
415 | int this_shift; | ||
416 | |||
417 | shift %= buf->len; | ||
418 | while (shifted < shift) { | ||
419 | this_shift = min(shift - shifted, LOCAL_BUF_LEN); | ||
420 | rotate_buf_a_little(buf, this_shift); | ||
421 | shifted += this_shift; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | static void rotate_left(u32 base, struct xdr_buf *buf, unsigned int shift) | ||
426 | { | ||
427 | struct xdr_buf subbuf; | ||
428 | |||
429 | xdr_buf_subsegment(buf, &subbuf, base, buf->len - base); | ||
430 | _rotate_left(&subbuf, shift); | ||
399 | } | 431 | } |
400 | 432 | ||
401 | static u32 | 433 | static u32 |
@@ -495,11 +527,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | |||
495 | 527 | ||
496 | seqnum = be64_to_cpup((__be64 *)(ptr + 8)); | 528 | seqnum = be64_to_cpup((__be64 *)(ptr + 8)); |
497 | 529 | ||
498 | if (rrc != 0) { | 530 | if (rrc != 0) |
499 | err = rotate_left(kctx, offset, buf, rrc); | 531 | rotate_left(offset + 16, buf, rrc); |
500 | if (err) | ||
501 | return GSS_S_FAILURE; | ||
502 | } | ||
503 | 532 | ||
504 | err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf, | 533 | err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf, |
505 | &headskip, &tailskip); | 534 | &headskip, &tailskip); |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 3089de37c433..73e957386600 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -336,7 +336,6 @@ struct rsc { | |||
336 | struct svc_cred cred; | 336 | struct svc_cred cred; |
337 | struct gss_svc_seq_data seqdata; | 337 | struct gss_svc_seq_data seqdata; |
338 | struct gss_ctx *mechctx; | 338 | struct gss_ctx *mechctx; |
339 | char *client_name; | ||
340 | }; | 339 | }; |
341 | 340 | ||
342 | static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old); | 341 | static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old); |
@@ -347,9 +346,7 @@ static void rsc_free(struct rsc *rsci) | |||
347 | kfree(rsci->handle.data); | 346 | kfree(rsci->handle.data); |
348 | if (rsci->mechctx) | 347 | if (rsci->mechctx) |
349 | gss_delete_sec_context(&rsci->mechctx); | 348 | gss_delete_sec_context(&rsci->mechctx); |
350 | if (rsci->cred.cr_group_info) | 349 | free_svc_cred(&rsci->cred); |
351 | put_group_info(rsci->cred.cr_group_info); | ||
352 | kfree(rsci->client_name); | ||
353 | } | 350 | } |
354 | 351 | ||
355 | static void rsc_put(struct kref *ref) | 352 | static void rsc_put(struct kref *ref) |
@@ -387,7 +384,7 @@ rsc_init(struct cache_head *cnew, struct cache_head *ctmp) | |||
387 | tmp->handle.data = NULL; | 384 | tmp->handle.data = NULL; |
388 | new->mechctx = NULL; | 385 | new->mechctx = NULL; |
389 | new->cred.cr_group_info = NULL; | 386 | new->cred.cr_group_info = NULL; |
390 | new->client_name = NULL; | 387 | new->cred.cr_principal = NULL; |
391 | } | 388 | } |
392 | 389 | ||
393 | static void | 390 | static void |
@@ -402,8 +399,8 @@ update_rsc(struct cache_head *cnew, struct cache_head *ctmp) | |||
402 | spin_lock_init(&new->seqdata.sd_lock); | 399 | spin_lock_init(&new->seqdata.sd_lock); |
403 | new->cred = tmp->cred; | 400 | new->cred = tmp->cred; |
404 | tmp->cred.cr_group_info = NULL; | 401 | tmp->cred.cr_group_info = NULL; |
405 | new->client_name = tmp->client_name; | 402 | new->cred.cr_principal = tmp->cred.cr_principal; |
406 | tmp->client_name = NULL; | 403 | tmp->cred.cr_principal = NULL; |
407 | } | 404 | } |
408 | 405 | ||
409 | static struct cache_head * | 406 | static struct cache_head * |
@@ -501,8 +498,8 @@ static int rsc_parse(struct cache_detail *cd, | |||
501 | /* get client name */ | 498 | /* get client name */ |
502 | len = qword_get(&mesg, buf, mlen); | 499 | len = qword_get(&mesg, buf, mlen); |
503 | if (len > 0) { | 500 | if (len > 0) { |
504 | rsci.client_name = kstrdup(buf, GFP_KERNEL); | 501 | rsci.cred.cr_principal = kstrdup(buf, GFP_KERNEL); |
505 | if (!rsci.client_name) | 502 | if (!rsci.cred.cr_principal) |
506 | goto out; | 503 | goto out; |
507 | } | 504 | } |
508 | 505 | ||
@@ -932,16 +929,6 @@ struct gss_svc_data { | |||
932 | struct rsc *rsci; | 929 | struct rsc *rsci; |
933 | }; | 930 | }; |
934 | 931 | ||
935 | char *svc_gss_principal(struct svc_rqst *rqstp) | ||
936 | { | ||
937 | struct gss_svc_data *gd = (struct gss_svc_data *)rqstp->rq_auth_data; | ||
938 | |||
939 | if (gd && gd->rsci) | ||
940 | return gd->rsci->client_name; | ||
941 | return NULL; | ||
942 | } | ||
943 | EXPORT_SYMBOL_GPL(svc_gss_principal); | ||
944 | |||
945 | static int | 932 | static int |
946 | svcauth_gss_set_client(struct svc_rqst *rqstp) | 933 | svcauth_gss_set_client(struct svc_rqst *rqstp) |
947 | { | 934 | { |
@@ -1220,7 +1207,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
1220 | } | 1207 | } |
1221 | svcdata->rsci = rsci; | 1208 | svcdata->rsci = rsci; |
1222 | cache_get(&rsci->h); | 1209 | cache_get(&rsci->h); |
1223 | rqstp->rq_flavor = gss_svc_to_pseudoflavor( | 1210 | rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor( |
1224 | rsci->mechctx->mech_type, gc->gc_svc); | 1211 | rsci->mechctx->mech_type, gc->gc_svc); |
1225 | ret = SVC_OK; | 1212 | ret = SVC_OK; |
1226 | goto out; | 1213 | goto out; |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 3c0653439f3d..92509ffe15fc 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -180,14 +180,16 @@ void rpcb_put_local(struct net *net) | |||
180 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 180 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
181 | struct rpc_clnt *clnt = sn->rpcb_local_clnt; | 181 | struct rpc_clnt *clnt = sn->rpcb_local_clnt; |
182 | struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; | 182 | struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; |
183 | int shutdown; | 183 | int shutdown = 0; |
184 | 184 | ||
185 | spin_lock(&sn->rpcb_clnt_lock); | 185 | spin_lock(&sn->rpcb_clnt_lock); |
186 | if (--sn->rpcb_users == 0) { | 186 | if (sn->rpcb_users) { |
187 | sn->rpcb_local_clnt = NULL; | 187 | if (--sn->rpcb_users == 0) { |
188 | sn->rpcb_local_clnt4 = NULL; | 188 | sn->rpcb_local_clnt = NULL; |
189 | sn->rpcb_local_clnt4 = NULL; | ||
190 | } | ||
191 | shutdown = !sn->rpcb_users; | ||
189 | } | 192 | } |
190 | shutdown = !sn->rpcb_users; | ||
191 | spin_unlock(&sn->rpcb_clnt_lock); | 193 | spin_unlock(&sn->rpcb_clnt_lock); |
192 | 194 | ||
193 | if (shutdown) { | 195 | if (shutdown) { |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 017c0117d154..7e9baaa1e543 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -407,6 +407,14 @@ static int svc_uses_rpcbind(struct svc_serv *serv) | |||
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | 409 | ||
410 | int svc_bind(struct svc_serv *serv, struct net *net) | ||
411 | { | ||
412 | if (!svc_uses_rpcbind(serv)) | ||
413 | return 0; | ||
414 | return svc_rpcb_setup(serv, net); | ||
415 | } | ||
416 | EXPORT_SYMBOL_GPL(svc_bind); | ||
417 | |||
410 | /* | 418 | /* |
411 | * Create an RPC service | 419 | * Create an RPC service |
412 | */ | 420 | */ |
@@ -471,15 +479,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | |||
471 | spin_lock_init(&pool->sp_lock); | 479 | spin_lock_init(&pool->sp_lock); |
472 | } | 480 | } |
473 | 481 | ||
474 | if (svc_uses_rpcbind(serv)) { | 482 | if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown)) |
475 | if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) { | 483 | serv->sv_shutdown = svc_rpcb_cleanup; |
476 | kfree(serv->sv_pools); | ||
477 | kfree(serv); | ||
478 | return NULL; | ||
479 | } | ||
480 | if (!serv->sv_shutdown) | ||
481 | serv->sv_shutdown = svc_rpcb_cleanup; | ||
482 | } | ||
483 | 484 | ||
484 | return serv; | 485 | return serv; |
485 | } | 486 | } |
@@ -536,8 +537,6 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net); | |||
536 | void | 537 | void |
537 | svc_destroy(struct svc_serv *serv) | 538 | svc_destroy(struct svc_serv *serv) |
538 | { | 539 | { |
539 | struct net *net = current->nsproxy->net_ns; | ||
540 | |||
541 | dprintk("svc: svc_destroy(%s, %d)\n", | 540 | dprintk("svc: svc_destroy(%s, %d)\n", |
542 | serv->sv_program->pg_name, | 541 | serv->sv_program->pg_name, |
543 | serv->sv_nrthreads); | 542 | serv->sv_nrthreads); |
@@ -552,8 +551,6 @@ svc_destroy(struct svc_serv *serv) | |||
552 | 551 | ||
553 | del_timer_sync(&serv->sv_temptimer); | 552 | del_timer_sync(&serv->sv_temptimer); |
554 | 553 | ||
555 | svc_shutdown_net(serv, net); | ||
556 | |||
557 | /* | 554 | /* |
558 | * The last user is gone and thus all sockets have to be destroyed to | 555 | * The last user is gone and thus all sockets have to be destroyed to |
559 | * the point. Check this. | 556 | * the point. Check this. |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index b98ee3514912..88f2bf671960 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -598,6 +598,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
598 | 598 | ||
599 | /* now allocate needed pages. If we get a failure, sleep briefly */ | 599 | /* now allocate needed pages. If we get a failure, sleep briefly */ |
600 | pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; | 600 | pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE; |
601 | BUG_ON(pages >= RPCSVC_MAXPAGES); | ||
601 | for (i = 0; i < pages ; i++) | 602 | for (i = 0; i < pages ; i++) |
602 | while (rqstp->rq_pages[i] == NULL) { | 603 | while (rqstp->rq_pages[i] == NULL) { |
603 | struct page *p = alloc_page(GFP_KERNEL); | 604 | struct page *p = alloc_page(GFP_KERNEL); |
@@ -612,7 +613,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
612 | rqstp->rq_pages[i] = p; | 613 | rqstp->rq_pages[i] = p; |
613 | } | 614 | } |
614 | rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */ | 615 | rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */ |
615 | BUG_ON(pages >= RPCSVC_MAXPAGES); | ||
616 | 616 | ||
617 | /* Make arg->head point to first page and arg->pages point to rest */ | 617 | /* Make arg->head point to first page and arg->pages point to rest */ |
618 | arg = &rqstp->rq_arg; | 618 | arg = &rqstp->rq_arg; |
@@ -973,7 +973,7 @@ void svc_close_net(struct svc_serv *serv, struct net *net) | |||
973 | svc_clear_pools(serv, net); | 973 | svc_clear_pools(serv, net); |
974 | /* | 974 | /* |
975 | * At this point the sp_sockets lists will stay empty, since | 975 | * At this point the sp_sockets lists will stay empty, since |
976 | * svc_enqueue will not add new entries without taking the | 976 | * svc_xprt_enqueue will not add new entries without taking the |
977 | * sp_lock and checking XPT_BUSY. | 977 | * sp_lock and checking XPT_BUSY. |
978 | */ | 978 | */ |
979 | svc_clear_list(&serv->sv_tempsocks, net); | 979 | svc_clear_list(&serv->sv_tempsocks, net); |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 6138c925923d..2777fa896645 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -746,6 +746,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
746 | struct svc_cred *cred = &rqstp->rq_cred; | 746 | struct svc_cred *cred = &rqstp->rq_cred; |
747 | 747 | ||
748 | cred->cr_group_info = NULL; | 748 | cred->cr_group_info = NULL; |
749 | cred->cr_principal = NULL; | ||
749 | rqstp->rq_client = NULL; | 750 | rqstp->rq_client = NULL; |
750 | 751 | ||
751 | if (argv->iov_len < 3*4) | 752 | if (argv->iov_len < 3*4) |
@@ -773,7 +774,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
773 | svc_putnl(resv, RPC_AUTH_NULL); | 774 | svc_putnl(resv, RPC_AUTH_NULL); |
774 | svc_putnl(resv, 0); | 775 | svc_putnl(resv, 0); |
775 | 776 | ||
776 | rqstp->rq_flavor = RPC_AUTH_NULL; | 777 | rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL; |
777 | return SVC_OK; | 778 | return SVC_OK; |
778 | } | 779 | } |
779 | 780 | ||
@@ -811,6 +812,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
811 | int len = argv->iov_len; | 812 | int len = argv->iov_len; |
812 | 813 | ||
813 | cred->cr_group_info = NULL; | 814 | cred->cr_group_info = NULL; |
815 | cred->cr_principal = NULL; | ||
814 | rqstp->rq_client = NULL; | 816 | rqstp->rq_client = NULL; |
815 | 817 | ||
816 | if ((len -= 3*4) < 0) | 818 | if ((len -= 3*4) < 0) |
@@ -847,7 +849,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
847 | svc_putnl(resv, RPC_AUTH_NULL); | 849 | svc_putnl(resv, RPC_AUTH_NULL); |
848 | svc_putnl(resv, 0); | 850 | svc_putnl(resv, 0); |
849 | 851 | ||
850 | rqstp->rq_flavor = RPC_AUTH_UNIX; | 852 | rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX; |
851 | return SVC_OK; | 853 | return SVC_OK; |
852 | 854 | ||
853 | badcred: | 855 | badcred: |