diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 192 |
1 files changed, 80 insertions, 112 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3ecb7da220f5..857125705b6f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2935,43 +2935,17 @@ nfs4_set_lock_task_retry(unsigned long timeout) | |||
2935 | return timeout; | 2935 | return timeout; |
2936 | } | 2936 | } |
2937 | 2937 | ||
2938 | static inline int | ||
2939 | nfs4_lck_type(int cmd, struct file_lock *request) | ||
2940 | { | ||
2941 | /* set lock type */ | ||
2942 | switch (request->fl_type) { | ||
2943 | case F_RDLCK: | ||
2944 | return IS_SETLKW(cmd) ? NFS4_READW_LT : NFS4_READ_LT; | ||
2945 | case F_WRLCK: | ||
2946 | return IS_SETLKW(cmd) ? NFS4_WRITEW_LT : NFS4_WRITE_LT; | ||
2947 | case F_UNLCK: | ||
2948 | return NFS4_WRITE_LT; | ||
2949 | } | ||
2950 | BUG(); | ||
2951 | return 0; | ||
2952 | } | ||
2953 | |||
2954 | static inline uint64_t | ||
2955 | nfs4_lck_length(struct file_lock *request) | ||
2956 | { | ||
2957 | if (request->fl_end == OFFSET_MAX) | ||
2958 | return ~(uint64_t)0; | ||
2959 | return request->fl_end - request->fl_start + 1; | ||
2960 | } | ||
2961 | |||
2962 | static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 2938 | static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
2963 | { | 2939 | { |
2964 | struct inode *inode = state->inode; | 2940 | struct inode *inode = state->inode; |
2965 | struct nfs_server *server = NFS_SERVER(inode); | 2941 | struct nfs_server *server = NFS_SERVER(inode); |
2966 | struct nfs4_client *clp = server->nfs4_state; | 2942 | struct nfs4_client *clp = server->nfs4_state; |
2967 | struct nfs_lockargs arg = { | 2943 | struct nfs_lockt_args arg = { |
2968 | .fh = NFS_FH(inode), | 2944 | .fh = NFS_FH(inode), |
2969 | .type = nfs4_lck_type(cmd, request), | 2945 | .fl = request, |
2970 | .offset = request->fl_start, | ||
2971 | .length = nfs4_lck_length(request), | ||
2972 | }; | 2946 | }; |
2973 | struct nfs_lockres res = { | 2947 | struct nfs_lockt_res res = { |
2974 | .server = server, | 2948 | .denied = request, |
2975 | }; | 2949 | }; |
2976 | struct rpc_message msg = { | 2950 | struct rpc_message msg = { |
2977 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], | 2951 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], |
@@ -2979,36 +2953,23 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
2979 | .rpc_resp = &res, | 2953 | .rpc_resp = &res, |
2980 | .rpc_cred = state->owner->so_cred, | 2954 | .rpc_cred = state->owner->so_cred, |
2981 | }; | 2955 | }; |
2982 | struct nfs_lowner nlo; | ||
2983 | struct nfs4_lock_state *lsp; | 2956 | struct nfs4_lock_state *lsp; |
2984 | int status; | 2957 | int status; |
2985 | 2958 | ||
2986 | down_read(&clp->cl_sem); | 2959 | down_read(&clp->cl_sem); |
2987 | nlo.clientid = clp->cl_clientid; | 2960 | arg.lock_owner.clientid = clp->cl_clientid; |
2988 | status = nfs4_set_lock_state(state, request); | 2961 | status = nfs4_set_lock_state(state, request); |
2989 | if (status != 0) | 2962 | if (status != 0) |
2990 | goto out; | 2963 | goto out; |
2991 | lsp = request->fl_u.nfs4_fl.owner; | 2964 | lsp = request->fl_u.nfs4_fl.owner; |
2992 | nlo.id = lsp->ls_id; | 2965 | arg.lock_owner.id = lsp->ls_id; |
2993 | arg.u.lockt = &nlo; | ||
2994 | status = rpc_call_sync(server->client, &msg, 0); | 2966 | status = rpc_call_sync(server->client, &msg, 0); |
2995 | if (!status) { | 2967 | switch (status) { |
2996 | request->fl_type = F_UNLCK; | 2968 | case 0: |
2997 | } else if (status == -NFS4ERR_DENIED) { | 2969 | request->fl_type = F_UNLCK; |
2998 | int64_t len, start, end; | 2970 | break; |
2999 | start = res.u.denied.offset; | 2971 | case -NFS4ERR_DENIED: |
3000 | len = res.u.denied.length; | 2972 | status = 0; |
3001 | end = start + len - 1; | ||
3002 | if (end < 0 || len == 0) | ||
3003 | request->fl_end = OFFSET_MAX; | ||
3004 | else | ||
3005 | request->fl_end = (loff_t)end; | ||
3006 | request->fl_start = (loff_t)start; | ||
3007 | request->fl_type = F_WRLCK; | ||
3008 | if (res.u.denied.type & 1) | ||
3009 | request->fl_type = F_RDLCK; | ||
3010 | request->fl_pid = 0; | ||
3011 | status = 0; | ||
3012 | } | 2973 | } |
3013 | out: | 2974 | out: |
3014 | up_read(&clp->cl_sem); | 2975 | up_read(&clp->cl_sem); |
@@ -3048,17 +3009,42 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
3048 | } | 3009 | } |
3049 | 3010 | ||
3050 | struct nfs4_unlockdata { | 3011 | struct nfs4_unlockdata { |
3051 | struct nfs_lockargs arg; | 3012 | struct nfs_locku_args arg; |
3052 | struct nfs_locku_opargs luargs; | 3013 | struct nfs_locku_res res; |
3053 | struct nfs_lockres res; | ||
3054 | struct nfs4_lock_state *lsp; | 3014 | struct nfs4_lock_state *lsp; |
3055 | struct nfs_open_context *ctx; | 3015 | struct nfs_open_context *ctx; |
3016 | struct file_lock fl; | ||
3017 | const struct nfs_server *server; | ||
3056 | }; | 3018 | }; |
3057 | 3019 | ||
3020 | static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | ||
3021 | struct nfs_open_context *ctx, | ||
3022 | struct nfs4_lock_state *lsp, | ||
3023 | struct nfs_seqid *seqid) | ||
3024 | { | ||
3025 | struct nfs4_unlockdata *p; | ||
3026 | struct inode *inode = lsp->ls_state->inode; | ||
3027 | |||
3028 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
3029 | if (p == NULL) | ||
3030 | return NULL; | ||
3031 | p->arg.fh = NFS_FH(inode); | ||
3032 | p->arg.fl = &p->fl; | ||
3033 | p->arg.seqid = seqid; | ||
3034 | p->arg.stateid = &lsp->ls_stateid; | ||
3035 | p->lsp = lsp; | ||
3036 | atomic_inc(&lsp->ls_count); | ||
3037 | /* Ensure we don't close file until we're done freeing locks! */ | ||
3038 | p->ctx = get_nfs_open_context(ctx); | ||
3039 | memcpy(&p->fl, fl, sizeof(p->fl)); | ||
3040 | p->server = NFS_SERVER(inode); | ||
3041 | return p; | ||
3042 | } | ||
3043 | |||
3058 | static void nfs4_locku_release_calldata(void *data) | 3044 | static void nfs4_locku_release_calldata(void *data) |
3059 | { | 3045 | { |
3060 | struct nfs4_unlockdata *calldata = data; | 3046 | struct nfs4_unlockdata *calldata = data; |
3061 | nfs_free_seqid(calldata->luargs.seqid); | 3047 | nfs_free_seqid(calldata->arg.seqid); |
3062 | nfs4_put_lock_state(calldata->lsp); | 3048 | nfs4_put_lock_state(calldata->lsp); |
3063 | put_nfs_open_context(calldata->ctx); | 3049 | put_nfs_open_context(calldata->ctx); |
3064 | kfree(calldata); | 3050 | kfree(calldata); |
@@ -3070,19 +3056,19 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3070 | 3056 | ||
3071 | if (RPC_ASSASSINATED(task)) | 3057 | if (RPC_ASSASSINATED(task)) |
3072 | return; | 3058 | return; |
3073 | nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); | 3059 | nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid); |
3074 | switch (task->tk_status) { | 3060 | switch (task->tk_status) { |
3075 | case 0: | 3061 | case 0: |
3076 | memcpy(calldata->lsp->ls_stateid.data, | 3062 | memcpy(calldata->lsp->ls_stateid.data, |
3077 | calldata->res.u.stateid.data, | 3063 | calldata->res.stateid.data, |
3078 | sizeof(calldata->lsp->ls_stateid.data)); | 3064 | sizeof(calldata->lsp->ls_stateid.data)); |
3079 | break; | 3065 | break; |
3080 | case -NFS4ERR_STALE_STATEID: | 3066 | case -NFS4ERR_STALE_STATEID: |
3081 | case -NFS4ERR_EXPIRED: | 3067 | case -NFS4ERR_EXPIRED: |
3082 | nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); | 3068 | nfs4_schedule_state_recovery(calldata->server->nfs4_state); |
3083 | break; | 3069 | break; |
3084 | default: | 3070 | default: |
3085 | if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { | 3071 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { |
3086 | rpc_restart_call(task); | 3072 | rpc_restart_call(task); |
3087 | } | 3073 | } |
3088 | } | 3074 | } |
@@ -3097,10 +3083,8 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3097 | .rpc_resp = &calldata->res, | 3083 | .rpc_resp = &calldata->res, |
3098 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, | 3084 | .rpc_cred = calldata->lsp->ls_state->owner->so_cred, |
3099 | }; | 3085 | }; |
3100 | int status; | ||
3101 | 3086 | ||
3102 | status = nfs_wait_on_sequence(calldata->luargs.seqid, task); | 3087 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
3103 | if (status != 0) | ||
3104 | return; | 3088 | return; |
3105 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { | 3089 | if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { |
3106 | /* Note: exit _without_ running nfs4_locku_done */ | 3090 | /* Note: exit _without_ running nfs4_locku_done */ |
@@ -3121,43 +3105,32 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3121 | struct nfs4_unlockdata *calldata; | 3105 | struct nfs4_unlockdata *calldata; |
3122 | struct inode *inode = state->inode; | 3106 | struct inode *inode = state->inode; |
3123 | struct nfs_server *server = NFS_SERVER(inode); | 3107 | struct nfs_server *server = NFS_SERVER(inode); |
3108 | struct nfs_seqid *seqid; | ||
3124 | struct nfs4_lock_state *lsp; | 3109 | struct nfs4_lock_state *lsp; |
3125 | struct rpc_task *task; | 3110 | struct rpc_task *task; |
3126 | int status = 0; | 3111 | int status = 0; |
3127 | 3112 | ||
3128 | /* Is this a delegated lock? */ | 3113 | /* Is this a delegated lock? */ |
3129 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 3114 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
3130 | goto out; | 3115 | goto out_unlock; |
3116 | /* Is this open_owner holding any locks on the server? */ | ||
3117 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | ||
3118 | goto out_unlock; | ||
3131 | 3119 | ||
3132 | status = nfs4_set_lock_state(state, request); | 3120 | status = nfs4_set_lock_state(state, request); |
3133 | if (status != 0) | 3121 | if (status != 0) |
3134 | goto out; | 3122 | goto out_unlock; |
3135 | lsp = request->fl_u.nfs4_fl.owner; | 3123 | lsp = request->fl_u.nfs4_fl.owner; |
3136 | /* We might have lost the locks! */ | ||
3137 | if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) | ||
3138 | goto out; | ||
3139 | status = -ENOMEM; | 3124 | status = -ENOMEM; |
3140 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 3125 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
3126 | if (seqid == NULL) | ||
3127 | goto out_unlock; | ||
3128 | calldata = nfs4_alloc_unlockdata(request, request->fl_file->private_data, | ||
3129 | lsp, seqid); | ||
3141 | if (calldata == NULL) | 3130 | if (calldata == NULL) |
3142 | goto out; | 3131 | goto out_free_seqid; |
3143 | calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3132 | /* Unlock _before_ we do the RPC call */ |
3144 | if (calldata->luargs.seqid == NULL) { | 3133 | do_vfs_lock(request->fl_file, request); |
3145 | kfree(calldata); | ||
3146 | goto out; | ||
3147 | } | ||
3148 | calldata->luargs.stateid = &lsp->ls_stateid; | ||
3149 | calldata->arg.fh = NFS_FH(inode); | ||
3150 | calldata->arg.type = nfs4_lck_type(cmd, request); | ||
3151 | calldata->arg.offset = request->fl_start; | ||
3152 | calldata->arg.length = nfs4_lck_length(request); | ||
3153 | calldata->arg.u.locku = &calldata->luargs; | ||
3154 | calldata->res.server = server; | ||
3155 | calldata->lsp = lsp; | ||
3156 | atomic_inc(&lsp->ls_count); | ||
3157 | |||
3158 | /* Ensure we don't close file until we're done freeing locks! */ | ||
3159 | calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data); | ||
3160 | |||
3161 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_locku_ops, calldata); | 3134 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_locku_ops, calldata); |
3162 | if (!IS_ERR(task)) { | 3135 | if (!IS_ERR(task)) { |
3163 | status = nfs4_wait_for_completion_rpc_task(task); | 3136 | status = nfs4_wait_for_completion_rpc_task(task); |
@@ -3166,7 +3139,10 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3166 | status = PTR_ERR(task); | 3139 | status = PTR_ERR(task); |
3167 | nfs4_locku_release_calldata(calldata); | 3140 | nfs4_locku_release_calldata(calldata); |
3168 | } | 3141 | } |
3169 | out: | 3142 | return status; |
3143 | out_free_seqid: | ||
3144 | nfs_free_seqid(seqid); | ||
3145 | out_unlock: | ||
3170 | do_vfs_lock(request->fl_file, request); | 3146 | do_vfs_lock(request->fl_file, request); |
3171 | return status; | 3147 | return status; |
3172 | } | 3148 | } |
@@ -3176,27 +3152,19 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
3176 | struct inode *inode = state->inode; | 3152 | struct inode *inode = state->inode; |
3177 | struct nfs_server *server = NFS_SERVER(inode); | 3153 | struct nfs_server *server = NFS_SERVER(inode); |
3178 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; | 3154 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; |
3179 | struct nfs_lock_opargs largs = { | 3155 | struct nfs_lock_args arg = { |
3156 | .fh = NFS_FH(inode), | ||
3157 | .fl = request, | ||
3180 | .lock_stateid = &lsp->ls_stateid, | 3158 | .lock_stateid = &lsp->ls_stateid, |
3181 | .open_stateid = &state->stateid, | 3159 | .open_stateid = &state->stateid, |
3182 | .lock_owner = { | 3160 | .lock_owner = { |
3183 | .clientid = server->nfs4_state->cl_clientid, | 3161 | .clientid = server->nfs4_state->cl_clientid, |
3184 | .id = lsp->ls_id, | 3162 | .id = lsp->ls_id, |
3185 | }, | 3163 | }, |
3164 | .block = (IS_SETLKW(cmd)) ? 1 : 0, | ||
3186 | .reclaim = reclaim, | 3165 | .reclaim = reclaim, |
3187 | }; | 3166 | }; |
3188 | struct nfs_lockargs arg = { | 3167 | struct nfs_lock_res res; |
3189 | .fh = NFS_FH(inode), | ||
3190 | .type = nfs4_lck_type(cmd, request), | ||
3191 | .offset = request->fl_start, | ||
3192 | .length = nfs4_lck_length(request), | ||
3193 | .u = { | ||
3194 | .lock = &largs, | ||
3195 | }, | ||
3196 | }; | ||
3197 | struct nfs_lockres res = { | ||
3198 | .server = server, | ||
3199 | }; | ||
3200 | struct rpc_message msg = { | 3168 | struct rpc_message msg = { |
3201 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | 3169 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], |
3202 | .rpc_argp = &arg, | 3170 | .rpc_argp = &arg, |
@@ -3205,37 +3173,37 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r | |||
3205 | }; | 3173 | }; |
3206 | int status = -ENOMEM; | 3174 | int status = -ENOMEM; |
3207 | 3175 | ||
3208 | largs.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3176 | arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
3209 | if (largs.lock_seqid == NULL) | 3177 | if (arg.lock_seqid == NULL) |
3210 | return -ENOMEM; | 3178 | return -ENOMEM; |
3211 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | 3179 | if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { |
3212 | struct nfs4_state_owner *owner = state->owner; | 3180 | struct nfs4_state_owner *owner = state->owner; |
3213 | 3181 | ||
3214 | largs.open_seqid = nfs_alloc_seqid(&owner->so_seqid); | 3182 | arg.open_seqid = nfs_alloc_seqid(&owner->so_seqid); |
3215 | if (largs.open_seqid == NULL) | 3183 | if (arg.open_seqid == NULL) |
3216 | goto out; | 3184 | goto out; |
3217 | largs.new_lock_owner = 1; | 3185 | arg.new_lock_owner = 1; |
3218 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3186 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
3219 | /* increment open seqid on success, and seqid mutating errors */ | 3187 | /* increment open seqid on success, and seqid mutating errors */ |
3220 | if (largs.new_lock_owner != 0) { | 3188 | if (arg.new_lock_owner != 0) { |
3221 | nfs_increment_open_seqid(status, largs.open_seqid); | 3189 | nfs_increment_open_seqid(status, arg.open_seqid); |
3222 | if (status == 0) | 3190 | if (status == 0) |
3223 | nfs_confirm_seqid(&lsp->ls_seqid, 0); | 3191 | nfs_confirm_seqid(&lsp->ls_seqid, 0); |
3224 | } | 3192 | } |
3225 | nfs_free_seqid(largs.open_seqid); | 3193 | nfs_free_seqid(arg.open_seqid); |
3226 | } else | 3194 | } else |
3227 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3195 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); |
3228 | /* increment lock seqid on success, and seqid mutating errors*/ | 3196 | /* increment lock seqid on success, and seqid mutating errors*/ |
3229 | nfs_increment_lock_seqid(status, largs.lock_seqid); | 3197 | nfs_increment_lock_seqid(status, arg.lock_seqid); |
3230 | /* save the returned stateid. */ | 3198 | /* save the returned stateid. */ |
3231 | if (status == 0) { | 3199 | if (status == 0) { |
3232 | memcpy(lsp->ls_stateid.data, res.u.stateid.data, | 3200 | memcpy(lsp->ls_stateid.data, res.stateid.data, |
3233 | sizeof(lsp->ls_stateid.data)); | 3201 | sizeof(lsp->ls_stateid.data)); |
3234 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 3202 | lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
3235 | } else if (status == -NFS4ERR_DENIED) | 3203 | } else if (status == -NFS4ERR_DENIED) |
3236 | status = -EAGAIN; | 3204 | status = -EAGAIN; |
3237 | out: | 3205 | out: |
3238 | nfs_free_seqid(largs.lock_seqid); | 3206 | nfs_free_seqid(arg.lock_seqid); |
3239 | return status; | 3207 | return status; |
3240 | } | 3208 | } |
3241 | 3209 | ||