xref: /openbmc/linux/fs/nfs/sysfs.c (revision bf11fbdb20b385157b046ea7781f04d0c62554a3)
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>
12*bf11fbdbSTrond Myklebust #include <linux/string.h>
13*bf11fbdbSTrond Myklebust #include <linux/nfs_fs.h>
14*bf11fbdbSTrond Myklebust #include <linux/rcupdate.h>
15996bc4f4STrond Myklebust 
16*bf11fbdbSTrond Myklebust #include "nfs4_fs.h"
17*bf11fbdbSTrond Myklebust #include "netns.h"
18996bc4f4STrond Myklebust #include "sysfs.h"
19996bc4f4STrond Myklebust 
20996bc4f4STrond Myklebust struct kobject *nfs_client_kobj;
21996bc4f4STrond Myklebust static struct kset *nfs_client_kset;
22996bc4f4STrond Myklebust 
23996bc4f4STrond Myklebust static void nfs_netns_object_release(struct kobject *kobj)
24996bc4f4STrond Myklebust {
25996bc4f4STrond Myklebust 	kfree(kobj);
26996bc4f4STrond Myklebust }
27996bc4f4STrond Myklebust 
28996bc4f4STrond Myklebust static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
29996bc4f4STrond Myklebust 		struct kobject *kobj)
30996bc4f4STrond Myklebust {
31996bc4f4STrond Myklebust 	return &net_ns_type_operations;
32996bc4f4STrond Myklebust }
33996bc4f4STrond Myklebust 
34996bc4f4STrond Myklebust static struct kobj_type nfs_netns_object_type = {
35996bc4f4STrond Myklebust 	.release = nfs_netns_object_release,
36996bc4f4STrond Myklebust 	.sysfs_ops = &kobj_sysfs_ops,
37996bc4f4STrond Myklebust 	.child_ns_type = nfs_netns_object_child_ns_type,
38996bc4f4STrond Myklebust };
39996bc4f4STrond Myklebust 
40996bc4f4STrond Myklebust static struct kobject *nfs_netns_object_alloc(const char *name,
41996bc4f4STrond Myklebust 		struct kset *kset, struct kobject *parent)
42996bc4f4STrond Myklebust {
43996bc4f4STrond Myklebust 	struct kobject *kobj;
44996bc4f4STrond Myklebust 
45996bc4f4STrond Myklebust 	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
46996bc4f4STrond Myklebust 	if (kobj) {
47996bc4f4STrond Myklebust 		kobj->kset = kset;
48996bc4f4STrond Myklebust 		if (kobject_init_and_add(kobj, &nfs_netns_object_type,
49996bc4f4STrond Myklebust 					parent, "%s", name) == 0)
50996bc4f4STrond Myklebust 			return kobj;
51996bc4f4STrond Myklebust 		kobject_put(kobj);
52996bc4f4STrond Myklebust 	}
53996bc4f4STrond Myklebust 	return NULL;
54996bc4f4STrond Myklebust }
55996bc4f4STrond Myklebust 
56996bc4f4STrond Myklebust int nfs_sysfs_init(void)
57996bc4f4STrond Myklebust {
58996bc4f4STrond Myklebust 	nfs_client_kset = kset_create_and_add("nfs", NULL, fs_kobj);
59996bc4f4STrond Myklebust 	if (!nfs_client_kset)
60996bc4f4STrond Myklebust 		return -ENOMEM;
61996bc4f4STrond Myklebust 	nfs_client_kobj = nfs_netns_object_alloc("net", nfs_client_kset, NULL);
62996bc4f4STrond Myklebust 	if  (!nfs_client_kobj) {
63996bc4f4STrond Myklebust 		kset_unregister(nfs_client_kset);
64996bc4f4STrond Myklebust 		nfs_client_kset = NULL;
65996bc4f4STrond Myklebust 		return -ENOMEM;
66996bc4f4STrond Myklebust 	}
67996bc4f4STrond Myklebust 	return 0;
68996bc4f4STrond Myklebust }
69996bc4f4STrond Myklebust 
70996bc4f4STrond Myklebust void nfs_sysfs_exit(void)
71996bc4f4STrond Myklebust {
72996bc4f4STrond Myklebust 	kobject_put(nfs_client_kobj);
73996bc4f4STrond Myklebust 	kset_unregister(nfs_client_kset);
74996bc4f4STrond Myklebust }
75*bf11fbdbSTrond Myklebust 
76*bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
77*bf11fbdbSTrond Myklebust 		struct kobj_attribute *attr, char *buf)
78*bf11fbdbSTrond Myklebust {
79*bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
80*bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
81*bf11fbdbSTrond Myklebust 			kobject);
82*bf11fbdbSTrond Myklebust 	return scnprintf(buf, PAGE_SIZE, "%s\n", c->identifier);
83*bf11fbdbSTrond Myklebust }
84*bf11fbdbSTrond Myklebust 
85*bf11fbdbSTrond Myklebust /* Strip trailing '\n' */
86*bf11fbdbSTrond Myklebust static size_t nfs_string_strip(const char *c, size_t len)
87*bf11fbdbSTrond Myklebust {
88*bf11fbdbSTrond Myklebust 	while (len > 0 && c[len-1] == '\n')
89*bf11fbdbSTrond Myklebust 		--len;
90*bf11fbdbSTrond Myklebust 	return len;
91*bf11fbdbSTrond Myklebust }
92*bf11fbdbSTrond Myklebust 
93*bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
94*bf11fbdbSTrond Myklebust 		struct kobj_attribute *attr,
95*bf11fbdbSTrond Myklebust 		const char *buf, size_t count)
96*bf11fbdbSTrond Myklebust {
97*bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
98*bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
99*bf11fbdbSTrond Myklebust 			kobject);
100*bf11fbdbSTrond Myklebust 	const char *old;
101*bf11fbdbSTrond Myklebust 	char *p;
102*bf11fbdbSTrond Myklebust 	size_t len;
103*bf11fbdbSTrond Myklebust 
104*bf11fbdbSTrond Myklebust 	len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
105*bf11fbdbSTrond Myklebust 	if (!len)
106*bf11fbdbSTrond Myklebust 		return 0;
107*bf11fbdbSTrond Myklebust 	p = kmemdup_nul(buf, len, GFP_KERNEL);
108*bf11fbdbSTrond Myklebust 	if (!p)
109*bf11fbdbSTrond Myklebust 		return -ENOMEM;
110*bf11fbdbSTrond Myklebust 	old = xchg(&c->identifier, p);
111*bf11fbdbSTrond Myklebust 	if (old) {
112*bf11fbdbSTrond Myklebust 		synchronize_rcu();
113*bf11fbdbSTrond Myklebust 		kfree(old);
114*bf11fbdbSTrond Myklebust 	}
115*bf11fbdbSTrond Myklebust 	return count;
116*bf11fbdbSTrond Myklebust }
117*bf11fbdbSTrond Myklebust 
118*bf11fbdbSTrond Myklebust static void nfs_netns_client_release(struct kobject *kobj)
119*bf11fbdbSTrond Myklebust {
120*bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
121*bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
122*bf11fbdbSTrond Myklebust 			kobject);
123*bf11fbdbSTrond Myklebust 
124*bf11fbdbSTrond Myklebust 	if (c->identifier)
125*bf11fbdbSTrond Myklebust 		kfree(c->identifier);
126*bf11fbdbSTrond Myklebust 	kfree(c);
127*bf11fbdbSTrond Myklebust }
128*bf11fbdbSTrond Myklebust 
129*bf11fbdbSTrond Myklebust static const void *nfs_netns_client_namespace(struct kobject *kobj)
130*bf11fbdbSTrond Myklebust {
131*bf11fbdbSTrond Myklebust 	return container_of(kobj, struct nfs_netns_client, kobject)->net;
132*bf11fbdbSTrond Myklebust }
133*bf11fbdbSTrond Myklebust 
134*bf11fbdbSTrond Myklebust static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
135*bf11fbdbSTrond Myklebust 		0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
136*bf11fbdbSTrond Myklebust 
137*bf11fbdbSTrond Myklebust static struct attribute *nfs_netns_client_attrs[] = {
138*bf11fbdbSTrond Myklebust 	&nfs_netns_client_id.attr,
139*bf11fbdbSTrond Myklebust 	NULL,
140*bf11fbdbSTrond Myklebust };
141*bf11fbdbSTrond Myklebust 
142*bf11fbdbSTrond Myklebust static struct kobj_type nfs_netns_client_type = {
143*bf11fbdbSTrond Myklebust 	.release = nfs_netns_client_release,
144*bf11fbdbSTrond Myklebust 	.default_attrs = nfs_netns_client_attrs,
145*bf11fbdbSTrond Myklebust 	.sysfs_ops = &kobj_sysfs_ops,
146*bf11fbdbSTrond Myklebust 	.namespace = nfs_netns_client_namespace,
147*bf11fbdbSTrond Myklebust };
148*bf11fbdbSTrond Myklebust 
149*bf11fbdbSTrond Myklebust static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
150*bf11fbdbSTrond Myklebust 		struct net *net)
151*bf11fbdbSTrond Myklebust {
152*bf11fbdbSTrond Myklebust 	struct nfs_netns_client *p;
153*bf11fbdbSTrond Myklebust 
154*bf11fbdbSTrond Myklebust 	p = kzalloc(sizeof(*p), GFP_KERNEL);
155*bf11fbdbSTrond Myklebust 	if (p) {
156*bf11fbdbSTrond Myklebust 		p->net = net;
157*bf11fbdbSTrond Myklebust 		p->kobject.kset = nfs_client_kset;
158*bf11fbdbSTrond Myklebust 		if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
159*bf11fbdbSTrond Myklebust 					parent, "nfs_client") == 0)
160*bf11fbdbSTrond Myklebust 			return p;
161*bf11fbdbSTrond Myklebust 		kobject_put(&p->kobject);
162*bf11fbdbSTrond Myklebust 	}
163*bf11fbdbSTrond Myklebust 	return NULL;
164*bf11fbdbSTrond Myklebust }
165*bf11fbdbSTrond Myklebust 
166*bf11fbdbSTrond Myklebust void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
167*bf11fbdbSTrond Myklebust {
168*bf11fbdbSTrond Myklebust 	struct nfs_netns_client *clp;
169*bf11fbdbSTrond Myklebust 
170*bf11fbdbSTrond Myklebust 	clp = nfs_netns_client_alloc(nfs_client_kobj, net);
171*bf11fbdbSTrond Myklebust 	if (clp) {
172*bf11fbdbSTrond Myklebust 		netns->nfs_client = clp;
173*bf11fbdbSTrond Myklebust 		kobject_uevent(&clp->kobject, KOBJ_ADD);
174*bf11fbdbSTrond Myklebust 	}
175*bf11fbdbSTrond Myklebust }
176*bf11fbdbSTrond Myklebust 
177*bf11fbdbSTrond Myklebust void nfs_netns_sysfs_destroy(struct nfs_net *netns)
178*bf11fbdbSTrond Myklebust {
179*bf11fbdbSTrond Myklebust 	struct nfs_netns_client *clp = netns->nfs_client;
180*bf11fbdbSTrond Myklebust 
181*bf11fbdbSTrond Myklebust 	if (clp) {
182*bf11fbdbSTrond Myklebust 		kobject_uevent(&clp->kobject, KOBJ_REMOVE);
183*bf11fbdbSTrond Myklebust 		kobject_del(&clp->kobject);
184*bf11fbdbSTrond Myklebust 		kobject_put(&clp->kobject);
185*bf11fbdbSTrond Myklebust 		netns->nfs_client = NULL;
186*bf11fbdbSTrond Myklebust 	}
187*bf11fbdbSTrond Myklebust }
188