aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c142
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
1130static 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
1130static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) 1145static 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
1574static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res) 1595static 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
1605static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) 1623static 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
1762int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) 1767int 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
2672static bool
2673nfs4_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
2648struct nfs4_closedata { 2681struct 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;
7833out: 7877out:
7834 dprintk("<-- %s\n", __func__); 7878 dprintk("<-- %s\n", __func__);
7835 return; 7879 return;
7880out_restart:
7881 task->tk_status = 0;
7882 rpc_restart_call_prepare(task);
7883 return;
7836out_overflow: 7884out_overflow:
7837 task->tk_status = -EOVERFLOW; 7885 task->tk_status = -EOVERFLOW;
7838 goto out; 7886 goto out;