diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-10-18 17:20:15 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-10-18 17:20:15 -0400 |
commit | faf5f49c2d9c0af2847837c232a432cc146e203b (patch) | |
tree | f0c097ae68ca3ec3cd5ee0a904916493b00b9c1b | |
parent | 0a8838f972883112f0a7b259141b24db17583c2d (diff) |
NFSv4: Make NFS clean up byte range locks asynchronously
Currently we fail to do so if the process was signalled.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 161 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 9 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 2 |
5 files changed, 116 insertions, 59 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index d4fcb5d0ce6c..2215cdee43ae 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -249,6 +249,7 @@ extern void nfs4_put_open_state(struct nfs4_state *); | |||
249 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | 249 | extern void nfs4_close_state(struct nfs4_state *, mode_t); |
250 | extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); | 250 | extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); |
251 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | 251 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); |
252 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | ||
252 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 253 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
253 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 254 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
254 | 255 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f57dba815099..612a9a14aed3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -58,9 +58,9 @@ | |||
58 | 58 | ||
59 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); | 59 | static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); |
60 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 60 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
61 | static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); | 61 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
62 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 62 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
63 | static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 63 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
64 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 64 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
65 | extern struct rpc_procinfo nfs4_procedures[]; | 65 | extern struct rpc_procinfo nfs4_procedures[]; |
66 | 66 | ||
@@ -2422,7 +2422,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2422 | } | 2422 | } |
2423 | 2423 | ||
2424 | static int | 2424 | static int |
2425 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2425 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) |
2426 | { | 2426 | { |
2427 | struct nfs4_client *clp = server->nfs4_state; | 2427 | struct nfs4_client *clp = server->nfs4_state; |
2428 | 2428 | ||
@@ -2500,7 +2500,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
2500 | /* This is the error handling routine for processes that are allowed | 2500 | /* This is the error handling routine for processes that are allowed |
2501 | * to sleep. | 2501 | * to sleep. |
2502 | */ | 2502 | */ |
2503 | int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 2503 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
2504 | { | 2504 | { |
2505 | struct nfs4_client *clp = server->nfs4_state; | 2505 | struct nfs4_client *clp = server->nfs4_state; |
2506 | int ret = errorcode; | 2506 | int ret = errorcode; |
@@ -2763,68 +2763,127 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
2763 | return res; | 2763 | return res; |
2764 | } | 2764 | } |
2765 | 2765 | ||
2766 | static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 2766 | struct nfs4_unlockdata { |
2767 | struct nfs_lockargs arg; | ||
2768 | struct nfs_locku_opargs luargs; | ||
2769 | struct nfs_lockres res; | ||
2770 | struct nfs4_lock_state *lsp; | ||
2771 | struct nfs_open_context *ctx; | ||
2772 | atomic_t refcount; | ||
2773 | struct completion completion; | ||
2774 | }; | ||
2775 | |||
2776 | static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata) | ||
2767 | { | 2777 | { |
2768 | struct inode *inode = state->inode; | 2778 | if (atomic_dec_and_test(&calldata->refcount)) { |
2769 | struct nfs_server *server = NFS_SERVER(inode); | 2779 | nfs_free_seqid(calldata->luargs.seqid); |
2770 | struct nfs_lockargs arg = { | 2780 | nfs4_put_lock_state(calldata->lsp); |
2771 | .fh = NFS_FH(inode), | 2781 | put_nfs_open_context(calldata->ctx); |
2772 | .type = nfs4_lck_type(cmd, request), | 2782 | kfree(calldata); |
2773 | .offset = request->fl_start, | 2783 | } |
2774 | .length = nfs4_lck_length(request), | 2784 | } |
2775 | }; | 2785 | |
2776 | struct nfs_lockres res = { | 2786 | static void nfs4_locku_complete(struct nfs4_unlockdata *calldata) |
2777 | .server = server, | 2787 | { |
2778 | }; | 2788 | complete(&calldata->completion); |
2789 | nfs4_locku_release_calldata(calldata); | ||
2790 | } | ||
2791 | |||
2792 | static void nfs4_locku_done(struct rpc_task *task) | ||
2793 | { | ||
2794 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | ||
2795 | |||
2796 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); | ||
2797 | switch (task->tk_status) { | ||
2798 | case 0: | ||
2799 | memcpy(calldata->lsp->ls_stateid.data, | ||
2800 | calldata->res.u.stateid.data, | ||
2801 | sizeof(calldata->lsp->ls_stateid.data)); | ||
2802 | break; | ||
2803 | case -NFS4ERR_STALE_STATEID: | ||
2804 | case -NFS4ERR_EXPIRED: | ||
2805 | nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); | ||
2806 | break; | ||
2807 | default: | ||
2808 | if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { | ||
2809 | rpc_restart_call(task); | ||
2810 | return; | ||
2811 | } | ||
2812 | } | ||
2813 | nfs4_locku_complete(calldata); | ||
2814 | } | ||
2815 | |||
2816 | static void nfs4_locku_begin(struct rpc_task *task) | ||
2817 | { | ||
2818 | struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata; | ||
2779 | struct rpc_message msg = { | 2819 | struct rpc_message msg = { |
2780 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], | 2820 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], |
2781 | .rpc_argp = &arg, | 2821 | .rpc_argp = &calldata->arg, |
2782 | .rpc_resp = &res, | 2822 | .rpc_resp = &calldata->res, |
2783 | .rpc_cred = state->owner->so_cred, | 2823 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, |
2784 | }; | 2824 | }; |
2825 | int status; | ||
2826 | |||
2827 | status = nfs_wait_on_sequence(calldata->luargs.seqid, task); | ||
2828 | if (status != 0) | ||
2829 | return; | ||
2830 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { | ||
2831 | nfs4_locku_complete(calldata); | ||
2832 | task->tk_exit = NULL; | ||
2833 | rpc_exit(task, 0); | ||
2834 | return; | ||
2835 | } | ||
2836 | rpc_call_setup(task, &msg, 0); | ||
2837 | } | ||
2838 | |||
2839 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | ||
2840 | { | ||
2841 | struct nfs4_unlockdata *calldata; | ||
2842 | struct inode *inode = state->inode; | ||
2843 | struct nfs_server *server = NFS_SERVER(inode); | ||
2785 | struct nfs4_lock_state *lsp; | 2844 | struct nfs4_lock_state *lsp; |
2786 | struct nfs_locku_opargs luargs; | ||
2787 | int status; | 2845 | int status; |
2788 | 2846 | ||
2789 | status = nfs4_set_lock_state(state, request); | 2847 | status = nfs4_set_lock_state(state, request); |
2790 | if (status != 0) | 2848 | if (status != 0) |
2791 | goto out; | 2849 | return status; |
2792 | lsp = request->fl_u.nfs4_fl.owner; | 2850 | lsp = request->fl_u.nfs4_fl.owner; |
2793 | /* We might have lost the locks! */ | 2851 | /* We might have lost the locks! */ |
2794 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) | 2852 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2795 | goto out; | 2853 | return 0; |
2796 | luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 2854 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
2797 | status = -ENOMEM; | 2855 | if (calldata == NULL) |
2798 | if (luargs.seqid == NULL) | 2856 | return -ENOMEM; |
2799 | goto out; | 2857 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2800 | memcpy(luargs.stateid.data, lsp->ls_stateid.data, sizeof(luargs.stateid.data)); | 2858 | if (calldata->luargs.seqid == NULL) { |
2801 | arg.u.locku = &luargs; | 2859 | kfree(calldata); |
2802 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 2860 | return -ENOMEM; |
2803 | nfs_increment_lock_seqid(status, luargs.seqid); | 2861 | } |
2804 | 2862 | calldata->luargs.stateid = &lsp->ls_stateid; | |
2805 | if (status == 0) | 2863 | calldata->arg.fh = NFS_FH(inode); |
2806 | memcpy(lsp->ls_stateid.data, res.u.stateid.data, | 2864 | calldata->arg.type = nfs4_lck_type(cmd, request); |
2807 | sizeof(lsp->ls_stateid.data)); | 2865 | calldata->arg.offset = request->fl_start; |
2808 | nfs_free_seqid(luargs.seqid); | 2866 | calldata->arg.length = nfs4_lck_length(request); |
2809 | out: | 2867 | calldata->arg.u.locku = &calldata->luargs; |
2868 | calldata->res.server = server; | ||
2869 | calldata->lsp = lsp; | ||
2870 | atomic_inc(&lsp->ls_count); | ||
2871 | |||
2872 | /* Ensure we don't close file until we're done freeing locks! */ | ||
2873 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); | ||
2874 | |||
2875 | atomic_set(&calldata->refcount, 2); | ||
2876 | init_completion(&calldata->completion); | ||
2877 | |||
2878 | status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_locku_begin, | ||
2879 | nfs4_locku_done, calldata); | ||
2810 | if (status == 0) | 2880 | if (status == 0) |
2811 | do_vfs_lock(request->fl_file, request); | 2881 | wait_for_completion_interruptible(&calldata->completion); |
2882 | do_vfs_lock(request->fl_file, request); | ||
2883 | nfs4_locku_release_calldata(calldata); | ||
2812 | return status; | 2884 | return status; |
2813 | } | 2885 | } |
2814 | 2886 | ||
2815 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | ||
2816 | { | ||
2817 | struct nfs4_exception exception = { }; | ||
2818 | int err; | ||
2819 | |||
2820 | do { | ||
2821 | err = nfs4_handle_exception(NFS_SERVER(state->inode), | ||
2822 | _nfs4_proc_unlck(state, cmd, request), | ||
2823 | &exception); | ||
2824 | } while (exception.retry); | ||
2825 | return err; | ||
2826 | } | ||
2827 | |||
2828 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) | 2887 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) |
2829 | { | 2888 | { |
2830 | struct inode *inode = state->inode; | 2889 | struct inode *inode = state->inode; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index bb3574361958..23834c8fb740 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -600,7 +600,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
600 | * Release reference to lock_state, and free it if we see that | 600 | * Release reference to lock_state, and free it if we see that |
601 | * it is no longer in use | 601 | * it is no longer in use |
602 | */ | 602 | */ |
603 | static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | 603 | void nfs4_put_lock_state(struct nfs4_lock_state *lsp) |
604 | { | 604 | { |
605 | struct nfs4_state *state; | 605 | struct nfs4_state *state; |
606 | 606 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 934ec50ea6bf..4706192cfb07 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -776,7 +776,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg) | |||
776 | WRITE32(OP_LOCKU); | 776 | WRITE32(OP_LOCKU); |
777 | WRITE32(arg->type); | 777 | WRITE32(arg->type); |
778 | WRITE32(opargs->seqid->sequence->counter); | 778 | WRITE32(opargs->seqid->sequence->counter); |
779 | WRITEMEM(&opargs->stateid, sizeof(opargs->stateid)); | 779 | WRITEMEM(opargs->stateid->data, sizeof(opargs->stateid->data)); |
780 | WRITE64(arg->offset); | 780 | WRITE64(arg->offset); |
781 | WRITE64(arg->length); | 781 | WRITE64(arg->length); |
782 | 782 | ||
@@ -1587,9 +1587,6 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lock | |||
1587 | }; | 1587 | }; |
1588 | int status; | 1588 | int status; |
1589 | 1589 | ||
1590 | status = nfs_wait_on_sequence(args->u.locku->seqid, req->rq_task); | ||
1591 | if (status != 0) | ||
1592 | goto out; | ||
1593 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1590 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1594 | encode_compound_hdr(&xdr, &hdr); | 1591 | encode_compound_hdr(&xdr, &hdr); |
1595 | status = encode_putfh(&xdr, args->fh); | 1592 | status = encode_putfh(&xdr, args->fh); |
@@ -2934,8 +2931,8 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res) | |||
2934 | 2931 | ||
2935 | status = decode_op_hdr(xdr, OP_LOCKU); | 2932 | status = decode_op_hdr(xdr, OP_LOCKU); |
2936 | if (status == 0) { | 2933 | if (status == 0) { |
2937 | READ_BUF(sizeof(nfs4_stateid)); | 2934 | READ_BUF(sizeof(res->u.stateid.data)); |
2938 | COPYMEM(&res->u.stateid, sizeof(res->u.stateid)); | 2935 | COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data)); |
2939 | } | 2936 | } |
2940 | return status; | 2937 | return status; |
2941 | } | 2938 | } |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index cac0df950c66..849f95c5fae4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -188,7 +188,7 @@ struct nfs_lock_opargs { | |||
188 | 188 | ||
189 | struct nfs_locku_opargs { | 189 | struct nfs_locku_opargs { |
190 | struct nfs_seqid * seqid; | 190 | struct nfs_seqid * seqid; |
191 | nfs4_stateid stateid; | 191 | nfs4_stateid * stateid; |
192 | }; | 192 | }; |
193 | 193 | ||
194 | struct nfs_lockargs { | 194 | struct nfs_lockargs { |