Skip to content

Commit aee7af3

Browse files
committed
NFSv4: Fix problems with close in the presence of a delegation
In the presence of delegations, we can no longer assume that the state->n_rdwr, state->n_rdonly, state->n_wronly reflect the open stateid share mode, and so we need to calculate the initial value for calldata->arg.fmode using the state->flags. Reported-by: James Drews <[email protected]> Fixes: 88069f7 (NFSv41: Fix a potential state leakage when...) Cc: [email protected] # 2.6.33+ Signed-off-by: Trond Myklebust <[email protected]>
1 parent 52addcf commit aee7af3

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

fs/nfs/nfs4proc.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,25 +2601,32 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
26012601
struct nfs4_closedata *calldata = data;
26022602
struct nfs4_state *state = calldata->state;
26032603
struct inode *inode = calldata->inode;
2604+
bool is_rdonly, is_wronly, is_rdwr;
26042605
int call_close = 0;
26052606

26062607
dprintk("%s: begin!\n", __func__);
26072608
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
26082609
goto out_wait;
26092610

26102611
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
2611-
calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
26122612
spin_lock(&state->owner->so_lock);
2613+
is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
2614+
is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
2615+
is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
2616+
/* Calculate the current open share mode */
2617+
calldata->arg.fmode = 0;
2618+
if (is_rdonly || is_rdwr)
2619+
calldata->arg.fmode |= FMODE_READ;
2620+
if (is_wronly || is_rdwr)
2621+
calldata->arg.fmode |= FMODE_WRITE;
26132622
/* Calculate the change in open mode */
26142623
if (state->n_rdwr == 0) {
26152624
if (state->n_rdonly == 0) {
2616-
call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
2617-
call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
2625+
call_close |= is_rdonly || is_rdwr;
26182626
calldata->arg.fmode &= ~FMODE_READ;
26192627
}
26202628
if (state->n_wronly == 0) {
2621-
call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
2622-
call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
2629+
call_close |= is_wronly || is_rdwr;
26232630
calldata->arg.fmode &= ~FMODE_WRITE;
26242631
}
26252632
}

0 commit comments

Comments
 (0)