NFS: add sysfs shutdown knob
authorBenjamin Coddington <bcodding@redhat.com>
Thu, 15 Jun 2023 18:07:30 +0000 (14:07 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 19 Jun 2023 19:08:12 +0000 (15:08 -0400)
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@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/sysfs.c
include/linux/nfs_fs_sb.h
include/linux/sunrpc/clnt.h
net/sunrpc/clnt.c

index 7009de149158a6feda7ae4620f10a807214ae95e..1fedbaff10e999f542f292de26177857cf213413 100644 (file)
@@ -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"
@@ -216,6 +217,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,
@@ -259,9 +304,16 @@ void nfs_sysfs_add_server(struct nfs_server *server)
 
        ret = kobject_init_and_add(&server->kobj, &nfs_sb_ktype,
                                &nfs_kset->kobj, "server-%d", server->s_sysfs_id);
-       if (ret < 0)
+       if (ret < 0) {
                pr_warn("NFS: nfs sysfs add server-%d failed (%d)\n",
                                        server->s_sysfs_id, ret);
+               return;
+       }
+       ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_shutdown.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);
 }
 EXPORT_SYMBOL_GPL(nfs_sysfs_add_server);
 
index 4bed0b6c79c7cf807bbb65be3c453384ece41298..20eeba8b009df1100a3c6080f84c93277aaba4dc 100644 (file)
@@ -154,6 +154,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 */
index 88cdf6e3012af6f5414960da9a25018c331f9d90..4f41d839face4d856b4f5b7553bbfa78737ac701 100644 (file)
@@ -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 xprtsec_parms    cl_xprtsec;     /* transport security policy */
 
        struct rpc_rtt *        cl_rtt;         /* RTO estimator data */
index 640c76ab2f1af58f9f5785702a31de3cdd90b9f8..d7c697af3762f69b8406f3d60a277f3f3f72b53a 100644 (file)
@@ -1724,6 +1724,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]++;