NFS: add superblock sysfs entries
authorBenjamin Coddington <bcodding@redhat.com>
Thu, 15 Jun 2023 18:07:26 +0000 (14:07 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 19 Jun 2023 19:03:48 +0000 (15:03 -0400)
Create a sysfs directory for each mount that corresponds to the mount's
nfs_server struct.  As the mount is being constructed, use the name
"server-n", but rename it to the "MAJOR:MINOR" of the mount after assigning
a device_id. The rename approach allows us to populate the mount's directory
with links to the various rpc_client objects during the mount's
construction.  The naming convention (MAJOR:MINOR) can be used to reference
a particular NFS mount's sysfs tree.

Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/client.c
fs/nfs/nfs4client.c
fs/nfs/super.c
fs/nfs/sysfs.c
fs/nfs/sysfs.h
include/linux/nfs_fs_sb.h

index d5441e6..e95672a 100644 (file)
@@ -698,6 +698,7 @@ static int nfs_init_server(struct nfs_server *server,
                return PTR_ERR(clp);
 
        server->nfs_client = clp;
+       nfs_sysfs_add_server(server);
 
        /* Initialise the client representation from the mount data */
        server->flags = ctx->flags;
@@ -952,6 +953,8 @@ void nfs_server_remove_lists(struct nfs_server *server)
 }
 EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
 
+static DEFINE_IDA(s_sysfs_ids);
+
 /*
  * Allocate and initialise a server record
  */
@@ -963,6 +966,12 @@ struct nfs_server *nfs_alloc_server(void)
        if (!server)
                return NULL;
 
+       server->s_sysfs_id = ida_alloc(&s_sysfs_ids, GFP_KERNEL);
+       if (server->s_sysfs_id < 0) {
+               kfree(server);
+               return NULL;
+       }
+
        server->client = server->client_acl = ERR_PTR(-EINVAL);
 
        /* Zero out the NFS state stuff */
@@ -1009,6 +1018,10 @@ void nfs_free_server(struct nfs_server *server)
 
        nfs_put_client(server->nfs_client);
 
+       nfs_sysfs_remove_server(server);
+       kobject_put(&server->kobj);
+       ida_free(&s_sysfs_ids, server->s_sysfs_id);
+
        ida_destroy(&server->lockowner_id);
        ida_destroy(&server->openowner_id);
        nfs_free_iostats(server->io_stats);
@@ -1110,6 +1123,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
 
        server->fsid = fattr->fsid;
 
+       nfs_sysfs_add_server(server);
+
        error = nfs_init_server_rpcclient(server,
                        source->client->cl_timeout,
                        flavor);
@@ -1393,6 +1408,7 @@ error_0:
 void nfs_fs_proc_exit(void)
 {
        remove_proc_subtree("fs/nfsfs", NULL);
+       ida_destroy(&s_sysfs_ids);
 }
 
 #endif /* CONFIG_PROC_FS */
index 3218549..a098a41 100644 (file)
@@ -18,6 +18,7 @@
 #include "nfs4idmap.h"
 #include "pnfs.h"
 #include "netns.h"
+#include "sysfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
@@ -952,6 +953,8 @@ static int nfs4_set_client(struct nfs_server *server,
        set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
 
        server->nfs_client = clp;
+       nfs_sysfs_add_server(server);
+
        return 0;
 }
 
index 059b0be..2284f74 100644 (file)
@@ -70,6 +70,8 @@
 #include "nfs4session.h"
 #include "pnfs.h"
 #include "nfs.h"
+#include "netns.h"
+#include "sysfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -1089,6 +1091,7 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
                                                 &sb->s_blocksize_bits);
 
        nfs_super_set_maxbytes(sb, server->maxfilesize);
+       nfs_sysfs_move_server_to_sb(sb);
        server->has_sec_mnt_opts = ctx->has_sec_mnt_opts;
 }
 
