|
17 | 17 | #include "internal.h"
|
18 | 18 |
|
19 | 19 | #define NFSDBG_FACILITY NFSDBG_PROC
|
| 20 | +static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std); |
20 | 21 |
|
21 | 22 | static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
|
22 | 23 | struct nfs_lock_context *lock, loff_t offset, loff_t len)
|
@@ -166,10 +167,15 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
166 | 167 | list_add_tail(©->copies, &server->ss_copies);
|
167 | 168 | spin_unlock(&server->nfs_client->cl_lock);
|
168 | 169 |
|
169 |
| - wait_for_completion_interruptible(©->completion); |
| 170 | + status = wait_for_completion_interruptible(©->completion); |
170 | 171 | spin_lock(&server->nfs_client->cl_lock);
|
171 | 172 | list_del_init(©->copies);
|
172 | 173 | spin_unlock(&server->nfs_client->cl_lock);
|
| 174 | + if (status == -ERESTARTSYS) { |
| 175 | + nfs42_do_offload_cancel_async(dst, ©->stateid); |
| 176 | + kfree(copy); |
| 177 | + return status; |
| 178 | + } |
173 | 179 | out:
|
174 | 180 | res->write_res.count = copy->count;
|
175 | 181 | memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
|
@@ -327,6 +333,89 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
|
327 | 333 | return err;
|
328 | 334 | }
|
329 | 335 |
|
| 336 | +struct nfs42_offloadcancel_data { |
| 337 | + struct nfs_server *seq_server; |
| 338 | + struct nfs42_offload_status_args args; |
| 339 | + struct nfs42_offload_status_res res; |
| 340 | +}; |
| 341 | + |
| 342 | +static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata) |
| 343 | +{ |
| 344 | + struct nfs42_offloadcancel_data *data = calldata; |
| 345 | + |
| 346 | + nfs4_setup_sequence(data->seq_server->nfs_client, |
| 347 | + &data->args.osa_seq_args, |
| 348 | + &data->res.osr_seq_res, task); |
| 349 | +} |
| 350 | + |
| 351 | +static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata) |
| 352 | +{ |
| 353 | + struct nfs42_offloadcancel_data *data = calldata; |
| 354 | + |
| 355 | + nfs41_sequence_done(task, &data->res.osr_seq_res); |
| 356 | + if (task->tk_status && |
| 357 | + nfs4_async_handle_error(task, data->seq_server, NULL, |
| 358 | + NULL) == -EAGAIN) |
| 359 | + rpc_restart_call_prepare(task); |
| 360 | +} |
| 361 | + |
| 362 | +static void nfs42_free_offloadcancel_data(void *data) |
| 363 | +{ |
| 364 | + kfree(data); |
| 365 | +} |
| 366 | + |
| 367 | +static const struct rpc_call_ops nfs42_offload_cancel_ops = { |
| 368 | + .rpc_call_prepare = nfs42_offload_cancel_prepare, |
| 369 | + .rpc_call_done = nfs42_offload_cancel_done, |
| 370 | + .rpc_release = nfs42_free_offloadcancel_data, |
| 371 | +}; |
| 372 | + |
| 373 | +static int nfs42_do_offload_cancel_async(struct file *dst, |
| 374 | + nfs4_stateid *stateid) |
| 375 | +{ |
| 376 | + struct nfs_server *dst_server = NFS_SERVER(file_inode(dst)); |
| 377 | + struct nfs42_offloadcancel_data *data = NULL; |
| 378 | + struct nfs_open_context *ctx = nfs_file_open_context(dst); |
| 379 | + struct rpc_task *task; |
| 380 | + struct rpc_message msg = { |
| 381 | + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL], |
| 382 | + .rpc_cred = ctx->cred, |
| 383 | + }; |
| 384 | + struct rpc_task_setup task_setup_data = { |
| 385 | + .rpc_client = dst_server->client, |
| 386 | + .rpc_message = &msg, |
| 387 | + .callback_ops = &nfs42_offload_cancel_ops, |
| 388 | + .workqueue = nfsiod_workqueue, |
| 389 | + .flags = RPC_TASK_ASYNC, |
| 390 | + }; |
| 391 | + int status; |
| 392 | + |
| 393 | + if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL)) |
| 394 | + return -EOPNOTSUPP; |
| 395 | + |
| 396 | + data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS); |
| 397 | + if (data == NULL) |
| 398 | + return -ENOMEM; |
| 399 | + |
| 400 | + data->seq_server = dst_server; |
| 401 | + data->args.osa_src_fh = NFS_FH(file_inode(dst)); |
| 402 | + memcpy(&data->args.osa_stateid, stateid, |
| 403 | + sizeof(data->args.osa_stateid)); |
| 404 | + msg.rpc_argp = &data->args; |
| 405 | + msg.rpc_resp = &data->res; |
| 406 | + task_setup_data.callback_data = data; |
| 407 | + nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res, |
| 408 | + 1, 0); |
| 409 | + task = rpc_run_task(&task_setup_data); |
| 410 | + if (IS_ERR(task)) |
| 411 | + return PTR_ERR(task); |
| 412 | + status = rpc_wait_for_completion_task(task); |
| 413 | + if (status == -ENOTSUPP) |
| 414 | + dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL; |
| 415 | + rpc_put_task(task); |
| 416 | + return status; |
| 417 | +} |
| 418 | + |
330 | 419 | static loff_t _nfs42_proc_llseek(struct file *filep,
|
331 | 420 | struct nfs_lock_context *lock, loff_t offset, int whence)
|
332 | 421 | {
|
|
0 commit comments