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;
21*d3acd81eSDavid Howells u32 nr_servers, vlflags;
22d2ddc776SDavid Howells int i, ret;
231da177e4SLinus Torvalds
24d001648eSDavid Howells _enter("");
251da177e4SLinus Torvalds
26d001648eSDavid Howells ret = afs_transfer_reply(call);
27372ee163SDavid Howells if (ret < 0)
28372ee163SDavid Howells return ret;
291da177e4SLinus Torvalds
3008e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */
31d2ddc776SDavid Howells uvldb = call->buffer;
32ffba718eSDavid Howells entry = call->ret_vldb;
331da177e4SLinus Torvalds
3445df8462SDavid Howells nr_servers = ntohl(uvldb->nServers);
3545df8462SDavid Howells if (nr_servers > AFS_NMAXNSERVERS)
3645df8462SDavid Howells nr_servers = AFS_NMAXNSERVERS;
3745df8462SDavid Howells
38d2ddc776SDavid Howells for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
39d2ddc776SDavid Howells entry->name[i] = (u8)ntohl(uvldb->name[i]);
40d2ddc776SDavid Howells entry->name[i] = 0;
41d2ddc776SDavid Howells entry->name_len = strlen(entry->name);
421da177e4SLinus Torvalds
431fba5868SMarc Dionne vlflags = ntohl(uvldb->flags);
4445df8462SDavid Howells for (i = 0; i < nr_servers; i++) {
45d2ddc776SDavid Howells struct afs_uuid__xdr *xdr;
46d2ddc776SDavid Howells struct afs_uuid *uuid;
47*d3acd81eSDavid Howells u32 tmp = ntohl(uvldb->serverFlags[i]);
48d2ddc776SDavid Howells int j;
494a46fdbaSMarc Dionne int n = entry->nr_servers;
501da177e4SLinus Torvalds
511fba5868SMarc Dionne if (tmp & AFS_VLSF_RWVOL) {
524a46fdbaSMarc Dionne entry->fs_mask[n] |= AFS_VOL_VTM_RW;
531fba5868SMarc Dionne if (vlflags & AFS_VLF_BACKEXISTS)
544a46fdbaSMarc Dionne entry->fs_mask[n] |= AFS_VOL_VTM_BAK;
551fba5868SMarc Dionne }
561da177e4SLinus Torvalds if (tmp & AFS_VLSF_ROVOL)
574a46fdbaSMarc Dionne entry->fs_mask[n] |= AFS_VOL_VTM_RO;
584a46fdbaSMarc Dionne if (!entry->fs_mask[n])
59d2ddc776SDavid Howells continue;
60d2ddc776SDavid Howells
61d2ddc776SDavid Howells xdr = &uvldb->serverNumber[i];
624a46fdbaSMarc Dionne uuid = (struct afs_uuid *)&entry->fs_server[n];
63d2ddc776SDavid Howells uuid->time_low = xdr->time_low;
64d2ddc776SDavid Howells uuid->time_mid = htons(ntohl(xdr->time_mid));
65d2ddc776SDavid Howells uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version));
66d2ddc776SDavid Howells uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved);
67d2ddc776SDavid Howells uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low);
68d2ddc776SDavid Howells for (j = 0; j < 6; j++)
69d2ddc776SDavid Howells uuid->node[j] = (u8)ntohl(xdr->node[j]);
70d2ddc776SDavid Howells
71*d3acd81eSDavid Howells entry->vlsf_flags[n] = tmp;
7281006805SDavid Howells entry->addr_version[n] = ntohl(uvldb->serverUnique[i]);
73d2ddc776SDavid Howells entry->nr_servers++;
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds
76d2ddc776SDavid Howells for (i = 0; i < AFS_MAXTYPES; i++)
77d2ddc776SDavid Howells entry->vid[i] = ntohl(uvldb->volumeId[i]);
781da177e4SLinus Torvalds
791fba5868SMarc Dionne if (vlflags & AFS_VLF_RWEXISTS)
80d2ddc776SDavid Howells __set_bit(AFS_VLDB_HAS_RW, &entry->flags);
811fba5868SMarc Dionne if (vlflags & AFS_VLF_ROEXISTS)
82d2ddc776SDavid Howells __set_bit(AFS_VLDB_HAS_RO, &entry->flags);
831fba5868SMarc Dionne if (vlflags & AFS_VLF_BACKEXISTS)
84d2ddc776SDavid Howells __set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
851da177e4SLinus Torvalds
861fba5868SMarc Dionne if (!(vlflags & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
87d2ddc776SDavid Howells entry->error = -ENOMEDIUM;
88d2ddc776SDavid Howells __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
89d2ddc776SDavid Howells }
90d2ddc776SDavid Howells
91d2ddc776SDavid Howells __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
9208e0e7c8SDavid Howells _leave(" = 0 [done]");
9308e0e7c8SDavid Howells return 0;
94ec26815aSDavid Howells }
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds /*
97d2ddc776SDavid Howells * VL.GetEntryByNameU operation type.
981da177e4SLinus Torvalds */
99d2ddc776SDavid Howells static const struct afs_call_type afs_RXVLGetEntryByNameU = {
100d2ddc776SDavid Howells .name = "VL.GetEntryByNameU",
101025db80cSDavid Howells .op = afs_VL_GetEntryByNameU,
102d2ddc776SDavid Howells .deliver = afs_deliver_vl_get_entry_by_name_u,
1036f2ff7e8SDavid Howells .destructor = afs_flat_call_destructor,
10408e0e7c8SDavid Howells };
10508e0e7c8SDavid Howells
10608e0e7c8SDavid Howells /*
107d2ddc776SDavid Howells * Dispatch a get volume entry by name or ID operation (uuid variant). If the
108d2ddc776SDavid Howells * volname is a decimal number then it's a volume ID not a volume name.
10908e0e7c8SDavid Howells */
afs_vl_get_entry_by_name_u(struct afs_vl_cursor * vc,const char * volname,int volnamesz)1100a5143f2SDavid Howells struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
11108e0e7c8SDavid Howells const char *volname,
112d2ddc776SDavid Howells int volnamesz)
11308e0e7c8SDavid Howells {
114d2ddc776SDavid Howells struct afs_vldb_entry *entry;
11508e0e7c8SDavid Howells struct afs_call *call;
1160a5143f2SDavid Howells struct afs_net *net = vc->cell->net;
117d2ddc776SDavid Howells size_t reqsz, padsz;
11808e0e7c8SDavid Howells __be32 *bp;
11908e0e7c8SDavid Howells
12008e0e7c8SDavid Howells _enter("");
12108e0e7c8SDavid Howells
12208e0e7c8SDavid Howells padsz = (4 - (volnamesz & 3)) & 3;
12308e0e7c8SDavid Howells reqsz = 8 + volnamesz + padsz;
12408e0e7c8SDavid Howells
125d2ddc776SDavid Howells entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
126d2ddc776SDavid Howells if (!entry)
127d2ddc776SDavid Howells return ERR_PTR(-ENOMEM);
128d2ddc776SDavid Howells
129d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
130d2ddc776SDavid Howells sizeof(struct afs_uvldbentry__xdr));
131d2ddc776SDavid Howells if (!call) {
132d2ddc776SDavid Howells kfree(entry);
133d2ddc776SDavid Howells return ERR_PTR(-ENOMEM);
134d2ddc776SDavid Howells }
13508e0e7c8SDavid Howells
1360a5143f2SDavid Howells call->key = vc->key;
137ffba718eSDavid Howells call->ret_vldb = entry;
13894f699c9SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN;
13998f9fda2SDavid Howells call->peer = rxrpc_kernel_get_peer(vc->alist->addrs[vc->addr_index].peer);
140e38f299eSDavid Howells call->service_id = vc->server->service_id;
14108e0e7c8SDavid Howells
142d2ddc776SDavid Howells /* Marshall the parameters */
14308e0e7c8SDavid Howells bp = call->request;
144d2ddc776SDavid Howells *bp++ = htonl(VLGETENTRYBYNAMEU);
14508e0e7c8SDavid Howells *bp++ = htonl(volnamesz);
14608e0e7c8SDavid Howells memcpy(bp, volname, volnamesz);
14708e0e7c8SDavid Howells if (padsz > 0)
14808e0e7c8SDavid Howells memset((void *)bp + volnamesz, 0, padsz);
14908e0e7c8SDavid Howells
150025db80cSDavid Howells trace_afs_make_vl_call(call);
15198f9fda2SDavid Howells afs_make_call(call, GFP_KERNEL);
15298f9fda2SDavid Howells afs_wait_for_call_to_complete(call);
153aa453becSDavid Howells vc->call_abort_code = call->abort_code;
154aa453becSDavid Howells vc->call_error = call->error;
155aa453becSDavid Howells vc->call_responded = call->responded;
1566f2ff7e8SDavid Howells afs_put_call(call);
157aa453becSDavid Howells if (vc->call_error) {
1586f2ff7e8SDavid Howells kfree(entry);
159aa453becSDavid Howells return ERR_PTR(vc->call_error);
1606f2ff7e8SDavid Howells }
1616f2ff7e8SDavid Howells return entry;
16208e0e7c8SDavid Howells }
16308e0e7c8SDavid Howells
16408e0e7c8SDavid Howells /*
165d2ddc776SDavid Howells * Deliver reply data to a VL.GetAddrsU call.
166d2ddc776SDavid Howells *
167d2ddc776SDavid Howells * GetAddrsU(IN ListAddrByAttributes *inaddr,
168d2ddc776SDavid Howells * OUT afsUUID *uuidp1,
169d2ddc776SDavid Howells * OUT uint32_t *uniquifier,
170d2ddc776SDavid Howells * OUT uint32_t *nentries,
171d2ddc776SDavid Howells * OUT bulkaddrs *blkaddrs);
17208e0e7c8SDavid Howells */
afs_deliver_vl_get_addrs_u(struct afs_call * call)173d2ddc776SDavid Howells static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
174d2ddc776SDavid Howells {
175d2ddc776SDavid Howells struct afs_addr_list *alist;
176d2ddc776SDavid Howells __be32 *bp;
177d2ddc776SDavid Howells u32 uniquifier, nentries, count;
178d2ddc776SDavid Howells int i, ret;
179d2ddc776SDavid Howells
18012bdcf33SDavid Howells _enter("{%u,%zu/%u}",
181fc276122SDavid Howells call->unmarshall, iov_iter_count(call->iter), call->count);
182d2ddc776SDavid Howells
183d2ddc776SDavid Howells switch (call->unmarshall) {
184d2ddc776SDavid Howells case 0:
18512bdcf33SDavid Howells afs_extract_to_buf(call,
18612bdcf33SDavid Howells sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
187d2ddc776SDavid Howells call->unmarshall++;
188d2ddc776SDavid Howells
189e690c9e3SGustavo A. R. Silva /* Extract the returned uuid, uniquifier, nentries and
190e690c9e3SGustavo A. R. Silva * blkaddrs size */
191df561f66SGustavo A. R. Silva fallthrough;
192d2ddc776SDavid Howells case 1:
19312bdcf33SDavid Howells ret = afs_extract_data(call, true);
194d2ddc776SDavid Howells if (ret < 0)
195d2ddc776SDavid Howells return ret;
196d2ddc776SDavid Howells
197d2ddc776SDavid Howells bp = call->buffer + sizeof(struct afs_uuid__xdr);
198d2ddc776SDavid Howells uniquifier = ntohl(*bp++);
199d2ddc776SDavid Howells nentries = ntohl(*bp++);
200d2ddc776SDavid Howells count = ntohl(*bp);
201d2ddc776SDavid Howells
202d2ddc776SDavid Howells nentries = min(nentries, count);
203e38f299eSDavid Howells alist = afs_alloc_addrlist(nentries);
204d2ddc776SDavid Howells if (!alist)
205d2ddc776SDavid Howells return -ENOMEM;
206d2ddc776SDavid Howells alist->version = uniquifier;
207ffba718eSDavid Howells call->ret_alist = alist;
208d2ddc776SDavid Howells call->count = count;
209d2ddc776SDavid Howells call->count2 = nentries;
210d2ddc776SDavid Howells call->unmarshall++;
211d2ddc776SDavid Howells
21212bdcf33SDavid Howells more_entries:
21312bdcf33SDavid Howells count = min(call->count, 4U);
21412bdcf33SDavid Howells afs_extract_to_buf(call, count * sizeof(__be32));
21512bdcf33SDavid Howells
216df561f66SGustavo A. R. Silva fallthrough; /* and extract entries */
217d2ddc776SDavid Howells case 2:
21812bdcf33SDavid Howells ret = afs_extract_data(call, call->count > 4);
219d2ddc776SDavid Howells if (ret < 0)
220d2ddc776SDavid Howells return ret;
221d2ddc776SDavid Howells
222ffba718eSDavid Howells alist = call->ret_alist;
223d2ddc776SDavid Howells bp = call->buffer;
22412bdcf33SDavid Howells count = min(call->count, 4U);
22572904d7bSDavid Howells for (i = 0; i < count; i++) {
22672904d7bSDavid Howells if (alist->nr_addrs < call->count2) {
22772904d7bSDavid Howells ret = afs_merge_fs_addr4(call->net, alist, *bp++, AFS_FS_PORT);
22872904d7bSDavid Howells if (ret < 0)
22972904d7bSDavid Howells return ret;
23072904d7bSDavid Howells }
23172904d7bSDavid Howells }
232d2ddc776SDavid Howells
233d2ddc776SDavid Howells call->count -= count;
234d2ddc776SDavid Howells if (call->count > 0)
23512bdcf33SDavid Howells goto more_entries;
236d2ddc776SDavid Howells call->unmarshall++;
237d2ddc776SDavid Howells break;
238d2ddc776SDavid Howells }
239d2ddc776SDavid Howells
240d2ddc776SDavid Howells _leave(" = 0 [done]");
241d2ddc776SDavid Howells return 0;
242d2ddc776SDavid Howells }
243d2ddc776SDavid Howells
244d2ddc776SDavid Howells /*
245d2ddc776SDavid Howells * VL.GetAddrsU operation type.
246d2ddc776SDavid Howells */
247d2ddc776SDavid Howells static const struct afs_call_type afs_RXVLGetAddrsU = {
248d2ddc776SDavid Howells .name = "VL.GetAddrsU",
249025db80cSDavid Howells .op = afs_VL_GetAddrsU,
250d2ddc776SDavid Howells .deliver = afs_deliver_vl_get_addrs_u,
2516f2ff7e8SDavid Howells .destructor = afs_flat_call_destructor,
252d2ddc776SDavid Howells };
253d2ddc776SDavid Howells
254d2ddc776SDavid Howells /*
255d2ddc776SDavid Howells * Dispatch an operation to get the addresses for a server, where the server is
256d2ddc776SDavid Howells * nominated by UUID.
257d2ddc776SDavid Howells */
afs_vl_get_addrs_u(struct afs_vl_cursor * vc,const uuid_t * uuid)2580a5143f2SDavid Howells struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
259d2ddc776SDavid Howells const uuid_t *uuid)
2601da177e4SLinus Torvalds {
261d2ddc776SDavid Howells struct afs_ListAddrByAttributes__xdr *r;
2626f2ff7e8SDavid Howells struct afs_addr_list *alist;
263d2ddc776SDavid Howells const struct afs_uuid *u = (const struct afs_uuid *)uuid;
26408e0e7c8SDavid Howells struct afs_call *call;
2650a5143f2SDavid Howells struct afs_net *net = vc->cell->net;
2661da177e4SLinus Torvalds __be32 *bp;
267d2ddc776SDavid Howells int i;
2681da177e4SLinus Torvalds
26908e0e7c8SDavid Howells _enter("");
2701da177e4SLinus Torvalds
271d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
272d2ddc776SDavid Howells sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
273d2ddc776SDavid Howells sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
27408e0e7c8SDavid Howells if (!call)
275d2ddc776SDavid Howells return ERR_PTR(-ENOMEM);
2761da177e4SLinus Torvalds
2770a5143f2SDavid Howells call->key = vc->key;
278ffba718eSDavid Howells call->ret_alist = NULL;
27994f699c9SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN;
28098f9fda2SDavid Howells call->peer = rxrpc_kernel_get_peer(vc->alist->addrs[vc->addr_index].peer);
281e38f299eSDavid Howells call->service_id = vc->server->service_id;
2821da177e4SLinus Torvalds
283d2ddc776SDavid Howells /* Marshall the parameters */
28408e0e7c8SDavid Howells bp = call->request;
285d2ddc776SDavid Howells *bp++ = htonl(VLGETADDRSU);
286d2ddc776SDavid Howells r = (struct afs_ListAddrByAttributes__xdr *)bp;
287d2ddc776SDavid Howells r->Mask = htonl(AFS_VLADDR_UUID);
288d2ddc776SDavid Howells r->ipaddr = 0;
289d2ddc776SDavid Howells r->index = 0;
290d2ddc776SDavid Howells r->spare = 0;
291d2ddc776SDavid Howells r->uuid.time_low = u->time_low;
292d2ddc776SDavid Howells r->uuid.time_mid = htonl(ntohs(u->time_mid));
293d2ddc776SDavid Howells r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version));
294d2ddc776SDavid Howells r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
295d2ddc776SDavid Howells r->uuid.clock_seq_low = htonl(u->clock_seq_low);
296d2ddc776SDavid Howells for (i = 0; i < 6; i++)
297fe342cf7SDavid Howells r->uuid.node[i] = htonl(u->node[i]);
2981da177e4SLinus Torvalds
299025db80cSDavid Howells trace_afs_make_vl_call(call);
30098f9fda2SDavid Howells afs_make_call(call, GFP_KERNEL);
30198f9fda2SDavid Howells afs_wait_for_call_to_complete(call);
302aa453becSDavid Howells vc->call_abort_code = call->abort_code;
303aa453becSDavid Howells vc->call_error = call->error;
304aa453becSDavid Howells vc->call_responded = call->responded;
3056f2ff7e8SDavid Howells alist = call->ret_alist;
3066f2ff7e8SDavid Howells afs_put_call(call);
307aa453becSDavid Howells if (vc->call_error) {
3081e5d8493SDavid Howells afs_put_addrlist(alist, afs_alist_trace_put_getaddru);
309aa453becSDavid Howells return ERR_PTR(vc->call_error);
3106f2ff7e8SDavid Howells }
3116f2ff7e8SDavid Howells return alist;
312ec26815aSDavid Howells }
313bf99a53cSDavid Howells
314bf99a53cSDavid Howells /*
315bf99a53cSDavid Howells * Deliver reply data to an VL.GetCapabilities operation.
316bf99a53cSDavid Howells */
afs_deliver_vl_get_capabilities(struct afs_call * call)317bf99a53cSDavid Howells static int afs_deliver_vl_get_capabilities(struct afs_call *call)
318bf99a53cSDavid Howells {
319bf99a53cSDavid Howells u32 count;
320bf99a53cSDavid Howells int ret;
321bf99a53cSDavid Howells
32212bdcf33SDavid Howells _enter("{%u,%zu/%u}",
323fc276122SDavid Howells call->unmarshall, iov_iter_count(call->iter), call->count);
324bf99a53cSDavid Howells
325bf99a53cSDavid Howells switch (call->unmarshall) {
326bf99a53cSDavid Howells case 0:
32712bdcf33SDavid Howells afs_extract_to_tmp(call);
328bf99a53cSDavid Howells call->unmarshall++;
329bf99a53cSDavid Howells
330df561f66SGustavo A. R. Silva fallthrough; /* and extract the capabilities word count */
331bf99a53cSDavid Howells case 1:
33212bdcf33SDavid Howells ret = afs_extract_data(call, true);
333bf99a53cSDavid Howells if (ret < 0)
334bf99a53cSDavid Howells return ret;
335bf99a53cSDavid Howells
336bf99a53cSDavid Howells count = ntohl(call->tmp);
337bf99a53cSDavid Howells call->count = count;
338bf99a53cSDavid Howells call->count2 = count;
33912bdcf33SDavid Howells
340bf99a53cSDavid Howells call->unmarshall++;
34112bdcf33SDavid Howells afs_extract_discard(call, count * sizeof(__be32));
342bf99a53cSDavid Howells
343df561f66SGustavo A. R. Silva fallthrough; /* and extract capabilities words */
344bf99a53cSDavid Howells case 2:
34512bdcf33SDavid Howells ret = afs_extract_data(call, false);
346bf99a53cSDavid Howells if (ret < 0)
347bf99a53cSDavid Howells return ret;
348bf99a53cSDavid Howells
349bf99a53cSDavid Howells /* TODO: Examine capabilities */
350bf99a53cSDavid Howells
351bf99a53cSDavid Howells call->unmarshall++;
352bf99a53cSDavid Howells break;
353bf99a53cSDavid Howells }
354bf99a53cSDavid Howells
355bf99a53cSDavid Howells _leave(" = 0 [done]");
356bf99a53cSDavid Howells return 0;
357bf99a53cSDavid Howells }
358bf99a53cSDavid Howells
afs_destroy_vl_get_capabilities(struct afs_call * call)3593bf0fb6fSDavid Howells static void afs_destroy_vl_get_capabilities(struct afs_call *call)
3603bf0fb6fSDavid Howells {
361f49b594dSDavid Howells afs_put_addrlist(call->vl_probe, afs_alist_trace_put_vlgetcaps);
362ffba718eSDavid Howells afs_put_vlserver(call->net, call->vlserver);
3633bf0fb6fSDavid Howells afs_flat_call_destructor(call);
3643bf0fb6fSDavid Howells }
3653bf0fb6fSDavid Howells
366bf99a53cSDavid Howells /*
367bf99a53cSDavid Howells * VL.GetCapabilities operation type
368bf99a53cSDavid Howells */
369bf99a53cSDavid Howells static const struct afs_call_type afs_RXVLGetCapabilities = {
370bf99a53cSDavid Howells .name = "VL.GetCapabilities",
371025db80cSDavid Howells .op = afs_VL_GetCapabilities,
372bf99a53cSDavid Howells .deliver = afs_deliver_vl_get_capabilities,
3733bf0fb6fSDavid Howells .done = afs_vlserver_probe_result,
3743bf0fb6fSDavid Howells .destructor = afs_destroy_vl_get_capabilities,
375bf99a53cSDavid Howells };
376bf99a53cSDavid Howells
377bf99a53cSDavid Howells /*
3780a5143f2SDavid Howells * Probe a volume server for the capabilities that it supports. This can
379bf99a53cSDavid Howells * return up to 196 words.
380bf99a53cSDavid Howells *
381bf99a53cSDavid Howells * We use this to probe for service upgrade to determine what the server at the
382bf99a53cSDavid Howells * other end supports.
383bf99a53cSDavid Howells */
afs_vl_get_capabilities(struct afs_net * net,struct afs_addr_list * alist,unsigned int addr_index,struct key * key,struct afs_vlserver * server,unsigned int server_index)3840b9bf381SDavid Howells struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
38598f9fda2SDavid Howells struct afs_addr_list *alist,
38698f9fda2SDavid Howells unsigned int addr_index,
3873bf0fb6fSDavid Howells struct key *key,
3883bf0fb6fSDavid Howells struct afs_vlserver *server,
3890b9bf381SDavid Howells unsigned int server_index)
390bf99a53cSDavid Howells {
391bf99a53cSDavid Howells struct afs_call *call;
392bf99a53cSDavid Howells __be32 *bp;
393bf99a53cSDavid Howells
394bf99a53cSDavid Howells _enter("");
395bf99a53cSDavid Howells
396bf99a53cSDavid Howells call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
397bf99a53cSDavid Howells if (!call)
3980b9bf381SDavid Howells return ERR_PTR(-ENOMEM);
399bf99a53cSDavid Howells
400bf99a53cSDavid Howells call->key = key;
401ffba718eSDavid Howells call->vlserver = afs_get_vlserver(server);
402ffba718eSDavid Howells call->server_index = server_index;
40398f9fda2SDavid Howells call->peer = rxrpc_kernel_get_peer(alist->addrs[addr_index].peer);
404f49b594dSDavid Howells call->vl_probe = afs_get_addrlist(alist, afs_alist_trace_get_vlgetcaps);
40598f9fda2SDavid Howells call->probe_index = addr_index;
406e38f299eSDavid Howells call->service_id = server->service_id;
4073bf0fb6fSDavid Howells call->upgrade = true;
4080b9bf381SDavid Howells call->async = true;
40994f699c9SDavid Howells call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
410bf99a53cSDavid Howells
411bf99a53cSDavid Howells /* marshall the parameters */
412bf99a53cSDavid Howells bp = call->request;
413bf99a53cSDavid Howells *bp++ = htonl(VLGETCAPABILITIES);
414bf99a53cSDavid Howells
415bf99a53cSDavid Howells /* Can't take a ref on server */
416025db80cSDavid Howells trace_afs_make_vl_call(call);
41798f9fda2SDavid Howells afs_make_call(call, GFP_KERNEL);
4180b9bf381SDavid Howells return call;
419bf99a53cSDavid Howells }
420bf99a53cSDavid Howells
421bf99a53cSDavid Howells /*
422bf99a53cSDavid Howells * Deliver reply data to a YFSVL.GetEndpoints call.
423bf99a53cSDavid Howells *
424bf99a53cSDavid Howells * GetEndpoints(IN yfsServerAttributes *attr,
425bf99a53cSDavid Howells * OUT opr_uuid *uuid,
426bf99a53cSDavid Howells * OUT afs_int32 *uniquifier,
427bf99a53cSDavid Howells * OUT endpoints *fsEndpoints,
428bf99a53cSDavid Howells * OUT endpoints *volEndpoints)
429bf99a53cSDavid Howells */
afs_deliver_yfsvl_get_endpoints(struct afs_call * call)430bf99a53cSDavid Howells static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
431bf99a53cSDavid Howells {
432bf99a53cSDavid Howells struct afs_addr_list *alist;
433bf99a53cSDavid Howells __be32 *bp;
434bf99a53cSDavid Howells u32 uniquifier, size;
435bf99a53cSDavid Howells int ret;
436bf99a53cSDavid Howells
43712bdcf33SDavid Howells _enter("{%u,%zu,%u}",
438fc276122SDavid Howells call->unmarshall, iov_iter_count(call->iter), call->count2);
439bf99a53cSDavid Howells
440bf99a53cSDavid Howells switch (call->unmarshall) {
441bf99a53cSDavid Howells case 0:
44212bdcf33SDavid Howells afs_extract_to_buf(call, sizeof(uuid_t) + 3 * sizeof(__be32));
443bf99a53cSDavid Howells call->unmarshall = 1;
444bf99a53cSDavid Howells
445bf99a53cSDavid Howells /* Extract the returned uuid, uniquifier, fsEndpoints count and
446bf99a53cSDavid Howells * either the first fsEndpoint type or the volEndpoints
447bf99a53cSDavid Howells * count if there are no fsEndpoints. */
448df561f66SGustavo A. R. Silva fallthrough;
449bf99a53cSDavid Howells case 1:
45012bdcf33SDavid Howells ret = afs_extract_data(call, true);
451bf99a53cSDavid Howells if (ret < 0)
452bf99a53cSDavid Howells return ret;
453bf99a53cSDavid Howells
454bf99a53cSDavid Howells bp = call->buffer + sizeof(uuid_t);
455bf99a53cSDavid Howells uniquifier = ntohl(*bp++);
456bf99a53cSDavid Howells call->count = ntohl(*bp++);
457bf99a53cSDavid Howells call->count2 = ntohl(*bp); /* Type or next count */
458bf99a53cSDavid Howells
459bf99a53cSDavid Howells if (call->count > YFS_MAXENDPOINTS)
4607126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_yvl_fsendpt_num);
461bf99a53cSDavid Howells
462e38f299eSDavid Howells alist = afs_alloc_addrlist(call->count);
463bf99a53cSDavid Howells if (!alist)
464bf99a53cSDavid Howells return -ENOMEM;
465bf99a53cSDavid Howells alist->version = uniquifier;
466ffba718eSDavid Howells call->ret_alist = alist;
467bf99a53cSDavid Howells
468bf99a53cSDavid Howells if (call->count == 0)
469bf99a53cSDavid Howells goto extract_volendpoints;
470bf99a53cSDavid Howells
47112bdcf33SDavid Howells next_fsendpoint:
472bf99a53cSDavid Howells switch (call->count2) {
473bf99a53cSDavid Howells case YFS_ENDPOINT_IPV4:
474bf99a53cSDavid Howells size = sizeof(__be32) * (1 + 1 + 1);
475bf99a53cSDavid Howells break;
476bf99a53cSDavid Howells case YFS_ENDPOINT_IPV6:
477bf99a53cSDavid Howells size = sizeof(__be32) * (1 + 4 + 1);
478bf99a53cSDavid Howells break;
479bf99a53cSDavid Howells default:
4807126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
481bf99a53cSDavid Howells }
482bf99a53cSDavid Howells
483bf99a53cSDavid Howells size += sizeof(__be32);
48412bdcf33SDavid Howells afs_extract_to_buf(call, size);
48512bdcf33SDavid Howells call->unmarshall = 2;
48612bdcf33SDavid Howells
487df561f66SGustavo A. R. Silva fallthrough; /* and extract fsEndpoints[] entries */
48812bdcf33SDavid Howells case 2:
48912bdcf33SDavid Howells ret = afs_extract_data(call, true);
490bf99a53cSDavid Howells if (ret < 0)
491bf99a53cSDavid Howells return ret;
492bf99a53cSDavid Howells
493ffba718eSDavid Howells alist = call->ret_alist;
494bf99a53cSDavid Howells bp = call->buffer;
495bf99a53cSDavid Howells switch (call->count2) {
496bf99a53cSDavid Howells case YFS_ENDPOINT_IPV4:
497bf99a53cSDavid Howells if (ntohl(bp[0]) != sizeof(__be32) * 2)
4987126ead9SDavid Howells return afs_protocol_error(
4997126ead9SDavid Howells call, afs_eproto_yvl_fsendpt4_len);
50072904d7bSDavid Howells ret = afs_merge_fs_addr4(call->net, alist, bp[1], ntohl(bp[2]));
50172904d7bSDavid Howells if (ret < 0)
50272904d7bSDavid Howells return ret;
503bf99a53cSDavid Howells bp += 3;
504bf99a53cSDavid Howells break;
505bf99a53cSDavid Howells case YFS_ENDPOINT_IPV6:
506bf99a53cSDavid Howells if (ntohl(bp[0]) != sizeof(__be32) * 5)
5077126ead9SDavid Howells return afs_protocol_error(
5087126ead9SDavid Howells call, afs_eproto_yvl_fsendpt6_len);
50972904d7bSDavid Howells ret = afs_merge_fs_addr6(call->net, alist, bp + 1, ntohl(bp[5]));
51072904d7bSDavid Howells if (ret < 0)
51172904d7bSDavid Howells return ret;
512bf99a53cSDavid Howells bp += 6;
513bf99a53cSDavid Howells break;
514bf99a53cSDavid Howells default:
5157126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_yvl_fsendpt_type);
516bf99a53cSDavid Howells }
517bf99a53cSDavid Howells
518bf99a53cSDavid Howells /* Got either the type of the next entry or the count of
519bf99a53cSDavid Howells * volEndpoints if no more fsEndpoints.
520bf99a53cSDavid Howells */
521fe342cf7SDavid Howells call->count2 = ntohl(*bp++);
522bf99a53cSDavid Howells
523bf99a53cSDavid Howells call->count--;
524bf99a53cSDavid Howells if (call->count > 0)
52512bdcf33SDavid Howells goto next_fsendpoint;
526bf99a53cSDavid Howells
527bf99a53cSDavid Howells extract_volendpoints:
528bf99a53cSDavid Howells /* Extract the list of volEndpoints. */
529bf99a53cSDavid Howells call->count = call->count2;
530bf99a53cSDavid Howells if (!call->count)
531bf99a53cSDavid Howells goto end;
532bf99a53cSDavid Howells if (call->count > YFS_MAXENDPOINTS)
5337126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
534bf99a53cSDavid Howells
53512bdcf33SDavid Howells afs_extract_to_buf(call, 1 * sizeof(__be32));
536bf99a53cSDavid Howells call->unmarshall = 3;
537bf99a53cSDavid Howells
538bf99a53cSDavid Howells /* Extract the type of volEndpoints[0]. Normally we would
539bf99a53cSDavid Howells * extract the type of the next endpoint when we extract the
540bf99a53cSDavid Howells * data of the current one, but this is the first...
541bf99a53cSDavid Howells */
542df561f66SGustavo A. R. Silva fallthrough;
543bf99a53cSDavid Howells case 3:
54412bdcf33SDavid Howells ret = afs_extract_data(call, true);
545bf99a53cSDavid Howells if (ret < 0)
546bf99a53cSDavid Howells return ret;
547bf99a53cSDavid Howells
548bf99a53cSDavid Howells bp = call->buffer;
549bf99a53cSDavid Howells
55012bdcf33SDavid Howells next_volendpoint:
55112bdcf33SDavid Howells call->count2 = ntohl(*bp++);
552bf99a53cSDavid Howells switch (call->count2) {
553bf99a53cSDavid Howells case YFS_ENDPOINT_IPV4:
554bf99a53cSDavid Howells size = sizeof(__be32) * (1 + 1 + 1);
555bf99a53cSDavid Howells break;
556bf99a53cSDavid Howells case YFS_ENDPOINT_IPV6:
557bf99a53cSDavid Howells size = sizeof(__be32) * (1 + 4 + 1);
558bf99a53cSDavid Howells break;
559bf99a53cSDavid Howells default:
5607126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
561bf99a53cSDavid Howells }
562bf99a53cSDavid Howells
563bf99a53cSDavid Howells if (call->count > 1)
56412bdcf33SDavid Howells size += sizeof(__be32); /* Get next type too */
56512bdcf33SDavid Howells afs_extract_to_buf(call, size);
56612bdcf33SDavid Howells call->unmarshall = 4;
56712bdcf33SDavid Howells
568df561f66SGustavo A. R. Silva fallthrough; /* and extract volEndpoints[] entries */
56912bdcf33SDavid Howells case 4:
57012bdcf33SDavid Howells ret = afs_extract_data(call, true);
571bf99a53cSDavid Howells if (ret < 0)
572bf99a53cSDavid Howells return ret;
573bf99a53cSDavid Howells
574bf99a53cSDavid Howells bp = call->buffer;
575bf99a53cSDavid Howells switch (call->count2) {
576bf99a53cSDavid Howells case YFS_ENDPOINT_IPV4:
577bf99a53cSDavid Howells if (ntohl(bp[0]) != sizeof(__be32) * 2)
5787126ead9SDavid Howells return afs_protocol_error(
5797126ead9SDavid Howells call, afs_eproto_yvl_vlendpt4_len);
580bf99a53cSDavid Howells bp += 3;
581bf99a53cSDavid Howells break;
582bf99a53cSDavid Howells case YFS_ENDPOINT_IPV6:
583bf99a53cSDavid Howells if (ntohl(bp[0]) != sizeof(__be32) * 5)
5847126ead9SDavid Howells return afs_protocol_error(
5857126ead9SDavid Howells call, afs_eproto_yvl_vlendpt6_len);
586bf99a53cSDavid Howells bp += 6;
587bf99a53cSDavid Howells break;
588bf99a53cSDavid Howells default:
5897126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_yvl_vlendpt_type);
590bf99a53cSDavid Howells }
591bf99a53cSDavid Howells
592bf99a53cSDavid Howells /* Got either the type of the next entry or the count of
593bf99a53cSDavid Howells * volEndpoints if no more fsEndpoints.
594bf99a53cSDavid Howells */
595bf99a53cSDavid Howells call->count--;
59612bdcf33SDavid Howells if (call->count > 0)
59712bdcf33SDavid Howells goto next_volendpoint;
598bf99a53cSDavid Howells
599bf99a53cSDavid Howells end:
60012bdcf33SDavid Howells afs_extract_discard(call, 0);
601bf99a53cSDavid Howells call->unmarshall = 5;
602bf99a53cSDavid Howells
603df561f66SGustavo A. R. Silva fallthrough; /* Done */
604bf99a53cSDavid Howells case 5:
60512bdcf33SDavid Howells ret = afs_extract_data(call, false);
606bf99a53cSDavid Howells if (ret < 0)
607bf99a53cSDavid Howells return ret;
608bf99a53cSDavid Howells call->unmarshall = 6;
609b2db6c35SGustavo A. R. Silva fallthrough;
610bf99a53cSDavid Howells
611bf99a53cSDavid Howells case 6:
612bf99a53cSDavid Howells break;
613bf99a53cSDavid Howells }
614bf99a53cSDavid Howells
615bf99a53cSDavid Howells _leave(" = 0 [done]");
616bf99a53cSDavid Howells return 0;
617bf99a53cSDavid Howells }
618bf99a53cSDavid Howells
619bf99a53cSDavid Howells /*
620bf99a53cSDavid Howells * YFSVL.GetEndpoints operation type.
621bf99a53cSDavid Howells */
622bf99a53cSDavid Howells static const struct afs_call_type afs_YFSVLGetEndpoints = {
623025db80cSDavid Howells .name = "YFSVL.GetEndpoints",
624025db80cSDavid Howells .op = afs_YFSVL_GetEndpoints,
625bf99a53cSDavid Howells .deliver = afs_deliver_yfsvl_get_endpoints,
6266f2ff7e8SDavid Howells .destructor = afs_flat_call_destructor,
627bf99a53cSDavid Howells };
628bf99a53cSDavid Howells
629bf99a53cSDavid Howells /*
630bf99a53cSDavid Howells * Dispatch an operation to get the addresses for a server, where the server is
631bf99a53cSDavid Howells * nominated by UUID.
632bf99a53cSDavid Howells */
afs_yfsvl_get_endpoints(struct afs_vl_cursor * vc,const uuid_t * uuid)6330a5143f2SDavid Howells struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
634bf99a53cSDavid Howells const uuid_t *uuid)
635bf99a53cSDavid Howells {
6366f2ff7e8SDavid Howells struct afs_addr_list *alist;
637bf99a53cSDavid Howells struct afs_call *call;
6380a5143f2SDavid Howells struct afs_net *net = vc->cell->net;
639bf99a53cSDavid Howells __be32 *bp;
640bf99a53cSDavid Howells
641bf99a53cSDavid Howells _enter("");
642bf99a53cSDavid Howells
643bf99a53cSDavid Howells call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
644bf99a53cSDavid Howells sizeof(__be32) * 2 + sizeof(*uuid),
645bf99a53cSDavid Howells sizeof(struct in6_addr) + sizeof(__be32) * 3);
646bf99a53cSDavid Howells if (!call)
647bf99a53cSDavid Howells return ERR_PTR(-ENOMEM);
648bf99a53cSDavid Howells
6490a5143f2SDavid Howells call->key = vc->key;
650ffba718eSDavid Howells call->ret_alist = NULL;
65194f699c9SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN;
65298f9fda2SDavid Howells call->peer = rxrpc_kernel_get_peer(vc->alist->addrs[vc->addr_index].peer);
653e38f299eSDavid Howells call->service_id = vc->server->service_id;
654bf99a53cSDavid Howells
655bf99a53cSDavid Howells /* Marshall the parameters */
656bf99a53cSDavid Howells bp = call->request;
657bf99a53cSDavid Howells *bp++ = htonl(YVLGETENDPOINTS);
658bf99a53cSDavid Howells *bp++ = htonl(YFS_SERVER_UUID);
659bf99a53cSDavid Howells memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
660bf99a53cSDavid Howells
661025db80cSDavid Howells trace_afs_make_vl_call(call);
66298f9fda2SDavid Howells afs_make_call(call, GFP_KERNEL);
66398f9fda2SDavid Howells afs_wait_for_call_to_complete(call);
664aa453becSDavid Howells vc->call_abort_code = call->abort_code;
665aa453becSDavid Howells vc->call_error = call->error;
666aa453becSDavid Howells vc->call_responded = call->responded;
6676f2ff7e8SDavid Howells alist = call->ret_alist;
6686f2ff7e8SDavid Howells afs_put_call(call);
669aa453becSDavid Howells if (vc->call_error) {
6701e5d8493SDavid Howells afs_put_addrlist(alist, afs_alist_trace_put_getaddru);
671aa453becSDavid Howells return ERR_PTR(vc->call_error);
6726f2ff7e8SDavid Howells }
6736f2ff7e8SDavid Howells return alist;
674bf99a53cSDavid Howells }
675c3e9f888SDavid Howells
676c3e9f888SDavid Howells /*
677c3e9f888SDavid Howells * Deliver reply data to a YFSVL.GetCellName operation.
678c3e9f888SDavid Howells */
afs_deliver_yfsvl_get_cell_name(struct afs_call * call)679c3e9f888SDavid Howells static int afs_deliver_yfsvl_get_cell_name(struct afs_call *call)
680c3e9f888SDavid Howells {
681c3e9f888SDavid Howells char *cell_name;
682c3e9f888SDavid Howells u32 namesz, paddedsz;
683c3e9f888SDavid Howells int ret;
684c3e9f888SDavid Howells
685c3e9f888SDavid Howells _enter("{%u,%zu/%u}",
686c3e9f888SDavid Howells call->unmarshall, iov_iter_count(call->iter), call->count);
687c3e9f888SDavid Howells
688c3e9f888SDavid Howells switch (call->unmarshall) {
689c3e9f888SDavid Howells case 0:
690c3e9f888SDavid Howells afs_extract_to_tmp(call);
691c3e9f888SDavid Howells call->unmarshall++;
692c3e9f888SDavid Howells
693df561f66SGustavo A. R. Silva fallthrough; /* and extract the cell name length */
694c3e9f888SDavid Howells case 1:
695c3e9f888SDavid Howells ret = afs_extract_data(call, true);
696c3e9f888SDavid Howells if (ret < 0)
697c3e9f888SDavid Howells return ret;
698c3e9f888SDavid Howells
699c3e9f888SDavid Howells namesz = ntohl(call->tmp);
700c3e9f888SDavid Howells if (namesz > AFS_MAXCELLNAME)
701c3e9f888SDavid Howells return afs_protocol_error(call, afs_eproto_cellname_len);
702c3e9f888SDavid Howells paddedsz = (namesz + 3) & ~3;
703c3e9f888SDavid Howells call->count = namesz;
704c3e9f888SDavid Howells call->count2 = paddedsz - namesz;
705c3e9f888SDavid Howells
706c3e9f888SDavid Howells cell_name = kmalloc(namesz + 1, GFP_KERNEL);
707c3e9f888SDavid Howells if (!cell_name)
708c3e9f888SDavid Howells return -ENOMEM;
709c3e9f888SDavid Howells cell_name[namesz] = 0;
710c3e9f888SDavid Howells call->ret_str = cell_name;
711c3e9f888SDavid Howells
712c3e9f888SDavid Howells afs_extract_begin(call, cell_name, namesz);
713c3e9f888SDavid Howells call->unmarshall++;
714c3e9f888SDavid Howells
715df561f66SGustavo A. R. Silva fallthrough; /* and extract cell name */
716c3e9f888SDavid Howells case 2:
717c3e9f888SDavid Howells ret = afs_extract_data(call, true);
718c3e9f888SDavid Howells if (ret < 0)
719c3e9f888SDavid Howells return ret;
720c3e9f888SDavid Howells
721c3e9f888SDavid Howells afs_extract_discard(call, call->count2);
722c3e9f888SDavid Howells call->unmarshall++;
723c3e9f888SDavid Howells
724df561f66SGustavo A. R. Silva fallthrough; /* and extract padding */
725c3e9f888SDavid Howells case 3:
726c3e9f888SDavid Howells ret = afs_extract_data(call, false);
727c3e9f888SDavid Howells if (ret < 0)
728c3e9f888SDavid Howells return ret;
729c3e9f888SDavid Howells
730c3e9f888SDavid Howells call->unmarshall++;
731c3e9f888SDavid Howells break;
732c3e9f888SDavid Howells }
733c3e9f888SDavid Howells
734c3e9f888SDavid Howells _leave(" = 0 [done]");
735c3e9f888SDavid Howells return 0;
736c3e9f888SDavid Howells }
737c3e9f888SDavid Howells
738c3e9f888SDavid Howells /*
739c3e9f888SDavid Howells * VL.GetCapabilities operation type
740c3e9f888SDavid Howells */
741c3e9f888SDavid Howells static const struct afs_call_type afs_YFSVLGetCellName = {
742c3e9f888SDavid Howells .name = "YFSVL.GetCellName",
743c3e9f888SDavid Howells .op = afs_YFSVL_GetCellName,
744c3e9f888SDavid Howells .deliver = afs_deliver_yfsvl_get_cell_name,
7456f2ff7e8SDavid Howells .destructor = afs_flat_call_destructor,
746c3e9f888SDavid Howells };
747c3e9f888SDavid Howells
748c3e9f888SDavid Howells /*
749c3e9f888SDavid Howells * Probe a volume server for the capabilities that it supports. This can
750c3e9f888SDavid Howells * return up to 196 words.
751c3e9f888SDavid Howells *
752c3e9f888SDavid Howells * We use this to probe for service upgrade to determine what the server at the
753c3e9f888SDavid Howells * other end supports.
754c3e9f888SDavid Howells */
afs_yfsvl_get_cell_name(struct afs_vl_cursor * vc)755c3e9f888SDavid Howells char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
756c3e9f888SDavid Howells {
757c3e9f888SDavid Howells struct afs_call *call;
758c3e9f888SDavid Howells struct afs_net *net = vc->cell->net;
759c3e9f888SDavid Howells __be32 *bp;
7606f2ff7e8SDavid Howells char *cellname;
761c3e9f888SDavid Howells
762c3e9f888SDavid Howells _enter("");
763c3e9f888SDavid Howells
764c3e9f888SDavid Howells call = afs_alloc_flat_call(net, &afs_YFSVLGetCellName, 1 * 4, 0);
765c3e9f888SDavid Howells if (!call)
766c3e9f888SDavid Howells return ERR_PTR(-ENOMEM);
767c3e9f888SDavid Howells
768c3e9f888SDavid Howells call->key = vc->key;
769c3e9f888SDavid Howells call->ret_str = NULL;
770c3e9f888SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN;
77198f9fda2SDavid Howells call->peer = rxrpc_kernel_get_peer(vc->alist->addrs[vc->addr_index].peer);
772e38f299eSDavid Howells call->service_id = vc->server->service_id;
773c3e9f888SDavid Howells
774c3e9f888SDavid Howells /* marshall the parameters */
775c3e9f888SDavid Howells bp = call->request;
776c3e9f888SDavid Howells *bp++ = htonl(YVLGETCELLNAME);
777c3e9f888SDavid Howells
778c3e9f888SDavid Howells /* Can't take a ref on server */
779c3e9f888SDavid Howells trace_afs_make_vl_call(call);
78098f9fda2SDavid Howells afs_make_call(call, GFP_KERNEL);
78198f9fda2SDavid Howells afs_wait_for_call_to_complete(call);
782aa453becSDavid Howells vc->call_abort_code = call->abort_code;
783aa453becSDavid Howells vc->call_error = call->error;
784aa453becSDavid Howells vc->call_responded = call->responded;
7856f2ff7e8SDavid Howells cellname = call->ret_str;
7866f2ff7e8SDavid Howells afs_put_call(call);
787aa453becSDavid Howells if (vc->call_error) {
7886f2ff7e8SDavid Howells kfree(cellname);
789aa453becSDavid Howells return ERR_PTR(vc->call_error);
7906f2ff7e8SDavid Howells }
7916f2ff7e8SDavid Howells return cellname;
792c3e9f888SDavid Howells }
793