1 /* AFS Volume Location Service client
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/gfp.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
19 * Deliver reply data to a VL.GetEntryByNameU call.
21 static int afs_deliver_vl_get_entry_by_name_u(struct afs_call
*call
)
23 struct afs_uvldbentry__xdr
*uvldb
;
24 struct afs_vldb_entry
*entry
;
25 bool new_only
= false;
31 ret
= afs_transfer_reply(call
);
35 /* unmarshall the reply once we've received all of it */
37 entry
= call
->reply
[0];
39 nr_servers
= ntohl(uvldb
->nServers
);
40 if (nr_servers
> AFS_NMAXNSERVERS
)
41 nr_servers
= AFS_NMAXNSERVERS
;
43 for (i
= 0; i
< ARRAY_SIZE(uvldb
->name
) - 1; i
++)
44 entry
->name
[i
] = (u8
)ntohl(uvldb
->name
[i
]);
46 entry
->name_len
= strlen(entry
->name
);
48 /* If there is a new replication site that we can use, ignore all the
49 * sites that aren't marked as new.
51 for (i
= 0; i
< nr_servers
; i
++) {
52 tmp
= ntohl(uvldb
->serverFlags
[i
]);
53 if (!(tmp
& AFS_VLSF_DONTUSE
) &&
54 (tmp
& AFS_VLSF_NEWREPSITE
))
58 for (i
= 0; i
< nr_servers
; i
++) {
59 struct afs_uuid__xdr
*xdr
;
60 struct afs_uuid
*uuid
;
63 tmp
= ntohl(uvldb
->serverFlags
[i
]);
64 if (tmp
& AFS_VLSF_DONTUSE
||
65 (new_only
&& !(tmp
& AFS_VLSF_NEWREPSITE
)))
67 if (tmp
& AFS_VLSF_RWVOL
)
68 entry
->fs_mask
[i
] |= AFS_VOL_VTM_RW
;
69 if (tmp
& AFS_VLSF_ROVOL
)
70 entry
->fs_mask
[i
] |= AFS_VOL_VTM_RO
;
71 if (tmp
& AFS_VLSF_BACKVOL
)
72 entry
->fs_mask
[i
] |= AFS_VOL_VTM_BAK
;
73 if (!entry
->fs_mask
[i
])
76 xdr
= &uvldb
->serverNumber
[i
];
77 uuid
= (struct afs_uuid
*)&entry
->fs_server
[i
];
78 uuid
->time_low
= xdr
->time_low
;
79 uuid
->time_mid
= htons(ntohl(xdr
->time_mid
));
80 uuid
->time_hi_and_version
= htons(ntohl(xdr
->time_hi_and_version
));
81 uuid
->clock_seq_hi_and_reserved
= (u8
)ntohl(xdr
->clock_seq_hi_and_reserved
);
82 uuid
->clock_seq_low
= (u8
)ntohl(xdr
->clock_seq_low
);
83 for (j
= 0; j
< 6; j
++)
84 uuid
->node
[j
] = (u8
)ntohl(xdr
->node
[j
]);
89 for (i
= 0; i
< AFS_MAXTYPES
; i
++)
90 entry
->vid
[i
] = ntohl(uvldb
->volumeId
[i
]);
92 tmp
= ntohl(uvldb
->flags
);
93 if (tmp
& AFS_VLF_RWEXISTS
)
94 __set_bit(AFS_VLDB_HAS_RW
, &entry
->flags
);
95 if (tmp
& AFS_VLF_ROEXISTS
)
96 __set_bit(AFS_VLDB_HAS_RO
, &entry
->flags
);
97 if (tmp
& AFS_VLF_BACKEXISTS
)
98 __set_bit(AFS_VLDB_HAS_BAK
, &entry
->flags
);
100 if (!(tmp
& (AFS_VLF_RWEXISTS
| AFS_VLF_ROEXISTS
| AFS_VLF_BACKEXISTS
))) {
101 entry
->error
= -ENOMEDIUM
;
102 __set_bit(AFS_VLDB_QUERY_ERROR
, &entry
->flags
);
105 __set_bit(AFS_VLDB_QUERY_VALID
, &entry
->flags
);
106 _leave(" = 0 [done]");
110 static void afs_destroy_vl_get_entry_by_name_u(struct afs_call
*call
)
112 kfree(call
->reply
[0]);
113 afs_flat_call_destructor(call
);
117 * VL.GetEntryByNameU operation type.
119 static const struct afs_call_type afs_RXVLGetEntryByNameU
= {
120 .name
= "VL.GetEntryByNameU",
121 .op
= afs_VL_GetEntryByNameU
,
122 .deliver
= afs_deliver_vl_get_entry_by_name_u
,
123 .destructor
= afs_destroy_vl_get_entry_by_name_u
,
127 * Dispatch a get volume entry by name or ID operation (uuid variant). If the
128 * volname is a decimal number then it's a volume ID not a volume name.
130 struct afs_vldb_entry
*afs_vl_get_entry_by_name_u(struct afs_net
*net
,
131 struct afs_addr_cursor
*ac
,
136 struct afs_vldb_entry
*entry
;
137 struct afs_call
*call
;
143 padsz
= (4 - (volnamesz
& 3)) & 3;
144 reqsz
= 8 + volnamesz
+ padsz
;
146 entry
= kzalloc(sizeof(struct afs_vldb_entry
), GFP_KERNEL
);
148 return ERR_PTR(-ENOMEM
);
150 call
= afs_alloc_flat_call(net
, &afs_RXVLGetEntryByNameU
, reqsz
,
151 sizeof(struct afs_uvldbentry__xdr
));
154 return ERR_PTR(-ENOMEM
);
158 call
->reply
[0] = entry
;
159 call
->ret_reply0
= true;
161 /* Marshall the parameters */
163 *bp
++ = htonl(VLGETENTRYBYNAMEU
);
164 *bp
++ = htonl(volnamesz
);
165 memcpy(bp
, volname
, volnamesz
);
167 memset((void *)bp
+ volnamesz
, 0, padsz
);
169 trace_afs_make_vl_call(call
);
170 return (struct afs_vldb_entry
*)afs_make_call(ac
, call
, GFP_KERNEL
, false);
174 * Deliver reply data to a VL.GetAddrsU call.
176 * GetAddrsU(IN ListAddrByAttributes *inaddr,
177 * OUT afsUUID *uuidp1,
178 * OUT uint32_t *uniquifier,
179 * OUT uint32_t *nentries,
180 * OUT bulkaddrs *blkaddrs);
182 static int afs_deliver_vl_get_addrs_u(struct afs_call
*call
)
184 struct afs_addr_list
*alist
;
186 u32 uniquifier
, nentries
, count
;
189 _enter("{%u,%zu/%u}", call
->unmarshall
, call
->offset
, call
->count
);
192 switch (call
->unmarshall
) {
197 /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
199 ret
= afs_extract_data(call
, call
->buffer
,
200 sizeof(struct afs_uuid__xdr
) + 3 * sizeof(__be32
),
205 bp
= call
->buffer
+ sizeof(struct afs_uuid__xdr
);
206 uniquifier
= ntohl(*bp
++);
207 nentries
= ntohl(*bp
++);
210 nentries
= min(nentries
, count
);
211 alist
= afs_alloc_addrlist(nentries
, FS_SERVICE
, AFS_FS_PORT
);
214 alist
->version
= uniquifier
;
215 call
->reply
[0] = alist
;
217 call
->count2
= nentries
;
221 /* Extract entries */
223 count
= min(call
->count
, 4U);
224 ret
= afs_extract_data(call
, call
->buffer
,
225 count
* sizeof(__be32
),
230 alist
= call
->reply
[0];
232 for (i
= 0; i
< count
; i
++)
233 if (alist
->nr_addrs
< call
->count2
)
234 afs_merge_fs_addr4(alist
, *bp
++, AFS_FS_PORT
);
236 call
->count
-= count
;
244 _leave(" = 0 [done]");
248 static void afs_vl_get_addrs_u_destructor(struct afs_call
*call
)
250 afs_put_server(call
->net
, (struct afs_server
*)call
->reply
[0]);
251 kfree(call
->reply
[1]);
252 return afs_flat_call_destructor(call
);
256 * VL.GetAddrsU operation type.
258 static const struct afs_call_type afs_RXVLGetAddrsU
= {
259 .name
= "VL.GetAddrsU",
260 .op
= afs_VL_GetAddrsU
,
261 .deliver
= afs_deliver_vl_get_addrs_u
,
262 .destructor
= afs_vl_get_addrs_u_destructor
,
266 * Dispatch an operation to get the addresses for a server, where the server is
269 struct afs_addr_list
*afs_vl_get_addrs_u(struct afs_net
*net
,
270 struct afs_addr_cursor
*ac
,
274 struct afs_ListAddrByAttributes__xdr
*r
;
275 const struct afs_uuid
*u
= (const struct afs_uuid
*)uuid
;
276 struct afs_call
*call
;
282 call
= afs_alloc_flat_call(net
, &afs_RXVLGetAddrsU
,
283 sizeof(__be32
) + sizeof(struct afs_ListAddrByAttributes__xdr
),
284 sizeof(struct afs_uuid__xdr
) + 3 * sizeof(__be32
));
286 return ERR_PTR(-ENOMEM
);
289 call
->reply
[0] = NULL
;
290 call
->ret_reply0
= true;
292 /* Marshall the parameters */
294 *bp
++ = htonl(VLGETADDRSU
);
295 r
= (struct afs_ListAddrByAttributes__xdr
*)bp
;
296 r
->Mask
= htonl(AFS_VLADDR_UUID
);
300 r
->uuid
.time_low
= u
->time_low
;
301 r
->uuid
.time_mid
= htonl(ntohs(u
->time_mid
));
302 r
->uuid
.time_hi_and_version
= htonl(ntohs(u
->time_hi_and_version
));
303 r
->uuid
.clock_seq_hi_and_reserved
= htonl(u
->clock_seq_hi_and_reserved
);
304 r
->uuid
.clock_seq_low
= htonl(u
->clock_seq_low
);
305 for (i
= 0; i
< 6; i
++)
306 r
->uuid
.node
[i
] = ntohl(u
->node
[i
]);
308 trace_afs_make_vl_call(call
);
309 return (struct afs_addr_list
*)afs_make_call(ac
, call
, GFP_KERNEL
, false);
313 * Deliver reply data to an VL.GetCapabilities operation.
315 static int afs_deliver_vl_get_capabilities(struct afs_call
*call
)
320 _enter("{%u,%zu/%u}", call
->unmarshall
, call
->offset
, call
->count
);
323 switch (call
->unmarshall
) {
328 /* Extract the capabilities word count */
330 ret
= afs_extract_data(call
, &call
->tmp
,
336 count
= ntohl(call
->tmp
);
339 call
->count2
= count
;
343 /* Extract capabilities words */
345 count
= min(call
->count
, 16U);
346 ret
= afs_extract_data(call
, call
->buffer
,
347 count
* sizeof(__be32
),
352 /* TODO: Examine capabilities */
354 call
->count
-= count
;
362 call
->reply
[0] = (void *)(unsigned long)call
->service_id
;
364 _leave(" = 0 [done]");
369 * VL.GetCapabilities operation type
371 static const struct afs_call_type afs_RXVLGetCapabilities
= {
372 .name
= "VL.GetCapabilities",
373 .op
= afs_VL_GetCapabilities
,
374 .deliver
= afs_deliver_vl_get_capabilities
,
375 .destructor
= afs_flat_call_destructor
,
379 * Probe a fileserver for the capabilities that it supports. This can
380 * return up to 196 words.
382 * We use this to probe for service upgrade to determine what the server at the
383 * other end supports.
385 int afs_vl_get_capabilities(struct afs_net
*net
,
386 struct afs_addr_cursor
*ac
,
389 struct afs_call
*call
;
394 call
= afs_alloc_flat_call(net
, &afs_RXVLGetCapabilities
, 1 * 4, 16 * 4);
399 call
->upgrade
= true; /* Let's see if this is a YFS server */
400 call
->reply
[0] = (void *)VLGETCAPABILITIES
;
401 call
->ret_reply0
= true;
403 /* marshall the parameters */
405 *bp
++ = htonl(VLGETCAPABILITIES
);
407 /* Can't take a ref on server */
408 trace_afs_make_vl_call(call
);
409 return afs_make_call(ac
, call
, GFP_KERNEL
, false);
413 * Deliver reply data to a YFSVL.GetEndpoints call.
415 * GetEndpoints(IN yfsServerAttributes *attr,
416 * OUT opr_uuid *uuid,
417 * OUT afs_int32 *uniquifier,
418 * OUT endpoints *fsEndpoints,
419 * OUT endpoints *volEndpoints)
421 static int afs_deliver_yfsvl_get_endpoints(struct afs_call
*call
)
423 struct afs_addr_list
*alist
;
425 u32 uniquifier
, size
;
428 _enter("{%u,%zu/%u,%u}", call
->unmarshall
, call
->offset
, call
->count
, call
->count2
);
431 switch (call
->unmarshall
) {
434 call
->unmarshall
= 1;
436 /* Extract the returned uuid, uniquifier, fsEndpoints count and
437 * either the first fsEndpoint type or the volEndpoints
438 * count if there are no fsEndpoints. */
440 ret
= afs_extract_data(call
, call
->buffer
,
447 bp
= call
->buffer
+ sizeof(uuid_t
);
448 uniquifier
= ntohl(*bp
++);
449 call
->count
= ntohl(*bp
++);
450 call
->count2
= ntohl(*bp
); /* Type or next count */
452 if (call
->count
> YFS_MAXENDPOINTS
)
455 alist
= afs_alloc_addrlist(call
->count
, FS_SERVICE
, AFS_FS_PORT
);
458 alist
->version
= uniquifier
;
459 call
->reply
[0] = alist
;
462 if (call
->count
== 0)
463 goto extract_volendpoints
;
465 call
->unmarshall
= 2;
467 /* Extract fsEndpoints[] entries */
469 switch (call
->count2
) {
470 case YFS_ENDPOINT_IPV4
:
471 size
= sizeof(__be32
) * (1 + 1 + 1);
473 case YFS_ENDPOINT_IPV6
:
474 size
= sizeof(__be32
) * (1 + 4 + 1);
480 size
+= sizeof(__be32
);
481 ret
= afs_extract_data(call
, call
->buffer
, size
, true);
485 alist
= call
->reply
[0];
487 switch (call
->count2
) {
488 case YFS_ENDPOINT_IPV4
:
489 if (ntohl(bp
[0]) != sizeof(__be32
) * 2)
491 afs_merge_fs_addr4(alist
, bp
[1], ntohl(bp
[2]));
494 case YFS_ENDPOINT_IPV6
:
495 if (ntohl(bp
[0]) != sizeof(__be32
) * 5)
497 afs_merge_fs_addr6(alist
, bp
+ 1, ntohl(bp
[5]));
504 /* Got either the type of the next entry or the count of
505 * volEndpoints if no more fsEndpoints.
507 call
->count2
= htonl(*bp
++);
514 extract_volendpoints
:
515 /* Extract the list of volEndpoints. */
516 call
->count
= call
->count2
;
519 if (call
->count
> YFS_MAXENDPOINTS
)
522 call
->unmarshall
= 3;
524 /* Extract the type of volEndpoints[0]. Normally we would
525 * extract the type of the next endpoint when we extract the
526 * data of the current one, but this is the first...
529 ret
= afs_extract_data(call
, call
->buffer
, sizeof(__be32
), true);
534 call
->count2
= htonl(*bp
++);
536 call
->unmarshall
= 4;
538 /* Extract volEndpoints[] entries */
540 switch (call
->count2
) {
541 case YFS_ENDPOINT_IPV4
:
542 size
= sizeof(__be32
) * (1 + 1 + 1);
544 case YFS_ENDPOINT_IPV6
:
545 size
= sizeof(__be32
) * (1 + 4 + 1);
552 size
+= sizeof(__be32
);
553 ret
= afs_extract_data(call
, call
->buffer
, size
, true);
558 switch (call
->count2
) {
559 case YFS_ENDPOINT_IPV4
:
560 if (ntohl(bp
[0]) != sizeof(__be32
) * 2)
564 case YFS_ENDPOINT_IPV6
:
565 if (ntohl(bp
[0]) != sizeof(__be32
) * 5)
573 /* Got either the type of the next entry or the count of
574 * volEndpoints if no more fsEndpoints.
578 if (call
->count
> 0) {
579 call
->count2
= htonl(*bp
++);
584 call
->unmarshall
= 5;
588 ret
= afs_extract_data(call
, call
->buffer
, 0, false);
591 call
->unmarshall
= 6;
597 alist
= call
->reply
[0];
599 /* Start with IPv6 if available. */
600 if (alist
->nr_ipv4
< alist
->nr_addrs
)
601 alist
->index
= alist
->nr_ipv4
;
603 _leave(" = 0 [done]");
608 * YFSVL.GetEndpoints operation type.
610 static const struct afs_call_type afs_YFSVLGetEndpoints
= {
611 .name
= "YFSVL.GetEndpoints",
612 .op
= afs_YFSVL_GetEndpoints
,
613 .deliver
= afs_deliver_yfsvl_get_endpoints
,
614 .destructor
= afs_vl_get_addrs_u_destructor
,
618 * Dispatch an operation to get the addresses for a server, where the server is
621 struct afs_addr_list
*afs_yfsvl_get_endpoints(struct afs_net
*net
,
622 struct afs_addr_cursor
*ac
,
626 struct afs_call
*call
;
631 call
= afs_alloc_flat_call(net
, &afs_YFSVLGetEndpoints
,
632 sizeof(__be32
) * 2 + sizeof(*uuid
),
633 sizeof(struct in6_addr
) + sizeof(__be32
) * 3);
635 return ERR_PTR(-ENOMEM
);
638 call
->reply
[0] = NULL
;
639 call
->ret_reply0
= true;
641 /* Marshall the parameters */
643 *bp
++ = htonl(YVLGETENDPOINTS
);
644 *bp
++ = htonl(YFS_SERVER_UUID
);
645 memcpy(bp
, uuid
, sizeof(*uuid
)); /* Type opr_uuid */
647 trace_afs_make_vl_call(call
);
648 return (struct afs_addr_list
*)afs_make_call(ac
, call
, GFP_KERNEL
, false);