1ec26815aSDavid Howells /* AFS Volume Location Service client 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 125a0e3ad6STejun Heo #include <linux/gfp.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 154d9df986SDavid Howells #include "afs_fs.h" 161da177e4SLinus Torvalds #include "internal.h" 171da177e4SLinus Torvalds 1808e0e7c8SDavid Howells /* 19d2ddc776SDavid Howells * Deliver reply data to a VL.GetEntryByNameU call. 201da177e4SLinus Torvalds */ 21d2ddc776SDavid Howells static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call) 221da177e4SLinus Torvalds { 23d2ddc776SDavid Howells struct afs_uvldbentry__xdr *uvldb; 24d2ddc776SDavid Howells struct afs_vldb_entry *entry; 25d2ddc776SDavid Howells bool new_only = false; 261fba5868SMarc Dionne u32 tmp, nr_servers, vlflags; 27d2ddc776SDavid Howells int i, ret; 281da177e4SLinus Torvalds 29d001648eSDavid Howells _enter(""); 301da177e4SLinus Torvalds 31d001648eSDavid Howells ret = afs_transfer_reply(call); 32372ee163SDavid Howells if (ret < 0) 33372ee163SDavid Howells return ret; 341da177e4SLinus Torvalds 3508e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 36d2ddc776SDavid Howells uvldb = call->buffer; 3797e3043aSDavid Howells entry = call->reply[0]; 381da177e4SLinus Torvalds 3945df8462SDavid Howells nr_servers = ntohl(uvldb->nServers); 4045df8462SDavid Howells if (nr_servers > AFS_NMAXNSERVERS) 4145df8462SDavid Howells nr_servers = AFS_NMAXNSERVERS; 4245df8462SDavid Howells 43d2ddc776SDavid Howells for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++) 44d2ddc776SDavid Howells entry->name[i] = (u8)ntohl(uvldb->name[i]); 45d2ddc776SDavid Howells entry->name[i] = 0; 46d2ddc776SDavid Howells entry->name_len = strlen(entry->name); 471da177e4SLinus Torvalds 48d2ddc776SDavid Howells /* If there is a new replication site that we can use, ignore all the 49d2ddc776SDavid Howells * sites that aren't marked as new. 50d2ddc776SDavid Howells */ 5145df8462SDavid Howells for (i = 0; i < nr_servers; i++) { 52d2ddc776SDavid Howells tmp = ntohl(uvldb->serverFlags[i]); 53d2ddc776SDavid Howells if (!(tmp & AFS_VLSF_DONTUSE) && 54d2ddc776SDavid Howells (tmp & AFS_VLSF_NEWREPSITE)) 55d2ddc776SDavid Howells new_only = true; 564d9df986SDavid Howells } 571da177e4SLinus Torvalds 581fba5868SMarc Dionne vlflags = ntohl(uvldb->flags); 5945df8462SDavid Howells for (i = 0; i < nr_servers; i++) { 60d2ddc776SDavid Howells struct afs_uuid__xdr *xdr; 61d2ddc776SDavid Howells struct afs_uuid *uuid; 62d2ddc776SDavid Howells int j; 631da177e4SLinus Torvalds 64d2ddc776SDavid Howells tmp = ntohl(uvldb->serverFlags[i]); 65d2ddc776SDavid Howells if (tmp & AFS_VLSF_DONTUSE || 66d2ddc776SDavid Howells (new_only && !(tmp & AFS_VLSF_NEWREPSITE))) 67d2ddc776SDavid Howells continue; 681fba5868SMarc Dionne if (tmp & AFS_VLSF_RWVOL) { 69d2ddc776SDavid Howells entry->fs_mask[i] |= AFS_VOL_VTM_RW; 701fba5868SMarc Dionne if (vlflags & AFS_VLF_BACKEXISTS) 711fba5868SMarc Dionne entry->fs_mask[i] |= AFS_VOL_VTM_BAK; 721fba5868SMarc Dionne } 731da177e4SLinus Torvalds if (tmp & AFS_VLSF_ROVOL) 74d2ddc776SDavid Howells entry->fs_mask[i] |= AFS_VOL_VTM_RO; 75d2ddc776SDavid Howells if (!entry->fs_mask[i]) 76d2ddc776SDavid Howells continue; 77d2ddc776SDavid Howells 78d2ddc776SDavid Howells xdr = &uvldb->serverNumber[i]; 79d2ddc776SDavid Howells uuid = (struct afs_uuid *)&entry->fs_server[i]; 80d2ddc776SDavid Howells uuid->time_low = xdr->time_low; 81d2ddc776SDavid Howells uuid->time_mid = htons(ntohl(xdr->time_mid)); 82d2ddc776SDavid Howells uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version)); 83d2ddc776SDavid Howells uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved); 84d2ddc776SDavid Howells uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low); 85d2ddc776SDavid Howells for (j = 0; j < 6; j++) 86d2ddc776SDavid Howells uuid->node[j] = (u8)ntohl(xdr->node[j]); 87d2ddc776SDavid Howells 88d2ddc776SDavid Howells entry->nr_servers++; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 91d2ddc776SDavid Howells for (i = 0; i < AFS_MAXTYPES; i++) 92d2ddc776SDavid Howells entry->vid[i] = ntohl(uvldb->volumeId[i]); 931da177e4SLinus Torvalds 941fba5868SMarc Dionne if (vlflags & AFS_VLF_RWEXISTS) 95d2ddc776SDavid Howells __set_bit(AFS_VLDB_HAS_RW, &entry->flags); 961fba5868SMarc Dionne if (vlflags & AFS_VLF_ROEXISTS) 97d2ddc776SDavid Howells __set_bit(AFS_VLDB_HAS_RO, &entry->flags); 981fba5868SMarc Dionne if (vlflags & AFS_VLF_BACKEXISTS) 99d2ddc776SDavid Howells __set_bit(AFS_VLDB_HAS_BAK, &entry->flags); 1001da177e4SLinus Torvalds 1011fba5868SMarc Dionne if (!(vlflags & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) { 102d2ddc776SDavid Howells entry->error = -ENOMEDIUM; 103d2ddc776SDavid Howells __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags); 104d2ddc776SDavid Howells } 105d2ddc776SDavid Howells 106d2ddc776SDavid Howells __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags); 10708e0e7c8SDavid Howells _leave(" = 0 [done]"); 10808e0e7c8SDavid Howells return 0; 109ec26815aSDavid Howells } 1101da177e4SLinus Torvalds 111d2ddc776SDavid Howells static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call) 112d2ddc776SDavid Howells { 113d2ddc776SDavid Howells kfree(call->reply[0]); 114d2ddc776SDavid Howells afs_flat_call_destructor(call); 115d2ddc776SDavid Howells } 116d2ddc776SDavid Howells 1171da177e4SLinus Torvalds /* 118d2ddc776SDavid Howells * VL.GetEntryByNameU operation type. 1191da177e4SLinus Torvalds */ 120d2ddc776SDavid Howells static const struct afs_call_type afs_RXVLGetEntryByNameU = { 121d2ddc776SDavid Howells .name = "VL.GetEntryByNameU", 122025db80cSDavid Howells .op = afs_VL_GetEntryByNameU, 123d2ddc776SDavid Howells .deliver = afs_deliver_vl_get_entry_by_name_u, 124d2ddc776SDavid Howells .destructor = afs_destroy_vl_get_entry_by_name_u, 12508e0e7c8SDavid Howells }; 12608e0e7c8SDavid Howells 12708e0e7c8SDavid Howells /* 128d2ddc776SDavid Howells * Dispatch a get volume entry by name or ID operation (uuid variant). If the 129d2ddc776SDavid Howells * volname is a decimal number then it's a volume ID not a volume name. 13008e0e7c8SDavid Howells */ 1310a5143f2SDavid Howells struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc, 13208e0e7c8SDavid Howells const char *volname, 133d2ddc776SDavid Howells int volnamesz) 13408e0e7c8SDavid Howells { 135d2ddc776SDavid Howells struct afs_vldb_entry *entry; 13608e0e7c8SDavid Howells struct afs_call *call; 1370a5143f2SDavid Howells struct afs_net *net = vc->cell->net; 138d2ddc776SDavid Howells size_t reqsz, padsz; 13908e0e7c8SDavid Howells __be32 *bp; 14008e0e7c8SDavid Howells 14108e0e7c8SDavid Howells _enter(""); 14208e0e7c8SDavid Howells 14308e0e7c8SDavid Howells padsz = (4 - (volnamesz & 3)) & 3; 14408e0e7c8SDavid Howells reqsz = 8 + volnamesz + padsz; 14508e0e7c8SDavid Howells 146d2ddc776SDavid Howells entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL); 147d2ddc776SDavid Howells if (!entry) 148d2ddc776SDavid Howells return ERR_PTR(-ENOMEM); 149d2ddc776SDavid Howells 150d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz, 151d2ddc776SDavid Howells sizeof(struct afs_uvldbentry__xdr)); 152d2ddc776SDavid Howells if (!call) { 153d2ddc776SDavid Howells kfree(entry); 154d2ddc776SDavid Howells return ERR_PTR(-ENOMEM); 155d2ddc776SDavid Howells } 15608e0e7c8SDavid Howells 1570a5143f2SDavid Howells call->key = vc->key; 15897e3043aSDavid Howells call->reply[0] = entry; 159d2ddc776SDavid Howells call->ret_reply0 = true; 160*94f699c9SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN; 16108e0e7c8SDavid Howells 162d2ddc776SDavid Howells /* Marshall the parameters */ 16308e0e7c8SDavid Howells bp = call->request; 164d2ddc776SDavid Howells *bp++ = htonl(VLGETENTRYBYNAMEU); 16508e0e7c8SDavid Howells *bp++ = htonl(volnamesz); 16608e0e7c8SDavid Howells memcpy(bp, volname, volnamesz); 16708e0e7c8SDavid Howells if (padsz > 0) 16808e0e7c8SDavid Howells memset((void *)bp + volnamesz, 0, padsz); 16908e0e7c8SDavid Howells 170025db80cSDavid Howells trace_afs_make_vl_call(call); 1710b9bf381SDavid Howells afs_make_call(&vc->ac, call, GFP_KERNEL); 1720b9bf381SDavid Howells return (struct afs_vldb_entry *)afs_wait_for_call_to_complete(call, &vc->ac); 17308e0e7c8SDavid Howells } 17408e0e7c8SDavid Howells 17508e0e7c8SDavid Howells /* 176d2ddc776SDavid Howells * Deliver reply data to a VL.GetAddrsU call. 177d2ddc776SDavid Howells * 178d2ddc776SDavid Howells * GetAddrsU(IN ListAddrByAttributes *inaddr, 179d2ddc776SDavid Howells * OUT afsUUID *uuidp1, 180d2ddc776SDavid Howells * OUT uint32_t *uniquifier, 181d2ddc776SDavid Howells * OUT uint32_t *nentries, 182d2ddc776SDavid Howells * OUT bulkaddrs *blkaddrs); 18308e0e7c8SDavid Howells */ 184d2ddc776SDavid Howells static int afs_deliver_vl_get_addrs_u(struct afs_call *call) 185d2ddc776SDavid Howells { 186d2ddc776SDavid Howells struct afs_addr_list *alist; 187d2ddc776SDavid Howells __be32 *bp; 188d2ddc776SDavid Howells u32 uniquifier, nentries, count; 189d2ddc776SDavid Howells int i, ret; 190d2ddc776SDavid Howells 19112bdcf33SDavid Howells _enter("{%u,%zu/%u}", 19212bdcf33SDavid Howells call->unmarshall, iov_iter_count(call->_iter), call->count); 193d2ddc776SDavid Howells 194d2ddc776SDavid Howells switch (call->unmarshall) { 195d2ddc776SDavid Howells case 0: 19612bdcf33SDavid Howells afs_extract_to_buf(call, 19712bdcf33SDavid Howells sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32)); 198d2ddc776SDavid Howells call->unmarshall++; 199d2ddc776SDavid Howells 200e690c9e3SGustavo A. R. Silva /* Extract the returned uuid, uniquifier, nentries and 201e690c9e3SGustavo A. R. Silva * blkaddrs size */ 202e690c9e3SGustavo A. R. Silva /* Fall through */ 203d2ddc776SDavid Howells case 1: 20412bdcf33SDavid Howells ret = afs_extract_data(call, true); 205d2ddc776SDavid Howells if (ret < 0) 206d2ddc776SDavid Howells return ret; 207d2ddc776SDavid Howells 208d2ddc776SDavid Howells bp = call->buffer + sizeof(struct afs_uuid__xdr); 209d2ddc776SDavid Howells uniquifier = ntohl(*bp++); 210d2ddc776SDavid Howells nentries = ntohl(*bp++); 211d2ddc776SDavid Howells count = ntohl(*bp); 212d2ddc776SDavid Howells 213d2ddc776SDavid Howells nentries = min(nentries, count); 214d2ddc776SDavid Howells alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT); 215d2ddc776SDavid Howells if (!alist) 216d2ddc776SDavid Howells return -ENOMEM; 217d2ddc776SDavid Howells alist->version = uniquifier; 218d2ddc776SDavid Howells call->reply[0] = alist; 219d2ddc776SDavid Howells call->count = count; 220d2ddc776SDavid Howells call->count2 = nentries; 221d2ddc776SDavid Howells call->unmarshall++; 222d2ddc776SDavid Howells 22312bdcf33SDavid Howells more_entries: 22412bdcf33SDavid Howells count = min(call->count, 4U); 22512bdcf33SDavid Howells afs_extract_to_buf(call, count * sizeof(__be32)); 22612bdcf33SDavid Howells 227e690c9e3SGustavo A. R. Silva /* Fall through - and extract entries */ 228d2ddc776SDavid Howells case 2: 22912bdcf33SDavid Howells ret = afs_extract_data(call, call->count > 4); 230d2ddc776SDavid Howells if (ret < 0) 231d2ddc776SDavid Howells return ret; 232d2ddc776SDavid Howells 233d2ddc776SDavid Howells alist = call->reply[0]; 234d2ddc776SDavid Howells bp = call->buffer; 23512bdcf33SDavid Howells count = min(call->count, 4U); 236d2ddc776SDavid Howells for (i = 0; i < count; i++) 237d2ddc776SDavid Howells if (alist->nr_addrs < call->count2) 238bf99a53cSDavid Howells afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT); 239d2ddc776SDavid Howells 240d2ddc776SDavid Howells call->count -= count; 241d2ddc776SDavid Howells if (call->count > 0) 24212bdcf33SDavid Howells goto more_entries; 243d2ddc776SDavid Howells call->unmarshall++; 244d2ddc776SDavid Howells break; 245d2ddc776SDavid Howells } 246d2ddc776SDavid Howells 247d2ddc776SDavid Howells _leave(" = 0 [done]"); 248d2ddc776SDavid Howells return 0; 249d2ddc776SDavid Howells } 250d2ddc776SDavid Howells 251d2ddc776SDavid Howells static void afs_vl_get_addrs_u_destructor(struct afs_call *call) 252d2ddc776SDavid Howells { 253d2ddc776SDavid Howells afs_put_server(call->net, (struct afs_server *)call->reply[0]); 254d2ddc776SDavid Howells kfree(call->reply[1]); 255d2ddc776SDavid Howells return afs_flat_call_destructor(call); 256d2ddc776SDavid Howells } 257d2ddc776SDavid Howells 258d2ddc776SDavid Howells /* 259d2ddc776SDavid Howells * VL.GetAddrsU operation type. 260d2ddc776SDavid Howells */ 261d2ddc776SDavid Howells static const struct afs_call_type afs_RXVLGetAddrsU = { 262d2ddc776SDavid Howells .name = "VL.GetAddrsU", 263025db80cSDavid Howells .op = afs_VL_GetAddrsU, 264d2ddc776SDavid Howells .deliver = afs_deliver_vl_get_addrs_u, 265d2ddc776SDavid Howells .destructor = afs_vl_get_addrs_u_destructor, 266d2ddc776SDavid Howells }; 267d2ddc776SDavid Howells 268d2ddc776SDavid Howells /* 269d2ddc776SDavid Howells * Dispatch an operation to get the addresses for a server, where the server is 270d2ddc776SDavid Howells * nominated by UUID. 271d2ddc776SDavid Howells */ 2720a5143f2SDavid Howells struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc, 273d2ddc776SDavid Howells const uuid_t *uuid) 2741da177e4SLinus Torvalds { 275d2ddc776SDavid Howells struct afs_ListAddrByAttributes__xdr *r; 276d2ddc776SDavid Howells const struct afs_uuid *u = (const struct afs_uuid *)uuid; 27708e0e7c8SDavid Howells struct afs_call *call; 2780a5143f2SDavid Howells struct afs_net *net = vc->cell->net; 2791da177e4SLinus Torvalds __be32 *bp; 280d2ddc776SDavid Howells int i; 2811da177e4SLinus Torvalds 28208e0e7c8SDavid Howells _enter(""); 2831da177e4SLinus Torvalds 284d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU, 285d2ddc776SDavid Howells sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr), 286d2ddc776SDavid Howells sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32)); 28708e0e7c8SDavid Howells if (!call) 288d2ddc776SDavid Howells return ERR_PTR(-ENOMEM); 2891da177e4SLinus Torvalds 2900a5143f2SDavid Howells call->key = vc->key; 291d2ddc776SDavid Howells call->reply[0] = NULL; 292d2ddc776SDavid Howells call->ret_reply0 = true; 293*94f699c9SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN; 2941da177e4SLinus Torvalds 295d2ddc776SDavid Howells /* Marshall the parameters */ 29608e0e7c8SDavid Howells bp = call->request; 297d2ddc776SDavid Howells *bp++ = htonl(VLGETADDRSU); 298d2ddc776SDavid Howells r = (struct afs_ListAddrByAttributes__xdr *)bp; 299d2ddc776SDavid Howells r->Mask = htonl(AFS_VLADDR_UUID); 300d2ddc776SDavid Howells r->ipaddr = 0; 301d2ddc776SDavid Howells r->index = 0; 302d2ddc776SDavid Howells r->spare = 0; 303d2ddc776SDavid Howells r->uuid.time_low = u->time_low; 304d2ddc776SDavid Howells r->uuid.time_mid = htonl(ntohs(u->time_mid)); 305d2ddc776SDavid Howells r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version)); 306d2ddc776SDavid Howells r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved); 307d2ddc776SDavid Howells r->uuid.clock_seq_low = htonl(u->clock_seq_low); 308d2ddc776SDavid Howells for (i = 0; i < 6; i++) 309fe342cf7SDavid Howells r->uuid.node[i] = htonl(u->node[i]); 3101da177e4SLinus Torvalds 311025db80cSDavid Howells trace_afs_make_vl_call(call); 3120b9bf381SDavid Howells afs_make_call(&vc->ac, call, GFP_KERNEL); 3130b9bf381SDavid Howells return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac); 314ec26815aSDavid Howells } 315bf99a53cSDavid Howells 316bf99a53cSDavid Howells /* 317bf99a53cSDavid Howells * Deliver reply data to an VL.GetCapabilities operation. 318bf99a53cSDavid Howells */ 319bf99a53cSDavid Howells static int afs_deliver_vl_get_capabilities(struct afs_call *call) 320bf99a53cSDavid Howells { 321bf99a53cSDavid Howells u32 count; 322bf99a53cSDavid Howells int ret; 323bf99a53cSDavid Howells 32412bdcf33SDavid Howells _enter("{%u,%zu/%u}", 32512bdcf33SDavid Howells call->unmarshall, iov_iter_count(call->_iter), call->count); 326bf99a53cSDavid Howells 327bf99a53cSDavid Howells switch (call->unmarshall) { 328bf99a53cSDavid Howells case 0: 32912bdcf33SDavid Howells afs_extract_to_tmp(call); 330bf99a53cSDavid Howells call->unmarshall++; 331bf99a53cSDavid Howells 332e690c9e3SGustavo A. R. Silva /* Fall through - and extract the capabilities word count */ 333bf99a53cSDavid Howells case 1: 33412bdcf33SDavid Howells ret = afs_extract_data(call, true); 335bf99a53cSDavid Howells if (ret < 0) 336bf99a53cSDavid Howells return ret; 337bf99a53cSDavid Howells 338bf99a53cSDavid Howells count = ntohl(call->tmp); 339bf99a53cSDavid Howells call->count = count; 340bf99a53cSDavid Howells call->count2 = count; 34112bdcf33SDavid Howells 342bf99a53cSDavid Howells call->unmarshall++; 34312bdcf33SDavid Howells afs_extract_discard(call, count * sizeof(__be32)); 344bf99a53cSDavid Howells 345e690c9e3SGustavo A. R. Silva /* Fall through - and extract capabilities words */ 346bf99a53cSDavid Howells case 2: 34712bdcf33SDavid Howells ret = afs_extract_data(call, false); 348bf99a53cSDavid Howells if (ret < 0) 349bf99a53cSDavid Howells return ret; 350bf99a53cSDavid Howells 351bf99a53cSDavid Howells /* TODO: Examine capabilities */ 352bf99a53cSDavid Howells 353bf99a53cSDavid Howells call->unmarshall++; 354bf99a53cSDavid Howells break; 355bf99a53cSDavid Howells } 356bf99a53cSDavid Howells 357bf99a53cSDavid Howells _leave(" = 0 [done]"); 358bf99a53cSDavid Howells return 0; 359bf99a53cSDavid Howells } 360bf99a53cSDavid Howells 3613bf0fb6fSDavid Howells static void afs_destroy_vl_get_capabilities(struct afs_call *call) 3623bf0fb6fSDavid Howells { 3633bf0fb6fSDavid Howells struct afs_vlserver *server = call->reply[0]; 3643bf0fb6fSDavid Howells 3653bf0fb6fSDavid Howells afs_put_vlserver(call->net, server); 3663bf0fb6fSDavid Howells afs_flat_call_destructor(call); 3673bf0fb6fSDavid Howells } 3683bf0fb6fSDavid Howells 369bf99a53cSDavid Howells /* 370bf99a53cSDavid Howells * VL.GetCapabilities operation type 371bf99a53cSDavid Howells */ 372bf99a53cSDavid Howells static const struct afs_call_type afs_RXVLGetCapabilities = { 373bf99a53cSDavid Howells .name = "VL.GetCapabilities", 374025db80cSDavid Howells .op = afs_VL_GetCapabilities, 375bf99a53cSDavid Howells .deliver = afs_deliver_vl_get_capabilities, 3763bf0fb6fSDavid Howells .done = afs_vlserver_probe_result, 3773bf0fb6fSDavid Howells .destructor = afs_destroy_vl_get_capabilities, 378bf99a53cSDavid Howells }; 379bf99a53cSDavid Howells 380bf99a53cSDavid Howells /* 3810a5143f2SDavid Howells * Probe a volume server for the capabilities that it supports. This can 382bf99a53cSDavid Howells * return up to 196 words. 383bf99a53cSDavid Howells * 384bf99a53cSDavid Howells * We use this to probe for service upgrade to determine what the server at the 385bf99a53cSDavid Howells * other end supports. 386bf99a53cSDavid Howells */ 3870b9bf381SDavid Howells struct afs_call *afs_vl_get_capabilities(struct afs_net *net, 3883bf0fb6fSDavid Howells struct afs_addr_cursor *ac, 3893bf0fb6fSDavid Howells struct key *key, 3903bf0fb6fSDavid Howells struct afs_vlserver *server, 3910b9bf381SDavid Howells unsigned int server_index) 392bf99a53cSDavid Howells { 393bf99a53cSDavid Howells struct afs_call *call; 394bf99a53cSDavid Howells __be32 *bp; 395bf99a53cSDavid Howells 396bf99a53cSDavid Howells _enter(""); 397bf99a53cSDavid Howells 398bf99a53cSDavid Howells call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4); 399bf99a53cSDavid Howells if (!call) 4000b9bf381SDavid Howells return ERR_PTR(-ENOMEM); 401bf99a53cSDavid Howells 402bf99a53cSDavid Howells call->key = key; 4033bf0fb6fSDavid Howells call->reply[0] = afs_get_vlserver(server); 4043bf0fb6fSDavid Howells call->reply[1] = (void *)(long)server_index; 4053bf0fb6fSDavid Howells call->upgrade = true; 4063bf0fb6fSDavid Howells call->want_reply_time = true; 4070b9bf381SDavid Howells call->async = true; 408*94f699c9SDavid Howells call->max_lifespan = AFS_PROBE_MAX_LIFESPAN; 409bf99a53cSDavid Howells 410bf99a53cSDavid Howells /* marshall the parameters */ 411bf99a53cSDavid Howells bp = call->request; 412bf99a53cSDavid Howells *bp++ = htonl(VLGETCAPABILITIES); 413bf99a53cSDavid Howells 414bf99a53cSDavid Howells /* Can't take a ref on server */ 415025db80cSDavid Howells trace_afs_make_vl_call(call); 4160b9bf381SDavid Howells afs_make_call(ac, call, GFP_KERNEL); 4170b9bf381SDavid Howells return call; 418bf99a53cSDavid Howells } 419bf99a53cSDavid Howells 420bf99a53cSDavid Howells /* 421bf99a53cSDavid Howells * Deliver reply data to a YFSVL.GetEndpoints call. 422bf99a53cSDavid Howells * 423bf99a53cSDavid Howells * GetEndpoints(IN yfsServerAttributes *attr, 424bf99a53cSDavid Howells * OUT opr_uuid *uuid, 425bf99a53cSDavid Howells * OUT afs_int32 *uniquifier, 426bf99a53cSDavid Howells * OUT endpoints *fsEndpoints, 427bf99a53cSDavid Howells * OUT endpoints *volEndpoints) 428bf99a53cSDavid Howells */ 429bf99a53cSDavid Howells static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) 430bf99a53cSDavid Howells { 431bf99a53cSDavid Howells struct afs_addr_list *alist; 432bf99a53cSDavid Howells __be32 *bp; 433bf99a53cSDavid Howells u32 uniquifier, size; 434bf99a53cSDavid Howells int ret; 435bf99a53cSDavid Howells 43612bdcf33SDavid Howells _enter("{%u,%zu,%u}", 43712bdcf33SDavid Howells call->unmarshall, iov_iter_count(call->_iter), call->count2); 438bf99a53cSDavid Howells 439bf99a53cSDavid Howells switch (call->unmarshall) { 440bf99a53cSDavid Howells case 0: 44112bdcf33SDavid Howells afs_extract_to_buf(call, sizeof(uuid_t) + 3 * sizeof(__be32)); 442bf99a53cSDavid Howells call->unmarshall = 1; 443bf99a53cSDavid Howells 444bf99a53cSDavid Howells /* Extract the returned uuid, uniquifier, fsEndpoints count and 445bf99a53cSDavid Howells * either the first fsEndpoint type or the volEndpoints 446bf99a53cSDavid Howells * count if there are no fsEndpoints. */ 447e690c9e3SGustavo A. R. Silva /* Fall through */ 448bf99a53cSDavid Howells case 1: 44912bdcf33SDavid Howells ret = afs_extract_data(call, true); 450bf99a53cSDavid Howells if (ret < 0) 451bf99a53cSDavid Howells return ret; 452bf99a53cSDavid Howells 453bf99a53cSDavid Howells bp = call->buffer + sizeof(uuid_t); 454bf99a53cSDavid Howells uniquifier = ntohl(*bp++); 455bf99a53cSDavid Howells call->count = ntohl(*bp++); 456bf99a53cSDavid Howells call->count2 = ntohl(*bp); /* Type or next count */ 457bf99a53cSDavid Howells 458bf99a53cSDavid Howells if (call->count > YFS_MAXENDPOINTS) 459160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 460160cb957SDavid Howells afs_eproto_yvl_fsendpt_num); 461bf99a53cSDavid Howells 462bf99a53cSDavid Howells alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); 463bf99a53cSDavid Howells if (!alist) 464bf99a53cSDavid Howells return -ENOMEM; 465bf99a53cSDavid Howells alist->version = uniquifier; 466bf99a53cSDavid Howells call->reply[0] = 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: 480160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 481160cb957SDavid Howells afs_eproto_yvl_fsendpt_type); 482bf99a53cSDavid Howells } 483bf99a53cSDavid Howells 484bf99a53cSDavid Howells size += sizeof(__be32); 48512bdcf33SDavid Howells afs_extract_to_buf(call, size); 48612bdcf33SDavid Howells call->unmarshall = 2; 48712bdcf33SDavid Howells 488e690c9e3SGustavo A. R. Silva /* Fall through - and extract fsEndpoints[] entries */ 48912bdcf33SDavid Howells case 2: 49012bdcf33SDavid Howells ret = afs_extract_data(call, true); 491bf99a53cSDavid Howells if (ret < 0) 492bf99a53cSDavid Howells return ret; 493bf99a53cSDavid Howells 494bf99a53cSDavid Howells alist = call->reply[0]; 495bf99a53cSDavid Howells bp = call->buffer; 496bf99a53cSDavid Howells switch (call->count2) { 497bf99a53cSDavid Howells case YFS_ENDPOINT_IPV4: 498bf99a53cSDavid Howells if (ntohl(bp[0]) != sizeof(__be32) * 2) 499160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 500160cb957SDavid Howells afs_eproto_yvl_fsendpt4_len); 501bf99a53cSDavid Howells afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); 502bf99a53cSDavid Howells bp += 3; 503bf99a53cSDavid Howells break; 504bf99a53cSDavid Howells case YFS_ENDPOINT_IPV6: 505bf99a53cSDavid Howells if (ntohl(bp[0]) != sizeof(__be32) * 5) 506160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 507160cb957SDavid Howells afs_eproto_yvl_fsendpt6_len); 508bf99a53cSDavid Howells afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); 509bf99a53cSDavid Howells bp += 6; 510bf99a53cSDavid Howells break; 511bf99a53cSDavid Howells default: 512160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 513160cb957SDavid Howells afs_eproto_yvl_fsendpt_type); 514bf99a53cSDavid Howells } 515bf99a53cSDavid Howells 516bf99a53cSDavid Howells /* Got either the type of the next entry or the count of 517bf99a53cSDavid Howells * volEndpoints if no more fsEndpoints. 518bf99a53cSDavid Howells */ 519fe342cf7SDavid Howells call->count2 = ntohl(*bp++); 520bf99a53cSDavid Howells 521bf99a53cSDavid Howells call->count--; 522bf99a53cSDavid Howells if (call->count > 0) 52312bdcf33SDavid Howells goto next_fsendpoint; 524bf99a53cSDavid Howells 525bf99a53cSDavid Howells extract_volendpoints: 526bf99a53cSDavid Howells /* Extract the list of volEndpoints. */ 527bf99a53cSDavid Howells call->count = call->count2; 528bf99a53cSDavid Howells if (!call->count) 529bf99a53cSDavid Howells goto end; 530bf99a53cSDavid Howells if (call->count > YFS_MAXENDPOINTS) 531160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 532160cb957SDavid Howells afs_eproto_yvl_vlendpt_type); 533bf99a53cSDavid Howells 53412bdcf33SDavid Howells afs_extract_to_buf(call, 1 * sizeof(__be32)); 535bf99a53cSDavid Howells call->unmarshall = 3; 536bf99a53cSDavid Howells 537bf99a53cSDavid Howells /* Extract the type of volEndpoints[0]. Normally we would 538bf99a53cSDavid Howells * extract the type of the next endpoint when we extract the 539bf99a53cSDavid Howells * data of the current one, but this is the first... 540bf99a53cSDavid Howells */ 541e690c9e3SGustavo A. R. Silva /* Fall through */ 542bf99a53cSDavid Howells case 3: 54312bdcf33SDavid Howells ret = afs_extract_data(call, true); 544bf99a53cSDavid Howells if (ret < 0) 545bf99a53cSDavid Howells return ret; 546bf99a53cSDavid Howells 547bf99a53cSDavid Howells bp = call->buffer; 548bf99a53cSDavid Howells 54912bdcf33SDavid Howells next_volendpoint: 55012bdcf33SDavid Howells call->count2 = ntohl(*bp++); 551bf99a53cSDavid Howells switch (call->count2) { 552bf99a53cSDavid Howells case YFS_ENDPOINT_IPV4: 553bf99a53cSDavid Howells size = sizeof(__be32) * (1 + 1 + 1); 554bf99a53cSDavid Howells break; 555bf99a53cSDavid Howells case YFS_ENDPOINT_IPV6: 556bf99a53cSDavid Howells size = sizeof(__be32) * (1 + 4 + 1); 557bf99a53cSDavid Howells break; 558bf99a53cSDavid Howells default: 559160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 560160cb957SDavid Howells 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 568e690c9e3SGustavo A. R. Silva /* Fall through - 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) 578160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 579160cb957SDavid Howells 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) 584160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 585160cb957SDavid Howells afs_eproto_yvl_vlendpt6_len); 586bf99a53cSDavid Howells bp += 6; 587bf99a53cSDavid Howells break; 588bf99a53cSDavid Howells default: 589160cb957SDavid Howells return afs_protocol_error(call, -EBADMSG, 590160cb957SDavid Howells afs_eproto_yvl_vlendpt_type); 591bf99a53cSDavid Howells } 592bf99a53cSDavid Howells 593bf99a53cSDavid Howells /* Got either the type of the next entry or the count of 594bf99a53cSDavid Howells * volEndpoints if no more fsEndpoints. 595bf99a53cSDavid Howells */ 596bf99a53cSDavid Howells call->count--; 59712bdcf33SDavid Howells if (call->count > 0) 59812bdcf33SDavid Howells goto next_volendpoint; 599bf99a53cSDavid Howells 600bf99a53cSDavid Howells end: 60112bdcf33SDavid Howells afs_extract_discard(call, 0); 602bf99a53cSDavid Howells call->unmarshall = 5; 603bf99a53cSDavid Howells 604e690c9e3SGustavo A. R. Silva /* Fall through - Done */ 605bf99a53cSDavid Howells case 5: 60612bdcf33SDavid Howells ret = afs_extract_data(call, false); 607bf99a53cSDavid Howells if (ret < 0) 608bf99a53cSDavid Howells return ret; 609bf99a53cSDavid Howells call->unmarshall = 6; 610bf99a53cSDavid Howells 611bf99a53cSDavid Howells case 6: 612bf99a53cSDavid Howells break; 613bf99a53cSDavid Howells } 614bf99a53cSDavid Howells 615bf99a53cSDavid Howells alist = call->reply[0]; 616bf99a53cSDavid Howells _leave(" = 0 [done]"); 617bf99a53cSDavid Howells return 0; 618bf99a53cSDavid Howells } 619bf99a53cSDavid Howells 620bf99a53cSDavid Howells /* 621bf99a53cSDavid Howells * YFSVL.GetEndpoints operation type. 622bf99a53cSDavid Howells */ 623bf99a53cSDavid Howells static const struct afs_call_type afs_YFSVLGetEndpoints = { 624025db80cSDavid Howells .name = "YFSVL.GetEndpoints", 625025db80cSDavid Howells .op = afs_YFSVL_GetEndpoints, 626bf99a53cSDavid Howells .deliver = afs_deliver_yfsvl_get_endpoints, 627bf99a53cSDavid Howells .destructor = afs_vl_get_addrs_u_destructor, 628bf99a53cSDavid Howells }; 629bf99a53cSDavid Howells 630bf99a53cSDavid Howells /* 631bf99a53cSDavid Howells * Dispatch an operation to get the addresses for a server, where the server is 632bf99a53cSDavid Howells * nominated by UUID. 633bf99a53cSDavid Howells */ 6340a5143f2SDavid Howells struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc, 635bf99a53cSDavid Howells const uuid_t *uuid) 636bf99a53cSDavid Howells { 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; 650bf99a53cSDavid Howells call->reply[0] = NULL; 651bf99a53cSDavid Howells call->ret_reply0 = true; 652*94f699c9SDavid Howells call->max_lifespan = AFS_VL_MAX_LIFESPAN; 653bf99a53cSDavid Howells 654bf99a53cSDavid Howells /* Marshall the parameters */ 655bf99a53cSDavid Howells bp = call->request; 656bf99a53cSDavid Howells *bp++ = htonl(YVLGETENDPOINTS); 657bf99a53cSDavid Howells *bp++ = htonl(YFS_SERVER_UUID); 658bf99a53cSDavid Howells memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */ 659bf99a53cSDavid Howells 660025db80cSDavid Howells trace_afs_make_vl_call(call); 6610b9bf381SDavid Howells afs_make_call(&vc->ac, call, GFP_KERNEL); 6620b9bf381SDavid Howells return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac); 663bf99a53cSDavid Howells } 664