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); |