xref: /openbmc/linux/fs/afs/vlclient.c (revision d32fd6bb9f2bc8178cdd65ebec1ad670a8bfa241)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ec26815aSDavid Howells /* AFS Volume Location Service client
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
51da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
85a0e3ad6STejun Heo #include <linux/gfp.h>
91da177e4SLinus Torvalds #include <linux/init.h>
101da177e4SLinus Torvalds #include <linux/sched.h>
114d9df986SDavid Howells #include "afs_fs.h"
121da177e4SLinus Torvalds #include "internal.h"
131da177e4SLinus Torvalds 
1408e0e7c8SDavid Howells /*
15d2ddc776SDavid Howells  * Deliver reply data to a VL.GetEntryByNameU call.
161da177e4SLinus Torvalds  */
afs_deliver_vl_get_entry_by_name_u(struct afs_call * call)17d2ddc776SDavid Howells static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
181da177e4SLinus Torvalds {
19d2ddc776SDavid Howells 	struct afs_uvldbentry__xdr *uvldb;
20d2ddc776SDavid Howells 	struct afs_vldb_entry *entry;
21d2ddc776SDavid Howells 	bool new_only = false;
221fba5868SMarc Dionne 	u32 tmp, nr_servers, vlflags;
23d2ddc776SDavid Howells 	int i, ret;
241da177e4SLinus Torvalds 
25d001648eSDavid Howells 	_enter("");
261da177e4SLinus Torvalds 
27d001648eSDavid Howells 	ret = afs_transfer_reply(call);
28372ee163SDavid Howells 	if (ret < 0)
29372ee163SDavid Howells 		return ret;
301da177e4SLinus Torvalds 
3108e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
32d2ddc776SDavid Howells 	uvldb = call->buffer;
33ffba718eSDavid Howells 	entry = call->ret_vldb;
341da177e4SLinus Torvalds 
3545df8462SDavid Howells 	nr_servers = ntohl(uvldb->nServers);
3645df8462SDavid Howells 	if (nr_servers > AFS_NMAXNSERVERS)
3745df8462SDavid Howells 		nr_servers = AFS_NMAXNSERVERS;
3845df8462SDavid Howells 
39d2ddc776SDavid Howells 	for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
40d2ddc776SDavid Howells 		entry->name[i] = (u8)ntohl(uvldb->name[i]);
41d2ddc776SDavid Howells 	entry->name[i] = 0;
42d2ddc776SDavid Howells 	entry->name_len = strlen(entry->name);
431da177e4SLinus Torvalds 
44d2ddc776SDavid Howells 	/* If there is a new replication site that we can use, ignore all the
45d2ddc776SDavid Howells 	 * sites that aren't marked as new.
46d2ddc776SDavid Howells 	 */
4745df8462SDavid Howells 	for (i = 0; i < nr_servers; i++) {
48d2ddc776SDavid Howells 		tmp = ntohl(uvldb->serverFlags[i]);
49d2ddc776SDavid Howells 		if (!(tmp & AFS_VLSF_DONTUSE) &&
50d2ddc776SDavid Howells 		    (tmp & AFS_VLSF_NEWREPSITE))
51d2ddc776SDavid Howells 			new_only = true;
524d9df986SDavid Howells 	}
531da177e4SLinus Torvalds 
541fba5868SMarc Dionne 	vlflags = ntohl(uvldb->flags);
5545df8462SDavid Howells 	for (i = 0; i < nr_servers; i++) {
56d2ddc776SDavid Howells 		struct afs_uuid__xdr *xdr;
57d2ddc776SDavid Howells 		struct afs_uuid *uuid;
58d2ddc776SDavid Howells 		int j;
594a46fdbaSMarc Dionne 		int n = entry->nr_servers;
601da177e4SLinus Torvalds 
61d2ddc776SDavid Howells 		tmp = ntohl(uvldb->serverFlags[i]);
62d2ddc776SDavid Howells 		if (tmp & AFS_VLSF_DONTUSE ||
63d2ddc776SDavid Howells 		    (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
64d2ddc776SDavid Howells 			continue;
651fba5868SMarc Dionne 		if (tmp & AFS_VLSF_RWVOL) {
664a46fdbaSMarc Dionne 			entry->fs_mask[n] |= AFS_VOL_VTM_RW;
671fba5868SMarc Dionne 			if (vlflags & AFS_VLF_BACKEXISTS)
684a46fdbaSMarc Dionne 				entry->fs_mask[n] |= AFS_VOL_VTM_BAK;
691fba5868SMarc Dionne 		}
701da177e4SLinus Torvalds 		if (tmp & AFS_VLSF_ROVOL)
714a46fdbaSMarc Dionne 			entry->fs_mask[n] |= AFS_VOL_VTM_RO;
724a46fdbaSMarc Dionne 		if (!entry->fs_mask[n])
73d2ddc776SDavid Howells 			continue;
74d2ddc776SDavid Howells 
75d2ddc776SDavid Howells 		xdr = &uvldb->serverNumber[i];
764a46fdbaSMarc Dionne 		uuid = (struct afs_uuid *)&entry->fs_server[n];
77d2ddc776SDavid Howells 		uuid->time_low			= xdr->time_low;
78d2ddc776SDavid Howells 		uuid->time_mid			= htons(ntohl(xdr->time_mid));
79d2ddc776SDavid Howells 		uuid->time_hi_and_version	= htons(ntohl(xdr->time_hi_and_version));
80d2ddc776SDavid Howells 		uuid->clock_seq_hi_and_reserved	= (u8)ntohl(xdr->clock_seq_hi_and_reserved);
81d2ddc776SDavid Howells 		uuid->clock_seq_low		= (u8)ntohl(xdr->clock_seq_low);
82d2ddc776SDavid Howells 		for (j = 0; j < 6; j++)
83d2ddc776SDavid Howells 			uuid->node[j] = (u8)ntohl(xdr->node[j]);
84d2ddc776SDavid Howells 
8581006805SDavid Howells 		entry->addr_version[n] = ntohl(uvldb->serverUnique[i]);
86d2ddc776SDavid Howells 		entry->nr_servers++;
871da177e4SLinus Torvalds 	}
881da177e4SLinus Torvalds 
89d2ddc776SDavid Howells 	for (i = 0; i < AFS_MAXTYPES; i++)
90d2ddc776SDavid Howells 		entry->vid[i] = ntohl(uvldb->volumeId[i]);
911da177e4SLinus Torvalds 
921fba5868SMarc Dionne 	if (vlflags & AFS_VLF_RWEXISTS)
93d2ddc776SDavid Howells 		__set_bit(AFS_VLDB_HAS_RW, &entry->flags);
941fba5868SMarc Dionne 	if (vlflags & AFS_VLF_ROEXISTS)
95d2ddc776SDavid Howells 		__set_bit(AFS_VLDB_HAS_RO, &entry->flags);
961fba5868SMarc Dionne 	if (vlflags & AFS_VLF_BACKEXISTS)
97d2ddc776SDavid Howells 		__set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
981da177e4SLinus Torvalds 
991fba5868SMarc Dionne 	if (!(vlflags & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
100d2ddc776SDavid Howells 		entry->error = -ENOMEDIUM;
101d2ddc776SDavid Howells 		__set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
102d2ddc776SDavid Howells 	}
103d2ddc776SDavid Howells 
104d2ddc776SDavid Howells 	__set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
10508e0e7c8SDavid Howells 	_leave(" = 0 [done]");
10608e0e7c8SDavid Howells 	return 0;
107ec26815aSDavid Howells }
1081da177e4SLinus Torvalds 
afs_destroy_vl_get_entry_by_name_u(struct afs_call * call)109d2ddc776SDavid Howells static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
110d2ddc776SDavid Howells {
111ffba718eSDavid Howells 	kfree(call->ret_vldb);
112d2ddc776SDavid Howells 	afs_flat_call_destructor(call);
113d2ddc776SDavid Howells }
114d2ddc776SDavid Howells 
1151da177e4SLinus Torvalds /*
116d2ddc776SDavid Howells  * VL.GetEntryByNameU operation type.
1171da177e4SLinus Torvalds  */
118d2ddc776SDavid Howells static const struct afs_call_type afs_RXVLGetEntryByNameU = {
119d2ddc776SDavid Howells 	.name		= "VL.GetEntryByNameU",
120025db80cSDavid Howells 	.op		= afs_VL_GetEntryByNameU,
121d2ddc776SDavid Howells 	.deliver	= afs_deliver_vl_get_entry_by_name_u,
122d2ddc776SDavid Howells 	.destructor	= afs_destroy_vl_get_entry_by_name_u,
12308e0e7c8SDavid Howells };
12408e0e7c8SDavid Howells 
12508e0e7c8SDavid Howells /*
126d2ddc776SDavid Howells  * Dispatch a get volume entry by name or ID operation (uuid variant).  If the
127d2ddc776SDavid Howells  * volname is a decimal number then it's a volume ID not a volume name.
12808e0e7c8SDavid Howells  */
afs_vl_get_entry_by_name_u(struct afs_vl_cursor * vc,const char * volname,int volnamesz)1290a5143f2SDavid Howells struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
13008e0e7c8SDavid Howells 						  const char *volname,
131d2ddc776SDavid Howells 						  int volnamesz)
13208e0e7c8SDavid Howells {
133d2ddc776SDavid Howells 	struct afs_vldb_entry *entry;
13408e0e7c8SDavid Howells 	struct afs_call *call;
1350a5143f2SDavid Howells 	struct afs_net *net = vc->cell->net;
136d2ddc776SDavid Howells 	size_t reqsz, padsz;
13708e0e7c8SDavid Howells 	__be32 *bp;
13808e0e7c8SDavid Howells 
13908e0e7c8SDavid Howells 	_enter("");
14008e0e7c8SDavid Howells 
14108e0e7c8SDavid Howells 	padsz = (4 - (volnamesz & 3)) & 3;
14208e0e7c8SDavid Howells 	reqsz = 8 + volnamesz + padsz;
14308e0e7c8SDavid Howells 
144d2ddc776SDavid Howells 	entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
145d2ddc776SDavid Howells 	if (!entry)
146d2ddc776SDavid Howells 		return ERR_PTR(-ENOMEM);
147d2ddc776SDavid Howells 
148d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
149d2ddc776SDavid Howells 				   sizeof(struct afs_uvldbentry__xdr));
150d2ddc776SDavid Howells 	if (!call) {
151d2ddc776SDavid Howells 		kfree(entry);
152d2ddc776SDavid Howells 		return ERR_PTR(-ENOMEM);
153d2ddc776SDavid Howells 	}
15408e0e7c8SDavid Howells 
1550a5143f2SDavid Howells 	call->key = vc->key;
156ffba718eSDavid Howells 	call->ret_vldb = entry;
15794f699c9SDavid Howells 	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
15808e0e7c8SDavid Howells 
159d2ddc776SDavid Howells 	/* Marshall the parameters */
16008e0e7c8SDavid Howells 	bp = call->request;
161d2ddc776SDavid Howells 	*bp++ = htonl(VLGETENTRYBYNAMEU);
16208e0e7c8SDavid Howells 	*bp++ = htonl(volnamesz);
16308e0e7c8SDavid Howells 	memcpy(bp, volname, volnamesz);
16408e0e7c8SDavid Howells 	if (padsz > 0)
16508e0e7c8SDavid Howells 		memset((void *)bp + volnamesz, 0, padsz);
16608e0e7c8SDavid Howells 
167025db80cSDavid Howells 	trace_afs_make_vl_call(call);
1680b9bf381SDavid Howells 	afs_make_call(&vc->ac, call, GFP_KERNEL);
1690b9bf381SDavid Howells 	return (struct afs_vldb_entry *)afs_wait_for_call_to_complete(call, &vc->ac);
17008e0e7c8SDavid Howells }
17108e0e7c8SDavid Howells 
17208e0e7c8SDavid Howells /*
173d2ddc776SDavid Howells  * Deliver reply data to a VL.GetAddrsU call.
174d2ddc776SDavid Howells  *
175d2ddc776SDavid Howells  *	GetAddrsU(IN ListAddrByAttributes *inaddr,
176d2ddc776SDavid Howells  *		  OUT afsUUID *uuidp1,
177d2ddc776SDavid Howells  *		  OUT uint32_t *uniquifier,
178d2ddc776SDavid Howells  *		  OUT uint32_t *nentries,
179d2ddc776SDavid Howells  *		  OUT bulkaddrs *blkaddrs);
18008e0e7c8SDavid Howells  */
afs_deliver_vl_get_addrs_u(struct afs_call * call)181d2ddc776SDavid Howells static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
182d2ddc776SDavid Howells {
183d2ddc776SDavid Howells 	struct afs_addr_list *alist;
184d2ddc776SDavid Howells 	__be32 *bp;
185d2ddc776SDavid Howells 	u32 uniquifier, nentries, count;
186d2ddc776SDavid Howells 	int i, ret;
187d2ddc776SDavid Howells 
18812bdcf33SDavid Howells 	_enter("{%u,%zu/%u}",
189fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), call->count);
190d2ddc776SDavid Howells 
191d2ddc776SDavid Howells 	switch (call->unmarshall) {
192d2ddc776SDavid Howells 	case 0:
19312bdcf33SDavid Howells 		afs_extract_to_buf(call,
19412bdcf33SDavid Howells 				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
195d2ddc776SDavid Howells 		call->unmarshall++;
196d2ddc776SDavid Howells 
197e690c9e3SGustavo A. R. Silva 		/* Extract the returned uuid, uniquifier, nentries and
198e690c9e3SGustavo A. R. Silva 		 * blkaddrs size */
199df561f66SGustavo A. R. Silva 		fallthrough;
200d2ddc776SDavid Howells 	case 1:
20112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
202d2ddc776SDavid Howells 		if (ret < 0)
203d2ddc776SDavid Howells 			return ret;
204d2ddc776SDavid Howells 
205d2ddc776SDavid Howells 		bp = call->buffer + sizeof(struct afs_uuid__xdr);
206d2ddc776SDavid Howells 		uniquifier	= ntohl(*bp++);
207d2ddc776SDavid Howells 		nentries	= ntohl(*bp++);
208d2ddc776SDavid Howells 		count		= ntohl(*bp);
209d2ddc776SDavid Howells 
210d2ddc776SDavid Howells 		nentries = min(nentries, count);
211d2ddc776SDavid Howells 		alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
212d2ddc776SDavid Howells 		if (!alist)
213d2ddc776SDavid Howells 			return -ENOMEM;
214d2ddc776SDavid Howells 		alist->version = uniquifier;
215ffba718eSDavid Howells 		call->ret_alist = alist;
216d2ddc776SDavid Howells 		call->count = count;
217d2ddc776SDavid Howells 		call->count2 = nentries;
218d2ddc776SDavid Howells 		call->unmarshall++;
219d2ddc776SDavid Howells 
22012bdcf33SDavid Howells 	more_entries:
22112bdcf33SDavid Howells 		count = min(call->count, 4U);
22212bdcf33SDavid Howells 		afs_extract_to_buf(call, count * sizeof(__be32));
22312bdcf33SDavid Howells 
224df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract entries */
225d2ddc776SDavid Howells 	case 2:
22612bdcf33SDavid Howells 		ret = afs_extract_data(call, call->count > 4);
227d2ddc776SDavid Howells 		if (ret < 0)
228d2ddc776SDavid Howells 			return ret;
229d2ddc776SDavid Howells 
230ffba718eSDavid Howells 		alist = call->ret_alist;
231d2ddc776SDavid Howells 		bp = call->buffer;
23212bdcf33SDavid Howells 		count = min(call->count, 4U);
233d2ddc776SDavid Howells 		for (i = 0; i < count; i++)
234d2ddc776SDavid Howells 			if (alist->nr_addrs < call->count2)
235bf99a53cSDavid Howells 				afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
236d2ddc776SDavid Howells 
237d2ddc776SDavid Howells 		call->count -= count;
238d2ddc776SDavid Howells 		if (call->count > 0)
23912bdcf33SDavid Howells 			goto more_entries;
240d2ddc776SDavid Howells 		call->unmarshall++;
241d2ddc776SDavid Howells 		break;
242d2ddc776SDavid Howells 	}
243d2ddc776SDavid Howells 
244d2ddc776SDavid Howells 	_leave(" = 0 [done]");
245d2ddc776SDavid Howells 	return 0;
246d2ddc776SDavid Howells }
247d2ddc776SDavid Howells 
afs_vl_get_addrs_u_destructor(struct afs_call * call)248d2ddc776SDavid Howells static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
249d2ddc776SDavid Howells {
250ffba718eSDavid Howells 	afs_put_addrlist(call->ret_alist);
251d2ddc776SDavid Howells 	return afs_flat_call_destructor(call);
252d2ddc776SDavid Howells }
253d2ddc776SDavid Howells 
254d2ddc776SDavid Howells /*
255d2ddc776SDavid Howells  * VL.GetAddrsU operation type.
256d2ddc776SDavid Howells  */
257d2ddc776SDavid Howells static const struct afs_call_type afs_RXVLGetAddrsU = {
258d2ddc776SDavid Howells 	.name		= "VL.GetAddrsU",
259025db80cSDavid Howells 	.op		= afs_VL_GetAddrsU,
260d2ddc776SDavid Howells 	.deliver	= afs_deliver_vl_get_addrs_u,
261d2ddc776SDavid Howells 	.destructor	= afs_vl_get_addrs_u_destructor,
262d2ddc776SDavid Howells };
263d2ddc776SDavid Howells 
264d2ddc776SDavid Howells /*
265d2ddc776SDavid Howells  * Dispatch an operation to get the addresses for a server, where the server is
266d2ddc776SDavid Howells  * nominated by UUID.
267d2ddc776SDavid Howells  */
afs_vl_get_addrs_u(struct afs_vl_cursor * vc,const uuid_t * uuid)2680a5143f2SDavid Howells struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
269d2ddc776SDavid Howells 					 const uuid_t *uuid)
2701da177e4SLinus Torvalds {
271d2ddc776SDavid Howells 	struct afs_ListAddrByAttributes__xdr *r;
272d2ddc776SDavid Howells 	const struct afs_uuid *u = (const struct afs_uuid *)uuid;
27308e0e7c8SDavid Howells 	struct afs_call *call;
2740a5143f2SDavid Howells 	struct afs_net *net = vc->cell->net;
2751da177e4SLinus Torvalds 	__be32 *bp;
276d2ddc776SDavid Howells 	int i;
2771da177e4SLinus Torvalds 
27808e0e7c8SDavid Howells 	_enter("");
2791da177e4SLinus Torvalds 
280d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
281d2ddc776SDavid Howells 				   sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
282d2ddc776SDavid Howells 				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
28308e0e7c8SDavid Howells 	if (!call)
284d2ddc776SDavid Howells 		return ERR_PTR(-ENOMEM);
2851da177e4SLinus Torvalds 
2860a5143f2SDavid Howells 	call->key = vc->key;
287ffba718eSDavid Howells 	call->ret_alist = NULL;
28894f699c9SDavid Howells 	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
2891da177e4SLinus Torvalds 
290d2ddc776SDavid Howells 	/* Marshall the parameters */
29108e0e7c8SDavid Howells 	bp = call->request;
292d2ddc776SDavid Howells 	*bp++ = htonl(VLGETADDRSU);
293d2ddc776SDavid Howells 	r = (struct afs_ListAddrByAttributes__xdr *)bp;
294d2ddc776SDavid Howells 	r->Mask		= htonl(AFS_VLADDR_UUID);
295d2ddc776SDavid Howells 	r->ipaddr	= 0;
296d2ddc776SDavid Howells 	r->index	= 0;
297d2ddc776SDavid Howells 	r->spare	= 0;
298d2ddc776SDavid Howells 	r->uuid.time_low			= u->time_low;
299d2ddc776SDavid Howells 	r->uuid.time_mid			= htonl(ntohs(u->time_mid));
300d2ddc776SDavid Howells 	r->uuid.time_hi_and_version		= htonl(ntohs(u->time_hi_and_version));
301d2ddc776SDavid Howells 	r->uuid.clock_seq_hi_and_reserved 	= htonl(u->clock_seq_hi_and_reserved);
302d2ddc776SDavid Howells 	r->uuid.clock_seq_low			= htonl(u->clock_seq_low);
303d2ddc776SDavid Howells 	for (i = 0; i < 6; i++)
304fe342cf7SDavid Howells 		r->uuid.node[i] = htonl(u->node[i]);
3051da177e4SLinus Torvalds 
306025db80cSDavid Howells 	trace_afs_make_vl_call(call);
3070b9bf381SDavid Howells 	afs_make_call(&vc->ac, call, GFP_KERNEL);
3080b9bf381SDavid Howells 	return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
309ec26815aSDavid Howells }
310bf99a53cSDavid Howells 
311bf99a53cSDavid Howells /*
312bf99a53cSDavid Howells  * Deliver reply data to an VL.GetCapabilities operation.
313bf99a53cSDavid Howells  */
afs_deliver_vl_get_capabilities(struct afs_call * call)314bf99a53cSDavid Howells static int afs_deliver_vl_get_capabilities(struct afs_call *call)
315bf99a53cSDavid Howells {
316bf99a53cSDavid Howells 	u32 count;
317bf99a53cSDavid Howells 	int ret;
318bf99a53cSDavid Howells 
31912bdcf33SDavid Howells 	_enter("{%u,%zu/%u}",
320fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), call->count);
321bf99a53cSDavid Howells 
322bf99a53cSDavid Howells 	switch (call->unmarshall) {
323bf99a53cSDavid Howells 	case 0:
32412bdcf33SDavid Howells 		afs_extract_to_tmp(call);
325bf99a53cSDavid Howells 		call->unmarshall++;
326bf99a53cSDavid Howells 
327df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract the capabilities word count */
328bf99a53cSDavid Howells 	case 1:
32912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
330bf99a53cSDavid Howells 		if (ret < 0)
331bf99a53cSDavid Howells 			return ret;
332bf99a53cSDavid Howells 
333bf99a53cSDavid Howells 		count = ntohl(call->tmp);
334bf99a53cSDavid Howells 		call->count = count;
335bf99a53cSDavid Howells 		call->count2 = count;
33612bdcf33SDavid Howells 
337bf99a53cSDavid Howells 		call->unmarshall++;
33812bdcf33SDavid Howells 		afs_extract_discard(call, count * sizeof(__be32));
339bf99a53cSDavid Howells 
340df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract capabilities words */
341bf99a53cSDavid Howells 	case 2:
34212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
343bf99a53cSDavid Howells 		if (ret < 0)
344bf99a53cSDavid Howells 			return ret;
345bf99a53cSDavid Howells 
346bf99a53cSDavid Howells 		/* TODO: Examine capabilities */
347bf99a53cSDavid Howells 
348bf99a53cSDavid Howells 		call->unmarshall++;
349bf99a53cSDavid Howells 		break;
350bf99a53cSDavid Howells 	}
351bf99a53cSDavid Howells 
352bf99a53cSDavid Howells 	_leave(" = 0 [done]");
353bf99a53cSDavid Howells 	return 0;
354bf99a53cSDavid Howells }
355bf99a53cSDavid Howells 
afs_destroy_vl_get_capabilities(struct afs_call * call)3563bf0fb6fSDavid Howells static void afs_destroy_vl_get_capabilities(struct afs_call *call)
3573bf0fb6fSDavid Howells {
358ffba718eSDavid Howells 	afs_put_vlserver(call->net, call->vlserver);
3593bf0fb6fSDavid Howells 	afs_flat_call_destructor(call);
3603bf0fb6fSDavid Howells }
3613bf0fb6fSDavid Howells 
362bf99a53cSDavid Howells /*
363bf99a53cSDavid Howells  * VL.GetCapabilities operation type
364bf99a53cSDavid Howells  */
365bf99a53cSDavid Howells static const struct afs_call_type afs_RXVLGetCapabilities = {
366bf99a53cSDavid Howells 	.name		= "VL.GetCapabilities",
367025db80cSDavid Howells 	.op		= afs_VL_GetCapabilities,
368bf99a53cSDavid Howells 	.deliver	= afs_deliver_vl_get_capabilities,
3693bf0fb6fSDavid Howells 	.done		= afs_vlserver_probe_result,
3703bf0fb6fSDavid Howells 	.destructor	= afs_destroy_vl_get_capabilities,
371bf99a53cSDavid Howells };
372bf99a53cSDavid Howells 
373bf99a53cSDavid Howells /*
3740a5143f2SDavid Howells  * Probe a volume server for the capabilities that it supports.  This can
375bf99a53cSDavid Howells  * return up to 196 words.
376bf99a53cSDavid Howells  *
377bf99a53cSDavid Howells  * We use this to probe for service upgrade to determine what the server at the
378bf99a53cSDavid Howells  * other end supports.
379bf99a53cSDavid Howells  */
afs_vl_get_capabilities(struct afs_net * net,struct afs_addr_cursor * ac,struct key * key,struct afs_vlserver * server,unsigned int server_index)3800b9bf381SDavid Howells struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
3813bf0fb6fSDavid Howells 					 struct afs_addr_cursor *ac,
3823bf0fb6fSDavid Howells 					 struct key *key,
3833bf0fb6fSDavid Howells 					 struct afs_vlserver *server,
3840b9bf381SDavid Howells 					 unsigned int server_index)
385bf99a53cSDavid Howells {
386bf99a53cSDavid Howells 	struct afs_call *call;
387bf99a53cSDavid Howells 	__be32 *bp;
388bf99a53cSDavid Howells 
389bf99a53cSDavid Howells 	_enter("");
390bf99a53cSDavid Howells 
391bf99a53cSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
392bf99a53cSDavid Howells 	if (!call)
3930b9bf381SDavid Howells 		return ERR_PTR(-ENOMEM);
394bf99a53cSDavid Howells 
395bf99a53cSDavid Howells 	call->key = key;
396ffba718eSDavid Howells 	call->vlserver = afs_get_vlserver(server);
397ffba718eSDavid Howells 	call->server_index = server_index;
3983bf0fb6fSDavid Howells 	call->upgrade = true;
3990b9bf381SDavid Howells 	call->async = true;
40094f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
401bf99a53cSDavid Howells 
402bf99a53cSDavid Howells 	/* marshall the parameters */
403bf99a53cSDavid Howells 	bp = call->request;
404bf99a53cSDavid Howells 	*bp++ = htonl(VLGETCAPABILITIES);
405bf99a53cSDavid Howells 
406bf99a53cSDavid Howells 	/* Can't take a ref on server */
407025db80cSDavid Howells 	trace_afs_make_vl_call(call);
4080b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_KERNEL);
4090b9bf381SDavid Howells 	return call;
410bf99a53cSDavid Howells }
411bf99a53cSDavid Howells 
412bf99a53cSDavid Howells /*
413bf99a53cSDavid Howells  * Deliver reply data to a YFSVL.GetEndpoints call.
414bf99a53cSDavid Howells  *
415bf99a53cSDavid Howells  *	GetEndpoints(IN yfsServerAttributes *attr,
416bf99a53cSDavid Howells  *		     OUT opr_uuid *uuid,
417bf99a53cSDavid Howells  *		     OUT afs_int32 *uniquifier,
418bf99a53cSDavid Howells  *		     OUT endpoints *fsEndpoints,
419bf99a53cSDavid Howells  *		     OUT endpoints *volEndpoints)
420bf99a53cSDavid Howells  */
afs_deliver_yfsvl_get_endpoints(struct afs_call * call)421bf99a53cSDavid Howells static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
422bf99a53cSDavid Howells {
423bf99a53cSDavid Howells 	struct afs_addr_list *alist;
424bf99a53cSDavid Howells 	__be32 *bp;
425bf99a53cSDavid Howells 	u32 uniquifier, size;
426bf99a53cSDavid Howells 	int ret;
427bf99a53cSDavid Howells 
42812bdcf33SDavid Howells 	_enter("{%u,%zu,%u}",
429fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), call->count2);
430bf99a53cSDavid Howells 
431bf99a53cSDavid Howells 	switch (call->unmarshall) {
432bf99a53cSDavid Howells 	case 0:
43312bdcf33SDavid Howells 		afs_extract_to_buf(call, sizeof(uuid_t) + 3 * sizeof(__be32));
434bf99a53cSDavid Howells 		call->unmarshall = 1;
435bf99a53cSDavid Howells 
436bf99a53cSDavid Howells 		/* Extract the returned uuid, uniquifier, fsEndpoints count and
437bf99a53cSDavid Howells 		 * either the first fsEndpoint type or the volEndpoints
438bf99a53cSDavid Howells 		 * count if there are no fsEndpoints. */
439df561f66SGustavo A. R. Silva 		fallthrough;
440bf99a53cSDavid Howells 	case 1:
44112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
442bf99a53cSDavid Howells 		if (ret < 0)
443bf99a53cSDavid Howells 			return ret;
444bf99a53cSDavid Howells 
445bf99a53cSDavid Howells 		bp = call->buffer + sizeof(uuid_t);
446bf99a53cSDavid Howells 		uniquifier	= ntohl(*bp++);
447bf99a53cSDavid Howells 		call->count	= ntohl(*bp++);
448bf99a53cSDavid Howells 		call->count2	= ntohl(*bp); /* Type or next count */
449bf99a53cSDavid Howells 
450bf99a53cSDavid Howells 		if (call->count > YFS_MAXENDPOINTS)
4517126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num);
452bf99a53cSDavid Howells 
453bf99a53cSDavid Howells 		alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
454bf99a53cSDavid Howells 		if (!alist)
455bf99a53cSDavid Howells 			return -ENOMEM;
456bf99a53cSDavid Howells 		alist->version = uniquifier;
457ffba718eSDavid Howells 		call->ret_alist = alist;
458bf99a53cSDavid Howells 
459bf99a53cSDavid Howells 		if (call->count == 0)
460bf99a53cSDavid Howells 			goto extract_volendpoints;
461bf99a53cSDavid Howells 
46212bdcf33SDavid Howells 	next_fsendpoint:
463bf99a53cSDavid Howells 		switch (call->count2) {
464bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV4:
465bf99a53cSDavid Howells 			size = sizeof(__be32) * (1 + 1 + 1);
466bf99a53cSDavid Howells 			break;
467bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV6:
468bf99a53cSDavid Howells 			size = sizeof(__be32) * (1 + 4 + 1);
469bf99a53cSDavid Howells 			break;
470bf99a53cSDavid Howells 		default:
4717126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
472bf99a53cSDavid Howells 		}
473bf99a53cSDavid Howells 
474bf99a53cSDavid Howells 		size += sizeof(__be32);
47512bdcf33SDavid Howells 		afs_extract_to_buf(call, size);
47612bdcf33SDavid Howells 		call->unmarshall = 2;
47712bdcf33SDavid Howells 
478df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract fsEndpoints[] entries */
47912bdcf33SDavid Howells 	case 2:
48012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
481bf99a53cSDavid Howells 		if (ret < 0)
482bf99a53cSDavid Howells 			return ret;
483bf99a53cSDavid Howells 
484ffba718eSDavid Howells 		alist = call->ret_alist;
485bf99a53cSDavid Howells 		bp = call->buffer;
486bf99a53cSDavid Howells 		switch (call->count2) {
487bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV4:
488bf99a53cSDavid Howells 			if (ntohl(bp[0]) != sizeof(__be32) * 2)
4897126ead9SDavid Howells 				return afs_protocol_error(
4907126ead9SDavid Howells 					call, afs_eproto_yvl_fsendpt4_len);
491bf99a53cSDavid Howells 			afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
492bf99a53cSDavid Howells 			bp += 3;
493bf99a53cSDavid Howells 			break;
494bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV6:
495bf99a53cSDavid Howells 			if (ntohl(bp[0]) != sizeof(__be32) * 5)
4967126ead9SDavid Howells 				return afs_protocol_error(
4977126ead9SDavid Howells 					call, afs_eproto_yvl_fsendpt6_len);
498bf99a53cSDavid Howells 			afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
499bf99a53cSDavid Howells 			bp += 6;
500bf99a53cSDavid Howells 			break;
501bf99a53cSDavid Howells 		default:
5027126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
503bf99a53cSDavid Howells 		}
504bf99a53cSDavid Howells 
505bf99a53cSDavid Howells 		/* Got either the type of the next entry or the count of
506bf99a53cSDavid Howells 		 * volEndpoints if no more fsEndpoints.
507bf99a53cSDavid Howells 		 */
508fe342cf7SDavid Howells 		call->count2 = ntohl(*bp++);
509bf99a53cSDavid Howells 
510bf99a53cSDavid Howells 		call->count--;
511bf99a53cSDavid Howells 		if (call->count > 0)
51212bdcf33SDavid Howells 			goto next_fsendpoint;
513bf99a53cSDavid Howells 
514bf99a53cSDavid Howells 	extract_volendpoints:
515bf99a53cSDavid Howells 		/* Extract the list of volEndpoints. */
516bf99a53cSDavid Howells 		call->count = call->count2;
517bf99a53cSDavid Howells 		if (!call->count)
518bf99a53cSDavid Howells 			goto end;
519bf99a53cSDavid Howells 		if (call->count > YFS_MAXENDPOINTS)
5207126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
521bf99a53cSDavid Howells 
52212bdcf33SDavid Howells 		afs_extract_to_buf(call, 1 * sizeof(__be32));
523bf99a53cSDavid Howells 		call->unmarshall = 3;
524bf99a53cSDavid Howells 
525bf99a53cSDavid Howells 		/* Extract the type of volEndpoints[0].  Normally we would
526bf99a53cSDavid Howells 		 * extract the type of the next endpoint when we extract the
527bf99a53cSDavid Howells 		 * data of the current one, but this is the first...
528bf99a53cSDavid Howells 		 */
529df561f66SGustavo A. R. Silva 		fallthrough;
530bf99a53cSDavid Howells 	case 3:
53112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
532bf99a53cSDavid Howells 		if (ret < 0)
533bf99a53cSDavid Howells 			return ret;
534bf99a53cSDavid Howells 
535bf99a53cSDavid Howells 		bp = call->buffer;
536bf99a53cSDavid Howells 
53712bdcf33SDavid Howells 	next_volendpoint:
53812bdcf33SDavid Howells 		call->count2 = ntohl(*bp++);
539bf99a53cSDavid Howells 		switch (call->count2) {
540bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV4:
541bf99a53cSDavid Howells 			size = sizeof(__be32) * (1 + 1 + 1);
542bf99a53cSDavid Howells 			break;
543bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV6:
544bf99a53cSDavid Howells 			size = sizeof(__be32) * (1 + 4 + 1);
545bf99a53cSDavid Howells 			break;
546bf99a53cSDavid Howells 		default:
5477126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
548bf99a53cSDavid Howells 		}
549bf99a53cSDavid Howells 
550bf99a53cSDavid Howells 		if (call->count > 1)
55112bdcf33SDavid Howells 			size += sizeof(__be32); /* Get next type too */
55212bdcf33SDavid Howells 		afs_extract_to_buf(call, size);
55312bdcf33SDavid Howells 		call->unmarshall = 4;
55412bdcf33SDavid Howells 
555df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract volEndpoints[] entries */
55612bdcf33SDavid Howells 	case 4:
55712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
558bf99a53cSDavid Howells 		if (ret < 0)
559bf99a53cSDavid Howells 			return ret;
560bf99a53cSDavid Howells 
561bf99a53cSDavid Howells 		bp = call->buffer;
562bf99a53cSDavid Howells 		switch (call->count2) {
563bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV4:
564bf99a53cSDavid Howells 			if (ntohl(bp[0]) != sizeof(__be32) * 2)
5657126ead9SDavid Howells 				return afs_protocol_error(
5667126ead9SDavid Howells 					call, afs_eproto_yvl_vlendpt4_len);
567bf99a53cSDavid Howells 			bp += 3;
568bf99a53cSDavid Howells 			break;
569bf99a53cSDavid Howells 		case YFS_ENDPOINT_IPV6:
570bf99a53cSDavid Howells 			if (ntohl(bp[0]) != sizeof(__be32) * 5)
5717126ead9SDavid Howells 				return afs_protocol_error(
5727126ead9SDavid Howells 					call, afs_eproto_yvl_vlendpt6_len);
573bf99a53cSDavid Howells 			bp += 6;
574bf99a53cSDavid Howells 			break;
575bf99a53cSDavid Howells 		default:
5767126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
577bf99a53cSDavid Howells 		}
578bf99a53cSDavid Howells 
579bf99a53cSDavid Howells 		/* Got either the type of the next entry or the count of
580bf99a53cSDavid Howells 		 * volEndpoints if no more fsEndpoints.
581bf99a53cSDavid Howells 		 */
582bf99a53cSDavid Howells 		call->count--;
58312bdcf33SDavid Howells 		if (call->count > 0)
58412bdcf33SDavid Howells 			goto next_volendpoint;
585bf99a53cSDavid Howells 
586bf99a53cSDavid Howells 	end:
58712bdcf33SDavid Howells 		afs_extract_discard(call, 0);
588bf99a53cSDavid Howells 		call->unmarshall = 5;
589bf99a53cSDavid Howells 
590df561f66SGustavo A. R. Silva 		fallthrough;	/* Done */
591bf99a53cSDavid Howells 	case 5:
59212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
593bf99a53cSDavid Howells 		if (ret < 0)
594bf99a53cSDavid Howells 			return ret;
595bf99a53cSDavid Howells 		call->unmarshall = 6;
596b2db6c35SGustavo A. R. Silva 		fallthrough;
597bf99a53cSDavid Howells 
598bf99a53cSDavid Howells 	case 6:
599bf99a53cSDavid Howells 		break;
600bf99a53cSDavid Howells 	}
601bf99a53cSDavid Howells 
602bf99a53cSDavid Howells 	_leave(" = 0 [done]");
603bf99a53cSDavid Howells 	return 0;
604bf99a53cSDavid Howells }
605bf99a53cSDavid Howells 
606bf99a53cSDavid Howells /*
607bf99a53cSDavid Howells  * YFSVL.GetEndpoints operation type.
608bf99a53cSDavid Howells  */
609bf99a53cSDavid Howells static const struct afs_call_type afs_YFSVLGetEndpoints = {
610025db80cSDavid Howells 	.name		= "YFSVL.GetEndpoints",
611025db80cSDavid Howells 	.op		= afs_YFSVL_GetEndpoints,
612bf99a53cSDavid Howells 	.deliver	= afs_deliver_yfsvl_get_endpoints,
613bf99a53cSDavid Howells 	.destructor	= afs_vl_get_addrs_u_destructor,
614bf99a53cSDavid Howells };
615bf99a53cSDavid Howells 
616bf99a53cSDavid Howells /*
617bf99a53cSDavid Howells  * Dispatch an operation to get the addresses for a server, where the server is
618bf99a53cSDavid Howells  * nominated by UUID.
619bf99a53cSDavid Howells  */
afs_yfsvl_get_endpoints(struct afs_vl_cursor * vc,const uuid_t * uuid)6200a5143f2SDavid Howells struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
621bf99a53cSDavid Howells 					      const uuid_t *uuid)
622bf99a53cSDavid Howells {
623bf99a53cSDavid Howells 	struct afs_call *call;
6240a5143f2SDavid Howells 	struct afs_net *net = vc->cell->net;
625bf99a53cSDavid Howells 	__be32 *bp;
626bf99a53cSDavid Howells 
627bf99a53cSDavid Howells 	_enter("");
628bf99a53cSDavid Howells 
629bf99a53cSDavid Howells 	call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
630bf99a53cSDavid Howells 				   sizeof(__be32) * 2 + sizeof(*uuid),
631bf99a53cSDavid Howells 				   sizeof(struct in6_addr) + sizeof(__be32) * 3);
632bf99a53cSDavid Howells 	if (!call)
633bf99a53cSDavid Howells 		return ERR_PTR(-ENOMEM);
634bf99a53cSDavid Howells 
6350a5143f2SDavid Howells 	call->key = vc->key;
636ffba718eSDavid Howells 	call->ret_alist = NULL;
63794f699c9SDavid Howells 	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
638bf99a53cSDavid Howells 
639bf99a53cSDavid Howells 	/* Marshall the parameters */
640bf99a53cSDavid Howells 	bp = call->request;
641bf99a53cSDavid Howells 	*bp++ = htonl(YVLGETENDPOINTS);
642bf99a53cSDavid Howells 	*bp++ = htonl(YFS_SERVER_UUID);
643bf99a53cSDavid Howells 	memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
644bf99a53cSDavid Howells 
645025db80cSDavid Howells 	trace_afs_make_vl_call(call);
6460b9bf381SDavid Howells 	afs_make_call(&vc->ac, call, GFP_KERNEL);
6470b9bf381SDavid Howells 	return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
648bf99a53cSDavid Howells }
649c3e9f888SDavid Howells 
650c3e9f888SDavid Howells /*
651c3e9f888SDavid Howells  * Deliver reply data to a YFSVL.GetCellName operation.
652c3e9f888SDavid Howells  */
afs_deliver_yfsvl_get_cell_name(struct afs_call * call)653c3e9f888SDavid Howells static int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
654c3e9f888SDavid Howells {
655c3e9f888SDavid Howells 	char *cell_name;
656c3e9f888SDavid Howells 	u32 namesz, paddedsz;
657c3e9f888SDavid Howells 	int ret;
658c3e9f888SDavid Howells 
659c3e9f888SDavid Howells 	_enter("{%u,%zu/%u}",
660c3e9f888SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), call->count);
661c3e9f888SDavid Howells 
662c3e9f888SDavid Howells 	switch (call->unmarshall) {
663c3e9f888SDavid Howells 	case 0:
664c3e9f888SDavid Howells 		afs_extract_to_tmp(call);
665c3e9f888SDavid Howells 		call->unmarshall++;
666c3e9f888SDavid Howells 
667df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract the cell name length */
668c3e9f888SDavid Howells 	case 1:
669c3e9f888SDavid Howells 		ret = afs_extract_data(call, true);
670c3e9f888SDavid Howells 		if (ret < 0)
671c3e9f888SDavid Howells 			return ret;
672c3e9f888SDavid Howells 
673c3e9f888SDavid Howells 		namesz = ntohl(call->tmp);
674*7673030eSDavid Howells 		if (namesz > YFS_VL_MAXCELLNAME)
675c3e9f888SDavid Howells 			return afs_protocol_error(call, afs_eproto_cellname_len);
676c3e9f888SDavid Howells 		paddedsz = (namesz + 3) & ~3;
677c3e9f888SDavid Howells 		call->count = namesz;
678c3e9f888SDavid Howells 		call->count2 = paddedsz - namesz;
679c3e9f888SDavid Howells 
680c3e9f888SDavid Howells 		cell_name = kmalloc(namesz + 1, GFP_KERNEL);
681c3e9f888SDavid Howells 		if (!cell_name)
682c3e9f888SDavid Howells 			return -ENOMEM;
683c3e9f888SDavid Howells 		cell_name[namesz] = 0;
684c3e9f888SDavid Howells 		call->ret_str = cell_name;
685c3e9f888SDavid Howells 
686c3e9f888SDavid Howells 		afs_extract_begin(call, cell_name, namesz);
687c3e9f888SDavid Howells 		call->unmarshall++;
688c3e9f888SDavid Howells 
689df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract cell name */
690c3e9f888SDavid Howells 	case 2:
691c3e9f888SDavid Howells 		ret = afs_extract_data(call, true);
692c3e9f888SDavid Howells 		if (ret < 0)
693c3e9f888SDavid Howells 			return ret;
694c3e9f888SDavid Howells 
695c3e9f888SDavid Howells 		afs_extract_discard(call, call->count2);
696c3e9f888SDavid Howells 		call->unmarshall++;
697c3e9f888SDavid Howells 
698df561f66SGustavo A. R. Silva 		fallthrough;	/* and extract padding */
699c3e9f888SDavid Howells 	case 3:
700c3e9f888SDavid Howells 		ret = afs_extract_data(call, false);
701c3e9f888SDavid Howells 		if (ret < 0)
702c3e9f888SDavid Howells 			return ret;
703c3e9f888SDavid Howells 
704c3e9f888SDavid Howells 		call->unmarshall++;
705c3e9f888SDavid Howells 		break;
706c3e9f888SDavid Howells 	}
707c3e9f888SDavid Howells 
708c3e9f888SDavid Howells 	_leave(" = 0 [done]");
709c3e9f888SDavid Howells 	return 0;
710c3e9f888SDavid Howells }
711c3e9f888SDavid Howells 
afs_destroy_yfsvl_get_cell_name(struct afs_call * call)712c3e9f888SDavid Howells static void afs_destroy_yfsvl_get_cell_name(struct afs_call *call)
713c3e9f888SDavid Howells {
714c3e9f888SDavid Howells 	kfree(call->ret_str);
715c3e9f888SDavid Howells 	afs_flat_call_destructor(call);
716c3e9f888SDavid Howells }
717c3e9f888SDavid Howells 
718c3e9f888SDavid Howells /*
719c3e9f888SDavid Howells  * VL.GetCapabilities operation type
720c3e9f888SDavid Howells  */
721c3e9f888SDavid Howells static const struct afs_call_type afs_YFSVLGetCellName = {
722c3e9f888SDavid Howells 	.name		= "YFSVL.GetCellName",
723c3e9f888SDavid Howells 	.op		= afs_YFSVL_GetCellName,
724c3e9f888SDavid Howells 	.deliver	= afs_deliver_yfsvl_get_cell_name,
725c3e9f888SDavid Howells 	.destructor	= afs_destroy_yfsvl_get_cell_name,
726c3e9f888SDavid Howells };
727c3e9f888SDavid Howells 
728c3e9f888SDavid Howells /*
729c3e9f888SDavid Howells  * Probe a volume server for the capabilities that it supports.  This can
730c3e9f888SDavid Howells  * return up to 196 words.
731c3e9f888SDavid Howells  *
732c3e9f888SDavid Howells  * We use this to probe for service upgrade to determine what the server at the
733c3e9f888SDavid Howells  * other end supports.
734c3e9f888SDavid Howells  */
afs_yfsvl_get_cell_name(struct afs_vl_cursor * vc)735c3e9f888SDavid Howells char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
736c3e9f888SDavid Howells {
737c3e9f888SDavid Howells 	struct afs_call *call;
738c3e9f888SDavid Howells 	struct afs_net *net = vc->cell->net;
739c3e9f888SDavid Howells 	__be32 *bp;
740c3e9f888SDavid Howells 
741c3e9f888SDavid Howells 	_enter("");
742c3e9f888SDavid Howells 
743c3e9f888SDavid Howells 	call = afs_alloc_flat_call(net, &afs_YFSVLGetCellName, 1 * 4, 0);
744c3e9f888SDavid Howells 	if (!call)
745c3e9f888SDavid Howells 		return ERR_PTR(-ENOMEM);
746c3e9f888SDavid Howells 
747c3e9f888SDavid Howells 	call->key = vc->key;
748c3e9f888SDavid Howells 	call->ret_str = NULL;
749c3e9f888SDavid Howells 	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
750c3e9f888SDavid Howells 
751c3e9f888SDavid Howells 	/* marshall the parameters */
752c3e9f888SDavid Howells 	bp = call->request;
753c3e9f888SDavid Howells 	*bp++ = htonl(YVLGETCELLNAME);
754c3e9f888SDavid Howells 
755c3e9f888SDavid Howells 	/* Can't take a ref on server */
756c3e9f888SDavid Howells 	trace_afs_make_vl_call(call);
757c3e9f888SDavid Howells 	afs_make_call(&vc->ac, call, GFP_KERNEL);
758c3e9f888SDavid Howells 	return (char *)afs_wait_for_call_to_complete(call, &vc->ac);
759c3e9f888SDavid Howells }
760