projects/linux·blob master · refs

474 lines · 11.4 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019 Hammerspace Inc
4 */
5
6#include <linux/module.h>
7#include <linux/kobject.h>
8#include <linux/sysfs.h>
9#include <linux/fs.h>
10#include <linux/slab.h>
11#include <linux/netdevice.h>
12#include <linux/string.h>
13#include <linux/nfs_fs.h>
14#include <net/net_namespace.h>
15#include <linux/rcupdate.h>
16#include <linux/lockd/bind.h>
17
18#include "internal.h"
19#include "nfs4_fs.h"
20#include "netns.h"
21#include "sysfs.h"
22
23static struct kset *nfs_kset;
24
25static void nfs_kset_release(struct kobject *kobj)
26{
27 struct kset *kset = container_of(kobj, struct kset, kobj);
28 kfree(kset);
29}
30
31static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
32 const struct kobject *kobj)
33{
34 return &net_ns_type_operations;
35}
36
37static struct kobj_type nfs_kset_type = {
38 .release = nfs_kset_release,
39 .sysfs_ops = &kobj_sysfs_ops,
40 .child_ns_type = nfs_netns_object_child_ns_type,
41};
42
43int nfs_sysfs_init(void)
44{
45 int ret;
46
47 nfs_kset = kzalloc_obj(*nfs_kset);
48 if (!nfs_kset)
49 return -ENOMEM;
50
51 ret = kobject_set_name(&nfs_kset->kobj, "nfs");
52 if (ret) {
53 kfree(nfs_kset);
54 return ret;
55 }
56
57 nfs_kset->kobj.parent = fs_kobj;
58 nfs_kset->kobj.ktype = &nfs_kset_type;
59 nfs_kset->kobj.kset = NULL;
60
61 ret = kset_register(nfs_kset);
62 if (ret) {
63 kfree(nfs_kset);
64 return ret;
65 }
66
67 return 0;
68}
69
70void nfs_sysfs_exit(void)
71{
72 kset_unregister(nfs_kset);
73}
74
75static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
76 struct kobj_attribute *attr, char *buf)
77{
78 struct nfs_netns_client *c = container_of(kobj,
79 struct nfs_netns_client,
80 kobject);
81 ssize_t ret;
82
83 rcu_read_lock();
84 ret = sysfs_emit(buf, "%s\n", rcu_dereference(c->identifier));
85 rcu_read_unlock();
86 return ret;
87}
88
89/* Strip trailing '\n' */
90static size_t nfs_string_strip(const char *c, size_t len)
91{
92 while (len > 0 && c[len-1] == '\n')
93 --len;
94 return len;
95}
96
97static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
98 struct kobj_attribute *attr,
99 const char *buf, size_t count)
100{
101 struct nfs_netns_client *c = container_of(kobj,
102 struct nfs_netns_client,
103 kobject);
104 const char *old;
105 char *p;
106 size_t len;
107
108 len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
109 if (!len)
110 return 0;
111 p = kmemdup_nul(buf, len, GFP_KERNEL);
112 if (!p)
113 return -ENOMEM;
114 old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1);
115 if (old) {
116 synchronize_rcu();
117 kfree(old);
118 }
119 return count;
120}
121
122static void nfs_netns_client_release(struct kobject *kobj)
123{
124 struct nfs_netns_client *c = container_of(kobj,
125 struct nfs_netns_client,
126 kobject);
127
128 kfree(rcu_dereference_raw(c->identifier));
129}
130
131static const struct ns_common *nfs_netns_client_namespace(const struct kobject *kobj)
132{
133 return to_ns_common(container_of(kobj, struct nfs_netns_client,
134 kobject)->net);
135}
136
137static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
138 0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
139
140static struct attribute *nfs_netns_client_attrs[] = {
141 &nfs_netns_client_id.attr,
142 NULL,
143};
144ATTRIBUTE_GROUPS(nfs_netns_client);
145
146static struct kobj_type nfs_netns_client_type = {
147 .release = nfs_netns_client_release,
148 .default_groups = nfs_netns_client_groups,
149 .sysfs_ops = &kobj_sysfs_ops,
150 .namespace = nfs_netns_client_namespace,
151};
152
153static void nfs_netns_object_release(struct kobject *kobj)
154{
155 struct nfs_netns_client *c = container_of(kobj,
156 struct nfs_netns_client,
157 nfs_net_kobj);
158 kfree(c);
159}
160
161static const struct ns_common *nfs_netns_namespace(const struct kobject *kobj)
162{
163 return to_ns_common(container_of(kobj, struct nfs_netns_client,
164 nfs_net_kobj)->net);
165}
166
167static struct kobj_type nfs_netns_object_type = {
168 .release = nfs_netns_object_release,
169 .sysfs_ops = &kobj_sysfs_ops,
170 .namespace = nfs_netns_namespace,
171};
172
173static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
174 struct net *net)
175{
176 struct nfs_netns_client *p;
177
178 p = kzalloc_obj(*p);
179 if (p) {
180 p->net = net;
181 p->kobject.kset = nfs_kset;
182 p->nfs_net_kobj.kset = nfs_kset;
183
184 if (kobject_init_and_add(&p->nfs_net_kobj, &nfs_netns_object_type,
185 parent, "net") != 0) {
186 kobject_put(&p->nfs_net_kobj);
187 return NULL;
188 }
189
190 if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
191 &p->nfs_net_kobj, "nfs_client") == 0)
192 return p;
193
194 kobject_put(&p->kobject);
195 kobject_put(&p->nfs_net_kobj);
196 }
197 return NULL;
198}
199
200void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
201{
202 struct nfs_netns_client *clp;
203
204 clp = nfs_netns_client_alloc(&nfs_kset->kobj, net);
205 if (clp) {
206 netns->nfs_client = clp;
207 kobject_uevent(&clp->kobject, KOBJ_ADD);
208 }
209}
210
211void nfs_netns_sysfs_destroy(struct nfs_net *netns)
212{
213 struct nfs_netns_client *clp = netns->nfs_client;
214
215 if (clp) {
216 kobject_uevent(&clp->kobject, KOBJ_REMOVE);
217 kobject_del(&clp->kobject);
218 kobject_put(&clp->kobject);
219 kobject_del(&clp->nfs_net_kobj);
220 kobject_put(&clp->nfs_net_kobj);
221 netns->nfs_client = NULL;
222 }
223}
224
225static bool shutdown_match_client(const struct rpc_task *task, const void *data)
226{
227 return true;
228}
229
230static void shutdown_client(struct rpc_clnt *clnt)
231{
232 clnt->cl_shutdown = 1;
233 rpc_cancel_tasks(clnt, -EIO, shutdown_match_client, NULL);
234}
235
236/*
237 * Shut down the nfs_client only once all the superblocks
238 * have been shut down.
239 */
240static void shutdown_nfs_client(struct nfs_client *clp)
241{
242 struct nfs_server *server;
243 rcu_read_lock();
244 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
245 if (!(server->flags & NFS_MOUNT_SHUTDOWN)) {
246 rcu_read_unlock();
247 return;
248 }
249 }
250 rcu_read_unlock();
251 nfs_mark_client_ready(clp, -EIO);
252 shutdown_client(clp->cl_rpcclient);
253}
254
255static ssize_t
256shutdown_show(struct kobject *kobj, struct kobj_attribute *attr,
257 char *buf)
258{
259 struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
260 bool shutdown = server->flags & NFS_MOUNT_SHUTDOWN;
261 return sysfs_emit(buf, "%d\n", shutdown);
262}
263
264static ssize_t
265shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
266 const char *buf, size_t count)
267{
268 struct nfs_server *server;
269 int ret, val;
270
271 server = container_of(kobj, struct nfs_server, kobj);
272
273 ret = kstrtoint(buf, 0, &val);
274 if (ret)
275 return ret;
276
277 if (val != 1)
278 return -EINVAL;
279
280 /* already shut down? */
281 if (server->flags & NFS_MOUNT_SHUTDOWN)
282 goto out;
283
284 server->flags |= NFS_MOUNT_SHUTDOWN;
285 shutdown_client(server->client);
286
287 if (!IS_ERR(server->client_acl))
288 shutdown_client(server->client_acl);
289
290 if (server->nlm_host)
291 nlmclnt_shutdown_rpc_clnt(server->nlm_host);
292out:
293 shutdown_nfs_client(server->nfs_client);
294 return count;
295}
296
297static struct kobj_attribute nfs_sysfs_attr_shutdown = __ATTR_RW(shutdown);
298
299#if IS_ENABLED(CONFIG_NFS_V4)
300static ssize_t
301implid_domain_show(struct kobject *kobj, struct kobj_attribute *attr,
302 char *buf)
303{
304 struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
305 struct nfs41_impl_id *impl_id = server->nfs_client->cl_implid;
306
307 if (!impl_id || strlen(impl_id->domain) == 0)
308 return 0; //sysfs_emit(buf, "");
309 return sysfs_emit(buf, "%s\n", impl_id->domain);
310}
311
312static struct kobj_attribute nfs_sysfs_attr_implid_domain = __ATTR_RO(implid_domain);
313
314
315static ssize_t
316implid_name_show(struct kobject *kobj, struct kobj_attribute *attr,
317 char *buf)
318{
319 struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
320 struct nfs41_impl_id *impl_id = server->nfs_client->cl_implid;
321
322 if (!impl_id || strlen(impl_id->name) == 0)
323 return 0; //sysfs_emit(buf, "");
324 return sysfs_emit(buf, "%s\n", impl_id->name);
325}
326
327static struct kobj_attribute nfs_sysfs_attr_implid_name = __ATTR_RO(implid_name);
328
329#endif /* IS_ENABLED(CONFIG_NFS_V4) */
330
331#define RPC_CLIENT_NAME_SIZE 64
332
333void nfs_sysfs_link_rpc_client(struct nfs_server *server,
334 struct rpc_clnt *clnt, const char *uniq)
335{
336 char name[RPC_CLIENT_NAME_SIZE];
337 int ret;
338
339 strscpy(name, clnt->cl_program->name, sizeof(name));
340 strncat(name, uniq ? uniq : "", sizeof(name) - strlen(name) - 1);
341 strncat(name, "_client", sizeof(name) - strlen(name) - 1);
342
343 ret = sysfs_create_link_nowarn(&server->kobj,
344 &clnt->cl_sysfs->kobject, name);
345 if (ret < 0)
346 pr_warn("NFS: can't create link to %s in sysfs (%d)\n",
347 name, ret);
348}
349EXPORT_SYMBOL_GPL(nfs_sysfs_link_rpc_client);
350
351static void nfs_sysfs_sb_release(struct kobject *kobj)
352{
353 /* no-op: why? see lib/kobject.c kobject_cleanup() */
354}
355
356static const struct ns_common *nfs_netns_server_namespace(const struct kobject *kobj)
357{
358 return to_ns_common(container_of(kobj, struct nfs_server,
359 kobj)->nfs_client->cl_net);
360}
361
362static struct kobj_type nfs_sb_ktype = {
363 .release = nfs_sysfs_sb_release,
364 .sysfs_ops = &kobj_sysfs_ops,
365 .namespace = nfs_netns_server_namespace,
366 .child_ns_type = nfs_netns_object_child_ns_type,
367};
368
369#if IS_ENABLED(CONFIG_NFS_V4)
370static void nfs_sysfs_add_nfsv41_server(struct nfs_server *server)
371{
372 int ret;
373
374 if (!server->nfs_client->cl_implid)
375 return;
376
377 ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_implid_domain.attr,
378 nfs_netns_server_namespace(&server->kobj));
379 if (ret < 0)
380 pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
381 server->s_sysfs_id, ret);
382
383 ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_implid_name.attr,
384 nfs_netns_server_namespace(&server->kobj));
385 if (ret < 0)
386 pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
387 server->s_sysfs_id, ret);
388}
389#else /* CONFIG_NFS_V4 */
390static inline void nfs_sysfs_add_nfsv41_server(struct nfs_server *server)
391{
392}
393#endif /* CONFIG_NFS_V4 */
394
395#if IS_ENABLED(CONFIG_NFS_LOCALIO)
396
397static ssize_t
398localio_show(struct kobject *kobj, struct kobj_attribute *attr,
399 char *buf)
400{
401 struct nfs_server *server = container_of(kobj, struct nfs_server, kobj);
402 bool localio = nfs_server_is_local(server->nfs_client);
403 return sysfs_emit(buf, "%d\n", localio);
404}
405
406static struct kobj_attribute nfs_sysfs_attr_localio = __ATTR_RO(localio);
407
408static void nfs_sysfs_add_nfs_localio_server(struct nfs_server *server)
409{
410 int ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_localio.attr,
411 nfs_netns_server_namespace(&server->kobj));
412 if (ret < 0)
413 pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
414 server->s_sysfs_id, ret);
415}
416#else
417static inline void nfs_sysfs_add_nfs_localio_server(struct nfs_server *server)
418{
419}
420#endif /* IS_ENABLED(CONFIG_NFS_LOCALIO) */
421
422void nfs_sysfs_add_server(struct nfs_server *server)
423{
424 int ret;
425
426 ret = kobject_init_and_add(&server->kobj, &nfs_sb_ktype,
427 &nfs_kset->kobj, "server-%d", server->s_sysfs_id);
428 if (ret < 0) {
429 pr_warn("NFS: nfs sysfs add server-%d failed (%d)\n",
430 server->s_sysfs_id, ret);
431 return;
432 }
433 ret = sysfs_create_file_ns(&server->kobj, &nfs_sysfs_attr_shutdown.attr,
434 nfs_netns_server_namespace(&server->kobj));
435 if (ret < 0)
436 pr_warn("NFS: sysfs_create_file_ns for server-%d failed (%d)\n",
437 server->s_sysfs_id, ret);
438
439 nfs_sysfs_add_nfsv41_server(server);
440 nfs_sysfs_add_nfs_localio_server(server);
441}
442EXPORT_SYMBOL_GPL(nfs_sysfs_add_server);
443
444void nfs_sysfs_move_server_to_sb(struct super_block *s)
445{
446 struct nfs_server *server = s->s_fs_info;
447 int ret;
448
449 ret = kobject_rename(&server->kobj, s->s_id);
450 if (ret < 0)
451 pr_warn("NFS: rename sysfs %s failed (%d)\n",
452 server->kobj.name, ret);
453}
454
455void nfs_sysfs_move_sb_to_server(struct nfs_server *server)
456{
457 const char *s;
458 int ret = -ENOMEM;
459
460 s = kasprintf(GFP_KERNEL, "server-%d", server->s_sysfs_id);
461 if (s) {
462 ret = kobject_rename(&server->kobj, s);
463 kfree(s);
464 }
465 if (ret < 0)
466 pr_warn("NFS: rename sysfs %s failed (%d)\n",
467 server->kobj.name, ret);
468}
469
470/* unlink, not dec-ref */
471void nfs_sysfs_remove_server(struct nfs_server *server)
472{
473 kobject_del(&server->kobj);
474}