diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-03 03:55:17 -0500 | 
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-01-06 14:58:44 -0500 | 
| commit | a5d16a4d090bd2af86e648ed9bb205903fcf1e86 (patch) | |
| tree | 9fd615f3991e50d07583010d9703a3d1aced8419 | |
| parent | 911d1aaf26fc4d771174d98fcab710a44e2a5fa0 (diff) | |
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>
| -rw-r--r-- | fs/nfs/nfs4proc.c | 244 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 6 | 
2 files changed, 175 insertions, 75 deletions
| diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 857125705b6f..718fcc722556 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -3100,11 +3100,30 @@ static const struct rpc_call_ops nfs4_locku_ops = { | |||
| 3100 | .rpc_release = nfs4_locku_release_calldata, | 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 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) | 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 | struct nfs_seqid *seqid; | 3127 | struct nfs_seqid *seqid; | 
| 3109 | struct nfs4_lock_state *lsp; | 3128 | struct nfs4_lock_state *lsp; | 
| 3110 | struct rpc_task *task; | 3129 | struct rpc_task *task; | 
| @@ -3125,86 +3144,173 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
| 3125 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 3144 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 
| 3126 | if (seqid == NULL) | 3145 | if (seqid == NULL) | 
| 3127 | goto out_unlock; | 3146 | goto out_unlock; | 
| 3128 | calldata = nfs4_alloc_unlockdata(request, request->fl_file->private_data, | 3147 | task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); | 
| 3129 | lsp, seqid); | 3148 | status = PTR_ERR(task); | 
| 3130 | if (calldata == NULL) | 3149 | if (IS_ERR(task)) | 
| 3131 | goto out_free_seqid; | 3150 | goto out_unlock; | 
| 3132 | /* Unlock _before_ we do the RPC call */ | 3151 | status = nfs4_wait_for_completion_rpc_task(task); | 
| 3133 | do_vfs_lock(request->fl_file, request); | 3152 | rpc_release_task(task); | 
| 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 | } | ||
| 3142 | return status; | 3153 | return status; | 
| 3143 | out_free_seqid: | ||
| 3144 | nfs_free_seqid(seqid); | ||
| 3145 | out_unlock: | 3154 | out_unlock: | 
| 3146 | do_vfs_lock(request->fl_file, request); | 3155 | do_vfs_lock(request->fl_file, request); | 
| 3147 | return status; | 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 | struct nfs_server *server = NFS_SERVER(inode); | 3174 | struct nfs_server *server = NFS_SERVER(inode); | 
| 3154 | struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; | 3175 | |
| 3155 | struct nfs_lock_args arg = { | 3176 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 
| 3156 | .fh = NFS_FH(inode), | 3177 | if (p == NULL) | 
| 3157 | .fl = request, | 3178 | return NULL; | 
| 3158 | .lock_stateid = &lsp->ls_stateid, | 3179 | |
| 3159 | .open_stateid = &state->stateid, | 3180 | p->arg.fh = NFS_FH(inode); | 
| 3160 | .lock_owner = { | 3181 | p->arg.fl = &p->fl; | 
| 3161 | .clientid = server->nfs4_state->cl_clientid, | 3182 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 
| 3162 | .id = lsp->ls_id, | 3183 | if (p->arg.lock_seqid == NULL) | 
| 3163 | }, | 3184 | goto out_free; | 
| 3164 | .block = (IS_SETLKW(cmd)) ? 1 : 0, | 3185 | p->arg.lock_stateid = &lsp->ls_stateid; | 
| 3165 | .reclaim = reclaim, | 3186 | p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; | 
| 3166 | }; | 3187 | p->arg.lock_owner.id = lsp->ls_id; | 
| 3167 | struct nfs_lock_res res; | 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 | struct rpc_message msg = { | 3203 | struct rpc_message msg = { | 
| 3169 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | 3204 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], | 
| 3170 | .rpc_argp = &arg, | 3205 | .rpc_argp = &data->arg, | 
| 3171 | .rpc_resp = &res, | 3206 | .rpc_resp = &data->res, | 
| 3172 | .rpc_cred = state->owner->so_cred, | 3207 | .rpc_cred = sp->so_cred, | 
| 3173 | }; | 3208 | }; | 
| 3174 | int status = -ENOMEM; | ||
| 3175 | |||
| 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 | 3209 | ||
| 3182 | arg.open_seqid = nfs_alloc_seqid(&owner->so_seqid); | 3210 | if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) | 
| 3183 | if (arg.open_seqid == NULL) | 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 | goto out; | 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); | 3221 | data->arg.open_stateid = &state->stateid; | 
| 3194 | } else | 3222 | data->arg.new_lock_owner = 1; | 
| 3195 | status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); | 3223 | } | 
| 3196 | /* increment lock seqid on success, and seqid mutating errors*/ | 3224 | rpc_call_setup(task, &msg, 0); | 
| 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; | ||
| 3205 | out: | 3225 | out: | 
| 3206 | nfs_free_seqid(arg.lock_seqid); | 3226 | dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status); | 
| 3207 | return 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 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 3316 | static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) | 
| diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index a7b5de899c6d..5d6bda43dfaa 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -1615,12 +1615,6 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_ | |||
| 1615 | }; | 1615 | }; | 
| 1616 | int status; | 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 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1618 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 
| 1625 | encode_compound_hdr(&xdr, &hdr); | 1619 | encode_compound_hdr(&xdr, &hdr); | 
| 1626 | status = encode_putfh(&xdr, args->fh); | 1620 | status = encode_putfh(&xdr, args->fh); | 
