Within each nfs_server sysfs tree, add an entry named "shutdown". Writing 1 to this file will set the cl_shutdown bit on the rpc_clnt structs associated with that mount. If cl_shutdown is set, the task scheduler immediately returns -EIO for new tasks. Signed-off-by: Benjamin Coddington <bcodding@xxxxxxxxxx> --- fs/nfs/sysfs.c | 46 +++++++++++++++++++++++++++++++++++++ include/linux/nfs_fs_sb.h | 1 + include/linux/sunrpc/clnt.h | 3 ++- net/sunrpc/clnt.c | 5 ++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c index e1b5df7a3df5..09fde2719495 100644 --- a/fs/nfs/sysfs.c +++ b/fs/nfs/sysfs.c @@ -12,6 +12,7 @@ #include <linux/string.h> #include <linux/nfs_fs.h> #include <linux/rcupdate.h> +#include <linux/lockd/lockd.h> #include "nfs4_fs.h" #include "netns.h" @@ -191,6 +192,50 @@ void nfs_netns_sysfs_destroy(struct nfs_net *netns) } } +static ssize_t +shutdown_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct nfs_server *server = container_of(kobj, struct nfs_server, kobj); + bool shutdown = server->flags & NFS_MOUNT_SHUTDOWN; + return sysfs_emit(buf, "%d\n", shutdown); +} + +static ssize_t +shutdown_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct nfs_server *server; + int ret, val; + + server = container_of(kobj, struct nfs_server, kobj); + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + if (val != 1) + return -EINVAL; + + /* already shut down? */ + if (server->flags & NFS_MOUNT_SHUTDOWN) + goto out; + + server->flags |= NFS_MOUNT_SHUTDOWN; + server->client->cl_shutdown = 1; + server->nfs_client->cl_rpcclient->cl_shutdown = 1; + + if (!IS_ERR(server->client_acl)) + server->client_acl->cl_shutdown = 1; + + if (server->nlm_host) + server->nlm_host->h_rpcclnt->cl_shutdown = 1; +out: + return count; +} + +static struct kobj_attribute nfs_sysfs_attr_shutdown = __ATTR_RW(shutdown); + #define RPC_CLIENT_NAME_SIZE 64 void nfs_sysfs_link_rpc_client(struct nfs_server *server, @@ -217,6 +262,7 @@ static void nfs_sysfs_sb_release(struct kobject *kobj) } static struct attribute *nfs_mp_attrs[] = { + &nfs_sysfs_attr_shutdown.attr, NULL, }; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index dee1664abca8..bc89496384ff 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -153,6 +153,7 @@ struct nfs_server { #define NFS_MOUNT_WRITE_EAGER 0x01000000 #define NFS_MOUNT_WRITE_WAIT 0x02000000 #define NFS_MOUNT_TRUNK_DISCOVERY 0x04000000 +#define NFS_MOUNT_SHUTDOWN 0x08000000 unsigned int fattr_valid; /* Valid attributes */ unsigned int caps; /* server capabilities */ diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 4ec718aa91f5..9f72c75a2056 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -63,7 +63,8 @@ struct rpc_clnt { cl_discrtry : 1,/* disconnect before retry */ cl_noretranstimeo: 1,/* No retransmit timeouts */ cl_autobind : 1,/* use getport() */ - cl_chatty : 1;/* be verbose */ + cl_chatty : 1,/* be verbose */ + cl_shutdown : 1;/* rpc immediate -EIO */ struct rpc_rtt * cl_rtt; /* RTO estimator data */ const struct rpc_timeout *cl_timeout; /* Timeout strategy */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0b0b9f1eed46..3c5dca88a918 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1717,6 +1717,11 @@ call_start(struct rpc_task *task) trace_rpc_request(task); + if (task->tk_client->cl_shutdown) { + rpc_call_rpcerror(task, -EIO); + return; + } + /* Increment call count (version might not be valid for ping) */ if (clnt->cl_program->version[clnt->cl_vers]) clnt->cl_program->version[clnt->cl_vers]->counts[idx]++; -- 2.39.2