aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-01-03 03:55:17 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-01-06 14:58:44 -0500
commita5d16a4d090bd2af86e648ed9bb205903fcf1e86 (patch)
tree9fd615f3991e50d07583010d9703a3d1aced8419 /fs
parent911d1aaf26fc4d771174d98fcab710a44e2a5fa0 (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>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4proc.c244
-rw-r--r--fs/nfs/nfs4xdr.c6
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
3103static 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
3103static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) 3125static 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;
3143out_free_seqid:
3144 nfs_free_seqid(seqid);
3145out_unlock: 3154out_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
3150static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) 3159struct 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
3169static 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;
3193out_free:
3194 kfree(p);
3195 return NULL;
3196}
3197
3198static 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;
3205out: 3225out:
3206 nfs_free_seqid(arg.lock_seqid); 3226 dprintk("%s: done!, ret = %d\n", __FUNCTION__, data->rpc_status);
3207 return status; 3227}
3228
3229static 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);
3251out:
3252 dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status);
3253}
3254
3255static 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
3277static 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
3283static 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
3210static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) 3316static 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);