diff options
| -rw-r--r-- | fs/nfs/nfs4proc.c | 115 |
1 files changed, 97 insertions, 18 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 02513da9a016..18cce76867ce 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -64,6 +64,7 @@ | |||
| 64 | 64 | ||
| 65 | struct nfs4_opendata; | 65 | struct nfs4_opendata; |
| 66 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 66 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
| 67 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | ||
| 67 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 68 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
| 68 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 69 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
| 69 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 70 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
| @@ -567,6 +568,12 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
| 567 | rpc_call_start(task); | 568 | rpc_call_start(task); |
| 568 | } | 569 | } |
| 569 | 570 | ||
| 571 | static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata) | ||
| 572 | { | ||
| 573 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 574 | nfs41_call_sync_prepare(task, calldata); | ||
| 575 | } | ||
| 576 | |||
| 570 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | 577 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) |
| 571 | { | 578 | { |
| 572 | struct nfs41_call_sync_data *data = calldata; | 579 | struct nfs41_call_sync_data *data = calldata; |
| @@ -579,12 +586,18 @@ struct rpc_call_ops nfs41_call_sync_ops = { | |||
| 579 | .rpc_call_done = nfs41_call_sync_done, | 586 | .rpc_call_done = nfs41_call_sync_done, |
| 580 | }; | 587 | }; |
| 581 | 588 | ||
| 589 | struct rpc_call_ops nfs41_call_priv_sync_ops = { | ||
| 590 | .rpc_call_prepare = nfs41_call_priv_sync_prepare, | ||
| 591 | .rpc_call_done = nfs41_call_sync_done, | ||
| 592 | }; | ||
| 593 | |||
| 582 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 594 | static int nfs4_call_sync_sequence(struct nfs_client *clp, |
| 583 | struct rpc_clnt *clnt, | 595 | struct rpc_clnt *clnt, |
| 584 | struct rpc_message *msg, | 596 | struct rpc_message *msg, |
| 585 | struct nfs4_sequence_args *args, | 597 | struct nfs4_sequence_args *args, |
| 586 | struct nfs4_sequence_res *res, | 598 | struct nfs4_sequence_res *res, |
| 587 | int cache_reply) | 599 | int cache_reply, |
| 600 | int privileged) | ||
| 588 | { | 601 | { |
| 589 | int ret; | 602 | int ret; |
| 590 | struct rpc_task *task; | 603 | struct rpc_task *task; |
| @@ -602,6 +615,8 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
| 602 | }; | 615 | }; |
| 603 | 616 | ||
| 604 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 617 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 618 | if (privileged) | ||
| 619 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | ||
| 605 | task = rpc_run_task(&task_setup); | 620 | task = rpc_run_task(&task_setup); |
| 606 | if (IS_ERR(task)) | 621 | if (IS_ERR(task)) |
| 607 | ret = PTR_ERR(task); | 622 | ret = PTR_ERR(task); |
| @@ -619,7 +634,7 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
| 619 | int cache_reply) | 634 | int cache_reply) |
| 620 | { | 635 | { |
| 621 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 636 | return nfs4_call_sync_sequence(server->nfs_client, server->client, |
| 622 | msg, args, res, cache_reply); | 637 | msg, args, res, cache_reply, 0); |
| 623 | } | 638 | } |
| 624 | 639 | ||
| 625 | #endif /* CONFIG_NFS_V4_1 */ | 640 | #endif /* CONFIG_NFS_V4_1 */ |
| @@ -1057,7 +1072,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
| 1057 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 1072 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
| 1058 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 1073 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
| 1059 | nfs4_init_opendata_res(opendata); | 1074 | nfs4_init_opendata_res(opendata); |
| 1060 | ret = _nfs4_proc_open(opendata); | 1075 | ret = _nfs4_recover_proc_open(opendata); |
| 1061 | if (ret != 0) | 1076 | if (ret != 0) |
| 1062 | return ret; | 1077 | return ret; |
| 1063 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1078 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
| @@ -1348,6 +1363,12 @@ out_no_action: | |||
| 1348 | 1363 | ||
| 1349 | } | 1364 | } |
| 1350 | 1365 | ||
| 1366 | static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata) | ||
| 1367 | { | ||
| 1368 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 1369 | nfs4_open_prepare(task, calldata); | ||
| 1370 | } | ||
| 1371 | |||
| 1351 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 1372 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
| 1352 | { | 1373 | { |
| 1353 | struct nfs4_opendata *data = calldata; | 1374 | struct nfs4_opendata *data = calldata; |
| @@ -1406,10 +1427,13 @@ static const struct rpc_call_ops nfs4_open_ops = { | |||
| 1406 | .rpc_release = nfs4_open_release, | 1427 | .rpc_release = nfs4_open_release, |
| 1407 | }; | 1428 | }; |
| 1408 | 1429 | ||
| 1409 | /* | 1430 | static const struct rpc_call_ops nfs4_recover_open_ops = { |
| 1410 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | 1431 | .rpc_call_prepare = nfs4_recover_open_prepare, |
| 1411 | */ | 1432 | .rpc_call_done = nfs4_open_done, |
| 1412 | static int _nfs4_proc_open(struct nfs4_opendata *data) | 1433 | .rpc_release = nfs4_open_release, |
| 1434 | }; | ||
| 1435 | |||
| 1436 | static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) | ||
| 1413 | { | 1437 | { |
| 1414 | struct inode *dir = data->dir->d_inode; | 1438 | struct inode *dir = data->dir->d_inode; |
| 1415 | struct nfs_server *server = NFS_SERVER(dir); | 1439 | struct nfs_server *server = NFS_SERVER(dir); |
| @@ -1436,16 +1460,55 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
| 1436 | data->rpc_done = 0; | 1460 | data->rpc_done = 0; |
| 1437 | data->rpc_status = 0; | 1461 | data->rpc_status = 0; |
| 1438 | data->cancelled = 0; | 1462 | data->cancelled = 0; |
| 1463 | if (isrecover) | ||
| 1464 | task_setup_data.callback_ops = &nfs4_recover_open_ops; | ||
| 1439 | task = rpc_run_task(&task_setup_data); | 1465 | task = rpc_run_task(&task_setup_data); |
| 1440 | if (IS_ERR(task)) | 1466 | if (IS_ERR(task)) |
| 1441 | return PTR_ERR(task); | 1467 | return PTR_ERR(task); |
| 1442 | status = nfs4_wait_for_completion_rpc_task(task); | 1468 | status = nfs4_wait_for_completion_rpc_task(task); |
| 1443 | if (status != 0) { | 1469 | if (status != 0) { |
| 1444 | data->cancelled = 1; | 1470 | data->cancelled = 1; |
| 1445 | smp_wmb(); | 1471 | smp_wmb(); |
| 1446 | } else | 1472 | } else |
| 1447 | status = data->rpc_status; | 1473 | status = data->rpc_status; |
| 1448 | rpc_put_task(task); | 1474 | rpc_put_task(task); |
| 1475 | |||
| 1476 | return status; | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | ||
| 1480 | { | ||
| 1481 | struct inode *dir = data->dir->d_inode; | ||
| 1482 | struct nfs_openres *o_res = &data->o_res; | ||
| 1483 | int status; | ||
| 1484 | |||
| 1485 | status = nfs4_run_open_task(data, 1); | ||
| 1486 | if (status != 0 || !data->rpc_done) | ||
| 1487 | return status; | ||
| 1488 | |||
| 1489 | nfs_refresh_inode(dir, o_res->dir_attr); | ||
| 1490 | |||
| 1491 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
| 1492 | status = _nfs4_proc_open_confirm(data); | ||
| 1493 | if (status != 0) | ||
| 1494 | return status; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | return status; | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | /* | ||
| 1501 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | ||
| 1502 | */ | ||
| 1503 | static int _nfs4_proc_open(struct nfs4_opendata *data) | ||
| 1504 | { | ||
| 1505 | struct inode *dir = data->dir->d_inode; | ||
| 1506 | struct nfs_server *server = NFS_SERVER(dir); | ||
| 1507 | struct nfs_openargs *o_arg = &data->o_arg; | ||
| 1508 | struct nfs_openres *o_res = &data->o_res; | ||
| 1509 | int status; | ||
| 1510 | |||
| 1511 | status = nfs4_run_open_task(data, 0); | ||
| 1449 | if (status != 0 || !data->rpc_done) | 1512 | if (status != 0 || !data->rpc_done) |
| 1450 | return status; | 1513 | return status; |
| 1451 | 1514 | ||
| @@ -3960,6 +4023,12 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 3960 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 4023 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
| 3961 | } | 4024 | } |
| 3962 | 4025 | ||
| 4026 | static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) | ||
| 4027 | { | ||
| 4028 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 4029 | nfs4_lock_prepare(task, calldata); | ||
| 4030 | } | ||
| 4031 | |||
| 3963 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) | 4032 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) |
| 3964 | { | 4033 | { |
| 3965 | struct nfs4_lockdata *data = calldata; | 4034 | struct nfs4_lockdata *data = calldata; |
| @@ -4015,6 +4084,12 @@ static const struct rpc_call_ops nfs4_lock_ops = { | |||
| 4015 | .rpc_release = nfs4_lock_release, | 4084 | .rpc_release = nfs4_lock_release, |
| 4016 | }; | 4085 | }; |
| 4017 | 4086 | ||
| 4087 | static const struct rpc_call_ops nfs4_recover_lock_ops = { | ||
| 4088 | .rpc_call_prepare = nfs4_recover_lock_prepare, | ||
| 4089 | .rpc_call_done = nfs4_lock_done, | ||
| 4090 | .rpc_release = nfs4_lock_release, | ||
| 4091 | }; | ||
| 4092 | |||
| 4018 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) | 4093 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) |
| 4019 | { | 4094 | { |
| 4020 | struct nfs4_lockdata *data; | 4095 | struct nfs4_lockdata *data; |
| @@ -4039,8 +4114,11 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
| 4039 | return -ENOMEM; | 4114 | return -ENOMEM; |
| 4040 | if (IS_SETLKW(cmd)) | 4115 | if (IS_SETLKW(cmd)) |
| 4041 | data->arg.block = 1; | 4116 | data->arg.block = 1; |
| 4042 | if (recovery_type == NFS_LOCK_RECLAIM) | 4117 | if (recovery_type > NFS_LOCK_NEW) { |
| 4118 | if (recovery_type == NFS_LOCK_RECLAIM) | ||
| 4043 | data->arg.reclaim = NFS_LOCK_RECLAIM; | 4119 | data->arg.reclaim = NFS_LOCK_RECLAIM; |
| 4120 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; | ||
| 4121 | } | ||
| 4044 | msg.rpc_argp = &data->arg, | 4122 | msg.rpc_argp = &data->arg, |
| 4045 | msg.rpc_resp = &data->res, | 4123 | msg.rpc_resp = &data->res, |
| 4046 | task_setup_data.callback_data = data; | 4124 | task_setup_data.callback_data = data; |
| @@ -4891,7 +4969,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 4891 | args.sa_cache_this = 0; | 4969 | args.sa_cache_this = 0; |
| 4892 | 4970 | ||
| 4893 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | 4971 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, |
| 4894 | &res, 0); | 4972 | &res, args.sa_cache_this, 1); |
| 4895 | } | 4973 | } |
| 4896 | 4974 | ||
| 4897 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 4975 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
| @@ -4973,6 +5051,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | |||
| 4973 | { | 5051 | { |
| 4974 | struct nfs4_reclaim_complete_data *calldata = data; | 5052 | struct nfs4_reclaim_complete_data *calldata = data; |
| 4975 | 5053 | ||
| 5054 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
| 4976 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | 5055 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, |
| 4977 | &calldata->res.seq_res, 0, task)) | 5056 | &calldata->res.seq_res, 0, task)) |
| 4978 | return; | 5057 | return; |
