diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nfs/nfs4proc.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 1450 |
1 files changed, 1019 insertions, 431 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 089da5b5d20a..5879b23e0c99 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -41,20 +41,25 @@ | |||
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/sunrpc/clnt.h> | 43 | #include <linux/sunrpc/clnt.h> |
44 | #include <linux/sunrpc/gss_api.h> | ||
44 | #include <linux/nfs.h> | 45 | #include <linux/nfs.h> |
45 | #include <linux/nfs4.h> | 46 | #include <linux/nfs4.h> |
46 | #include <linux/nfs_fs.h> | 47 | #include <linux/nfs_fs.h> |
47 | #include <linux/nfs_page.h> | 48 | #include <linux/nfs_page.h> |
49 | #include <linux/nfs_mount.h> | ||
48 | #include <linux/namei.h> | 50 | #include <linux/namei.h> |
49 | #include <linux/mount.h> | 51 | #include <linux/mount.h> |
50 | #include <linux/module.h> | 52 | #include <linux/module.h> |
51 | #include <linux/sunrpc/bc_xprt.h> | 53 | #include <linux/sunrpc/bc_xprt.h> |
54 | #include <linux/xattr.h> | ||
55 | #include <linux/utsname.h> | ||
52 | 56 | ||
53 | #include "nfs4_fs.h" | 57 | #include "nfs4_fs.h" |
54 | #include "delegation.h" | 58 | #include "delegation.h" |
55 | #include "internal.h" | 59 | #include "internal.h" |
56 | #include "iostat.h" | 60 | #include "iostat.h" |
57 | #include "callback.h" | 61 | #include "callback.h" |
62 | #include "pnfs.h" | ||
58 | 63 | ||
59 | #define NFSDBG_FACILITY NFSDBG_PROC | 64 | #define NFSDBG_FACILITY NFSDBG_PROC |
60 | 65 | ||
@@ -68,7 +73,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data); | |||
68 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | 73 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); |
69 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 74 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
70 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 75 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
71 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 76 | static int _nfs4_proc_lookup(struct rpc_clnt *client, struct inode *dir, |
77 | const struct qstr *name, struct nfs_fh *fhandle, | ||
78 | struct nfs_fattr *fattr); | ||
72 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 79 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
73 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 80 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
74 | struct nfs_fattr *fattr, struct iattr *sattr, | 81 | struct nfs_fattr *fattr, struct iattr *sattr, |
@@ -82,6 +89,11 @@ static int nfs4_map_errors(int err) | |||
82 | switch (err) { | 89 | switch (err) { |
83 | case -NFS4ERR_RESOURCE: | 90 | case -NFS4ERR_RESOURCE: |
84 | return -EREMOTEIO; | 91 | return -EREMOTEIO; |
92 | case -NFS4ERR_WRONGSEC: | ||
93 | return -EPERM; | ||
94 | case -NFS4ERR_BADOWNER: | ||
95 | case -NFS4ERR_BADNAME: | ||
96 | return -EINVAL; | ||
85 | default: | 97 | default: |
86 | dprintk("%s could not handle NFSv4 error %d\n", | 98 | dprintk("%s could not handle NFSv4 error %d\n", |
87 | __func__, -err); | 99 | __func__, -err); |
@@ -129,7 +141,8 @@ const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE | |||
129 | | FATTR4_WORD0_MAXREAD | 141 | | FATTR4_WORD0_MAXREAD |
130 | | FATTR4_WORD0_MAXWRITE | 142 | | FATTR4_WORD0_MAXWRITE |
131 | | FATTR4_WORD0_LEASE_TIME, | 143 | | FATTR4_WORD0_LEASE_TIME, |
132 | 0 | 144 | FATTR4_WORD1_TIME_DELTA |
145 | | FATTR4_WORD1_FS_LAYOUT_TYPES | ||
133 | }; | 146 | }; |
134 | 147 | ||
135 | const u32 nfs4_fs_locations_bitmap[2] = { | 148 | const u32 nfs4_fs_locations_bitmap[2] = { |
@@ -237,7 +250,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
237 | /* This is the error handling routine for processes that are allowed | 250 | /* This is the error handling routine for processes that are allowed |
238 | * to sleep. | 251 | * to sleep. |
239 | */ | 252 | */ |
240 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 253 | static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
241 | { | 254 | { |
242 | struct nfs_client *clp = server->nfs_client; | 255 | struct nfs_client *clp = server->nfs_client; |
243 | struct nfs4_state *state = exception->state; | 256 | struct nfs4_state *state = exception->state; |
@@ -252,15 +265,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
252 | case -NFS4ERR_OPENMODE: | 265 | case -NFS4ERR_OPENMODE: |
253 | if (state == NULL) | 266 | if (state == NULL) |
254 | break; | 267 | break; |
255 | nfs4_state_mark_reclaim_nograce(clp, state); | 268 | nfs4_schedule_stateid_recovery(server, state); |
256 | goto do_state_recovery; | 269 | goto wait_on_recovery; |
270 | case -NFS4ERR_EXPIRED: | ||
271 | if (state != NULL) | ||
272 | nfs4_schedule_stateid_recovery(server, state); | ||
257 | case -NFS4ERR_STALE_STATEID: | 273 | case -NFS4ERR_STALE_STATEID: |
258 | if (state == NULL) | ||
259 | break; | ||
260 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
261 | case -NFS4ERR_STALE_CLIENTID: | 274 | case -NFS4ERR_STALE_CLIENTID: |
262 | case -NFS4ERR_EXPIRED: | 275 | nfs4_schedule_lease_recovery(clp); |
263 | goto do_state_recovery; | 276 | goto wait_on_recovery; |
264 | #if defined(CONFIG_NFS_V4_1) | 277 | #if defined(CONFIG_NFS_V4_1) |
265 | case -NFS4ERR_BADSESSION: | 278 | case -NFS4ERR_BADSESSION: |
266 | case -NFS4ERR_BADSLOT: | 279 | case -NFS4ERR_BADSLOT: |
@@ -271,7 +284,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
271 | case -NFS4ERR_SEQ_MISORDERED: | 284 | case -NFS4ERR_SEQ_MISORDERED: |
272 | dprintk("%s ERROR: %d Reset session\n", __func__, | 285 | dprintk("%s ERROR: %d Reset session\n", __func__, |
273 | errorcode); | 286 | errorcode); |
274 | nfs4_schedule_state_recovery(clp); | 287 | nfs4_schedule_session_recovery(clp->cl_session); |
275 | exception->retry = 1; | 288 | exception->retry = 1; |
276 | break; | 289 | break; |
277 | #endif /* defined(CONFIG_NFS_V4_1) */ | 290 | #endif /* defined(CONFIG_NFS_V4_1) */ |
@@ -289,13 +302,26 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
289 | ret = nfs4_delay(server->client, &exception->timeout); | 302 | ret = nfs4_delay(server->client, &exception->timeout); |
290 | if (ret != 0) | 303 | if (ret != 0) |
291 | break; | 304 | break; |
305 | case -NFS4ERR_RETRY_UNCACHED_REP: | ||
292 | case -NFS4ERR_OLD_STATEID: | 306 | case -NFS4ERR_OLD_STATEID: |
293 | exception->retry = 1; | 307 | exception->retry = 1; |
308 | break; | ||
309 | case -NFS4ERR_BADOWNER: | ||
310 | /* The following works around a Linux server bug! */ | ||
311 | case -NFS4ERR_BADNAME: | ||
312 | if (server->caps & NFS_CAP_UIDGID_NOMAP) { | ||
313 | server->caps &= ~NFS_CAP_UIDGID_NOMAP; | ||
314 | exception->retry = 1; | ||
315 | printk(KERN_WARNING "NFS: v4 server %s " | ||
316 | "does not accept raw " | ||
317 | "uid/gids. " | ||
318 | "Reenabling the idmapper.\n", | ||
319 | server->nfs_client->cl_hostname); | ||
320 | } | ||
294 | } | 321 | } |
295 | /* We failed to handle the error */ | 322 | /* We failed to handle the error */ |
296 | return nfs4_map_errors(ret); | 323 | return nfs4_map_errors(ret); |
297 | do_state_recovery: | 324 | wait_on_recovery: |
298 | nfs4_schedule_state_recovery(clp); | ||
299 | ret = nfs4_wait_clnt_recover(clp); | 325 | ret = nfs4_wait_clnt_recover(clp); |
300 | if (ret == 0) | 326 | if (ret == 0) |
301 | exception->retry = 1; | 327 | exception->retry = 1; |
@@ -334,10 +360,12 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
334 | * Must be called while holding tbl->slot_tbl_lock | 360 | * Must be called while holding tbl->slot_tbl_lock |
335 | */ | 361 | */ |
336 | static void | 362 | static void |
337 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | 363 | nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot) |
338 | { | 364 | { |
365 | int free_slotid = free_slot - tbl->slots; | ||
339 | int slotid = free_slotid; | 366 | int slotid = free_slotid; |
340 | 367 | ||
368 | BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE); | ||
341 | /* clear used bit in bitmap */ | 369 | /* clear used bit in bitmap */ |
342 | __clear_bit(slotid, tbl->used_slots); | 370 | __clear_bit(slotid, tbl->used_slots); |
343 | 371 | ||
@@ -354,9 +382,9 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | |||
354 | } | 382 | } |
355 | 383 | ||
356 | /* | 384 | /* |
357 | * Signal state manager thread if session is drained | 385 | * Signal state manager thread if session fore channel is drained |
358 | */ | 386 | */ |
359 | static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | 387 | static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) |
360 | { | 388 | { |
361 | struct rpc_task *task; | 389 | struct rpc_task *task; |
362 | 390 | ||
@@ -370,8 +398,20 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
370 | if (ses->fc_slot_table.highest_used_slotid != -1) | 398 | if (ses->fc_slot_table.highest_used_slotid != -1) |
371 | return; | 399 | return; |
372 | 400 | ||
373 | dprintk("%s COMPLETE: Session Drained\n", __func__); | 401 | dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__); |
374 | complete(&ses->complete); | 402 | complete(&ses->fc_slot_table.complete); |
403 | } | ||
404 | |||
405 | /* | ||
406 | * Signal state manager thread if session back channel is drained | ||
407 | */ | ||
408 | void nfs4_check_drain_bc_complete(struct nfs4_session *ses) | ||
409 | { | ||
410 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) || | ||
411 | ses->bc_slot_table.highest_used_slotid != -1) | ||
412 | return; | ||
413 | dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__); | ||
414 | complete(&ses->bc_slot_table.complete); | ||
375 | } | 415 | } |
376 | 416 | ||
377 | static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | 417 | static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) |
@@ -379,7 +419,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
379 | struct nfs4_slot_table *tbl; | 419 | struct nfs4_slot_table *tbl; |
380 | 420 | ||
381 | tbl = &res->sr_session->fc_slot_table; | 421 | tbl = &res->sr_session->fc_slot_table; |
382 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 422 | if (!res->sr_slot) { |
383 | /* just wake up the next guy waiting since | 423 | /* just wake up the next guy waiting since |
384 | * we may have not consumed a slot after all */ | 424 | * we may have not consumed a slot after all */ |
385 | dprintk("%s: No slot\n", __func__); | 425 | dprintk("%s: No slot\n", __func__); |
@@ -387,17 +427,15 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
387 | } | 427 | } |
388 | 428 | ||
389 | spin_lock(&tbl->slot_tbl_lock); | 429 | spin_lock(&tbl->slot_tbl_lock); |
390 | nfs4_free_slot(tbl, res->sr_slotid); | 430 | nfs4_free_slot(tbl, res->sr_slot); |
391 | nfs41_check_drain_session_complete(res->sr_session); | 431 | nfs4_check_drain_fc_complete(res->sr_session); |
392 | spin_unlock(&tbl->slot_tbl_lock); | 432 | spin_unlock(&tbl->slot_tbl_lock); |
393 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 433 | res->sr_slot = NULL; |
394 | } | 434 | } |
395 | 435 | ||
396 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | 436 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
397 | { | 437 | { |
398 | unsigned long timestamp; | 438 | unsigned long timestamp; |
399 | struct nfs4_slot_table *tbl; | ||
400 | struct nfs4_slot *slot; | ||
401 | struct nfs_client *clp; | 439 | struct nfs_client *clp; |
402 | 440 | ||
403 | /* | 441 | /* |
@@ -409,36 +447,35 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * | |||
409 | if (res->sr_status == 1) | 447 | if (res->sr_status == 1) |
410 | res->sr_status = NFS_OK; | 448 | res->sr_status = NFS_OK; |
411 | 449 | ||
412 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | 450 | /* don't increment the sequence number if the task wasn't sent */ |
413 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 451 | if (!RPC_WAS_SENT(task)) |
414 | goto out; | 452 | goto out; |
415 | 453 | ||
416 | tbl = &res->sr_session->fc_slot_table; | ||
417 | slot = tbl->slots + res->sr_slotid; | ||
418 | |||
419 | /* Check the SEQUENCE operation status */ | 454 | /* Check the SEQUENCE operation status */ |
420 | switch (res->sr_status) { | 455 | switch (res->sr_status) { |
421 | case 0: | 456 | case 0: |
422 | /* Update the slot's sequence and clientid lease timer */ | 457 | /* Update the slot's sequence and clientid lease timer */ |
423 | ++slot->seq_nr; | 458 | ++res->sr_slot->seq_nr; |
424 | timestamp = res->sr_renewal_time; | 459 | timestamp = res->sr_renewal_time; |
425 | clp = res->sr_session->clp; | 460 | clp = res->sr_session->clp; |
426 | do_renew_lease(clp, timestamp); | 461 | do_renew_lease(clp, timestamp); |
427 | /* Check sequence flags */ | 462 | /* Check sequence flags */ |
428 | if (atomic_read(&clp->cl_count) > 1) | 463 | if (res->sr_status_flags != 0) |
429 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 464 | nfs4_schedule_lease_recovery(clp); |
430 | break; | 465 | break; |
431 | case -NFS4ERR_DELAY: | 466 | case -NFS4ERR_DELAY: |
432 | /* The server detected a resend of the RPC call and | 467 | /* The server detected a resend of the RPC call and |
433 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 | 468 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 |
434 | * of RFC5661. | 469 | * of RFC5661. |
435 | */ | 470 | */ |
436 | dprintk("%s: slot=%d seq=%d: Operation in progress\n", | 471 | dprintk("%s: slot=%td seq=%d: Operation in progress\n", |
437 | __func__, res->sr_slotid, slot->seq_nr); | 472 | __func__, |
473 | res->sr_slot - res->sr_session->fc_slot_table.slots, | ||
474 | res->sr_slot->seq_nr); | ||
438 | goto out_retry; | 475 | goto out_retry; |
439 | default: | 476 | default: |
440 | /* Just update the slot sequence no. */ | 477 | /* Just update the slot sequence no. */ |
441 | ++slot->seq_nr; | 478 | ++res->sr_slot->seq_nr; |
442 | } | 479 | } |
443 | out: | 480 | out: |
444 | /* The session may be reset by one of the error handlers. */ | 481 | /* The session may be reset by one of the error handlers. */ |
@@ -493,7 +530,7 @@ out: | |||
493 | return ret_id; | 530 | return ret_id; |
494 | } | 531 | } |
495 | 532 | ||
496 | static int nfs41_setup_sequence(struct nfs4_session *session, | 533 | int nfs41_setup_sequence(struct nfs4_session *session, |
497 | struct nfs4_sequence_args *args, | 534 | struct nfs4_sequence_args *args, |
498 | struct nfs4_sequence_res *res, | 535 | struct nfs4_sequence_res *res, |
499 | int cache_reply, | 536 | int cache_reply, |
@@ -505,10 +542,9 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
505 | 542 | ||
506 | dprintk("--> %s\n", __func__); | 543 | dprintk("--> %s\n", __func__); |
507 | /* slot already allocated? */ | 544 | /* slot already allocated? */ |
508 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | 545 | if (res->sr_slot != NULL) |
509 | return 0; | 546 | return 0; |
510 | 547 | ||
511 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
512 | tbl = &session->fc_slot_table; | 548 | tbl = &session->fc_slot_table; |
513 | 549 | ||
514 | spin_lock(&tbl->slot_tbl_lock); | 550 | spin_lock(&tbl->slot_tbl_lock); |
@@ -550,7 +586,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
550 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | 586 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); |
551 | 587 | ||
552 | res->sr_session = session; | 588 | res->sr_session = session; |
553 | res->sr_slotid = slotid; | 589 | res->sr_slot = slot; |
554 | res->sr_renewal_time = jiffies; | 590 | res->sr_renewal_time = jiffies; |
555 | res->sr_status_flags = 0; | 591 | res->sr_status_flags = 0; |
556 | /* | 592 | /* |
@@ -560,6 +596,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
560 | res->sr_status = 1; | 596 | res->sr_status = 1; |
561 | return 0; | 597 | return 0; |
562 | } | 598 | } |
599 | EXPORT_SYMBOL_GPL(nfs41_setup_sequence); | ||
563 | 600 | ||
564 | int nfs4_setup_sequence(const struct nfs_server *server, | 601 | int nfs4_setup_sequence(const struct nfs_server *server, |
565 | struct nfs4_sequence_args *args, | 602 | struct nfs4_sequence_args *args, |
@@ -576,8 +613,9 @@ int nfs4_setup_sequence(const struct nfs_server *server, | |||
576 | goto out; | 613 | goto out; |
577 | } | 614 | } |
578 | 615 | ||
579 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | 616 | dprintk("--> %s clp %p session %p sr_slot %td\n", |
580 | __func__, session->clp, session, res->sr_slotid); | 617 | __func__, session->clp, session, res->sr_slot ? |
618 | res->sr_slot - session->fc_slot_table.slots : -1); | ||
581 | 619 | ||
582 | ret = nfs41_setup_sequence(session, args, res, cache_reply, | 620 | ret = nfs41_setup_sequence(session, args, res, cache_reply, |
583 | task); | 621 | task); |
@@ -628,7 +666,8 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = { | |||
628 | .rpc_call_done = nfs41_call_sync_done, | 666 | .rpc_call_done = nfs41_call_sync_done, |
629 | }; | 667 | }; |
630 | 668 | ||
631 | static int nfs4_call_sync_sequence(struct nfs_server *server, | 669 | static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, |
670 | struct nfs_server *server, | ||
632 | struct rpc_message *msg, | 671 | struct rpc_message *msg, |
633 | struct nfs4_sequence_args *args, | 672 | struct nfs4_sequence_args *args, |
634 | struct nfs4_sequence_res *res, | 673 | struct nfs4_sequence_res *res, |
@@ -644,13 +683,13 @@ static int nfs4_call_sync_sequence(struct nfs_server *server, | |||
644 | .cache_reply = cache_reply, | 683 | .cache_reply = cache_reply, |
645 | }; | 684 | }; |
646 | struct rpc_task_setup task_setup = { | 685 | struct rpc_task_setup task_setup = { |
647 | .rpc_client = server->client, | 686 | .rpc_client = clnt, |
648 | .rpc_message = msg, | 687 | .rpc_message = msg, |
649 | .callback_ops = &nfs41_call_sync_ops, | 688 | .callback_ops = &nfs41_call_sync_ops, |
650 | .callback_data = &data | 689 | .callback_data = &data |
651 | }; | 690 | }; |
652 | 691 | ||
653 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 692 | res->sr_slot = NULL; |
654 | if (privileged) | 693 | if (privileged) |
655 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | 694 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; |
656 | task = rpc_run_task(&task_setup); | 695 | task = rpc_run_task(&task_setup); |
@@ -663,13 +702,14 @@ static int nfs4_call_sync_sequence(struct nfs_server *server, | |||
663 | return ret; | 702 | return ret; |
664 | } | 703 | } |
665 | 704 | ||
666 | int _nfs4_call_sync_session(struct nfs_server *server, | 705 | int _nfs4_call_sync_session(struct rpc_clnt *clnt, |
706 | struct nfs_server *server, | ||
667 | struct rpc_message *msg, | 707 | struct rpc_message *msg, |
668 | struct nfs4_sequence_args *args, | 708 | struct nfs4_sequence_args *args, |
669 | struct nfs4_sequence_res *res, | 709 | struct nfs4_sequence_res *res, |
670 | int cache_reply) | 710 | int cache_reply) |
671 | { | 711 | { |
672 | return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0); | 712 | return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0); |
673 | } | 713 | } |
674 | 714 | ||
675 | #else | 715 | #else |
@@ -680,19 +720,28 @@ static int nfs4_sequence_done(struct rpc_task *task, | |||
680 | } | 720 | } |
681 | #endif /* CONFIG_NFS_V4_1 */ | 721 | #endif /* CONFIG_NFS_V4_1 */ |
682 | 722 | ||
683 | int _nfs4_call_sync(struct nfs_server *server, | 723 | int _nfs4_call_sync(struct rpc_clnt *clnt, |
724 | struct nfs_server *server, | ||
684 | struct rpc_message *msg, | 725 | struct rpc_message *msg, |
685 | struct nfs4_sequence_args *args, | 726 | struct nfs4_sequence_args *args, |
686 | struct nfs4_sequence_res *res, | 727 | struct nfs4_sequence_res *res, |
687 | int cache_reply) | 728 | int cache_reply) |
688 | { | 729 | { |
689 | args->sa_session = res->sr_session = NULL; | 730 | args->sa_session = res->sr_session = NULL; |
690 | return rpc_call_sync(server->client, msg, 0); | 731 | return rpc_call_sync(clnt, msg, 0); |
691 | } | 732 | } |
692 | 733 | ||
693 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | 734 | static inline |
694 | (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \ | 735 | int nfs4_call_sync(struct rpc_clnt *clnt, |
695 | &(res)->seq_res, (cache_reply)) | 736 | struct nfs_server *server, |
737 | struct rpc_message *msg, | ||
738 | struct nfs4_sequence_args *args, | ||
739 | struct nfs4_sequence_res *res, | ||
740 | int cache_reply) | ||
741 | { | ||
742 | return server->nfs_client->cl_mvops->call_sync(clnt, server, msg, | ||
743 | args, res, cache_reply); | ||
744 | } | ||
696 | 745 | ||
697 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 746 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
698 | { | 747 | { |
@@ -735,7 +784,6 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
735 | p->o_res.server = p->o_arg.server; | 784 | p->o_res.server = p->o_arg.server; |
736 | nfs_fattr_init(&p->f_attr); | 785 | nfs_fattr_init(&p->f_attr); |
737 | nfs_fattr_init(&p->dir_attr); | 786 | nfs_fattr_init(&p->dir_attr); |
738 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
739 | } | 787 | } |
740 | 788 | ||
741 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 789 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
@@ -1120,6 +1168,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1120 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1168 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1121 | smp_rmb(); | 1169 | smp_rmb(); |
1122 | if (state->n_rdwr != 0) { | 1170 | if (state->n_rdwr != 0) { |
1171 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1123 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); | 1172 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); |
1124 | if (ret != 0) | 1173 | if (ret != 0) |
1125 | return ret; | 1174 | return ret; |
@@ -1127,6 +1176,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1127 | return -ESTALE; | 1176 | return -ESTALE; |
1128 | } | 1177 | } |
1129 | if (state->n_wronly != 0) { | 1178 | if (state->n_wronly != 0) { |
1179 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1130 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); | 1180 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); |
1131 | if (ret != 0) | 1181 | if (ret != 0) |
1132 | return ret; | 1182 | return ret; |
@@ -1134,6 +1184,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1134 | return -ESTALE; | 1184 | return -ESTALE; |
1135 | } | 1185 | } |
1136 | if (state->n_rdonly != 0) { | 1186 | if (state->n_rdonly != 0) { |
1187 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1137 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); | 1188 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); |
1138 | if (ret != 0) | 1189 | if (ret != 0) |
1139 | return ret; | 1190 | return ret; |
@@ -1188,7 +1239,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1188 | int err; | 1239 | int err; |
1189 | do { | 1240 | do { |
1190 | err = _nfs4_do_open_reclaim(ctx, state); | 1241 | err = _nfs4_do_open_reclaim(ctx, state); |
1191 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) | 1242 | if (err != -NFS4ERR_DELAY) |
1192 | break; | 1243 | break; |
1193 | nfs4_handle_exception(server, err, &exception); | 1244 | nfs4_handle_exception(server, err, &exception); |
1194 | } while (exception.retry); | 1245 | } while (exception.retry); |
@@ -1241,14 +1292,13 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
1241 | case -NFS4ERR_BAD_HIGH_SLOT: | 1292 | case -NFS4ERR_BAD_HIGH_SLOT: |
1242 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | 1293 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: |
1243 | case -NFS4ERR_DEADSESSION: | 1294 | case -NFS4ERR_DEADSESSION: |
1244 | nfs4_schedule_state_recovery( | 1295 | nfs4_schedule_session_recovery(server->nfs_client->cl_session); |
1245 | server->nfs_client); | ||
1246 | goto out; | 1296 | goto out; |
1247 | case -NFS4ERR_STALE_CLIENTID: | 1297 | case -NFS4ERR_STALE_CLIENTID: |
1248 | case -NFS4ERR_STALE_STATEID: | 1298 | case -NFS4ERR_STALE_STATEID: |
1249 | case -NFS4ERR_EXPIRED: | 1299 | case -NFS4ERR_EXPIRED: |
1250 | /* Don't recall a delegation if it was lost */ | 1300 | /* Don't recall a delegation if it was lost */ |
1251 | nfs4_schedule_state_recovery(server->nfs_client); | 1301 | nfs4_schedule_lease_recovery(server->nfs_client); |
1252 | goto out; | 1302 | goto out; |
1253 | case -ERESTARTSYS: | 1303 | case -ERESTARTSYS: |
1254 | /* | 1304 | /* |
@@ -1257,7 +1307,14 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
1257 | */ | 1307 | */ |
1258 | case -NFS4ERR_ADMIN_REVOKED: | 1308 | case -NFS4ERR_ADMIN_REVOKED: |
1259 | case -NFS4ERR_BAD_STATEID: | 1309 | case -NFS4ERR_BAD_STATEID: |
1260 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | 1310 | nfs4_schedule_stateid_recovery(server, state); |
1311 | case -EKEYEXPIRED: | ||
1312 | /* | ||
1313 | * User RPCSEC_GSS context has expired. | ||
1314 | * We cannot recover this stateid now, so | ||
1315 | * skip it and allow recovery thread to | ||
1316 | * proceed. | ||
1317 | */ | ||
1261 | case -ENOMEM: | 1318 | case -ENOMEM: |
1262 | err = 0; | 1319 | err = 0; |
1263 | goto out; | 1320 | goto out; |
@@ -1553,9 +1610,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1553 | return 0; | 1610 | return 0; |
1554 | } | 1611 | } |
1555 | 1612 | ||
1556 | static int nfs4_recover_expired_lease(struct nfs_server *server) | 1613 | static int nfs4_client_recover_expired_lease(struct nfs_client *clp) |
1557 | { | 1614 | { |
1558 | struct nfs_client *clp = server->nfs_client; | ||
1559 | unsigned int loop; | 1615 | unsigned int loop; |
1560 | int ret; | 1616 | int ret; |
1561 | 1617 | ||
@@ -1566,12 +1622,17 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) | |||
1566 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && | 1622 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) && |
1567 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) | 1623 | !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state)) |
1568 | break; | 1624 | break; |
1569 | nfs4_schedule_state_recovery(clp); | 1625 | nfs4_schedule_state_manager(clp); |
1570 | ret = -EIO; | 1626 | ret = -EIO; |
1571 | } | 1627 | } |
1572 | return ret; | 1628 | return ret; |
1573 | } | 1629 | } |
1574 | 1630 | ||
1631 | static int nfs4_recover_expired_lease(struct nfs_server *server) | ||
1632 | { | ||
1633 | return nfs4_client_recover_expired_lease(server->nfs_client); | ||
1634 | } | ||
1635 | |||
1575 | /* | 1636 | /* |
1576 | * OPEN_EXPIRED: | 1637 | * OPEN_EXPIRED: |
1577 | * reclaim state on the server after a network partition. | 1638 | * reclaim state on the server after a network partition. |
@@ -1605,7 +1666,6 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state | |||
1605 | goto out; | 1666 | goto out; |
1606 | case -NFS4ERR_GRACE: | 1667 | case -NFS4ERR_GRACE: |
1607 | case -NFS4ERR_DELAY: | 1668 | case -NFS4ERR_DELAY: |
1608 | case -EKEYEXPIRED: | ||
1609 | nfs4_handle_exception(server, err, &exception); | 1669 | nfs4_handle_exception(server, err, &exception); |
1610 | err = 0; | 1670 | err = 0; |
1611 | } | 1671 | } |
@@ -1791,7 +1851,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1791 | } else | 1851 | } else |
1792 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1852 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1793 | 1853 | ||
1794 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 1854 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
1795 | if (status == 0 && state != NULL) | 1855 | if (status == 0 && state != NULL) |
1796 | renew_lease(server, timestamp); | 1856 | renew_lease(server, timestamp); |
1797 | return status; | 1857 | return status; |
@@ -1820,6 +1880,8 @@ struct nfs4_closedata { | |||
1820 | struct nfs_closeres res; | 1880 | struct nfs_closeres res; |
1821 | struct nfs_fattr fattr; | 1881 | struct nfs_fattr fattr; |
1822 | unsigned long timestamp; | 1882 | unsigned long timestamp; |
1883 | bool roc; | ||
1884 | u32 roc_barrier; | ||
1823 | }; | 1885 | }; |
1824 | 1886 | ||
1825 | static void nfs4_free_closedata(void *data) | 1887 | static void nfs4_free_closedata(void *data) |
@@ -1827,6 +1889,8 @@ static void nfs4_free_closedata(void *data) | |||
1827 | struct nfs4_closedata *calldata = data; | 1889 | struct nfs4_closedata *calldata = data; |
1828 | struct nfs4_state_owner *sp = calldata->state->owner; | 1890 | struct nfs4_state_owner *sp = calldata->state->owner; |
1829 | 1891 | ||
1892 | if (calldata->roc) | ||
1893 | pnfs_roc_release(calldata->state->inode); | ||
1830 | nfs4_put_open_state(calldata->state); | 1894 | nfs4_put_open_state(calldata->state); |
1831 | nfs_free_seqid(calldata->arg.seqid); | 1895 | nfs_free_seqid(calldata->arg.seqid); |
1832 | nfs4_put_state_owner(sp); | 1896 | nfs4_put_state_owner(sp); |
@@ -1859,6 +1923,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1859 | */ | 1923 | */ |
1860 | switch (task->tk_status) { | 1924 | switch (task->tk_status) { |
1861 | case 0: | 1925 | case 0: |
1926 | if (calldata->roc) | ||
1927 | pnfs_roc_set_barrier(state->inode, | ||
1928 | calldata->roc_barrier); | ||
1862 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1929 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
1863 | renew_lease(server, calldata->timestamp); | 1930 | renew_lease(server, calldata->timestamp); |
1864 | nfs4_close_clear_stateid_flags(state, | 1931 | nfs4_close_clear_stateid_flags(state, |
@@ -1911,8 +1978,15 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1911 | return; | 1978 | return; |
1912 | } | 1979 | } |
1913 | 1980 | ||
1914 | if (calldata->arg.fmode == 0) | 1981 | if (calldata->arg.fmode == 0) { |
1915 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | 1982 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; |
1983 | if (calldata->roc && | ||
1984 | pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) { | ||
1985 | rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq, | ||
1986 | task, NULL); | ||
1987 | return; | ||
1988 | } | ||
1989 | } | ||
1916 | 1990 | ||
1917 | nfs_fattr_init(calldata->res.fattr); | 1991 | nfs_fattr_init(calldata->res.fattr); |
1918 | calldata->timestamp = jiffies; | 1992 | calldata->timestamp = jiffies; |
@@ -1940,7 +2014,7 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
1940 | * | 2014 | * |
1941 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 2015 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
1942 | */ | 2016 | */ |
1943 | int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait) | 2017 | int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc) |
1944 | { | 2018 | { |
1945 | struct nfs_server *server = NFS_SERVER(state->inode); | 2019 | struct nfs_server *server = NFS_SERVER(state->inode); |
1946 | struct nfs4_closedata *calldata; | 2020 | struct nfs4_closedata *calldata; |
@@ -1975,12 +2049,12 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i | |||
1975 | calldata->res.fattr = &calldata->fattr; | 2049 | calldata->res.fattr = &calldata->fattr; |
1976 | calldata->res.seqid = calldata->arg.seqid; | 2050 | calldata->res.seqid = calldata->arg.seqid; |
1977 | calldata->res.server = server; | 2051 | calldata->res.server = server; |
1978 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 2052 | calldata->roc = roc; |
1979 | path_get(path); | 2053 | path_get(path); |
1980 | calldata->path = *path; | 2054 | calldata->path = *path; |
1981 | 2055 | ||
1982 | msg.rpc_argp = &calldata->arg, | 2056 | msg.rpc_argp = &calldata->arg; |
1983 | msg.rpc_resp = &calldata->res, | 2057 | msg.rpc_resp = &calldata->res; |
1984 | task_setup_data.callback_data = calldata; | 2058 | task_setup_data.callback_data = calldata; |
1985 | task = rpc_run_task(&task_setup_data); | 2059 | task = rpc_run_task(&task_setup_data); |
1986 | if (IS_ERR(task)) | 2060 | if (IS_ERR(task)) |
@@ -1993,125 +2067,24 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i | |||
1993 | out_free_calldata: | 2067 | out_free_calldata: |
1994 | kfree(calldata); | 2068 | kfree(calldata); |
1995 | out: | 2069 | out: |
2070 | if (roc) | ||
2071 | pnfs_roc_release(state->inode); | ||
1996 | nfs4_put_open_state(state); | 2072 | nfs4_put_open_state(state); |
1997 | nfs4_put_state_owner(sp); | 2073 | nfs4_put_state_owner(sp); |
1998 | return status; | 2074 | return status; |
1999 | } | 2075 | } |
2000 | 2076 | ||
2001 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode) | 2077 | static struct inode * |
2002 | { | 2078 | nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) |
2003 | struct file *filp; | ||
2004 | int ret; | ||
2005 | |||
2006 | /* If the open_intent is for execute, we have an extra check to make */ | ||
2007 | if (fmode & FMODE_EXEC) { | ||
2008 | ret = nfs_may_open(state->inode, | ||
2009 | state->owner->so_cred, | ||
2010 | nd->intent.open.flags); | ||
2011 | if (ret < 0) | ||
2012 | goto out_close; | ||
2013 | } | ||
2014 | filp = lookup_instantiate_filp(nd, path->dentry, NULL); | ||
2015 | if (!IS_ERR(filp)) { | ||
2016 | struct nfs_open_context *ctx; | ||
2017 | ctx = nfs_file_open_context(filp); | ||
2018 | ctx->state = state; | ||
2019 | return 0; | ||
2020 | } | ||
2021 | ret = PTR_ERR(filp); | ||
2022 | out_close: | ||
2023 | nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE)); | ||
2024 | return ret; | ||
2025 | } | ||
2026 | |||
2027 | struct dentry * | ||
2028 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
2029 | { | 2079 | { |
2030 | struct path path = { | ||
2031 | .mnt = nd->path.mnt, | ||
2032 | .dentry = dentry, | ||
2033 | }; | ||
2034 | struct dentry *parent; | ||
2035 | struct iattr attr; | ||
2036 | struct rpc_cred *cred; | ||
2037 | struct nfs4_state *state; | 2080 | struct nfs4_state *state; |
2038 | struct dentry *res; | ||
2039 | int open_flags = nd->intent.open.flags; | ||
2040 | fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
2041 | |||
2042 | if (nd->flags & LOOKUP_CREATE) { | ||
2043 | attr.ia_mode = nd->intent.open.create_mode; | ||
2044 | attr.ia_valid = ATTR_MODE; | ||
2045 | if (!IS_POSIXACL(dir)) | ||
2046 | attr.ia_mode &= ~current_umask(); | ||
2047 | } else { | ||
2048 | open_flags &= ~O_EXCL; | ||
2049 | attr.ia_valid = 0; | ||
2050 | BUG_ON(open_flags & O_CREAT); | ||
2051 | } | ||
2052 | 2081 | ||
2053 | cred = rpc_lookup_cred(); | ||
2054 | if (IS_ERR(cred)) | ||
2055 | return (struct dentry *)cred; | ||
2056 | parent = dentry->d_parent; | ||
2057 | /* Protect against concurrent sillydeletes */ | 2082 | /* Protect against concurrent sillydeletes */ |
2058 | nfs_block_sillyrename(parent); | 2083 | state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred); |
2059 | state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); | 2084 | if (IS_ERR(state)) |
2060 | put_rpccred(cred); | 2085 | return ERR_CAST(state); |
2061 | if (IS_ERR(state)) { | 2086 | ctx->state = state; |
2062 | if (PTR_ERR(state) == -ENOENT) { | 2087 | return igrab(state->inode); |
2063 | d_add(dentry, NULL); | ||
2064 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
2065 | } | ||
2066 | nfs_unblock_sillyrename(parent); | ||
2067 | return (struct dentry *)state; | ||
2068 | } | ||
2069 | res = d_add_unique(dentry, igrab(state->inode)); | ||
2070 | if (res != NULL) | ||
2071 | path.dentry = res; | ||
2072 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); | ||
2073 | nfs_unblock_sillyrename(parent); | ||
2074 | nfs4_intent_set_file(nd, &path, state, fmode); | ||
2075 | return res; | ||
2076 | } | ||
2077 | |||
2078 | int | ||
2079 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) | ||
2080 | { | ||
2081 | struct path path = { | ||
2082 | .mnt = nd->path.mnt, | ||
2083 | .dentry = dentry, | ||
2084 | }; | ||
2085 | struct rpc_cred *cred; | ||
2086 | struct nfs4_state *state; | ||
2087 | fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE); | ||
2088 | |||
2089 | cred = rpc_lookup_cred(); | ||
2090 | if (IS_ERR(cred)) | ||
2091 | return PTR_ERR(cred); | ||
2092 | state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred); | ||
2093 | put_rpccred(cred); | ||
2094 | if (IS_ERR(state)) { | ||
2095 | switch (PTR_ERR(state)) { | ||
2096 | case -EPERM: | ||
2097 | case -EACCES: | ||
2098 | case -EDQUOT: | ||
2099 | case -ENOSPC: | ||
2100 | case -EROFS: | ||
2101 | return PTR_ERR(state); | ||
2102 | default: | ||
2103 | goto out_drop; | ||
2104 | } | ||
2105 | } | ||
2106 | if (state->inode == dentry->d_inode) { | ||
2107 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
2108 | nfs4_intent_set_file(nd, &path, state, fmode); | ||
2109 | return 1; | ||
2110 | } | ||
2111 | nfs4_close_sync(&path, state, fmode); | ||
2112 | out_drop: | ||
2113 | d_drop(dentry); | ||
2114 | return 0; | ||
2115 | } | 2088 | } |
2116 | 2089 | ||
2117 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | 2090 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) |
@@ -2137,7 +2110,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
2137 | }; | 2110 | }; |
2138 | int status; | 2111 | int status; |
2139 | 2112 | ||
2140 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2113 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2141 | if (status == 0) { | 2114 | if (status == 0) { |
2142 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2115 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
2143 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| | 2116 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| |
@@ -2207,7 +2180,7 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2207 | }; | 2180 | }; |
2208 | 2181 | ||
2209 | nfs_fattr_init(info->fattr); | 2182 | nfs_fattr_init(info->fattr); |
2210 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 2183 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2211 | } | 2184 | } |
2212 | 2185 | ||
2213 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2186 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2216,22 +2189,75 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2216 | struct nfs4_exception exception = { }; | 2189 | struct nfs4_exception exception = { }; |
2217 | int err; | 2190 | int err; |
2218 | do { | 2191 | do { |
2219 | err = nfs4_handle_exception(server, | 2192 | err = _nfs4_lookup_root(server, fhandle, info); |
2220 | _nfs4_lookup_root(server, fhandle, info), | 2193 | switch (err) { |
2221 | &exception); | 2194 | case 0: |
2195 | case -NFS4ERR_WRONGSEC: | ||
2196 | break; | ||
2197 | default: | ||
2198 | err = nfs4_handle_exception(server, err, &exception); | ||
2199 | } | ||
2222 | } while (exception.retry); | 2200 | } while (exception.retry); |
2223 | return err; | 2201 | return err; |
2224 | } | 2202 | } |
2225 | 2203 | ||
2204 | static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | ||
2205 | struct nfs_fsinfo *info, rpc_authflavor_t flavor) | ||
2206 | { | ||
2207 | struct rpc_auth *auth; | ||
2208 | int ret; | ||
2209 | |||
2210 | auth = rpcauth_create(flavor, server->client); | ||
2211 | if (!auth) { | ||
2212 | ret = -EIO; | ||
2213 | goto out; | ||
2214 | } | ||
2215 | ret = nfs4_lookup_root(server, fhandle, info); | ||
2216 | out: | ||
2217 | return ret; | ||
2218 | } | ||
2219 | |||
2220 | static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | ||
2221 | struct nfs_fsinfo *info) | ||
2222 | { | ||
2223 | int i, len, status = 0; | ||
2224 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; | ||
2225 | |||
2226 | len = gss_mech_list_pseudoflavors(&flav_array[0]); | ||
2227 | flav_array[len] = RPC_AUTH_NULL; | ||
2228 | len += 1; | ||
2229 | |||
2230 | for (i = 0; i < len; i++) { | ||
2231 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); | ||
2232 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) | ||
2233 | continue; | ||
2234 | break; | ||
2235 | } | ||
2236 | /* | ||
2237 | * -EACCESS could mean that the user doesn't have correct permissions | ||
2238 | * to access the mount. It could also mean that we tried to mount | ||
2239 | * with a gss auth flavor, but rpc.gssd isn't running. Either way, | ||
2240 | * existing mount programs don't handle -EACCES very well so it should | ||
2241 | * be mapped to -EPERM instead. | ||
2242 | */ | ||
2243 | if (status == -EACCES) | ||
2244 | status = -EPERM; | ||
2245 | return status; | ||
2246 | } | ||
2247 | |||
2226 | /* | 2248 | /* |
2227 | * get the file handle for the "/" directory on the server | 2249 | * get the file handle for the "/" directory on the server |
2228 | */ | 2250 | */ |
2229 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2251 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
2230 | struct nfs_fsinfo *info) | 2252 | struct nfs_fsinfo *info) |
2231 | { | 2253 | { |
2232 | int status; | 2254 | int status = nfs4_lookup_root(server, fhandle, info); |
2233 | 2255 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) | |
2234 | status = nfs4_lookup_root(server, fhandle, info); | 2256 | /* |
2257 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM | ||
2258 | * by nfs4_map_errors() as this function exits. | ||
2259 | */ | ||
2260 | status = nfs4_find_root_sec(server, fhandle, info); | ||
2235 | if (status == 0) | 2261 | if (status == 0) |
2236 | status = nfs4_server_capabilities(server, fhandle); | 2262 | status = nfs4_server_capabilities(server, fhandle); |
2237 | if (status == 0) | 2263 | if (status == 0) |
@@ -2239,12 +2265,14 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2239 | return nfs4_map_errors(status); | 2265 | return nfs4_map_errors(status); |
2240 | } | 2266 | } |
2241 | 2267 | ||
2268 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); | ||
2242 | /* | 2269 | /* |
2243 | * Get locations and (maybe) other attributes of a referral. | 2270 | * Get locations and (maybe) other attributes of a referral. |
2244 | * Note that we'll actually follow the referral later when | 2271 | * Note that we'll actually follow the referral later when |
2245 | * we detect fsid mismatch in inode revalidation | 2272 | * we detect fsid mismatch in inode revalidation |
2246 | */ | 2273 | */ |
2247 | static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle) | 2274 | static int nfs4_get_referral(struct inode *dir, const struct qstr *name, |
2275 | struct nfs_fattr *fattr, struct nfs_fh *fhandle) | ||
2248 | { | 2276 | { |
2249 | int status = -ENOMEM; | 2277 | int status = -ENOMEM; |
2250 | struct page *page = NULL; | 2278 | struct page *page = NULL; |
@@ -2262,15 +2290,16 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct | |||
2262 | goto out; | 2290 | goto out; |
2263 | /* Make sure server returned a different fsid for the referral */ | 2291 | /* Make sure server returned a different fsid for the referral */ |
2264 | if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { | 2292 | if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { |
2265 | dprintk("%s: server did not return a different fsid for a referral at %s\n", __func__, name->name); | 2293 | dprintk("%s: server did not return a different fsid for" |
2294 | " a referral at %s\n", __func__, name->name); | ||
2266 | status = -EIO; | 2295 | status = -EIO; |
2267 | goto out; | 2296 | goto out; |
2268 | } | 2297 | } |
2298 | /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */ | ||
2299 | nfs_fixup_referral_attributes(&locations->fattr); | ||
2269 | 2300 | ||
2301 | /* replace the lookup nfs_fattr with the locations nfs_fattr */ | ||
2270 | memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr)); | 2302 | memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr)); |
2271 | fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL; | ||
2272 | if (!fattr->mode) | ||
2273 | fattr->mode = S_IFDIR; | ||
2274 | memset(fhandle, 0, sizeof(struct nfs_fh)); | 2303 | memset(fhandle, 0, sizeof(struct nfs_fh)); |
2275 | out: | 2304 | out: |
2276 | if (page) | 2305 | if (page) |
@@ -2296,7 +2325,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2296 | }; | 2325 | }; |
2297 | 2326 | ||
2298 | nfs_fattr_init(fattr); | 2327 | nfs_fattr_init(fattr); |
2299 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 2328 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2300 | } | 2329 | } |
2301 | 2330 | ||
2302 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2331 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -2337,6 +2366,9 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
2337 | struct nfs4_state *state = NULL; | 2366 | struct nfs4_state *state = NULL; |
2338 | int status; | 2367 | int status; |
2339 | 2368 | ||
2369 | if (pnfs_ld_layoutret_on_setattr(inode)) | ||
2370 | pnfs_return_layout(inode); | ||
2371 | |||
2340 | nfs_fattr_init(fattr); | 2372 | nfs_fattr_init(fattr); |
2341 | 2373 | ||
2342 | /* Search for an existing open(O_WRITE) file */ | 2374 | /* Search for an existing open(O_WRITE) file */ |
@@ -2356,9 +2388,9 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
2356 | return status; | 2388 | return status; |
2357 | } | 2389 | } |
2358 | 2390 | ||
2359 | static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh, | 2391 | static int _nfs4_proc_lookupfh(struct rpc_clnt *clnt, struct nfs_server *server, |
2360 | const struct qstr *name, struct nfs_fh *fhandle, | 2392 | const struct nfs_fh *dirfh, const struct qstr *name, |
2361 | struct nfs_fattr *fattr) | 2393 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
2362 | { | 2394 | { |
2363 | int status; | 2395 | int status; |
2364 | struct nfs4_lookup_arg args = { | 2396 | struct nfs4_lookup_arg args = { |
@@ -2380,7 +2412,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
2380 | nfs_fattr_init(fattr); | 2412 | nfs_fattr_init(fattr); |
2381 | 2413 | ||
2382 | dprintk("NFS call lookupfh %s\n", name->name); | 2414 | dprintk("NFS call lookupfh %s\n", name->name); |
2383 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2415 | status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0); |
2384 | dprintk("NFS reply lookupfh: %d\n", status); | 2416 | dprintk("NFS reply lookupfh: %d\n", status); |
2385 | return status; | 2417 | return status; |
2386 | } | 2418 | } |
@@ -2392,7 +2424,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
2392 | struct nfs4_exception exception = { }; | 2424 | struct nfs4_exception exception = { }; |
2393 | int err; | 2425 | int err; |
2394 | do { | 2426 | do { |
2395 | err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); | 2427 | err = _nfs4_proc_lookupfh(server->client, server, dirfh, name, fhandle, fattr); |
2396 | /* FIXME: !!!! */ | 2428 | /* FIXME: !!!! */ |
2397 | if (err == -NFS4ERR_MOVED) { | 2429 | if (err == -NFS4ERR_MOVED) { |
2398 | err = -EREMOTE; | 2430 | err = -EREMOTE; |
@@ -2403,27 +2435,41 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
2403 | return err; | 2435 | return err; |
2404 | } | 2436 | } |
2405 | 2437 | ||
2406 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, | 2438 | static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, |
2407 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2439 | const struct qstr *name, struct nfs_fh *fhandle, |
2440 | struct nfs_fattr *fattr) | ||
2408 | { | 2441 | { |
2409 | int status; | 2442 | int status; |
2410 | 2443 | ||
2411 | dprintk("NFS call lookup %s\n", name->name); | 2444 | dprintk("NFS call lookup %s\n", name->name); |
2412 | status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); | 2445 | status = _nfs4_proc_lookupfh(clnt, NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); |
2413 | if (status == -NFS4ERR_MOVED) | 2446 | if (status == -NFS4ERR_MOVED) |
2414 | status = nfs4_get_referral(dir, name, fattr, fhandle); | 2447 | status = nfs4_get_referral(dir, name, fattr, fhandle); |
2415 | dprintk("NFS reply lookup: %d\n", status); | 2448 | dprintk("NFS reply lookup: %d\n", status); |
2416 | return status; | 2449 | return status; |
2417 | } | 2450 | } |
2418 | 2451 | ||
2419 | static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2452 | void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh) |
2453 | { | ||
2454 | memset(fh, 0, sizeof(struct nfs_fh)); | ||
2455 | fattr->fsid.major = 1; | ||
2456 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | | ||
2457 | NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT; | ||
2458 | fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
2459 | fattr->nlink = 2; | ||
2460 | } | ||
2461 | |||
2462 | static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, | ||
2463 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | ||
2420 | { | 2464 | { |
2421 | struct nfs4_exception exception = { }; | 2465 | struct nfs4_exception exception = { }; |
2422 | int err; | 2466 | int err; |
2423 | do { | 2467 | do { |
2424 | err = nfs4_handle_exception(NFS_SERVER(dir), | 2468 | err = nfs4_handle_exception(NFS_SERVER(dir), |
2425 | _nfs4_proc_lookup(dir, name, fhandle, fattr), | 2469 | _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr), |
2426 | &exception); | 2470 | &exception); |
2471 | if (err == -EPERM) | ||
2472 | nfs_fixup_secinfo_attributes(fattr, fhandle); | ||
2427 | } while (exception.retry); | 2473 | } while (exception.retry); |
2428 | return err; | 2474 | return err; |
2429 | } | 2475 | } |
@@ -2468,7 +2514,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
2468 | if (res.fattr == NULL) | 2514 | if (res.fattr == NULL) |
2469 | return -ENOMEM; | 2515 | return -ENOMEM; |
2470 | 2516 | ||
2471 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2517 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2472 | if (!status) { | 2518 | if (!status) { |
2473 | entry->mask = 0; | 2519 | entry->mask = 0; |
2474 | if (res.access & NFS4_ACCESS_READ) | 2520 | if (res.access & NFS4_ACCESS_READ) |
@@ -2535,7 +2581,7 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
2535 | .rpc_resp = &res, | 2581 | .rpc_resp = &res, |
2536 | }; | 2582 | }; |
2537 | 2583 | ||
2538 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); | 2584 | return nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); |
2539 | } | 2585 | } |
2540 | 2586 | ||
2541 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2587 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2568,36 +2614,35 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
2568 | 2614 | ||
2569 | static int | 2615 | static int |
2570 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 2616 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
2571 | int flags, struct nameidata *nd) | 2617 | int flags, struct nfs_open_context *ctx) |
2572 | { | 2618 | { |
2573 | struct path path = { | 2619 | struct path my_path = { |
2574 | .mnt = nd->path.mnt, | ||
2575 | .dentry = dentry, | 2620 | .dentry = dentry, |
2576 | }; | 2621 | }; |
2622 | struct path *path = &my_path; | ||
2577 | struct nfs4_state *state; | 2623 | struct nfs4_state *state; |
2578 | struct rpc_cred *cred; | 2624 | struct rpc_cred *cred = NULL; |
2579 | fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE); | 2625 | fmode_t fmode = 0; |
2580 | int status = 0; | 2626 | int status = 0; |
2581 | 2627 | ||
2582 | cred = rpc_lookup_cred(); | 2628 | if (ctx != NULL) { |
2583 | if (IS_ERR(cred)) { | 2629 | cred = ctx->cred; |
2584 | status = PTR_ERR(cred); | 2630 | path = &ctx->path; |
2585 | goto out; | 2631 | fmode = ctx->mode; |
2586 | } | 2632 | } |
2587 | state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred); | 2633 | sattr->ia_mode &= ~current_umask(); |
2634 | state = nfs4_do_open(dir, path, fmode, flags, sattr, cred); | ||
2588 | d_drop(dentry); | 2635 | d_drop(dentry); |
2589 | if (IS_ERR(state)) { | 2636 | if (IS_ERR(state)) { |
2590 | status = PTR_ERR(state); | 2637 | status = PTR_ERR(state); |
2591 | goto out_putcred; | 2638 | goto out; |
2592 | } | 2639 | } |
2593 | d_add(dentry, igrab(state->inode)); | 2640 | d_add(dentry, igrab(state->inode)); |
2594 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 2641 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
2595 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2642 | if (ctx != NULL) |
2596 | status = nfs4_intent_set_file(nd, &path, state, fmode); | 2643 | ctx->state = state; |
2597 | else | 2644 | else |
2598 | nfs4_close_sync(&path, state, fmode); | 2645 | nfs4_close_sync(path, state, fmode); |
2599 | out_putcred: | ||
2600 | put_rpccred(cred); | ||
2601 | out: | 2646 | out: |
2602 | return status; | 2647 | return status; |
2603 | } | 2648 | } |
@@ -2625,7 +2670,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2625 | if (res.dir_attr == NULL) | 2670 | if (res.dir_attr == NULL) |
2626 | goto out; | 2671 | goto out; |
2627 | 2672 | ||
2628 | status = nfs4_call_sync(server, &msg, &args, &res, 1); | 2673 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); |
2629 | if (status == 0) { | 2674 | if (status == 0) { |
2630 | update_changeattr(dir, &res.cinfo); | 2675 | update_changeattr(dir, &res.cinfo); |
2631 | nfs_post_op_update_inode(dir, res.dir_attr); | 2676 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2655,6 +2700,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
2655 | 2700 | ||
2656 | args->bitmask = server->cache_consistency_bitmask; | 2701 | args->bitmask = server->cache_consistency_bitmask; |
2657 | res->server = server; | 2702 | res->server = server; |
2703 | res->seq_res.sr_slot = NULL; | ||
2658 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; | 2704 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; |
2659 | } | 2705 | } |
2660 | 2706 | ||
@@ -2671,18 +2717,46 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2671 | return 1; | 2717 | return 1; |
2672 | } | 2718 | } |
2673 | 2719 | ||
2720 | static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir) | ||
2721 | { | ||
2722 | struct nfs_server *server = NFS_SERVER(dir); | ||
2723 | struct nfs_renameargs *arg = msg->rpc_argp; | ||
2724 | struct nfs_renameres *res = msg->rpc_resp; | ||
2725 | |||
2726 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME]; | ||
2727 | arg->bitmask = server->attr_bitmask; | ||
2728 | res->server = server; | ||
2729 | } | ||
2730 | |||
2731 | static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | ||
2732 | struct inode *new_dir) | ||
2733 | { | ||
2734 | struct nfs_renameres *res = task->tk_msg.rpc_resp; | ||
2735 | |||
2736 | if (!nfs4_sequence_done(task, &res->seq_res)) | ||
2737 | return 0; | ||
2738 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | ||
2739 | return 0; | ||
2740 | |||
2741 | update_changeattr(old_dir, &res->old_cinfo); | ||
2742 | nfs_post_op_update_inode(old_dir, res->old_fattr); | ||
2743 | update_changeattr(new_dir, &res->new_cinfo); | ||
2744 | nfs_post_op_update_inode(new_dir, res->new_fattr); | ||
2745 | return 1; | ||
2746 | } | ||
2747 | |||
2674 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | 2748 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, |
2675 | struct inode *new_dir, struct qstr *new_name) | 2749 | struct inode *new_dir, struct qstr *new_name) |
2676 | { | 2750 | { |
2677 | struct nfs_server *server = NFS_SERVER(old_dir); | 2751 | struct nfs_server *server = NFS_SERVER(old_dir); |
2678 | struct nfs4_rename_arg arg = { | 2752 | struct nfs_renameargs arg = { |
2679 | .old_dir = NFS_FH(old_dir), | 2753 | .old_dir = NFS_FH(old_dir), |
2680 | .new_dir = NFS_FH(new_dir), | 2754 | .new_dir = NFS_FH(new_dir), |
2681 | .old_name = old_name, | 2755 | .old_name = old_name, |
2682 | .new_name = new_name, | 2756 | .new_name = new_name, |
2683 | .bitmask = server->attr_bitmask, | 2757 | .bitmask = server->attr_bitmask, |
2684 | }; | 2758 | }; |
2685 | struct nfs4_rename_res res = { | 2759 | struct nfs_renameres res = { |
2686 | .server = server, | 2760 | .server = server, |
2687 | }; | 2761 | }; |
2688 | struct rpc_message msg = { | 2762 | struct rpc_message msg = { |
@@ -2697,7 +2771,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2697 | if (res.old_fattr == NULL || res.new_fattr == NULL) | 2771 | if (res.old_fattr == NULL || res.new_fattr == NULL) |
2698 | goto out; | 2772 | goto out; |
2699 | 2773 | ||
2700 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2774 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
2701 | if (!status) { | 2775 | if (!status) { |
2702 | update_changeattr(old_dir, &res.old_cinfo); | 2776 | update_changeattr(old_dir, &res.old_cinfo); |
2703 | nfs_post_op_update_inode(old_dir, res.old_fattr); | 2777 | nfs_post_op_update_inode(old_dir, res.old_fattr); |
@@ -2748,7 +2822,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2748 | if (res.fattr == NULL || res.dir_attr == NULL) | 2822 | if (res.fattr == NULL || res.dir_attr == NULL) |
2749 | goto out; | 2823 | goto out; |
2750 | 2824 | ||
2751 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2825 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
2752 | if (!status) { | 2826 | if (!status) { |
2753 | update_changeattr(dir, &res.cinfo); | 2827 | update_changeattr(dir, &res.cinfo); |
2754 | nfs_post_op_update_inode(dir, res.dir_attr); | 2828 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2811,8 +2885,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2811 | 2885 | ||
2812 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2886 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2813 | { | 2887 | { |
2814 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, | 2888 | int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg, |
2815 | &data->arg, &data->res, 1); | 2889 | &data->arg.seq_args, &data->res.seq_res, 1); |
2816 | if (status == 0) { | 2890 | if (status == 0) { |
2817 | update_changeattr(dir, &data->res.dir_cinfo); | 2891 | update_changeattr(dir, &data->res.dir_cinfo); |
2818 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2892 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2887,6 +2961,8 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
2887 | { | 2961 | { |
2888 | struct nfs4_exception exception = { }; | 2962 | struct nfs4_exception exception = { }; |
2889 | int err; | 2963 | int err; |
2964 | |||
2965 | sattr->ia_mode &= ~current_umask(); | ||
2890 | do { | 2966 | do { |
2891 | err = nfs4_handle_exception(NFS_SERVER(dir), | 2967 | err = nfs4_handle_exception(NFS_SERVER(dir), |
2892 | _nfs4_proc_mkdir(dir, dentry, sattr), | 2968 | _nfs4_proc_mkdir(dir, dentry, sattr), |
@@ -2896,15 +2972,16 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, | |||
2896 | } | 2972 | } |
2897 | 2973 | ||
2898 | static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | 2974 | static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
2899 | u64 cookie, struct page *page, unsigned int count, int plus) | 2975 | u64 cookie, struct page **pages, unsigned int count, int plus) |
2900 | { | 2976 | { |
2901 | struct inode *dir = dentry->d_inode; | 2977 | struct inode *dir = dentry->d_inode; |
2902 | struct nfs4_readdir_arg args = { | 2978 | struct nfs4_readdir_arg args = { |
2903 | .fh = NFS_FH(dir), | 2979 | .fh = NFS_FH(dir), |
2904 | .pages = &page, | 2980 | .pages = pages, |
2905 | .pgbase = 0, | 2981 | .pgbase = 0, |
2906 | .count = count, | 2982 | .count = count, |
2907 | .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, | 2983 | .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, |
2984 | .plus = plus, | ||
2908 | }; | 2985 | }; |
2909 | struct nfs4_readdir_res res; | 2986 | struct nfs4_readdir_res res; |
2910 | struct rpc_message msg = { | 2987 | struct rpc_message msg = { |
@@ -2921,9 +2998,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2921 | (unsigned long long)cookie); | 2998 | (unsigned long long)cookie); |
2922 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2999 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2923 | res.pgbase = args.pgbase; | 3000 | res.pgbase = args.pgbase; |
2924 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); | 3001 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); |
2925 | if (status == 0) | 3002 | if (status >= 0) { |
2926 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 3003 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
3004 | status += args.pgbase; | ||
3005 | } | ||
2927 | 3006 | ||
2928 | nfs_invalidate_atime(dir); | 3007 | nfs_invalidate_atime(dir); |
2929 | 3008 | ||
@@ -2932,14 +3011,14 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2932 | } | 3011 | } |
2933 | 3012 | ||
2934 | static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | 3013 | static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
2935 | u64 cookie, struct page *page, unsigned int count, int plus) | 3014 | u64 cookie, struct page **pages, unsigned int count, int plus) |
2936 | { | 3015 | { |
2937 | struct nfs4_exception exception = { }; | 3016 | struct nfs4_exception exception = { }; |
2938 | int err; | 3017 | int err; |
2939 | do { | 3018 | do { |
2940 | err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), | 3019 | err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), |
2941 | _nfs4_proc_readdir(dentry, cred, cookie, | 3020 | _nfs4_proc_readdir(dentry, cred, cookie, |
2942 | page, count, plus), | 3021 | pages, count, plus), |
2943 | &exception); | 3022 | &exception); |
2944 | } while (exception.retry); | 3023 | } while (exception.retry); |
2945 | return err; | 3024 | return err; |
@@ -2984,6 +3063,8 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, | |||
2984 | { | 3063 | { |
2985 | struct nfs4_exception exception = { }; | 3064 | struct nfs4_exception exception = { }; |
2986 | int err; | 3065 | int err; |
3066 | |||
3067 | sattr->ia_mode &= ~current_umask(); | ||
2987 | do { | 3068 | do { |
2988 | err = nfs4_handle_exception(NFS_SERVER(dir), | 3069 | err = nfs4_handle_exception(NFS_SERVER(dir), |
2989 | _nfs4_proc_mknod(dir, dentry, sattr, rdev), | 3070 | _nfs4_proc_mknod(dir, dentry, sattr, rdev), |
@@ -3009,7 +3090,7 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3009 | }; | 3090 | }; |
3010 | 3091 | ||
3011 | nfs_fattr_init(fsstat->fattr); | 3092 | nfs_fattr_init(fsstat->fattr); |
3012 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 3093 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
3013 | } | 3094 | } |
3014 | 3095 | ||
3015 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 3096 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -3040,7 +3121,7 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3040 | .rpc_resp = &res, | 3121 | .rpc_resp = &res, |
3041 | }; | 3122 | }; |
3042 | 3123 | ||
3043 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 3124 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
3044 | } | 3125 | } |
3045 | 3126 | ||
3046 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 3127 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -3085,7 +3166,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
3085 | } | 3166 | } |
3086 | 3167 | ||
3087 | nfs_fattr_init(pathconf->fattr); | 3168 | nfs_fattr_init(pathconf->fattr); |
3088 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 3169 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
3089 | } | 3170 | } |
3090 | 3171 | ||
3091 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 3172 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -3102,39 +3183,65 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3102 | return err; | 3183 | return err; |
3103 | } | 3184 | } |
3104 | 3185 | ||
3105 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | 3186 | void __nfs4_read_done_cb(struct nfs_read_data *data) |
3106 | { | 3187 | { |
3107 | struct nfs_server *server = NFS_SERVER(data->inode); | 3188 | nfs_invalidate_atime(data->inode); |
3108 | 3189 | } | |
3109 | dprintk("--> %s\n", __func__); | ||
3110 | 3190 | ||
3111 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 3191 | static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data) |
3112 | return -EAGAIN; | 3192 | { |
3193 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
3113 | 3194 | ||
3114 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3195 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
3115 | nfs_restart_rpc(task, server->nfs_client); | 3196 | nfs_restart_rpc(task, server->nfs_client); |
3116 | return -EAGAIN; | 3197 | return -EAGAIN; |
3117 | } | 3198 | } |
3118 | 3199 | ||
3119 | nfs_invalidate_atime(data->inode); | 3200 | __nfs4_read_done_cb(data); |
3120 | if (task->tk_status > 0) | 3201 | if (task->tk_status > 0) |
3121 | renew_lease(server, data->timestamp); | 3202 | renew_lease(server, data->timestamp); |
3122 | return 0; | 3203 | return 0; |
3123 | } | 3204 | } |
3124 | 3205 | ||
3206 | static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | ||
3207 | { | ||
3208 | |||
3209 | dprintk("--> %s\n", __func__); | ||
3210 | |||
3211 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3212 | return -EAGAIN; | ||
3213 | |||
3214 | return data->read_done_cb ? data->read_done_cb(task, data) : | ||
3215 | nfs4_read_done_cb(task, data); | ||
3216 | } | ||
3217 | |||
3125 | static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) | 3218 | static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) |
3126 | { | 3219 | { |
3127 | data->timestamp = jiffies; | 3220 | data->timestamp = jiffies; |
3221 | data->read_done_cb = nfs4_read_done_cb; | ||
3128 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; | 3222 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; |
3129 | } | 3223 | } |
3130 | 3224 | ||
3131 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | 3225 | /* Reset the the nfs_read_data to send the read to the MDS. */ |
3226 | void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data) | ||
3227 | { | ||
3228 | dprintk("%s Reset task for i/o through\n", __func__); | ||
3229 | put_lseg(data->lseg); | ||
3230 | data->lseg = NULL; | ||
3231 | /* offsets will differ in the dense stripe case */ | ||
3232 | data->args.offset = data->mds_offset; | ||
3233 | data->ds_clp = NULL; | ||
3234 | data->args.fh = NFS_FH(data->inode); | ||
3235 | data->read_done_cb = nfs4_read_done_cb; | ||
3236 | task->tk_ops = data->mds_ops; | ||
3237 | rpc_task_reset_client(task, NFS_CLIENT(data->inode)); | ||
3238 | } | ||
3239 | EXPORT_SYMBOL_GPL(nfs4_reset_read); | ||
3240 | |||
3241 | static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data) | ||
3132 | { | 3242 | { |
3133 | struct inode *inode = data->inode; | 3243 | struct inode *inode = data->inode; |
3134 | 3244 | ||
3135 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3136 | return -EAGAIN; | ||
3137 | |||
3138 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3245 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3139 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3246 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3140 | return -EAGAIN; | 3247 | return -EAGAIN; |
@@ -3146,23 +3253,51 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3146 | return 0; | 3253 | return 0; |
3147 | } | 3254 | } |
3148 | 3255 | ||
3256 | static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | ||
3257 | { | ||
3258 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3259 | return -EAGAIN; | ||
3260 | return data->write_done_cb ? data->write_done_cb(task, data) : | ||
3261 | nfs4_write_done_cb(task, data); | ||
3262 | } | ||
3263 | |||
3264 | /* Reset the the nfs_write_data to send the write to the MDS. */ | ||
3265 | void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data) | ||
3266 | { | ||
3267 | dprintk("%s Reset task for i/o through\n", __func__); | ||
3268 | put_lseg(data->lseg); | ||
3269 | data->lseg = NULL; | ||
3270 | data->ds_clp = NULL; | ||
3271 | data->write_done_cb = nfs4_write_done_cb; | ||
3272 | data->args.fh = NFS_FH(data->inode); | ||
3273 | data->args.bitmask = data->res.server->cache_consistency_bitmask; | ||
3274 | data->args.offset = data->mds_offset; | ||
3275 | data->res.fattr = &data->fattr; | ||
3276 | task->tk_ops = data->mds_ops; | ||
3277 | rpc_task_reset_client(task, NFS_CLIENT(data->inode)); | ||
3278 | } | ||
3279 | EXPORT_SYMBOL_GPL(nfs4_reset_write); | ||
3280 | |||
3149 | static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) | 3281 | static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg) |
3150 | { | 3282 | { |
3151 | struct nfs_server *server = NFS_SERVER(data->inode); | 3283 | struct nfs_server *server = NFS_SERVER(data->inode); |
3152 | 3284 | ||
3153 | data->args.bitmask = server->cache_consistency_bitmask; | 3285 | if (data->lseg) { |
3286 | data->args.bitmask = NULL; | ||
3287 | data->res.fattr = NULL; | ||
3288 | } else | ||
3289 | data->args.bitmask = server->cache_consistency_bitmask; | ||
3290 | if (!data->write_done_cb) | ||
3291 | data->write_done_cb = nfs4_write_done_cb; | ||
3154 | data->res.server = server; | 3292 | data->res.server = server; |
3155 | data->timestamp = jiffies; | 3293 | data->timestamp = jiffies; |
3156 | 3294 | ||
3157 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; | 3295 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; |
3158 | } | 3296 | } |
3159 | 3297 | ||
3160 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 3298 | static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data) |
3161 | { | 3299 | { |
3162 | struct inode *inode = data->inode; | 3300 | struct inode *inode = data->inode; |
3163 | |||
3164 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3165 | return -EAGAIN; | ||
3166 | 3301 | ||
3167 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3302 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3168 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3303 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
@@ -3172,11 +3307,24 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3172 | return 0; | 3307 | return 0; |
3173 | } | 3308 | } |
3174 | 3309 | ||
3310 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | ||
3311 | { | ||
3312 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3313 | return -EAGAIN; | ||
3314 | return data->write_done_cb(task, data); | ||
3315 | } | ||
3316 | |||
3175 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) | 3317 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
3176 | { | 3318 | { |
3177 | struct nfs_server *server = NFS_SERVER(data->inode); | 3319 | struct nfs_server *server = NFS_SERVER(data->inode); |
3178 | 3320 | ||
3179 | data->args.bitmask = server->cache_consistency_bitmask; | 3321 | if (data->lseg) { |
3322 | data->args.bitmask = NULL; | ||
3323 | data->res.fattr = NULL; | ||
3324 | } else | ||
3325 | data->args.bitmask = server->cache_consistency_bitmask; | ||
3326 | if (!data->write_done_cb) | ||
3327 | data->write_done_cb = nfs4_commit_done_cb; | ||
3180 | data->res.server = server; | 3328 | data->res.server = server; |
3181 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | 3329 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; |
3182 | } | 3330 | } |
@@ -3210,7 +3358,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata) | |||
3210 | if (task->tk_status < 0) { | 3358 | if (task->tk_status < 0) { |
3211 | /* Unless we're shutting down, schedule state recovery! */ | 3359 | /* Unless we're shutting down, schedule state recovery! */ |
3212 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0) | 3360 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0) |
3213 | nfs4_schedule_state_recovery(clp); | 3361 | nfs4_schedule_lease_recovery(clp); |
3214 | return; | 3362 | return; |
3215 | } | 3363 | } |
3216 | do_renew_lease(clp, timestamp); | 3364 | do_renew_lease(clp, timestamp); |
@@ -3284,6 +3432,35 @@ static void buf_to_pages(const void *buf, size_t buflen, | |||
3284 | } | 3432 | } |
3285 | } | 3433 | } |
3286 | 3434 | ||
3435 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | ||
3436 | struct page **pages, unsigned int *pgbase) | ||
3437 | { | ||
3438 | struct page *newpage, **spages; | ||
3439 | int rc = 0; | ||
3440 | size_t len; | ||
3441 | spages = pages; | ||
3442 | |||
3443 | do { | ||
3444 | len = min_t(size_t, PAGE_CACHE_SIZE, buflen); | ||
3445 | newpage = alloc_page(GFP_KERNEL); | ||
3446 | |||
3447 | if (newpage == NULL) | ||
3448 | goto unwind; | ||
3449 | memcpy(page_address(newpage), buf, len); | ||
3450 | buf += len; | ||
3451 | buflen -= len; | ||
3452 | *pages++ = newpage; | ||
3453 | rc++; | ||
3454 | } while (buflen != 0); | ||
3455 | |||
3456 | return rc; | ||
3457 | |||
3458 | unwind: | ||
3459 | for(; rc > 0; rc--) | ||
3460 | __free_page(spages[rc-1]); | ||
3461 | return -ENOMEM; | ||
3462 | } | ||
3463 | |||
3287 | struct nfs4_cached_acl { | 3464 | struct nfs4_cached_acl { |
3288 | int cached; | 3465 | int cached; |
3289 | size_t len; | 3466 | size_t len; |
@@ -3385,7 +3562,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3385 | resp_buf = buf; | 3562 | resp_buf = buf; |
3386 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3563 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
3387 | } | 3564 | } |
3388 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); | 3565 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); |
3389 | if (ret) | 3566 | if (ret) |
3390 | goto out_free; | 3567 | goto out_free; |
3391 | if (res.acl_len > args.acl_len) | 3568 | if (res.acl_len > args.acl_len) |
@@ -3429,6 +3606,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
3429 | ret = nfs_revalidate_inode(server, inode); | 3606 | ret = nfs_revalidate_inode(server, inode); |
3430 | if (ret < 0) | 3607 | if (ret < 0) |
3431 | return ret; | 3608 | return ret; |
3609 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
3610 | nfs_zap_acl_cache(inode); | ||
3432 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3611 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
3433 | if (ret != -ENOENT) | 3612 | if (ret != -ENOENT) |
3434 | return ret; | 3613 | return ret; |
@@ -3450,13 +3629,30 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
3450 | .rpc_argp = &arg, | 3629 | .rpc_argp = &arg, |
3451 | .rpc_resp = &res, | 3630 | .rpc_resp = &res, |
3452 | }; | 3631 | }; |
3453 | int ret; | 3632 | int ret, i; |
3454 | 3633 | ||
3455 | if (!nfs4_server_supports_acls(server)) | 3634 | if (!nfs4_server_supports_acls(server)) |
3456 | return -EOPNOTSUPP; | 3635 | return -EOPNOTSUPP; |
3636 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | ||
3637 | if (i < 0) | ||
3638 | return i; | ||
3457 | nfs_inode_return_delegation(inode); | 3639 | nfs_inode_return_delegation(inode); |
3458 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3640 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
3459 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); | 3641 | |
3642 | /* | ||
3643 | * Free each page after tx, so the only ref left is | ||
3644 | * held by the network stack | ||
3645 | */ | ||
3646 | for (; i > 0; i--) | ||
3647 | put_page(pages[i-1]); | ||
3648 | |||
3649 | /* | ||
3650 | * Acl update can result in inode attribute update. | ||
3651 | * so mark the attribute cache invalid. | ||
3652 | */ | ||
3653 | spin_lock(&inode->i_lock); | ||
3654 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR; | ||
3655 | spin_unlock(&inode->i_lock); | ||
3460 | nfs_access_zap_cache(inode); | 3656 | nfs_access_zap_cache(inode); |
3461 | nfs_zap_acl_cache(inode); | 3657 | nfs_zap_acl_cache(inode); |
3462 | return ret; | 3658 | return ret; |
@@ -3487,15 +3683,15 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3487 | case -NFS4ERR_OPENMODE: | 3683 | case -NFS4ERR_OPENMODE: |
3488 | if (state == NULL) | 3684 | if (state == NULL) |
3489 | break; | 3685 | break; |
3490 | nfs4_state_mark_reclaim_nograce(clp, state); | 3686 | nfs4_schedule_stateid_recovery(server, state); |
3491 | goto do_state_recovery; | 3687 | goto wait_on_recovery; |
3688 | case -NFS4ERR_EXPIRED: | ||
3689 | if (state != NULL) | ||
3690 | nfs4_schedule_stateid_recovery(server, state); | ||
3492 | case -NFS4ERR_STALE_STATEID: | 3691 | case -NFS4ERR_STALE_STATEID: |
3493 | if (state == NULL) | ||
3494 | break; | ||
3495 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
3496 | case -NFS4ERR_STALE_CLIENTID: | 3692 | case -NFS4ERR_STALE_CLIENTID: |
3497 | case -NFS4ERR_EXPIRED: | 3693 | nfs4_schedule_lease_recovery(clp); |
3498 | goto do_state_recovery; | 3694 | goto wait_on_recovery; |
3499 | #if defined(CONFIG_NFS_V4_1) | 3695 | #if defined(CONFIG_NFS_V4_1) |
3500 | case -NFS4ERR_BADSESSION: | 3696 | case -NFS4ERR_BADSESSION: |
3501 | case -NFS4ERR_BADSLOT: | 3697 | case -NFS4ERR_BADSLOT: |
@@ -3506,7 +3702,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3506 | case -NFS4ERR_SEQ_MISORDERED: | 3702 | case -NFS4ERR_SEQ_MISORDERED: |
3507 | dprintk("%s ERROR %d, Reset session\n", __func__, | 3703 | dprintk("%s ERROR %d, Reset session\n", __func__, |
3508 | task->tk_status); | 3704 | task->tk_status); |
3509 | nfs4_schedule_state_recovery(clp); | 3705 | nfs4_schedule_session_recovery(clp->cl_session); |
3510 | task->tk_status = 0; | 3706 | task->tk_status = 0; |
3511 | return -EAGAIN; | 3707 | return -EAGAIN; |
3512 | #endif /* CONFIG_NFS_V4_1 */ | 3708 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -3517,15 +3713,15 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3517 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3713 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
3518 | task->tk_status = 0; | 3714 | task->tk_status = 0; |
3519 | return -EAGAIN; | 3715 | return -EAGAIN; |
3716 | case -NFS4ERR_RETRY_UNCACHED_REP: | ||
3520 | case -NFS4ERR_OLD_STATEID: | 3717 | case -NFS4ERR_OLD_STATEID: |
3521 | task->tk_status = 0; | 3718 | task->tk_status = 0; |
3522 | return -EAGAIN; | 3719 | return -EAGAIN; |
3523 | } | 3720 | } |
3524 | task->tk_status = nfs4_map_errors(task->tk_status); | 3721 | task->tk_status = nfs4_map_errors(task->tk_status); |
3525 | return 0; | 3722 | return 0; |
3526 | do_state_recovery: | 3723 | wait_on_recovery: |
3527 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 3724 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
3528 | nfs4_schedule_state_recovery(clp); | ||
3529 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | 3725 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) |
3530 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3726 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
3531 | task->tk_status = 0; | 3727 | task->tk_status = 0; |
@@ -3540,6 +3736,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3540 | struct nfs4_setclientid setclientid = { | 3736 | struct nfs4_setclientid setclientid = { |
3541 | .sc_verifier = &sc_verifier, | 3737 | .sc_verifier = &sc_verifier, |
3542 | .sc_prog = program, | 3738 | .sc_prog = program, |
3739 | .sc_cb_ident = clp->cl_cb_ident, | ||
3543 | }; | 3740 | }; |
3544 | struct rpc_message msg = { | 3741 | struct rpc_message msg = { |
3545 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], | 3742 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], |
@@ -3573,21 +3770,20 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3573 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", | 3770 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
3574 | clp->cl_ipaddr, port >> 8, port & 255); | 3771 | clp->cl_ipaddr, port >> 8, port & 255); |
3575 | 3772 | ||
3576 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3773 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
3577 | if (status != -NFS4ERR_CLID_INUSE) | 3774 | if (status != -NFS4ERR_CLID_INUSE) |
3578 | break; | 3775 | break; |
3579 | if (signalled()) | 3776 | if (loop != 0) { |
3777 | ++clp->cl_id_uniquifier; | ||
3580 | break; | 3778 | break; |
3581 | if (loop++ & 1) | 3779 | } |
3582 | ssleep(clp->cl_lease_time + 1); | 3780 | ++loop; |
3583 | else | 3781 | ssleep(clp->cl_lease_time / HZ + 1); |
3584 | if (++clp->cl_id_uniquifier == 0) | ||
3585 | break; | ||
3586 | } | 3782 | } |
3587 | return status; | 3783 | return status; |
3588 | } | 3784 | } |
3589 | 3785 | ||
3590 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | 3786 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
3591 | struct nfs4_setclientid_res *arg, | 3787 | struct nfs4_setclientid_res *arg, |
3592 | struct rpc_cred *cred) | 3788 | struct rpc_cred *cred) |
3593 | { | 3789 | { |
@@ -3602,7 +3798,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
3602 | int status; | 3798 | int status; |
3603 | 3799 | ||
3604 | now = jiffies; | 3800 | now = jiffies; |
3605 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3801 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
3606 | if (status == 0) { | 3802 | if (status == 0) { |
3607 | spin_lock(&clp->cl_lock); | 3803 | spin_lock(&clp->cl_lock); |
3608 | clp->cl_lease_time = fsinfo.lease_time * HZ; | 3804 | clp->cl_lease_time = fsinfo.lease_time * HZ; |
@@ -3612,27 +3808,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
3612 | return status; | 3808 | return status; |
3613 | } | 3809 | } |
3614 | 3810 | ||
3615 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | ||
3616 | struct nfs4_setclientid_res *arg, | ||
3617 | struct rpc_cred *cred) | ||
3618 | { | ||
3619 | long timeout = 0; | ||
3620 | int err; | ||
3621 | do { | ||
3622 | err = _nfs4_proc_setclientid_confirm(clp, arg, cred); | ||
3623 | switch (err) { | ||
3624 | case 0: | ||
3625 | return err; | ||
3626 | case -NFS4ERR_RESOURCE: | ||
3627 | /* The IBM lawyers misread another document! */ | ||
3628 | case -NFS4ERR_DELAY: | ||
3629 | case -EKEYEXPIRED: | ||
3630 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | ||
3631 | } | ||
3632 | } while (err == 0); | ||
3633 | return err; | ||
3634 | } | ||
3635 | |||
3636 | struct nfs4_delegreturndata { | 3811 | struct nfs4_delegreturndata { |
3637 | struct nfs4_delegreturnargs args; | 3812 | struct nfs4_delegreturnargs args; |
3638 | struct nfs4_delegreturnres res; | 3813 | struct nfs4_delegreturnres res; |
@@ -3721,14 +3896,13 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3721 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3896 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3722 | data->res.fattr = &data->fattr; | 3897 | data->res.fattr = &data->fattr; |
3723 | data->res.server = server; | 3898 | data->res.server = server; |
3724 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3725 | nfs_fattr_init(data->res.fattr); | 3899 | nfs_fattr_init(data->res.fattr); |
3726 | data->timestamp = jiffies; | 3900 | data->timestamp = jiffies; |
3727 | data->rpc_status = 0; | 3901 | data->rpc_status = 0; |
3728 | 3902 | ||
3729 | task_setup_data.callback_data = data; | 3903 | task_setup_data.callback_data = data; |
3730 | msg.rpc_argp = &data->args, | 3904 | msg.rpc_argp = &data->args; |
3731 | msg.rpc_resp = &data->res, | 3905 | msg.rpc_resp = &data->res; |
3732 | task = rpc_run_task(&task_setup_data); | 3906 | task = rpc_run_task(&task_setup_data); |
3733 | if (IS_ERR(task)) | 3907 | if (IS_ERR(task)) |
3734 | return PTR_ERR(task); | 3908 | return PTR_ERR(task); |
@@ -3807,7 +3981,8 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3807 | goto out; | 3981 | goto out; |
3808 | lsp = request->fl_u.nfs4_fl.owner; | 3982 | lsp = request->fl_u.nfs4_fl.owner; |
3809 | arg.lock_owner.id = lsp->ls_id.id; | 3983 | arg.lock_owner.id = lsp->ls_id.id; |
3810 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 3984 | arg.lock_owner.s_dev = server->s_dev; |
3985 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | ||
3811 | switch (status) { | 3986 | switch (status) { |
3812 | case 0: | 3987 | case 0: |
3813 | request->fl_type = F_UNLCK; | 3988 | request->fl_type = F_UNLCK; |
@@ -3874,7 +4049,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3874 | p->arg.fl = &p->fl; | 4049 | p->arg.fl = &p->fl; |
3875 | p->arg.seqid = seqid; | 4050 | p->arg.seqid = seqid; |
3876 | p->res.seqid = seqid; | 4051 | p->res.seqid = seqid; |
3877 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3878 | p->arg.stateid = &lsp->ls_stateid; | 4052 | p->arg.stateid = &lsp->ls_stateid; |
3879 | p->lsp = lsp; | 4053 | p->lsp = lsp; |
3880 | atomic_inc(&lsp->ls_count); | 4054 | atomic_inc(&lsp->ls_count); |
@@ -3973,8 +4147,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3973 | return ERR_PTR(-ENOMEM); | 4147 | return ERR_PTR(-ENOMEM); |
3974 | } | 4148 | } |
3975 | 4149 | ||
3976 | msg.rpc_argp = &data->arg, | 4150 | msg.rpc_argp = &data->arg; |
3977 | msg.rpc_resp = &data->res, | 4151 | msg.rpc_resp = &data->res; |
3978 | task_setup_data.callback_data = data; | 4152 | task_setup_data.callback_data = data; |
3979 | return rpc_run_task(&task_setup_data); | 4153 | return rpc_run_task(&task_setup_data); |
3980 | } | 4154 | } |
@@ -4053,8 +4227,8 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
4053 | p->arg.lock_stateid = &lsp->ls_stateid; | 4227 | p->arg.lock_stateid = &lsp->ls_stateid; |
4054 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 4228 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
4055 | p->arg.lock_owner.id = lsp->ls_id.id; | 4229 | p->arg.lock_owner.id = lsp->ls_id.id; |
4230 | p->arg.lock_owner.s_dev = server->s_dev; | ||
4056 | p->res.lock_seqid = p->arg.lock_seqid; | 4231 | p->res.lock_seqid = p->arg.lock_seqid; |
4057 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4058 | p->lsp = lsp; | 4232 | p->lsp = lsp; |
4059 | p->server = server; | 4233 | p->server = server; |
4060 | atomic_inc(&lsp->ls_count); | 4234 | atomic_inc(&lsp->ls_count); |
@@ -4137,7 +4311,7 @@ static void nfs4_lock_release(void *calldata) | |||
4137 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | 4311 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, |
4138 | data->arg.lock_seqid); | 4312 | data->arg.lock_seqid); |
4139 | if (!IS_ERR(task)) | 4313 | if (!IS_ERR(task)) |
4140 | rpc_put_task(task); | 4314 | rpc_put_task_async(task); |
4141 | dprintk("%s: cancelling lock!\n", __func__); | 4315 | dprintk("%s: cancelling lock!\n", __func__); |
4142 | } else | 4316 | } else |
4143 | nfs_free_seqid(data->arg.lock_seqid); | 4317 | nfs_free_seqid(data->arg.lock_seqid); |
@@ -4161,23 +4335,18 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = { | |||
4161 | 4335 | ||
4162 | static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) | 4336 | static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) |
4163 | { | 4337 | { |
4164 | struct nfs_client *clp = server->nfs_client; | ||
4165 | struct nfs4_state *state = lsp->ls_state; | ||
4166 | |||
4167 | switch (error) { | 4338 | switch (error) { |
4168 | case -NFS4ERR_ADMIN_REVOKED: | 4339 | case -NFS4ERR_ADMIN_REVOKED: |
4169 | case -NFS4ERR_BAD_STATEID: | 4340 | case -NFS4ERR_BAD_STATEID: |
4170 | case -NFS4ERR_EXPIRED: | 4341 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; |
4171 | if (new_lock_owner != 0 || | 4342 | if (new_lock_owner != 0 || |
4172 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | 4343 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) |
4173 | nfs4_state_mark_reclaim_nograce(clp, state); | 4344 | nfs4_schedule_stateid_recovery(server, lsp->ls_state); |
4174 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4175 | break; | 4345 | break; |
4176 | case -NFS4ERR_STALE_STATEID: | 4346 | case -NFS4ERR_STALE_STATEID: |
4177 | if (new_lock_owner != 0 || | ||
4178 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4179 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
4180 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | 4347 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; |
4348 | case -NFS4ERR_EXPIRED: | ||
4349 | nfs4_schedule_lease_recovery(server->nfs_client); | ||
4181 | }; | 4350 | }; |
4182 | } | 4351 | } |
4183 | 4352 | ||
@@ -4211,8 +4380,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4211 | data->arg.reclaim = NFS_LOCK_RECLAIM; | 4380 | data->arg.reclaim = NFS_LOCK_RECLAIM; |
4212 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; | 4381 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; |
4213 | } | 4382 | } |
4214 | msg.rpc_argp = &data->arg, | 4383 | msg.rpc_argp = &data->arg; |
4215 | msg.rpc_resp = &data->res, | 4384 | msg.rpc_resp = &data->res; |
4216 | task_setup_data.callback_data = data; | 4385 | task_setup_data.callback_data = data; |
4217 | task = rpc_run_task(&task_setup_data); | 4386 | task = rpc_run_task(&task_setup_data); |
4218 | if (IS_ERR(task)) | 4387 | if (IS_ERR(task)) |
@@ -4241,7 +4410,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4241 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4410 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4242 | return 0; | 4411 | return 0; |
4243 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); | 4412 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4244 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) | 4413 | if (err != -NFS4ERR_DELAY) |
4245 | break; | 4414 | break; |
4246 | nfs4_handle_exception(server, err, &exception); | 4415 | nfs4_handle_exception(server, err, &exception); |
4247 | } while (exception.retry); | 4416 | } while (exception.retry); |
@@ -4266,7 +4435,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4266 | goto out; | 4435 | goto out; |
4267 | case -NFS4ERR_GRACE: | 4436 | case -NFS4ERR_GRACE: |
4268 | case -NFS4ERR_DELAY: | 4437 | case -NFS4ERR_DELAY: |
4269 | case -EKEYEXPIRED: | ||
4270 | nfs4_handle_exception(server, err, &exception); | 4438 | nfs4_handle_exception(server, err, &exception); |
4271 | err = 0; | 4439 | err = 0; |
4272 | } | 4440 | } |
@@ -4392,14 +4560,17 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4392 | case -ESTALE: | 4560 | case -ESTALE: |
4393 | goto out; | 4561 | goto out; |
4394 | case -NFS4ERR_EXPIRED: | 4562 | case -NFS4ERR_EXPIRED: |
4563 | nfs4_schedule_stateid_recovery(server, state); | ||
4395 | case -NFS4ERR_STALE_CLIENTID: | 4564 | case -NFS4ERR_STALE_CLIENTID: |
4396 | case -NFS4ERR_STALE_STATEID: | 4565 | case -NFS4ERR_STALE_STATEID: |
4566 | nfs4_schedule_lease_recovery(server->nfs_client); | ||
4567 | goto out; | ||
4397 | case -NFS4ERR_BADSESSION: | 4568 | case -NFS4ERR_BADSESSION: |
4398 | case -NFS4ERR_BADSLOT: | 4569 | case -NFS4ERR_BADSLOT: |
4399 | case -NFS4ERR_BAD_HIGH_SLOT: | 4570 | case -NFS4ERR_BAD_HIGH_SLOT: |
4400 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | 4571 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: |
4401 | case -NFS4ERR_DEADSESSION: | 4572 | case -NFS4ERR_DEADSESSION: |
4402 | nfs4_schedule_state_recovery(server->nfs_client); | 4573 | nfs4_schedule_session_recovery(server->nfs_client->cl_session); |
4403 | goto out; | 4574 | goto out; |
4404 | case -ERESTARTSYS: | 4575 | case -ERESTARTSYS: |
4405 | /* | 4576 | /* |
@@ -4409,7 +4580,16 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4409 | case -NFS4ERR_ADMIN_REVOKED: | 4580 | case -NFS4ERR_ADMIN_REVOKED: |
4410 | case -NFS4ERR_BAD_STATEID: | 4581 | case -NFS4ERR_BAD_STATEID: |
4411 | case -NFS4ERR_OPENMODE: | 4582 | case -NFS4ERR_OPENMODE: |
4412 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | 4583 | nfs4_schedule_stateid_recovery(server, state); |
4584 | err = 0; | ||
4585 | goto out; | ||
4586 | case -EKEYEXPIRED: | ||
4587 | /* | ||
4588 | * User RPCSEC_GSS context has expired. | ||
4589 | * We cannot recover this stateid now, so | ||
4590 | * skip it and allow recovery thread to | ||
4591 | * proceed. | ||
4592 | */ | ||
4413 | err = 0; | 4593 | err = 0; |
4414 | goto out; | 4594 | goto out; |
4415 | case -ENOMEM: | 4595 | case -ENOMEM: |
@@ -4418,7 +4598,6 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4418 | err = 0; | 4598 | err = 0; |
4419 | goto out; | 4599 | goto out; |
4420 | case -NFS4ERR_DELAY: | 4600 | case -NFS4ERR_DELAY: |
4421 | case -EKEYEXPIRED: | ||
4422 | break; | 4601 | break; |
4423 | } | 4602 | } |
4424 | err = nfs4_handle_exception(server, err, &exception); | 4603 | err = nfs4_handle_exception(server, err, &exception); |
@@ -4451,56 +4630,55 @@ void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) | |||
4451 | return; | 4630 | return; |
4452 | args->lock_owner.clientid = server->nfs_client->cl_clientid; | 4631 | args->lock_owner.clientid = server->nfs_client->cl_clientid; |
4453 | args->lock_owner.id = lsp->ls_id.id; | 4632 | args->lock_owner.id = lsp->ls_id.id; |
4633 | args->lock_owner.s_dev = server->s_dev; | ||
4454 | msg.rpc_argp = args; | 4634 | msg.rpc_argp = args; |
4455 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); | 4635 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); |
4456 | } | 4636 | } |
4457 | 4637 | ||
4458 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | 4638 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" |
4459 | 4639 | ||
4460 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | 4640 | static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key, |
4461 | size_t buflen, int flags) | 4641 | const void *buf, size_t buflen, |
4642 | int flags, int type) | ||
4462 | { | 4643 | { |
4463 | struct inode *inode = dentry->d_inode; | 4644 | if (strcmp(key, "") != 0) |
4464 | 4645 | return -EINVAL; | |
4465 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
4466 | return -EOPNOTSUPP; | ||
4467 | 4646 | ||
4468 | return nfs4_proc_set_acl(inode, buf, buflen); | 4647 | return nfs4_proc_set_acl(dentry->d_inode, buf, buflen); |
4469 | } | 4648 | } |
4470 | 4649 | ||
4471 | /* The getxattr man page suggests returning -ENODATA for unknown attributes, | 4650 | static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key, |
4472 | * and that's what we'll do for e.g. user attributes that haven't been set. | 4651 | void *buf, size_t buflen, int type) |
4473 | * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported | ||
4474 | * attributes in kernel-managed attribute namespaces. */ | ||
4475 | ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, | ||
4476 | size_t buflen) | ||
4477 | { | 4652 | { |
4478 | struct inode *inode = dentry->d_inode; | 4653 | if (strcmp(key, "") != 0) |
4479 | 4654 | return -EINVAL; | |
4480 | if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0) | ||
4481 | return -EOPNOTSUPP; | ||
4482 | 4655 | ||
4483 | return nfs4_proc_get_acl(inode, buf, buflen); | 4656 | return nfs4_proc_get_acl(dentry->d_inode, buf, buflen); |
4484 | } | 4657 | } |
4485 | 4658 | ||
4486 | ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | 4659 | static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list, |
4660 | size_t list_len, const char *name, | ||
4661 | size_t name_len, int type) | ||
4487 | { | 4662 | { |
4488 | size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1; | 4663 | size_t len = sizeof(XATTR_NAME_NFSV4_ACL); |
4489 | 4664 | ||
4490 | if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode))) | 4665 | if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode))) |
4491 | return 0; | 4666 | return 0; |
4492 | if (buf && buflen < len) | 4667 | |
4493 | return -ERANGE; | 4668 | if (list && len <= list_len) |
4494 | if (buf) | 4669 | memcpy(list, XATTR_NAME_NFSV4_ACL, len); |
4495 | memcpy(buf, XATTR_NAME_NFSV4_ACL, len); | ||
4496 | return len; | 4670 | return len; |
4497 | } | 4671 | } |
4498 | 4672 | ||
4673 | /* | ||
4674 | * nfs_fhget will use either the mounted_on_fileid or the fileid | ||
4675 | */ | ||
4499 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr) | 4676 | static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr) |
4500 | { | 4677 | { |
4501 | if (!((fattr->valid & NFS_ATTR_FATTR_FILEID) && | 4678 | if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) || |
4502 | (fattr->valid & NFS_ATTR_FATTR_FSID) && | 4679 | (fattr->valid & NFS_ATTR_FATTR_FILEID)) && |
4503 | (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL))) | 4680 | (fattr->valid & NFS_ATTR_FATTR_FSID) && |
4681 | (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL))) | ||
4504 | return; | 4682 | return; |
4505 | 4683 | ||
4506 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | | 4684 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | |
@@ -4515,7 +4693,6 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4515 | struct nfs_server *server = NFS_SERVER(dir); | 4693 | struct nfs_server *server = NFS_SERVER(dir); |
4516 | u32 bitmask[2] = { | 4694 | u32 bitmask[2] = { |
4517 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, | 4695 | [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, |
4518 | [1] = FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
4519 | }; | 4696 | }; |
4520 | struct nfs4_fs_locations_arg args = { | 4697 | struct nfs4_fs_locations_arg args = { |
4521 | .dir_fh = NFS_FH(dir), | 4698 | .dir_fh = NFS_FH(dir), |
@@ -4534,17 +4711,77 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4534 | int status; | 4711 | int status; |
4535 | 4712 | ||
4536 | dprintk("%s: start\n", __func__); | 4713 | dprintk("%s: start\n", __func__); |
4714 | |||
4715 | /* Ask for the fileid of the absent filesystem if mounted_on_fileid | ||
4716 | * is not supported */ | ||
4717 | if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
4718 | bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
4719 | else | ||
4720 | bitmask[0] |= FATTR4_WORD0_FILEID; | ||
4721 | |||
4537 | nfs_fattr_init(&fs_locations->fattr); | 4722 | nfs_fattr_init(&fs_locations->fattr); |
4538 | fs_locations->server = server; | 4723 | fs_locations->server = server; |
4539 | fs_locations->nlocations = 0; | 4724 | fs_locations->nlocations = 0; |
4540 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 4725 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
4541 | nfs_fixup_referral_attributes(&fs_locations->fattr); | ||
4542 | dprintk("%s: returned status = %d\n", __func__, status); | 4726 | dprintk("%s: returned status = %d\n", __func__, status); |
4543 | return status; | 4727 | return status; |
4544 | } | 4728 | } |
4545 | 4729 | ||
4730 | static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | ||
4731 | { | ||
4732 | int status; | ||
4733 | struct nfs4_secinfo_arg args = { | ||
4734 | .dir_fh = NFS_FH(dir), | ||
4735 | .name = name, | ||
4736 | }; | ||
4737 | struct nfs4_secinfo_res res = { | ||
4738 | .flavors = flavors, | ||
4739 | }; | ||
4740 | struct rpc_message msg = { | ||
4741 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO], | ||
4742 | .rpc_argp = &args, | ||
4743 | .rpc_resp = &res, | ||
4744 | }; | ||
4745 | |||
4746 | dprintk("NFS call secinfo %s\n", name->name); | ||
4747 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); | ||
4748 | dprintk("NFS reply secinfo: %d\n", status); | ||
4749 | return status; | ||
4750 | } | ||
4751 | |||
4752 | int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | ||
4753 | { | ||
4754 | struct nfs4_exception exception = { }; | ||
4755 | int err; | ||
4756 | do { | ||
4757 | err = nfs4_handle_exception(NFS_SERVER(dir), | ||
4758 | _nfs4_proc_secinfo(dir, name, flavors), | ||
4759 | &exception); | ||
4760 | } while (exception.retry); | ||
4761 | return err; | ||
4762 | } | ||
4763 | |||
4546 | #ifdef CONFIG_NFS_V4_1 | 4764 | #ifdef CONFIG_NFS_V4_1 |
4547 | /* | 4765 | /* |
4766 | * Check the exchange flags returned by the server for invalid flags, having | ||
4767 | * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or | ||
4768 | * DS flags set. | ||
4769 | */ | ||
4770 | static int nfs4_check_cl_exchange_flags(u32 flags) | ||
4771 | { | ||
4772 | if (flags & ~EXCHGID4_FLAG_MASK_R) | ||
4773 | goto out_inval; | ||
4774 | if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) && | ||
4775 | (flags & EXCHGID4_FLAG_USE_NON_PNFS)) | ||
4776 | goto out_inval; | ||
4777 | if (!(flags & (EXCHGID4_FLAG_MASK_PNFS))) | ||
4778 | goto out_inval; | ||
4779 | return NFS_OK; | ||
4780 | out_inval: | ||
4781 | return -NFS4ERR_INVAL; | ||
4782 | } | ||
4783 | |||
4784 | /* | ||
4548 | * nfs4_proc_exchange_id() | 4785 | * nfs4_proc_exchange_id() |
4549 | * | 4786 | * |
4550 | * Since the clientid has expired, all compounds using sessions | 4787 | * Since the clientid has expired, all compounds using sessions |
@@ -4557,7 +4794,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4557 | nfs4_verifier verifier; | 4794 | nfs4_verifier verifier; |
4558 | struct nfs41_exchange_id_args args = { | 4795 | struct nfs41_exchange_id_args args = { |
4559 | .client = clp, | 4796 | .client = clp, |
4560 | .flags = clp->cl_exchange_flags, | 4797 | .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER, |
4561 | }; | 4798 | }; |
4562 | struct nfs41_exchange_id_res res = { | 4799 | struct nfs41_exchange_id_res res = { |
4563 | .client = clp, | 4800 | .client = clp, |
@@ -4574,34 +4811,21 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4574 | dprintk("--> %s\n", __func__); | 4811 | dprintk("--> %s\n", __func__); |
4575 | BUG_ON(clp == NULL); | 4812 | BUG_ON(clp == NULL); |
4576 | 4813 | ||
4577 | /* Remove server-only flags */ | ||
4578 | args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R; | ||
4579 | |||
4580 | p = (u32 *)verifier.data; | 4814 | p = (u32 *)verifier.data; |
4581 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | 4815 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); |
4582 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | 4816 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); |
4583 | args.verifier = &verifier; | 4817 | args.verifier = &verifier; |
4584 | 4818 | ||
4585 | while (1) { | 4819 | args.id_len = scnprintf(args.id, sizeof(args.id), |
4586 | args.id_len = scnprintf(args.id, sizeof(args.id), | 4820 | "%s/%s.%s/%u", |
4587 | "%s/%s %u", | 4821 | clp->cl_ipaddr, |
4588 | clp->cl_ipaddr, | 4822 | init_utsname()->nodename, |
4589 | rpc_peeraddr2str(clp->cl_rpcclient, | 4823 | init_utsname()->domainname, |
4590 | RPC_DISPLAY_ADDR), | 4824 | clp->cl_rpcclient->cl_auth->au_flavor); |
4591 | clp->cl_id_uniquifier); | ||
4592 | |||
4593 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4594 | |||
4595 | if (status != -NFS4ERR_CLID_INUSE) | ||
4596 | break; | ||
4597 | |||
4598 | if (signalled()) | ||
4599 | break; | ||
4600 | |||
4601 | if (++clp->cl_id_uniquifier == 0) | ||
4602 | break; | ||
4603 | } | ||
4604 | 4825 | ||
4826 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | ||
4827 | if (!status) | ||
4828 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | ||
4605 | dprintk("<-- %s status= %d\n", __func__, status); | 4829 | dprintk("<-- %s status= %d\n", __func__, status); |
4606 | return status; | 4830 | return status; |
4607 | } | 4831 | } |
@@ -4647,10 +4871,11 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4647 | switch (task->tk_status) { | 4871 | switch (task->tk_status) { |
4648 | case -NFS4ERR_DELAY: | 4872 | case -NFS4ERR_DELAY: |
4649 | case -NFS4ERR_GRACE: | 4873 | case -NFS4ERR_GRACE: |
4650 | case -EKEYEXPIRED: | ||
4651 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4874 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4652 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4875 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4653 | task->tk_status = 0; | 4876 | task->tk_status = 0; |
4877 | /* fall through */ | ||
4878 | case -NFS4ERR_RETRY_UNCACHED_REP: | ||
4654 | nfs_restart_rpc(task, data->clp); | 4879 | nfs_restart_rpc(task, data->clp); |
4655 | return; | 4880 | return; |
4656 | } | 4881 | } |
@@ -4683,11 +4908,11 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4683 | .rpc_client = clp->cl_rpcclient, | 4908 | .rpc_client = clp->cl_rpcclient, |
4684 | .rpc_message = &msg, | 4909 | .rpc_message = &msg, |
4685 | .callback_ops = &nfs4_get_lease_time_ops, | 4910 | .callback_ops = &nfs4_get_lease_time_ops, |
4686 | .callback_data = &data | 4911 | .callback_data = &data, |
4912 | .flags = RPC_TASK_TIMEOUT, | ||
4687 | }; | 4913 | }; |
4688 | int status; | 4914 | int status; |
4689 | 4915 | ||
4690 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4691 | dprintk("--> %s\n", __func__); | 4916 | dprintk("--> %s\n", __func__); |
4692 | task = rpc_run_task(&task_setup); | 4917 | task = rpc_run_task(&task_setup); |
4693 | 4918 | ||
@@ -4837,17 +5062,17 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4837 | if (!session) | 5062 | if (!session) |
4838 | return NULL; | 5063 | return NULL; |
4839 | 5064 | ||
4840 | init_completion(&session->complete); | ||
4841 | |||
4842 | tbl = &session->fc_slot_table; | 5065 | tbl = &session->fc_slot_table; |
4843 | tbl->highest_used_slotid = -1; | 5066 | tbl->highest_used_slotid = -1; |
4844 | spin_lock_init(&tbl->slot_tbl_lock); | 5067 | spin_lock_init(&tbl->slot_tbl_lock); |
4845 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | 5068 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); |
5069 | init_completion(&tbl->complete); | ||
4846 | 5070 | ||
4847 | tbl = &session->bc_slot_table; | 5071 | tbl = &session->bc_slot_table; |
4848 | tbl->highest_used_slotid = -1; | 5072 | tbl->highest_used_slotid = -1; |
4849 | spin_lock_init(&tbl->slot_tbl_lock); | 5073 | spin_lock_init(&tbl->slot_tbl_lock); |
4850 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 5074 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
5075 | init_completion(&tbl->complete); | ||
4851 | 5076 | ||
4852 | session->session_state = 1<<NFS4_SESSION_INITING; | 5077 | session->session_state = 1<<NFS4_SESSION_INITING; |
4853 | 5078 | ||
@@ -4886,7 +5111,6 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4886 | if (mxresp_sz == 0) | 5111 | if (mxresp_sz == 0) |
4887 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | 5112 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; |
4888 | /* Fore channel attributes */ | 5113 | /* Fore channel attributes */ |
4889 | args->fc_attrs.headerpadsz = 0; | ||
4890 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 5114 | args->fc_attrs.max_rqst_sz = mxrqst_sz; |
4891 | args->fc_attrs.max_resp_sz = mxresp_sz; | 5115 | args->fc_attrs.max_resp_sz = mxresp_sz; |
4892 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 5116 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
@@ -4899,7 +5123,6 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4899 | args->fc_attrs.max_ops, args->fc_attrs.max_reqs); | 5123 | args->fc_attrs.max_ops, args->fc_attrs.max_reqs); |
4900 | 5124 | ||
4901 | /* Back channel attributes */ | 5125 | /* Back channel attributes */ |
4902 | args->bc_attrs.headerpadsz = 0; | ||
4903 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | 5126 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; |
4904 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | 5127 | args->bc_attrs.max_resp_sz = PAGE_SIZE; |
4905 | args->bc_attrs.max_resp_sz_cached = 0; | 5128 | args->bc_attrs.max_resp_sz_cached = 0; |
@@ -4914,49 +5137,54 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4914 | args->bc_attrs.max_reqs); | 5137 | args->bc_attrs.max_reqs); |
4915 | } | 5138 | } |
4916 | 5139 | ||
4917 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | 5140 | static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session) |
4918 | { | 5141 | { |
4919 | if (rcvd <= sent) | 5142 | struct nfs4_channel_attrs *sent = &args->fc_attrs; |
4920 | return 0; | 5143 | struct nfs4_channel_attrs *rcvd = &session->fc_attrs; |
4921 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | 5144 | |
4922 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | 5145 | if (rcvd->max_resp_sz > sent->max_resp_sz) |
4923 | return -EINVAL; | 5146 | return -EINVAL; |
5147 | /* | ||
5148 | * Our requested max_ops is the minimum we need; we're not | ||
5149 | * prepared to break up compounds into smaller pieces than that. | ||
5150 | * So, no point even trying to continue if the server won't | ||
5151 | * cooperate: | ||
5152 | */ | ||
5153 | if (rcvd->max_ops < sent->max_ops) | ||
5154 | return -EINVAL; | ||
5155 | if (rcvd->max_reqs == 0) | ||
5156 | return -EINVAL; | ||
5157 | return 0; | ||
4924 | } | 5158 | } |
4925 | 5159 | ||
4926 | #define _verify_fore_channel_attr(_name_) \ | 5160 | static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session) |
4927 | _verify_channel_attr("fore", #_name_, \ | 5161 | { |
4928 | args->fc_attrs._name_, \ | 5162 | struct nfs4_channel_attrs *sent = &args->bc_attrs; |
4929 | session->fc_attrs._name_) | 5163 | struct nfs4_channel_attrs *rcvd = &session->bc_attrs; |
4930 | 5164 | ||
4931 | #define _verify_back_channel_attr(_name_) \ | 5165 | if (rcvd->max_rqst_sz > sent->max_rqst_sz) |
4932 | _verify_channel_attr("back", #_name_, \ | 5166 | return -EINVAL; |
4933 | args->bc_attrs._name_, \ | 5167 | if (rcvd->max_resp_sz < sent->max_resp_sz) |
4934 | session->bc_attrs._name_) | 5168 | return -EINVAL; |
5169 | if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached) | ||
5170 | return -EINVAL; | ||
5171 | /* These would render the backchannel useless: */ | ||
5172 | if (rcvd->max_ops == 0) | ||
5173 | return -EINVAL; | ||
5174 | if (rcvd->max_reqs == 0) | ||
5175 | return -EINVAL; | ||
5176 | return 0; | ||
5177 | } | ||
4935 | 5178 | ||
4936 | /* | ||
4937 | * The server is not allowed to increase the fore channel header pad size, | ||
4938 | * maximum response size, or maximum number of operations. | ||
4939 | * | ||
4940 | * The back channel attributes are only negotiatied down: We send what the | ||
4941 | * (back channel) server insists upon. | ||
4942 | */ | ||
4943 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | 5179 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, |
4944 | struct nfs4_session *session) | 5180 | struct nfs4_session *session) |
4945 | { | 5181 | { |
4946 | int ret = 0; | 5182 | int ret; |
4947 | |||
4948 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4949 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4950 | ret |= _verify_fore_channel_attr(max_ops); | ||
4951 | |||
4952 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4953 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4954 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4955 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4956 | ret |= _verify_back_channel_attr(max_ops); | ||
4957 | ret |= _verify_back_channel_attr(max_reqs); | ||
4958 | 5183 | ||
4959 | return ret; | 5184 | ret = nfs4_verify_fore_channel_attrs(args, session); |
5185 | if (ret) | ||
5186 | return ret; | ||
5187 | return nfs4_verify_back_channel_attrs(args, session); | ||
4960 | } | 5188 | } |
4961 | 5189 | ||
4962 | static int _nfs4_proc_create_session(struct nfs_client *clp) | 5190 | static int _nfs4_proc_create_session(struct nfs_client *clp) |
@@ -4979,7 +5207,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp) | |||
4979 | nfs4_init_channel_attrs(&args); | 5207 | nfs4_init_channel_attrs(&args); |
4980 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | 5208 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); |
4981 | 5209 | ||
4982 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | 5210 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
4983 | 5211 | ||
4984 | if (!status) | 5212 | if (!status) |
4985 | /* Verify the session's negotiated channel_attrs values */ | 5213 | /* Verify the session's negotiated channel_attrs values */ |
@@ -5046,7 +5274,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
5046 | msg.rpc_argp = session; | 5274 | msg.rpc_argp = session; |
5047 | msg.rpc_resp = NULL; | 5275 | msg.rpc_resp = NULL; |
5048 | msg.rpc_cred = NULL; | 5276 | msg.rpc_cred = NULL; |
5049 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | 5277 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
5050 | 5278 | ||
5051 | if (status) | 5279 | if (status) |
5052 | printk(KERN_WARNING | 5280 | printk(KERN_WARNING |
@@ -5087,6 +5315,27 @@ int nfs4_init_session(struct nfs_server *server) | |||
5087 | return ret; | 5315 | return ret; |
5088 | } | 5316 | } |
5089 | 5317 | ||
5318 | int nfs4_init_ds_session(struct nfs_client *clp) | ||
5319 | { | ||
5320 | struct nfs4_session *session = clp->cl_session; | ||
5321 | int ret; | ||
5322 | |||
5323 | if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) | ||
5324 | return 0; | ||
5325 | |||
5326 | ret = nfs4_client_recover_expired_lease(clp); | ||
5327 | if (!ret) | ||
5328 | /* Test for the DS role */ | ||
5329 | if (!is_ds_client(clp)) | ||
5330 | ret = -ENODEV; | ||
5331 | if (!ret) | ||
5332 | ret = nfs4_check_client_ready(clp); | ||
5333 | return ret; | ||
5334 | |||
5335 | } | ||
5336 | EXPORT_SYMBOL_GPL(nfs4_init_ds_session); | ||
5337 | |||
5338 | |||
5090 | /* | 5339 | /* |
5091 | * Renew the cl_session lease. | 5340 | * Renew the cl_session lease. |
5092 | */ | 5341 | */ |
@@ -5111,11 +5360,10 @@ static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client | |||
5111 | { | 5360 | { |
5112 | switch(task->tk_status) { | 5361 | switch(task->tk_status) { |
5113 | case -NFS4ERR_DELAY: | 5362 | case -NFS4ERR_DELAY: |
5114 | case -EKEYEXPIRED: | ||
5115 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 5363 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
5116 | return -EAGAIN; | 5364 | return -EAGAIN; |
5117 | default: | 5365 | default: |
5118 | nfs4_schedule_state_recovery(clp); | 5366 | nfs4_schedule_lease_recovery(clp); |
5119 | } | 5367 | } |
5120 | return 0; | 5368 | return 0; |
5121 | } | 5369 | } |
@@ -5180,12 +5428,11 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_ | |||
5180 | 5428 | ||
5181 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5429 | if (!atomic_inc_not_zero(&clp->cl_count)) |
5182 | return ERR_PTR(-EIO); | 5430 | return ERR_PTR(-EIO); |
5183 | calldata = kmalloc(sizeof(*calldata), GFP_NOFS); | 5431 | calldata = kzalloc(sizeof(*calldata), GFP_NOFS); |
5184 | if (calldata == NULL) { | 5432 | if (calldata == NULL) { |
5185 | nfs_put_client(clp); | 5433 | nfs_put_client(clp); |
5186 | return ERR_PTR(-ENOMEM); | 5434 | return ERR_PTR(-ENOMEM); |
5187 | } | 5435 | } |
5188 | calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5189 | msg.rpc_argp = &calldata->args; | 5436 | msg.rpc_argp = &calldata->args; |
5190 | msg.rpc_resp = &calldata->res; | 5437 | msg.rpc_resp = &calldata->res; |
5191 | calldata->clp = clp; | 5438 | calldata->clp = clp; |
@@ -5203,7 +5450,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr | |||
5203 | if (IS_ERR(task)) | 5450 | if (IS_ERR(task)) |
5204 | ret = PTR_ERR(task); | 5451 | ret = PTR_ERR(task); |
5205 | else | 5452 | else |
5206 | rpc_put_task(task); | 5453 | rpc_put_task_async(task); |
5207 | dprintk("<-- %s status=%d\n", __func__, ret); | 5454 | dprintk("<-- %s status=%d\n", __func__, ret); |
5208 | return ret; | 5455 | return ret; |
5209 | } | 5456 | } |
@@ -5219,8 +5466,13 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
5219 | goto out; | 5466 | goto out; |
5220 | } | 5467 | } |
5221 | ret = rpc_wait_for_completion_task(task); | 5468 | ret = rpc_wait_for_completion_task(task); |
5222 | if (!ret) | 5469 | if (!ret) { |
5470 | struct nfs4_sequence_res *res = task->tk_msg.rpc_resp; | ||
5471 | |||
5472 | if (task->tk_status == 0) | ||
5473 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | ||
5223 | ret = task->tk_status; | 5474 | ret = task->tk_status; |
5475 | } | ||
5224 | rpc_put_task(task); | 5476 | rpc_put_task(task); |
5225 | out: | 5477 | out: |
5226 | dprintk("<-- %s status=%d\n", __func__, ret); | 5478 | dprintk("<-- %s status=%d\n", __func__, ret); |
@@ -5254,11 +5506,12 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf | |||
5254 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ | 5506 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ |
5255 | break; | 5507 | break; |
5256 | case -NFS4ERR_DELAY: | 5508 | case -NFS4ERR_DELAY: |
5257 | case -EKEYEXPIRED: | ||
5258 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 5509 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
5510 | /* fall through */ | ||
5511 | case -NFS4ERR_RETRY_UNCACHED_REP: | ||
5259 | return -EAGAIN; | 5512 | return -EAGAIN; |
5260 | default: | 5513 | default: |
5261 | nfs4_schedule_state_recovery(clp); | 5514 | nfs4_schedule_lease_recovery(clp); |
5262 | } | 5515 | } |
5263 | return 0; | 5516 | return 0; |
5264 | } | 5517 | } |
@@ -5317,7 +5570,6 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
5317 | goto out; | 5570 | goto out; |
5318 | calldata->clp = clp; | 5571 | calldata->clp = clp; |
5319 | calldata->arg.one_fs = 0; | 5572 | calldata->arg.one_fs = 0; |
5320 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5321 | 5573 | ||
5322 | msg.rpc_argp = &calldata->arg; | 5574 | msg.rpc_argp = &calldata->arg; |
5323 | msg.rpc_resp = &calldata->res; | 5575 | msg.rpc_resp = &calldata->res; |
@@ -5327,12 +5579,330 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
5327 | status = PTR_ERR(task); | 5579 | status = PTR_ERR(task); |
5328 | goto out; | 5580 | goto out; |
5329 | } | 5581 | } |
5582 | status = nfs4_wait_for_completion_rpc_task(task); | ||
5583 | if (status == 0) | ||
5584 | status = task->tk_status; | ||
5330 | rpc_put_task(task); | 5585 | rpc_put_task(task); |
5331 | return 0; | 5586 | return 0; |
5332 | out: | 5587 | out: |
5333 | dprintk("<-- %s status=%d\n", __func__, status); | 5588 | dprintk("<-- %s status=%d\n", __func__, status); |
5334 | return status; | 5589 | return status; |
5335 | } | 5590 | } |
5591 | |||
5592 | static void | ||
5593 | nfs4_layoutget_prepare(struct rpc_task *task, void *calldata) | ||
5594 | { | ||
5595 | struct nfs4_layoutget *lgp = calldata; | ||
5596 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
5597 | |||
5598 | dprintk("--> %s\n", __func__); | ||
5599 | /* Note the is a race here, where a CB_LAYOUTRECALL can come in | ||
5600 | * right now covering the LAYOUTGET we are about to send. | ||
5601 | * However, that is not so catastrophic, and there seems | ||
5602 | * to be no way to prevent it completely. | ||
5603 | */ | ||
5604 | if (nfs4_setup_sequence(server, &lgp->args.seq_args, | ||
5605 | &lgp->res.seq_res, 0, task)) | ||
5606 | return; | ||
5607 | if (pnfs_choose_layoutget_stateid(&lgp->args.stateid, | ||
5608 | NFS_I(lgp->args.inode)->layout, | ||
5609 | lgp->args.ctx->state)) { | ||
5610 | rpc_exit(task, NFS4_OK); | ||
5611 | return; | ||
5612 | } | ||
5613 | rpc_call_start(task); | ||
5614 | } | ||
5615 | |||
5616 | static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | ||
5617 | { | ||
5618 | struct nfs4_layoutget *lgp = calldata; | ||
5619 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
5620 | |||
5621 | dprintk("--> %s\n", __func__); | ||
5622 | |||
5623 | if (!nfs4_sequence_done(task, &lgp->res.seq_res)) | ||
5624 | return; | ||
5625 | |||
5626 | switch (task->tk_status) { | ||
5627 | case 0: | ||
5628 | break; | ||
5629 | case -NFS4ERR_LAYOUTTRYLATER: | ||
5630 | case -NFS4ERR_RECALLCONFLICT: | ||
5631 | task->tk_status = -NFS4ERR_DELAY; | ||
5632 | /* Fall through */ | ||
5633 | default: | ||
5634 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | ||
5635 | rpc_restart_call_prepare(task); | ||
5636 | return; | ||
5637 | } | ||
5638 | } | ||
5639 | dprintk("<-- %s\n", __func__); | ||
5640 | } | ||
5641 | |||
5642 | static void nfs4_layoutget_release(void *calldata) | ||
5643 | { | ||
5644 | struct nfs4_layoutget *lgp = calldata; | ||
5645 | |||
5646 | dprintk("--> %s\n", __func__); | ||
5647 | put_nfs_open_context(lgp->args.ctx); | ||
5648 | kfree(calldata); | ||
5649 | dprintk("<-- %s\n", __func__); | ||
5650 | } | ||
5651 | |||
5652 | static const struct rpc_call_ops nfs4_layoutget_call_ops = { | ||
5653 | .rpc_call_prepare = nfs4_layoutget_prepare, | ||
5654 | .rpc_call_done = nfs4_layoutget_done, | ||
5655 | .rpc_release = nfs4_layoutget_release, | ||
5656 | }; | ||
5657 | |||
5658 | int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | ||
5659 | { | ||
5660 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
5661 | struct rpc_task *task; | ||
5662 | struct rpc_message msg = { | ||
5663 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], | ||
5664 | .rpc_argp = &lgp->args, | ||
5665 | .rpc_resp = &lgp->res, | ||
5666 | }; | ||
5667 | struct rpc_task_setup task_setup_data = { | ||
5668 | .rpc_client = server->client, | ||
5669 | .rpc_message = &msg, | ||
5670 | .callback_ops = &nfs4_layoutget_call_ops, | ||
5671 | .callback_data = lgp, | ||
5672 | .flags = RPC_TASK_ASYNC, | ||
5673 | }; | ||
5674 | int status = 0; | ||
5675 | |||
5676 | dprintk("--> %s\n", __func__); | ||
5677 | |||
5678 | lgp->res.layoutp = &lgp->args.layout; | ||
5679 | lgp->res.seq_res.sr_slot = NULL; | ||
5680 | task = rpc_run_task(&task_setup_data); | ||
5681 | if (IS_ERR(task)) | ||
5682 | return PTR_ERR(task); | ||
5683 | status = nfs4_wait_for_completion_rpc_task(task); | ||
5684 | if (status == 0) | ||
5685 | status = task->tk_status; | ||
5686 | if (status == 0) | ||
5687 | status = pnfs_layout_process(lgp); | ||
5688 | rpc_put_task(task); | ||
5689 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5690 | return status; | ||
5691 | } | ||
5692 | |||
5693 | static void | ||
5694 | nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata) | ||
5695 | { | ||
5696 | struct nfs4_layoutreturn *lrp = calldata; | ||
5697 | |||
5698 | dprintk("--> %s\n", __func__); | ||
5699 | if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args, | ||
5700 | &lrp->res.seq_res, 0, task)) | ||
5701 | return; | ||
5702 | rpc_call_start(task); | ||
5703 | } | ||
5704 | |||
5705 | static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | ||
5706 | { | ||
5707 | struct nfs4_layoutreturn *lrp = calldata; | ||
5708 | struct nfs_server *server; | ||
5709 | struct pnfs_layout_hdr *lo = NFS_I(lrp->args.inode)->layout; | ||
5710 | |||
5711 | dprintk("--> %s\n", __func__); | ||
5712 | |||
5713 | if (!nfs4_sequence_done(task, &lrp->res.seq_res)) | ||
5714 | return; | ||
5715 | |||
5716 | server = NFS_SERVER(lrp->args.inode); | ||
5717 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | ||
5718 | nfs_restart_rpc(task, lrp->clp); | ||
5719 | return; | ||
5720 | } | ||
5721 | spin_lock(&lo->plh_inode->i_lock); | ||
5722 | if (task->tk_status == 0) { | ||
5723 | if (lrp->res.lrs_present) { | ||
5724 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); | ||
5725 | } else | ||
5726 | BUG_ON(!list_empty(&lo->plh_segs)); | ||
5727 | } | ||
5728 | lo->plh_block_lgets--; | ||
5729 | spin_unlock(&lo->plh_inode->i_lock); | ||
5730 | dprintk("<-- %s\n", __func__); | ||
5731 | } | ||
5732 | |||
5733 | static void nfs4_layoutreturn_release(void *calldata) | ||
5734 | { | ||
5735 | struct nfs4_layoutreturn *lrp = calldata; | ||
5736 | |||
5737 | dprintk("--> %s\n", __func__); | ||
5738 | put_layout_hdr(NFS_I(lrp->args.inode)->layout); | ||
5739 | kfree(calldata); | ||
5740 | dprintk("<-- %s\n", __func__); | ||
5741 | } | ||
5742 | |||
5743 | static const struct rpc_call_ops nfs4_layoutreturn_call_ops = { | ||
5744 | .rpc_call_prepare = nfs4_layoutreturn_prepare, | ||
5745 | .rpc_call_done = nfs4_layoutreturn_done, | ||
5746 | .rpc_release = nfs4_layoutreturn_release, | ||
5747 | }; | ||
5748 | |||
5749 | int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp) | ||
5750 | { | ||
5751 | struct rpc_task *task; | ||
5752 | struct rpc_message msg = { | ||
5753 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN], | ||
5754 | .rpc_argp = &lrp->args, | ||
5755 | .rpc_resp = &lrp->res, | ||
5756 | }; | ||
5757 | struct rpc_task_setup task_setup_data = { | ||
5758 | .rpc_client = lrp->clp->cl_rpcclient, | ||
5759 | .rpc_message = &msg, | ||
5760 | .callback_ops = &nfs4_layoutreturn_call_ops, | ||
5761 | .callback_data = lrp, | ||
5762 | }; | ||
5763 | int status; | ||
5764 | |||
5765 | dprintk("--> %s\n", __func__); | ||
5766 | task = rpc_run_task(&task_setup_data); | ||
5767 | if (IS_ERR(task)) | ||
5768 | return PTR_ERR(task); | ||
5769 | status = task->tk_status; | ||
5770 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5771 | rpc_put_task(task); | ||
5772 | return status; | ||
5773 | } | ||
5774 | |||
5775 | static int | ||
5776 | _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | ||
5777 | { | ||
5778 | struct nfs4_getdeviceinfo_args args = { | ||
5779 | .pdev = pdev, | ||
5780 | }; | ||
5781 | struct nfs4_getdeviceinfo_res res = { | ||
5782 | .pdev = pdev, | ||
5783 | }; | ||
5784 | struct rpc_message msg = { | ||
5785 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO], | ||
5786 | .rpc_argp = &args, | ||
5787 | .rpc_resp = &res, | ||
5788 | }; | ||
5789 | int status; | ||
5790 | |||
5791 | dprintk("--> %s\n", __func__); | ||
5792 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | ||
5793 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5794 | |||
5795 | return status; | ||
5796 | } | ||
5797 | |||
5798 | int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | ||
5799 | { | ||
5800 | struct nfs4_exception exception = { }; | ||
5801 | int err; | ||
5802 | |||
5803 | do { | ||
5804 | err = nfs4_handle_exception(server, | ||
5805 | _nfs4_proc_getdeviceinfo(server, pdev), | ||
5806 | &exception); | ||
5807 | } while (exception.retry); | ||
5808 | return err; | ||
5809 | } | ||
5810 | EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); | ||
5811 | |||
5812 | static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) | ||
5813 | { | ||
5814 | struct nfs4_layoutcommit_data *data = calldata; | ||
5815 | struct nfs_server *server = NFS_SERVER(data->args.inode); | ||
5816 | |||
5817 | if (nfs4_setup_sequence(server, &data->args.seq_args, | ||
5818 | &data->res.seq_res, 1, task)) | ||
5819 | return; | ||
5820 | rpc_call_start(task); | ||
5821 | } | ||
5822 | |||
5823 | static void | ||
5824 | nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) | ||
5825 | { | ||
5826 | struct nfs4_layoutcommit_data *data = calldata; | ||
5827 | struct nfs_server *server = NFS_SERVER(data->args.inode); | ||
5828 | |||
5829 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
5830 | return; | ||
5831 | |||
5832 | switch (task->tk_status) { /* Just ignore these failures */ | ||
5833 | case NFS4ERR_DELEG_REVOKED: /* layout was recalled */ | ||
5834 | case NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */ | ||
5835 | case NFS4ERR_BADLAYOUT: /* no layout */ | ||
5836 | case NFS4ERR_GRACE: /* loca_recalim always false */ | ||
5837 | task->tk_status = 0; | ||
5838 | } | ||
5839 | |||
5840 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | ||
5841 | nfs_restart_rpc(task, server->nfs_client); | ||
5842 | return; | ||
5843 | } | ||
5844 | |||
5845 | if (task->tk_status == 0) | ||
5846 | nfs_post_op_update_inode_force_wcc(data->args.inode, | ||
5847 | data->res.fattr); | ||
5848 | } | ||
5849 | |||
5850 | static void nfs4_layoutcommit_release(void *calldata) | ||
5851 | { | ||
5852 | struct nfs4_layoutcommit_data *data = calldata; | ||
5853 | |||
5854 | /* Matched by references in pnfs_set_layoutcommit */ | ||
5855 | put_lseg(data->lseg); | ||
5856 | put_rpccred(data->cred); | ||
5857 | kfree(data); | ||
5858 | } | ||
5859 | |||
5860 | static const struct rpc_call_ops nfs4_layoutcommit_ops = { | ||
5861 | .rpc_call_prepare = nfs4_layoutcommit_prepare, | ||
5862 | .rpc_call_done = nfs4_layoutcommit_done, | ||
5863 | .rpc_release = nfs4_layoutcommit_release, | ||
5864 | }; | ||
5865 | |||
5866 | int | ||
5867 | nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) | ||
5868 | { | ||
5869 | struct rpc_message msg = { | ||
5870 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT], | ||
5871 | .rpc_argp = &data->args, | ||
5872 | .rpc_resp = &data->res, | ||
5873 | .rpc_cred = data->cred, | ||
5874 | }; | ||
5875 | struct rpc_task_setup task_setup_data = { | ||
5876 | .task = &data->task, | ||
5877 | .rpc_client = NFS_CLIENT(data->args.inode), | ||
5878 | .rpc_message = &msg, | ||
5879 | .callback_ops = &nfs4_layoutcommit_ops, | ||
5880 | .callback_data = data, | ||
5881 | .flags = RPC_TASK_ASYNC, | ||
5882 | }; | ||
5883 | struct rpc_task *task; | ||
5884 | int status = 0; | ||
5885 | |||
5886 | dprintk("NFS: %4d initiating layoutcommit call. sync %d " | ||
5887 | "lbw: %llu inode %lu\n", | ||
5888 | data->task.tk_pid, sync, | ||
5889 | data->args.lastbytewritten, | ||
5890 | data->args.inode->i_ino); | ||
5891 | |||
5892 | task = rpc_run_task(&task_setup_data); | ||
5893 | if (IS_ERR(task)) | ||
5894 | return PTR_ERR(task); | ||
5895 | if (sync == false) | ||
5896 | goto out; | ||
5897 | status = nfs4_wait_for_completion_rpc_task(task); | ||
5898 | if (status != 0) | ||
5899 | goto out; | ||
5900 | status = task->tk_status; | ||
5901 | out: | ||
5902 | dprintk("%s: status %d\n", __func__, status); | ||
5903 | rpc_put_task(task); | ||
5904 | return status; | ||
5905 | } | ||
5336 | #endif /* CONFIG_NFS_V4_1 */ | 5906 | #endif /* CONFIG_NFS_V4_1 */ |
5337 | 5907 | ||
5338 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5908 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -5421,9 +5991,10 @@ static const struct inode_operations nfs4_file_inode_operations = { | |||
5421 | .permission = nfs_permission, | 5991 | .permission = nfs_permission, |
5422 | .getattr = nfs_getattr, | 5992 | .getattr = nfs_getattr, |
5423 | .setattr = nfs_setattr, | 5993 | .setattr = nfs_setattr, |
5424 | .getxattr = nfs4_getxattr, | 5994 | .getxattr = generic_getxattr, |
5425 | .setxattr = nfs4_setxattr, | 5995 | .setxattr = generic_setxattr, |
5426 | .listxattr = nfs4_listxattr, | 5996 | .listxattr = generic_listxattr, |
5997 | .removexattr = generic_removexattr, | ||
5427 | }; | 5998 | }; |
5428 | 5999 | ||
5429 | const struct nfs_rpc_ops nfs_v4_clientops = { | 6000 | const struct nfs_rpc_ops nfs_v4_clientops = { |
@@ -5443,6 +6014,8 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
5443 | .unlink_setup = nfs4_proc_unlink_setup, | 6014 | .unlink_setup = nfs4_proc_unlink_setup, |
5444 | .unlink_done = nfs4_proc_unlink_done, | 6015 | .unlink_done = nfs4_proc_unlink_done, |
5445 | .rename = nfs4_proc_rename, | 6016 | .rename = nfs4_proc_rename, |
6017 | .rename_setup = nfs4_proc_rename_setup, | ||
6018 | .rename_done = nfs4_proc_rename_done, | ||
5446 | .link = nfs4_proc_link, | 6019 | .link = nfs4_proc_link, |
5447 | .symlink = nfs4_proc_symlink, | 6020 | .symlink = nfs4_proc_symlink, |
5448 | .mkdir = nfs4_proc_mkdir, | 6021 | .mkdir = nfs4_proc_mkdir, |
@@ -5463,6 +6036,21 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
5463 | .lock = nfs4_proc_lock, | 6036 | .lock = nfs4_proc_lock, |
5464 | .clear_acl_cache = nfs4_zap_acl_attr, | 6037 | .clear_acl_cache = nfs4_zap_acl_attr, |
5465 | .close_context = nfs4_close_context, | 6038 | .close_context = nfs4_close_context, |
6039 | .open_context = nfs4_atomic_open, | ||
6040 | .init_client = nfs4_init_client, | ||
6041 | .secinfo = nfs4_proc_secinfo, | ||
6042 | }; | ||
6043 | |||
6044 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { | ||
6045 | .prefix = XATTR_NAME_NFSV4_ACL, | ||
6046 | .list = nfs4_xattr_list_nfs4_acl, | ||
6047 | .get = nfs4_xattr_get_nfs4_acl, | ||
6048 | .set = nfs4_xattr_set_nfs4_acl, | ||
6049 | }; | ||
6050 | |||
6051 | const struct xattr_handler *nfs4_xattr_handlers[] = { | ||
6052 | &nfs4_xattr_nfs4_acl_handler, | ||
6053 | NULL | ||
5466 | }; | 6054 | }; |
5467 | 6055 | ||
5468 | /* | 6056 | /* |