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/lockd.h>
17
18 #include "internal.h"
19 #include "nfs4_fs.h"
20 #include "netns.h"
21 #include "sysfs.h"
22
23 static struct kset *nfs_kset;
24
nfs_kset_release(struct kobject * kobj)25 static void nfs_kset_release(struct kobject *kobj)
26 {
27 struct kset *kset = container_of(kobj, struct kset, kobj);
28 kfree(kset);
29 }
30
nfs_netns_object_child_ns_type(const struct kobject * kobj)31 static 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
37 static 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
nfs_sysfs_init(void)43 int 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
nfs_sysfs_exit(void)70 void nfs_sysfs_exit(void)
71 {
72 kset_unregister(nfs_kset);
73 }
74
nfs_netns_identifier_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)75 static 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' */
nfs_string_strip(const char * c,size_t len)90 static 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
nfs_netns_identifier_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)97 static 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
nfs_netns_client_release(struct kobject * kobj)122 static 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
nfs_netns_client_namespace(const struct kobject * kobj)131 static 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
137 static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
138 0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
139
140 static struct attribute *nfs_netns_client_attrs[] = {
141 &nfs_netns_client_id.attr,
142 NULL,
143 };
144 ATTRIBUTE_GROUPS(nfs_netns_client);
145
146 static 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
nfs_netns_object_release(struct kobject * kobj)153 static 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
nfs_netns_namespace(const struct kobject * kobj)161 static 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
167 static 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
nfs_netns_client_alloc(struct kobject * parent,struct net * net)173 static 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
nfs_netns_sysfs_setup(struct nfs_net * netns,struct net * net)200 void 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
nfs_netns_sysfs_destroy(struct nfs_net * netns)211 void 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
shutdown_match_client(const struct rpc_task * task,const void * data)225 static bool shutdown_match_client(const struct rpc_task *task, const void *data)
226 {
227 return true;
228 }
229
shutdown_client(struct rpc_clnt * clnt)230 static 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 */
shutdown_nfs_client(struct nfs_client * clp)240 static 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
255 static ssize_t
shutdown_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)256 shutdown_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
264 static ssize_t
shutdown_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)265 shutdown_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 shutdown_client(server->nlm_host->h_rpcclnt);
292 out:
293 shutdown_nfs_client(server->nfs_client);
294 return count;
295 }
296
297 static struct kobj_attribute nfs_sysfs_attr_shutdown = __ATTR_RW(shutdown);
298
299 #if IS_ENABLED(CONFIG_NFS_V4)
300 static ssize_t
implid_domain_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)301 implid_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
312 static struct kobj_attribute nfs_sysfs_attr_implid_domain = __ATTR_RO(implid_domain);
313
314
315 static ssize_t
implid_name_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)316 implid_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
327 static 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
nfs_sysfs_link_rpc_client(struct nfs_server * server,struct rpc_clnt * clnt,const char * uniq)333 void 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 }
349 EXPORT_SYMBOL_GPL(nfs_sysfs_link_rpc_client);
350
nfs_sysfs_sb_release(struct kobject * kobj)351 static void nfs_sysfs_sb_release(struct kobject *kobj)
352 {
353 /* no-op: why? see lib/kobject.c kobject_cleanup() */
354 }
355
nfs_netns_server_namespace(const struct kobject * kobj)356 static 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
362 static 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)
nfs_sysfs_add_nfsv41_server(struct nfs_server * server)370 static 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 */
nfs_sysfs_add_nfsv41_server(struct nfs_server * server)390 static 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
397 static ssize_t
localio_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)398 localio_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
406 static struct kobj_attribute nfs_sysfs_attr_localio = __ATTR_RO(localio);
407
nfs_sysfs_add_nfs_localio_server(struct nfs_server * server)408 static 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
nfs_sysfs_add_nfs_localio_server(struct nfs_server * server)417 static inline void nfs_sysfs_add_nfs_localio_server(struct nfs_server *server)
418 {
419 }
420 #endif /* IS_ENABLED(CONFIG_NFS_LOCALIO) */
421
nfs_sysfs_add_server(struct nfs_server * server)422 void 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 }
442 EXPORT_SYMBOL_GPL(nfs_sysfs_add_server);
443
nfs_sysfs_move_server_to_sb(struct super_block * s)444 void 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
nfs_sysfs_move_sb_to_server(struct nfs_server * server)455 void 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 */
nfs_sysfs_remove_server(struct nfs_server * server)471 void nfs_sysfs_remove_server(struct nfs_server *server)
472 {
473 kobject_del(&server->kobj);
474 }
475