blob: 48d137628d6a9d5769bd5db6ffa77ed8c43ae5fc [file] [log] [blame]
David Howellsec268152007-04-26 15:49:28 -07001/* AFS Volume Location Service client
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells ([email protected])
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/init.h>
14#include <linux/sched.h>
David Howells4d9df982017-11-02 15:27:47 +000015#include "afs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "internal.h"
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018/*
David Howells08e0e7c2007-04-26 15:55:03 -070019 * map volume locator abort codes to error codes
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
David Howells08e0e7c2007-04-26 15:55:03 -070021static int afs_vl_abort_to_error(u32 abort_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070022{
David Howells08e0e7c2007-04-26 15:55:03 -070023 _enter("%u", abort_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
David Howells08e0e7c2007-04-26 15:55:03 -070025 switch (abort_code) {
26 case AFSVL_IDEXIST: return -EEXIST;
27 case AFSVL_IO: return -EREMOTEIO;
28 case AFSVL_NAMEEXIST: return -EEXIST;
29 case AFSVL_CREATEFAIL: return -EREMOTEIO;
30 case AFSVL_NOENT: return -ENOMEDIUM;
31 case AFSVL_EMPTY: return -ENOMEDIUM;
32 case AFSVL_ENTDELETED: return -ENOMEDIUM;
33 case AFSVL_BADNAME: return -EINVAL;
34 case AFSVL_BADINDEX: return -EINVAL;
35 case AFSVL_BADVOLTYPE: return -EINVAL;
36 case AFSVL_BADSERVER: return -EINVAL;
37 case AFSVL_BADPARTITION: return -EINVAL;
38 case AFSVL_REPSFULL: return -EFBIG;
39 case AFSVL_NOREPSERVER: return -ENOENT;
40 case AFSVL_DUPREPSERVER: return -EEXIST;
41 case AFSVL_RWNOTFOUND: return -ENOENT;
42 case AFSVL_BADREFCOUNT: return -EINVAL;
43 case AFSVL_SIZEEXCEEDED: return -EINVAL;
44 case AFSVL_BADENTRY: return -EINVAL;
45 case AFSVL_BADVOLIDBUMP: return -EINVAL;
46 case AFSVL_IDALREADYHASHED: return -EINVAL;
47 case AFSVL_ENTRYLOCKED: return -EBUSY;
48 case AFSVL_BADVOLOPER: return -EBADRQC;
49 case AFSVL_BADRELLOCKTYPE: return -EINVAL;
50 case AFSVL_RERELEASE: return -EREMOTEIO;
51 case AFSVL_BADSERVERFLAG: return -EINVAL;
52 case AFSVL_PERM: return -EACCES;
53 case AFSVL_NOMEM: return -EREMOTEIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 default:
David Howells08e0e7c2007-04-26 15:55:03 -070055 return afs_abort_to_error(abort_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 }
David Howellsec268152007-04-26 15:49:28 -070057}
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/*
David Howells08e0e7c2007-04-26 15:55:03 -070060 * deliver reply data to a VL.GetEntryByXXX call
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 */
David Howellsd0016482016-08-30 20:42:14 +010062static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
David Howells08e0e7c2007-04-26 15:55:03 -070064 struct afs_cache_vlocation *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 __be32 *bp;
David Howells08e0e7c2007-04-26 15:55:03 -070066 u32 tmp;
David Howells372ee162016-08-03 14:11:40 +010067 int loop, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
David Howellsd0016482016-08-30 20:42:14 +010069 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
David Howellsd0016482016-08-30 20:42:14 +010071 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +010072 if (ret < 0)
73 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
David Howells08e0e7c2007-04-26 15:55:03 -070075 /* unmarshall the reply once we've received all of it */
76 entry = call->reply;
77 bp = call->buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
David Howells08e0e7c2007-04-26 15:55:03 -070079 for (loop = 0; loop < 64; loop++)
80 entry->name[loop] = ntohl(*bp++);
81 entry->name[loop] = 0;
82 bp++; /* final NUL */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
David Howells08e0e7c2007-04-26 15:55:03 -070084 bp++; /* type */
85 entry->nservers = ntohl(*bp++);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
David Howells4d9df982017-11-02 15:27:47 +000087 for (loop = 0; loop < 8; loop++) {
88 entry->servers[loop].srx_family = AF_RXRPC;
89 entry->servers[loop].srx_service = FS_SERVICE;
90 entry->servers[loop].transport_type = SOCK_DGRAM;
91 entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin);
92 entry->servers[loop].transport.sin.sin_family = AF_INET;
93 entry->servers[loop].transport.sin.sin_port = htons(AFS_FS_PORT);
94 entry->servers[loop].transport.sin.sin_addr.s_addr = *bp++;
95 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
David Howells08e0e7c2007-04-26 15:55:03 -070097 bp += 8; /* partition IDs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
David Howells08e0e7c2007-04-26 15:55:03 -070099 for (loop = 0; loop < 8; loop++) {
100 tmp = ntohl(*bp++);
101 entry->srvtmask[loop] = 0;
102 if (tmp & AFS_VLSF_RWVOL)
103 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
104 if (tmp & AFS_VLSF_ROVOL)
105 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
106 if (tmp & AFS_VLSF_BACKVOL)
107 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 }
109
David Howells08e0e7c2007-04-26 15:55:03 -0700110 entry->vid[0] = ntohl(*bp++);
111 entry->vid[1] = ntohl(*bp++);
112 entry->vid[2] = ntohl(*bp++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
David Howells08e0e7c2007-04-26 15:55:03 -0700114 bp++; /* clone ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
David Howells08e0e7c2007-04-26 15:55:03 -0700116 tmp = ntohl(*bp++); /* flags */
117 entry->vidmask = 0;
118 if (tmp & AFS_VLF_RWEXISTS)
119 entry->vidmask |= AFS_VOL_VTM_RW;
120 if (tmp & AFS_VLF_ROEXISTS)
121 entry->vidmask |= AFS_VOL_VTM_RO;
122 if (tmp & AFS_VLF_BACKEXISTS)
123 entry->vidmask |= AFS_VOL_VTM_BAK;
124 if (!entry->vidmask)
125 return -EBADMSG;
126
127 _leave(" = 0 [done]");
128 return 0;
David Howellsec268152007-04-26 15:49:28 -0700129}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131/*
David Howells08e0e7c2007-04-26 15:55:03 -0700132 * VL.GetEntryByName operation type
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 */
David Howells08e0e7c2007-04-26 15:55:03 -0700134static const struct afs_call_type afs_RXVLGetEntryByName = {
David Howells00d3b7a2007-04-26 15:57:07 -0700135 .name = "VL.GetEntryByName",
David Howells08e0e7c2007-04-26 15:55:03 -0700136 .deliver = afs_deliver_vl_get_entry_by_xxx,
137 .abort_to_error = afs_vl_abort_to_error,
138 .destructor = afs_flat_call_destructor,
139};
140
141/*
142 * VL.GetEntryById operation type
143 */
144static const struct afs_call_type afs_RXVLGetEntryById = {
David Howells00d3b7a2007-04-26 15:57:07 -0700145 .name = "VL.GetEntryById",
David Howells08e0e7c2007-04-26 15:55:03 -0700146 .deliver = afs_deliver_vl_get_entry_by_xxx,
147 .abort_to_error = afs_vl_abort_to_error,
148 .destructor = afs_flat_call_destructor,
149};
150
151/*
152 * dispatch a get volume entry by name operation
153 */
David Howellsf044c882017-11-02 15:27:45 +0000154int afs_vl_get_entry_by_name(struct afs_net *net,
David Howells4d9df982017-11-02 15:27:47 +0000155 struct sockaddr_rxrpc *addr,
David Howells00d3b7a2007-04-26 15:57:07 -0700156 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700157 const char *volname,
158 struct afs_cache_vlocation *entry,
David Howells56ff9c82017-01-05 10:38:36 +0000159 bool async)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160{
David Howells08e0e7c2007-04-26 15:55:03 -0700161 struct afs_call *call;
162 size_t volnamesz, reqsz, padsz;
163 __be32 *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
David Howells08e0e7c2007-04-26 15:55:03 -0700165 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
David Howells08e0e7c2007-04-26 15:55:03 -0700167 volnamesz = strlen(volname);
168 padsz = (4 - (volnamesz & 3)) & 3;
169 reqsz = 8 + volnamesz + padsz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
David Howellsf044c882017-11-02 15:27:45 +0000171 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByName, reqsz, 384);
David Howells08e0e7c2007-04-26 15:55:03 -0700172 if (!call)
173 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
David Howells00d3b7a2007-04-26 15:57:07 -0700175 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700176 call->reply = entry;
David Howells08e0e7c2007-04-26 15:55:03 -0700177
178 /* marshall the parameters */
179 bp = call->request;
180 *bp++ = htonl(VLGETENTRYBYNAME);
181 *bp++ = htonl(volnamesz);
182 memcpy(bp, volname, volnamesz);
183 if (padsz > 0)
184 memset((void *) bp + volnamesz, 0, padsz);
185
186 /* initiate the call */
David Howells56ff9c82017-01-05 10:38:36 +0000187 return afs_make_call(addr, call, GFP_KERNEL, async);
David Howellsec268152007-04-26 15:49:28 -0700188}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190/*
David Howells08e0e7c2007-04-26 15:55:03 -0700191 * dispatch a get volume entry by ID operation
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 */
David Howellsf044c882017-11-02 15:27:45 +0000193int afs_vl_get_entry_by_id(struct afs_net *net,
David Howells4d9df982017-11-02 15:27:47 +0000194 struct sockaddr_rxrpc *addr,
David Howells00d3b7a2007-04-26 15:57:07 -0700195 struct key *key,
David Howells08e0e7c2007-04-26 15:55:03 -0700196 afs_volid_t volid,
197 afs_voltype_t voltype,
198 struct afs_cache_vlocation *entry,
David Howells56ff9c82017-01-05 10:38:36 +0000199 bool async)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
David Howells08e0e7c2007-04-26 15:55:03 -0700201 struct afs_call *call;
202 __be32 *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
David Howells08e0e7c2007-04-26 15:55:03 -0700204 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
David Howellsf044c882017-11-02 15:27:45 +0000206 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryById, 12, 384);
David Howells08e0e7c2007-04-26 15:55:03 -0700207 if (!call)
208 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
David Howells00d3b7a2007-04-26 15:57:07 -0700210 call->key = key;
David Howells08e0e7c2007-04-26 15:55:03 -0700211 call->reply = entry;
David Howells08e0e7c2007-04-26 15:55:03 -0700212
213 /* marshall the parameters */
214 bp = call->request;
215 *bp++ = htonl(VLGETENTRYBYID);
216 *bp++ = htonl(volid);
217 *bp = htonl(voltype);
218
219 /* initiate the call */
David Howells56ff9c82017-01-05 10:38:36 +0000220 return afs_make_call(addr, call, GFP_KERNEL, async);
David Howellsec268152007-04-26 15:49:28 -0700221}