diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-03 03:55:13 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-06 14:58:43 -0500 |
commit | e761692381f294ea079d2e869fcd7c0afc79e394 (patch) | |
tree | 34ebc00c001cddc94866936c460547d311e5dabb | |
parent | cdd4e68b5f0ed12c64b3e2be83655d2a47588a74 (diff) |
NFSv4: Make nfs4_state track O_RDWR, O_RDONLY and O_WRONLY separately
A closer reading of RFC3530 reveals that OPEN_DOWNGRADE must always
specify a access modes that have been the argument of a previous OPEN
operation.
IOW: doing OPEN(O_RDWR) and then OPEN_DOWNGRADE(O_WRONLY) is forbidden
unless the user called OPEN(O_WRONLY)
In order to fix that, we really need to track the three possible open
states separately.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4_fs.h | 5 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 34 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 31 |
3 files changed, 42 insertions, 28 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index b7f262dcb6e3..4ad5981f9375 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -182,8 +182,9 @@ struct nfs4_state { | |||
182 | 182 | ||
183 | nfs4_stateid stateid; | 183 | nfs4_stateid stateid; |
184 | 184 | ||
185 | unsigned int nreaders; | 185 | unsigned int n_rdonly; |
186 | unsigned int nwriters; | 186 | unsigned int n_wronly; |
187 | unsigned int n_rdwr; | ||
187 | int state; /* State on the server (R,W, or RW) */ | 188 | int state; /* State on the server (R,W, or RW) */ |
188 | atomic_t count; | 189 | atomic_t count; |
189 | }; | 190 | }; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8154f2579469..e494cc2ea986 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -297,6 +297,20 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
297 | return ret; | 297 | return ret; |
298 | } | 298 | } |
299 | 299 | ||
300 | static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | ||
301 | { | ||
302 | switch (open_flags) { | ||
303 | case FMODE_WRITE: | ||
304 | state->n_wronly++; | ||
305 | break; | ||
306 | case FMODE_READ: | ||
307 | state->n_rdonly++; | ||
308 | break; | ||
309 | case FMODE_READ|FMODE_WRITE: | ||
310 | state->n_rdwr++; | ||
311 | } | ||
312 | } | ||
313 | |||
300 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 314 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
301 | { | 315 | { |
302 | struct inode *inode = state->inode; | 316 | struct inode *inode = state->inode; |
@@ -306,10 +320,7 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, | |||
306 | spin_lock(&state->owner->so_lock); | 320 | spin_lock(&state->owner->so_lock); |
307 | spin_lock(&inode->i_lock); | 321 | spin_lock(&inode->i_lock); |
308 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); | 322 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); |
309 | if ((open_flags & FMODE_WRITE)) | 323 | update_open_stateflags(state, open_flags); |
310 | state->nwriters++; | ||
311 | if (open_flags & FMODE_READ) | ||
312 | state->nreaders++; | ||
313 | nfs4_state_set_mode_locked(state, state->state | open_flags); | 324 | nfs4_state_set_mode_locked(state, state->state | open_flags); |
314 | spin_unlock(&inode->i_lock); | 325 | spin_unlock(&inode->i_lock); |
315 | spin_unlock(&state->owner->so_lock); | 326 | spin_unlock(&state->owner->so_lock); |
@@ -822,10 +833,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
822 | err = -ENOENT; | 833 | err = -ENOENT; |
823 | if ((state->state & open_flags) == open_flags) { | 834 | if ((state->state & open_flags) == open_flags) { |
824 | spin_lock(&inode->i_lock); | 835 | spin_lock(&inode->i_lock); |
825 | if (open_flags & FMODE_READ) | 836 | update_open_stateflags(state, open_flags); |
826 | state->nreaders++; | ||
827 | if (open_flags & FMODE_WRITE) | ||
828 | state->nwriters++; | ||
829 | spin_unlock(&inode->i_lock); | 837 | spin_unlock(&inode->i_lock); |
830 | goto out_ok; | 838 | goto out_ok; |
831 | } else if (state->state != 0) | 839 | } else if (state->state != 0) |
@@ -1082,10 +1090,12 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1082 | spin_lock(&state->owner->so_lock); | 1090 | spin_lock(&state->owner->so_lock); |
1083 | spin_lock(&calldata->inode->i_lock); | 1091 | spin_lock(&calldata->inode->i_lock); |
1084 | mode = old_mode = state->state; | 1092 | mode = old_mode = state->state; |
1085 | if (state->nreaders == 0) | 1093 | if (state->n_rdwr == 0) { |
1086 | mode &= ~FMODE_READ; | 1094 | if (state->n_rdonly == 0) |
1087 | if (state->nwriters == 0) | 1095 | mode &= ~FMODE_READ; |
1088 | mode &= ~FMODE_WRITE; | 1096 | if (state->n_wronly == 0) |
1097 | mode &= ~FMODE_WRITE; | ||
1098 | } | ||
1089 | nfs4_state_set_mode_locked(state, mode); | 1099 | nfs4_state_set_mode_locked(state, mode); |
1090 | spin_unlock(&calldata->inode->i_lock); | 1100 | spin_unlock(&calldata->inode->i_lock); |
1091 | spin_unlock(&state->owner->so_lock); | 1101 | spin_unlock(&state->owner->so_lock); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5ef4c57618fe..41a5f1a8a984 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -349,14 +349,9 @@ nfs4_alloc_open_state(void) | |||
349 | { | 349 | { |
350 | struct nfs4_state *state; | 350 | struct nfs4_state *state; |
351 | 351 | ||
352 | state = kmalloc(sizeof(*state), GFP_KERNEL); | 352 | state = kzalloc(sizeof(*state), GFP_KERNEL); |
353 | if (!state) | 353 | if (!state) |
354 | return NULL; | 354 | return NULL; |
355 | state->state = 0; | ||
356 | state->nreaders = 0; | ||
357 | state->nwriters = 0; | ||
358 | state->flags = 0; | ||
359 | memset(state->stateid.data, 0, sizeof(state->stateid.data)); | ||
360 | atomic_set(&state->count, 1); | 355 | atomic_set(&state->count, 1); |
361 | INIT_LIST_HEAD(&state->lock_states); | 356 | INIT_LIST_HEAD(&state->lock_states); |
362 | spin_lock_init(&state->state_lock); | 357 | spin_lock_init(&state->state_lock); |
@@ -475,15 +470,23 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) | |||
475 | /* Protect against nfs4_find_state() */ | 470 | /* Protect against nfs4_find_state() */ |
476 | spin_lock(&owner->so_lock); | 471 | spin_lock(&owner->so_lock); |
477 | spin_lock(&inode->i_lock); | 472 | spin_lock(&inode->i_lock); |
478 | if (mode & FMODE_READ) | 473 | switch (mode & (FMODE_READ | FMODE_WRITE)) { |
479 | state->nreaders--; | 474 | case FMODE_READ: |
480 | if (mode & FMODE_WRITE) | 475 | state->n_rdonly--; |
481 | state->nwriters--; | 476 | break; |
477 | case FMODE_WRITE: | ||
478 | state->n_wronly--; | ||
479 | break; | ||
480 | case FMODE_READ|FMODE_WRITE: | ||
481 | state->n_rdwr--; | ||
482 | } | ||
482 | oldstate = newstate = state->state; | 483 | oldstate = newstate = state->state; |
483 | if (state->nreaders == 0) | 484 | if (state->n_rdwr == 0) { |
484 | newstate &= ~FMODE_READ; | 485 | if (state->n_rdonly == 0) |
485 | if (state->nwriters == 0) | 486 | newstate &= ~FMODE_READ; |
486 | newstate &= ~FMODE_WRITE; | 487 | if (state->n_wronly == 0) |
488 | newstate &= ~FMODE_WRITE; | ||
489 | } | ||
487 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 490 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
488 | nfs4_state_set_mode_locked(state, newstate); | 491 | nfs4_state_set_mode_locked(state, newstate); |
489 | oldstate = newstate; | 492 | oldstate = newstate; |