diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 126 |
1 files changed, 68 insertions, 58 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fc0c9d255cf7..e8df52dc2bc5 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -323,7 +323,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
323 | } | 323 | } |
324 | 324 | ||
325 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 325 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
326 | struct nfs4_state_owner *sp, int flags, | 326 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
327 | const struct iattr *attrs) | 327 | const struct iattr *attrs) |
328 | { | 328 | { |
329 | struct dentry *parent = dget_parent(path->dentry); | 329 | struct dentry *parent = dget_parent(path->dentry); |
@@ -343,7 +343,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
343 | p->owner = sp; | 343 | p->owner = sp; |
344 | atomic_inc(&sp->so_count); | 344 | atomic_inc(&sp->so_count); |
345 | p->o_arg.fh = NFS_FH(dir); | 345 | p->o_arg.fh = NFS_FH(dir); |
346 | p->o_arg.open_flags = flags, | 346 | p->o_arg.open_flags = flags; |
347 | p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); | ||
347 | p->o_arg.clientid = server->nfs_client->cl_clientid; | 348 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
348 | p->o_arg.id = sp->so_owner_id.id; | 349 | p->o_arg.id = sp->so_owner_id.id; |
349 | p->o_arg.name = &p->path.dentry->d_name; | 350 | p->o_arg.name = &p->path.dentry->d_name; |
@@ -399,10 +400,13 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
399 | return ret; | 400 | return ret; |
400 | } | 401 | } |
401 | 402 | ||
402 | static int can_open_cached(struct nfs4_state *state, int mode) | 403 | static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) |
403 | { | 404 | { |
404 | int ret = 0; | 405 | int ret = 0; |
405 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | 406 | |
407 | if (open_mode & O_EXCL) | ||
408 | goto out; | ||
409 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | ||
406 | case FMODE_READ: | 410 | case FMODE_READ: |
407 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 411 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; |
408 | break; | 412 | break; |
@@ -412,12 +416,13 @@ static int can_open_cached(struct nfs4_state *state, int mode) | |||
412 | case FMODE_READ|FMODE_WRITE: | 416 | case FMODE_READ|FMODE_WRITE: |
413 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 417 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; |
414 | } | 418 | } |
419 | out: | ||
415 | return ret; | 420 | return ret; |
416 | } | 421 | } |
417 | 422 | ||
418 | static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | 423 | static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) |
419 | { | 424 | { |
420 | if ((delegation->type & open_flags) != open_flags) | 425 | if ((delegation->type & fmode) != fmode) |
421 | return 0; | 426 | return 0; |
422 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) | 427 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) |
423 | return 0; | 428 | return 0; |
@@ -425,9 +430,9 @@ static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_fla | |||
425 | return 1; | 430 | return 1; |
426 | } | 431 | } |
427 | 432 | ||
428 | static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | 433 | static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode) |
429 | { | 434 | { |
430 | switch (open_flags) { | 435 | switch (fmode) { |
431 | case FMODE_WRITE: | 436 | case FMODE_WRITE: |
432 | state->n_wronly++; | 437 | state->n_wronly++; |
433 | break; | 438 | break; |
@@ -437,15 +442,15 @@ static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | |||
437 | case FMODE_READ|FMODE_WRITE: | 442 | case FMODE_READ|FMODE_WRITE: |
438 | state->n_rdwr++; | 443 | state->n_rdwr++; |
439 | } | 444 | } |
440 | nfs4_state_set_mode_locked(state, state->state | open_flags); | 445 | nfs4_state_set_mode_locked(state, state->state | fmode); |
441 | } | 446 | } |
442 | 447 | ||
443 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 448 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
444 | { | 449 | { |
445 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 450 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
446 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | 451 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); |
447 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | 452 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); |
448 | switch (open_flags) { | 453 | switch (fmode) { |
449 | case FMODE_READ: | 454 | case FMODE_READ: |
450 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | 455 | set_bit(NFS_O_RDONLY_STATE, &state->flags); |
451 | break; | 456 | break; |
@@ -457,14 +462,14 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
457 | } | 462 | } |
458 | } | 463 | } |
459 | 464 | ||
460 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 465 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
461 | { | 466 | { |
462 | write_seqlock(&state->seqlock); | 467 | write_seqlock(&state->seqlock); |
463 | nfs_set_open_stateid_locked(state, stateid, open_flags); | 468 | nfs_set_open_stateid_locked(state, stateid, fmode); |
464 | write_sequnlock(&state->seqlock); | 469 | write_sequnlock(&state->seqlock); |
465 | } | 470 | } |
466 | 471 | ||
467 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, int open_flags) | 472 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) |
468 | { | 473 | { |
469 | /* | 474 | /* |
470 | * Protect the call to nfs4_state_set_mode_locked and | 475 | * Protect the call to nfs4_state_set_mode_locked and |
@@ -476,20 +481,20 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s | |||
476 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 481 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
477 | } | 482 | } |
478 | if (open_stateid != NULL) | 483 | if (open_stateid != NULL) |
479 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | 484 | nfs_set_open_stateid_locked(state, open_stateid, fmode); |
480 | write_sequnlock(&state->seqlock); | 485 | write_sequnlock(&state->seqlock); |
481 | spin_lock(&state->owner->so_lock); | 486 | spin_lock(&state->owner->so_lock); |
482 | update_open_stateflags(state, open_flags); | 487 | update_open_stateflags(state, fmode); |
483 | spin_unlock(&state->owner->so_lock); | 488 | spin_unlock(&state->owner->so_lock); |
484 | } | 489 | } |
485 | 490 | ||
486 | static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, int open_flags) | 491 | static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode) |
487 | { | 492 | { |
488 | struct nfs_inode *nfsi = NFS_I(state->inode); | 493 | struct nfs_inode *nfsi = NFS_I(state->inode); |
489 | struct nfs_delegation *deleg_cur; | 494 | struct nfs_delegation *deleg_cur; |
490 | int ret = 0; | 495 | int ret = 0; |
491 | 496 | ||
492 | open_flags &= (FMODE_READ|FMODE_WRITE); | 497 | fmode &= (FMODE_READ|FMODE_WRITE); |
493 | 498 | ||
494 | rcu_read_lock(); | 499 | rcu_read_lock(); |
495 | deleg_cur = rcu_dereference(nfsi->delegation); | 500 | deleg_cur = rcu_dereference(nfsi->delegation); |
@@ -498,7 +503,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat | |||
498 | 503 | ||
499 | spin_lock(&deleg_cur->lock); | 504 | spin_lock(&deleg_cur->lock); |
500 | if (nfsi->delegation != deleg_cur || | 505 | if (nfsi->delegation != deleg_cur || |
501 | (deleg_cur->type & open_flags) != open_flags) | 506 | (deleg_cur->type & fmode) != fmode) |
502 | goto no_delegation_unlock; | 507 | goto no_delegation_unlock; |
503 | 508 | ||
504 | if (delegation == NULL) | 509 | if (delegation == NULL) |
@@ -507,7 +512,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat | |||
507 | goto no_delegation_unlock; | 512 | goto no_delegation_unlock; |
508 | 513 | ||
509 | nfs_mark_delegation_referenced(deleg_cur); | 514 | nfs_mark_delegation_referenced(deleg_cur); |
510 | __update_open_stateid(state, open_stateid, &deleg_cur->stateid, open_flags); | 515 | __update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode); |
511 | ret = 1; | 516 | ret = 1; |
512 | no_delegation_unlock: | 517 | no_delegation_unlock: |
513 | spin_unlock(&deleg_cur->lock); | 518 | spin_unlock(&deleg_cur->lock); |
@@ -515,7 +520,7 @@ no_delegation: | |||
515 | rcu_read_unlock(); | 520 | rcu_read_unlock(); |
516 | 521 | ||
517 | if (!ret && open_stateid != NULL) { | 522 | if (!ret && open_stateid != NULL) { |
518 | __update_open_stateid(state, open_stateid, NULL, open_flags); | 523 | __update_open_stateid(state, open_stateid, NULL, fmode); |
519 | ret = 1; | 524 | ret = 1; |
520 | } | 525 | } |
521 | 526 | ||
@@ -523,13 +528,13 @@ no_delegation: | |||
523 | } | 528 | } |
524 | 529 | ||
525 | 530 | ||
526 | static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) | 531 | static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode) |
527 | { | 532 | { |
528 | struct nfs_delegation *delegation; | 533 | struct nfs_delegation *delegation; |
529 | 534 | ||
530 | rcu_read_lock(); | 535 | rcu_read_lock(); |
531 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 536 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
532 | if (delegation == NULL || (delegation->type & open_flags) == open_flags) { | 537 | if (delegation == NULL || (delegation->type & fmode) == fmode) { |
533 | rcu_read_unlock(); | 538 | rcu_read_unlock(); |
534 | return; | 539 | return; |
535 | } | 540 | } |
@@ -542,15 +547,16 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
542 | struct nfs4_state *state = opendata->state; | 547 | struct nfs4_state *state = opendata->state; |
543 | struct nfs_inode *nfsi = NFS_I(state->inode); | 548 | struct nfs_inode *nfsi = NFS_I(state->inode); |
544 | struct nfs_delegation *delegation; | 549 | struct nfs_delegation *delegation; |
545 | int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); | 550 | int open_mode = opendata->o_arg.open_flags & O_EXCL; |
551 | fmode_t fmode = opendata->o_arg.fmode; | ||
546 | nfs4_stateid stateid; | 552 | nfs4_stateid stateid; |
547 | int ret = -EAGAIN; | 553 | int ret = -EAGAIN; |
548 | 554 | ||
549 | for (;;) { | 555 | for (;;) { |
550 | if (can_open_cached(state, open_mode)) { | 556 | if (can_open_cached(state, fmode, open_mode)) { |
551 | spin_lock(&state->owner->so_lock); | 557 | spin_lock(&state->owner->so_lock); |
552 | if (can_open_cached(state, open_mode)) { | 558 | if (can_open_cached(state, fmode, open_mode)) { |
553 | update_open_stateflags(state, open_mode); | 559 | update_open_stateflags(state, fmode); |
554 | spin_unlock(&state->owner->so_lock); | 560 | spin_unlock(&state->owner->so_lock); |
555 | goto out_return_state; | 561 | goto out_return_state; |
556 | } | 562 | } |
@@ -559,7 +565,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
559 | rcu_read_lock(); | 565 | rcu_read_lock(); |
560 | delegation = rcu_dereference(nfsi->delegation); | 566 | delegation = rcu_dereference(nfsi->delegation); |
561 | if (delegation == NULL || | 567 | if (delegation == NULL || |
562 | !can_open_delegated(delegation, open_mode)) { | 568 | !can_open_delegated(delegation, fmode)) { |
563 | rcu_read_unlock(); | 569 | rcu_read_unlock(); |
564 | break; | 570 | break; |
565 | } | 571 | } |
@@ -572,7 +578,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |||
572 | ret = -EAGAIN; | 578 | ret = -EAGAIN; |
573 | 579 | ||
574 | /* Try to update the stateid using the delegation */ | 580 | /* Try to update the stateid using the delegation */ |
575 | if (update_open_stateid(state, NULL, &stateid, open_mode)) | 581 | if (update_open_stateid(state, NULL, &stateid, fmode)) |
576 | goto out_return_state; | 582 | goto out_return_state; |
577 | } | 583 | } |
578 | out: | 584 | out: |
@@ -624,7 +630,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
624 | } | 630 | } |
625 | 631 | ||
626 | update_open_stateid(state, &data->o_res.stateid, NULL, | 632 | update_open_stateid(state, &data->o_res.stateid, NULL, |
627 | data->o_arg.open_flags); | 633 | data->o_arg.fmode); |
628 | iput(inode); | 634 | iput(inode); |
629 | out: | 635 | out: |
630 | return state; | 636 | return state; |
@@ -655,7 +661,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
655 | { | 661 | { |
656 | struct nfs4_opendata *opendata; | 662 | struct nfs4_opendata *opendata; |
657 | 663 | ||
658 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); | 664 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL); |
659 | if (opendata == NULL) | 665 | if (opendata == NULL) |
660 | return ERR_PTR(-ENOMEM); | 666 | return ERR_PTR(-ENOMEM); |
661 | opendata->state = state; | 667 | opendata->state = state; |
@@ -663,12 +669,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
663 | return opendata; | 669 | return opendata; |
664 | } | 670 | } |
665 | 671 | ||
666 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) | 672 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res) |
667 | { | 673 | { |
668 | struct nfs4_state *newstate; | 674 | struct nfs4_state *newstate; |
669 | int ret; | 675 | int ret; |
670 | 676 | ||
671 | opendata->o_arg.open_flags = openflags; | 677 | opendata->o_arg.open_flags = 0; |
678 | opendata->o_arg.fmode = fmode; | ||
672 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 679 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
673 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 680 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
674 | nfs4_init_opendata_res(opendata); | 681 | nfs4_init_opendata_res(opendata); |
@@ -678,7 +685,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openf | |||
678 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 685 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
679 | if (IS_ERR(newstate)) | 686 | if (IS_ERR(newstate)) |
680 | return PTR_ERR(newstate); | 687 | return PTR_ERR(newstate); |
681 | nfs4_close_state(&opendata->path, newstate, openflags); | 688 | nfs4_close_state(&opendata->path, newstate, fmode); |
682 | *res = newstate; | 689 | *res = newstate; |
683 | return 0; | 690 | return 0; |
684 | } | 691 | } |
@@ -734,7 +741,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
734 | { | 741 | { |
735 | struct nfs_delegation *delegation; | 742 | struct nfs_delegation *delegation; |
736 | struct nfs4_opendata *opendata; | 743 | struct nfs4_opendata *opendata; |
737 | int delegation_type = 0; | 744 | fmode_t delegation_type = 0; |
738 | int status; | 745 | int status; |
739 | 746 | ||
740 | opendata = nfs4_open_recoverdata_alloc(ctx, state); | 747 | opendata = nfs4_open_recoverdata_alloc(ctx, state); |
@@ -847,7 +854,7 @@ static void nfs4_open_confirm_release(void *calldata) | |||
847 | goto out_free; | 854 | goto out_free; |
848 | state = nfs4_opendata_to_nfs4_state(data); | 855 | state = nfs4_opendata_to_nfs4_state(data); |
849 | if (!IS_ERR(state)) | 856 | if (!IS_ERR(state)) |
850 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); | 857 | nfs4_close_state(&data->path, state, data->o_arg.fmode); |
851 | out_free: | 858 | out_free: |
852 | nfs4_opendata_put(data); | 859 | nfs4_opendata_put(data); |
853 | } | 860 | } |
@@ -911,7 +918,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
911 | if (data->state != NULL) { | 918 | if (data->state != NULL) { |
912 | struct nfs_delegation *delegation; | 919 | struct nfs_delegation *delegation; |
913 | 920 | ||
914 | if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) | 921 | if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags)) |
915 | goto out_no_action; | 922 | goto out_no_action; |
916 | rcu_read_lock(); | 923 | rcu_read_lock(); |
917 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | 924 | delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); |
@@ -980,7 +987,7 @@ static void nfs4_open_release(void *calldata) | |||
980 | goto out_free; | 987 | goto out_free; |
981 | state = nfs4_opendata_to_nfs4_state(data); | 988 | state = nfs4_opendata_to_nfs4_state(data); |
982 | if (!IS_ERR(state)) | 989 | if (!IS_ERR(state)) |
983 | nfs4_close_state(&data->path, state, data->o_arg.open_flags); | 990 | nfs4_close_state(&data->path, state, data->o_arg.fmode); |
984 | out_free: | 991 | out_free: |
985 | nfs4_opendata_put(data); | 992 | nfs4_opendata_put(data); |
986 | } | 993 | } |
@@ -1135,7 +1142,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct | |||
1135 | /* | 1142 | /* |
1136 | * Returns a referenced nfs4_state | 1143 | * Returns a referenced nfs4_state |
1137 | */ | 1144 | */ |
1138 | static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 1145 | static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) |
1139 | { | 1146 | { |
1140 | struct nfs4_state_owner *sp; | 1147 | struct nfs4_state_owner *sp; |
1141 | struct nfs4_state *state = NULL; | 1148 | struct nfs4_state *state = NULL; |
@@ -1153,9 +1160,9 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct | |||
1153 | if (status != 0) | 1160 | if (status != 0) |
1154 | goto err_put_state_owner; | 1161 | goto err_put_state_owner; |
1155 | if (path->dentry->d_inode != NULL) | 1162 | if (path->dentry->d_inode != NULL) |
1156 | nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); | 1163 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); |
1157 | status = -ENOMEM; | 1164 | status = -ENOMEM; |
1158 | opendata = nfs4_opendata_alloc(path, sp, flags, sattr); | 1165 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr); |
1159 | if (opendata == NULL) | 1166 | if (opendata == NULL) |
1160 | goto err_put_state_owner; | 1167 | goto err_put_state_owner; |
1161 | 1168 | ||
@@ -1187,14 +1194,14 @@ out_err: | |||
1187 | } | 1194 | } |
1188 | 1195 | ||
1189 | 1196 | ||
1190 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1197 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred) |
1191 | { | 1198 | { |
1192 | struct nfs4_exception exception = { }; | 1199 | struct nfs4_exception exception = { }; |
1193 | struct nfs4_state *res; | 1200 | struct nfs4_state *res; |
1194 | int status; | 1201 | int status; |
1195 | 1202 | ||
1196 | do { | 1203 | do { |
1197 | status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); | 1204 | status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res); |
1198 | if (status == 0) | 1205 | if (status == 0) |
1199 | break; | 1206 | break; |
1200 | /* NOTE: BAD_SEQID means the server and client disagree about the | 1207 | /* NOTE: BAD_SEQID means the server and client disagree about the |
@@ -1332,7 +1339,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1332 | case -NFS4ERR_OLD_STATEID: | 1339 | case -NFS4ERR_OLD_STATEID: |
1333 | case -NFS4ERR_BAD_STATEID: | 1340 | case -NFS4ERR_BAD_STATEID: |
1334 | case -NFS4ERR_EXPIRED: | 1341 | case -NFS4ERR_EXPIRED: |
1335 | if (calldata->arg.open_flags == 0) | 1342 | if (calldata->arg.fmode == 0) |
1336 | break; | 1343 | break; |
1337 | default: | 1344 | default: |
1338 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1345 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
@@ -1374,10 +1381,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1374 | nfs_fattr_init(calldata->res.fattr); | 1381 | nfs_fattr_init(calldata->res.fattr); |
1375 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | 1382 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { |
1376 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1383 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1377 | calldata->arg.open_flags = FMODE_READ; | 1384 | calldata->arg.fmode = FMODE_READ; |
1378 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | 1385 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { |
1379 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1386 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1380 | calldata->arg.open_flags = FMODE_WRITE; | 1387 | calldata->arg.fmode = FMODE_WRITE; |
1381 | } | 1388 | } |
1382 | calldata->timestamp = jiffies; | 1389 | calldata->timestamp = jiffies; |
1383 | rpc_call_start(task); | 1390 | rpc_call_start(task); |
@@ -1430,7 +1437,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1430 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1437 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1431 | if (calldata->arg.seqid == NULL) | 1438 | if (calldata->arg.seqid == NULL) |
1432 | goto out_free_calldata; | 1439 | goto out_free_calldata; |
1433 | calldata->arg.open_flags = 0; | 1440 | calldata->arg.fmode = 0; |
1434 | calldata->arg.bitmask = server->attr_bitmask; | 1441 | calldata->arg.bitmask = server->attr_bitmask; |
1435 | calldata->res.fattr = &calldata->fattr; | 1442 | calldata->res.fattr = &calldata->fattr; |
1436 | calldata->res.seqid = calldata->arg.seqid; | 1443 | calldata->res.seqid = calldata->arg.seqid; |
@@ -1457,13 +1464,13 @@ out: | |||
1457 | return status; | 1464 | return status; |
1458 | } | 1465 | } |
1459 | 1466 | ||
1460 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) | 1467 | static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode) |
1461 | { | 1468 | { |
1462 | struct file *filp; | 1469 | struct file *filp; |
1463 | int ret; | 1470 | int ret; |
1464 | 1471 | ||
1465 | /* If the open_intent is for execute, we have an extra check to make */ | 1472 | /* If the open_intent is for execute, we have an extra check to make */ |
1466 | if (nd->intent.open.flags & FMODE_EXEC) { | 1473 | if (fmode & FMODE_EXEC) { |
1467 | ret = nfs_may_open(state->inode, | 1474 | ret = nfs_may_open(state->inode, |
1468 | state->owner->so_cred, | 1475 | state->owner->so_cred, |
1469 | nd->intent.open.flags); | 1476 | nd->intent.open.flags); |
@@ -1479,7 +1486,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct | |||
1479 | } | 1486 | } |
1480 | ret = PTR_ERR(filp); | 1487 | ret = PTR_ERR(filp); |
1481 | out_close: | 1488 | out_close: |
1482 | nfs4_close_sync(path, state, nd->intent.open.flags); | 1489 | nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE)); |
1483 | return ret; | 1490 | return ret; |
1484 | } | 1491 | } |
1485 | 1492 | ||
@@ -1495,6 +1502,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1495 | struct rpc_cred *cred; | 1502 | struct rpc_cred *cred; |
1496 | struct nfs4_state *state; | 1503 | struct nfs4_state *state; |
1497 | struct dentry *res; | 1504 | struct dentry *res; |
1505 | fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); | ||
1498 | 1506 | ||
1499 | if (nd->flags & LOOKUP_CREATE) { | 1507 | if (nd->flags & LOOKUP_CREATE) { |
1500 | attr.ia_mode = nd->intent.open.create_mode; | 1508 | attr.ia_mode = nd->intent.open.create_mode; |
@@ -1512,7 +1520,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1512 | parent = dentry->d_parent; | 1520 | parent = dentry->d_parent; |
1513 | /* Protect against concurrent sillydeletes */ | 1521 | /* Protect against concurrent sillydeletes */ |
1514 | nfs_block_sillyrename(parent); | 1522 | nfs_block_sillyrename(parent); |
1515 | state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); | 1523 | state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred); |
1516 | put_rpccred(cred); | 1524 | put_rpccred(cred); |
1517 | if (IS_ERR(state)) { | 1525 | if (IS_ERR(state)) { |
1518 | if (PTR_ERR(state) == -ENOENT) { | 1526 | if (PTR_ERR(state) == -ENOENT) { |
@@ -1527,7 +1535,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1527 | path.dentry = res; | 1535 | path.dentry = res; |
1528 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); | 1536 | nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); |
1529 | nfs_unblock_sillyrename(parent); | 1537 | nfs_unblock_sillyrename(parent); |
1530 | nfs4_intent_set_file(nd, &path, state); | 1538 | nfs4_intent_set_file(nd, &path, state, fmode); |
1531 | return res; | 1539 | return res; |
1532 | } | 1540 | } |
1533 | 1541 | ||
@@ -1540,11 +1548,12 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1540 | }; | 1548 | }; |
1541 | struct rpc_cred *cred; | 1549 | struct rpc_cred *cred; |
1542 | struct nfs4_state *state; | 1550 | struct nfs4_state *state; |
1551 | fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE); | ||
1543 | 1552 | ||
1544 | cred = rpc_lookup_cred(); | 1553 | cred = rpc_lookup_cred(); |
1545 | if (IS_ERR(cred)) | 1554 | if (IS_ERR(cred)) |
1546 | return PTR_ERR(cred); | 1555 | return PTR_ERR(cred); |
1547 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); | 1556 | state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred); |
1548 | put_rpccred(cred); | 1557 | put_rpccred(cred); |
1549 | if (IS_ERR(state)) { | 1558 | if (IS_ERR(state)) { |
1550 | switch (PTR_ERR(state)) { | 1559 | switch (PTR_ERR(state)) { |
@@ -1561,10 +1570,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1561 | } | 1570 | } |
1562 | if (state->inode == dentry->d_inode) { | 1571 | if (state->inode == dentry->d_inode) { |
1563 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1572 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1564 | nfs4_intent_set_file(nd, &path, state); | 1573 | nfs4_intent_set_file(nd, &path, state, fmode); |
1565 | return 1; | 1574 | return 1; |
1566 | } | 1575 | } |
1567 | nfs4_close_sync(&path, state, openflags); | 1576 | nfs4_close_sync(&path, state, fmode); |
1568 | out_drop: | 1577 | out_drop: |
1569 | d_drop(dentry); | 1578 | d_drop(dentry); |
1570 | return 0; | 1579 | return 0; |
@@ -1990,6 +1999,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1990 | }; | 1999 | }; |
1991 | struct nfs4_state *state; | 2000 | struct nfs4_state *state; |
1992 | struct rpc_cred *cred; | 2001 | struct rpc_cred *cred; |
2002 | fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE); | ||
1993 | int status = 0; | 2003 | int status = 0; |
1994 | 2004 | ||
1995 | cred = rpc_lookup_cred(); | 2005 | cred = rpc_lookup_cred(); |
@@ -1997,7 +2007,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1997 | status = PTR_ERR(cred); | 2007 | status = PTR_ERR(cred); |
1998 | goto out; | 2008 | goto out; |
1999 | } | 2009 | } |
2000 | state = nfs4_do_open(dir, &path, flags, sattr, cred); | 2010 | state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred); |
2001 | d_drop(dentry); | 2011 | d_drop(dentry); |
2002 | if (IS_ERR(state)) { | 2012 | if (IS_ERR(state)) { |
2003 | status = PTR_ERR(state); | 2013 | status = PTR_ERR(state); |
@@ -2013,9 +2023,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
2013 | nfs_post_op_update_inode(state->inode, &fattr); | 2023 | nfs_post_op_update_inode(state->inode, &fattr); |
2014 | } | 2024 | } |
2015 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2025 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
2016 | status = nfs4_intent_set_file(nd, &path, state); | 2026 | status = nfs4_intent_set_file(nd, &path, state, fmode); |
2017 | else | 2027 | else |
2018 | nfs4_close_sync(&path, state, flags); | 2028 | nfs4_close_sync(&path, state, fmode); |
2019 | out_putcred: | 2029 | out_putcred: |
2020 | put_rpccred(cred); | 2030 | put_rpccred(cred); |
2021 | out: | 2031 | out: |