diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-03 03:55:08 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-06 14:58:41 -0500 |
commit | e56e0b78eb1097a8e06512b9ed4be94d7538e7ac (patch) | |
tree | fe2b82993dd62323f9891f28bdb79c7cb2b01442 | |
parent | 06f814a3ad0ddfe19e6e4f44e3da5d490547faf3 (diff) |
NFSv4: Allocate OPEN call RPC arguments using kmalloc()
Cleanup in preparation for making OPEN calls interruptible by the user.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 213 |
1 files changed, 117 insertions, 96 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c7bec4319236..4a5cc8402110 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -194,6 +194,76 @@ static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinf | |||
194 | spin_unlock(&inode->i_lock); | 194 | spin_unlock(&inode->i_lock); |
195 | } | 195 | } |
196 | 196 | ||
197 | struct nfs4_opendata { | ||
198 | struct nfs_openargs o_arg; | ||
199 | struct nfs_openres o_res; | ||
200 | struct nfs_fattr f_attr; | ||
201 | struct nfs_fattr dir_attr; | ||
202 | struct dentry *dentry; | ||
203 | struct dentry *dir; | ||
204 | struct nfs4_state_owner *owner; | ||
205 | struct iattr attrs; | ||
206 | }; | ||
207 | |||
208 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | ||
209 | struct nfs4_state_owner *sp, int flags, | ||
210 | const struct iattr *attrs) | ||
211 | { | ||
212 | struct dentry *parent = dget_parent(dentry); | ||
213 | struct inode *dir = parent->d_inode; | ||
214 | struct nfs_server *server = NFS_SERVER(dir); | ||
215 | struct nfs4_opendata *p; | ||
216 | |||
217 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
218 | if (p == NULL) | ||
219 | goto err; | ||
220 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
221 | if (p->o_arg.seqid == NULL) | ||
222 | goto err_free; | ||
223 | p->dentry = dget(dentry); | ||
224 | p->dir = parent; | ||
225 | p->owner = sp; | ||
226 | atomic_inc(&sp->so_count); | ||
227 | p->o_arg.fh = NFS_FH(dir); | ||
228 | p->o_arg.open_flags = flags, | ||
229 | p->o_arg.clientid = server->nfs4_state->cl_clientid; | ||
230 | p->o_arg.id = sp->so_id; | ||
231 | p->o_arg.name = &dentry->d_name; | ||
232 | p->o_arg.server = server; | ||
233 | p->o_arg.bitmask = server->attr_bitmask; | ||
234 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | ||
235 | p->o_res.f_attr = &p->f_attr; | ||
236 | p->o_res.dir_attr = &p->dir_attr; | ||
237 | p->o_res.server = server; | ||
238 | nfs_fattr_init(&p->f_attr); | ||
239 | nfs_fattr_init(&p->dir_attr); | ||
240 | if (flags & O_EXCL) { | ||
241 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
242 | s[0] = jiffies; | ||
243 | s[1] = current->pid; | ||
244 | } else if (flags & O_CREAT) { | ||
245 | p->o_arg.u.attrs = &p->attrs; | ||
246 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
247 | } | ||
248 | return p; | ||
249 | err_free: | ||
250 | kfree(p); | ||
251 | err: | ||
252 | dput(parent); | ||
253 | return NULL; | ||
254 | } | ||
255 | |||
256 | static void nfs4_opendata_free(struct nfs4_opendata *p) | ||
257 | { | ||
258 | if (p != NULL) { | ||
259 | nfs_free_seqid(p->o_arg.seqid); | ||
260 | nfs4_put_state_owner(p->owner); | ||
261 | dput(p->dir); | ||
262 | dput(p->dentry); | ||
263 | kfree(p); | ||
264 | } | ||
265 | } | ||
266 | |||
197 | /* Helper for asynchronous RPC calls */ | 267 | /* Helper for asynchronous RPC calls */ |
198 | static int nfs4_call_async(struct rpc_clnt *clnt, | 268 | static int nfs4_call_async(struct rpc_clnt *clnt, |
199 | const struct rpc_call_ops *tk_ops, void *calldata) | 269 | const struct rpc_call_ops *tk_ops, void *calldata) |
@@ -314,57 +384,45 @@ static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state | |||
314 | struct nfs4_state_owner *sp = state->owner; | 384 | struct nfs4_state_owner *sp = state->owner; |
315 | struct inode *inode = dentry->d_inode; | 385 | struct inode *inode = dentry->d_inode; |
316 | struct nfs_server *server = NFS_SERVER(inode); | 386 | struct nfs_server *server = NFS_SERVER(inode); |
317 | struct dentry *parent = dget_parent(dentry); | ||
318 | struct nfs_openargs arg = { | ||
319 | .fh = NFS_FH(parent->d_inode), | ||
320 | .clientid = server->nfs4_state->cl_clientid, | ||
321 | .name = &dentry->d_name, | ||
322 | .id = sp->so_id, | ||
323 | .server = server, | ||
324 | .bitmask = server->attr_bitmask, | ||
325 | .claim = NFS4_OPEN_CLAIM_DELEGATE_CUR, | ||
326 | }; | ||
327 | struct nfs_openres res = { | ||
328 | .server = server, | ||
329 | }; | ||
330 | struct rpc_message msg = { | 387 | struct rpc_message msg = { |
331 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], | 388 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR], |
332 | .rpc_argp = &arg, | ||
333 | .rpc_resp = &res, | ||
334 | .rpc_cred = sp->so_cred, | 389 | .rpc_cred = sp->so_cred, |
335 | }; | 390 | }; |
391 | struct nfs4_opendata *opendata; | ||
336 | int status = 0; | 392 | int status = 0; |
337 | 393 | ||
338 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 394 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
339 | goto out; | 395 | goto out; |
340 | if (state->state == 0) | 396 | if (state->state == 0) |
341 | goto out; | 397 | goto out; |
342 | arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 398 | opendata = nfs4_opendata_alloc(dentry, sp, state->state, NULL); |
343 | status = -ENOMEM; | 399 | status = -ENOMEM; |
344 | if (arg.seqid == NULL) | 400 | if (opendata == NULL) |
345 | goto out; | 401 | goto out; |
346 | arg.open_flags = state->state; | 402 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; |
347 | memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data)); | 403 | msg.rpc_argp = &opendata->o_arg; |
404 | msg.rpc_resp = &opendata->o_res; | ||
405 | memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, | ||
406 | sizeof(opendata->o_arg.u.delegation.data)); | ||
348 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 407 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
349 | nfs_increment_open_seqid(status, arg.seqid); | 408 | nfs_increment_open_seqid(status, opendata->o_arg.seqid); |
350 | if (status != 0) | 409 | if (status != 0) |
351 | goto out_free; | 410 | goto out_free; |
352 | if(res.rflags & NFS4_OPEN_RESULT_CONFIRM) { | 411 | if(opendata->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { |
353 | status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), | 412 | status = _nfs4_proc_open_confirm(server->client, NFS_FH(inode), |
354 | sp, &res.stateid, arg.seqid); | 413 | sp, &opendata->o_res.stateid, opendata->o_arg.seqid); |
355 | if (status != 0) | 414 | if (status != 0) |
356 | goto out_free; | 415 | goto out_free; |
357 | } | 416 | } |
358 | nfs_confirm_seqid(&sp->so_seqid, 0); | 417 | nfs_confirm_seqid(&sp->so_seqid, 0); |
359 | if (status >= 0) { | 418 | if (status >= 0) { |
360 | memcpy(state->stateid.data, res.stateid.data, | 419 | memcpy(state->stateid.data, opendata->o_res.stateid.data, |
361 | sizeof(state->stateid.data)); | 420 | sizeof(state->stateid.data)); |
362 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 421 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
363 | } | 422 | } |
364 | out_free: | 423 | out_free: |
365 | nfs_free_seqid(arg.seqid); | 424 | nfs4_opendata_free(opendata); |
366 | out: | 425 | out: |
367 | dput(parent); | ||
368 | return status; | 426 | return status; |
369 | } | 427 | } |
370 | 428 | ||
@@ -506,21 +564,8 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
506 | struct dentry *parent = dget_parent(dentry); | 564 | struct dentry *parent = dget_parent(dentry); |
507 | struct inode *dir = parent->d_inode; | 565 | struct inode *dir = parent->d_inode; |
508 | struct inode *inode = state->inode; | 566 | struct inode *inode = state->inode; |
509 | struct nfs_server *server = NFS_SERVER(dir); | ||
510 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 567 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; |
511 | struct nfs_fattr f_attr, dir_attr; | 568 | struct nfs4_opendata *opendata; |
512 | struct nfs_openargs o_arg = { | ||
513 | .fh = NFS_FH(dir), | ||
514 | .open_flags = state->state, | ||
515 | .name = &dentry->d_name, | ||
516 | .bitmask = server->attr_bitmask, | ||
517 | .claim = NFS4_OPEN_CLAIM_NULL, | ||
518 | }; | ||
519 | struct nfs_openres o_res = { | ||
520 | .f_attr = &f_attr, | ||
521 | .dir_attr = &dir_attr, | ||
522 | .server = server, | ||
523 | }; | ||
524 | int status = 0; | 569 | int status = 0; |
525 | 570 | ||
526 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | 571 | if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { |
@@ -531,38 +576,38 @@ static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
531 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 576 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
532 | goto out; | 577 | goto out; |
533 | } | 578 | } |
534 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | ||
535 | status = -ENOMEM; | 579 | status = -ENOMEM; |
536 | if (o_arg.seqid == NULL) | 580 | opendata = nfs4_opendata_alloc(dentry, sp, state->state, NULL); |
581 | if (opendata == NULL) | ||
537 | goto out; | 582 | goto out; |
538 | nfs_fattr_init(&f_attr); | 583 | status = _nfs4_proc_open(dir, sp, &opendata->o_arg, &opendata->o_res); |
539 | nfs_fattr_init(&dir_attr); | ||
540 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | ||
541 | if (status != 0) | 584 | if (status != 0) |
542 | goto out_nodeleg; | 585 | goto out_nodeleg; |
543 | /* Check if files differ */ | 586 | /* Check if files differ */ |
544 | if ((f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT)) | 587 | if ((opendata->f_attr.mode & S_IFMT) != (inode->i_mode & S_IFMT)) |
545 | goto out_stale; | 588 | goto out_stale; |
546 | /* Has the file handle changed? */ | 589 | /* Has the file handle changed? */ |
547 | if (nfs_compare_fh(&o_res.fh, NFS_FH(inode)) != 0) { | 590 | if (nfs_compare_fh(&opendata->o_res.fh, NFS_FH(inode)) != 0) { |
548 | /* Verify if the change attributes are the same */ | 591 | /* Verify if the change attributes are the same */ |
549 | if (f_attr.change_attr != NFS_I(inode)->change_attr) | 592 | if (opendata->f_attr.change_attr != NFS_I(inode)->change_attr) |
550 | goto out_stale; | 593 | goto out_stale; |
551 | if (nfs_size_to_loff_t(f_attr.size) != inode->i_size) | 594 | if (nfs_size_to_loff_t(opendata->f_attr.size) != inode->i_size) |
552 | goto out_stale; | 595 | goto out_stale; |
553 | /* Lets just pretend that this is the same file */ | 596 | /* Lets just pretend that this is the same file */ |
554 | nfs_copy_fh(NFS_FH(inode), &o_res.fh); | 597 | nfs_copy_fh(NFS_FH(inode), &opendata->o_res.fh); |
555 | NFS_I(inode)->fileid = f_attr.fileid; | 598 | NFS_I(inode)->fileid = opendata->f_attr.fileid; |
556 | } | 599 | } |
557 | memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); | 600 | memcpy(&state->stateid, &opendata->o_res.stateid, sizeof(state->stateid)); |
558 | if (o_res.delegation_type != 0) { | 601 | if (opendata->o_res.delegation_type != 0) { |
559 | if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) | 602 | if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) |
560 | nfs_inode_set_delegation(inode, sp->so_cred, &o_res); | 603 | nfs_inode_set_delegation(inode, sp->so_cred, |
604 | &opendata->o_res); | ||
561 | else | 605 | else |
562 | nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res); | 606 | nfs_inode_reclaim_delegation(inode, sp->so_cred, |
607 | &opendata->o_res); | ||
563 | } | 608 | } |
564 | out_nodeleg: | 609 | out_nodeleg: |
565 | nfs_free_seqid(o_arg.seqid); | 610 | nfs4_opendata_free(opendata); |
566 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 611 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
567 | out: | 612 | out: |
568 | dput(parent); | 613 | dput(parent); |
@@ -706,21 +751,8 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
706 | struct nfs_server *server = NFS_SERVER(dir); | 751 | struct nfs_server *server = NFS_SERVER(dir); |
707 | struct nfs4_client *clp = server->nfs4_state; | 752 | struct nfs4_client *clp = server->nfs4_state; |
708 | struct inode *inode = NULL; | 753 | struct inode *inode = NULL; |
754 | struct nfs4_opendata *opendata; | ||
709 | int status; | 755 | int status; |
710 | struct nfs_fattr f_attr, dir_attr; | ||
711 | struct nfs_openargs o_arg = { | ||
712 | .fh = NFS_FH(dir), | ||
713 | .open_flags = flags, | ||
714 | .name = &dentry->d_name, | ||
715 | .server = server, | ||
716 | .bitmask = server->attr_bitmask, | ||
717 | .claim = NFS4_OPEN_CLAIM_NULL, | ||
718 | }; | ||
719 | struct nfs_openres o_res = { | ||
720 | .f_attr = &f_attr, | ||
721 | .dir_attr = &dir_attr, | ||
722 | .server = server, | ||
723 | }; | ||
724 | 756 | ||
725 | /* Protect against reboot recovery conflicts */ | 757 | /* Protect against reboot recovery conflicts */ |
726 | down_read(&clp->cl_sem); | 758 | down_read(&clp->cl_sem); |
@@ -729,45 +761,34 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
729 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); | 761 | dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); |
730 | goto out_err; | 762 | goto out_err; |
731 | } | 763 | } |
732 | if (flags & O_EXCL) { | 764 | opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); |
733 | u32 *p = (u32 *) o_arg.u.verifier.data; | 765 | if (opendata == NULL) |
734 | p[0] = jiffies; | 766 | goto err_put_state_owner; |
735 | p[1] = current->pid; | ||
736 | } else | ||
737 | o_arg.u.attrs = sattr; | ||
738 | /* Serialization for the sequence id */ | ||
739 | 767 | ||
740 | o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 768 | status = _nfs4_proc_open(dir, sp, &opendata->o_arg, &opendata->o_res); |
741 | if (o_arg.seqid == NULL) | ||
742 | return -ENOMEM; | ||
743 | nfs_fattr_init(&f_attr); | ||
744 | nfs_fattr_init(&dir_attr); | ||
745 | status = _nfs4_proc_open(dir, sp, &o_arg, &o_res); | ||
746 | if (status != 0) | 769 | if (status != 0) |
747 | goto out_err; | 770 | goto err_opendata_free; |
748 | 771 | ||
749 | status = -ENOMEM; | 772 | status = -ENOMEM; |
750 | inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); | 773 | inode = nfs_fhget(dir->i_sb, &opendata->o_res.fh, &opendata->f_attr); |
751 | if (!inode) | 774 | if (!inode) |
752 | goto out_err; | 775 | goto err_opendata_free; |
753 | state = nfs4_get_open_state(inode, sp); | 776 | state = nfs4_get_open_state(inode, sp); |
754 | if (!state) | 777 | if (!state) |
755 | goto out_err; | 778 | goto err_opendata_free; |
756 | update_open_stateid(state, &o_res.stateid, flags); | 779 | update_open_stateid(state, &opendata->o_res.stateid, flags); |
757 | if (o_res.delegation_type != 0) | 780 | if (opendata->o_res.delegation_type != 0) |
758 | nfs_inode_set_delegation(inode, cred, &o_res); | 781 | nfs_inode_set_delegation(inode, cred, &opendata->o_res); |
759 | nfs_free_seqid(o_arg.seqid); | 782 | nfs4_opendata_free(opendata); |
760 | nfs4_put_state_owner(sp); | 783 | nfs4_put_state_owner(sp); |
761 | up_read(&clp->cl_sem); | 784 | up_read(&clp->cl_sem); |
762 | *res = state; | 785 | *res = state; |
763 | return 0; | 786 | return 0; |
787 | err_opendata_free: | ||
788 | nfs4_opendata_free(opendata); | ||
789 | err_put_state_owner: | ||
790 | nfs4_put_state_owner(sp); | ||
764 | out_err: | 791 | out_err: |
765 | if (sp != NULL) { | ||
766 | if (state != NULL) | ||
767 | nfs4_put_open_state(state); | ||
768 | nfs_free_seqid(o_arg.seqid); | ||
769 | nfs4_put_state_owner(sp); | ||
770 | } | ||
771 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ | 792 | /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ |
772 | up_read(&clp->cl_sem); | 793 | up_read(&clp->cl_sem); |
773 | if (inode != NULL) | 794 | if (inode != NULL) |