diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 127 |
1 files changed, 82 insertions, 45 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 693b903b48bd..f93b9cdb4934 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -1127,6 +1127,21 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
| 1127 | return ret; | 1127 | return ret; |
| 1128 | } | 1128 | } |
| 1129 | 1129 | ||
| 1130 | static bool nfs4_mode_match_open_stateid(struct nfs4_state *state, | ||
| 1131 | fmode_t fmode) | ||
| 1132 | { | ||
| 1133 | switch(fmode & (FMODE_READ|FMODE_WRITE)) { | ||
| 1134 | case FMODE_READ|FMODE_WRITE: | ||
| 1135 | return state->n_rdwr != 0; | ||
| 1136 | case FMODE_WRITE: | ||
| 1137 | return state->n_wronly != 0; | ||
| 1138 | case FMODE_READ: | ||
| 1139 | return state->n_rdonly != 0; | ||
| 1140 | } | ||
| 1141 | WARN_ON_ONCE(1); | ||
| 1142 | return false; | ||
| 1143 | } | ||
| 1144 | |||
| 1130 | static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) | 1145 | static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) |
| 1131 | { | 1146 | { |
| 1132 | int ret = 0; | 1147 | int ret = 0; |
| @@ -1571,17 +1586,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
| 1571 | return opendata; | 1586 | return opendata; |
| 1572 | } | 1587 | } |
| 1573 | 1588 | ||
| 1574 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res) | 1589 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, |
| 1590 | fmode_t fmode) | ||
| 1575 | { | 1591 | { |
| 1576 | struct nfs4_state *newstate; | 1592 | struct nfs4_state *newstate; |
| 1577 | int ret; | 1593 | int ret; |
| 1578 | 1594 | ||
| 1579 | if ((opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR || | 1595 | if (!nfs4_mode_match_open_stateid(opendata->state, fmode)) |
| 1580 | opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEG_CUR_FH) && | ||
| 1581 | (opendata->o_arg.u.delegation_type & fmode) != fmode) | ||
| 1582 | /* This mode can't have been delegated, so we must have | ||
| 1583 | * a valid open_stateid to cover it - not need to reclaim. | ||
| 1584 | */ | ||
| 1585 | return 0; | 1596 | return 0; |
| 1586 | opendata->o_arg.open_flags = 0; | 1597 | opendata->o_arg.open_flags = 0; |
| 1587 | opendata->o_arg.fmode = fmode; | 1598 | opendata->o_arg.fmode = fmode; |
| @@ -1597,14 +1608,14 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
| 1597 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1608 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
| 1598 | if (IS_ERR(newstate)) | 1609 | if (IS_ERR(newstate)) |
| 1599 | return PTR_ERR(newstate); | 1610 | return PTR_ERR(newstate); |
| 1611 | if (newstate != opendata->state) | ||
| 1612 | ret = -ESTALE; | ||
| 1600 | nfs4_close_state(newstate, fmode); | 1613 | nfs4_close_state(newstate, fmode); |
| 1601 | *res = newstate; | 1614 | return ret; |
| 1602 | return 0; | ||
| 1603 | } | 1615 | } |
| 1604 | 1616 | ||
| 1605 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | 1617 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) |
| 1606 | { | 1618 | { |
| 1607 | struct nfs4_state *newstate; | ||
| 1608 | int ret; | 1619 | int ret; |
| 1609 | 1620 | ||
| 1610 | /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ | 1621 | /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ |
| @@ -1615,27 +1626,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
| 1615 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1626 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
| 1616 | clear_bit(NFS_OPEN_STATE, &state->flags); | 1627 | clear_bit(NFS_OPEN_STATE, &state->flags); |
| 1617 | smp_rmb(); | 1628 | smp_rmb(); |
| 1618 | if (state->n_rdwr != 0) { | 1629 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); |
| 1619 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); | 1630 | if (ret != 0) |
| 1620 | if (ret != 0) | 1631 | return ret; |
| 1621 | return ret; | 1632 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE); |
| 1622 | if (newstate != state) | 1633 | if (ret != 0) |
| 1623 | return -ESTALE; | 1634 | return ret; |
| 1624 | } | 1635 | ret = nfs4_open_recover_helper(opendata, FMODE_READ); |
| 1625 | if (state->n_wronly != 0) { | 1636 | if (ret != 0) |
| 1626 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); | 1637 | return ret; |
| 1627 | if (ret != 0) | ||
| 1628 | return ret; | ||
| 1629 | if (newstate != state) | ||
| 1630 | return -ESTALE; | ||
| 1631 | } | ||
| 1632 | if (state->n_rdonly != 0) { | ||
| 1633 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); | ||
| 1634 | if (ret != 0) | ||
| 1635 | return ret; | ||
| 1636 | if (newstate != state) | ||
| 1637 | return -ESTALE; | ||
| 1638 | } | ||
| 1639 | /* | 1638 | /* |
| 1640 | * We may have performed cached opens for all three recoveries. | 1639 | * We may have performed cached opens for all three recoveries. |
| 1641 | * Check if we need to update the current stateid. | 1640 | * Check if we need to update the current stateid. |
| @@ -1759,18 +1758,32 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
| 1759 | return err; | 1758 | return err; |
| 1760 | } | 1759 | } |
| 1761 | 1760 | ||
| 1762 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | 1761 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, |
| 1762 | struct nfs4_state *state, const nfs4_stateid *stateid, | ||
| 1763 | fmode_t type) | ||
| 1763 | { | 1764 | { |
| 1764 | struct nfs_server *server = NFS_SERVER(state->inode); | 1765 | struct nfs_server *server = NFS_SERVER(state->inode); |
| 1765 | struct nfs4_opendata *opendata; | 1766 | struct nfs4_opendata *opendata; |
| 1766 | int err; | 1767 | int err = 0; |
| 1767 | 1768 | ||
| 1768 | opendata = nfs4_open_recoverdata_alloc(ctx, state, | 1769 | opendata = nfs4_open_recoverdata_alloc(ctx, state, |
| 1769 | NFS4_OPEN_CLAIM_DELEG_CUR_FH); | 1770 | NFS4_OPEN_CLAIM_DELEG_CUR_FH); |
| 1770 | if (IS_ERR(opendata)) | 1771 | if (IS_ERR(opendata)) |
| 1771 | return PTR_ERR(opendata); | 1772 | return PTR_ERR(opendata); |
| 1772 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); | 1773 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); |
| 1773 | err = nfs4_open_recover(opendata, state); | 1774 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
| 1775 | switch (type & (FMODE_READ|FMODE_WRITE)) { | ||
| 1776 | case FMODE_READ|FMODE_WRITE: | ||
| 1777 | case FMODE_WRITE: | ||
| 1778 | err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); | ||
| 1779 | if (err) | ||
| 1780 | break; | ||
| 1781 | err = nfs4_open_recover_helper(opendata, FMODE_WRITE); | ||
| 1782 | if (err) | ||
| 1783 | break; | ||
| 1784 | case FMODE_READ: | ||
| 1785 | err = nfs4_open_recover_helper(opendata, FMODE_READ); | ||
| 1786 | } | ||
| 1774 | nfs4_opendata_put(opendata); | 1787 | nfs4_opendata_put(opendata); |
| 1775 | return nfs4_handle_delegation_recall_error(server, state, stateid, err); | 1788 | return nfs4_handle_delegation_recall_error(server, state, stateid, err); |
| 1776 | } | 1789 | } |
| @@ -2645,6 +2658,15 @@ out: | |||
| 2645 | return err; | 2658 | return err; |
| 2646 | } | 2659 | } |
| 2647 | 2660 | ||
| 2661 | static bool | ||
| 2662 | nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task) | ||
| 2663 | { | ||
| 2664 | if (inode == NULL || !nfs_have_layout(inode)) | ||
| 2665 | return false; | ||
| 2666 | |||
| 2667 | return pnfs_wait_on_layoutreturn(inode, task); | ||
| 2668 | } | ||
| 2669 | |||
| 2648 | struct nfs4_closedata { | 2670 | struct nfs4_closedata { |
| 2649 | struct inode *inode; | 2671 | struct inode *inode; |
| 2650 | struct nfs4_state *state; | 2672 | struct nfs4_state *state; |
| @@ -2763,6 +2785,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 2763 | goto out_no_action; | 2785 | goto out_no_action; |
| 2764 | } | 2786 | } |
| 2765 | 2787 | ||
| 2788 | if (nfs4_wait_on_layoutreturn(inode, task)) { | ||
| 2789 | nfs_release_seqid(calldata->arg.seqid); | ||
| 2790 | goto out_wait; | ||
| 2791 | } | ||
| 2792 | |||
| 2766 | if (calldata->arg.fmode == 0) | 2793 | if (calldata->arg.fmode == 0) |
| 2767 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | 2794 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; |
| 2768 | if (calldata->roc) | 2795 | if (calldata->roc) |
| @@ -5308,6 +5335,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
| 5308 | 5335 | ||
| 5309 | d_data = (struct nfs4_delegreturndata *)data; | 5336 | d_data = (struct nfs4_delegreturndata *)data; |
| 5310 | 5337 | ||
| 5338 | if (nfs4_wait_on_layoutreturn(d_data->inode, task)) | ||
| 5339 | return; | ||
| 5340 | |||
| 5311 | if (d_data->roc) | 5341 | if (d_data->roc) |
| 5312 | pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier); | 5342 | pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier); |
| 5313 | 5343 | ||
| @@ -7800,39 +7830,46 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
| 7800 | dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n", | 7830 | dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n", |
| 7801 | __func__, delay); | 7831 | __func__, delay); |
| 7802 | rpc_delay(task, delay); | 7832 | rpc_delay(task, delay); |
| 7803 | task->tk_status = 0; | 7833 | /* Do not call nfs4_async_handle_error() */ |
| 7804 | rpc_restart_call_prepare(task); | 7834 | goto out_restart; |
| 7805 | goto out; /* Do not call nfs4_async_handle_error() */ | ||
| 7806 | } | 7835 | } |
| 7807 | break; | 7836 | break; |
| 7808 | case -NFS4ERR_EXPIRED: | 7837 | case -NFS4ERR_EXPIRED: |
| 7809 | case -NFS4ERR_BAD_STATEID: | 7838 | case -NFS4ERR_BAD_STATEID: |
| 7810 | spin_lock(&inode->i_lock); | 7839 | spin_lock(&inode->i_lock); |
| 7811 | lo = NFS_I(inode)->layout; | 7840 | if (nfs4_stateid_match(&lgp->args.stateid, |
| 7812 | if (!lo || list_empty(&lo->plh_segs)) { | 7841 | &lgp->args.ctx->state->stateid)) { |
| 7813 | spin_unlock(&inode->i_lock); | 7842 | spin_unlock(&inode->i_lock); |
| 7814 | /* If the open stateid was bad, then recover it. */ | 7843 | /* If the open stateid was bad, then recover it. */ |
| 7815 | state = lgp->args.ctx->state; | 7844 | state = lgp->args.ctx->state; |
| 7816 | } else { | 7845 | break; |
| 7846 | } | ||
| 7847 | lo = NFS_I(inode)->layout; | ||
| 7848 | if (lo && nfs4_stateid_match(&lgp->args.stateid, | ||
| 7849 | &lo->plh_stateid)) { | ||
| 7817 | LIST_HEAD(head); | 7850 | LIST_HEAD(head); |
| 7818 | 7851 | ||
| 7819 | /* | 7852 | /* |
| 7820 | * Mark the bad layout state as invalid, then retry | 7853 | * Mark the bad layout state as invalid, then retry |
| 7821 | * with the current stateid. | 7854 | * with the current stateid. |
| 7822 | */ | 7855 | */ |
| 7856 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); | ||
| 7823 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL); | 7857 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL); |
| 7824 | spin_unlock(&inode->i_lock); | 7858 | spin_unlock(&inode->i_lock); |
| 7825 | pnfs_free_lseg_list(&head); | 7859 | pnfs_free_lseg_list(&head); |
| 7826 | 7860 | } else | |
| 7827 | task->tk_status = 0; | 7861 | spin_unlock(&inode->i_lock); |
| 7828 | rpc_restart_call_prepare(task); | 7862 | goto out_restart; |
| 7829 | } | ||
| 7830 | } | 7863 | } |
| 7831 | if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) | 7864 | if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) |
| 7832 | rpc_restart_call_prepare(task); | 7865 | goto out_restart; |
| 7833 | out: | 7866 | out: |
| 7834 | dprintk("<-- %s\n", __func__); | 7867 | dprintk("<-- %s\n", __func__); |
| 7835 | return; | 7868 | return; |
| 7869 | out_restart: | ||
| 7870 | task->tk_status = 0; | ||
| 7871 | rpc_restart_call_prepare(task); | ||
| 7872 | return; | ||
| 7836 | out_overflow: | 7873 | out_overflow: |
| 7837 | task->tk_status = -EOVERFLOW; | 7874 | task->tk_status = -EOVERFLOW; |
| 7838 | goto out; | 7875 | goto out; |
