diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 142 |
1 files changed, 95 insertions, 47 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 693b903b48bd..5133bb18830e 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; |
@@ -1443,12 +1458,18 @@ nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state) | |||
1443 | if (delegation) | 1458 | if (delegation) |
1444 | delegation_flags = delegation->flags; | 1459 | delegation_flags = delegation->flags; |
1445 | rcu_read_unlock(); | 1460 | rcu_read_unlock(); |
1446 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) { | 1461 | switch (data->o_arg.claim) { |
1462 | default: | ||
1463 | break; | ||
1464 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | ||
1465 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | ||
1447 | pr_err_ratelimited("NFS: Broken NFSv4 server %s is " | 1466 | pr_err_ratelimited("NFS: Broken NFSv4 server %s is " |
1448 | "returning a delegation for " | 1467 | "returning a delegation for " |
1449 | "OPEN(CLAIM_DELEGATE_CUR)\n", | 1468 | "OPEN(CLAIM_DELEGATE_CUR)\n", |
1450 | clp->cl_hostname); | 1469 | clp->cl_hostname); |
1451 | } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) | 1470 | return; |
1471 | } | ||
1472 | if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0) | ||
1452 | nfs_inode_set_delegation(state->inode, | 1473 | nfs_inode_set_delegation(state->inode, |
1453 | data->owner->so_cred, | 1474 | data->owner->so_cred, |
1454 | &data->o_res); | 1475 | &data->o_res); |
@@ -1571,17 +1592,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
1571 | return opendata; | 1592 | return opendata; |
1572 | } | 1593 | } |
1573 | 1594 | ||
1574 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res) | 1595 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, |
1596 | fmode_t fmode) | ||
1575 | { | 1597 | { |
1576 | struct nfs4_state *newstate; | 1598 | struct nfs4_state *newstate; |
1577 | int ret; | 1599 | int ret; |
1578 | 1600 | ||
1579 | if ((opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR || | 1601 | 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; | 1602 | return 0; |
1586 | opendata->o_arg.open_flags = 0; | 1603 | opendata->o_arg.open_flags = 0; |
1587 | opendata->o_arg.fmode = fmode; | 1604 | opendata->o_arg.fmode = fmode; |
@@ -1597,14 +1614,14 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
1597 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1614 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
1598 | if (IS_ERR(newstate)) | 1615 | if (IS_ERR(newstate)) |
1599 | return PTR_ERR(newstate); | 1616 | return PTR_ERR(newstate); |
1617 | if (newstate != opendata->state) | ||
1618 | ret = -ESTALE; | ||
1600 | nfs4_close_state(newstate, fmode); | 1619 | nfs4_close_state(newstate, fmode); |
1601 | *res = newstate; | 1620 | return ret; |
1602 | return 0; | ||
1603 | } | 1621 | } |
1604 | 1622 | ||
1605 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | 1623 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) |
1606 | { | 1624 | { |
1607 | struct nfs4_state *newstate; | ||
1608 | int ret; | 1625 | int ret; |
1609 | 1626 | ||
1610 | /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ | 1627 | /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ |
@@ -1615,27 +1632,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1615 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1632 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1616 | clear_bit(NFS_OPEN_STATE, &state->flags); | 1633 | clear_bit(NFS_OPEN_STATE, &state->flags); |
1617 | smp_rmb(); | 1634 | smp_rmb(); |
1618 | if (state->n_rdwr != 0) { | 1635 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); |
1619 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); | 1636 | if (ret != 0) |
1620 | if (ret != 0) | 1637 | return ret; |
1621 | return ret; | 1638 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE); |
1622 | if (newstate != state) | 1639 | if (ret != 0) |
1623 | return -ESTALE; | 1640 | return ret; |
1624 | } | 1641 | ret = nfs4_open_recover_helper(opendata, FMODE_READ); |
1625 | if (state->n_wronly != 0) { | 1642 | if (ret != 0) |
1626 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); | 1643 | 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 | /* | 1644 | /* |
1640 | * We may have performed cached opens for all three recoveries. | 1645 | * We may have performed cached opens for all three recoveries. |
1641 | * Check if we need to update the current stateid. | 1646 | * Check if we need to update the current stateid. |
@@ -1759,18 +1764,35 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
1759 | return err; | 1764 | return err; |
1760 | } | 1765 | } |
1761 | 1766 | ||
1762 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | 1767 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, |
1768 | struct nfs4_state *state, const nfs4_stateid *stateid, | ||
1769 | fmode_t type) | ||
1763 | { | 1770 | { |
1764 | struct nfs_server *server = NFS_SERVER(state->inode); | 1771 | struct nfs_server *server = NFS_SERVER(state->inode); |
1765 | struct nfs4_opendata *opendata; | 1772 | struct nfs4_opendata *opendata; |
1766 | int err; | 1773 | int err = 0; |
1767 | 1774 | ||
1768 | opendata = nfs4_open_recoverdata_alloc(ctx, state, | 1775 | opendata = nfs4_open_recoverdata_alloc(ctx, state, |
1769 | NFS4_OPEN_CLAIM_DELEG_CUR_FH); | 1776 | NFS4_OPEN_CLAIM_DELEG_CUR_FH); |
1770 | if (IS_ERR(opendata)) | 1777 | if (IS_ERR(opendata)) |
1771 | return PTR_ERR(opendata); | 1778 | return PTR_ERR(opendata); |
1772 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); | 1779 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); |
1773 | err = nfs4_open_recover(opendata, state); | 1780 | write_seqlock(&state->seqlock); |
1781 | nfs4_stateid_copy(&state->stateid, &state->open_stateid); | ||
1782 | write_sequnlock(&state->seqlock); | ||
1783 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
1784 | switch (type & (FMODE_READ|FMODE_WRITE)) { | ||
1785 | case FMODE_READ|FMODE_WRITE: | ||
1786 | case FMODE_WRITE: | ||
1787 | err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); | ||
1788 | if (err) | ||
1789 | break; | ||
1790 | err = nfs4_open_recover_helper(opendata, FMODE_WRITE); | ||
1791 | if (err) | ||
1792 | break; | ||
1793 | case FMODE_READ: | ||
1794 | err = nfs4_open_recover_helper(opendata, FMODE_READ); | ||
1795 | } | ||
1774 | nfs4_opendata_put(opendata); | 1796 | nfs4_opendata_put(opendata); |
1775 | return nfs4_handle_delegation_recall_error(server, state, stateid, err); | 1797 | return nfs4_handle_delegation_recall_error(server, state, stateid, err); |
1776 | } | 1798 | } |
@@ -1850,6 +1872,8 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
1850 | data->rpc_done = 0; | 1872 | data->rpc_done = 0; |
1851 | data->rpc_status = 0; | 1873 | data->rpc_status = 0; |
1852 | data->timestamp = jiffies; | 1874 | data->timestamp = jiffies; |
1875 | if (data->is_recover) | ||
1876 | nfs4_set_sequence_privileged(&data->c_arg.seq_args); | ||
1853 | task = rpc_run_task(&task_setup_data); | 1877 | task = rpc_run_task(&task_setup_data); |
1854 | if (IS_ERR(task)) | 1878 | if (IS_ERR(task)) |
1855 | return PTR_ERR(task); | 1879 | return PTR_ERR(task); |
@@ -2645,6 +2669,15 @@ out: | |||
2645 | return err; | 2669 | return err; |
2646 | } | 2670 | } |
2647 | 2671 | ||
2672 | static bool | ||
2673 | nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task) | ||
2674 | { | ||
2675 | if (inode == NULL || !nfs_have_layout(inode)) | ||
2676 | return false; | ||
2677 | |||
2678 | return pnfs_wait_on_layoutreturn(inode, task); | ||
2679 | } | ||
2680 | |||
2648 | struct nfs4_closedata { | 2681 | struct nfs4_closedata { |
2649 | struct inode *inode; | 2682 | struct inode *inode; |
2650 | struct nfs4_state *state; | 2683 | struct nfs4_state *state; |
@@ -2763,6 +2796,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
2763 | goto out_no_action; | 2796 | goto out_no_action; |
2764 | } | 2797 | } |
2765 | 2798 | ||
2799 | if (nfs4_wait_on_layoutreturn(inode, task)) { | ||
2800 | nfs_release_seqid(calldata->arg.seqid); | ||
2801 | goto out_wait; | ||
2802 | } | ||
2803 | |||
2766 | if (calldata->arg.fmode == 0) | 2804 | if (calldata->arg.fmode == 0) |
2767 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | 2805 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; |
2768 | if (calldata->roc) | 2806 | if (calldata->roc) |
@@ -5308,6 +5346,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
5308 | 5346 | ||
5309 | d_data = (struct nfs4_delegreturndata *)data; | 5347 | d_data = (struct nfs4_delegreturndata *)data; |
5310 | 5348 | ||
5349 | if (nfs4_wait_on_layoutreturn(d_data->inode, task)) | ||
5350 | return; | ||
5351 | |||
5311 | if (d_data->roc) | 5352 | if (d_data->roc) |
5312 | pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier); | 5353 | pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier); |
5313 | 5354 | ||
@@ -7800,39 +7841,46 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
7800 | dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n", | 7841 | dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n", |
7801 | __func__, delay); | 7842 | __func__, delay); |
7802 | rpc_delay(task, delay); | 7843 | rpc_delay(task, delay); |
7803 | task->tk_status = 0; | 7844 | /* Do not call nfs4_async_handle_error() */ |
7804 | rpc_restart_call_prepare(task); | 7845 | goto out_restart; |
7805 | goto out; /* Do not call nfs4_async_handle_error() */ | ||
7806 | } | 7846 | } |
7807 | break; | 7847 | break; |
7808 | case -NFS4ERR_EXPIRED: | 7848 | case -NFS4ERR_EXPIRED: |
7809 | case -NFS4ERR_BAD_STATEID: | 7849 | case -NFS4ERR_BAD_STATEID: |
7810 | spin_lock(&inode->i_lock); | 7850 | spin_lock(&inode->i_lock); |
7811 | lo = NFS_I(inode)->layout; | 7851 | if (nfs4_stateid_match(&lgp->args.stateid, |
7812 | if (!lo || list_empty(&lo->plh_segs)) { | 7852 | &lgp->args.ctx->state->stateid)) { |
7813 | spin_unlock(&inode->i_lock); | 7853 | spin_unlock(&inode->i_lock); |
7814 | /* If the open stateid was bad, then recover it. */ | 7854 | /* If the open stateid was bad, then recover it. */ |
7815 | state = lgp->args.ctx->state; | 7855 | state = lgp->args.ctx->state; |
7816 | } else { | 7856 | break; |
7857 | } | ||
7858 | lo = NFS_I(inode)->layout; | ||
7859 | if (lo && nfs4_stateid_match(&lgp->args.stateid, | ||
7860 | &lo->plh_stateid)) { | ||
7817 | LIST_HEAD(head); | 7861 | LIST_HEAD(head); |
7818 | 7862 | ||
7819 | /* | 7863 | /* |
7820 | * Mark the bad layout state as invalid, then retry | 7864 | * Mark the bad layout state as invalid, then retry |
7821 | * with the current stateid. | 7865 | * with the current stateid. |
7822 | */ | 7866 | */ |
7867 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); | ||
7823 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL); | 7868 | pnfs_mark_matching_lsegs_invalid(lo, &head, NULL); |
7824 | spin_unlock(&inode->i_lock); | 7869 | spin_unlock(&inode->i_lock); |
7825 | pnfs_free_lseg_list(&head); | 7870 | pnfs_free_lseg_list(&head); |
7826 | 7871 | } else | |
7827 | task->tk_status = 0; | 7872 | spin_unlock(&inode->i_lock); |
7828 | rpc_restart_call_prepare(task); | 7873 | goto out_restart; |
7829 | } | ||
7830 | } | 7874 | } |
7831 | if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) | 7875 | if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) |
7832 | rpc_restart_call_prepare(task); | 7876 | goto out_restart; |
7833 | out: | 7877 | out: |
7834 | dprintk("<-- %s\n", __func__); | 7878 | dprintk("<-- %s\n", __func__); |
7835 | return; | 7879 | return; |
7880 | out_restart: | ||
7881 | task->tk_status = 0; | ||
7882 | rpc_restart_call_prepare(task); | ||
7883 | return; | ||
7836 | out_overflow: | 7884 | out_overflow: |
7837 | task->tk_status = -EOVERFLOW; | 7885 | task->tk_status = -EOVERFLOW; |
7838 | goto out; | 7886 | goto out; |