@@ -1331,13 +1334,14 @@ error_splat_super:
 }
 
 /*
- * Destroy an NFS2/3 superblock
+ * Destroy an NFS superblock
  */
 void nfs_kill_super(struct super_block *s)
 {
        struct nfs_server *server = NFS_SB(s);
        dev_t dev = s->s_dev;
 
+       nfs_sysfs_move_sb_to_server(server);
        generic_shutdown_super(s);
 
        nfs_fscache_release_super_cookie(s);
index 90256a3..0ff24f1 100644 (file)
@@ -215,3 +215,62 @@ void nfs_netns_sysfs_destroy(struct nfs_net *netns)
                netns->nfs_client = NULL;
        }
 }
+
+static void nfs_sysfs_sb_release(struct kobject *kobj)
+{
+       /* no-op: why? see lib/kobject.c kobject_cleanup() */
+}
+
+static const void *nfs_netns_server_namespace(const struct kobject *kobj)
+{
+       return container_of(kobj, struct nfs_server, kobj)->nfs_client->cl_net;
+}
+
+static struct kobj_type nfs_sb_ktype = {
+       .release = nfs_sysfs_sb_release,
+       .sysfs_ops = &kobj_sysfs_ops,
+       .namespace = nfs_netns_server_namespace,
+       .child_ns_type = nfs_netns_object_child_ns_type,
+};
+
+void nfs_sysfs_add_server(struct nfs_server *server)
+{
+       int ret;
+
+       ret = kobject_init_and_add(&server->kobj, &nfs_sb_ktype,
+                               &nfs_kset->kobj, "server-%d", server->s_sysfs_id);
+       if (ret < 0)
+               pr_warn("NFS: nfs sysfs add server-%d failed (%d)\n",
+                                       server->s_sysfs_id, ret);
+}
+EXPORT_SYMBOL_GPL(nfs_sysfs_add_server);
+
+void nfs_sysfs_move_server_to_sb(struct super_block *s)
+{
+       struct nfs_server *server = s->s_fs_info;
+       int ret;
+
+       ret = kobject_rename(&server->kobj, s->s_id);
+       if (ret < 0)
+               pr_warn("NFS: rename sysfs %s failed (%d)\n",
+                                       server->kobj.name, ret);
+}
+
+void nfs_sysfs_move_sb_to_server(struct nfs_server *server)
+{
+       const char *s;
+       int ret = -ENOMEM;
+
+       s = kasprintf(GFP_KERNEL, "server-%d", server->s_sysfs_id);
+       if (s)
+               ret = kobject_rename(&server->kobj, s);
+       if (ret < 0)
+               pr_warn("NFS: rename sysfs %s failed (%d)\n",
+                                       server->kobj.name, ret);
+}
+
+/* unlink, not dec-ref */
+void nfs_sysfs_remove_server(struct nfs_server *server)
+{
+       kobject_del(&server->kobj);
+}
index dc4cc98..c9f5e36 100644 (file)
@@ -23,4 +23,9 @@ extern void nfs_sysfs_exit(void);
 void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net);
 void nfs_netns_sysfs_destroy(struct nfs_net *netns);
 
+void nfs_sysfs_add_server(struct nfs_server *s);
+void nfs_sysfs_move_server_to_sb(struct super_block *s);
+void nfs_sysfs_move_sb_to_server(struct nfs_server *s);
+void nfs_sysfs_remove_server(struct nfs_server *s);
+
 #endif
index fa5a592..4bed0b6 100644 (file)
@@ -184,6 +184,7 @@ struct nfs_server {
                                change_attr_type;/* Description of change attribute */
 
        struct nfs_fsid         fsid;
+       int                     s_sysfs_id;     /* sysfs dentry index */
        __u64                   maxfilesize;    /* maximum file size */
        struct timespec64       time_delta;     /* smallest time granularity */
        unsigned long           mount_time;     /* when this fs was mounted */
@@ -260,6 +261,7 @@ struct nfs_server {
        /* User namespace info */
        const struct cred       *cred;
        bool                    has_sec_mnt_opts;
+       struct kobject          kobj;
 };
 
 /* Server capabilities */