diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 65 |
1 files changed, 36 insertions, 29 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 368b75b3bcba..c7bec4319236 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -206,6 +206,17 @@ static int nfs4_call_async(struct rpc_clnt *clnt, | |||
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | 208 | ||
209 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | ||
210 | { | ||
211 | sigset_t oldset; | ||
212 | int ret; | ||
213 | |||
214 | rpc_clnt_sigmask(task->tk_client, &oldset); | ||
215 | ret = rpc_wait_for_completion_task(task); | ||
216 | rpc_clnt_sigunmask(task->tk_client, &oldset); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
209 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 220 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
210 | { | 221 | { |
211 | struct inode *inode = state->inode; | 222 | struct inode *inode = state->inode; |
@@ -2867,31 +2878,23 @@ struct nfs4_unlockdata { | |||
2867 | struct nfs_lockres res; | 2878 | struct nfs_lockres res; |
2868 | struct nfs4_lock_state *lsp; | 2879 | struct nfs4_lock_state *lsp; |
2869 | struct nfs_open_context *ctx; | 2880 | struct nfs_open_context *ctx; |
2870 | atomic_t refcount; | ||
2871 | struct completion completion; | ||
2872 | }; | 2881 | }; |
2873 | 2882 | ||
2874 | static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata) | 2883 | static void nfs4_locku_release_calldata(void *data) |
2875 | { | ||
2876 | if (atomic_dec_and_test(&calldata->refcount)) { | ||
2877 | nfs_free_seqid(calldata->luargs.seqid); | ||
2878 | nfs4_put_lock_state(calldata->lsp); | ||
2879 | put_nfs_open_context(calldata->ctx); | ||
2880 | kfree(calldata); | ||
2881 | } | ||
2882 | } | ||
2883 | |||
2884 | static void nfs4_locku_complete(void *data) | ||
2885 | { | 2884 | { |
2886 | struct nfs4_unlockdata *calldata = data; | 2885 | struct nfs4_unlockdata *calldata = data; |
2887 | complete(&calldata->completion); | 2886 | nfs_free_seqid(calldata->luargs.seqid); |
2888 | nfs4_locku_release_calldata(calldata); | 2887 | nfs4_put_lock_state(calldata->lsp); |
2888 | put_nfs_open_context(calldata->ctx); | ||
2889 | kfree(calldata); | ||
2889 | } | 2890 | } |
2890 | 2891 | ||
2891 | static void nfs4_locku_done(struct rpc_task *task, void *data) | 2892 | static void nfs4_locku_done(struct rpc_task *task, void *data) |
2892 | { | 2893 | { |
2893 | struct nfs4_unlockdata *calldata = data; | 2894 | struct nfs4_unlockdata *calldata = data; |
2894 | 2895 | ||
2896 | if (RPC_ASSASSINATED(task)) | ||
2897 | return; | ||
2895 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); | 2898 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); |
2896 | switch (task->tk_status) { | 2899 | switch (task->tk_status) { |
2897 | case 0: | 2900 | case 0: |
@@ -2935,7 +2938,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
2935 | static const struct rpc_call_ops nfs4_locku_ops = { | 2938 | static const struct rpc_call_ops nfs4_locku_ops = { |
2936 | .rpc_call_prepare = nfs4_locku_prepare, | 2939 | .rpc_call_prepare = nfs4_locku_prepare, |
2937 | .rpc_call_done = nfs4_locku_done, | 2940 | .rpc_call_done = nfs4_locku_done, |
2938 | .rpc_release = nfs4_locku_complete, | 2941 | .rpc_release = nfs4_locku_release_calldata, |
2939 | }; | 2942 | }; |
2940 | 2943 | ||
2941 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 2944 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
@@ -2944,26 +2947,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
2944 | struct inode *inode = state->inode; | 2947 | struct inode *inode = state->inode; |
2945 | struct nfs_server *server = NFS_SERVER(inode); | 2948 | struct nfs_server *server = NFS_SERVER(inode); |
2946 | struct nfs4_lock_state *lsp; | 2949 | struct nfs4_lock_state *lsp; |
2947 | int status; | 2950 | struct rpc_task *task; |
2951 | int status = 0; | ||
2948 | 2952 | ||
2949 | /* Is this a delegated lock? */ | 2953 | /* Is this a delegated lock? */ |
2950 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 2954 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
2951 | return do_vfs_lock(request->fl_file, request); | 2955 | goto out; |
2952 | 2956 | ||
2953 | status = nfs4_set_lock_state(state, request); | 2957 | status = nfs4_set_lock_state(state, request); |
2954 | if (status != 0) | 2958 | if (status != 0) |
2955 | return status; | 2959 | goto out; |
2956 | lsp = request->fl_u.nfs4_fl.owner; | 2960 | lsp = request->fl_u.nfs4_fl.owner; |
2957 | /* We might have lost the locks! */ | 2961 | /* We might have lost the locks! */ |
2958 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) | 2962 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) |
2959 | return 0; | 2963 | goto out; |
2964 | status = -ENOMEM; | ||
2960 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 2965 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); |
2961 | if (calldata == NULL) | 2966 | if (calldata == NULL) |
2962 | return -ENOMEM; | 2967 | goto out; |
2963 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 2968 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
2964 | if (calldata->luargs.seqid == NULL) { | 2969 | if (calldata->luargs.seqid == NULL) { |
2965 | kfree(calldata); | 2970 | kfree(calldata); |
2966 | return -ENOMEM; | 2971 | goto out; |
2967 | } | 2972 | } |
2968 | calldata->luargs.stateid = &lsp->ls_stateid; | 2973 | calldata->luargs.stateid = &lsp->ls_stateid; |
2969 | calldata->arg.fh = NFS_FH(inode); | 2974 | calldata->arg.fh = NFS_FH(inode); |
@@ -2978,14 +2983,16 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
2978 | /* Ensure we don't close file until we're done freeing locks! */ | 2983 | /* Ensure we don't close file until we're done freeing locks! */ |
2979 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); | 2984 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); |
2980 | 2985 | ||
2981 | atomic_set(&calldata->refcount, 2); | 2986 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_locku_ops, calldata); |
2982 | init_completion(&calldata->completion); | 2987 | if (!IS_ERR(task)) { |
2983 | 2988 | status = nfs4_wait_for_completion_rpc_task(task); | |
2984 | status = nfs4_call_async(NFS_SERVER(inode)->client, &nfs4_locku_ops, calldata); | 2989 | rpc_release_task(task); |
2985 | if (status == 0) | 2990 | } else { |
2986 | wait_for_completion_interruptible(&calldata->completion); | 2991 | status = PTR_ERR(task); |
2992 | nfs4_locku_release_calldata(calldata); | ||
2993 | } | ||
2994 | out: | ||
2987 | do_vfs_lock(request->fl_file, request); | 2995 | do_vfs_lock(request->fl_file, request); |
2988 | nfs4_locku_release_calldata(calldata); | ||
2989 | return status; | 2996 | return status; |
2990 | } | 2997 | } |
2991 | 2998 | ||