diff options
-rw-r--r-- | fs/nfs/nfs4_fs.h | 14 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 88 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 28 |
3 files changed, 94 insertions, 36 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 44b56c915f72..4a1c4d80a577 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -122,7 +122,10 @@ struct nfs4_lock_state { | |||
122 | /* bits for nfs4_state->flags */ | 122 | /* bits for nfs4_state->flags */ |
123 | enum { | 123 | enum { |
124 | LK_STATE_IN_USE, | 124 | LK_STATE_IN_USE, |
125 | NFS_DELEGATED_STATE, | 125 | NFS_DELEGATED_STATE, /* Current stateid is delegation */ |
126 | NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ | ||
127 | NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ | ||
128 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ | ||
126 | }; | 129 | }; |
127 | 130 | ||
128 | struct nfs4_state { | 131 | struct nfs4_state { |
@@ -136,11 +139,12 @@ struct nfs4_state { | |||
136 | unsigned long flags; /* Do we hold any locks? */ | 139 | unsigned long flags; /* Do we hold any locks? */ |
137 | spinlock_t state_lock; /* Protects the lock_states list */ | 140 | spinlock_t state_lock; /* Protects the lock_states list */ |
138 | 141 | ||
139 | nfs4_stateid stateid; | 142 | nfs4_stateid stateid; /* Current stateid: may be delegation */ |
143 | nfs4_stateid open_stateid; /* OPEN stateid */ | ||
140 | 144 | ||
141 | unsigned int n_rdonly; | 145 | unsigned int n_rdonly; /* Number of read-only references */ |
142 | unsigned int n_wronly; | 146 | unsigned int n_wronly; /* Number of write-only references */ |
143 | unsigned int n_rdwr; | 147 | unsigned int n_rdwr; /* Number of read/write references */ |
144 | int state; /* State on the server (R,W, or RW) */ | 148 | int state; /* State on the server (R,W, or RW) */ |
145 | atomic_t count; | 149 | atomic_t count; |
146 | }; | 150 | }; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 61ba32af4d2f..128fe23d3f1e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -319,7 +319,7 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |||
319 | return ret; | 319 | return ret; |
320 | } | 320 | } |
321 | 321 | ||
322 | static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | 322 | static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) |
323 | { | 323 | { |
324 | switch (open_flags) { | 324 | switch (open_flags) { |
325 | case FMODE_WRITE: | 325 | case FMODE_WRITE: |
@@ -331,9 +331,36 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_ | |||
331 | case FMODE_READ|FMODE_WRITE: | 331 | case FMODE_READ|FMODE_WRITE: |
332 | state->n_rdwr++; | 332 | state->n_rdwr++; |
333 | } | 333 | } |
334 | nfs4_state_set_mode_locked(state, state->state | open_flags); | ||
335 | } | ||
336 | |||
337 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | ||
338 | { | ||
339 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | ||
340 | memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | ||
341 | memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | ||
342 | switch (open_flags) { | ||
343 | case FMODE_READ: | ||
344 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
345 | break; | ||
346 | case FMODE_WRITE: | ||
347 | set_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
348 | break; | ||
349 | case FMODE_READ|FMODE_WRITE: | ||
350 | set_bit(NFS_O_RDWR_STATE, &state->flags); | ||
351 | } | ||
334 | } | 352 | } |
335 | 353 | ||
336 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 354 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
355 | { | ||
356 | spin_lock(&state->owner->so_lock); | ||
357 | spin_lock(&state->inode->i_lock); | ||
358 | nfs_set_open_stateid_locked(state, stateid, open_flags); | ||
359 | spin_unlock(&state->inode->i_lock); | ||
360 | spin_unlock(&state->owner->so_lock); | ||
361 | } | ||
362 | |||
363 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | ||
337 | { | 364 | { |
338 | struct inode *inode = state->inode; | 365 | struct inode *inode = state->inode; |
339 | 366 | ||
@@ -341,9 +368,13 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, | |||
341 | /* Protect against nfs4_find_state_byowner() */ | 368 | /* Protect against nfs4_find_state_byowner() */ |
342 | spin_lock(&state->owner->so_lock); | 369 | spin_lock(&state->owner->so_lock); |
343 | spin_lock(&inode->i_lock); | 370 | spin_lock(&inode->i_lock); |
344 | memcpy(&state->stateid, stateid, sizeof(state->stateid)); | 371 | if (deleg_stateid != NULL) { |
372 | memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); | ||
373 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
374 | } | ||
375 | if (open_stateid != NULL) | ||
376 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | ||
345 | update_open_stateflags(state, open_flags); | 377 | update_open_stateflags(state, open_flags); |
346 | nfs4_state_set_mode_locked(state, state->state | open_flags); | ||
347 | spin_unlock(&inode->i_lock); | 378 | spin_unlock(&inode->i_lock); |
348 | spin_unlock(&state->owner->so_lock); | 379 | spin_unlock(&state->owner->so_lock); |
349 | } | 380 | } |
@@ -352,6 +383,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
352 | { | 383 | { |
353 | struct inode *inode; | 384 | struct inode *inode; |
354 | struct nfs4_state *state = NULL; | 385 | struct nfs4_state *state = NULL; |
386 | struct nfs_delegation *delegation; | ||
387 | nfs4_stateid *deleg_stateid = NULL; | ||
355 | 388 | ||
356 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | 389 | if (!(data->f_attr.valid & NFS_ATTR_FATTR)) |
357 | goto out; | 390 | goto out; |
@@ -361,13 +394,14 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
361 | state = nfs4_get_open_state(inode, data->owner); | 394 | state = nfs4_get_open_state(inode, data->owner); |
362 | if (state == NULL) | 395 | if (state == NULL) |
363 | goto put_inode; | 396 | goto put_inode; |
364 | update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); | ||
365 | if (data->o_res.delegation_type != 0) { | 397 | if (data->o_res.delegation_type != 0) { |
366 | struct nfs_inode *nfsi = NFS_I(inode); | ||
367 | int delegation_flags = 0; | 398 | int delegation_flags = 0; |
368 | 399 | ||
369 | if (nfsi->delegation) | 400 | rcu_read_lock(); |
370 | delegation_flags = nfsi->delegation->flags; | 401 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
402 | if (delegation) | ||
403 | delegation_flags = delegation->flags; | ||
404 | rcu_read_unlock(); | ||
371 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | 405 | if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) |
372 | nfs_inode_set_delegation(state->inode, | 406 | nfs_inode_set_delegation(state->inode, |
373 | data->owner->so_cred, | 407 | data->owner->so_cred, |
@@ -377,6 +411,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data | |||
377 | data->owner->so_cred, | 411 | data->owner->so_cred, |
378 | &data->o_res); | 412 | &data->o_res); |
379 | } | 413 | } |
414 | rcu_read_lock(); | ||
415 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
416 | if (delegation != NULL) | ||
417 | deleg_stateid = &delegation->stateid; | ||
418 | update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); | ||
419 | rcu_read_unlock(); | ||
380 | put_inode: | 420 | put_inode: |
381 | iput(inode); | 421 | iput(inode); |
382 | out: | 422 | out: |
@@ -911,8 +951,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
911 | unlock_kernel(); | 951 | unlock_kernel(); |
912 | if (err != 0) | 952 | if (err != 0) |
913 | goto out_put_open_state; | 953 | goto out_put_open_state; |
914 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 954 | update_open_stateid(state, NULL, &delegation->stateid, open_flags); |
915 | update_open_stateid(state, &delegation->stateid, open_flags); | ||
916 | out_ok: | 955 | out_ok: |
917 | nfs4_put_state_owner(sp); | 956 | nfs4_put_state_owner(sp); |
918 | up_read(&nfsi->rwsem); | 957 | up_read(&nfsi->rwsem); |
@@ -1149,8 +1188,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1149 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | 1188 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); |
1150 | switch (task->tk_status) { | 1189 | switch (task->tk_status) { |
1151 | case 0: | 1190 | case 0: |
1152 | memcpy(&state->stateid, &calldata->res.stateid, | 1191 | nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); |
1153 | sizeof(state->stateid)); | ||
1154 | renew_lease(server, calldata->timestamp); | 1192 | renew_lease(server, calldata->timestamp); |
1155 | break; | 1193 | break; |
1156 | case -NFS4ERR_STALE_STATEID: | 1194 | case -NFS4ERR_STALE_STATEID: |
@@ -1175,26 +1213,32 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1175 | .rpc_resp = &calldata->res, | 1213 | .rpc_resp = &calldata->res, |
1176 | .rpc_cred = state->owner->so_cred, | 1214 | .rpc_cred = state->owner->so_cred, |
1177 | }; | 1215 | }; |
1178 | int mode = 0, old_mode; | 1216 | int clear_rd, clear_wr, clear_rdwr; |
1217 | int mode; | ||
1179 | 1218 | ||
1180 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1219 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1181 | return; | 1220 | return; |
1182 | /* Recalculate the new open mode in case someone reopened the file | 1221 | |
1183 | * while we were waiting in line to be scheduled. | 1222 | mode = FMODE_READ|FMODE_WRITE; |
1184 | */ | 1223 | clear_rd = clear_wr = clear_rdwr = 0; |
1185 | spin_lock(&state->owner->so_lock); | 1224 | spin_lock(&state->owner->so_lock); |
1186 | spin_lock(&calldata->inode->i_lock); | 1225 | spin_lock(&calldata->inode->i_lock); |
1187 | mode = old_mode = state->state; | 1226 | /* Calculate the change in open mode */ |
1188 | if (state->n_rdwr == 0) { | 1227 | if (state->n_rdwr == 0) { |
1189 | if (state->n_rdonly == 0) | 1228 | if (state->n_rdonly == 0) { |
1190 | mode &= ~FMODE_READ; | 1229 | mode &= ~FMODE_READ; |
1191 | if (state->n_wronly == 0) | 1230 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); |
1231 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1232 | } | ||
1233 | if (state->n_wronly == 0) { | ||
1192 | mode &= ~FMODE_WRITE; | 1234 | mode &= ~FMODE_WRITE; |
1235 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1236 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1237 | } | ||
1193 | } | 1238 | } |
1194 | nfs4_state_set_mode_locked(state, mode); | ||
1195 | spin_unlock(&calldata->inode->i_lock); | 1239 | spin_unlock(&calldata->inode->i_lock); |
1196 | spin_unlock(&state->owner->so_lock); | 1240 | spin_unlock(&state->owner->so_lock); |
1197 | if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 1241 | if (!clear_rd && !clear_wr && !clear_rdwr) { |
1198 | /* Note: exit _without_ calling nfs4_close_done */ | 1242 | /* Note: exit _without_ calling nfs4_close_done */ |
1199 | task->tk_action = NULL; | 1243 | task->tk_action = NULL; |
1200 | return; | 1244 | return; |
@@ -1238,7 +1282,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state) | |||
1238 | calldata->inode = state->inode; | 1282 | calldata->inode = state->inode; |
1239 | calldata->state = state; | 1283 | calldata->state = state; |
1240 | calldata->arg.fh = NFS_FH(state->inode); | 1284 | calldata->arg.fh = NFS_FH(state->inode); |
1241 | calldata->arg.stateid = &state->stateid; | 1285 | calldata->arg.stateid = &state->open_stateid; |
1242 | /* Serialization for the sequence id */ | 1286 | /* Serialization for the sequence id */ |
1243 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1287 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1244 | if (calldata->arg.seqid == NULL) | 1288 | if (calldata->arg.seqid == NULL) |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index ac816b303f3a..4f78c0d1eab5 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -412,7 +412,8 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | |||
412 | { | 412 | { |
413 | struct inode *inode = state->inode; | 413 | struct inode *inode = state->inode; |
414 | struct nfs4_state_owner *owner = state->owner; | 414 | struct nfs4_state_owner *owner = state->owner; |
415 | int oldstate, newstate = 0; | 415 | int call_close = 0; |
416 | int newstate; | ||
416 | 417 | ||
417 | atomic_inc(&owner->so_count); | 418 | atomic_inc(&owner->so_count); |
418 | /* Protect against nfs4_find_state() */ | 419 | /* Protect against nfs4_find_state() */ |
@@ -428,21 +429,26 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | |||
428 | case FMODE_READ|FMODE_WRITE: | 429 | case FMODE_READ|FMODE_WRITE: |
429 | state->n_rdwr--; | 430 | state->n_rdwr--; |
430 | } | 431 | } |
431 | oldstate = newstate = state->state; | 432 | newstate = FMODE_READ|FMODE_WRITE; |
432 | if (state->n_rdwr == 0) { | 433 | if (state->n_rdwr == 0) { |
433 | if (state->n_rdonly == 0) | 434 | if (state->n_rdonly == 0) { |
434 | newstate &= ~FMODE_READ; | 435 | newstate &= ~FMODE_READ; |
435 | if (state->n_wronly == 0) | 436 | call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); |
437 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); | ||
438 | } | ||
439 | if (state->n_wronly == 0) { | ||
436 | newstate &= ~FMODE_WRITE; | 440 | newstate &= ~FMODE_WRITE; |
441 | call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
442 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); | ||
443 | } | ||
444 | if (newstate == 0) | ||
445 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
437 | } | 446 | } |
438 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | 447 | nfs4_state_set_mode_locked(state, newstate); |
439 | nfs4_state_set_mode_locked(state, newstate); | ||
440 | oldstate = newstate; | ||
441 | } | ||
442 | spin_unlock(&inode->i_lock); | 448 | spin_unlock(&inode->i_lock); |
443 | spin_unlock(&owner->so_lock); | 449 | spin_unlock(&owner->so_lock); |
444 | 450 | ||
445 | if (oldstate == newstate) { | 451 | if (!call_close) { |
446 | nfs4_put_open_state(state); | 452 | nfs4_put_open_state(state); |
447 | nfs4_put_state_owner(owner); | 453 | nfs4_put_state_owner(owner); |
448 | } else | 454 | } else |
@@ -838,6 +844,10 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp) | |||
838 | sp->so_seqid.flags = 0; | 844 | sp->so_seqid.flags = 0; |
839 | spin_lock(&sp->so_lock); | 845 | spin_lock(&sp->so_lock); |
840 | list_for_each_entry(state, &sp->so_states, open_states) { | 846 | list_for_each_entry(state, &sp->so_states, open_states) { |
847 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
848 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
849 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
850 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
841 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 851 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
842 | lock->ls_seqid.counter = 0; | 852 | lock->ls_seqid.counter = 0; |
843 | lock->ls_seqid.flags = 0; | 853 | lock->ls_seqid.flags = 0; |