xref: /openbmc/linux/fs/nfs/sysfs.c (revision d9615d16)
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>
15*d9615d16SBenjamin Coddington #include <linux/lockd/lockd.h>
16996bc4f4STrond Myklebust 
17bf11fbdbSTrond Myklebust #include "nfs4_fs.h"
18bf11fbdbSTrond Myklebust #include "netns.h"
19996bc4f4STrond Myklebust #include "sysfs.h"
20996bc4f4STrond Myklebust 
218b18a2edSBenjamin Coddington static struct kset *nfs_kset;
22996bc4f4STrond Myklebust 
23943aef2dSBenjamin Coddington static void nfs_kset_release(struct kobject *kobj)
24943aef2dSBenjamin Coddington {
25943aef2dSBenjamin Coddington 	struct kset *kset = container_of(kobj, struct kset, kobj);
26943aef2dSBenjamin Coddington 	kfree(kset);
27943aef2dSBenjamin Coddington }
28943aef2dSBenjamin Coddington 
29996bc4f4STrond Myklebust static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
3002a476d9SGreg Kroah-Hartman 		const struct kobject *kobj)
31996bc4f4STrond Myklebust {
32996bc4f4STrond Myklebust 	return &net_ns_type_operations;
33996bc4f4STrond Myklebust }
34996bc4f4STrond Myklebust 
35943aef2dSBenjamin Coddington static struct kobj_type nfs_kset_type = {
36943aef2dSBenjamin Coddington 	.release = nfs_kset_release,
37943aef2dSBenjamin Coddington 	.sysfs_ops = &kobj_sysfs_ops,
38996bc4f4STrond Myklebust 	.child_ns_type = nfs_netns_object_child_ns_type,
39996bc4f4STrond Myklebust };
40996bc4f4STrond Myklebust 
41996bc4f4STrond Myklebust int nfs_sysfs_init(void)
42996bc4f4STrond Myklebust {
43943aef2dSBenjamin Coddington 	int ret;
44943aef2dSBenjamin Coddington 
45943aef2dSBenjamin Coddington 	nfs_kset = kzalloc(sizeof(*nfs_kset), GFP_KERNEL);
468b18a2edSBenjamin Coddington 	if (!nfs_kset)
47996bc4f4STrond Myklebust 		return -ENOMEM;
48943aef2dSBenjamin Coddington 
49943aef2dSBenjamin Coddington 	ret = kobject_set_name(&nfs_kset->kobj, "nfs");
50943aef2dSBenjamin Coddington 	if (ret) {
51943aef2dSBenjamin Coddington 		kfree(nfs_kset);
52943aef2dSBenjamin Coddington 		return ret;
53943aef2dSBenjamin Coddington 	}
54943aef2dSBenjamin Coddington 
55943aef2dSBenjamin Coddington 	nfs_kset->kobj.parent = fs_kobj;
56943aef2dSBenjamin Coddington 	nfs_kset->kobj.ktype = &nfs_kset_type;
57943aef2dSBenjamin Coddington 	nfs_kset->kobj.kset = NULL;
58943aef2dSBenjamin Coddington 
59943aef2dSBenjamin Coddington 	ret = kset_register(nfs_kset);
60943aef2dSBenjamin Coddington 	if (ret) {
61943aef2dSBenjamin Coddington 		kfree(nfs_kset);
62943aef2dSBenjamin Coddington 		return ret;
63943aef2dSBenjamin Coddington 	}
64943aef2dSBenjamin Coddington 
65996bc4f4STrond Myklebust 	return 0;
66996bc4f4STrond Myklebust }
67996bc4f4STrond Myklebust 
68996bc4f4STrond Myklebust void nfs_sysfs_exit(void)
69996bc4f4STrond Myklebust {
708b18a2edSBenjamin Coddington 	kset_unregister(nfs_kset);
71996bc4f4STrond Myklebust }
72bf11fbdbSTrond Myklebust 
73bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
74bf11fbdbSTrond Myklebust 		struct kobj_attribute *attr, char *buf)
75bf11fbdbSTrond Myklebust {
76bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
77bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
78bf11fbdbSTrond Myklebust 			kobject);
79094eca37STrond Myklebust 	ssize_t ret;
80094eca37STrond Myklebust 
81094eca37STrond Myklebust 	rcu_read_lock();
8219cdc8faSye xingchen 	ret = sysfs_emit(buf, "%s\n", rcu_dereference(c->identifier));
83094eca37STrond Myklebust 	rcu_read_unlock();
84094eca37STrond Myklebust 	return ret;
85bf11fbdbSTrond Myklebust }
86bf11fbdbSTrond Myklebust 
87bf11fbdbSTrond Myklebust /* Strip trailing '\n' */
88bf11fbdbSTrond Myklebust static size_t nfs_string_strip(const char *c, size_t len)
89bf11fbdbSTrond Myklebust {
90bf11fbdbSTrond Myklebust 	while (len > 0 && c[len-1] == '\n')
91bf11fbdbSTrond Myklebust 		--len;
92bf11fbdbSTrond Myklebust 	return len;
93bf11fbdbSTrond Myklebust }
94bf11fbdbSTrond Myklebust 
95bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
96bf11fbdbSTrond Myklebust 		struct kobj_attribute *attr,
97bf11fbdbSTrond Myklebust 		const char *buf, size_t count)
98bf11fbdbSTrond Myklebust {
99bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
100bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
101bf11fbdbSTrond Myklebust 			kobject);
102bf11fbdbSTrond Myklebust 	const char *old;
103bf11fbdbSTrond Myklebust 	char *p;
104bf11fbdbSTrond Myklebust 	size_t len;
105bf11fbdbSTrond Myklebust 
106bf11fbdbSTrond Myklebust 	len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
107bf11fbdbSTrond Myklebust 	if (!len)
108bf11fbdbSTrond Myklebust 		return 0;
109bf11fbdbSTrond Myklebust 	p = kmemdup_nul(buf, len, GFP_KERNEL);
110bf11fbdbSTrond Myklebust 	if (!p)
111bf11fbdbSTrond Myklebust 		return -ENOMEM;
112094eca37STrond Myklebust 	old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1);
113bf11fbdbSTrond Myklebust 	if (old) {
114bf11fbdbSTrond Myklebust 		synchronize_rcu();
115bf11fbdbSTrond Myklebust 		kfree(old);
116bf11fbdbSTrond Myklebust 	}
117bf11fbdbSTrond Myklebust 	return count;
118bf11fbdbSTrond Myklebust }
119bf11fbdbSTrond Myklebust 
120bf11fbdbSTrond Myklebust static void nfs_netns_client_release(struct kobject *kobj)
121bf11fbdbSTrond Myklebust {
122bf11fbdbSTrond Myklebust 	struct nfs_netns_client *c = container_of(kobj,
123bf11fbdbSTrond Myklebust 			struct nfs_netns_client,
124bf11fbdbSTrond Myklebust 			kobject);
125bf11fbdbSTrond Myklebust 
126094eca37STrond Myklebust 	kfree(rcu_dereference_raw(c->identifier));
127bf11fbdbSTrond Myklebust }
128bf11fbdbSTrond Myklebust 
12902a476d9SGreg Kroah-Hartman static const void *nfs_netns_client_namespace(const struct kobject *kobj)
130bf11fbdbSTrond Myklebust {
131bf11fbdbSTrond Myklebust 	return container_of(kobj, struct nfs_netns_client, kobject)->net;
132bf11fbdbSTrond Myklebust }
133bf11fbdbSTrond Myklebust 
134bf11fbdbSTrond Myklebust static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
135bf11fbdbSTrond Myklebust 		0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
136bf11fbdbSTrond Myklebust 
137bf11fbdbSTrond Myklebust static struct attribute *nfs_netns_client_attrs[] = {
138bf11fbdbSTrond Myklebust 	&nfs_netns_client_id.attr,
139bf11fbdbSTrond Myklebust 	NULL,
140bf11fbdbSTrond Myklebust };
14101f34245SGreg Kroah-Hartman ATTRIBUTE_GROUPS(nfs_netns_client);
142bf11fbdbSTrond Myklebust 
143bf11fbdbSTrond Myklebust static struct kobj_type nfs_netns_client_type = {
144bf11fbdbSTrond Myklebust 	.release = nfs_netns_client_release,
14501f34245SGreg Kroah-Hartman 	.default_groups = nfs_netns_client_groups,
146bf11fbdbSTrond Myklebust 	.sysfs_ops = &kobj_sysfs_ops,
147bf11fbdbSTrond Myklebust 	.namespace = nfs_netns_client_namespace,
148bf11fbdbSTrond Myklebust };
149bf11fbdbSTrond Myklebust 
150e96f9268SBenjamin Coddington static void nfs_netns_object_release(struct kobject *kobj)
151e96f9268SBenjamin Coddington {
152e96f9268SBenjamin Coddington 	struct nfs_netns_client *c = container_of(kobj,
153e96f9268SBenjamin Coddington 			struct nfs_netns_client,
154e96f9268SBenjamin Coddington 			nfs_net_kobj);
155e96f9268SBenjamin Coddington 	kfree(c);
156e96f9268SBenjamin Coddington }
157e96f9268SBenjamin Coddington 
158e96f9268SBenjamin Coddington static const void *nfs_netns_namespace(const struct kobject *kobj)
159e96f9268SBenjamin Coddington {
160e96f9268SBenjamin Coddington 	return container_of(kobj, struct nfs_netns_client, nfs_net_kobj)->net;
161e96f9268SBenjamin Coddington }
162e96f9268SBenjamin Coddington 
163e96f9268SBenjamin Coddington static struct kobj_type nfs_netns_object_type = {
164e96f9268SBenjamin Coddington 	.release = nfs_netns_object_release,
165e96f9268SBenjamin Coddington 	.sysfs_ops = &kobj_sysfs_ops,
166e96f9268SBenjamin Coddington 	.namespace =  nfs_netns_namespace,
167e96f9268SBenjamin Coddington };
168e96f9268SBenjamin Coddington 
169bf11fbdbSTrond Myklebust static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
170bf11fbdbSTrond Myklebust 		struct net *net)
171bf11fbdbSTrond Myklebust {
172bf11fbdbSTrond Myklebust 	struct nfs_netns_client *p;
173bf11fbdbSTrond Myklebust 
174bf11fbdbSTrond Myklebust 	p = kzalloc(sizeof(*p), GFP_KERNEL);
175bf11fbdbSTrond Myklebust 	if (p) {
176bf11fbdbSTrond Myklebust 		p->net = net;
1778b18a2edSBenjamin Coddington 		p->kobject.kset = nfs_kset;
178e96f9268SBenjamin Coddington 		p->nfs_net_kobj.kset = nfs_kset;
179e96f9268SBenjamin Coddington 
180e96f9268SBenjamin Coddington 		if (kobject_init_and_add(&p->nfs_net_kobj, &nfs_netns_object_type,
181e96f9268SBenjamin Coddington 					parent, "net") != 0) {
182e96f9268SBenjamin Coddington 			kobject_put(&p->nfs_net_kobj);
183e96f9268SBenjamin Coddington 			return NULL;
184e96f9268SBenjamin Coddington 		}
185e96f9268SBenjamin Coddington 
186bf11fbdbSTrond Myklebust 		if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
187e96f9268SBenjamin Coddington 					&p->nfs_net_kobj, "nfs_client") == 0)
188bf11fbdbSTrond Myklebust 			return p;
189e96f9268SBenjamin Coddington 
190bf11fbdbSTrond Myklebust 		kobject_put(&p->kobject);
191bf11fbdbSTrond Myklebust 	}
192bf11fbdbSTrond Myklebust 	return NULL;
193bf11fbdbSTrond Myklebust }
194bf11fbdbSTrond Myklebust 
195bf11fbdbSTrond Myklebust void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
196bf11fbdbSTrond Myklebust {
197bf11fbdbSTrond Myklebust 	struct nfs_netns_client *clp;
198bf11fbdbSTrond Myklebust 
199e96f9268SBenjamin Coddington 	clp = nfs_netns_client_alloc(&nfs_kset->kobj, net);
200bf11fbdbSTrond Myklebust 	if (clp) {
201bf11fbdbSTrond Myklebust 		netns->nfs_client = clp;
202bf11fbdbSTrond Myklebust 		kobject_uevent(&clp->kobject, KOBJ_ADD);
203bf11fbdbSTrond Myklebust 	}
204bf11fbdbSTrond Myklebust }
205bf11fbdbSTrond Myklebust 
206bf11fbdbSTrond Myklebust void nfs_netns_sysfs_destroy(struct nfs_net *netns)
207bf11fbdbSTrond Myklebust {
208bf11fbdbSTrond Myklebust 	struct nfs_netns_client *clp = netns->nfs_client;
209bf11fbdbSTrond Myklebust 
210bf11fbdbSTrond Myklebust 	if (clp) {
211bf11fbdbSTrond Myklebust 		kobject_uevent(&clp->kobject, KOBJ_REMOVE);
212bf11fbdbSTrond Myklebust 		kobject_del(&clp->kobject);
213bf11fbdbSTrond Myklebust 		kobject_put(&clp->kobject);
214e96f9268SBenjamin Coddington 		kobject_del(&clp->nfs_net_kobj);
215e96f9268SBenjamin Coddington 		kobject_put(&clp->nfs_net_kobj);
216bf11fbdbSTrond Myklebust 		netns->nfs_client = NULL;
217bf11fbdbSTrond Myklebust 	}
218bf11fbdbSTrond Myklebust }
2191c725118SBenjamin Coddington 
220*d9615d16SBenjamin Coddington static ssize_t
221*d9615d16SBenjamin Coddington shutdown_show(struct kobject *kobj, struct kobj_attribute *attr,
222*d9615d16SBenjamin Coddington 				char *buf)
223*d9615d16SBenjamin Coddington {
224*d9615d16SBenjamin Coddington 	struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
225*d9615d16SBenjamin Coddington 	bool shutdown = server->flags & NFS_MOUNT_SHUTDOWN;
226*d9615d16SBenjamin Coddington 	return sysfs_emit(buf, "%d\n", shutdown);
227*d9615d16SBenjamin Coddington }
228*d9615d16SBenjamin Coddington 
229*d9615d16SBenjamin Coddington static ssize_t
230*d9615d16SBenjamin Coddington shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
231*d9615d16SBenjamin Coddington 				const char *buf, size_t count)
232*d9615d16SBenjamin Coddington {
233*d9615d16SBenjamin Coddington 	struct nfs_server *server;
234*d9615d16SBenjamin Coddington 	int ret, val;
235*d9615d16SBenjamin Coddington 
236*d9615d16SBenjamin Coddington 	server = container_of(kobj, struct nfs_server, kobj);
237*d9615d16SBenjamin Coddington 
238*d9615d16SBenjamin Coddington 	ret = kstrtoint(buf, 0, &val);
239*d9615d16SBenjamin Coddington 	if (ret)
240*d9615d16SBenjamin Coddington 		return ret;
241*d9615d16SBenjamin Coddington 
242*d9615d16SBenjamin Coddington 	if (val != 1)
243*d9615d16SBenjamin Coddington 		return -EINVAL;
244*d9615d16SBenjamin Coddington 
245*d9615d16SBenjamin Coddington 	/* already shut down? */
246*d9615d16SBenjamin Coddington 	if (server->flags & NFS_MOUNT_SHUTDOWN)
247*d9615d16SBenjamin Coddington 		goto out;
248*d9615d16SBenjamin Coddington 
249*d9615d16SBenjamin Coddington 	server->flags |= NFS_MOUNT_SHUTDOWN;
250*d9615d16SBenjamin Coddington 	server->client->cl_shutdown = 1;
251*d9615d16SBenjamin Coddington 	server->nfs_client->cl_rpcclient->cl_shutdown = 1;
252*d9615d16SBenjamin Coddington 
253*d9615d16SBenjamin Coddington 	if (!IS_ERR(server->client_acl))
254*d9615d16SBenjamin Coddington 		server->client_acl->cl_shutdown = 1;
255*d9615d16SBenjamin Coddington 
256*d9615d16SBenjamin Coddington 	if (server->nlm_host)
257*d9615d16SBenjamin Coddington 		server->nlm_host->h_rpcclnt->cl_shutdown = 1;
258*d9615d16SBenjamin Coddington out:
259*d9615d16SBenjamin Coddington 	return count;
260*d9615d16SBenjamin Coddington }
261*d9615d16SBenjamin Coddington 
262*d9615d16SBenjamin Coddington static struct kobj_attribute nfs_sysfs_attr_shutdown = __ATTR_RW(shutdown);
263*d9615d16SBenjamin Coddington 
264e13b5493SBenjamin Coddington #define RPC_CLIENT_NAME_SIZE 64
265e13b5493SBenjamin Coddington 
266e13b5493SBenjamin Coddington void nfs_sysfs_link_rpc_client(struct nfs_server *server,
267e13b5493SBenjamin Coddington 			struct rpc_clnt *clnt, const char *uniq)
268e13b5493SBenjamin Coddington {
269e13b5493SBenjamin Coddington 	char name[RPC_CLIENT_NAME_SIZE];
270e13b5493SBenjamin Coddington 	int ret;
271e13b5493SBenjamin Coddington 
272e13b5493SBenjamin Coddington 	strcpy(name, clnt->cl_program->name);
273e13b5493SBenjamin Coddington 	strcat(name, uniq ? uniq : "");
274e13b5493SBenjamin Coddington 	strcat(name, "_client");
275e13b5493SBenjamin Coddington 
276e13b5493SBenjamin Coddington 	ret = sysfs_create_link_nowarn(&server->kobj,
277e13b5493SBenjamin Coddington 						&clnt->cl_sysfs->kobject, name);
278e13b5493SBenjamin Coddington 	if (ret < 0)
279e13b5493SBenjamin Coddington 		pr_warn("NFS: can't create link to %s in sysfs (%d)\n",
280e13b5493SBenjamin Coddington 			name, ret);
281e13b5493SBenjamin Coddington }
282e13b5493SBenjamin Coddington EXPORT_SYMBOL_GPL(nfs_sysfs_link_rpc_client);
283e13b5493SBenjamin Coddington 
2841c725118SBenjamin Coddington static void nfs_sysfs_sb_release(struct kobject *kobj)
2851c725118SBenjamin Coddington {
2861c725118SBenjamin Coddington 	/* no-op: why? see lib/kobject.c kobject_cleanup() */
2871c725118SBenjamin Coddington }
2881c725118SBenjamin Coddington 
2891c725118SBenjamin Coddington static const void *nfs_netns_server_namespace(const struct kobject *kobj)
2901c725118SBenjamin Coddington {
2911c725118SBenjamin Coddington 	return container_of(kobj, struct nfs_server, kobj)->nfs_client->cl_net;
2921c725118SBenjamin Coddington }
2931c725118SBenjamin Coddington 
2941c725118SBenjamin Coddington static struct kobj_type nfs_sb_ktype = {
2951c725118SBenjamin Coddington 	.release = nfs_sysfs_sb_release,
2961c725118SBenjamin Coddington 	.sysfs_ops = &kobj_sysfs_ops,
2971c725118SBenjamin Coddington 	.namespace = nfs_netns_server_namespace,
2981c725118SBenjamin Coddington 	.child_ns_type = nfs_netns_object_child_ns_type,
2991c725118SBenjamin Coddington };
3001c725118SBenjamin Coddington 
3011c725118SBenjamin Coddington void nfs_sysfs_add_server(struct nfs_server *server)
3021c725118SBenjamin Coddington {
3031c725118SBenjamin Coddington 	int ret;
3041c725118SBenjamin Coddington 
3051c725118SBenjamin Coddington 	ret = kobject_init_and_add(&server->kobj, &nfs_sb_ktype,
3061c725118SBenjamin Coddington 				&nfs_kset->kobj, "server-%d", server->s_sysfs_id);
307*d9615d16SBenjamin Coddington 	if (ret < 0) {
3081c725118SBenjamin Coddington 		pr_warn("NFS: nfs sysfs add server-%d failed (%d)\n",
3091c725118SBenjamin Coddington 					server->s_sysfs_id, ret);
310*d9615d16SBenjamin Coddington 		return;
311*d9615d16SBenjamin Coddington 	}
312*d9615d16SBenjamin Coddington 	ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_shutdown.attr,
313*d9615d16SBenjamin Coddington 				nfs_netns_server_namespace(&server->kobj));
314*d9615d16SBenjamin Coddington 	if (ret < 0)
315*d9615d16SBenjamin Coddington 		pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
316*d9615d16SBenjamin Coddington 			server->s_sysfs_id, ret);
3171c725118SBenjamin Coddington }
3181c725118SBenjamin Coddington EXPORT_SYMBOL_GPL(nfs_sysfs_add_server);
3191c725118SBenjamin Coddington 
3201c725118SBenjamin Coddington void nfs_sysfs_move_server_to_sb(struct super_block *s)
3211c725118SBenjamin Coddington {
3221c725118SBenjamin Coddington 	struct nfs_server *server = s->s_fs_info;
3231c725118SBenjamin Coddington 	int ret;
3241c725118SBenjamin Coddington 
3251c725118SBenjamin Coddington 	ret = kobject_rename(&server->kobj, s->s_id);
3261c725118SBenjamin Coddington 	if (ret < 0)
3271c725118SBenjamin Coddington 		pr_warn("NFS: rename sysfs %s failed (%d)\n",
3281c725118SBenjamin Coddington 					server->kobj.name, ret);
3291c725118SBenjamin Coddington }
3301c725118SBenjamin Coddington 
3311c725118SBenjamin Coddington void nfs_sysfs_move_sb_to_server(struct nfs_server *server)
3321c725118SBenjamin Coddington {
3331c725118SBenjamin Coddington 	const char *s;
3341c725118SBenjamin Coddington 	int ret = -ENOMEM;
3351c725118SBenjamin Coddington 
3361c725118SBenjamin Coddington 	s = kasprintf(GFP_KERNEL, "server-%d", server->s_sysfs_id);
3371c725118SBenjamin Coddington 	if (s)
3381c725118SBenjamin Coddington 		ret = kobject_rename(&server->kobj, s);
3391c725118SBenjamin Coddington 	if (ret < 0)
3401c725118SBenjamin Coddington 		pr_warn("NFS: rename sysfs %s failed (%d)\n",
3411c725118SBenjamin Coddington 					server->kobj.name, ret);
3421c725118SBenjamin Coddington }
3431c725118SBenjamin Coddington 
3441c725118SBenjamin Coddington /* unlink, not dec-ref */
3451c725118SBenjamin Coddington void nfs_sysfs_remove_server(struct nfs_server *server)
3461c725118SBenjamin Coddington {
3471c725118SBenjamin Coddington 	kobject_del(&server->kobj);
3481c725118SBenjamin Coddington }
349