diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-02-11 10:41:07 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-02-19 21:21:07 -0500 |
commit | 226056c5c312b3dac16ff6d4f40208f95c070b6a (patch) | |
tree | 0c1869e6f68abffd43dbef69fa62673373fc27df /fs/nfs/nfs4proc.c | |
parent | 78096ccac561ce2d89fbff1d1aa451bf4090a1a2 (diff) |
NFSv4: Use correct locking when updating nfs4_state in nfs4_close_done
The stateid and state->flags should be updated atomically under
protection of the state->seqlock.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 96e0bd42f38c..1f593a0bd938 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1149,6 +1149,38 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state, | |||
1149 | return false; | 1149 | return false; |
1150 | } | 1150 | } |
1151 | 1151 | ||
1152 | static void nfs_clear_open_stateid_locked(struct nfs4_state *state, | ||
1153 | nfs4_stateid *stateid, fmode_t fmode) | ||
1154 | { | ||
1155 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1156 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { | ||
1157 | case FMODE_WRITE: | ||
1158 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1159 | break; | ||
1160 | case FMODE_READ: | ||
1161 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1162 | break; | ||
1163 | case 0: | ||
1164 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1165 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1166 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
1167 | } | ||
1168 | if (stateid == NULL) | ||
1169 | return; | ||
1170 | if (!nfs_need_update_open_stateid(state, stateid)) | ||
1171 | return; | ||
1172 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | ||
1173 | nfs4_stateid_copy(&state->stateid, stateid); | ||
1174 | nfs4_stateid_copy(&state->open_stateid, stateid); | ||
1175 | } | ||
1176 | |||
1177 | static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | ||
1178 | { | ||
1179 | write_seqlock(&state->seqlock); | ||
1180 | nfs_clear_open_stateid_locked(state, stateid, fmode); | ||
1181 | write_sequnlock(&state->seqlock); | ||
1182 | } | ||
1183 | |||
1152 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | 1184 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) |
1153 | { | 1185 | { |
1154 | switch (fmode) { | 1186 | switch (fmode) { |
@@ -1168,13 +1200,6 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
1168 | nfs4_stateid_copy(&state->open_stateid, stateid); | 1200 | nfs4_stateid_copy(&state->open_stateid, stateid); |
1169 | } | 1201 | } |
1170 | 1202 | ||
1171 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | ||
1172 | { | ||
1173 | write_seqlock(&state->seqlock); | ||
1174 | nfs_set_open_stateid_locked(state, stateid, fmode); | ||
1175 | write_sequnlock(&state->seqlock); | ||
1176 | } | ||
1177 | |||
1178 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) | 1203 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) |
1179 | { | 1204 | { |
1180 | /* | 1205 | /* |
@@ -2489,26 +2514,6 @@ static void nfs4_free_closedata(void *data) | |||
2489 | kfree(calldata); | 2514 | kfree(calldata); |
2490 | } | 2515 | } |
2491 | 2516 | ||
2492 | static void nfs4_close_clear_stateid_flags(struct nfs4_state *state, | ||
2493 | fmode_t fmode) | ||
2494 | { | ||
2495 | spin_lock(&state->owner->so_lock); | ||
2496 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
2497 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { | ||
2498 | case FMODE_WRITE: | ||
2499 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2500 | break; | ||
2501 | case FMODE_READ: | ||
2502 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2503 | break; | ||
2504 | case 0: | ||
2505 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2506 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2507 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
2508 | } | ||
2509 | spin_unlock(&state->owner->so_lock); | ||
2510 | } | ||
2511 | |||
2512 | static void nfs4_close_done(struct rpc_task *task, void *data) | 2517 | static void nfs4_close_done(struct rpc_task *task, void *data) |
2513 | { | 2518 | { |
2514 | struct nfs4_closedata *calldata = data; | 2519 | struct nfs4_closedata *calldata = data; |
@@ -2527,9 +2532,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2527 | if (calldata->roc) | 2532 | if (calldata->roc) |
2528 | pnfs_roc_set_barrier(state->inode, | 2533 | pnfs_roc_set_barrier(state->inode, |
2529 | calldata->roc_barrier); | 2534 | calldata->roc_barrier); |
2530 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 2535 | nfs_clear_open_stateid(state, &calldata->res.stateid, 0); |
2531 | renew_lease(server, calldata->timestamp); | 2536 | renew_lease(server, calldata->timestamp); |
2532 | break; | 2537 | goto out_release; |
2533 | case -NFS4ERR_ADMIN_REVOKED: | 2538 | case -NFS4ERR_ADMIN_REVOKED: |
2534 | case -NFS4ERR_STALE_STATEID: | 2539 | case -NFS4ERR_STALE_STATEID: |
2535 | case -NFS4ERR_OLD_STATEID: | 2540 | case -NFS4ERR_OLD_STATEID: |
@@ -2543,7 +2548,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2543 | goto out_release; | 2548 | goto out_release; |
2544 | } | 2549 | } |
2545 | } | 2550 | } |
2546 | nfs4_close_clear_stateid_flags(state, calldata->arg.fmode); | 2551 | nfs_clear_open_stateid(state, NULL, calldata->arg.fmode); |
2547 | out_release: | 2552 | out_release: |
2548 | nfs_release_seqid(calldata->arg.seqid); | 2553 | nfs_release_seqid(calldata->arg.seqid); |
2549 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 2554 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |