Commit a5d16a4d090bd2af86e648ed9bb205903fcf1e86
1 parent
911d1aaf26
NFSv4: Convert LOCK rpc call into an asynchronous RPC call
In order to allow users to interrupt/cancel it. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 2 changed files with 175 additions and 75 deletions Side-by-side Diff
fs/nfs/nfs4proc.c
... | ... | @@ -3100,11 +3100,30 @@ |
3100 | 3100 | .rpc_release = nfs4_locku_release_calldata, |
3101 | 3101 | }; |
3102 | 3102 | |
3103 | +static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |
3104 | + struct nfs_open_context *ctx, | |
3105 | + struct nfs4_lock_state *lsp, | |
3106 | + struct nfs_seqid *seqid) | |
3107 | +{ | |
3108 | + struct nfs4_unlockdata *data; | |
3109 | + struct rpc_task *task; | |
3110 | + | |
3111 | + data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | |
3112 | + if (data == NULL) { | |
3113 | + nfs_free_seqid(seqid); | |
3114 | + return ERR_PTR(-ENOMEM); | |
3115 | + } | |
3116 | + | |
3117 | + /* Unlock _before_ we do the RPC call */ | |
3118 | + do_vfs_lock(fl->fl_file, fl); | |
3119 | + task = rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); | |
3120 | + if (IS_ERR(task)) | |
3121 | + nfs4_locku_release_calldata(data); | |
3122 | + return task; | |
3123 | +} | |
3124 | + | |
3103 | 3125 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
3104 | 3126 | { |
3105 | - struct nfs4_unlockdata *calldata; | |
3106 | - struct inode *inode = state->inode; | |
3107 | - struct nfs_server *server = NFS_SERVER(inode); | |
3108 | 3127 | struct nfs_seqid *seqid; |
3109 | 3128 | struct nfs4_lock_state *lsp; |
3110 | 3129 | struct rpc_task *task; |
3111 | 3130 | |
3112 | 3131 | |
3113 | 3132 | |
3114 | 3133 | |
3115 | 3134 | |
3116 | 3135 | |
3117 | 3136 | |
3118 | 3137 | |
3119 | 3138 | |
3120 | 3139 | |
... | ... | @@ -3125,86 +3144,173 @@ |
3125 | 3144 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); |
3126 | 3145 | if (seqid == NULL) |
3127 | 3146 | goto out_unlock; |
3128 | - calldata = nfs4_alloc_unlockdata(request, request->fl_file->private_data, | |
3129 | - lsp, seqid); | |
3130 | - if (calldata == NULL) | |
3131 | - goto out_free_seqid; | |
3132 | - /* Unlock _before_ we do the RPC call */ | |
3133 | - do_vfs_lock(request->fl_file, request); | |
3134 | - task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_locku_ops, calldata); | |
3135 | - if (!IS_ERR(task)) { | |
3136 | - status = nfs4_wait_for_completion_rpc_task(task); | |
3137 | - rpc_release_task(task); | |
3138 | - } else { | |
3139 | - status = PTR_ERR(task); | |
3140 | - nfs4_locku_release_calldata(calldata); | |
3141 | - } | |
3147 | + task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); | |
3148 | + status = PTR_ERR(task); | |
3149 | + if (IS_ERR(task)) | |
3150 | + goto out_unlock; | |
3151 | + status = nfs4_wait_for_completion_rpc_task(task); | |
3152 | + rpc_release_task(task); | |
3142 | 3153 | return status; |
3143 | -out_free_seqid: | |
3144 | - nfs_free_seqid(seqid); | |
3145 | 3154 | out_unlock: |
3146 | 3155 | do_vfs_lock(request->fl_file, request); |
3147 | 3156 | return status; |
3148 | 3157 | } |
3149 | 3158 | |
3150 | -static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) | |
3159 | +struct nfs4_lockdata { | |
3160 | + struct nfs_lock_args arg; | |
3161 | + struct nfs_lock_res res; | |
3162 | + struct nfs4_lock_state *lsp; | |
3163 | + struct nfs_open_context *ctx; | |
3164 | + struct file_lock fl; | |
3165 | + int rpc_status; | |
3166 | + int cancelled; | |
3167 | +}; | |
3168 | + | |
3169 | +static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |
3170 | + struct nfs_open_context *ctx, struct nfs4_lock_state *lsp) | |
3151 | 3171 | { |
3152 | - struct inode *inode = state->inode; | |
3172 | + struct nfs4_lockdata *p; | |
3173 | + struct inode *inode = lsp->ls_state->inode; | |
3153 | 3174 | struct nfs_server *server = NFS_SERVER(inode); |
3154 | - struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; | |
3155 | - struct nfs_lock_args arg = { | |
3156 | - .fh = NFS_FH(inode), | |
3157 | - .fl = request, | |
3158 | - .lock_stateid = &lsp->ls_stateid, | |
3159 | - .open_stateid = &state->stateid, | |
3160 | - .lock_owner = { | |
3161 | - .clientid = server->nfs4_state->cl_clientid, | |
3162 | - .id = lsp->ls_id, | |
3163 | - }, | |
3164 | - .block = (IS_SETLKW(cmd)) ? 1 : 0, | |
3165 | - .reclaim = reclaim, | |
3166 | - }; | |
3167 | - struct nfs_lock_res res; | |
3175 | + | |
3176 | + p = kzalloc(sizeof(*p), GFP_KERNEL); | |
3177 | + if (p == NULL) | |
3178 | + return NULL; | |
3179 | + | |
3180 | + p->arg.fh = NFS_FH(inode); | |
3181 | + p->arg.fl = &p->fl; | |
3182 | + p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | |
3183 | + if (p->arg.lock_seqid == NULL) | |
3184 | + goto out_free; | |
3185 | + p->arg.lock_stateid = &lsp->ls_stateid; | |
3186 | + p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; | |
3187 | + p->arg.lock_owner.id = lsp->ls_id; | |
3188 | + p->lsp = lsp; | |
3189 | + atomic_inc(&lsp->ls_count); | |
3190 | + p->ctx = get_nfs_open_context(ctx); | |
3191 | + memcpy(&p->fl, fl, sizeof(p->fl)); | |
3192 | + return p; | |
3193 | +out_free: | |
3194 | + kfree(p); | |
3195 | + return NULL; | |
3196 | +} | |
3197 | + | |
3198 | +static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |
3199 | +{ | |
3200 | + struct nfs4_lockdata *data = calldata; | |
3201 | + struct nfs4_state *state = data->lsp->ls_state; | |
3202 | + struct nfs4_state_owner *sp = state->owner; | |
3168 | 3203 | struct rpc_message msg = { |
3169 | - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | |
3170 | - .rpc_argp = &arg, | |
3171 | - .rpc_resp = &res, | |
3172 | - .rpc_cred = state->owner->so_cred, | |
3204 | + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | |
3205 | + .rpc_argp = &data->arg, | |
3206 | + .rpc_resp = &data->res, | |
3207 | + .rpc_cred = sp->so_cred, | |
3173 | 3208 | }; |
3174 | - int status = -ENOMEM; | |
3175 | 3209 | |
3176 | - arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | |
3177 | - if (arg.lock_seqid == NULL) | |
3178 | - return -ENOMEM; | |
3179 | - if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { | |
3180 | - struct nfs4_state_owner *owner = state->owner; | |
3181 | - | |
3182 | - arg.open_seqid = nfs_alloc_seqid(&owner->so_seqid); | |
3183 | - if (arg.open_seqid == NULL) | |
3210 | + if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) | |
3211 | + return; | |
3212 | + dprintk("%s: begin!\n", __FUNCTION__); | |
3213 | + /* Do we need to do an open_to_lock_owner? */ | |
3214 | + if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { | |
3215 | + data->arg.open_seqid = nfs_alloc_seqid(&sp->so_seqid); | |
3216 | + if (data->arg.open_seqid == NULL) { | |
3217 | + data->rpc_status = -ENOMEM; | |
3218 | + task->tk_action = NULL; | |
3184 | 3219 | goto out; |
3185 | - arg.new_lock_owner = 1; | |
3186 | - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | |
3187 | - /* increment open seqid on success, and seqid mutating errors */ | |
3188 | - if (arg.new_lock_owner != 0) { | |
3189 | - nfs_increment_open_seqid(status, arg.open_seqid); | |
3190 | - if (status == 0) | |
3191 | - nfs_confirm_seqid(&lsp->ls_seqid, 0); | |
3192 | 3220 | } |
3193 | - nfs_free_seqid(arg.open_seqid); | |
3194 | - } else | |
3195 | - status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | |
3196 | - /* increment lock seqid on success, and seqid mutating errors*/ | |
3197 | - nfs_increment_lock_seqid(status, arg.lock_seqid); | |
3198 | - /* save the returned stateid. */ | |
3199 | - if (status == 0) { | |
3200 | - memcpy(lsp->ls_stateid.data, res.stateid.data, | |
3201 | - sizeof(lsp->ls_stateid.data)); | |
3202 | - lsp->ls_flags |= NFS_LOCK_INITIALIZED; | |
3203 | - } else if (status == -NFS4ERR_DENIED) | |
3204 | - status = -EAGAIN; | |
3221 | + data->arg.open_stateid = &state->stateid; | |
3222 | + data->arg.new_lock_owner = 1; | |
3223 | + } | |
3224 | + rpc_call_setup(task, &msg, 0); | |
3205 | 3225 | out: |
3206 | - nfs_free_seqid(arg.lock_seqid); | |
3207 | - return status; | |
3226 | + dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); | |
3227 | +} | |
3228 | + | |
3229 | +static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |
3230 | +{ | |
3231 | + struct nfs4_lockdata *data = calldata; | |
3232 | + | |
3233 | + dprintk("%s: begin!\n", __FUNCTION__); | |
3234 | + | |
3235 | + data->rpc_status = task->tk_status; | |
3236 | + if (RPC_ASSASSINATED(task)) | |
3237 | + goto out; | |
3238 | + if (data->arg.new_lock_owner != 0) { | |
3239 | + nfs_increment_open_seqid(data->rpc_status, data->arg.open_seqid); | |
3240 | + if (data->rpc_status == 0) | |
3241 | + nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | |
3242 | + else | |
3243 | + goto out; | |
3244 | + } | |
3245 | + if (data->rpc_status == 0) { | |
3246 | + memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | |
3247 | + sizeof(data->lsp->ls_stateid.data)); | |
3248 | + data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | |
3249 | + } | |
3250 | + nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | |
3251 | +out: | |
3252 | + dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); | |
3253 | +} | |
3254 | + | |
3255 | +static void nfs4_lock_release(void *calldata) | |
3256 | +{ | |
3257 | + struct nfs4_lockdata *data = calldata; | |
3258 | + | |
3259 | + dprintk("%s: begin!\n", __FUNCTION__); | |
3260 | + if (data->arg.open_seqid != NULL) | |
3261 | + nfs_free_seqid(data->arg.open_seqid); | |
3262 | + if (data->cancelled != 0) { | |
3263 | + struct rpc_task *task; | |
3264 | + task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, | |
3265 | + data->arg.lock_seqid); | |
3266 | + if (!IS_ERR(task)) | |
3267 | + rpc_release_task(task); | |
3268 | + dprintk("%s: cancelling lock!\n", __FUNCTION__); | |
3269 | + } else | |
3270 | + nfs_free_seqid(data->arg.lock_seqid); | |
3271 | + nfs4_put_lock_state(data->lsp); | |
3272 | + put_nfs_open_context(data->ctx); | |
3273 | + kfree(data); | |
3274 | + dprintk("%s: done!\n", __FUNCTION__); | |
3275 | +} | |
3276 | + | |
3277 | +static const struct rpc_call_ops nfs4_lock_ops = { | |
3278 | + .rpc_call_prepare = nfs4_lock_prepare, | |
3279 | + .rpc_call_done = nfs4_lock_done, | |
3280 | + .rpc_release = nfs4_lock_release, | |
3281 | +}; | |
3282 | + | |
3283 | +static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) | |
3284 | +{ | |
3285 | + struct nfs4_lockdata *data; | |
3286 | + struct rpc_task *task; | |
3287 | + int ret; | |
3288 | + | |
3289 | + dprintk("%s: begin!\n", __FUNCTION__); | |
3290 | + data = nfs4_alloc_lockdata(fl, fl->fl_file->private_data, | |
3291 | + fl->fl_u.nfs4_fl.owner); | |
3292 | + if (data == NULL) | |
3293 | + return -ENOMEM; | |
3294 | + if (IS_SETLKW(cmd)) | |
3295 | + data->arg.block = 1; | |
3296 | + if (reclaim != 0) | |
3297 | + data->arg.reclaim = 1; | |
3298 | + task = rpc_run_task(NFS_CLIENT(state->inode), RPC_TASK_ASYNC, | |
3299 | + &nfs4_lock_ops, data); | |
3300 | + if (IS_ERR(task)) { | |
3301 | + nfs4_lock_release(data); | |
3302 | + return PTR_ERR(task); | |
3303 | + } | |
3304 | + ret = nfs4_wait_for_completion_rpc_task(task); | |
3305 | + if (ret == 0) { | |
3306 | + ret = data->rpc_status; | |
3307 | + if (ret == -NFS4ERR_DENIED) | |
3308 | + ret = -EAGAIN; | |
3309 | + } else | |
3310 | + data->cancelled = 1; | |
3311 | + rpc_release_task(task); | |
3312 | + dprintk("%s: done, ret = %d!\n", __FUNCTION__, ret); | |
3313 | + return ret; | |
3208 | 3314 | } |
3209 | 3315 | |
3210 | 3316 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) |
fs/nfs/nfs4xdr.c
... | ... | @@ -1615,12 +1615,6 @@ |
1615 | 1615 | }; |
1616 | 1616 | int status; |
1617 | 1617 | |
1618 | - status = nfs_wait_on_sequence(args->lock_seqid, req->rq_task); | |
1619 | - if (status != 0) | |
1620 | - goto out; | |
1621 | - /* Do we need to do an open_to_lock_owner? */ | |
1622 | - if (args->lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED) | |
1623 | - args->new_lock_owner = 0; | |
1624 | 1618 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1625 | 1619 | encode_compound_hdr(&xdr, &hdr); |
1626 | 1620 | status = encode_putfh(&xdr, args->fh); |