mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
NFS client updates for Linux 6.15
Highlights include: Bugfixes: - 3 Fixes for looping in the NFSv4 state manager delegation code. - Fix for the NFSv4 state XDR code from Neil Brown. - Fix a leaked reference in nfs_lock_and_join_requests(). - Fix a use-after-free in the delegation return code. Features: - Implemenation of the NFSv4.2 copy offload OFFLOAD_STATUS operation to allow monitoring of an in-progress copy. - Add a mount option to force NFSv3/NFSv4 to use READDIRPLUS in a getdents() call. - SUNRPC now allows some basic management of an existing RPC client's connections using sysfs. - Improvements to the automated teardown of a NFS client when the container it was initiated from gets killed. - Improvements to prevent tasks from getting stuck in a killable wait state after calling exit_signals(). -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAmftuE0ACgkQZwvnipYK APIAAhAAqFdJnh88UUT0/R184Qzpd021lR9XhxkwNA3TzhOIzmpuTgBzNE1iMG1j EHveYqCpTU2orA1aisAyw5c8meJlsCQREPDvUOQ2i4BTCCmsBHOMxg7KDWwwRdNh SVDCezFWrHYz4An81jpgBe3/x6RJaEyAhKC45ZzQruiBtSMeoOX1TAV/DTWwEo0j JcLdAUSGVBsfyrj3qT0oJXoj+96o7rbB80loCdNKy8m8PBWHWp0oILwuU00XdXgu 7jYyjZfxW1013It+vfVFsjTYRVfJ92pq3wiz/U9HXYDe3Arc4oPRw509/Jo3xEWW tdUljc/HepD3459ahiubTCLY39JxILl8/GapWe2Fn0J/JJuOGgZX9lqIMKDn4QCA 6TBOqWK7OEwImj4M7cfPptJQWd+hp91T4AR13xWJeQgp19AR8yOqEW0YX6hVlaBg UrBwdR+l6ys5lJJBReUW+JMDCYZmbH9RjuwcqzXn71JmlACHNFi6odwLnQ1mInvF P5pEf7aXaZkF6kEz2kmZ1eUgdkERAaIGCNFQTui6intlCSlQodNurrEU7Vx146os OvowJYM0HvnVBDOnERrJD04HADKZeDS8jt59ev0uXbP/NFxEJnPRRQgIdiZbfISV beQrc2fpUgwdjYAURbW1qWO7XNTJzK9LHJzn02SytfCazX0IQO0= =zPX4 -----END PGP SIGNATURE----- Merge tag 'nfs-for-6.15-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client updates from Trond Myklebust: "Bugfixes: - Three fixes for looping in the NFSv4 state manager delegation code - Fix for the NFSv4 state XDR code (Neil Brown) - Fix a leaked reference in nfs_lock_and_join_requests() - Fix a use-after-free in the delegation return code Features: - Implement the NFSv4.2 copy offload OFFLOAD_STATUS operation to allow monitoring of an in-progress copy - Add a mount option to force NFSv3/NFSv4 to use READDIRPLUS in a getdents() call - SUNRPC now allows some basic management of an existing RPC client's connections using sysfs - Improvements to the automated teardown of a NFS client when the container it was initiated from gets killed - Improvements to prevent tasks from getting stuck in a killable wait state after calling exit_signals()" * tag 'nfs-for-6.15-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (29 commits) nfs: Add missing release on error in nfs_lock_and_join_requests() NFSv4: Check for delegation validity in nfs_start_delegation_return_locked() NFS: Don't allow waiting for exiting tasks SUNRPC: Don't allow waiting for exiting tasks NFSv4: Treat ENETUNREACH errors as fatal for state recovery NFSv4: clp->cl_cons_state < 0 signifies an invalid nfs_client NFSv4: Further cleanups to shutdown loops NFS: Shut down the nfs_client only after all the superblocks SUNRPC: rpc_clnt_set_transport() must not change the autobind setting SUNRPC: rpcbind should never reset the port to the value '0' pNFS/flexfiles: Report ENETDOWN as a connection error pNFS/flexfiles: Treat ENETUNREACH errors as fatal in containers NFS: Treat ENETUNREACH errors as fatal in containers NFS: Add a mount option to make ENETUNREACH errors fatal sunrpc: Add a sysfs file for one-step xprt deletion sunrpc: Add a sysfs file for adding a new xprt sunrpc: Add a sysfs files for rpc_clnt information sunrpc: Add a sysfs attr for xprtsec NFS: Add implid to sysfs NFS: Extend rdirplus mount option with "force|none" ...
This commit is contained in:
commit
94d471a4f4
@ -546,6 +546,8 @@ int nfs_create_rpc_client(struct nfs_client *clp,
|
||||
args.flags |= RPC_CLNT_CREATE_NOPING;
|
||||
if (test_bit(NFS_CS_REUSEPORT, &clp->cl_flags))
|
||||
args.flags |= RPC_CLNT_CREATE_REUSEPORT;
|
||||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags))
|
||||
args.flags |= RPC_CLNT_CREATE_NETUNREACH_FATAL;
|
||||
|
||||
if (!IS_ERR(clp->cl_rpcclient))
|
||||
return 0;
|
||||
@ -709,6 +711,9 @@ static int nfs_init_server(struct nfs_server *server,
|
||||
if (ctx->flags & NFS_MOUNT_NORESVPORT)
|
||||
set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
|
||||
|
||||
if (ctx->flags & NFS_MOUNT_NETUNREACH_FATAL)
|
||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
|
||||
|
||||
/* Allocate or find a client reference we can use */
|
||||
clp = nfs_get_client(&cl_init);
|
||||
if (IS_ERR(clp))
|
||||
|
@ -79,6 +79,7 @@ static void nfs_mark_return_delegation(struct nfs_server *server,
|
||||
struct nfs_delegation *delegation)
|
||||
{
|
||||
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
|
||||
set_bit(NFS4SERV_DELEGRETURN, &server->delegation_flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
|
||||
}
|
||||
|
||||
@ -306,7 +307,8 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
|
||||
if (delegation == NULL)
|
||||
goto out;
|
||||
spin_lock(&delegation->lock);
|
||||
if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
|
||||
if (delegation->inode &&
|
||||
!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
|
||||
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
|
||||
/* Refcount matched in nfs_end_delegation_return() */
|
||||
ret = nfs_get_delegation(delegation);
|
||||
@ -330,14 +332,16 @@ nfs_start_delegation_return(struct nfs_inode *nfsi)
|
||||
}
|
||||
|
||||
static void nfs_abort_delegation_return(struct nfs_delegation *delegation,
|
||||
struct nfs_client *clp, int err)
|
||||
struct nfs_server *server, int err)
|
||||
{
|
||||
|
||||
spin_lock(&delegation->lock);
|
||||
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
||||
if (err == -EAGAIN) {
|
||||
set_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN_DELAYED, &clp->cl_state);
|
||||
set_bit(NFS4SERV_DELEGRETURN_DELAYED,
|
||||
&server->delegation_flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN_DELAYED,
|
||||
&server->nfs_client->cl_state);
|
||||
}
|
||||
spin_unlock(&delegation->lock);
|
||||
}
|
||||
@ -547,7 +551,7 @@ out:
|
||||
*/
|
||||
static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
|
||||
{
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
unsigned int mode = O_WRONLY | O_RDWR;
|
||||
int err = 0;
|
||||
|
||||
@ -569,11 +573,11 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation
|
||||
/*
|
||||
* Guard against state recovery
|
||||
*/
|
||||
err = nfs4_wait_clnt_recover(clp);
|
||||
err = nfs4_wait_clnt_recover(server->nfs_client);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
nfs_abort_delegation_return(delegation, clp, err);
|
||||
nfs_abort_delegation_return(delegation, server, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -590,17 +594,6 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
|
||||
|
||||
if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
|
||||
ret = true;
|
||||
else if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags)) {
|
||||
struct inode *inode;
|
||||
|
||||
spin_lock(&delegation->lock);
|
||||
inode = delegation->inode;
|
||||
if (inode && list_empty(&NFS_I(inode)->open_files))
|
||||
ret = true;
|
||||
spin_unlock(&delegation->lock);
|
||||
}
|
||||
if (ret)
|
||||
clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
|
||||
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags) ||
|
||||
test_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags) ||
|
||||
test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
|
||||
@ -619,6 +612,9 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
|
||||
struct nfs_delegation *place_holder_deleg = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (!test_and_clear_bit(NFS4SERV_DELEGRETURN,
|
||||
&server->delegation_flags))
|
||||
return 0;
|
||||
restart:
|
||||
/*
|
||||
* To avoid quadratic looping we hold a reference
|
||||
@ -670,6 +666,7 @@ restart:
|
||||
cond_resched();
|
||||
if (!err)
|
||||
goto restart;
|
||||
set_bit(NFS4SERV_DELEGRETURN, &server->delegation_flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
|
||||
goto out;
|
||||
}
|
||||
@ -684,6 +681,9 @@ static bool nfs_server_clear_delayed_delegations(struct nfs_server *server)
|
||||
struct nfs_delegation *d;
|
||||
bool ret = false;
|
||||
|
||||
if (!test_and_clear_bit(NFS4SERV_DELEGRETURN_DELAYED,
|
||||
&server->delegation_flags))
|
||||
goto out;
|
||||
list_for_each_entry_rcu (d, &server->delegations, super_list) {
|
||||
if (!test_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags))
|
||||
continue;
|
||||
@ -691,6 +691,7 @@ static bool nfs_server_clear_delayed_delegations(struct nfs_server *server)
|
||||
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags);
|
||||
ret = true;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -878,11 +879,25 @@ int nfs4_inode_make_writeable(struct inode *inode)
|
||||
return nfs4_inode_return_delegation(inode);
|
||||
}
|
||||
|
||||
static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
|
||||
struct nfs_delegation *delegation)
|
||||
static void
|
||||
nfs_mark_return_if_closed_delegation(struct nfs_server *server,
|
||||
struct nfs_delegation *delegation)
|
||||
{
|
||||
set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
|
||||
struct inode *inode;
|
||||
|
||||
if (test_bit(NFS_DELEGATION_RETURN, &delegation->flags) ||
|
||||
test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags))
|
||||
return;
|
||||
spin_lock(&delegation->lock);
|
||||
inode = delegation->inode;
|
||||
if (!inode)
|
||||
goto out;
|
||||
if (list_empty(&NFS_I(inode)->open_files))
|
||||
nfs_mark_return_delegation(server, delegation);
|
||||
else
|
||||
set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
|
||||
out:
|
||||
spin_unlock(&delegation->lock);
|
||||
}
|
||||
|
||||
static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
|
||||
@ -1276,6 +1291,7 @@ static void nfs_mark_test_expired_delegation(struct nfs_server *server,
|
||||
return;
|
||||
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
|
||||
set_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
|
||||
set_bit(NFS4SERV_DELEGATION_EXPIRED, &server->delegation_flags);
|
||||
set_bit(NFS4CLNT_DELEGATION_EXPIRED, &server->nfs_client->cl_state);
|
||||
}
|
||||
|
||||
@ -1354,6 +1370,9 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
|
||||
nfs4_stateid stateid;
|
||||
unsigned long gen = ++server->delegation_gen;
|
||||
|
||||
if (!test_and_clear_bit(NFS4SERV_DELEGATION_EXPIRED,
|
||||
&server->delegation_flags))
|
||||
return 0;
|
||||
restart:
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
|
||||
@ -1383,6 +1402,9 @@ restart:
|
||||
goto restart;
|
||||
}
|
||||
nfs_inode_mark_test_expired_delegation(server,inode);
|
||||
set_bit(NFS4SERV_DELEGATION_EXPIRED, &server->delegation_flags);
|
||||
set_bit(NFS4CLNT_DELEGATION_EXPIRED,
|
||||
&server->nfs_client->cl_state);
|
||||
iput(inode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
@ -666,6 +666,8 @@ static bool nfs_use_readdirplus(struct inode *dir, struct dir_context *ctx,
|
||||
{
|
||||
if (!nfs_server_capable(dir, NFS_CAP_READDIRPLUS))
|
||||
return false;
|
||||
if (NFS_SERVER(dir)->flags & NFS_MOUNT_FORCE_RDIRPLUS)
|
||||
return true;
|
||||
if (ctx->pos == 0 ||
|
||||
cache_hits + cache_misses > NFS_READDIR_CACHE_USAGE_THRESHOLD)
|
||||
return true;
|
||||
|
@ -1154,10 +1154,14 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
|
||||
rpc_wake_up(&tbl->slot_tbl_waitq);
|
||||
goto reset;
|
||||
/* RPC connection errors */
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags))
|
||||
return -NFS4ERR_FATAL_IOERROR;
|
||||
fallthrough;
|
||||
case -ECONNREFUSED:
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETUNREACH:
|
||||
case -EIO:
|
||||
case -ETIMEDOUT:
|
||||
case -EPIPE:
|
||||
@ -1183,6 +1187,7 @@ reset:
|
||||
|
||||
/* Retry all errors through either pNFS or MDS except for -EJUKEBOX */
|
||||
static int ff_layout_async_handle_error_v3(struct rpc_task *task,
|
||||
struct nfs_client *clp,
|
||||
struct pnfs_layout_segment *lseg,
|
||||
u32 idx)
|
||||
{
|
||||
@ -1200,6 +1205,11 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
|
||||
case -EJUKEBOX:
|
||||
nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY);
|
||||
goto out_retry;
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags))
|
||||
return -NFS4ERR_FATAL_IOERROR;
|
||||
fallthrough;
|
||||
default:
|
||||
dprintk("%s DS connection error %d\n", __func__,
|
||||
task->tk_status);
|
||||
@ -1234,7 +1244,7 @@ static int ff_layout_async_handle_error(struct rpc_task *task,
|
||||
|
||||
switch (vers) {
|
||||
case 3:
|
||||
return ff_layout_async_handle_error_v3(task, lseg, idx);
|
||||
return ff_layout_async_handle_error_v3(task, clp, lseg, idx);
|
||||
case 4:
|
||||
return ff_layout_async_handle_error_v4(task, state, clp,
|
||||
lseg, idx);
|
||||
@ -1264,6 +1274,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
|
||||
case -ECONNRESET:
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
case -EADDRINUSE:
|
||||
case -ENOBUFS:
|
||||
@ -1337,6 +1348,9 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
|
||||
return task->tk_status;
|
||||
case -EAGAIN:
|
||||
goto out_eagain;
|
||||
case -NFS4ERR_FATAL_IOERROR:
|
||||
task->tk_status = -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1507,6 +1521,9 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
|
||||
return task->tk_status;
|
||||
case -EAGAIN:
|
||||
return -EAGAIN;
|
||||
case -NFS4ERR_FATAL_IOERROR:
|
||||
task->tk_status = -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hdr->res.verf->committed == NFS_FILE_SYNC ||
|
||||
@ -1551,6 +1568,9 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
|
||||
case -EAGAIN:
|
||||
rpc_restart_call_prepare(task);
|
||||
return -EAGAIN;
|
||||
case -NFS4ERR_FATAL_IOERROR:
|
||||
task->tk_status = -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ff_layout_set_layoutcommit(data->inode, data->lseg, data->lwb);
|
||||
|
@ -50,6 +50,7 @@ enum nfs_param {
|
||||
Opt_clientaddr,
|
||||
Opt_cto,
|
||||
Opt_alignwrite,
|
||||
Opt_fatal_neterrors,
|
||||
Opt_fg,
|
||||
Opt_fscache,
|
||||
Opt_fscache_flag,
|
||||
@ -72,6 +73,8 @@ enum nfs_param {
|
||||
Opt_posix,
|
||||
Opt_proto,
|
||||
Opt_rdirplus,
|
||||
Opt_rdirplus_none,
|
||||
Opt_rdirplus_force,
|
||||
Opt_rdma,
|
||||
Opt_resvport,
|
||||
Opt_retrans,
|
||||
@ -95,6 +98,20 @@ enum nfs_param {
|
||||
Opt_xprtsec,
|
||||
};
|
||||
|
||||
enum {
|
||||
Opt_fatal_neterrors_default,
|
||||
Opt_fatal_neterrors_enetunreach,
|
||||
Opt_fatal_neterrors_none,
|
||||
};
|
||||
|
||||
static const struct constant_table nfs_param_enums_fatal_neterrors[] = {
|
||||
{ "default", Opt_fatal_neterrors_default },
|
||||
{ "ENETDOWN:ENETUNREACH", Opt_fatal_neterrors_enetunreach },
|
||||
{ "ENETUNREACH:ENETDOWN", Opt_fatal_neterrors_enetunreach },
|
||||
{ "none", Opt_fatal_neterrors_none },
|
||||
{}
|
||||
};
|
||||
|
||||
enum {
|
||||
Opt_local_lock_all,
|
||||
Opt_local_lock_flock,
|
||||
@ -151,6 +168,8 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
|
||||
fsparam_string("clientaddr", Opt_clientaddr),
|
||||
fsparam_flag_no("cto", Opt_cto),
|
||||
fsparam_flag_no("alignwrite", Opt_alignwrite),
|
||||
fsparam_enum("fatal_neterrors", Opt_fatal_neterrors,
|
||||
nfs_param_enums_fatal_neterrors),
|
||||
fsparam_flag ("fg", Opt_fg),
|
||||
fsparam_flag_no("fsc", Opt_fscache_flag),
|
||||
fsparam_string("fsc", Opt_fscache),
|
||||
@ -174,7 +193,8 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
|
||||
fsparam_u32 ("port", Opt_port),
|
||||
fsparam_flag_no("posix", Opt_posix),
|
||||
fsparam_string("proto", Opt_proto),
|
||||
fsparam_flag_no("rdirplus", Opt_rdirplus),
|
||||
fsparam_flag_no("rdirplus", Opt_rdirplus), // rdirplus|nordirplus
|
||||
fsparam_string("rdirplus", Opt_rdirplus), // rdirplus=...
|
||||
fsparam_flag ("rdma", Opt_rdma),
|
||||
fsparam_flag_no("resvport", Opt_resvport),
|
||||
fsparam_u32 ("retrans", Opt_retrans),
|
||||
@ -288,6 +308,12 @@ static const struct constant_table nfs_xprtsec_policies[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct constant_table nfs_rdirplus_tokens[] = {
|
||||
{ "none", Opt_rdirplus_none },
|
||||
{ "force", Opt_rdirplus_force },
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Sanity-check a server address provided by the mount command.
|
||||
*
|
||||
@ -636,10 +662,25 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
|
||||
ctx->flags &= ~NFS_MOUNT_NOACL;
|
||||
break;
|
||||
case Opt_rdirplus:
|
||||
if (result.negated)
|
||||
if (result.negated) {
|
||||
ctx->flags &= ~NFS_MOUNT_FORCE_RDIRPLUS;
|
||||
ctx->flags |= NFS_MOUNT_NORDIRPLUS;
|
||||
else
|
||||
ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
|
||||
} else if (!param->string) {
|
||||
ctx->flags &= ~(NFS_MOUNT_NORDIRPLUS | NFS_MOUNT_FORCE_RDIRPLUS);
|
||||
} else {
|
||||
switch (lookup_constant(nfs_rdirplus_tokens, param->string, -1)) {
|
||||
case Opt_rdirplus_none:
|
||||
ctx->flags &= ~NFS_MOUNT_FORCE_RDIRPLUS;
|
||||
ctx->flags |= NFS_MOUNT_NORDIRPLUS;
|
||||
break;
|
||||
case Opt_rdirplus_force:
|
||||
ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
|
||||
ctx->flags |= NFS_MOUNT_FORCE_RDIRPLUS;
|
||||
break;
|
||||
default:
|
||||
goto out_invalid_value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opt_sharecache:
|
||||
if (result.negated)
|
||||
@ -872,6 +913,25 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
|
||||
goto out_of_bounds;
|
||||
ctx->nfs_server.max_connect = result.uint_32;
|
||||
break;
|
||||
case Opt_fatal_neterrors:
|
||||
trace_nfs_mount_assign(param->key, param->string);
|
||||
switch (result.uint_32) {
|
||||
case Opt_fatal_neterrors_default:
|
||||
if (fc->net_ns != &init_net)
|
||||
ctx->flags |= NFS_MOUNT_NETUNREACH_FATAL;
|
||||
else
|
||||
ctx->flags &= ~NFS_MOUNT_NETUNREACH_FATAL;
|
||||
break;
|
||||
case Opt_fatal_neterrors_enetunreach:
|
||||
ctx->flags |= NFS_MOUNT_NETUNREACH_FATAL;
|
||||
break;
|
||||
case Opt_fatal_neterrors_none:
|
||||
ctx->flags &= ~NFS_MOUNT_NETUNREACH_FATAL;
|
||||
break;
|
||||
default:
|
||||
goto out_invalid_value;
|
||||
}
|
||||
break;
|
||||
case Opt_lookupcache:
|
||||
trace_nfs_mount_assign(param->key, param->string);
|
||||
switch (result.uint_32) {
|
||||
@ -1651,6 +1711,9 @@ static int nfs_init_fs_context(struct fs_context *fc)
|
||||
ctx->xprtsec.cert_serial = TLS_NO_CERT;
|
||||
ctx->xprtsec.privkey_serial = TLS_NO_PRIVKEY;
|
||||
|
||||
if (fc->net_ns != &init_net)
|
||||
ctx->flags |= NFS_MOUNT_NETUNREACH_FATAL;
|
||||
|
||||
fc->s_iflags |= SB_I_STABLE_WRITES;
|
||||
}
|
||||
fc->fs_private = ctx;
|
||||
|
@ -74,6 +74,8 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
|
||||
|
||||
int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
|
||||
{
|
||||
if (unlikely(nfs_current_task_exiting()))
|
||||
return -EINTR;
|
||||
schedule();
|
||||
if (signal_pending_state(mode, current))
|
||||
return -ERESTARTSYS;
|
||||
|
@ -912,6 +912,11 @@ static inline u32 nfs_stateid_hash(nfs4_stateid *stateid)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool nfs_current_task_exiting(void)
|
||||
{
|
||||
return (current->flags & PF_EXITING) != 0;
|
||||
}
|
||||
|
||||
static inline bool nfs_error_is_fatal(int err)
|
||||
{
|
||||
switch (err) {
|
||||
|
@ -120,6 +120,8 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_server *mds_srv,
|
||||
|
||||
if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
|
||||
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
|
||||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &mds_clp->cl_flags))
|
||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
|
||||
|
||||
__set_bit(NFS_CS_DS, &cl_init.init_flags);
|
||||
|
||||
|
@ -39,7 +39,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
|
||||
__set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
|
||||
schedule_timeout(NFS_JUKEBOX_RETRY_TIME);
|
||||
res = -ERESTARTSYS;
|
||||
} while (!fatal_signal_pending(current));
|
||||
} while (!fatal_signal_pending(current) && !nfs_current_task_exiting());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_PROC
|
||||
static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
|
||||
static int nfs42_proc_offload_status(struct file *file, nfs4_stateid *stateid,
|
||||
u64 *copied);
|
||||
|
||||
static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr)
|
||||
{
|
||||
@ -173,6 +175,20 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nfs4_copy_dequeue_callback(struct nfs_server *dst_server,
|
||||
struct nfs_server *src_server,
|
||||
struct nfs4_copy_state *copy)
|
||||
{
|
||||
spin_lock(&dst_server->nfs_client->cl_lock);
|
||||
list_del_init(©->copies);
|
||||
spin_unlock(&dst_server->nfs_client->cl_lock);
|
||||
if (dst_server != src_server) {
|
||||
spin_lock(&src_server->nfs_client->cl_lock);
|
||||
list_del_init(©->src_copies);
|
||||
spin_unlock(&src_server->nfs_client->cl_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_async_copy(struct nfs42_copy_res *res,
|
||||
struct nfs_server *dst_server,
|
||||
struct nfs_server *src_server,
|
||||
@ -182,9 +198,12 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
||||
bool *restart)
|
||||
{
|
||||
struct nfs4_copy_state *copy, *tmp_copy = NULL, *iter;
|
||||
int status = NFS4_OK;
|
||||
struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
|
||||
struct nfs_open_context *src_ctx = nfs_file_open_context(src);
|
||||
struct nfs_client *clp = dst_server->nfs_client;
|
||||
unsigned long timeout = 3 * HZ;
|
||||
int status = NFS4_OK;
|
||||
u64 copied;
|
||||
|
||||
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL);
|
||||
if (!copy)
|
||||
@ -222,15 +241,12 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
||||
spin_unlock(&src_server->nfs_client->cl_lock);
|
||||
}
|
||||
|
||||
status = wait_for_completion_interruptible(©->completion);
|
||||
spin_lock(&dst_server->nfs_client->cl_lock);
|
||||
list_del_init(©->copies);
|
||||
spin_unlock(&dst_server->nfs_client->cl_lock);
|
||||
if (dst_server != src_server) {
|
||||
spin_lock(&src_server->nfs_client->cl_lock);
|
||||
list_del_init(©->src_copies);
|
||||
spin_unlock(&src_server->nfs_client->cl_lock);
|
||||
}
|
||||
wait:
|
||||
status = wait_for_completion_interruptible_timeout(©->completion,
|
||||
timeout);
|
||||
if (!status)
|
||||
goto timeout;
|
||||
nfs4_copy_dequeue_callback(dst_server, src_server, copy);
|
||||
if (status == -ERESTARTSYS) {
|
||||
goto out_cancel;
|
||||
} else if (copy->flags || copy->error == NFS4ERR_PARTNER_NO_AUTH) {
|
||||
@ -240,6 +256,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
||||
}
|
||||
out:
|
||||
res->write_res.count = copy->count;
|
||||
/* Copy out the updated write verifier provided by CB_OFFLOAD. */
|
||||
memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
|
||||
status = -copy->error;
|
||||
|
||||
@ -251,6 +268,39 @@ out_cancel:
|
||||
if (!nfs42_files_from_same_server(src, dst))
|
||||
nfs42_do_offload_cancel_async(src, src_stateid);
|
||||
goto out_free;
|
||||
timeout:
|
||||
timeout <<= 1;
|
||||
if (timeout > (clp->cl_lease_time >> 1))
|
||||
timeout = clp->cl_lease_time >> 1;
|
||||
status = nfs42_proc_offload_status(dst, ©->stateid, &copied);
|
||||
if (status == -EINPROGRESS)
|
||||
goto wait;
|
||||
nfs4_copy_dequeue_callback(dst_server, src_server, copy);
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* The server recognized the copy stateid, so it hasn't
|
||||
* rebooted. Don't overwrite the verifier returned in the
|
||||
* COPY result. */
|
||||
res->write_res.count = copied;
|
||||
goto out_free;
|
||||
case -EREMOTEIO:
|
||||
/* COPY operation failed on the server. */
|
||||
status = -EOPNOTSUPP;
|
||||
res->write_res.count = copied;
|
||||
goto out_free;
|
||||
case -EBADF:
|
||||
/* Server did not recognize the copy stateid. It has
|
||||
* probably restarted and lost the plot. */
|
||||
res->write_res.count = 0;
|
||||
status = -EOPNOTSUPP;
|
||||
break;
|
||||
case -EOPNOTSUPP:
|
||||
/* RFC 7862 REQUIREs server to support OFFLOAD_STATUS when
|
||||
* it has signed up for an async COPY, so server is not
|
||||
* spec-compliant. */
|
||||
res->write_res.count = 0;
|
||||
}
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
static int process_copy_commit(struct file *dst, loff_t pos_dst,
|
||||
@ -582,6 +632,108 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
_nfs42_proc_offload_status(struct nfs_server *server, struct file *file,
|
||||
struct nfs42_offload_data *data)
|
||||
{
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(file);
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_STATUS],
|
||||
.rpc_argp = &data->args,
|
||||
.rpc_resp = &data->res,
|
||||
.rpc_cred = ctx->cred,
|
||||
};
|
||||
int status;
|
||||
|
||||
status = nfs4_call_sync(server->client, server, &msg,
|
||||
&data->args.osa_seq_args,
|
||||
&data->res.osr_seq_res, 1);
|
||||
trace_nfs4_offload_status(&data->args, status);
|
||||
switch (status) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
/*
|
||||
* Server does not recognize the COPY stateid. CB_OFFLOAD
|
||||
* could have purged it, or server might have rebooted.
|
||||
* Since COPY stateids don't have an associated inode,
|
||||
* avoid triggering state recovery.
|
||||
*/
|
||||
status = -EBADF;
|
||||
break;
|
||||
case -NFS4ERR_NOTSUPP:
|
||||
case -ENOTSUPP:
|
||||
case -EOPNOTSUPP:
|
||||
server->caps &= ~NFS_CAP_OFFLOAD_STATUS;
|
||||
status = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs42_proc_offload_status - Poll completion status of an async copy operation
|
||||
* @dst: handle of file being copied into
|
||||
* @stateid: copy stateid (from async COPY result)
|
||||
* @copied: OUT: number of bytes copied so far
|
||||
*
|
||||
* Return values:
|
||||
* %0: Server returned an NFS4_OK completion status
|
||||
* %-EINPROGRESS: Server returned no completion status
|
||||
* %-EREMOTEIO: Server returned an error completion status
|
||||
* %-EBADF: Server did not recognize the copy stateid
|
||||
* %-EOPNOTSUPP: Server does not support OFFLOAD_STATUS
|
||||
* %-ERESTARTSYS: Wait interrupted by signal
|
||||
*
|
||||
* Other negative errnos indicate the client could not complete the
|
||||
* request.
|
||||
*/
|
||||
static int
|
||||
nfs42_proc_offload_status(struct file *dst, nfs4_stateid *stateid, u64 *copied)
|
||||
{
|
||||
struct inode *inode = file_inode(dst);
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct nfs4_exception exception = {
|
||||
.inode = inode,
|
||||
};
|
||||
struct nfs42_offload_data *data;
|
||||
int status;
|
||||
|
||||
if (!(server->caps & NFS_CAP_OFFLOAD_STATUS))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
data->seq_server = server;
|
||||
data->args.osa_src_fh = NFS_FH(inode);
|
||||
memcpy(&data->args.osa_stateid, stateid,
|
||||
sizeof(data->args.osa_stateid));
|
||||
exception.stateid = &data->args.osa_stateid;
|
||||
do {
|
||||
status = _nfs42_proc_offload_status(server, dst, data);
|
||||
if (status == -EOPNOTSUPP)
|
||||
goto out;
|
||||
status = nfs4_handle_exception(server, status, &exception);
|
||||
} while (exception.retry);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
*copied = data->res.osr_count;
|
||||
if (!data->res.complete_count)
|
||||
status = -EINPROGRESS;
|
||||
else if (data->res.osr_complete != NFS_OK)
|
||||
status = -EREMOTEIO;
|
||||
|
||||
out:
|
||||
kfree(data);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
|
||||
struct nfs42_copy_notify_args *args,
|
||||
struct nfs42_copy_notify_res *res)
|
||||
|
@ -35,6 +35,11 @@
|
||||
#define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \
|
||||
XDR_QUADLEN(NFS4_STATEID_SIZE))
|
||||
#define decode_offload_cancel_maxsz (op_decode_hdr_maxsz)
|
||||
#define encode_offload_status_maxsz (op_encode_hdr_maxsz + \
|
||||
XDR_QUADLEN(NFS4_STATEID_SIZE))
|
||||
#define decode_offload_status_maxsz (op_decode_hdr_maxsz + \
|
||||
2 /* osr_count */ + \
|
||||
2 /* osr_complete */)
|
||||
#define encode_copy_notify_maxsz (op_encode_hdr_maxsz + \
|
||||
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
|
||||
1 + /* nl4_type */ \
|
||||
@ -143,6 +148,14 @@
|
||||
decode_sequence_maxsz + \
|
||||
decode_putfh_maxsz + \
|
||||
decode_offload_cancel_maxsz)
|
||||
#define NFS4_enc_offload_status_sz (compound_encode_hdr_maxsz + \
|
||||
encode_sequence_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
encode_offload_status_maxsz)
|
||||
#define NFS4_dec_offload_status_sz (compound_decode_hdr_maxsz + \
|
||||
decode_sequence_maxsz + \
|
||||
decode_putfh_maxsz + \
|
||||
decode_offload_status_maxsz)
|
||||
#define NFS4_enc_copy_notify_sz (compound_encode_hdr_maxsz + \
|
||||
encode_sequence_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
@ -345,6 +358,14 @@ static void encode_offload_cancel(struct xdr_stream *xdr,
|
||||
encode_nfs4_stateid(xdr, &args->osa_stateid);
|
||||
}
|
||||
|
||||
static void encode_offload_status(struct xdr_stream *xdr,
|
||||
const struct nfs42_offload_status_args *args,
|
||||
struct compound_hdr *hdr)
|
||||
{
|
||||
encode_op_hdr(xdr, OP_OFFLOAD_STATUS, decode_offload_status_maxsz, hdr);
|
||||
encode_nfs4_stateid(xdr, &args->osa_stateid);
|
||||
}
|
||||
|
||||
static void encode_copy_notify(struct xdr_stream *xdr,
|
||||
const struct nfs42_copy_notify_args *args,
|
||||
struct compound_hdr *hdr)
|
||||
@ -569,6 +590,25 @@ static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req,
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode OFFLOAD_STATUS request
|
||||
*/
|
||||
static void nfs4_xdr_enc_offload_status(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nfs42_offload_status_args *args = data;
|
||||
struct compound_hdr hdr = {
|
||||
.minorversion = nfs4_xdr_minorversion(&args->osa_seq_args),
|
||||
};
|
||||
|
||||
encode_compound_hdr(xdr, req, &hdr);
|
||||
encode_sequence(xdr, &args->osa_seq_args, &hdr);
|
||||
encode_putfh(xdr, args->osa_src_fh, &hdr);
|
||||
encode_offload_status(xdr, args, &hdr);
|
||||
encode_nops(&hdr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode COPY_NOTIFY request
|
||||
*/
|
||||
@ -921,6 +961,26 @@ static int decode_offload_cancel(struct xdr_stream *xdr,
|
||||
return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL);
|
||||
}
|
||||
|
||||
static int decode_offload_status(struct xdr_stream *xdr,
|
||||
struct nfs42_offload_status_res *res)
|
||||
{
|
||||
ssize_t result;
|
||||
int status;
|
||||
|
||||
status = decode_op_hdr(xdr, OP_OFFLOAD_STATUS);
|
||||
if (status)
|
||||
return status;
|
||||
/* osr_count */
|
||||
if (xdr_stream_decode_u64(xdr, &res->osr_count) < 0)
|
||||
return -EIO;
|
||||
/* osr_complete<1> */
|
||||
result = xdr_stream_decode_uint32_array(xdr, &res->osr_complete, 1);
|
||||
if (result < 0)
|
||||
return -EIO;
|
||||
res->complete_count = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_copy_notify(struct xdr_stream *xdr,
|
||||
struct nfs42_copy_notify_res *res)
|
||||
{
|
||||
@ -1370,6 +1430,32 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode OFFLOAD_STATUS response
|
||||
*/
|
||||
static int nfs4_xdr_dec_offload_status(struct rpc_rqst *rqstp,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct nfs42_offload_status_res *res = data;
|
||||
struct compound_hdr hdr;
|
||||
int status;
|
||||
|
||||
status = decode_compound_hdr(xdr, &hdr);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_sequence(xdr, &res->osr_seq_res, rqstp);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_putfh(xdr);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_offload_status(xdr, res);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode COPY_NOTIFY response
|
||||
*/
|
||||
|
@ -233,6 +233,8 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
|
||||
__set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
|
||||
if (test_bit(NFS_CS_PNFS, &cl_init->init_flags))
|
||||
__set_bit(NFS_CS_PNFS, &clp->cl_flags);
|
||||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &cl_init->init_flags))
|
||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &clp->cl_flags);
|
||||
/*
|
||||
* Set up the connection to the server before we add add to the
|
||||
* global list.
|
||||
@ -937,6 +939,9 @@ static int nfs4_set_client(struct nfs_server *server,
|
||||
__set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags);
|
||||
server->port = rpc_get_port((struct sockaddr *)addr);
|
||||
|
||||
if (server->flags & NFS_MOUNT_NETUNREACH_FATAL)
|
||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
|
||||
|
||||
/* Allocate or find a client reference we can use */
|
||||
clp = nfs_get_client(&cl_init);
|
||||
if (IS_ERR(clp))
|
||||
@ -1011,6 +1016,8 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
|
||||
|
||||
if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
|
||||
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
|
||||
if (test_bit(NFS_CS_NETUNREACH_FATAL, &mds_clp->cl_flags))
|
||||
__set_bit(NFS_CS_NETUNREACH_FATAL, &cl_init.init_flags);
|
||||
|
||||
__set_bit(NFS_CS_PNFS, &cl_init.init_flags);
|
||||
cl_init.max_connect = NFS_MAX_TRANSPORTS;
|
||||
|
@ -195,6 +195,9 @@ static int nfs4_map_errors(int err)
|
||||
return -EBUSY;
|
||||
case -NFS4ERR_NOT_SAME:
|
||||
return -ENOTSYNC;
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
break;
|
||||
default:
|
||||
dprintk("%s could not handle NFSv4 error %d\n",
|
||||
__func__, -err);
|
||||
@ -443,6 +446,8 @@ static int nfs4_delay_killable(long *timeout)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (unlikely(nfs_current_task_exiting()))
|
||||
return -EINTR;
|
||||
__set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
|
||||
schedule_timeout(nfs4_update_delay(timeout));
|
||||
if (!__fatal_signal_pending(current))
|
||||
@ -454,6 +459,8 @@ static int nfs4_delay_interruptible(long *timeout)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (unlikely(nfs_current_task_exiting()))
|
||||
return -EINTR;
|
||||
__set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE_UNSAFE);
|
||||
schedule_timeout(nfs4_update_delay(timeout));
|
||||
if (!signal_pending(current))
|
||||
@ -1774,7 +1781,8 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state,
|
||||
rcu_read_unlock();
|
||||
trace_nfs4_open_stateid_update_wait(state->inode, stateid, 0);
|
||||
|
||||
if (!fatal_signal_pending(current)) {
|
||||
if (!fatal_signal_pending(current) &&
|
||||
!nfs_current_task_exiting()) {
|
||||
if (schedule_timeout(5*HZ) == 0)
|
||||
status = -EAGAIN;
|
||||
else
|
||||
@ -3576,7 +3584,7 @@ static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
|
||||
write_sequnlock(&state->seqlock);
|
||||
trace_nfs4_close_stateid_update_wait(state->inode, dst, 0);
|
||||
|
||||
if (fatal_signal_pending(current))
|
||||
if (fatal_signal_pending(current) || nfs_current_task_exiting())
|
||||
status = -EINTR;
|
||||
else
|
||||
if (schedule_timeout(5*HZ) != 0)
|
||||
@ -9594,7 +9602,7 @@ static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
|
||||
return;
|
||||
|
||||
trace_nfs4_sequence(clp, task->tk_status);
|
||||
if (task->tk_status < 0 && !task->tk_client->cl_shutdown) {
|
||||
if (task->tk_status < 0 && clp->cl_cons_state >= 0) {
|
||||
dprintk("%s ERROR %d\n", __func__, task->tk_status);
|
||||
if (refcount_read(&clp->cl_count) == 1)
|
||||
return;
|
||||
@ -10798,7 +10806,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
||||
| NFS_CAP_CLONE
|
||||
| NFS_CAP_LAYOUTERROR
|
||||
| NFS_CAP_READ_PLUS
|
||||
| NFS_CAP_MOVEABLE,
|
||||
| NFS_CAP_MOVEABLE
|
||||
| NFS_CAP_OFFLOAD_STATUS,
|
||||
.init_client = nfs41_init_client,
|
||||
.shutdown_client = nfs41_shutdown_client,
|
||||
.match_stateid = nfs41_match_stateid,
|
||||
|
@ -1198,7 +1198,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
|
||||
struct rpc_clnt *clnt = clp->cl_rpcclient;
|
||||
bool swapon = false;
|
||||
|
||||
if (clnt->cl_shutdown)
|
||||
if (clp->cl_cons_state < 0)
|
||||
return;
|
||||
|
||||
set_bit(NFS4CLNT_RUN_MANAGER, &clp->cl_state);
|
||||
@ -1403,7 +1403,7 @@ int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_
|
||||
dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
|
||||
clp->cl_hostname);
|
||||
nfs4_schedule_state_manager(clp);
|
||||
return 0;
|
||||
return clp->cl_cons_state < 0 ? clp->cl_cons_state : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
|
||||
|
||||
@ -2739,7 +2739,15 @@ out_error:
|
||||
pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
|
||||
" with error %d\n", section_sep, section,
|
||||
clp->cl_hostname, -status);
|
||||
ssleep(1);
|
||||
switch (status) {
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
nfs_mark_client_ready(clp, -EIO);
|
||||
break;
|
||||
default:
|
||||
ssleep(1);
|
||||
break;
|
||||
}
|
||||
out_drain:
|
||||
memalloc_nofs_restore(memflags);
|
||||
nfs4_end_drain_session(clp);
|
||||
|
@ -2608,7 +2608,7 @@ TRACE_EVENT(nfs4_copy_notify,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfs4_offload_cancel,
|
||||
DECLARE_EVENT_CLASS(nfs4_offload_class,
|
||||
TP_PROTO(
|
||||
const struct nfs42_offload_status_args *args,
|
||||
int error
|
||||
@ -2640,6 +2640,15 @@ TRACE_EVENT(nfs4_offload_cancel,
|
||||
__entry->stateid_seq, __entry->stateid_hash
|
||||
)
|
||||
);
|
||||
#define DEFINE_NFS4_OFFLOAD_EVENT(name) \
|
||||
DEFINE_EVENT(nfs4_offload_class, name, \
|
||||
TP_PROTO( \
|
||||
const struct nfs42_offload_status_args *args, \
|
||||
int error \
|
||||
), \
|
||||
TP_ARGS(args, error))
|
||||
DEFINE_NFS4_OFFLOAD_EVENT(nfs4_offload_cancel);
|
||||
DEFINE_NFS4_OFFLOAD_EVENT(nfs4_offload_status);
|
||||
|
||||
DECLARE_EVENT_CLASS(nfs4_xattr_event,
|
||||
TP_PROTO(
|
||||
|
@ -82,9 +82,8 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
* we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2)
|
||||
*/
|
||||
#define pagepad_maxsz (1)
|
||||
#define open_owner_id_maxsz (1 + 2 + 1 + 1 + 2)
|
||||
#define lock_owner_id_maxsz (1 + 1 + 4)
|
||||
#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
|
||||
#define open_owner_id_maxsz (2 + 1 + 2 + 2)
|
||||
#define lock_owner_id_maxsz (2 + 1 + 2)
|
||||
#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
|
||||
#define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
|
||||
#define op_encode_hdr_maxsz (1)
|
||||
@ -185,7 +184,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
#define encode_claim_null_maxsz (1 + nfs4_name_maxsz)
|
||||
#define encode_open_maxsz (op_encode_hdr_maxsz + \
|
||||
2 + encode_share_access_maxsz + 2 + \
|
||||
open_owner_id_maxsz + \
|
||||
1 + open_owner_id_maxsz + \
|
||||
encode_opentype_maxsz + \
|
||||
encode_claim_null_maxsz)
|
||||
#define decode_space_limit_maxsz (3)
|
||||
@ -255,13 +254,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
#define encode_link_maxsz (op_encode_hdr_maxsz + \
|
||||
nfs4_name_maxsz)
|
||||
#define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz)
|
||||
#define encode_lockowner_maxsz (7)
|
||||
#define encode_lockowner_maxsz (2 + 1 + lock_owner_id_maxsz)
|
||||
|
||||
#define encode_lock_maxsz (op_encode_hdr_maxsz + \
|
||||
7 + \
|
||||
1 + encode_stateid_maxsz + 1 + \
|
||||
encode_lockowner_maxsz)
|
||||
#define decode_lock_denied_maxsz \
|
||||
(8 + decode_lockowner_maxsz)
|
||||
(2 + 2 + 1 + 2 + 1 + lock_owner_id_maxsz)
|
||||
#define decode_lock_maxsz (op_decode_hdr_maxsz + \
|
||||
decode_lock_denied_maxsz)
|
||||
#define encode_lockt_maxsz (op_encode_hdr_maxsz + 5 + \
|
||||
@ -617,7 +617,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
encode_lockowner_maxsz)
|
||||
#define NFS4_dec_release_lockowner_sz \
|
||||
(compound_decode_hdr_maxsz + \
|
||||
decode_lockowner_maxsz)
|
||||
decode_release_lockowner_maxsz)
|
||||
#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
|
||||
encode_sequence_maxsz + \
|
||||
encode_putfh_maxsz + \
|
||||
@ -1412,7 +1412,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
|
||||
__be32 *p;
|
||||
/*
|
||||
* opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
|
||||
* owner 4 = 32
|
||||
* owner 28
|
||||
*/
|
||||
encode_nfs4_seqid(xdr, arg->seqid);
|
||||
encode_share_access(xdr, arg->share_access);
|
||||
@ -5077,7 +5077,7 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
|
||||
/*
|
||||
* We create the owner, so we know a proper owner.id length is 4.
|
||||
*/
|
||||
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
|
||||
static int decode_lock_denied(struct xdr_stream *xdr, struct file_lock *fl)
|
||||
{
|
||||
uint64_t offset, length, clientid;
|
||||
__be32 *p;
|
||||
@ -7702,6 +7702,7 @@ const struct rpc_procinfo nfs4_procedures[] = {
|
||||
PROC42(CLONE, enc_clone, dec_clone),
|
||||
PROC42(COPY, enc_copy, dec_copy),
|
||||
PROC42(OFFLOAD_CANCEL, enc_offload_cancel, dec_offload_cancel),
|
||||
PROC42(OFFLOAD_STATUS, enc_offload_status, dec_offload_status),
|
||||
PROC42(COPY_NOTIFY, enc_copy_notify, dec_copy_notify),
|
||||
PROC(LOOKUPP, enc_lookupp, dec_lookupp),
|
||||
PROC42(LAYOUTERROR, enc_layouterror, dec_layouterror),
|
||||
|
@ -454,8 +454,12 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
{ NFS_MOUNT_NONLM, ",nolock", "" },
|
||||
{ NFS_MOUNT_NOACL, ",noacl", "" },
|
||||
{ NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
|
||||
{ NFS_MOUNT_FORCE_RDIRPLUS, ",rdirplus=force", "" },
|
||||
{ NFS_MOUNT_UNSHARED, ",nosharecache", "" },
|
||||
{ NFS_MOUNT_NORESVPORT, ",noresvport", "" },
|
||||
{ NFS_MOUNT_NETUNREACH_FATAL,
|
||||
",fatal_neterrors=ENETDOWN:ENETUNREACH",
|
||||
",fatal_neterrors=none" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
const struct proc_nfs_info *nfs_infop;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "nfs4_fs.h"
|
||||
#include "netns.h"
|
||||
#include "sysfs.h"
|
||||
@ -228,6 +229,25 @@ static void shutdown_client(struct rpc_clnt *clnt)
|
||||
rpc_cancel_tasks(clnt, -EIO, shutdown_match_client, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shut down the nfs_client only once all the superblocks
|
||||
* have been shut down.
|
||||
*/
|
||||
static void shutdown_nfs_client(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_server *server;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
|
||||
if (!(server->flags & NFS_MOUNT_SHUTDOWN)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
nfs_mark_client_ready(clp, -EIO);
|
||||
shutdown_client(clp->cl_rpcclient);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
shutdown_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
@ -259,7 +279,6 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
|
||||
server->flags |= NFS_MOUNT_SHUTDOWN;
|
||||
shutdown_client(server->client);
|
||||
shutdown_client(server->nfs_client->cl_rpcclient);
|
||||
|
||||
if (!IS_ERR(server->client_acl))
|
||||
shutdown_client(server->client_acl);
|
||||
@ -267,11 +286,44 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
if (server->nlm_host)
|
||||
shutdown_client(server->nlm_host->h_rpcclnt);
|
||||
out:
|
||||
shutdown_nfs_client(server->nfs_client);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute nfs_sysfs_attr_shutdown = __ATTR_RW(shutdown);
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
static ssize_t
|
||||
implid_domain_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
|
||||
struct nfs41_impl_id *impl_id = server->nfs_client->cl_implid;
|
||||
|
||||
if (!impl_id || strlen(impl_id->domain) == 0)
|
||||
return 0; //sysfs_emit(buf, "");
|
||||
return sysfs_emit(buf, "%s\n", impl_id->domain);
|
||||
}
|
||||
|
||||
static struct kobj_attribute nfs_sysfs_attr_implid_domain = __ATTR_RO(implid_domain);
|
||||
|
||||
|
||||
static ssize_t
|
||||
implid_name_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
|
||||
struct nfs41_impl_id *impl_id = server->nfs_client->cl_implid;
|
||||
|
||||
if (!impl_id || strlen(impl_id->name) == 0)
|
||||
return 0; //sysfs_emit(buf, "");
|
||||
return sysfs_emit(buf, "%s\n", impl_id->name);
|
||||
}
|
||||
|
||||
static struct kobj_attribute nfs_sysfs_attr_implid_name = __ATTR_RO(implid_name);
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_NFS_V4_1) */
|
||||
|
||||
#define RPC_CLIENT_NAME_SIZE 64
|
||||
|
||||
void nfs_sysfs_link_rpc_client(struct nfs_server *server,
|
||||
@ -309,6 +361,32 @@ static struct kobj_type nfs_sb_ktype = {
|
||||
.child_ns_type = nfs_netns_object_child_ns_type,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
static void nfs_sysfs_add_nfsv41_server(struct nfs_server *server)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!server->nfs_client->cl_implid)
|
||||
return;
|
||||
|
||||
ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_implid_domain.attr,
|
||||
nfs_netns_server_namespace(&server->kobj));
|
||||
if (ret < 0)
|
||||
pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
|
||||
server->s_sysfs_id, ret);
|
||||
|
||||
ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_implid_name.attr,
|
||||
nfs_netns_server_namespace(&server->kobj));
|
||||
if (ret < 0)
|
||||
pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
|
||||
server->s_sysfs_id, ret);
|
||||
}
|
||||
#else /* CONFIG_NFS_V4_1 */
|
||||
static inline void nfs_sysfs_add_nfsv41_server(struct nfs_server *server)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
void nfs_sysfs_add_server(struct nfs_server *server)
|
||||
{
|
||||
int ret;
|
||||
@ -325,6 +403,8 @@ void nfs_sysfs_add_server(struct nfs_server *server)
|
||||
if (ret < 0)
|
||||
pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
|
||||
server->s_sysfs_id, ret);
|
||||
|
||||
nfs_sysfs_add_nfsv41_server(server);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_sysfs_add_server);
|
||||
|
||||
|
@ -579,8 +579,10 @@ retry:
|
||||
|
||||
while (!nfs_lock_request(head)) {
|
||||
ret = nfs_wait_on_request(head);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
nfs_release_request(head);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that nobody removed the request before we locked it */
|
||||
|
@ -300,6 +300,7 @@ enum nfsstat4 {
|
||||
/* error codes for internal client use */
|
||||
#define NFS4ERR_RESET_TO_MDS 12001
|
||||
#define NFS4ERR_RESET_TO_PNFS 12002
|
||||
#define NFS4ERR_FATAL_IOERROR 12003
|
||||
|
||||
static inline bool seqid_mutating_err(u32 err)
|
||||
{
|
||||
@ -691,6 +692,7 @@ enum {
|
||||
NFSPROC4_CLNT_LISTXATTRS,
|
||||
NFSPROC4_CLNT_REMOVEXATTR,
|
||||
NFSPROC4_CLNT_READ_PLUS,
|
||||
NFSPROC4_CLNT_OFFLOAD_STATUS,
|
||||
};
|
||||
|
||||
/* nfs41 types */
|
||||
|
@ -50,6 +50,7 @@ struct nfs_client {
|
||||
#define NFS_CS_DS 7 /* - Server is a DS */
|
||||
#define NFS_CS_REUSEPORT 8 /* - reuse src port on reconnect */
|
||||
#define NFS_CS_PNFS 9 /* - Server used for pnfs */
|
||||
#define NFS_CS_NETUNREACH_FATAL 10 /* - ENETUNREACH errors are fatal */
|
||||
struct sockaddr_storage cl_addr; /* server identifier */
|
||||
size_t cl_addrlen;
|
||||
char * cl_hostname; /* hostname of server */
|
||||
@ -167,6 +168,8 @@ struct nfs_server {
|
||||
#define NFS_MOUNT_TRUNK_DISCOVERY 0x04000000
|
||||
#define NFS_MOUNT_SHUTDOWN 0x08000000
|
||||
#define NFS_MOUNT_NO_ALIGNWRITE 0x10000000
|
||||
#define NFS_MOUNT_FORCE_RDIRPLUS 0x20000000
|
||||
#define NFS_MOUNT_NETUNREACH_FATAL 0x40000000
|
||||
|
||||
unsigned int fattr_valid; /* Valid attributes */
|
||||
unsigned int caps; /* server capabilities */
|
||||
@ -250,6 +253,10 @@ struct nfs_server {
|
||||
struct list_head ss_copies;
|
||||
struct list_head ss_src_copies;
|
||||
|
||||
unsigned long delegation_flags;
|
||||
#define NFS4SERV_DELEGRETURN (1)
|
||||
#define NFS4SERV_DELEGATION_EXPIRED (2)
|
||||
#define NFS4SERV_DELEGRETURN_DELAYED (3)
|
||||
unsigned long delegation_gen;
|
||||
unsigned long mig_gen;
|
||||
unsigned long mig_status;
|
||||
@ -289,6 +296,7 @@ struct nfs_server {
|
||||
#define NFS_CAP_CASE_INSENSITIVE (1U << 6)
|
||||
#define NFS_CAP_CASE_PRESERVING (1U << 7)
|
||||
#define NFS_CAP_REBOOT_LAYOUTRETURN (1U << 8)
|
||||
#define NFS_CAP_OFFLOAD_STATUS (1U << 9)
|
||||
#define NFS_CAP_OPEN_XOR (1U << 12)
|
||||
#define NFS_CAP_DELEGTIME (1U << 13)
|
||||
#define NFS_CAP_POSIX_LOCK (1U << 14)
|
||||
|
@ -1515,8 +1515,9 @@ struct nfs42_offload_status_args {
|
||||
|
||||
struct nfs42_offload_status_res {
|
||||
struct nfs4_sequence_res osr_seq_res;
|
||||
uint64_t osr_count;
|
||||
int osr_status;
|
||||
u64 osr_count;
|
||||
int complete_count;
|
||||
u32 osr_complete;
|
||||
};
|
||||
|
||||
struct nfs42_copy_notify_args {
|
||||
|
@ -64,7 +64,9 @@ struct rpc_clnt {
|
||||
cl_noretranstimeo: 1,/* No retransmit timeouts */
|
||||
cl_autobind : 1,/* use getport() */
|
||||
cl_chatty : 1,/* be verbose */
|
||||
cl_shutdown : 1;/* rpc immediate -EIO */
|
||||
cl_shutdown : 1,/* rpc immediate -EIO */
|
||||
cl_netunreach_fatal : 1;
|
||||
/* Treat ENETUNREACH errors as fatal */
|
||||
struct xprtsec_parms cl_xprtsec; /* transport security policy */
|
||||
|
||||
struct rpc_rtt * cl_rtt; /* RTO estimator data */
|
||||
@ -175,6 +177,7 @@ struct rpc_add_xprt_test {
|
||||
#define RPC_CLNT_CREATE_SOFTERR (1UL << 10)
|
||||
#define RPC_CLNT_CREATE_REUSEPORT (1UL << 11)
|
||||
#define RPC_CLNT_CREATE_CONNECTED (1UL << 12)
|
||||
#define RPC_CLNT_CREATE_NETUNREACH_FATAL (1UL << 13)
|
||||
|
||||
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
|
||||
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
|
||||
|
@ -134,6 +134,7 @@ struct rpc_task_setup {
|
||||
#define RPC_TASK_MOVEABLE 0x0004 /* nfs4.1+ rpc tasks */
|
||||
#define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */
|
||||
#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */
|
||||
#define RPC_TASK_NETUNREACH_FATAL 0x0040 /* ENETUNREACH is fatal */
|
||||
#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
|
||||
#define RPC_TASK_NO_ROUND_ROBIN 0x0100 /* send requests on "main" xprt */
|
||||
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
|
||||
|
@ -56,6 +56,7 @@ extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps,
|
||||
struct rpc_xprt *xprt);
|
||||
extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
|
||||
struct rpc_xprt *xprt, bool offline);
|
||||
extern struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps);
|
||||
|
||||
extern void xprt_iter_init(struct rpc_xprt_iter *xpi,
|
||||
struct rpc_xprt_switch *xps);
|
||||
|
@ -343,6 +343,7 @@ TRACE_EVENT(rpc_request,
|
||||
{ RPC_TASK_MOVEABLE, "MOVEABLE" }, \
|
||||
{ RPC_TASK_NULLCREDS, "NULLCREDS" }, \
|
||||
{ RPC_CALL_MAJORSEEN, "MAJORSEEN" }, \
|
||||
{ RPC_TASK_NETUNREACH_FATAL, "NETUNREACH_FATAL"}, \
|
||||
{ RPC_TASK_DYNAMIC, "DYNAMIC" }, \
|
||||
{ RPC_TASK_NO_ROUND_ROBIN, "NO_ROUND_ROBIN" }, \
|
||||
{ RPC_TASK_SOFT, "SOFT" }, \
|
||||
|
@ -270,9 +270,6 @@ static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
|
||||
old = rcu_dereference_protected(clnt->cl_xprt,
|
||||
lockdep_is_held(&clnt->cl_lock));
|
||||
|
||||
if (!xprt_bound(xprt))
|
||||
clnt->cl_autobind = 1;
|
||||
|
||||
clnt->cl_timeout = timeout;
|
||||
rcu_assign_pointer(clnt->cl_xprt, xprt);
|
||||
spin_unlock(&clnt->cl_lock);
|
||||
@ -512,6 +509,8 @@ static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
|
||||
clnt->cl_discrtry = 1;
|
||||
if (!(args->flags & RPC_CLNT_CREATE_QUIET))
|
||||
clnt->cl_chatty = 1;
|
||||
if (args->flags & RPC_CLNT_CREATE_NETUNREACH_FATAL)
|
||||
clnt->cl_netunreach_fatal = 1;
|
||||
|
||||
return clnt;
|
||||
}
|
||||
@ -662,6 +661,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
|
||||
new->cl_noretranstimeo = clnt->cl_noretranstimeo;
|
||||
new->cl_discrtry = clnt->cl_discrtry;
|
||||
new->cl_chatty = clnt->cl_chatty;
|
||||
new->cl_netunreach_fatal = clnt->cl_netunreach_fatal;
|
||||
new->cl_principal = clnt->cl_principal;
|
||||
new->cl_max_connect = clnt->cl_max_connect;
|
||||
return new;
|
||||
@ -1195,6 +1195,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
|
||||
task->tk_flags |= RPC_TASK_TIMEOUT;
|
||||
if (clnt->cl_noretranstimeo)
|
||||
task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
|
||||
if (clnt->cl_netunreach_fatal)
|
||||
task->tk_flags |= RPC_TASK_NETUNREACH_FATAL;
|
||||
atomic_inc(&clnt->cl_task_count);
|
||||
}
|
||||
|
||||
@ -2102,14 +2104,17 @@ call_bind_status(struct rpc_task *task)
|
||||
case -EPROTONOSUPPORT:
|
||||
trace_rpcb_bind_version_err(task);
|
||||
goto retry_timeout;
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
if (task->tk_flags & RPC_TASK_NETUNREACH_FATAL)
|
||||
break;
|
||||
fallthrough;
|
||||
case -ECONNREFUSED: /* connection problems */
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
case -ENOTCONN:
|
||||
case -EHOSTDOWN:
|
||||
case -ENETDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETUNREACH:
|
||||
case -EPIPE:
|
||||
trace_rpcb_unreachable_err(task);
|
||||
if (!RPC_IS_SOFTCONN(task)) {
|
||||
@ -2191,19 +2196,22 @@ call_connect_status(struct rpc_task *task)
|
||||
|
||||
task->tk_status = 0;
|
||||
switch (status) {
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
if (task->tk_flags & RPC_TASK_NETUNREACH_FATAL)
|
||||
break;
|
||||
fallthrough;
|
||||
case -ECONNREFUSED:
|
||||
case -ECONNRESET:
|
||||
/* A positive refusal suggests a rebind is needed. */
|
||||
if (RPC_IS_SOFTCONN(task))
|
||||
break;
|
||||
if (clnt->cl_autobind) {
|
||||
rpc_force_rebind(clnt);
|
||||
if (RPC_IS_SOFTCONN(task))
|
||||
break;
|
||||
goto out_retry;
|
||||
}
|
||||
fallthrough;
|
||||
case -ECONNABORTED:
|
||||
case -ENETDOWN:
|
||||
case -ENETUNREACH:
|
||||
case -EHOSTUNREACH:
|
||||
case -EPIPE:
|
||||
case -EPROTO:
|
||||
@ -2455,10 +2463,13 @@ call_status(struct rpc_task *task)
|
||||
trace_rpc_call_status(task);
|
||||
task->tk_status = 0;
|
||||
switch(status) {
|
||||
case -EHOSTDOWN:
|
||||
case -ENETDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETUNREACH:
|
||||
if (task->tk_flags & RPC_TASK_NETUNREACH_FATAL)
|
||||
goto out_exit;
|
||||
fallthrough;
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -EPERM:
|
||||
if (RPC_IS_SOFTCONN(task))
|
||||
goto out_exit;
|
||||
|
@ -820,9 +820,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
|
||||
}
|
||||
|
||||
trace_rpcb_setport(child, map->r_status, map->r_port);
|
||||
xprt->ops->set_port(xprt, map->r_port);
|
||||
if (map->r_port)
|
||||
if (map->r_port) {
|
||||
xprt->ops->set_port(xprt, map->r_port);
|
||||
xprt_set_bound(xprt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -276,6 +276,8 @@ EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
|
||||
|
||||
static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
|
||||
{
|
||||
if (unlikely(current->flags & PF_EXITING))
|
||||
return -EINTR;
|
||||
schedule();
|
||||
if (signal_pending_state(mode, current))
|
||||
return -ERESTARTSYS;
|
||||
|
@ -59,6 +59,16 @@ static struct kobject *rpc_sysfs_object_alloc(const char *name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct rpc_clnt *
|
||||
rpc_sysfs_client_kobj_get_clnt(struct kobject *kobj)
|
||||
{
|
||||
struct rpc_sysfs_client *c = container_of(kobj,
|
||||
struct rpc_sysfs_client, kobject);
|
||||
struct rpc_clnt *ret = c->clnt;
|
||||
|
||||
return refcount_inc_not_zero(&ret->cl_count) ? ret : NULL;
|
||||
}
|
||||
|
||||
static inline struct rpc_xprt *
|
||||
rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
|
||||
{
|
||||
@ -86,6 +96,51 @@ rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
|
||||
return xprt_switch_get(x->xprt_switch);
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_clnt_version_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rpc_clnt *clnt = rpc_sysfs_client_kobj_get_clnt(kobj);
|
||||
ssize_t ret;
|
||||
|
||||
if (!clnt)
|
||||
return sprintf(buf, "<closed>\n");
|
||||
|
||||
ret = sprintf(buf, "%u", clnt->cl_vers);
|
||||
refcount_dec(&clnt->cl_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_clnt_program_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rpc_clnt *clnt = rpc_sysfs_client_kobj_get_clnt(kobj);
|
||||
ssize_t ret;
|
||||
|
||||
if (!clnt)
|
||||
return sprintf(buf, "<closed>\n");
|
||||
|
||||
ret = sprintf(buf, "%s", clnt->cl_program->name);
|
||||
refcount_dec(&clnt->cl_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_clnt_max_connect_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rpc_clnt *clnt = rpc_sysfs_client_kobj_get_clnt(kobj);
|
||||
ssize_t ret;
|
||||
|
||||
if (!clnt)
|
||||
return sprintf(buf, "<closed>\n");
|
||||
|
||||
ret = sprintf(buf, "%u\n", clnt->cl_max_connect);
|
||||
refcount_dec(&clnt->cl_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
@ -129,6 +184,31 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *xprtsec_strings[] = {
|
||||
[RPC_XPRTSEC_NONE] = "none",
|
||||
[RPC_XPRTSEC_TLS_ANON] = "tls-anon",
|
||||
[RPC_XPRTSEC_TLS_X509] = "tls-x509",
|
||||
};
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_xprtsec_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
|
||||
ssize_t ret;
|
||||
|
||||
if (!xprt) {
|
||||
ret = sprintf(buf, "<closed>\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = sprintf(buf, "%s\n", xprtsec_strings[xprt->xprtsec.policy]);
|
||||
xprt_put(xprt);
|
||||
out:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
@ -206,6 +286,14 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_del_xprt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "# delete this xprt\n");
|
||||
}
|
||||
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
@ -225,6 +313,55 @@ static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_switch_add_xprt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "# add one xprt to this xprt_switch\n");
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_switch_add_xprt_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct rpc_xprt_switch *xprt_switch =
|
||||
rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
|
||||
struct xprt_create xprt_create_args;
|
||||
struct rpc_xprt *xprt, *new;
|
||||
|
||||
if (!xprt_switch)
|
||||
return 0;
|
||||
|
||||
xprt = rpc_xprt_switch_get_main_xprt(xprt_switch);
|
||||
if (!xprt)
|
||||
goto out;
|
||||
|
||||
xprt_create_args.ident = xprt->xprt_class->ident;
|
||||
xprt_create_args.net = xprt->xprt_net;
|
||||
xprt_create_args.dstaddr = (struct sockaddr *)&xprt->addr;
|
||||
xprt_create_args.addrlen = xprt->addrlen;
|
||||
xprt_create_args.servername = xprt->servername;
|
||||
xprt_create_args.bc_xprt = xprt->bc_xprt;
|
||||
xprt_create_args.xprtsec = xprt->xprtsec;
|
||||
xprt_create_args.connect_timeout = xprt->connect_timeout;
|
||||
xprt_create_args.reconnect_timeout = xprt->max_reconnect_timeout;
|
||||
|
||||
new = xprt_create_transport(&xprt_create_args);
|
||||
if (IS_ERR_OR_NULL(new)) {
|
||||
count = PTR_ERR(new);
|
||||
goto out_put_xprt;
|
||||
}
|
||||
|
||||
rpc_xprt_switch_add_xprt(xprt_switch, new);
|
||||
xprt_put(new);
|
||||
|
||||
out_put_xprt:
|
||||
xprt_put(xprt);
|
||||
out:
|
||||
xprt_switch_put(xprt_switch);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@ -335,6 +472,40 @@ out_put:
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rpc_sysfs_xprt_del_xprt(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
|
||||
struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
|
||||
|
||||
if (!xprt || !xps) {
|
||||
count = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (xprt->main) {
|
||||
count = -EINVAL;
|
||||
goto release_tasks;
|
||||
}
|
||||
|
||||
if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
|
||||
count = -EINTR;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
xprt_set_offline_locked(xprt, xps);
|
||||
xprt_delete_locked(xprt, xps);
|
||||
|
||||
release_tasks:
|
||||
xprt_release_write(xprt, NULL);
|
||||
out_put:
|
||||
xprt_put(xprt);
|
||||
xprt_switch_put(xps);
|
||||
out:
|
||||
return count;
|
||||
}
|
||||
|
||||
int rpc_sysfs_init(void)
|
||||
{
|
||||
rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
|
||||
@ -398,23 +569,48 @@ static const void *rpc_sysfs_xprt_namespace(const struct kobject *kobj)
|
||||
kobject)->xprt->xprt_net;
|
||||
}
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_clnt_version = __ATTR(rpc_version,
|
||||
0444, rpc_sysfs_clnt_version_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_clnt_program = __ATTR(program,
|
||||
0444, rpc_sysfs_clnt_program_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_clnt_max_connect = __ATTR(max_connect,
|
||||
0444, rpc_sysfs_clnt_max_connect_show, NULL);
|
||||
|
||||
static struct attribute *rpc_sysfs_rpc_clnt_attrs[] = {
|
||||
&rpc_sysfs_clnt_version.attr,
|
||||
&rpc_sysfs_clnt_program.attr,
|
||||
&rpc_sysfs_clnt_max_connect.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(rpc_sysfs_rpc_clnt);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
|
||||
0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
|
||||
0644, rpc_sysfs_xprt_srcaddr_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_xprtsec = __ATTR(xprtsec,
|
||||
0644, rpc_sysfs_xprt_xprtsec_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
|
||||
0444, rpc_sysfs_xprt_info_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
|
||||
0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_del = __ATTR(del_xprt,
|
||||
0644, rpc_sysfs_xprt_del_xprt_show, rpc_sysfs_xprt_del_xprt);
|
||||
|
||||
static struct attribute *rpc_sysfs_xprt_attrs[] = {
|
||||
&rpc_sysfs_xprt_dstaddr.attr,
|
||||
&rpc_sysfs_xprt_srcaddr.attr,
|
||||
&rpc_sysfs_xprt_xprtsec.attr,
|
||||
&rpc_sysfs_xprt_info.attr,
|
||||
&rpc_sysfs_xprt_change_state.attr,
|
||||
&rpc_sysfs_xprt_del.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
|
||||
@ -422,14 +618,20 @@ ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
|
||||
static struct kobj_attribute rpc_sysfs_xprt_switch_info =
|
||||
__ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
|
||||
|
||||
static struct kobj_attribute rpc_sysfs_xprt_switch_add_xprt =
|
||||
__ATTR(add_xprt, 0644, rpc_sysfs_xprt_switch_add_xprt_show,
|
||||
rpc_sysfs_xprt_switch_add_xprt_store);
|
||||
|
||||
static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
|
||||
&rpc_sysfs_xprt_switch_info.attr,
|
||||
&rpc_sysfs_xprt_switch_add_xprt.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
|
||||
|
||||
static const struct kobj_type rpc_sysfs_client_type = {
|
||||
.release = rpc_sysfs_client_release,
|
||||
.default_groups = rpc_sysfs_rpc_clnt_groups,
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.namespace = rpc_sysfs_client_namespace,
|
||||
};
|
||||
|
@ -92,6 +92,27 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
|
||||
xprt_put(xprt);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_xprt_switch_get_main_xprt - Get the 'main' xprt for an xprt switch.
|
||||
* @xps: pointer to struct rpc_xprt_switch.
|
||||
*/
|
||||
struct rpc_xprt *rpc_xprt_switch_get_main_xprt(struct rpc_xprt_switch *xps)
|
||||
{
|
||||
struct rpc_xprt_iter xpi;
|
||||
struct rpc_xprt *xprt;
|
||||
|
||||
xprt_iter_init_listall(&xpi, xps);
|
||||
|
||||
xprt = xprt_iter_get_next(&xpi);
|
||||
while (xprt && !xprt->main) {
|
||||
xprt_put(xprt);
|
||||
xprt = xprt_iter_get_next(&xpi);
|
||||
}
|
||||
|
||||
xprt_iter_destroy(&xpi);
|
||||
return xprt;
|
||||
}
|
||||
|
||||
static DEFINE_IDA(rpc_xprtswitch_ids);
|
||||
|
||||
void xprt_multipath_cleanup_ids(void)
|
||||
|
Loading…
x
Reference in New Issue
Block a user