diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-01-29 21:40:10 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-07-06 14:54:49 -0400 |
commit | bf11fbdb20b385157b046ea7781f04d0c62554a3 (patch) | |
tree | fc24ca63f5e1529f713cc9243716dfc45075bd36 /fs/nfs | |
parent | 10b7a70cbb81a62353f763c3343ac0c48410696f (diff) |
NFS: Add sysfs support for per-container identifier
In order to identify containers to the NFS client, we add a per-net
sysfs attribute that udev can fill with the appropriate identifier.
The identifier could be a unique hostname, but in most cases it
will probably be a persisted uuid.
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/client.c | 4 | ||||
-rw-r--r-- | fs/nfs/netns.h | 3 | ||||
-rw-r--r-- | fs/nfs/sysfs.c | 118 | ||||
-rw-r--r-- | fs/nfs/sysfs.h | 10 |
4 files changed, 135 insertions, 0 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 0acb104f7b00..6e7aeb543f6a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include "pnfs.h" | 49 | #include "pnfs.h" |
50 | #include "nfs.h" | 50 | #include "nfs.h" |
51 | #include "netns.h" | 51 | #include "netns.h" |
52 | #include "sysfs.h" | ||
52 | 53 | ||
53 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 54 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
54 | 55 | ||
@@ -1072,12 +1073,15 @@ void nfs_clients_init(struct net *net) | |||
1072 | #endif | 1073 | #endif |
1073 | spin_lock_init(&nn->nfs_client_lock); | 1074 | spin_lock_init(&nn->nfs_client_lock); |
1074 | nn->boot_time = ktime_get_real(); | 1075 | nn->boot_time = ktime_get_real(); |
1076 | |||
1077 | nfs_netns_sysfs_setup(nn, net); | ||
1075 | } | 1078 | } |
1076 | 1079 | ||
1077 | void nfs_clients_exit(struct net *net) | 1080 | void nfs_clients_exit(struct net *net) |
1078 | { | 1081 | { |
1079 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 1082 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
1080 | 1083 | ||
1084 | nfs_netns_sysfs_destroy(nn); | ||
1081 | nfs_cleanup_cb_ident_idr(net); | 1085 | nfs_cleanup_cb_ident_idr(net); |
1082 | WARN_ON_ONCE(!list_empty(&nn->nfs_client_list)); | 1086 | WARN_ON_ONCE(!list_empty(&nn->nfs_client_list)); |
1083 | WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list)); | 1087 | WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list)); |
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index fc9978c58265..c8374f74dce1 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h | |||
@@ -15,6 +15,8 @@ struct bl_dev_msg { | |||
15 | uint32_t major, minor; | 15 | uint32_t major, minor; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | struct nfs_netns_client; | ||
19 | |||
18 | struct nfs_net { | 20 | struct nfs_net { |
19 | struct cache_detail *nfs_dns_resolve; | 21 | struct cache_detail *nfs_dns_resolve; |
20 | struct rpc_pipe *bl_device_pipe; | 22 | struct rpc_pipe *bl_device_pipe; |
@@ -29,6 +31,7 @@ struct nfs_net { | |||
29 | unsigned short nfs_callback_tcpport6; | 31 | unsigned short nfs_callback_tcpport6; |
30 | int cb_users[NFS4_MAX_MINOR_VERSION + 1]; | 32 | int cb_users[NFS4_MAX_MINOR_VERSION + 1]; |
31 | #endif | 33 | #endif |
34 | struct nfs_netns_client *nfs_client; | ||
32 | spinlock_t nfs_client_lock; | 35 | spinlock_t nfs_client_lock; |
33 | ktime_t boot_time; | 36 | ktime_t boot_time; |
34 | #ifdef CONFIG_PROC_FS | 37 | #ifdef CONFIG_PROC_FS |
diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c index 7070711ff6c5..4f3390b20239 100644 --- a/fs/nfs/sysfs.c +++ b/fs/nfs/sysfs.c | |||
@@ -9,7 +9,12 @@ | |||
9 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/netdevice.h> | 11 | #include <linux/netdevice.h> |
12 | #include <linux/string.h> | ||
13 | #include <linux/nfs_fs.h> | ||
14 | #include <linux/rcupdate.h> | ||
12 | 15 | ||
16 | #include "nfs4_fs.h" | ||
17 | #include "netns.h" | ||
13 | #include "sysfs.h" | 18 | #include "sysfs.h" |
14 | 19 | ||
15 | struct kobject *nfs_client_kobj; | 20 | struct kobject *nfs_client_kobj; |
@@ -67,3 +72,116 @@ void nfs_sysfs_exit(void) | |||
67 | kobject_put(nfs_client_kobj); | 72 | kobject_put(nfs_client_kobj); |
68 | kset_unregister(nfs_client_kset); | 73 | kset_unregister(nfs_client_kset); |
69 | } | 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 | } | ||
diff --git a/fs/nfs/sysfs.h b/fs/nfs/sysfs.h index 666f8db2ba92..f1b27411dcc0 100644 --- a/fs/nfs/sysfs.h +++ b/fs/nfs/sysfs.h | |||
@@ -6,10 +6,20 @@ | |||
6 | #ifndef __NFS_SYSFS_H | 6 | #ifndef __NFS_SYSFS_H |
7 | #define __NFS_SYSFS_H | 7 | #define __NFS_SYSFS_H |
8 | 8 | ||
9 | #define CONTAINER_ID_MAXLEN (64) | ||
10 | |||
11 | struct nfs_netns_client { | ||
12 | struct kobject kobject; | ||
13 | struct net *net; | ||
14 | const char *identifier; | ||
15 | }; | ||
9 | 16 | ||
10 | extern struct kobject *nfs_client_kobj; | 17 | extern struct kobject *nfs_client_kobj; |
11 | 18 | ||
12 | extern int nfs_sysfs_init(void); | 19 | extern int nfs_sysfs_init(void); |
13 | extern void nfs_sysfs_exit(void); | 20 | extern void nfs_sysfs_exit(void); |
14 | 21 | ||
22 | void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net); | ||
23 | void nfs_netns_sysfs_destroy(struct nfs_net *netns); | ||
24 | |||
15 | #endif | 25 | #endif |