xref: /openbmc/linux/fs/nfs/sysfs.c (revision e96f9268eea626126021641eefeed02f8669f584)
1996bc4f4STrond Myklebust // SPDX-License-Identifier: GPL-2.0
2996bc4f4STrond Myklebust /*
3996bc4f4STrond Myklebust  * Copyright (c) 2019 Hammerspace Inc
4996bc4f4STrond Myklebust  */
5996bc4f4STrond Myklebust 
6996bc4f4STrond Myklebust #include <linux/module.h>
7996bc4f4STrond Myklebust #include <linux/kobject.h>
8996bc4f4STrond Myklebust #include <linux/sysfs.h>
9996bc4f4STrond Myklebust #include <linux/fs.h>
10996bc4f4STrond Myklebust #include <linux/slab.h>
11996bc4f4STrond Myklebust #include <linux/netdevice.h>
12bf11fbdbSTrond Myklebust #include <linux/string.h>
13bf11fbdbSTrond Myklebust #include <linux/nfs_fs.h>
14bf11fbdbSTrond Myklebust #include <linux/rcupdate.h>
15996bc4f4STrond Myklebust 
16bf11fbdbSTrond Myklebust #include "nfs4_fs.h"
17bf11fbdbSTrond Myklebust #include "netns.h"
18996bc4f4STrond Myklebust #include "sysfs.h"
19996bc4f4STrond Myklebust 
208b18a2edSBenjamin Coddington static struct kset *nfs_kset;
21996bc4f4STrond Myklebust 
22943aef2dSBenjamin Coddington static void nfs_kset_release(struct kobject *kobj)
23943aef2dSBenjamin Coddington {
24943aef2dSBenjamin Coddington 	struct kset *kset = container_of(kobj, struct kset, kobj);
25943aef2dSBenjamin Coddington 	kfree(kset);
26943aef2dSBenjamin Coddington }
27943aef2dSBenjamin Coddington 
28996bc4f4STrond Myklebust static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
2902a476d9SGreg Kroah-Hartman 		const struct kobject *kobj)
30996bc4f4STrond Myklebust {
31996bc4f4STrond Myklebust 	return &net_ns_type_operations;
32996bc4f4STrond Myklebust }
33996bc4f4STrond Myklebust 
34943aef2dSBenjamin Coddington static struct kobj_type nfs_kset_type = {
35943aef2dSBenjamin Coddington 	.release = nfs_kset_release,
36943aef2dSBenjamin Coddington 	.sysfs_ops = &kobj_sysfs_ops,
37996bc4f4STrond Myklebust 	.child_ns_type = nfs_netns_object_child_ns_type,
38996bc4f4STrond Myklebust };
39996bc4f4STrond Myklebust 
40996bc4f4STrond Myklebust int nfs_sysfs_init(void)
41996bc4f4STrond Myklebust {
42943aef2dSBenjamin Coddington 	int ret;
43943aef2dSBenjamin Coddington 
44943aef2dSBenjamin Coddington 	nfs_kset = kzalloc(sizeof(*nfs_kset), GFP_KERNEL);
458b18a2edSBenjamin Coddington 	if (!nfs_kset)
46996bc4f4STrond Myklebust 		return -ENOMEM;
47943aef2dSBenjamin Coddington 
48943aef2dSBenjamin Coddington 	ret = kobject_set_name(&nfs_kset->kobj, "nfs");
49943aef2dSBenjamin Coddington 	if (ret) {
50943aef2dSBenjamin Coddington 		kfree(nfs_kset);
51943aef2dSBenjamin Coddington 		return ret;
52943aef2dSBenjamin Coddington 	}
53943aef2dSBenjamin Coddington 
54943aef2dSBenjamin Coddington 	nfs_kset->kobj.parent = fs_kobj;
55943aef2dSBenjamin Coddington 	nfs_kset->kobj.ktype = &nfs_kset_type;
56943aef2dSBenjamin Coddington 	nfs_kset->kobj.kset = NULL;
57943aef2dSBenjamin Coddington 
58943aef2dSBenjamin Coddington 	ret = kset_register(nfs_kset);
59943aef2dSBenjamin Coddington 	if (ret) {
60943aef2dSBenjamin Coddington 		kfree(nfs_kset);
61943aef2dSBenjamin Coddington 		return ret;
62943aef2dSBenjamin Coddington 	}
63943aef2dSBenjamin Coddington 
64996bc4f4STrond Myklebust 	return 0;
65996bc4f4STrond Myklebust }
66996bc4f4STrond Myklebust 
67996bc4f4STrond Myklebust void nfs_sysfs_exit(void)
68996bc4f4STrond Myklebust {
698b18a2edSBenjamin Coddington 	kset_unregister(nfs_kset);
70996bc4f4STrond Myklebust }
71bf11fbdbSTrond Myklebust 
72bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
73bf11fbdbSTrond Myklebust 		struct kobj_attribute *attr, char *buf)
74bf11fbdbSTrond Myklebust {
75bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
76bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
77bf11fbdbSTrond Myklebust 			kobject);
78094eca37STrond Myklebust 	ssize_t ret;
79094eca37STrond Myklebust 
80094eca37STrond Myklebust 	rcu_read_lock();
8119cdc8faSye xingchen 	ret = sysfs_emit(buf, "%s\n", rcu_dereference(c->identifier));
82094eca37STrond Myklebust 	rcu_read_unlock();
83094eca37STrond Myklebust 	return ret;
84bf11fbdbSTrond Myklebust }
85bf11fbdbSTrond Myklebust 
86bf11fbdbSTrond Myklebust /* Strip trailing '\n' */
87bf11fbdbSTrond Myklebust static size_t nfs_string_strip(const char *c, size_t len)
88bf11fbdbSTrond Myklebust {
89bf11fbdbSTrond Myklebust 	while (len > 0 && c[len-1] == '\n')
90bf11fbdbSTrond Myklebust 		--len;
91bf11fbdbSTrond Myklebust 	return len;
92bf11fbdbSTrond Myklebust }
93bf11fbdbSTrond Myklebust 
94bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
95bf11fbdbSTrond Myklebust 		struct kobj_attribute *attr,
96bf11fbdbSTrond Myklebust 		const char *buf, size_t count)
97bf11fbdbSTrond Myklebust {
98bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
99bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
100bf11fbdbSTrond Myklebust 			kobject);
101bf11fbdbSTrond Myklebust 	const char *old;
102bf11fbdbSTrond Myklebust 	char *p;
103bf11fbdbSTrond Myklebust 	size_t len;
104bf11fbdbSTrond Myklebust 
105bf11fbdbSTrond Myklebust 	len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
106bf11fbdbSTrond Myklebust 	if (!len)
107bf11fbdbSTrond Myklebust 		return 0;
108bf11fbdbSTrond Myklebust 	p = kmemdup_nul(buf, len, GFP_KERNEL);
109bf11fbdbSTrond Myklebust 	if (!p)
110bf11fbdbSTrond Myklebust 		return -ENOMEM;
111094eca37STrond Myklebust 	old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1);
112bf11fbdbSTrond Myklebust 	if (old) {
113bf11fbdbSTrond Myklebust 		synchronize_rcu();
114bf11fbdbSTrond Myklebust 		kfree(old);
115bf11fbdbSTrond Myklebust 	}
116bf11fbdbSTrond Myklebust 	return count;
117bf11fbdbSTrond Myklebust }
118bf11fbdbSTrond Myklebust 
119bf11fbdbSTrond Myklebust static void nfs_netns_client_release(struct kobject *kobj)
120bf11fbdbSTrond Myklebust {
121bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
122bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
123bf11fbdbSTrond Myklebust 			kobject);
124bf11fbdbSTrond Myklebust 
125094eca37STrond Myklebust 	kfree(rcu_dereference_raw(c->identifier));
126bf11fbdbSTrond Myklebust }
127bf11fbdbSTrond Myklebust 
12802a476d9SGreg Kroah-Hartman static const void *nfs_netns_client_namespace(const struct kobject *kobj)
129bf11fbdbSTrond Myklebust {
130bf11fbdbSTrond Myklebust 	return container_of(kobj, struct nfs_netns_client, kobject)->net;
131bf11fbdbSTrond Myklebust }
132bf11fbdbSTrond Myklebust 
133bf11fbdbSTrond Myklebust static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
134bf11fbdbSTrond Myklebust 		0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
135bf11fbdbSTrond Myklebust 
136bf11fbdbSTrond Myklebust static struct attribute *nfs_netns_client_attrs[] = {
137bf11fbdbSTrond Myklebust 	&nfs_netns_client_id.attr,
138bf11fbdbSTrond Myklebust 	NULL,
139bf11fbdbSTrond Myklebust };
14001f34245SGreg Kroah-Hartman ATTRIBUTE_GROUPS(nfs_netns_client);
141bf11fbdbSTrond Myklebust 
142bf11fbdbSTrond Myklebust static struct kobj_type nfs_netns_client_type = {
143bf11fbdbSTrond Myklebust 	.release = nfs_netns_client_release,
14401f34245SGreg Kroah-Hartman 	.default_groups = nfs_netns_client_groups,
145bf11fbdbSTrond Myklebust 	.sysfs_ops = &kobj_sysfs_ops,
146bf11fbdbSTrond Myklebust 	.namespace = nfs_netns_client_namespace,
147bf11fbdbSTrond Myklebust };
148bf11fbdbSTrond Myklebust 
149*e96f9268SBenjamin Coddington static void nfs_netns_object_release(struct kobject *kobj)
150*e96f9268SBenjamin Coddington {
151*e96f9268SBenjamin Coddington 	struct nfs_netns_client *c = container_of(kobj,
152*e96f9268SBenjamin Coddington 			struct nfs_netns_client,
153*e96f9268SBenjamin Coddington 			nfs_net_kobj);
154*e96f9268SBenjamin Coddington 	kfree(c);
155*e96f9268SBenjamin Coddington }
156*e96f9268SBenjamin Coddington 
157*e96f9268SBenjamin Coddington static const void *nfs_netns_namespace(const struct kobject *kobj)
158*e96f9268SBenjamin Coddington {
159*e96f9268SBenjamin Coddington 	return container_of(kobj, struct nfs_netns_client, nfs_net_kobj)->net;
160*e96f9268SBenjamin Coddington }
161*e96f9268SBenjamin Coddington 
162*e96f9268SBenjamin Coddington static struct kobj_type nfs_netns_object_type = {
163*e96f9268SBenjamin Coddington 	.release = nfs_netns_object_release,
164*e96f9268SBenjamin Coddington 	.sysfs_ops = &kobj_sysfs_ops,
165*e96f9268SBenjamin Coddington 	.namespace =  nfs_netns_namespace,
166*e96f9268SBenjamin Coddington };
167*e96f9268SBenjamin Coddington 
168bf11fbdbSTrond Myklebust static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
169bf11fbdbSTrond Myklebust 		struct net *net)
170bf11fbdbSTrond Myklebust {
171bf11fbdbSTrond Myklebust 	struct nfs_netns_client *p;
172bf11fbdbSTrond Myklebust 
173bf11fbdbSTrond Myklebust 	p = kzalloc(sizeof(*p), GFP_KERNEL);
174bf11fbdbSTrond Myklebust 	if (p) {
175bf11fbdbSTrond Myklebust 		p->net = net;
1768b18a2edSBenjamin Coddington 		p->kobject.kset = nfs_kset;
177*e96f9268SBenjamin Coddington 		p->nfs_net_kobj.kset = nfs_kset;
178*e96f9268SBenjamin Coddington 
179*e96f9268SBenjamin Coddington 		if (kobject_init_and_add(&p->nfs_net_kobj, &nfs_netns_object_type,
180*e96f9268SBenjamin Coddington 					parent, "net") != 0) {
181*e96f9268SBenjamin Coddington 			kobject_put(&p->nfs_net_kobj);
182*e96f9268SBenjamin Coddington 			return NULL;
183*e96f9268SBenjamin Coddington 		}
184*e96f9268SBenjamin Coddington 
185bf11fbdbSTrond Myklebust 		if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
186*e96f9268SBenjamin Coddington 					&p->nfs_net_kobj, "nfs_client") == 0)
187bf11fbdbSTrond Myklebust 			return p;
188*e96f9268SBenjamin Coddington 
189bf11fbdbSTrond Myklebust 		kobject_put(&p->kobject);
190bf11fbdbSTrond Myklebust 	}
191bf11fbdbSTrond Myklebust 	return NULL;
192bf11fbdbSTrond Myklebust }
193bf11fbdbSTrond Myklebust 
194bf11fbdbSTrond Myklebust void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
195bf11fbdbSTrond Myklebust {
196bf11fbdbSTrond Myklebust 	struct nfs_netns_client *clp;
197bf11fbdbSTrond Myklebust 
198*e96f9268SBenjamin Coddington 	clp = nfs_netns_client_alloc(&nfs_kset->kobj, net);
199bf11fbdbSTrond Myklebust 	if (clp) {
200bf11fbdbSTrond Myklebust 		netns->nfs_client = clp;
201bf11fbdbSTrond Myklebust 		kobject_uevent(&clp->kobject, KOBJ_ADD);
202bf11fbdbSTrond Myklebust 	}
203bf11fbdbSTrond Myklebust }
204bf11fbdbSTrond Myklebust 
205bf11fbdbSTrond Myklebust void nfs_netns_sysfs_destroy(struct nfs_net *netns)
206bf11fbdbSTrond Myklebust {
207bf11fbdbSTrond Myklebust 	struct nfs_netns_client *clp = netns->nfs_client;
208bf11fbdbSTrond Myklebust 
209bf11fbdbSTrond Myklebust 	if (clp) {
210bf11fbdbSTrond Myklebust 		kobject_uevent(&clp->kobject, KOBJ_REMOVE);
211bf11fbdbSTrond Myklebust 		kobject_del(&clp->kobject);
212bf11fbdbSTrond Myklebust 		kobject_put(&clp->kobject);
213*e96f9268SBenjamin Coddington 		kobject_del(&clp->nfs_net_kobj);
214*e96f9268SBenjamin Coddington 		kobject_put(&clp->nfs_net_kobj);
215bf11fbdbSTrond Myklebust 		netns->nfs_client = NULL;
216bf11fbdbSTrond Myklebust 	}
217bf11fbdbSTrond Myklebust }
218