blob: 173c652fe875b9009e5fbe6b1c83cf4e221faaf3 [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 (dhowells@redhat.com)
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 Howellsd2ddc772017-11-02 15:27:50 +000019 * Deliver reply data to a VL.GetEntryByNameU call.
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
David Howellsd2ddc772017-11-02 15:27:50 +000021static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070022{
David Howellsd2ddc772017-11-02 15:27:50 +000023 struct afs_uvldbentry__xdr *uvldb;
24 struct afs_vldb_entry *entry;
25 bool new_only = false;
David Howells08e0e7c2007-04-26 15:55:03 -070026 u32 tmp;
David Howellsd2ddc772017-11-02 15:27:50 +000027 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
David Howellsd0016482016-08-30 20:42:14 +010029 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
David Howellsd0016482016-08-30 20:42:14 +010031 ret = afs_transfer_reply(call);
David Howells372ee162016-08-03 14:11:40 +010032 if (ret < 0)
33 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
David Howells08e0e7c2007-04-26 15:55:03 -070035 /* unmarshall the reply once we've received all of it */
David Howellsd2ddc772017-11-02 15:27:50 +000036 uvldb = call->buffer;
David Howells97e30432017-11-02 15:27:48 +000037 entry = call->reply[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
David Howellsd2ddc772017-11-02 15:27:50 +000039 for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
40 entry->name[i] = (u8)ntohl(uvldb->name[i]);
41 entry->name[i] = 0;
42 entry->name_len = strlen(entry->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
David Howellsd2ddc772017-11-02 15:27:50 +000044 /* If there is a new replication site that we can use, ignore all the
45 * sites that aren't marked as new.
46 */
47 for (i = 0; i < AFS_NMAXNSERVERS; i++) {
48 tmp = ntohl(uvldb->serverFlags[i]);
49 if (!(tmp & AFS_VLSF_DONTUSE) &&
50 (tmp & AFS_VLSF_NEWREPSITE))
51 new_only = true;
David Howells4d9df982017-11-02 15:27:47 +000052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
David Howellsd2ddc772017-11-02 15:27:50 +000054 for (i = 0; i < AFS_NMAXNSERVERS; i++) {
55 struct afs_uuid__xdr *xdr;
56 struct afs_uuid *uuid;
57 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
David Howellsd2ddc772017-11-02 15:27:50 +000059 tmp = ntohl(uvldb->serverFlags[i]);
60 if (tmp & AFS_VLSF_DONTUSE ||
61 (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
62 continue;
David Howells08e0e7c2007-04-26 15:55:03 -070063 if (tmp & AFS_VLSF_RWVOL)
David Howellsd2ddc772017-11-02 15:27:50 +000064 entry->fs_mask[i] |= AFS_VOL_VTM_RW;
David Howells08e0e7c2007-04-26 15:55:03 -070065 if (tmp & AFS_VLSF_ROVOL)
David Howellsd2ddc772017-11-02 15:27:50 +000066 entry->fs_mask[i] |= AFS_VOL_VTM_RO;
David Howells08e0e7c2007-04-26 15:55:03 -070067 if (tmp & AFS_VLSF_BACKVOL)
David Howellsd2ddc772017-11-02 15:27:50 +000068 entry->fs_mask[i] |= AFS_VOL_VTM_BAK;
69 if (!entry->fs_mask[i])
70 continue;
71
72 xdr = &uvldb->serverNumber[i];
73 uuid = (struct afs_uuid *)&entry->fs_server[i];
74 uuid->time_low = xdr->time_low;
75 uuid->time_mid = htons(ntohl(xdr->time_mid));
76 uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version));
77 uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved);
78 uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low);
79 for (j = 0; j < 6; j++)
80 uuid->node[j] = (u8)ntohl(xdr->node[j]);
81
82 entry->nr_servers++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 }
84
David Howellsd2ddc772017-11-02 15:27:50 +000085 for (i = 0; i < AFS_MAXTYPES; i++)
86 entry->vid[i] = ntohl(uvldb->volumeId[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
David Howellsd2ddc772017-11-02 15:27:50 +000088 tmp = ntohl(uvldb->flags);
David Howells08e0e7c2007-04-26 15:55:03 -070089 if (tmp & AFS_VLF_RWEXISTS)
David Howellsd2ddc772017-11-02 15:27:50 +000090 __set_bit(AFS_VLDB_HAS_RW, &entry->flags);
David Howells08e0e7c2007-04-26 15:55:03 -070091 if (tmp & AFS_VLF_ROEXISTS)
David Howellsd2ddc772017-11-02 15:27:50 +000092 __set_bit(AFS_VLDB_HAS_RO, &entry->flags);
David Howells08e0e7c2007-04-26 15:55:03 -070093 if (tmp & AFS_VLF_BACKEXISTS)
David Howellsd2ddc772017-11-02 15:27:50 +000094 __set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
95
96 if (!(tmp & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
97 entry->error = -ENOMEDIUM;
98 __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
99 }
100
101 __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
102 _leave(" = 0 [done]");
103 return 0;
104}
105
106static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
107{
108 kfree(call->reply[0]);
109 afs_flat_call_destructor(call);
110}
111
112/*
113 * VL.GetEntryByNameU operation type.
114 */
115static const struct afs_call_type afs_RXVLGetEntryByNameU = {
116 .name = "VL.GetEntryByNameU",
117 .deliver = afs_deliver_vl_get_entry_by_name_u,
118 .destructor = afs_destroy_vl_get_entry_by_name_u,
119};
120
121/*
122 * Dispatch a get volume entry by name or ID operation (uuid variant). If the
123 * volname is a decimal number then it's a volume ID not a volume name.
124 */
125struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
126 struct afs_addr_cursor *ac,
127 struct key *key,
128 const char *volname,
129 int volnamesz)
130{
131 struct afs_vldb_entry *entry;
132 struct afs_call *call;
133 size_t reqsz, padsz;
134 __be32 *bp;
135
136 _enter("");
137
138 padsz = (4 - (volnamesz & 3)) & 3;
139 reqsz = 8 + volnamesz + padsz;
140
141 entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
142 if (!entry)
143 return ERR_PTR(-ENOMEM);
144
145 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
146 sizeof(struct afs_uvldbentry__xdr));
147 if (!call) {
148 kfree(entry);
149 return ERR_PTR(-ENOMEM);
150 }
151
152 call->key = key;
153 call->reply[0] = entry;
154 call->ret_reply0 = true;
155
156 /* Marshall the parameters */
157 bp = call->request;
158 *bp++ = htonl(VLGETENTRYBYNAMEU);
159 *bp++ = htonl(volnamesz);
160 memcpy(bp, volname, volnamesz);
161 if (padsz > 0)
162 memset((void *)bp + volnamesz, 0, padsz);
163
164 return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false);
165}
166
167/*
168 * Deliver reply data to a VL.GetAddrsU call.
169 *
170 * GetAddrsU(IN ListAddrByAttributes *inaddr,
171 * OUT afsUUID *uuidp1,
172 * OUT uint32_t *uniquifier,
173 * OUT uint32_t *nentries,
174 * OUT bulkaddrs *blkaddrs);
175 */
176static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
177{
178 struct afs_addr_list *alist;
179 __be32 *bp;
180 u32 uniquifier, nentries, count;
181 int i, ret;
182
183 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
184
185again:
186 switch (call->unmarshall) {
187 case 0:
188 call->offset = 0;
189 call->unmarshall++;
190
191 /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
192 case 1:
193 ret = afs_extract_data(call, call->buffer,
194 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32),
195 true);
196 if (ret < 0)
197 return ret;
198
199 bp = call->buffer + sizeof(struct afs_uuid__xdr);
200 uniquifier = ntohl(*bp++);
201 nentries = ntohl(*bp++);
202 count = ntohl(*bp);
203
204 nentries = min(nentries, count);
205 alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
206 if (!alist)
207 return -ENOMEM;
208 alist->version = uniquifier;
209 call->reply[0] = alist;
210 call->count = count;
211 call->count2 = nentries;
212 call->offset = 0;
213 call->unmarshall++;
214
215 /* Extract entries */
216 case 2:
217 count = min(call->count, 4U);
218 ret = afs_extract_data(call, call->buffer,
219 count * sizeof(__be32),
220 call->count > 4);
221 if (ret < 0)
222 return ret;
223
224 alist = call->reply[0];
225 bp = call->buffer;
226 for (i = 0; i < count; i++)
227 if (alist->nr_addrs < call->count2)
228 afs_merge_fs_addr4(alist, *bp++);
229
230 call->count -= count;
231 if (call->count > 0)
232 goto again;
233 call->offset = 0;
234 call->unmarshall++;
235 break;
236 }
David Howells08e0e7c2007-04-26 15:55:03 -0700237
238 _leave(" = 0 [done]");
239 return 0;
David Howellsec268152007-04-26 15:49:28 -0700240}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
David Howellsd2ddc772017-11-02 15:27:50 +0000242static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
David Howellsd2ddc772017-11-02 15:27:50 +0000244 afs_put_server(call->net, (struct afs_server *)call->reply[0]);
245 kfree(call->reply[1]);
246 return afs_flat_call_destructor(call);
David Howellsec268152007-04-26 15:49:28 -0700247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249/*
David Howellsd2ddc772017-11-02 15:27:50 +0000250 * VL.GetAddrsU operation type.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 */
David Howellsd2ddc772017-11-02 15:27:50 +0000252static const struct afs_call_type afs_RXVLGetAddrsU = {
253 .name = "VL.GetAddrsU",
254 .deliver = afs_deliver_vl_get_addrs_u,
255 .destructor = afs_vl_get_addrs_u_destructor,
256};
257
258/*
259 * Dispatch an operation to get the addresses for a server, where the server is
260 * nominated by UUID.
261 */
262struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
263 struct afs_addr_cursor *ac,
264 struct key *key,
265 const uuid_t *uuid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
David Howellsd2ddc772017-11-02 15:27:50 +0000267 struct afs_ListAddrByAttributes__xdr *r;
268 const struct afs_uuid *u = (const struct afs_uuid *)uuid;
David Howells08e0e7c2007-04-26 15:55:03 -0700269 struct afs_call *call;
270 __be32 *bp;
David Howellsd2ddc772017-11-02 15:27:50 +0000271 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
David Howells08e0e7c2007-04-26 15:55:03 -0700273 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
David Howellsd2ddc772017-11-02 15:27:50 +0000275 call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
276 sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
277 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
David Howells08e0e7c2007-04-26 15:55:03 -0700278 if (!call)
David Howellsd2ddc772017-11-02 15:27:50 +0000279 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
David Howells00d3b7a2007-04-26 15:57:07 -0700281 call->key = key;
David Howellsd2ddc772017-11-02 15:27:50 +0000282 call->reply[0] = NULL;
283 call->ret_reply0 = true;
David Howells08e0e7c2007-04-26 15:55:03 -0700284
David Howellsd2ddc772017-11-02 15:27:50 +0000285 /* Marshall the parameters */
David Howells08e0e7c2007-04-26 15:55:03 -0700286 bp = call->request;
David Howellsd2ddc772017-11-02 15:27:50 +0000287 *bp++ = htonl(VLGETADDRSU);
288 r = (struct afs_ListAddrByAttributes__xdr *)bp;
289 r->Mask = htonl(AFS_VLADDR_UUID);
290 r->ipaddr = 0;
291 r->index = 0;
292 r->spare = 0;
293 r->uuid.time_low = u->time_low;
294 r->uuid.time_mid = htonl(ntohs(u->time_mid));
295 r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version));
296 r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
297 r->uuid.clock_seq_low = htonl(u->clock_seq_low);
298 for (i = 0; i < 6; i++)
299 r->uuid.node[i] = ntohl(u->node[i]);
David Howells08e0e7c2007-04-26 15:55:03 -0700300
David Howellsd2ddc772017-11-02 15:27:50 +0000301 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
David Howellsec268152007-04-26 15:49:28 -0700302}