diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-26 17:47:34 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-08-07 15:13:19 -0400 |
commit | 45328c354e8ae16b67cb3adb72ab57459f9e5fd6 (patch) | |
tree | f0c4271a0c9f6b8d9b499f22fffc1804419d49c8 | |
parent | ba683031fae115d61c6b5f4c675cc27f6e9576d2 (diff) |
NFS: Fix NFSv4 open stateid regressions
Do not allow cached open for O_RDONLY or O_WRONLY unless the file has been
previously opened in these modes.
Also Fix the calculation of the mode in nfs4_close_prepare. We should only
issue an OPEN_DOWNGRADE if we're sure that we will still be holding the
correct open modes. This may not be the case if we've been doing delegated
opens.
Finally, there is no need to adjust the open mode bit flags in
nfs4_close_done(): that has already been done in nfs4_close_prepare().
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 16 |
1 files changed, 7 insertions, 9 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6ca2795ccd9c..62b3ae280310 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -332,11 +332,9 @@ static int can_open_cached(struct nfs4_state *state, int mode) | |||
332 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | 332 | switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { |
333 | case FMODE_READ: | 333 | case FMODE_READ: |
334 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 334 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; |
335 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
336 | break; | 335 | break; |
337 | case FMODE_WRITE: | 336 | case FMODE_WRITE: |
338 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | 337 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; |
339 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | ||
340 | break; | 338 | break; |
341 | case FMODE_READ|FMODE_WRITE: | 339 | case FMODE_READ|FMODE_WRITE: |
342 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 340 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; |
@@ -1260,7 +1258,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1260 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | 1258 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); |
1261 | switch (task->tk_status) { | 1259 | switch (task->tk_status) { |
1262 | case 0: | 1260 | case 0: |
1263 | nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); | 1261 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
1264 | renew_lease(server, calldata->timestamp); | 1262 | renew_lease(server, calldata->timestamp); |
1265 | break; | 1263 | break; |
1266 | case -NFS4ERR_STALE_STATEID: | 1264 | case -NFS4ERR_STALE_STATEID: |
@@ -1286,23 +1284,19 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1286 | .rpc_cred = state->owner->so_cred, | 1284 | .rpc_cred = state->owner->so_cred, |
1287 | }; | 1285 | }; |
1288 | int clear_rd, clear_wr, clear_rdwr; | 1286 | int clear_rd, clear_wr, clear_rdwr; |
1289 | int mode; | ||
1290 | 1287 | ||
1291 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1288 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1292 | return; | 1289 | return; |
1293 | 1290 | ||
1294 | mode = FMODE_READ|FMODE_WRITE; | ||
1295 | clear_rd = clear_wr = clear_rdwr = 0; | 1291 | clear_rd = clear_wr = clear_rdwr = 0; |
1296 | spin_lock(&state->owner->so_lock); | 1292 | spin_lock(&state->owner->so_lock); |
1297 | /* Calculate the change in open mode */ | 1293 | /* Calculate the change in open mode */ |
1298 | if (state->n_rdwr == 0) { | 1294 | if (state->n_rdwr == 0) { |
1299 | if (state->n_rdonly == 0) { | 1295 | if (state->n_rdonly == 0) { |
1300 | mode &= ~FMODE_READ; | ||
1301 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1296 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1302 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1297 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); |
1303 | } | 1298 | } |
1304 | if (state->n_wronly == 0) { | 1299 | if (state->n_wronly == 0) { |
1305 | mode &= ~FMODE_WRITE; | ||
1306 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1300 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); |
1307 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1301 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); |
1308 | } | 1302 | } |
@@ -1314,9 +1308,13 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1314 | return; | 1308 | return; |
1315 | } | 1309 | } |
1316 | nfs_fattr_init(calldata->res.fattr); | 1310 | nfs_fattr_init(calldata->res.fattr); |
1317 | if (mode != 0) | 1311 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { |
1318 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | 1312 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1319 | calldata->arg.open_flags = mode; | 1313 | calldata->arg.open_flags = FMODE_READ; |
1314 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | ||
1315 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1316 | calldata->arg.open_flags = FMODE_WRITE; | ||
1317 | } | ||
1320 | calldata->timestamp = jiffies; | 1318 | calldata->timestamp = jiffies; |
1321 | rpc_call_setup(task, &msg, 0); | 1319 | rpc_call_setup(task, &msg, 0); |
1322 | } | 1320 | } |