diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-03 23:48:13 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:40 -0400 |
commit | 2ced46c27058710a6d731d6eca77f1dd14ccde75 (patch) | |
tree | d505d922873c7b3ade6426d0e9924b1c0c380614 /fs/nfs | |
parent | 549d6ed5e85003370fe858e70864a71882491d28 (diff) |
NFSv4: Fix up a bug in nfs4_open_recover()
Don't clobber the delegation info...
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 65 |
1 files changed, 31 insertions, 34 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4f0b06d549fa..03b60c67ca7c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -230,6 +230,16 @@ struct nfs4_opendata { | |||
230 | int cancelled; | 230 | int cancelled; |
231 | }; | 231 | }; |
232 | 232 | ||
233 | |||
234 | static void nfs4_init_opendata_res(struct nfs4_opendata *p) | ||
235 | { | ||
236 | p->o_res.f_attr = &p->f_attr; | ||
237 | p->o_res.dir_attr = &p->dir_attr; | ||
238 | p->o_res.server = p->o_arg.server; | ||
239 | nfs_fattr_init(&p->f_attr); | ||
240 | nfs_fattr_init(&p->dir_attr); | ||
241 | } | ||
242 | |||
233 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 243 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
234 | struct nfs4_state_owner *sp, int flags, | 244 | struct nfs4_state_owner *sp, int flags, |
235 | const struct iattr *attrs) | 245 | const struct iattr *attrs) |
@@ -258,11 +268,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
258 | p->o_arg.server = server; | 268 | p->o_arg.server = server; |
259 | p->o_arg.bitmask = server->attr_bitmask; | 269 | p->o_arg.bitmask = server->attr_bitmask; |
260 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 270 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
261 | p->o_res.f_attr = &p->f_attr; | ||
262 | p->o_res.dir_attr = &p->dir_attr; | ||
263 | p->o_res.server = server; | ||
264 | nfs_fattr_init(&p->f_attr); | ||
265 | nfs_fattr_init(&p->dir_attr); | ||
266 | if (flags & O_EXCL) { | 271 | if (flags & O_EXCL) { |
267 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 272 | u32 *s = (u32 *) p->o_arg.u.verifier.data; |
268 | s[0] = jiffies; | 273 | s[0] = jiffies; |
@@ -274,6 +279,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
274 | p->c_arg.fh = &p->o_res.fh; | 279 | p->c_arg.fh = &p->o_res.fh; |
275 | p->c_arg.stateid = &p->o_res.stateid; | 280 | p->c_arg.stateid = &p->o_res.stateid; |
276 | p->c_arg.seqid = p->o_arg.seqid; | 281 | p->c_arg.seqid = p->o_arg.seqid; |
282 | nfs4_init_opendata_res(p); | ||
277 | kref_init(&p->kref); | 283 | kref_init(&p->kref); |
278 | return p; | 284 | return p; |
279 | err_free: | 285 | err_free: |
@@ -394,64 +400,54 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * | |||
394 | return ERR_PTR(-ENOENT); | 400 | return ERR_PTR(-ENOENT); |
395 | } | 401 | } |
396 | 402 | ||
397 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) | 403 | static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) |
398 | { | 404 | { |
405 | struct nfs4_state *newstate; | ||
399 | int ret; | 406 | int ret; |
400 | 407 | ||
401 | opendata->o_arg.open_flags = openflags; | 408 | opendata->o_arg.open_flags = openflags; |
409 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | ||
410 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | ||
411 | nfs4_init_opendata_res(opendata); | ||
402 | ret = _nfs4_proc_open(opendata); | 412 | ret = _nfs4_proc_open(opendata); |
403 | if (ret != 0) | 413 | if (ret != 0) |
404 | return ret; | 414 | return ret; |
405 | memcpy(stateid->data, opendata->o_res.stateid.data, | 415 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
406 | sizeof(stateid->data)); | 416 | if (newstate != NULL) |
417 | nfs4_close_state(&opendata->path, newstate, openflags); | ||
418 | *res = newstate; | ||
407 | return 0; | 419 | return 0; |
408 | } | 420 | } |
409 | 421 | ||
410 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | 422 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) |
411 | { | 423 | { |
412 | nfs4_stateid stateid; | ||
413 | struct nfs4_state *newstate; | 424 | struct nfs4_state *newstate; |
414 | int mode = 0; | ||
415 | int delegation = 0; | ||
416 | int ret; | 425 | int ret; |
417 | 426 | ||
418 | /* memory barrier prior to reading state->n_* */ | 427 | /* memory barrier prior to reading state->n_* */ |
428 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
419 | smp_rmb(); | 429 | smp_rmb(); |
420 | if (state->n_rdwr != 0) { | 430 | if (state->n_rdwr != 0) { |
421 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); | 431 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); |
422 | if (ret != 0) | 432 | if (ret != 0) |
423 | return ret; | 433 | return ret; |
424 | mode |= FMODE_READ|FMODE_WRITE; | 434 | if (newstate != state) |
425 | if (opendata->o_res.delegation_type != 0) | 435 | return -ESTALE; |
426 | delegation = opendata->o_res.delegation_type; | ||
427 | smp_rmb(); | ||
428 | } | 436 | } |
429 | if (state->n_wronly != 0) { | 437 | if (state->n_wronly != 0) { |
430 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); | 438 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); |
431 | if (ret != 0) | 439 | if (ret != 0) |
432 | return ret; | 440 | return ret; |
433 | mode |= FMODE_WRITE; | 441 | if (newstate != state) |
434 | if (opendata->o_res.delegation_type != 0) | 442 | return -ESTALE; |
435 | delegation = opendata->o_res.delegation_type; | ||
436 | smp_rmb(); | ||
437 | } | 443 | } |
438 | if (state->n_rdonly != 0) { | 444 | if (state->n_rdonly != 0) { |
439 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); | 445 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); |
440 | if (ret != 0) | 446 | if (ret != 0) |
441 | return ret; | 447 | return ret; |
442 | mode |= FMODE_READ; | 448 | if (newstate != state) |
449 | return -ESTALE; | ||
443 | } | 450 | } |
444 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
445 | if (mode == 0) | ||
446 | return 0; | ||
447 | if (opendata->o_res.delegation_type == 0) | ||
448 | opendata->o_res.delegation_type = delegation; | ||
449 | opendata->o_arg.open_flags |= mode; | ||
450 | newstate = nfs4_opendata_to_nfs4_state(opendata); | ||
451 | if (newstate != NULL) | ||
452 | nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags); | ||
453 | if (newstate != state) | ||
454 | return -ESTALE; | ||
455 | return 0; | 451 | return 0; |
456 | } | 452 | } |
457 | 453 | ||
@@ -730,6 +726,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
730 | * want to ensure that it takes the 'error' code path. | 726 | * want to ensure that it takes the 'error' code path. |
731 | */ | 727 | */ |
732 | data->rpc_status = -ENOMEM; | 728 | data->rpc_status = -ENOMEM; |
729 | data->cancelled = 0; | ||
733 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | 730 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); |
734 | if (IS_ERR(task)) | 731 | if (IS_ERR(task)) |
735 | return PTR_ERR(task); | 732 | return PTR_ERR(task); |