xref: /kernel/linux/linux-5.10/fs/afs/vlclient.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* AFS Volume Location Service client
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/gfp.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/sched.h>
118c2ecf20Sopenharmony_ci#include "afs_fs.h"
128c2ecf20Sopenharmony_ci#include "internal.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Deliver reply data to a VL.GetEntryByNameU call.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_cistatic int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	struct afs_uvldbentry__xdr *uvldb;
208c2ecf20Sopenharmony_ci	struct afs_vldb_entry *entry;
218c2ecf20Sopenharmony_ci	bool new_only = false;
228c2ecf20Sopenharmony_ci	u32 tmp, nr_servers, vlflags;
238c2ecf20Sopenharmony_ci	int i, ret;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	_enter("");
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
288c2ecf20Sopenharmony_ci	if (ret < 0)
298c2ecf20Sopenharmony_ci		return ret;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
328c2ecf20Sopenharmony_ci	uvldb = call->buffer;
338c2ecf20Sopenharmony_ci	entry = call->ret_vldb;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	nr_servers = ntohl(uvldb->nServers);
368c2ecf20Sopenharmony_ci	if (nr_servers > AFS_NMAXNSERVERS)
378c2ecf20Sopenharmony_ci		nr_servers = AFS_NMAXNSERVERS;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
408c2ecf20Sopenharmony_ci		entry->name[i] = (u8)ntohl(uvldb->name[i]);
418c2ecf20Sopenharmony_ci	entry->name[i] = 0;
428c2ecf20Sopenharmony_ci	entry->name_len = strlen(entry->name);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	/* If there is a new replication site that we can use, ignore all the
458c2ecf20Sopenharmony_ci	 * sites that aren't marked as new.
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	for (i = 0; i < nr_servers; i++) {
488c2ecf20Sopenharmony_ci		tmp = ntohl(uvldb->serverFlags[i]);
498c2ecf20Sopenharmony_ci		if (!(tmp & AFS_VLSF_DONTUSE) &&
508c2ecf20Sopenharmony_ci		    (tmp & AFS_VLSF_NEWREPSITE))
518c2ecf20Sopenharmony_ci			new_only = true;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	vlflags = ntohl(uvldb->flags);
558c2ecf20Sopenharmony_ci	for (i = 0; i < nr_servers; i++) {
568c2ecf20Sopenharmony_ci		struct afs_uuid__xdr *xdr;
578c2ecf20Sopenharmony_ci		struct afs_uuid *uuid;
588c2ecf20Sopenharmony_ci		int j;
598c2ecf20Sopenharmony_ci		int n = entry->nr_servers;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		tmp = ntohl(uvldb->serverFlags[i]);
628c2ecf20Sopenharmony_ci		if (tmp & AFS_VLSF_DONTUSE ||
638c2ecf20Sopenharmony_ci		    (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
648c2ecf20Sopenharmony_ci			continue;
658c2ecf20Sopenharmony_ci		if (tmp & AFS_VLSF_RWVOL) {
668c2ecf20Sopenharmony_ci			entry->fs_mask[n] |= AFS_VOL_VTM_RW;
678c2ecf20Sopenharmony_ci			if (vlflags & AFS_VLF_BACKEXISTS)
688c2ecf20Sopenharmony_ci				entry->fs_mask[n] |= AFS_VOL_VTM_BAK;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci		if (tmp & AFS_VLSF_ROVOL)
718c2ecf20Sopenharmony_ci			entry->fs_mask[n] |= AFS_VOL_VTM_RO;
728c2ecf20Sopenharmony_ci		if (!entry->fs_mask[n])
738c2ecf20Sopenharmony_ci			continue;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		xdr = &uvldb->serverNumber[i];
768c2ecf20Sopenharmony_ci		uuid = (struct afs_uuid *)&entry->fs_server[n];
778c2ecf20Sopenharmony_ci		uuid->time_low			= xdr->time_low;
788c2ecf20Sopenharmony_ci		uuid->time_mid			= htons(ntohl(xdr->time_mid));
798c2ecf20Sopenharmony_ci		uuid->time_hi_and_version	= htons(ntohl(xdr->time_hi_and_version));
808c2ecf20Sopenharmony_ci		uuid->clock_seq_hi_and_reserved	= (u8)ntohl(xdr->clock_seq_hi_and_reserved);
818c2ecf20Sopenharmony_ci		uuid->clock_seq_low		= (u8)ntohl(xdr->clock_seq_low);
828c2ecf20Sopenharmony_ci		for (j = 0; j < 6; j++)
838c2ecf20Sopenharmony_ci			uuid->node[j] = (u8)ntohl(xdr->node[j]);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		entry->addr_version[n] = ntohl(uvldb->serverUnique[i]);
868c2ecf20Sopenharmony_ci		entry->nr_servers++;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	for (i = 0; i < AFS_MAXTYPES; i++)
908c2ecf20Sopenharmony_ci		entry->vid[i] = ntohl(uvldb->volumeId[i]);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (vlflags & AFS_VLF_RWEXISTS)
938c2ecf20Sopenharmony_ci		__set_bit(AFS_VLDB_HAS_RW, &entry->flags);
948c2ecf20Sopenharmony_ci	if (vlflags & AFS_VLF_ROEXISTS)
958c2ecf20Sopenharmony_ci		__set_bit(AFS_VLDB_HAS_RO, &entry->flags);
968c2ecf20Sopenharmony_ci	if (vlflags & AFS_VLF_BACKEXISTS)
978c2ecf20Sopenharmony_ci		__set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (!(vlflags & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
1008c2ecf20Sopenharmony_ci		entry->error = -ENOMEDIUM;
1018c2ecf20Sopenharmony_ci		__set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	__set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
1058c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	kfree(call->ret_vldb);
1128c2ecf20Sopenharmony_ci	afs_flat_call_destructor(call);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/*
1168c2ecf20Sopenharmony_ci * VL.GetEntryByNameU operation type.
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXVLGetEntryByNameU = {
1198c2ecf20Sopenharmony_ci	.name		= "VL.GetEntryByNameU",
1208c2ecf20Sopenharmony_ci	.op		= afs_VL_GetEntryByNameU,
1218c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_vl_get_entry_by_name_u,
1228c2ecf20Sopenharmony_ci	.destructor	= afs_destroy_vl_get_entry_by_name_u,
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/*
1268c2ecf20Sopenharmony_ci * Dispatch a get volume entry by name or ID operation (uuid variant).  If the
1278c2ecf20Sopenharmony_ci * volname is a decimal number then it's a volume ID not a volume name.
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_cistruct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
1308c2ecf20Sopenharmony_ci						  const char *volname,
1318c2ecf20Sopenharmony_ci						  int volnamesz)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct afs_vldb_entry *entry;
1348c2ecf20Sopenharmony_ci	struct afs_call *call;
1358c2ecf20Sopenharmony_ci	struct afs_net *net = vc->cell->net;
1368c2ecf20Sopenharmony_ci	size_t reqsz, padsz;
1378c2ecf20Sopenharmony_ci	__be32 *bp;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	_enter("");
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	padsz = (4 - (volnamesz & 3)) & 3;
1428c2ecf20Sopenharmony_ci	reqsz = 8 + volnamesz + padsz;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
1458c2ecf20Sopenharmony_ci	if (!entry)
1468c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
1498c2ecf20Sopenharmony_ci				   sizeof(struct afs_uvldbentry__xdr));
1508c2ecf20Sopenharmony_ci	if (!call) {
1518c2ecf20Sopenharmony_ci		kfree(entry);
1528c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	call->key = vc->key;
1568c2ecf20Sopenharmony_ci	call->ret_vldb = entry;
1578c2ecf20Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Marshall the parameters */
1608c2ecf20Sopenharmony_ci	bp = call->request;
1618c2ecf20Sopenharmony_ci	*bp++ = htonl(VLGETENTRYBYNAMEU);
1628c2ecf20Sopenharmony_ci	*bp++ = htonl(volnamesz);
1638c2ecf20Sopenharmony_ci	memcpy(bp, volname, volnamesz);
1648c2ecf20Sopenharmony_ci	if (padsz > 0)
1658c2ecf20Sopenharmony_ci		memset((void *)bp + volnamesz, 0, padsz);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	trace_afs_make_vl_call(call);
1688c2ecf20Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
1698c2ecf20Sopenharmony_ci	return (struct afs_vldb_entry *)afs_wait_for_call_to_complete(call, &vc->ac);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/*
1738c2ecf20Sopenharmony_ci * Deliver reply data to a VL.GetAddrsU call.
1748c2ecf20Sopenharmony_ci *
1758c2ecf20Sopenharmony_ci *	GetAddrsU(IN ListAddrByAttributes *inaddr,
1768c2ecf20Sopenharmony_ci *		  OUT afsUUID *uuidp1,
1778c2ecf20Sopenharmony_ci *		  OUT uint32_t *uniquifier,
1788c2ecf20Sopenharmony_ci *		  OUT uint32_t *nentries,
1798c2ecf20Sopenharmony_ci *		  OUT bulkaddrs *blkaddrs);
1808c2ecf20Sopenharmony_ci */
1818c2ecf20Sopenharmony_cistatic int afs_deliver_vl_get_addrs_u(struct afs_call *call)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct afs_addr_list *alist;
1848c2ecf20Sopenharmony_ci	__be32 *bp;
1858c2ecf20Sopenharmony_ci	u32 uniquifier, nentries, count;
1868c2ecf20Sopenharmony_ci	int i, ret;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	_enter("{%u,%zu/%u}",
1898c2ecf20Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
1928c2ecf20Sopenharmony_ci	case 0:
1938c2ecf20Sopenharmony_ci		afs_extract_to_buf(call,
1948c2ecf20Sopenharmony_ci				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
1958c2ecf20Sopenharmony_ci		call->unmarshall++;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		/* Extract the returned uuid, uniquifier, nentries and
1988c2ecf20Sopenharmony_ci		 * blkaddrs size */
1998c2ecf20Sopenharmony_ci		fallthrough;
2008c2ecf20Sopenharmony_ci	case 1:
2018c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
2028c2ecf20Sopenharmony_ci		if (ret < 0)
2038c2ecf20Sopenharmony_ci			return ret;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		bp = call->buffer + sizeof(struct afs_uuid__xdr);
2068c2ecf20Sopenharmony_ci		uniquifier	= ntohl(*bp++);
2078c2ecf20Sopenharmony_ci		nentries	= ntohl(*bp++);
2088c2ecf20Sopenharmony_ci		count		= ntohl(*bp);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		nentries = min(nentries, count);
2118c2ecf20Sopenharmony_ci		alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
2128c2ecf20Sopenharmony_ci		if (!alist)
2138c2ecf20Sopenharmony_ci			return -ENOMEM;
2148c2ecf20Sopenharmony_ci		alist->version = uniquifier;
2158c2ecf20Sopenharmony_ci		call->ret_alist = alist;
2168c2ecf20Sopenharmony_ci		call->count = count;
2178c2ecf20Sopenharmony_ci		call->count2 = nentries;
2188c2ecf20Sopenharmony_ci		call->unmarshall++;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	more_entries:
2218c2ecf20Sopenharmony_ci		count = min(call->count, 4U);
2228c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, count * sizeof(__be32));
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		fallthrough;	/* and extract entries */
2258c2ecf20Sopenharmony_ci	case 2:
2268c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, call->count > 4);
2278c2ecf20Sopenharmony_ci		if (ret < 0)
2288c2ecf20Sopenharmony_ci			return ret;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		alist = call->ret_alist;
2318c2ecf20Sopenharmony_ci		bp = call->buffer;
2328c2ecf20Sopenharmony_ci		count = min(call->count, 4U);
2338c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++)
2348c2ecf20Sopenharmony_ci			if (alist->nr_addrs < call->count2)
2358c2ecf20Sopenharmony_ci				afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		call->count -= count;
2388c2ecf20Sopenharmony_ci		if (call->count > 0)
2398c2ecf20Sopenharmony_ci			goto more_entries;
2408c2ecf20Sopenharmony_ci		call->unmarshall++;
2418c2ecf20Sopenharmony_ci		break;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
2458c2ecf20Sopenharmony_ci	return 0;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic void afs_vl_get_addrs_u_destructor(struct afs_call *call)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	afs_put_addrlist(call->ret_alist);
2518c2ecf20Sopenharmony_ci	return afs_flat_call_destructor(call);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/*
2558c2ecf20Sopenharmony_ci * VL.GetAddrsU operation type.
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXVLGetAddrsU = {
2588c2ecf20Sopenharmony_ci	.name		= "VL.GetAddrsU",
2598c2ecf20Sopenharmony_ci	.op		= afs_VL_GetAddrsU,
2608c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_vl_get_addrs_u,
2618c2ecf20Sopenharmony_ci	.destructor	= afs_vl_get_addrs_u_destructor,
2628c2ecf20Sopenharmony_ci};
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/*
2658c2ecf20Sopenharmony_ci * Dispatch an operation to get the addresses for a server, where the server is
2668c2ecf20Sopenharmony_ci * nominated by UUID.
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistruct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
2698c2ecf20Sopenharmony_ci					 const uuid_t *uuid)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct afs_ListAddrByAttributes__xdr *r;
2728c2ecf20Sopenharmony_ci	const struct afs_uuid *u = (const struct afs_uuid *)uuid;
2738c2ecf20Sopenharmony_ci	struct afs_call *call;
2748c2ecf20Sopenharmony_ci	struct afs_net *net = vc->cell->net;
2758c2ecf20Sopenharmony_ci	__be32 *bp;
2768c2ecf20Sopenharmony_ci	int i;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	_enter("");
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
2818c2ecf20Sopenharmony_ci				   sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
2828c2ecf20Sopenharmony_ci				   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
2838c2ecf20Sopenharmony_ci	if (!call)
2848c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	call->key = vc->key;
2878c2ecf20Sopenharmony_ci	call->ret_alist = NULL;
2888c2ecf20Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* Marshall the parameters */
2918c2ecf20Sopenharmony_ci	bp = call->request;
2928c2ecf20Sopenharmony_ci	*bp++ = htonl(VLGETADDRSU);
2938c2ecf20Sopenharmony_ci	r = (struct afs_ListAddrByAttributes__xdr *)bp;
2948c2ecf20Sopenharmony_ci	r->Mask		= htonl(AFS_VLADDR_UUID);
2958c2ecf20Sopenharmony_ci	r->ipaddr	= 0;
2968c2ecf20Sopenharmony_ci	r->index	= 0;
2978c2ecf20Sopenharmony_ci	r->spare	= 0;
2988c2ecf20Sopenharmony_ci	r->uuid.time_low			= u->time_low;
2998c2ecf20Sopenharmony_ci	r->uuid.time_mid			= htonl(ntohs(u->time_mid));
3008c2ecf20Sopenharmony_ci	r->uuid.time_hi_and_version		= htonl(ntohs(u->time_hi_and_version));
3018c2ecf20Sopenharmony_ci	r->uuid.clock_seq_hi_and_reserved 	= htonl(u->clock_seq_hi_and_reserved);
3028c2ecf20Sopenharmony_ci	r->uuid.clock_seq_low			= htonl(u->clock_seq_low);
3038c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
3048c2ecf20Sopenharmony_ci		r->uuid.node[i] = htonl(u->node[i]);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	trace_afs_make_vl_call(call);
3078c2ecf20Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
3088c2ecf20Sopenharmony_ci	return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/*
3128c2ecf20Sopenharmony_ci * Deliver reply data to an VL.GetCapabilities operation.
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_cistatic int afs_deliver_vl_get_capabilities(struct afs_call *call)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	u32 count;
3178c2ecf20Sopenharmony_ci	int ret;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	_enter("{%u,%zu/%u}",
3208c2ecf20Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
3238c2ecf20Sopenharmony_ci	case 0:
3248c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
3258c2ecf20Sopenharmony_ci		call->unmarshall++;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		fallthrough;	/* and extract the capabilities word count */
3288c2ecf20Sopenharmony_ci	case 1:
3298c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
3308c2ecf20Sopenharmony_ci		if (ret < 0)
3318c2ecf20Sopenharmony_ci			return ret;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		count = ntohl(call->tmp);
3348c2ecf20Sopenharmony_ci		call->count = count;
3358c2ecf20Sopenharmony_ci		call->count2 = count;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		call->unmarshall++;
3388c2ecf20Sopenharmony_ci		afs_extract_discard(call, count * sizeof(__be32));
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		fallthrough;	/* and extract capabilities words */
3418c2ecf20Sopenharmony_ci	case 2:
3428c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
3438c2ecf20Sopenharmony_ci		if (ret < 0)
3448c2ecf20Sopenharmony_ci			return ret;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		/* TODO: Examine capabilities */
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		call->unmarshall++;
3498c2ecf20Sopenharmony_ci		break;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
3538c2ecf20Sopenharmony_ci	return 0;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void afs_destroy_vl_get_capabilities(struct afs_call *call)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	afs_put_vlserver(call->net, call->vlserver);
3598c2ecf20Sopenharmony_ci	afs_flat_call_destructor(call);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci/*
3638c2ecf20Sopenharmony_ci * VL.GetCapabilities operation type
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXVLGetCapabilities = {
3668c2ecf20Sopenharmony_ci	.name		= "VL.GetCapabilities",
3678c2ecf20Sopenharmony_ci	.op		= afs_VL_GetCapabilities,
3688c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_vl_get_capabilities,
3698c2ecf20Sopenharmony_ci	.done		= afs_vlserver_probe_result,
3708c2ecf20Sopenharmony_ci	.destructor	= afs_destroy_vl_get_capabilities,
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/*
3748c2ecf20Sopenharmony_ci * Probe a volume server for the capabilities that it supports.  This can
3758c2ecf20Sopenharmony_ci * return up to 196 words.
3768c2ecf20Sopenharmony_ci *
3778c2ecf20Sopenharmony_ci * We use this to probe for service upgrade to determine what the server at the
3788c2ecf20Sopenharmony_ci * other end supports.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_cistruct afs_call *afs_vl_get_capabilities(struct afs_net *net,
3818c2ecf20Sopenharmony_ci					 struct afs_addr_cursor *ac,
3828c2ecf20Sopenharmony_ci					 struct key *key,
3838c2ecf20Sopenharmony_ci					 struct afs_vlserver *server,
3848c2ecf20Sopenharmony_ci					 unsigned int server_index)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	struct afs_call *call;
3878c2ecf20Sopenharmony_ci	__be32 *bp;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	_enter("");
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
3928c2ecf20Sopenharmony_ci	if (!call)
3938c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	call->key = key;
3968c2ecf20Sopenharmony_ci	call->vlserver = afs_get_vlserver(server);
3978c2ecf20Sopenharmony_ci	call->server_index = server_index;
3988c2ecf20Sopenharmony_ci	call->upgrade = true;
3998c2ecf20Sopenharmony_ci	call->async = true;
4008c2ecf20Sopenharmony_ci	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/* marshall the parameters */
4038c2ecf20Sopenharmony_ci	bp = call->request;
4048c2ecf20Sopenharmony_ci	*bp++ = htonl(VLGETCAPABILITIES);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* Can't take a ref on server */
4078c2ecf20Sopenharmony_ci	trace_afs_make_vl_call(call);
4088c2ecf20Sopenharmony_ci	afs_make_call(ac, call, GFP_KERNEL);
4098c2ecf20Sopenharmony_ci	return call;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci/*
4138c2ecf20Sopenharmony_ci * Deliver reply data to a YFSVL.GetEndpoints call.
4148c2ecf20Sopenharmony_ci *
4158c2ecf20Sopenharmony_ci *	GetEndpoints(IN yfsServerAttributes *attr,
4168c2ecf20Sopenharmony_ci *		     OUT opr_uuid *uuid,
4178c2ecf20Sopenharmony_ci *		     OUT afs_int32 *uniquifier,
4188c2ecf20Sopenharmony_ci *		     OUT endpoints *fsEndpoints,
4198c2ecf20Sopenharmony_ci *		     OUT endpoints *volEndpoints)
4208c2ecf20Sopenharmony_ci */
4218c2ecf20Sopenharmony_cistatic int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct afs_addr_list *alist;
4248c2ecf20Sopenharmony_ci	__be32 *bp;
4258c2ecf20Sopenharmony_ci	u32 uniquifier, size;
4268c2ecf20Sopenharmony_ci	int ret;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	_enter("{%u,%zu,%u}",
4298c2ecf20Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count2);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
4328c2ecf20Sopenharmony_ci	case 0:
4338c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, sizeof(uuid_t) + 3 * sizeof(__be32));
4348c2ecf20Sopenharmony_ci		call->unmarshall = 1;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		/* Extract the returned uuid, uniquifier, fsEndpoints count and
4378c2ecf20Sopenharmony_ci		 * either the first fsEndpoint type or the volEndpoints
4388c2ecf20Sopenharmony_ci		 * count if there are no fsEndpoints. */
4398c2ecf20Sopenharmony_ci		fallthrough;
4408c2ecf20Sopenharmony_ci	case 1:
4418c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
4428c2ecf20Sopenharmony_ci		if (ret < 0)
4438c2ecf20Sopenharmony_ci			return ret;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		bp = call->buffer + sizeof(uuid_t);
4468c2ecf20Sopenharmony_ci		uniquifier	= ntohl(*bp++);
4478c2ecf20Sopenharmony_ci		call->count	= ntohl(*bp++);
4488c2ecf20Sopenharmony_ci		call->count2	= ntohl(*bp); /* Type or next count */
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		if (call->count > YFS_MAXENDPOINTS)
4518c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
4548c2ecf20Sopenharmony_ci		if (!alist)
4558c2ecf20Sopenharmony_ci			return -ENOMEM;
4568c2ecf20Sopenharmony_ci		alist->version = uniquifier;
4578c2ecf20Sopenharmony_ci		call->ret_alist = alist;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		if (call->count == 0)
4608c2ecf20Sopenharmony_ci			goto extract_volendpoints;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	next_fsendpoint:
4638c2ecf20Sopenharmony_ci		switch (call->count2) {
4648c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
4658c2ecf20Sopenharmony_ci			size = sizeof(__be32) * (1 + 1 + 1);
4668c2ecf20Sopenharmony_ci			break;
4678c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
4688c2ecf20Sopenharmony_ci			size = sizeof(__be32) * (1 + 4 + 1);
4698c2ecf20Sopenharmony_ci			break;
4708c2ecf20Sopenharmony_ci		default:
4718c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		size += sizeof(__be32);
4758c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, size);
4768c2ecf20Sopenharmony_ci		call->unmarshall = 2;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		fallthrough;	/* and extract fsEndpoints[] entries */
4798c2ecf20Sopenharmony_ci	case 2:
4808c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
4818c2ecf20Sopenharmony_ci		if (ret < 0)
4828c2ecf20Sopenharmony_ci			return ret;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		alist = call->ret_alist;
4858c2ecf20Sopenharmony_ci		bp = call->buffer;
4868c2ecf20Sopenharmony_ci		switch (call->count2) {
4878c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
4888c2ecf20Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 2)
4898c2ecf20Sopenharmony_ci				return afs_protocol_error(
4908c2ecf20Sopenharmony_ci					call, afs_eproto_yvl_fsendpt4_len);
4918c2ecf20Sopenharmony_ci			afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
4928c2ecf20Sopenharmony_ci			bp += 3;
4938c2ecf20Sopenharmony_ci			break;
4948c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
4958c2ecf20Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 5)
4968c2ecf20Sopenharmony_ci				return afs_protocol_error(
4978c2ecf20Sopenharmony_ci					call, afs_eproto_yvl_fsendpt6_len);
4988c2ecf20Sopenharmony_ci			afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
4998c2ecf20Sopenharmony_ci			bp += 6;
5008c2ecf20Sopenharmony_ci			break;
5018c2ecf20Sopenharmony_ci		default:
5028c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
5038c2ecf20Sopenharmony_ci		}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		/* Got either the type of the next entry or the count of
5068c2ecf20Sopenharmony_ci		 * volEndpoints if no more fsEndpoints.
5078c2ecf20Sopenharmony_ci		 */
5088c2ecf20Sopenharmony_ci		call->count2 = ntohl(*bp++);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		call->count--;
5118c2ecf20Sopenharmony_ci		if (call->count > 0)
5128c2ecf20Sopenharmony_ci			goto next_fsendpoint;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	extract_volendpoints:
5158c2ecf20Sopenharmony_ci		/* Extract the list of volEndpoints. */
5168c2ecf20Sopenharmony_ci		call->count = call->count2;
5178c2ecf20Sopenharmony_ci		if (!call->count)
5188c2ecf20Sopenharmony_ci			goto end;
5198c2ecf20Sopenharmony_ci		if (call->count > YFS_MAXENDPOINTS)
5208c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, 1 * sizeof(__be32));
5238c2ecf20Sopenharmony_ci		call->unmarshall = 3;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		/* Extract the type of volEndpoints[0].  Normally we would
5268c2ecf20Sopenharmony_ci		 * extract the type of the next endpoint when we extract the
5278c2ecf20Sopenharmony_ci		 * data of the current one, but this is the first...
5288c2ecf20Sopenharmony_ci		 */
5298c2ecf20Sopenharmony_ci		fallthrough;
5308c2ecf20Sopenharmony_ci	case 3:
5318c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
5328c2ecf20Sopenharmony_ci		if (ret < 0)
5338c2ecf20Sopenharmony_ci			return ret;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		bp = call->buffer;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	next_volendpoint:
5388c2ecf20Sopenharmony_ci		call->count2 = ntohl(*bp++);
5398c2ecf20Sopenharmony_ci		switch (call->count2) {
5408c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
5418c2ecf20Sopenharmony_ci			size = sizeof(__be32) * (1 + 1 + 1);
5428c2ecf20Sopenharmony_ci			break;
5438c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
5448c2ecf20Sopenharmony_ci			size = sizeof(__be32) * (1 + 4 + 1);
5458c2ecf20Sopenharmony_ci			break;
5468c2ecf20Sopenharmony_ci		default:
5478c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
5488c2ecf20Sopenharmony_ci		}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		if (call->count > 1)
5518c2ecf20Sopenharmony_ci			size += sizeof(__be32); /* Get next type too */
5528c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, size);
5538c2ecf20Sopenharmony_ci		call->unmarshall = 4;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		fallthrough;	/* and extract volEndpoints[] entries */
5568c2ecf20Sopenharmony_ci	case 4:
5578c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
5588c2ecf20Sopenharmony_ci		if (ret < 0)
5598c2ecf20Sopenharmony_ci			return ret;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		bp = call->buffer;
5628c2ecf20Sopenharmony_ci		switch (call->count2) {
5638c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV4:
5648c2ecf20Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 2)
5658c2ecf20Sopenharmony_ci				return afs_protocol_error(
5668c2ecf20Sopenharmony_ci					call, afs_eproto_yvl_vlendpt4_len);
5678c2ecf20Sopenharmony_ci			bp += 3;
5688c2ecf20Sopenharmony_ci			break;
5698c2ecf20Sopenharmony_ci		case YFS_ENDPOINT_IPV6:
5708c2ecf20Sopenharmony_ci			if (ntohl(bp[0]) != sizeof(__be32) * 5)
5718c2ecf20Sopenharmony_ci				return afs_protocol_error(
5728c2ecf20Sopenharmony_ci					call, afs_eproto_yvl_vlendpt6_len);
5738c2ecf20Sopenharmony_ci			bp += 6;
5748c2ecf20Sopenharmony_ci			break;
5758c2ecf20Sopenharmony_ci		default:
5768c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
5778c2ecf20Sopenharmony_ci		}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		/* Got either the type of the next entry or the count of
5808c2ecf20Sopenharmony_ci		 * volEndpoints if no more fsEndpoints.
5818c2ecf20Sopenharmony_ci		 */
5828c2ecf20Sopenharmony_ci		call->count--;
5838c2ecf20Sopenharmony_ci		if (call->count > 0)
5848c2ecf20Sopenharmony_ci			goto next_volendpoint;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	end:
5878c2ecf20Sopenharmony_ci		afs_extract_discard(call, 0);
5888c2ecf20Sopenharmony_ci		call->unmarshall = 5;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		fallthrough;	/* Done */
5918c2ecf20Sopenharmony_ci	case 5:
5928c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
5938c2ecf20Sopenharmony_ci		if (ret < 0)
5948c2ecf20Sopenharmony_ci			return ret;
5958c2ecf20Sopenharmony_ci		call->unmarshall = 6;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	case 6:
5988c2ecf20Sopenharmony_ci		break;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
6028c2ecf20Sopenharmony_ci	return 0;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci/*
6068c2ecf20Sopenharmony_ci * YFSVL.GetEndpoints operation type.
6078c2ecf20Sopenharmony_ci */
6088c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_YFSVLGetEndpoints = {
6098c2ecf20Sopenharmony_ci	.name		= "YFSVL.GetEndpoints",
6108c2ecf20Sopenharmony_ci	.op		= afs_YFSVL_GetEndpoints,
6118c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_yfsvl_get_endpoints,
6128c2ecf20Sopenharmony_ci	.destructor	= afs_vl_get_addrs_u_destructor,
6138c2ecf20Sopenharmony_ci};
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci/*
6168c2ecf20Sopenharmony_ci * Dispatch an operation to get the addresses for a server, where the server is
6178c2ecf20Sopenharmony_ci * nominated by UUID.
6188c2ecf20Sopenharmony_ci */
6198c2ecf20Sopenharmony_cistruct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
6208c2ecf20Sopenharmony_ci					      const uuid_t *uuid)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	struct afs_call *call;
6238c2ecf20Sopenharmony_ci	struct afs_net *net = vc->cell->net;
6248c2ecf20Sopenharmony_ci	__be32 *bp;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	_enter("");
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
6298c2ecf20Sopenharmony_ci				   sizeof(__be32) * 2 + sizeof(*uuid),
6308c2ecf20Sopenharmony_ci				   sizeof(struct in6_addr) + sizeof(__be32) * 3);
6318c2ecf20Sopenharmony_ci	if (!call)
6328c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	call->key = vc->key;
6358c2ecf20Sopenharmony_ci	call->ret_alist = NULL;
6368c2ecf20Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* Marshall the parameters */
6398c2ecf20Sopenharmony_ci	bp = call->request;
6408c2ecf20Sopenharmony_ci	*bp++ = htonl(YVLGETENDPOINTS);
6418c2ecf20Sopenharmony_ci	*bp++ = htonl(YFS_SERVER_UUID);
6428c2ecf20Sopenharmony_ci	memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	trace_afs_make_vl_call(call);
6458c2ecf20Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
6468c2ecf20Sopenharmony_ci	return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
6478c2ecf20Sopenharmony_ci}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci/*
6508c2ecf20Sopenharmony_ci * Deliver reply data to a YFSVL.GetCellName operation.
6518c2ecf20Sopenharmony_ci */
6528c2ecf20Sopenharmony_cistatic int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	char *cell_name;
6558c2ecf20Sopenharmony_ci	u32 namesz, paddedsz;
6568c2ecf20Sopenharmony_ci	int ret;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	_enter("{%u,%zu/%u}",
6598c2ecf20Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), call->count);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
6628c2ecf20Sopenharmony_ci	case 0:
6638c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
6648c2ecf20Sopenharmony_ci		call->unmarshall++;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		fallthrough;	/* and extract the cell name length */
6678c2ecf20Sopenharmony_ci	case 1:
6688c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
6698c2ecf20Sopenharmony_ci		if (ret < 0)
6708c2ecf20Sopenharmony_ci			return ret;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci		namesz = ntohl(call->tmp);
6738c2ecf20Sopenharmony_ci		if (namesz > AFS_MAXCELLNAME)
6748c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_cellname_len);
6758c2ecf20Sopenharmony_ci		paddedsz = (namesz + 3) & ~3;
6768c2ecf20Sopenharmony_ci		call->count = namesz;
6778c2ecf20Sopenharmony_ci		call->count2 = paddedsz - namesz;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		cell_name = kmalloc(namesz + 1, GFP_KERNEL);
6808c2ecf20Sopenharmony_ci		if (!cell_name)
6818c2ecf20Sopenharmony_ci			return -ENOMEM;
6828c2ecf20Sopenharmony_ci		cell_name[namesz] = 0;
6838c2ecf20Sopenharmony_ci		call->ret_str = cell_name;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		afs_extract_begin(call, cell_name, namesz);
6868c2ecf20Sopenharmony_ci		call->unmarshall++;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		fallthrough;	/* and extract cell name */
6898c2ecf20Sopenharmony_ci	case 2:
6908c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
6918c2ecf20Sopenharmony_ci		if (ret < 0)
6928c2ecf20Sopenharmony_ci			return ret;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		afs_extract_discard(call, call->count2);
6958c2ecf20Sopenharmony_ci		call->unmarshall++;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		fallthrough;	/* and extract padding */
6988c2ecf20Sopenharmony_ci	case 3:
6998c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
7008c2ecf20Sopenharmony_ci		if (ret < 0)
7018c2ecf20Sopenharmony_ci			return ret;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		call->unmarshall++;
7048c2ecf20Sopenharmony_ci		break;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
7088c2ecf20Sopenharmony_ci	return 0;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cistatic void afs_destroy_yfsvl_get_cell_name(struct afs_call *call)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	kfree(call->ret_str);
7148c2ecf20Sopenharmony_ci	afs_flat_call_destructor(call);
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci/*
7188c2ecf20Sopenharmony_ci * VL.GetCapabilities operation type
7198c2ecf20Sopenharmony_ci */
7208c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_YFSVLGetCellName = {
7218c2ecf20Sopenharmony_ci	.name		= "YFSVL.GetCellName",
7228c2ecf20Sopenharmony_ci	.op		= afs_YFSVL_GetCellName,
7238c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_yfsvl_get_cell_name,
7248c2ecf20Sopenharmony_ci	.destructor	= afs_destroy_yfsvl_get_cell_name,
7258c2ecf20Sopenharmony_ci};
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci/*
7288c2ecf20Sopenharmony_ci * Probe a volume server for the capabilities that it supports.  This can
7298c2ecf20Sopenharmony_ci * return up to 196 words.
7308c2ecf20Sopenharmony_ci *
7318c2ecf20Sopenharmony_ci * We use this to probe for service upgrade to determine what the server at the
7328c2ecf20Sopenharmony_ci * other end supports.
7338c2ecf20Sopenharmony_ci */
7348c2ecf20Sopenharmony_cichar *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct afs_call *call;
7378c2ecf20Sopenharmony_ci	struct afs_net *net = vc->cell->net;
7388c2ecf20Sopenharmony_ci	__be32 *bp;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	_enter("");
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_YFSVLGetCellName, 1 * 4, 0);
7438c2ecf20Sopenharmony_ci	if (!call)
7448c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	call->key = vc->key;
7478c2ecf20Sopenharmony_ci	call->ret_str = NULL;
7488c2ecf20Sopenharmony_ci	call->max_lifespan = AFS_VL_MAX_LIFESPAN;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* marshall the parameters */
7518c2ecf20Sopenharmony_ci	bp = call->request;
7528c2ecf20Sopenharmony_ci	*bp++ = htonl(YVLGETCELLNAME);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	/* Can't take a ref on server */
7558c2ecf20Sopenharmony_ci	trace_afs_make_vl_call(call);
7568c2ecf20Sopenharmony_ci	afs_make_call(&vc->ac, call, GFP_KERNEL);
7578c2ecf20Sopenharmony_ci	return (char *)afs_wait_for_call_to_complete(call, &vc->ac);
7588c2ecf20Sopenharmony_ci}
759