sunrpc: Create per-rpc_clnt sysfs kobjects
[linux-2.6-microblaze.git] / net / sunrpc / sysfs.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com>
4  */
5 #include <linux/sunrpc/clnt.h>
6 #include <linux/kobject.h>
7 #include "sysfs.h"
8
9 static struct kset *rpc_sunrpc_kset;
10 static struct kobject *rpc_sunrpc_client_kobj;
11
12 static void rpc_sysfs_object_release(struct kobject *kobj)
13 {
14         kfree(kobj);
15 }
16
17 static const struct kobj_ns_type_operations *
18 rpc_sysfs_object_child_ns_type(struct kobject *kobj)
19 {
20         return &net_ns_type_operations;
21 }
22
23 static struct kobj_type rpc_sysfs_object_type = {
24         .release = rpc_sysfs_object_release,
25         .sysfs_ops = &kobj_sysfs_ops,
26         .child_ns_type = rpc_sysfs_object_child_ns_type,
27 };
28
29 static struct kobject *rpc_sysfs_object_alloc(const char *name,
30                                               struct kset *kset,
31                                               struct kobject *parent)
32 {
33         struct kobject *kobj;
34
35         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
36         if (kobj) {
37                 kobj->kset = kset;
38                 if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
39                                          parent, "%s", name) == 0)
40                         return kobj;
41                 kobject_put(kobj);
42         }
43         return NULL;
44 }
45
46 int rpc_sysfs_init(void)
47 {
48         rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
49         if (!rpc_sunrpc_kset)
50                 return -ENOMEM;
51         rpc_sunrpc_client_kobj = rpc_sysfs_object_alloc("client", rpc_sunrpc_kset, NULL);
52         if (!rpc_sunrpc_client_kobj) {
53                 kset_unregister(rpc_sunrpc_kset);
54                 rpc_sunrpc_client_kobj = NULL;
55                 return -ENOMEM;
56         }
57         return 0;
58 }
59
60 static void rpc_sysfs_client_release(struct kobject *kobj)
61 {
62         struct rpc_sysfs_client *c;
63
64         c = container_of(kobj, struct rpc_sysfs_client, kobject);
65         kfree(c);
66 }
67
68 static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
69 {
70         return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
71 }
72
73 static struct kobj_type rpc_sysfs_client_type = {
74         .release = rpc_sysfs_client_release,
75         .sysfs_ops = &kobj_sysfs_ops,
76         .namespace = rpc_sysfs_client_namespace,
77 };
78
79 void rpc_sysfs_exit(void)
80 {
81         kobject_put(rpc_sunrpc_client_kobj);
82         kset_unregister(rpc_sunrpc_kset);
83 }
84
85 static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
86                                                        struct net *net,
87                                                        int clid)
88 {
89         struct rpc_sysfs_client *p;
90
91         p = kzalloc(sizeof(*p), GFP_KERNEL);
92         if (p) {
93                 p->net = net;
94                 p->kobject.kset = rpc_sunrpc_kset;
95                 if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
96                                          parent, "clnt-%d", clid) == 0)
97                         return p;
98                 kobject_put(&p->kobject);
99         }
100         return NULL;
101 }
102
103 void rpc_sysfs_client_setup(struct rpc_clnt *clnt, struct net *net)
104 {
105         struct rpc_sysfs_client *rpc_client;
106
107         rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj, net, clnt->cl_clid);
108         if (rpc_client) {
109                 clnt->cl_sysfs = rpc_client;
110                 kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
111         }
112 }
113
114 void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
115 {
116         struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
117
118         if (rpc_client) {
119                 kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
120                 kobject_del(&rpc_client->kobject);
121                 kobject_put(&rpc_client->kobject);
122                 clnt->cl_sysfs = NULL;
123         }
124 }