xref: /openbmc/linux/fs/afs/vlclient.c (revision 680ef72a)
1 /* AFS Volume Location Service client
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/gfp.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include "afs_fs.h"
16 #include "internal.h"
17 
18 /*
19  * Deliver reply data to a VL.GetEntryByNameU call.
20  */
21 static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
22 {
23 	struct afs_uvldbentry__xdr *uvldb;
24 	struct afs_vldb_entry *entry;
25 	bool new_only = false;
26 	u32 tmp;
27 	int i, ret;
28 
29 	_enter("");
30 
31 	ret = afs_transfer_reply(call);
32 	if (ret < 0)
33 		return ret;
34 
35 	/* unmarshall the reply once we've received all of it */
36 	uvldb = call->buffer;
37 	entry = call->reply[0];
38 
39 	for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
40 		entry->name[i] = (u8)ntohl(uvldb->name[i]);
41 	entry->name[i] = 0;
42 	entry->name_len = strlen(entry->name);
43 
44 	/* If there is a new replication site that we can use, ignore all the
45 	 * sites that aren't marked as new.
46 	 */
47 	for (i = 0; i < AFS_NMAXNSERVERS; i++) {
48 		tmp = ntohl(uvldb->serverFlags[i]);
49 		if (!(tmp & AFS_VLSF_DONTUSE) &&
50 		    (tmp & AFS_VLSF_NEWREPSITE))
51 			new_only = true;
52 	}
53 
54 	for (i = 0; i < AFS_NMAXNSERVERS; i++) {
55 		struct afs_uuid__xdr *xdr;
56 		struct afs_uuid *uuid;
57 		int j;
58 
59 		tmp = ntohl(uvldb->serverFlags[i]);
60 		if (tmp & AFS_VLSF_DONTUSE ||
61 		    (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
62 			continue;
63 		if (tmp & AFS_VLSF_RWVOL)
64 			entry->fs_mask[i] |= AFS_VOL_VTM_RW;
65 		if (tmp & AFS_VLSF_ROVOL)
66 			entry->fs_mask[i] |= AFS_VOL_VTM_RO;
67 		if (tmp & AFS_VLSF_BACKVOL)
68 			entry->fs_mask[i] |= AFS_VOL_VTM_BAK;
69 		if (!entry->fs_mask[i])
70 			continue;
71 
72 		xdr = &uvldb->serverNumber[i];
73 		uuid = (struct afs_uuid *)&entry->fs_server[i];
74 		uuid->time_low			= xdr->time_low;
75 		uuid->time_mid			= htons(ntohl(xdr->time_mid));
76 		uuid->time_hi_and_version	= htons(ntohl(xdr->time_hi_and_version));
77 		uuid->clock_seq_hi_and_reserved	= (u8)ntohl(xdr->clock_seq_hi_and_reserved);
78 		uuid->clock_seq_low		= (u8)ntohl(xdr->clock_seq_low);
79 		for (j = 0; j < 6; j++)
80 			uuid->node[j] = (u8)ntohl(xdr->node[j]);
81 
82 		entry->nr_servers++;
83 	}
84 
85 	for (i = 0; i < AFS_MAXTYPES; i++)
86 		entry->vid[i] = ntohl(uvldb->volumeId[i]);
87 
88 	tmp = ntohl(uvldb->flags);
89 	if (tmp & AFS_VLF_RWEXISTS)
90 		__set_bit(AFS_VLDB_HAS_RW, &entry->flags);
91 	if (tmp & AFS_VLF_ROEXISTS)
92 		__set_bit(AFS_VLDB_HAS_RO, &entry->flags);
93 	if (tmp & AFS_VLF_BACKEXISTS)
94 		__set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
95 
96 	if (!(tmp & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
97 		entry->error = -ENOMEDIUM;
98 		__set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
99 	}
100 
101 	__set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
102 	_leave(" = 0 [done]");
103 	return 0;
104 }
105 
106 static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
107 {
108 	kfree(call->reply[0]);
109 	afs_flat_call_destructor(call);
110 }
111 
112 /*
113  * VL.GetEntryByNameU operation type.
114  */
115 static const struct afs_call_type afs_RXVLGetEntryByNameU = {
116 	.name		= "VL.GetEntryByNameU",
117 	.op		= afs_VL_GetEntryByNameU,
118 	.deliver	= afs_deliver_vl_get_entry_by_name_u,
119 	.destructor	= afs_destroy_vl_get_entry_by_name_u,
120 };
121 
122 /*
123  * Dispatch a get volume entry by name or ID operation (uuid variant).  If the
124  * volname is a decimal number then it's a volume ID not a volume name.
125  */
126 struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
127 						  struct afs_addr_cursor *ac,
128 						  struct key *key,
129 						  const char *volname,
130 						  int volnamesz)
131 {
132 	struct afs_vldb_entry *entry;
133 	struct afs_call *call;
134 	size_t reqsz, padsz;
135 	__be32 *bp;
136 
137 	_enter("");
138 
139 	padsz = (4 - (volnamesz & 3)) & 3;
140 	reqsz = 8 + volnamesz + padsz;
141 
142 	entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
143 	if (!entry)
144 		return ERR_PTR(-ENOMEM);
145 
146 	call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
147 				   sizeof(struct afs_uvldbentry__xdr));
148 	if (!call) {
149 		kfree(entry);
150 		return ERR_PTR(-ENOMEM);
151 	}
152 
153 	call->key = key;
154 	call->reply[0] = entry;
155 	call->ret_reply0 = true;
156 
157 	/* Marshall the parameters */
158 	bp = call->request;
159 	*bp++ = htonl(VLGETENTRYBYNAMEU);
160 	*bp++ = htonl(volnamesz);
161 	memcpy(bp, volname, volnamesz);
162 	if (padsz > 0)
163 		memset((void *)bp + volnamesz, 0, padsz);
164 
165 	trace_afs_make_vl_call(call);
166 	return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false);
167 }
168 
169 /*
170  * Deliver reply data to a VL.GetAddrsU call.
171  *
172  *	GetAddrsU(IN ListAddrByAttributes *inaddr,
173  *		  OUT afsUUID *uuidp1,
174  *		  OUT uint32_t *uniquifier,
175  *		  OUT uint32_t *nentries,
176  *		  OUT bulkaddrs *blkaddrs);
177  */
178 static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
179 {
180 	struct afs_addr_list *alist;
181 	__be32 *bp;
182 	u32 uniquifier, nentries, count;
183 	int i, ret;
184 
185 	_enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
186 
187 again:
188 	switch (call->unmarshall) {
189 	case 0:
190 		call->offset = 0;
191 		call->unmarshall++;
192 
193 		/* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
194 	case 1:
195 		ret = afs_extract_data(call, call->buffer,
196 				       sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32),
197 				       true);
198 		if (ret < 0)
199 			return ret;
200 
201 		bp = call->buffer + sizeof(struct afs_uuid__xdr);
202 		uniquifier	= ntohl(*bp++);
203 		nentries	= ntohl(*bp++);
204 		count		= ntohl(*bp);
205 
206 		nentries = min(nentries, count);
207 		alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
208 		if (!alist)
209 			return -ENOMEM;
210 		alist->version = uniquifier;
211 		call->reply[0] = alist;
212 		call->count = count;
213 		call->count2 = nentries;
214 		call->offset = 0;
215 		call->unmarshall++;
216 
217 		/* Extract entries */
218 	case 2:
219 		count = min(call->count, 4U);
220 		ret = afs_extract_data(call, call->buffer,
221 				       count * sizeof(__be32),
222 				       call->count > 4);
223 		if (ret < 0)
224 			return ret;
225 
226 		alist = call->reply[0];
227 		bp = call->buffer;
228 		for (i = 0; i < count; i++)
229 			if (alist->nr_addrs < call->count2)
230 				afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
231 
232 		call->count -= count;
233 		if (call->count > 0)
234 			goto again;
235 		call->offset = 0;
236 		call->unmarshall++;
237 		break;
238 	}
239 
240 	_leave(" = 0 [done]");
241 	return 0;
242 }
243 
244 static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
245 {
246 	afs_put_server(call->net, (struct afs_server *)call->reply[0]);
247 	kfree(call->reply[1]);
248 	return afs_flat_call_destructor(call);
249 }
250 
251 /*
252  * VL.GetAddrsU operation type.
253  */
254 static const struct afs_call_type afs_RXVLGetAddrsU = {
255 	.name		= "VL.GetAddrsU",
256 	.op		= afs_VL_GetAddrsU,
257 	.deliver	= afs_deliver_vl_get_addrs_u,
258 	.destructor	= afs_vl_get_addrs_u_destructor,
259 };
260 
261 /*
262  * Dispatch an operation to get the addresses for a server, where the server is
263  * nominated by UUID.
264  */
265 struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
266 					 struct afs_addr_cursor *ac,
267 					 struct key *key,
268 					 const uuid_t *uuid)
269 {
270 	struct afs_ListAddrByAttributes__xdr *r;
271 	const struct afs_uuid *u = (const struct afs_uuid *)uuid;
272 	struct afs_call *call;
273 	__be32 *bp;
274 	int i;
275 
276 	_enter("");
277 
278 	call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
279 				   sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
280 				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
281 	if (!call)
282 		return ERR_PTR(-ENOMEM);
283 
284 	call->key = key;
285 	call->reply[0] = NULL;
286 	call->ret_reply0 = true;
287 
288 	/* Marshall the parameters */
289 	bp = call->request;
290 	*bp++ = htonl(VLGETADDRSU);
291 	r = (struct afs_ListAddrByAttributes__xdr *)bp;
292 	r->Mask		= htonl(AFS_VLADDR_UUID);
293 	r->ipaddr	= 0;
294 	r->index	= 0;
295 	r->spare	= 0;
296 	r->uuid.time_low			= u->time_low;
297 	r->uuid.time_mid			= htonl(ntohs(u->time_mid));
298 	r->uuid.time_hi_and_version		= htonl(ntohs(u->time_hi_and_version));
299 	r->uuid.clock_seq_hi_and_reserved 	= htonl(u->clock_seq_hi_and_reserved);
300 	r->uuid.clock_seq_low			= htonl(u->clock_seq_low);
301 	for (i = 0; i < 6; i++)
302 		r->uuid.node[i] = ntohl(u->node[i]);
303 
304 	trace_afs_make_vl_call(call);
305 	return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
306 }
307 
308 /*
309  * Deliver reply data to an VL.GetCapabilities operation.
310  */
311 static int afs_deliver_vl_get_capabilities(struct afs_call *call)
312 {
313 	u32 count;
314 	int ret;
315 
316 	_enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
317 
318 again:
319 	switch (call->unmarshall) {
320 	case 0:
321 		call->offset = 0;
322 		call->unmarshall++;
323 
324 		/* Extract the capabilities word count */
325 	case 1:
326 		ret = afs_extract_data(call, &call->tmp,
327 				       1 * sizeof(__be32),
328 				       true);
329 		if (ret < 0)
330 			return ret;
331 
332 		count = ntohl(call->tmp);
333 
334 		call->count = count;
335 		call->count2 = count;
336 		call->offset = 0;
337 		call->unmarshall++;
338 
339 		/* Extract capabilities words */
340 	case 2:
341 		count = min(call->count, 16U);
342 		ret = afs_extract_data(call, call->buffer,
343 				       count * sizeof(__be32),
344 				       call->count > 16);
345 		if (ret < 0)
346 			return ret;
347 
348 		/* TODO: Examine capabilities */
349 
350 		call->count -= count;
351 		if (call->count > 0)
352 			goto again;
353 		call->offset = 0;
354 		call->unmarshall++;
355 		break;
356 	}
357 
358 	call->reply[0] = (void *)(unsigned long)call->service_id;
359 
360 	_leave(" = 0 [done]");
361 	return 0;
362 }
363 
364 /*
365  * VL.GetCapabilities operation type
366  */
367 static const struct afs_call_type afs_RXVLGetCapabilities = {
368 	.name		= "VL.GetCapabilities",
369 	.op		= afs_VL_GetCapabilities,
370 	.deliver	= afs_deliver_vl_get_capabilities,
371 	.destructor	= afs_flat_call_destructor,
372 };
373 
374 /*
375  * Probe a fileserver for the capabilities that it supports.  This can
376  * return up to 196 words.
377  *
378  * We use this to probe for service upgrade to determine what the server at the
379  * other end supports.
380  */
381 int afs_vl_get_capabilities(struct afs_net *net,
382 			    struct afs_addr_cursor *ac,
383 			    struct key *key)
384 {
385 	struct afs_call *call;
386 	__be32 *bp;
387 
388 	_enter("");
389 
390 	call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
391 	if (!call)
392 		return -ENOMEM;
393 
394 	call->key = key;
395 	call->upgrade = true; /* Let's see if this is a YFS server */
396 	call->reply[0] = (void *)VLGETCAPABILITIES;
397 	call->ret_reply0 = true;
398 
399 	/* marshall the parameters */
400 	bp = call->request;
401 	*bp++ = htonl(VLGETCAPABILITIES);
402 
403 	/* Can't take a ref on server */
404 	trace_afs_make_vl_call(call);
405 	return afs_make_call(ac, call, GFP_KERNEL, false);
406 }
407 
408 /*
409  * Deliver reply data to a YFSVL.GetEndpoints call.
410  *
411  *	GetEndpoints(IN yfsServerAttributes *attr,
412  *		     OUT opr_uuid *uuid,
413  *		     OUT afs_int32 *uniquifier,
414  *		     OUT endpoints *fsEndpoints,
415  *		     OUT endpoints *volEndpoints)
416  */
417 static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
418 {
419 	struct afs_addr_list *alist;
420 	__be32 *bp;
421 	u32 uniquifier, size;
422 	int ret;
423 
424 	_enter("{%u,%zu/%u,%u}", call->unmarshall, call->offset, call->count, call->count2);
425 
426 again:
427 	switch (call->unmarshall) {
428 	case 0:
429 		call->offset = 0;
430 		call->unmarshall = 1;
431 
432 		/* Extract the returned uuid, uniquifier, fsEndpoints count and
433 		 * either the first fsEndpoint type or the volEndpoints
434 		 * count if there are no fsEndpoints. */
435 	case 1:
436 		ret = afs_extract_data(call, call->buffer,
437 				       sizeof(uuid_t) +
438 				       3 * sizeof(__be32),
439 				       true);
440 		if (ret < 0)
441 			return ret;
442 
443 		bp = call->buffer + sizeof(uuid_t);
444 		uniquifier	= ntohl(*bp++);
445 		call->count	= ntohl(*bp++);
446 		call->count2	= ntohl(*bp); /* Type or next count */
447 
448 		if (call->count > YFS_MAXENDPOINTS)
449 			return -EBADMSG;
450 
451 		alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
452 		if (!alist)
453 			return -ENOMEM;
454 		alist->version = uniquifier;
455 		call->reply[0] = alist;
456 		call->offset = 0;
457 
458 		if (call->count == 0)
459 			goto extract_volendpoints;
460 
461 		call->unmarshall = 2;
462 
463 		/* Extract fsEndpoints[] entries */
464 	case 2:
465 		switch (call->count2) {
466 		case YFS_ENDPOINT_IPV4:
467 			size = sizeof(__be32) * (1 + 1 + 1);
468 			break;
469 		case YFS_ENDPOINT_IPV6:
470 			size = sizeof(__be32) * (1 + 4 + 1);
471 			break;
472 		default:
473 			return -EBADMSG;
474 		}
475 
476 		size += sizeof(__be32);
477 		ret = afs_extract_data(call, call->buffer, size, true);
478 		if (ret < 0)
479 			return ret;
480 
481 		alist = call->reply[0];
482 		bp = call->buffer;
483 		switch (call->count2) {
484 		case YFS_ENDPOINT_IPV4:
485 			if (ntohl(bp[0]) != sizeof(__be32) * 2)
486 				return -EBADMSG;
487 			afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
488 			bp += 3;
489 			break;
490 		case YFS_ENDPOINT_IPV6:
491 			if (ntohl(bp[0]) != sizeof(__be32) * 5)
492 				return -EBADMSG;
493 			afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
494 			bp += 6;
495 			break;
496 		default:
497 			return -EBADMSG;
498 		}
499 
500 		/* Got either the type of the next entry or the count of
501 		 * volEndpoints if no more fsEndpoints.
502 		 */
503 		call->count2 = htonl(*bp++);
504 
505 		call->offset = 0;
506 		call->count--;
507 		if (call->count > 0)
508 			goto again;
509 
510 	extract_volendpoints:
511 		/* Extract the list of volEndpoints. */
512 		call->count = call->count2;
513 		if (!call->count)
514 			goto end;
515 		if (call->count > YFS_MAXENDPOINTS)
516 			return -EBADMSG;
517 
518 		call->unmarshall = 3;
519 
520 		/* Extract the type of volEndpoints[0].  Normally we would
521 		 * extract the type of the next endpoint when we extract the
522 		 * data of the current one, but this is the first...
523 		 */
524 	case 3:
525 		ret = afs_extract_data(call, call->buffer, sizeof(__be32), true);
526 		if (ret < 0)
527 			return ret;
528 
529 		bp = call->buffer;
530 		call->count2 = htonl(*bp++);
531 		call->offset = 0;
532 		call->unmarshall = 4;
533 
534 		/* Extract volEndpoints[] entries */
535 	case 4:
536 		switch (call->count2) {
537 		case YFS_ENDPOINT_IPV4:
538 			size = sizeof(__be32) * (1 + 1 + 1);
539 			break;
540 		case YFS_ENDPOINT_IPV6:
541 			size = sizeof(__be32) * (1 + 4 + 1);
542 			break;
543 		default:
544 			return -EBADMSG;
545 		}
546 
547 		if (call->count > 1)
548 			size += sizeof(__be32);
549 		ret = afs_extract_data(call, call->buffer, size, true);
550 		if (ret < 0)
551 			return ret;
552 
553 		bp = call->buffer;
554 		switch (call->count2) {
555 		case YFS_ENDPOINT_IPV4:
556 			if (ntohl(bp[0]) != sizeof(__be32) * 2)
557 				return -EBADMSG;
558 			bp += 3;
559 			break;
560 		case YFS_ENDPOINT_IPV6:
561 			if (ntohl(bp[0]) != sizeof(__be32) * 5)
562 				return -EBADMSG;
563 			bp += 6;
564 			break;
565 		default:
566 			return -EBADMSG;
567 		}
568 
569 		/* Got either the type of the next entry or the count of
570 		 * volEndpoints if no more fsEndpoints.
571 		 */
572 		call->offset = 0;
573 		call->count--;
574 		if (call->count > 0) {
575 			call->count2 = htonl(*bp++);
576 			goto again;
577 		}
578 
579 	end:
580 		call->unmarshall = 5;
581 
582 		/* Done */
583 	case 5:
584 		ret = afs_extract_data(call, call->buffer, 0, false);
585 		if (ret < 0)
586 			return ret;
587 		call->unmarshall = 6;
588 
589 	case 6:
590 		break;
591 	}
592 
593 	alist = call->reply[0];
594 
595 	/* Start with IPv6 if available. */
596 	if (alist->nr_ipv4 < alist->nr_addrs)
597 		alist->index = alist->nr_ipv4;
598 
599 	_leave(" = 0 [done]");
600 	return 0;
601 }
602 
603 /*
604  * YFSVL.GetEndpoints operation type.
605  */
606 static const struct afs_call_type afs_YFSVLGetEndpoints = {
607 	.name		= "YFSVL.GetEndpoints",
608 	.op		= afs_YFSVL_GetEndpoints,
609 	.deliver	= afs_deliver_yfsvl_get_endpoints,
610 	.destructor	= afs_vl_get_addrs_u_destructor,
611 };
612 
613 /*
614  * Dispatch an operation to get the addresses for a server, where the server is
615  * nominated by UUID.
616  */
617 struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net,
618 					      struct afs_addr_cursor *ac,
619 					      struct key *key,
620 					      const uuid_t *uuid)
621 {
622 	struct afs_call *call;
623 	__be32 *bp;
624 
625 	_enter("");
626 
627 	call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
628 				   sizeof(__be32) * 2 + sizeof(*uuid),
629 				   sizeof(struct in6_addr) + sizeof(__be32) * 3);
630 	if (!call)
631 		return ERR_PTR(-ENOMEM);
632 
633 	call->key = key;
634 	call->reply[0] = NULL;
635 	call->ret_reply0 = true;
636 
637 	/* Marshall the parameters */
638 	bp = call->request;
639 	*bp++ = htonl(YVLGETENDPOINTS);
640 	*bp++ = htonl(YFS_SERVER_UUID);
641 	memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
642 
643 	trace_afs_make_vl_call(call);
644 	return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
645 }
646