diff options
Diffstat (limited to 'fs/nfs/sysfs.c')
-rw-r--r-- | fs/nfs/sysfs.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c new file mode 100644 index 000000000000..4f3390b20239 --- /dev/null +++ b/fs/nfs/sysfs.c | |||
@@ -0,0 +1,187 @@ | |||
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 <linux/rcupdate.h> | ||
15 | |||
16 | #include "nfs4_fs.h" | ||
17 | #include "netns.h" | ||
18 | #include "sysfs.h" | ||
19 | |||
20 | struct kobject *nfs_client_kobj; | ||
21 | static struct kset *nfs_client_kset; | ||
22 | |||
23 | static void nfs_netns_object_release(struct kobject *kobj) | ||
24 | { | ||
25 | kfree(kobj); | ||
26 | } | ||
27 | |||
28 | static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type( | ||
29 | struct kobject *kobj) | ||
30 | { | ||
31 | return &net_ns_type_operations; | ||
32 | } | ||
33 | |||
34 | static struct kobj_type nfs_netns_object_type = { | ||
35 | .release = nfs_netns_object_release, | ||
36 | .sysfs_ops = &kobj_sysfs_ops, | ||
37 | .child_ns_type = nfs_netns_object_child_ns_type, | ||
38 | }; | ||
39 | |||
40 | static struct kobject *nfs_netns_object_alloc(const char *name, | ||
41 | struct kset *kset, struct kobject *parent) | ||
42 | { | ||
43 | struct kobject *kobj; | ||
44 | |||
45 | kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); | ||
46 | if (kobj) { | ||
47 | kobj->kset = kset; | ||
48 | if (kobject_init_and_add(kobj, &nfs_netns_object_type, | ||
49 | parent, "%s", name) == 0) | ||
50 | return kobj; | ||
51 | kobject_put(kobj); | ||
52 | } | ||
53 | return NULL; | ||
54 | } | ||
55 | |||
56 | int nfs_sysfs_init(void) | ||
57 | { | ||
58 | nfs_client_kset = kset_create_and_add("nfs", NULL, fs_kobj); | ||
59 | if (!nfs_client_kset) | ||
60 | return -ENOMEM; | ||
61 | nfs_client_kobj = nfs_netns_object_alloc("net", nfs_client_kset, NULL); | ||
62 | if (!nfs_client_kobj) { | ||
63 | kset_unregister(nfs_client_kset); | ||
64 | nfs_client_kset = NULL; | ||
65 | return -ENOMEM; | ||
66 | } | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | void nfs_sysfs_exit(void) | ||
71 | { | ||
72 | kobject_put(nfs_client_kobj); | ||
73 | kset_unregister(nfs_client_kset); | ||
74 | } | ||
75 | |||
76 | static ssize_t nfs_netns_identifier_show(struct kobject *kobj, | ||
77 | struct kobj_attribute *attr, char *buf) | ||
78 | { | ||
79 | struct nfs_netns_client *c = container_of(kobj, | ||
80 | struct nfs_netns_client, | ||
81 | kobject); | ||
82 | return scnprintf(buf, PAGE_SIZE, "%s\n", c->identifier); | ||
83 | } | ||
84 | |||
85 | /* Strip trailing '\n' */ | ||
86 | static size_t nfs_string_strip(const char *c, size_t len) | ||
87 | { | ||
88 | while (len > 0 && c[len-1] == '\n') | ||
89 | --len; | ||
90 | return len; | ||
91 | } | ||
92 | |||
93 | static ssize_t nfs_netns_identifier_store(struct kobject *kobj, | ||
94 | struct kobj_attribute *attr, | ||
95 | const char *buf, size_t count) | ||
96 | { | ||
97 | struct nfs_netns_client *c = container_of(kobj, | ||
98 | struct nfs_netns_client, | ||
99 | kobject); | ||
100 | const char *old; | ||
101 | char *p; | ||
102 | size_t len; | ||
103 | |||
104 | len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN)); | ||
105 | if (!len) | ||
106 | return 0; | ||
107 | p = kmemdup_nul(buf, len, GFP_KERNEL); | ||
108 | if (!p) | ||
109 | return -ENOMEM; | ||
110 | old = xchg(&c->identifier, p); | ||
111 | if (old) { | ||
112 | synchronize_rcu(); | ||
113 | kfree(old); | ||
114 | } | ||
115 | return count; | ||
116 | } | ||
117 | |||
118 | static void nfs_netns_client_release(struct kobject *kobj) | ||
119 | { | ||
120 | struct nfs_netns_client *c = container_of(kobj, | ||
121 | struct nfs_netns_client, | ||
122 | kobject); | ||
123 | |||
124 | if (c->identifier) | ||
125 | kfree(c->identifier); | ||
126 | kfree(c); | ||
127 | } | ||
128 | |||
129 | static const void *nfs_netns_client_namespace(struct kobject *kobj) | ||
130 | { | ||
131 | return container_of(kobj, struct nfs_netns_client, kobject)->net; | ||
132 | } | ||
133 | |||
134 | static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier, | ||
135 | 0644, nfs_netns_identifier_show, nfs_netns_identifier_store); | ||
136 | |||
137 | static struct attribute *nfs_netns_client_attrs[] = { | ||
138 | &nfs_netns_client_id.attr, | ||
139 | NULL, | ||
140 | }; | ||
141 | |||
142 | static struct kobj_type nfs_netns_client_type = { | ||
143 | .release = nfs_netns_client_release, | ||
144 | .default_attrs = nfs_netns_client_attrs, | ||
145 | .sysfs_ops = &kobj_sysfs_ops, | ||
146 | .namespace = nfs_netns_client_namespace, | ||
147 | }; | ||
148 | |||
149 | static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent, | ||
150 | struct net *net) | ||
151 | { | ||
152 | struct nfs_netns_client *p; | ||
153 | |||
154 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
155 | if (p) { | ||
156 | p->net = net; | ||
157 | p->kobject.kset = nfs_client_kset; | ||
158 | if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type, | ||
159 | parent, "nfs_client") == 0) | ||
160 | return p; | ||
161 | kobject_put(&p->kobject); | ||
162 | } | ||
163 | return NULL; | ||
164 | } | ||
165 | |||
166 | void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net) | ||
167 | { | ||
168 | struct nfs_netns_client *clp; | ||
169 | |||
170 | clp = nfs_netns_client_alloc(nfs_client_kobj, net); | ||
171 | if (clp) { | ||
172 | netns->nfs_client = clp; | ||
173 | kobject_uevent(&clp->kobject, KOBJ_ADD); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | void nfs_netns_sysfs_destroy(struct nfs_net *netns) | ||
178 | { | ||
179 | struct nfs_netns_client *clp = netns->nfs_client; | ||
180 | |||
181 | if (clp) { | ||
182 | kobject_uevent(&clp->kobject, KOBJ_REMOVE); | ||
183 | kobject_del(&clp->kobject); | ||
184 | kobject_put(&clp->kobject); | ||
185 | netns->nfs_client = NULL; | ||
186 | } | ||
187 | } | ||