aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2019-01-29 21:40:10 -0500
committerTrond Myklebust <trond.myklebust@hammerspace.com>2019-07-06 14:54:49 -0400
commitbf11fbdb20b385157b046ea7781f04d0c62554a3 (patch)
treefc24ca63f5e1529f713cc9243716dfc45075bd36 /fs/nfs
parent10b7a70cbb81a62353f763c3343ac0c48410696f (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.c4
-rw-r--r--fs/nfs/netns.h3
-rw-r--r--fs/nfs/sysfs.c118
-rw-r--r--fs/nfs/sysfs.h10
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
1077void nfs_clients_exit(struct net *net) 1080void 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
18struct nfs_netns_client;
19
18struct nfs_net { 20struct 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
15struct kobject *nfs_client_kobj; 20struct 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
76static 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' */
86static 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
93static 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
118static 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
129static const void *nfs_netns_client_namespace(struct kobject *kobj)
130{
131 return container_of(kobj, struct nfs_netns_client, kobject)->net;
132}
133
134static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
135 0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
136
137static struct attribute *nfs_netns_client_attrs[] = {
138 &nfs_netns_client_id.attr,
139 NULL,
140};
141
142static 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
149static 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
166void 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
177void 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
11struct nfs_netns_client {
12 struct kobject kobject;
13 struct net *net;
14 const char *identifier;
15};
9 16
10extern struct kobject *nfs_client_kobj; 17extern struct kobject *nfs_client_kobj;
11 18
12extern int nfs_sysfs_init(void); 19extern int nfs_sysfs_init(void);
13extern void nfs_sysfs_exit(void); 20extern void nfs_sysfs_exit(void);
14 21
22void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net);
23void nfs_netns_sysfs_destroy(struct nfs_net *netns);
24
15#endif 25#endif