aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2009-12-08 08:33:16 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-12-08 08:33:16 -0500
commit88069f77e1ac580a495762ce7a631c251c52cb90 (patch)
treee30011cdb39fa167370b4d35bbc9b3cc04a4bc27 /fs/nfs
parent74e7bb73a3e0d15a7db10b0f2b2efdeeef36609e (diff)
NFSv41: Fix a potential state leakage when restarting nfs4_close_prepare
Currently, if the call to nfs4_setup_sequence() in nfs4_close_prepare fails, any later retries will fail to launch an RPC call, due to the fact that the &state->flags will have been cleared. Ditto if nfs4_close_done() triggers a call to the NFSv4.1 version of nfs_restart_rpc(). We therefore move the actual clearing of the state->flags to nfs4_close_done(), when we know that the RPC call was successful. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c52
1 files changed, 35 insertions, 17 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index cdf17d628450..9f5f11ecfd93 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -761,13 +761,16 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
761 goto out; 761 goto out;
762 switch (mode & (FMODE_READ|FMODE_WRITE)) { 762 switch (mode & (FMODE_READ|FMODE_WRITE)) {
763 case FMODE_READ: 763 case FMODE_READ:
764 ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; 764 ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
765 && state->n_rdonly != 0;
765 break; 766 break;
766 case FMODE_WRITE: 767 case FMODE_WRITE:
767 ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; 768 ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0
769 && state->n_wronly != 0;
768 break; 770 break;
769 case FMODE_READ|FMODE_WRITE: 771 case FMODE_READ|FMODE_WRITE:
770 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; 772 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0
773 && state->n_rdwr != 0;
771 } 774 }
772out: 775out:
773 return ret; 776 return ret;
@@ -1711,6 +1714,18 @@ static void nfs4_free_closedata(void *data)
1711 kfree(calldata); 1714 kfree(calldata);
1712} 1715}
1713 1716
1717static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
1718 fmode_t fmode)
1719{
1720 spin_lock(&state->owner->so_lock);
1721 if (!(fmode & FMODE_READ))
1722 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1723 if (!(fmode & FMODE_WRITE))
1724 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1725 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1726 spin_unlock(&state->owner->so_lock);
1727}
1728
1714static void nfs4_close_done(struct rpc_task *task, void *data) 1729static void nfs4_close_done(struct rpc_task *task, void *data)
1715{ 1730{
1716 struct nfs4_closedata *calldata = data; 1731 struct nfs4_closedata *calldata = data;
@@ -1727,6 +1742,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
1727 case 0: 1742 case 0:
1728 nfs_set_open_stateid(state, &calldata->res.stateid, 0); 1743 nfs_set_open_stateid(state, &calldata->res.stateid, 0);
1729 renew_lease(server, calldata->timestamp); 1744 renew_lease(server, calldata->timestamp);
1745 nfs4_close_clear_stateid_flags(state,
1746 calldata->arg.fmode);
1730 break; 1747 break;
1731 case -NFS4ERR_STALE_STATEID: 1748 case -NFS4ERR_STALE_STATEID:
1732 case -NFS4ERR_OLD_STATEID: 1749 case -NFS4ERR_OLD_STATEID:
@@ -1747,38 +1764,39 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
1747{ 1764{
1748 struct nfs4_closedata *calldata = data; 1765 struct nfs4_closedata *calldata = data;
1749 struct nfs4_state *state = calldata->state; 1766 struct nfs4_state *state = calldata->state;
1750 int clear_rd, clear_wr, clear_rdwr; 1767 int call_close = 0;
1751 1768
1752 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) 1769 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
1753 return; 1770 return;
1754 1771
1755 clear_rd = clear_wr = clear_rdwr = 0; 1772 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
1773 calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
1756 spin_lock(&state->owner->so_lock); 1774 spin_lock(&state->owner->so_lock);
1757 /* Calculate the change in open mode */ 1775 /* Calculate the change in open mode */
1758 if (state->n_rdwr == 0) { 1776 if (state->n_rdwr == 0) {
1759 if (state->n_rdonly == 0) { 1777 if (state->n_rdonly == 0) {
1760 clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); 1778 call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
1761 clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); 1779 call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
1780 calldata->arg.fmode &= ~FMODE_READ;
1762 } 1781 }
1763 if (state->n_wronly == 0) { 1782 if (state->n_wronly == 0) {
1764 clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); 1783 call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
1765 clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); 1784 call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
1785 calldata->arg.fmode &= ~FMODE_WRITE;
1766 } 1786 }
1767 } 1787 }
1768 spin_unlock(&state->owner->so_lock); 1788 spin_unlock(&state->owner->so_lock);
1769 if (!clear_rd && !clear_wr && !clear_rdwr) { 1789
1790 if (!call_close) {
1770 /* Note: exit _without_ calling nfs4_close_done */ 1791 /* Note: exit _without_ calling nfs4_close_done */
1771 task->tk_action = NULL; 1792 task->tk_action = NULL;
1772 return; 1793 return;
1773 } 1794 }
1795
1796 if (calldata->arg.fmode == 0)
1797 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
1798
1774 nfs_fattr_init(calldata->res.fattr); 1799 nfs_fattr_init(calldata->res.fattr);
1775 if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) {
1776 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
1777 calldata->arg.fmode = FMODE_READ;
1778 } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) {
1779 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
1780 calldata->arg.fmode = FMODE_WRITE;
1781 }
1782 calldata->timestamp = jiffies; 1800 calldata->timestamp = jiffies;
1783 if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, 1801 if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client,
1784 &calldata->arg.seq_args, &calldata->res.seq_res, 1802 &calldata->arg.seq_args, &calldata->res.seq_res,