diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 88 |
1 files changed, 66 insertions, 22 deletions
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) |