diff options
author | Peng Tao <tao.peng@primarydata.com> | 2014-05-29 09:06:57 -0400 |
---|---|---|
committer | Tom Haynes <loghyr@primarydata.com> | 2015-02-03 14:06:32 -0500 |
commit | 875ae0694be48f3e3bdddd435b79abf52b680299 (patch) | |
tree | 67d05d85741b68eddacdf048072257901185e791 /fs/nfs/filelayout/filelayoutdev.c | |
parent | 085d1e33a6a8495d9afa58ad2b8b7ea74d613515 (diff) |
nfs41: pull data server cache from file layout to generic pnfs
Also pull nfs4_pnfs_ds_addr and nfs4_pnfs_ds to generic pnfs.
They can all be reused by flexfile layout as well.
Reviewed-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
Signed-off-by: Tom Haynes <Thomas.Haynes@primarydata.com>
Diffstat (limited to 'fs/nfs/filelayout/filelayoutdev.c')
-rw-r--r-- | fs/nfs/filelayout/filelayoutdev.c | 235 |
1 files changed, 2 insertions, 233 deletions
diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c index d21080aed9b2..fbfbb701159d 100644 --- a/fs/nfs/filelayout/filelayoutdev.c +++ b/fs/nfs/filelayout/filelayoutdev.c | |||
@@ -43,114 +43,6 @@ static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO; | |||
43 | static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; | 43 | static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * Data server cache | ||
47 | * | ||
48 | * Data servers can be mapped to different device ids. | ||
49 | * nfs4_pnfs_ds reference counting | ||
50 | * - set to 1 on allocation | ||
51 | * - incremented when a device id maps a data server already in the cache. | ||
52 | * - decremented when deviceid is removed from the cache. | ||
53 | */ | ||
54 | static DEFINE_SPINLOCK(nfs4_ds_cache_lock); | ||
55 | static LIST_HEAD(nfs4_data_server_cache); | ||
56 | |||
57 | /* Debug routines */ | ||
58 | void | ||
59 | print_ds(struct nfs4_pnfs_ds *ds) | ||
60 | { | ||
61 | if (ds == NULL) { | ||
62 | printk("%s NULL device\n", __func__); | ||
63 | return; | ||
64 | } | ||
65 | printk(" ds %s\n" | ||
66 | " ref count %d\n" | ||
67 | " client %p\n" | ||
68 | " cl_exchange_flags %x\n", | ||
69 | ds->ds_remotestr, | ||
70 | atomic_read(&ds->ds_count), ds->ds_clp, | ||
71 | ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0); | ||
72 | } | ||
73 | |||
74 | static bool | ||
75 | same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2) | ||
76 | { | ||
77 | struct sockaddr_in *a, *b; | ||
78 | struct sockaddr_in6 *a6, *b6; | ||
79 | |||
80 | if (addr1->sa_family != addr2->sa_family) | ||
81 | return false; | ||
82 | |||
83 | switch (addr1->sa_family) { | ||
84 | case AF_INET: | ||
85 | a = (struct sockaddr_in *)addr1; | ||
86 | b = (struct sockaddr_in *)addr2; | ||
87 | |||
88 | if (a->sin_addr.s_addr == b->sin_addr.s_addr && | ||
89 | a->sin_port == b->sin_port) | ||
90 | return true; | ||
91 | break; | ||
92 | |||
93 | case AF_INET6: | ||
94 | a6 = (struct sockaddr_in6 *)addr1; | ||
95 | b6 = (struct sockaddr_in6 *)addr2; | ||
96 | |||
97 | /* LINKLOCAL addresses must have matching scope_id */ | ||
98 | if (ipv6_addr_src_scope(&a6->sin6_addr) == | ||
99 | IPV6_ADDR_SCOPE_LINKLOCAL && | ||
100 | a6->sin6_scope_id != b6->sin6_scope_id) | ||
101 | return false; | ||
102 | |||
103 | if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) && | ||
104 | a6->sin6_port == b6->sin6_port) | ||
105 | return true; | ||
106 | break; | ||
107 | |||
108 | default: | ||
109 | dprintk("%s: unhandled address family: %u\n", | ||
110 | __func__, addr1->sa_family); | ||
111 | return false; | ||
112 | } | ||
113 | |||
114 | return false; | ||
115 | } | ||
116 | |||
117 | static bool | ||
118 | _same_data_server_addrs_locked(const struct list_head *dsaddrs1, | ||
119 | const struct list_head *dsaddrs2) | ||
120 | { | ||
121 | struct nfs4_pnfs_ds_addr *da1, *da2; | ||
122 | |||
123 | /* step through both lists, comparing as we go */ | ||
124 | for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node), | ||
125 | da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node); | ||
126 | da1 != NULL && da2 != NULL; | ||
127 | da1 = list_entry(da1->da_node.next, typeof(*da1), da_node), | ||
128 | da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) { | ||
129 | if (!same_sockaddr((struct sockaddr *)&da1->da_addr, | ||
130 | (struct sockaddr *)&da2->da_addr)) | ||
131 | return false; | ||
132 | } | ||
133 | if (da1 == NULL && da2 == NULL) | ||
134 | return true; | ||
135 | |||
136 | return false; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Lookup DS by addresses. nfs4_ds_cache_lock is held | ||
141 | */ | ||
142 | static struct nfs4_pnfs_ds * | ||
143 | _data_server_lookup_locked(const struct list_head *dsaddrs) | ||
144 | { | ||
145 | struct nfs4_pnfs_ds *ds; | ||
146 | |||
147 | list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) | ||
148 | if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs)) | ||
149 | return ds; | ||
150 | return NULL; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Create an rpc connection to the nfs4_pnfs_ds data server | 46 | * Create an rpc connection to the nfs4_pnfs_ds data server |
155 | * Currently only supports IPv4 and IPv6 addresses | 47 | * Currently only supports IPv4 and IPv6 addresses |
156 | */ | 48 | */ |
@@ -195,30 +87,6 @@ out_put: | |||
195 | goto out; | 87 | goto out; |
196 | } | 88 | } |
197 | 89 | ||
198 | static void | ||
199 | destroy_ds(struct nfs4_pnfs_ds *ds) | ||
200 | { | ||
201 | struct nfs4_pnfs_ds_addr *da; | ||
202 | |||
203 | dprintk("--> %s\n", __func__); | ||
204 | ifdebug(FACILITY) | ||
205 | print_ds(ds); | ||
206 | |||
207 | nfs_put_client(ds->ds_clp); | ||
208 | |||
209 | while (!list_empty(&ds->ds_addrs)) { | ||
210 | da = list_first_entry(&ds->ds_addrs, | ||
211 | struct nfs4_pnfs_ds_addr, | ||
212 | da_node); | ||
213 | list_del_init(&da->da_node); | ||
214 | kfree(da->da_remotestr); | ||
215 | kfree(da); | ||
216 | } | ||
217 | |||
218 | kfree(ds->ds_remotestr); | ||
219 | kfree(ds); | ||
220 | } | ||
221 | |||
222 | void | 90 | void |
223 | nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | 91 | nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) |
224 | { | 92 | { |
@@ -229,113 +97,14 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | |||
229 | 97 | ||
230 | for (i = 0; i < dsaddr->ds_num; i++) { | 98 | for (i = 0; i < dsaddr->ds_num; i++) { |
231 | ds = dsaddr->ds_list[i]; | 99 | ds = dsaddr->ds_list[i]; |
232 | if (ds != NULL) { | 100 | if (ds != NULL) |
233 | if (atomic_dec_and_lock(&ds->ds_count, | 101 | nfs4_pnfs_ds_put(ds); |
234 | &nfs4_ds_cache_lock)) { | ||
235 | list_del_init(&ds->ds_node); | ||
236 | spin_unlock(&nfs4_ds_cache_lock); | ||
237 | destroy_ds(ds); | ||
238 | } | ||
239 | } | ||
240 | } | 102 | } |
241 | kfree(dsaddr->stripe_indices); | 103 | kfree(dsaddr->stripe_indices); |
242 | kfree(dsaddr); | 104 | kfree(dsaddr); |
243 | } | 105 | } |
244 | 106 | ||
245 | /* | 107 | /* |
246 | * Create a string with a human readable address and port to avoid | ||
247 | * complicated setup around many dprinks. | ||
248 | */ | ||
249 | static char * | ||
250 | nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags) | ||
251 | { | ||
252 | struct nfs4_pnfs_ds_addr *da; | ||
253 | char *remotestr; | ||
254 | size_t len; | ||
255 | char *p; | ||
256 | |||
257 | len = 3; /* '{', '}' and eol */ | ||
258 | list_for_each_entry(da, dsaddrs, da_node) { | ||
259 | len += strlen(da->da_remotestr) + 1; /* string plus comma */ | ||
260 | } | ||
261 | |||
262 | remotestr = kzalloc(len, gfp_flags); | ||
263 | if (!remotestr) | ||
264 | return NULL; | ||
265 | |||
266 | p = remotestr; | ||
267 | *(p++) = '{'; | ||
268 | len--; | ||
269 | list_for_each_entry(da, dsaddrs, da_node) { | ||
270 | size_t ll = strlen(da->da_remotestr); | ||
271 | |||
272 | if (ll > len) | ||
273 | goto out_err; | ||
274 | |||
275 | memcpy(p, da->da_remotestr, ll); | ||
276 | p += ll; | ||
277 | len -= ll; | ||
278 | |||
279 | if (len < 1) | ||
280 | goto out_err; | ||
281 | (*p++) = ','; | ||
282 | len--; | ||
283 | } | ||
284 | if (len < 2) | ||
285 | goto out_err; | ||
286 | *(p++) = '}'; | ||
287 | *p = '\0'; | ||
288 | return remotestr; | ||
289 | out_err: | ||
290 | kfree(remotestr); | ||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | static struct nfs4_pnfs_ds * | ||
295 | nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) | ||
296 | { | ||
297 | struct nfs4_pnfs_ds *tmp_ds, *ds = NULL; | ||
298 | char *remotestr; | ||
299 | |||
300 | if (list_empty(dsaddrs)) { | ||
301 | dprintk("%s: no addresses defined\n", __func__); | ||
302 | goto out; | ||
303 | } | ||
304 | |||
305 | ds = kzalloc(sizeof(*ds), gfp_flags); | ||
306 | if (!ds) | ||
307 | goto out; | ||
308 | |||
309 | /* this is only used for debugging, so it's ok if its NULL */ | ||
310 | remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags); | ||
311 | |||
312 | spin_lock(&nfs4_ds_cache_lock); | ||
313 | tmp_ds = _data_server_lookup_locked(dsaddrs); | ||
314 | if (tmp_ds == NULL) { | ||
315 | INIT_LIST_HEAD(&ds->ds_addrs); | ||
316 | list_splice_init(dsaddrs, &ds->ds_addrs); | ||
317 | ds->ds_remotestr = remotestr; | ||
318 | atomic_set(&ds->ds_count, 1); | ||
319 | INIT_LIST_HEAD(&ds->ds_node); | ||
320 | ds->ds_clp = NULL; | ||
321 | list_add(&ds->ds_node, &nfs4_data_server_cache); | ||
322 | dprintk("%s add new data server %s\n", __func__, | ||
323 | ds->ds_remotestr); | ||
324 | } else { | ||
325 | kfree(remotestr); | ||
326 | kfree(ds); | ||
327 | atomic_inc(&tmp_ds->ds_count); | ||
328 | dprintk("%s data server %s found, inc'ed ds_count to %d\n", | ||
329 | __func__, tmp_ds->ds_remotestr, | ||
330 | atomic_read(&tmp_ds->ds_count)); | ||
331 | ds = tmp_ds; | ||
332 | } | ||
333 | spin_unlock(&nfs4_ds_cache_lock); | ||
334 | out: | ||
335 | return ds; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * Currently only supports ipv4, ipv6 and one multi-path address. | 108 | * Currently only supports ipv4, ipv6 and one multi-path address. |
340 | */ | 109 | */ |
341 | static struct nfs4_pnfs_ds_addr * | 110 | static struct nfs4_pnfs_ds_addr * |