1 /* vlclient.c: 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/init.h>
13 #include <linux/sched.h>
14 #include <rxrpc/rxrpc.h>
15 #include <rxrpc/transport.h>
16 #include <rxrpc/connection.h>
17 #include <rxrpc/call.h>
21 #include "kafsasyncd.h"
22 #include "kafstimod.h"
26 #define VLGETENTRYBYID 503 /* AFS Get Cache Entry By ID operation ID */
27 #define VLGETENTRYBYNAME 504 /* AFS Get Cache Entry By Name operation ID */
28 #define VLPROBE 514 /* AFS Probe Volume Location Service operation ID */
30 static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call
*call
);
31 static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call
*call
);
33 /*****************************************************************************/
35 * map afs VL abort codes to/from Linux error codes
36 * - called with call->lock held
38 static void afs_rxvl_aemap(struct rxrpc_call
*call
)
43 call
->app_err_state
, call
->app_abort_code
, call
->app_errno
);
45 switch (call
->app_err_state
) {
46 case RXRPC_ESTATE_LOCAL_ABORT
:
47 call
->app_abort_code
= -call
->app_errno
;
50 case RXRPC_ESTATE_PEER_ABORT
:
51 switch (call
->app_abort_code
) {
52 case AFSVL_IDEXIST
: err
= -EEXIST
; break;
53 case AFSVL_IO
: err
= -EREMOTEIO
; break;
54 case AFSVL_NAMEEXIST
: err
= -EEXIST
; break;
55 case AFSVL_CREATEFAIL
: err
= -EREMOTEIO
; break;
56 case AFSVL_NOENT
: err
= -ENOMEDIUM
; break;
57 case AFSVL_EMPTY
: err
= -ENOMEDIUM
; break;
58 case AFSVL_ENTDELETED
: err
= -ENOMEDIUM
; break;
59 case AFSVL_BADNAME
: err
= -EINVAL
; break;
60 case AFSVL_BADINDEX
: err
= -EINVAL
; break;
61 case AFSVL_BADVOLTYPE
: err
= -EINVAL
; break;
62 case AFSVL_BADSERVER
: err
= -EINVAL
; break;
63 case AFSVL_BADPARTITION
: err
= -EINVAL
; break;
64 case AFSVL_REPSFULL
: err
= -EFBIG
; break;
65 case AFSVL_NOREPSERVER
: err
= -ENOENT
; break;
66 case AFSVL_DUPREPSERVER
: err
= -EEXIST
; break;
67 case AFSVL_RWNOTFOUND
: err
= -ENOENT
; break;
68 case AFSVL_BADREFCOUNT
: err
= -EINVAL
; break;
69 case AFSVL_SIZEEXCEEDED
: err
= -EINVAL
; break;
70 case AFSVL_BADENTRY
: err
= -EINVAL
; break;
71 case AFSVL_BADVOLIDBUMP
: err
= -EINVAL
; break;
72 case AFSVL_IDALREADYHASHED
: err
= -EINVAL
; break;
73 case AFSVL_ENTRYLOCKED
: err
= -EBUSY
; break;
74 case AFSVL_BADVOLOPER
: err
= -EBADRQC
; break;
75 case AFSVL_BADRELLOCKTYPE
: err
= -EINVAL
; break;
76 case AFSVL_RERELEASE
: err
= -EREMOTEIO
; break;
77 case AFSVL_BADSERVERFLAG
: err
= -EINVAL
; break;
78 case AFSVL_PERM
: err
= -EACCES
; break;
79 case AFSVL_NOMEM
: err
= -EREMOTEIO
; break;
81 err
= afs_abort_to_error(call
->app_abort_code
);
84 call
->app_errno
= err
;
90 } /* end afs_rxvl_aemap() */
93 /*****************************************************************************/
95 * probe a volume location server to see if it is still alive -- unused
97 static int afs_rxvl_probe(struct afs_server
*server
, int alloc_flags
)
99 struct rxrpc_connection
*conn
;
100 struct rxrpc_call
*call
;
106 DECLARE_WAITQUEUE(myself
, current
);
108 /* get hold of the vlserver connection */
109 ret
= afs_server_get_vlconn(server
, &conn
);
113 /* create a call through that connection */
114 ret
= rxrpc_create_call(conn
, NULL
, NULL
, afs_rxvl_aemap
, &call
);
116 printk("kAFS: Unable to create call: %d\n", ret
);
119 call
->app_opcode
= VLPROBE
;
121 /* we want to get event notifications from the call */
122 add_wait_queue(&call
->waitq
, &myself
);
124 /* marshall the parameters */
125 param
[0] = htonl(VLPROBE
);
126 piov
[0].iov_len
= sizeof(param
);
127 piov
[0].iov_base
= param
;
129 /* send the parameters to the server */
130 ret
= rxrpc_call_write_data(call
, 1, piov
, RXRPC_LAST_PACKET
,
131 alloc_flags
, 0, &sent
);
135 /* wait for the reply to completely arrive */
137 set_current_state(TASK_INTERRUPTIBLE
);
138 if (call
->app_call_state
!= RXRPC_CSTATE_CLNT_RCV_REPLY
||
139 signal_pending(current
))
143 set_current_state(TASK_RUNNING
);
146 if (signal_pending(current
))
149 switch (call
->app_call_state
) {
150 case RXRPC_CSTATE_ERROR
:
151 ret
= call
->app_errno
;
154 case RXRPC_CSTATE_CLNT_GOT_REPLY
:
163 set_current_state(TASK_UNINTERRUPTIBLE
);
164 rxrpc_call_abort(call
, ret
);
168 set_current_state(TASK_RUNNING
);
169 remove_wait_queue(&call
->waitq
, &myself
);
170 rxrpc_put_call(call
);
172 rxrpc_put_connection(conn
);
176 } /* end afs_rxvl_probe() */
179 /*****************************************************************************/
181 * look up a volume location database entry by name
183 int afs_rxvl_get_entry_by_name(struct afs_server
*server
,
186 struct afs_cache_vlocation
*entry
)
188 DECLARE_WAITQUEUE(myself
, current
);
190 struct rxrpc_connection
*conn
;
191 struct rxrpc_call
*call
;
196 __be32
*bp
, param
[2], zero
;
198 _enter(",%*.*s,%u,", volnamesz
, volnamesz
, volname
, volnamesz
);
200 memset(entry
, 0, sizeof(*entry
));
202 /* get hold of the vlserver connection */
203 ret
= afs_server_get_vlconn(server
, &conn
);
207 /* create a call through that connection */
208 ret
= rxrpc_create_call(conn
, NULL
, NULL
, afs_rxvl_aemap
, &call
);
210 printk("kAFS: Unable to create call: %d\n", ret
);
213 call
->app_opcode
= VLGETENTRYBYNAME
;
215 /* we want to get event notifications from the call */
216 add_wait_queue(&call
->waitq
, &myself
);
218 /* marshall the parameters */
219 piov
[1].iov_len
= volnamesz
;
220 piov
[1].iov_base
= (char *) volname
;
223 piov
[2].iov_len
= (4 - (piov
[1].iov_len
& 3)) & 3;
224 piov
[2].iov_base
= &zero
;
226 param
[0] = htonl(VLGETENTRYBYNAME
);
227 param
[1] = htonl(piov
[1].iov_len
);
229 piov
[0].iov_len
= sizeof(param
);
230 piov
[0].iov_base
= param
;
232 /* send the parameters to the server */
233 ret
= rxrpc_call_write_data(call
, 3, piov
, RXRPC_LAST_PACKET
, GFP_NOFS
,
238 /* wait for the reply to completely arrive */
239 bp
= rxrpc_call_alloc_scratch(call
, 384);
241 ret
= rxrpc_call_read_data(call
, bp
, 384,
242 RXRPC_CALL_READ_BLOCK
|
243 RXRPC_CALL_READ_ALL
);
245 if (ret
== -ECONNABORTED
) {
246 ret
= call
->app_errno
;
252 /* unmarshall the reply */
253 for (loop
= 0; loop
< 64; loop
++)
254 entry
->name
[loop
] = ntohl(*bp
++);
255 bp
++; /* final NUL */
258 entry
->nservers
= ntohl(*bp
++);
260 for (loop
= 0; loop
< 8; loop
++)
261 entry
->servers
[loop
].s_addr
= *bp
++;
263 bp
+= 8; /* partition IDs */
265 for (loop
= 0; loop
< 8; loop
++) {
267 if (tmp
& AFS_VLSF_RWVOL
)
268 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_RW
;
269 if (tmp
& AFS_VLSF_ROVOL
)
270 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_RO
;
271 if (tmp
& AFS_VLSF_BACKVOL
)
272 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_BAK
;
275 entry
->vid
[0] = ntohl(*bp
++);
276 entry
->vid
[1] = ntohl(*bp
++);
277 entry
->vid
[2] = ntohl(*bp
++);
281 tmp
= ntohl(*bp
++); /* flags */
282 if (tmp
& AFS_VLF_RWEXISTS
)
283 entry
->vidmask
|= AFS_VOL_VTM_RW
;
284 if (tmp
& AFS_VLF_ROEXISTS
)
285 entry
->vidmask
|= AFS_VOL_VTM_RO
;
286 if (tmp
& AFS_VLF_BACKEXISTS
)
287 entry
->vidmask
|= AFS_VOL_VTM_BAK
;
294 entry
->rtime
= get_seconds();
298 set_current_state(TASK_RUNNING
);
299 remove_wait_queue(&call
->waitq
, &myself
);
300 rxrpc_put_call(call
);
302 rxrpc_put_connection(conn
);
304 _leave(" = %d", ret
);
308 set_current_state(TASK_UNINTERRUPTIBLE
);
309 rxrpc_call_abort(call
, ret
);
312 } /* end afs_rxvl_get_entry_by_name() */
314 /*****************************************************************************/
316 * look up a volume location database entry by ID
318 int afs_rxvl_get_entry_by_id(struct afs_server
*server
,
320 afs_voltype_t voltype
,
321 struct afs_cache_vlocation
*entry
)
323 DECLARE_WAITQUEUE(myself
, current
);
325 struct rxrpc_connection
*conn
;
326 struct rxrpc_call
*call
;
331 __be32
*bp
, param
[3];
333 _enter(",%x,%d,", volid
, voltype
);
335 memset(entry
, 0, sizeof(*entry
));
337 /* get hold of the vlserver connection */
338 ret
= afs_server_get_vlconn(server
, &conn
);
342 /* create a call through that connection */
343 ret
= rxrpc_create_call(conn
, NULL
, NULL
, afs_rxvl_aemap
, &call
);
345 printk("kAFS: Unable to create call: %d\n", ret
);
348 call
->app_opcode
= VLGETENTRYBYID
;
350 /* we want to get event notifications from the call */
351 add_wait_queue(&call
->waitq
, &myself
);
353 /* marshall the parameters */
354 param
[0] = htonl(VLGETENTRYBYID
);
355 param
[1] = htonl(volid
);
356 param
[2] = htonl(voltype
);
358 piov
[0].iov_len
= sizeof(param
);
359 piov
[0].iov_base
= param
;
361 /* send the parameters to the server */
362 ret
= rxrpc_call_write_data(call
, 1, piov
, RXRPC_LAST_PACKET
, GFP_NOFS
,
367 /* wait for the reply to completely arrive */
368 bp
= rxrpc_call_alloc_scratch(call
, 384);
370 ret
= rxrpc_call_read_data(call
, bp
, 384,
371 RXRPC_CALL_READ_BLOCK
|
372 RXRPC_CALL_READ_ALL
);
374 if (ret
== -ECONNABORTED
) {
375 ret
= call
->app_errno
;
381 /* unmarshall the reply */
382 for (loop
= 0; loop
< 64; loop
++)
383 entry
->name
[loop
] = ntohl(*bp
++);
384 bp
++; /* final NUL */
387 entry
->nservers
= ntohl(*bp
++);
389 for (loop
= 0; loop
< 8; loop
++)
390 entry
->servers
[loop
].s_addr
= *bp
++;
392 bp
+= 8; /* partition IDs */
394 for (loop
= 0; loop
< 8; loop
++) {
396 if (tmp
& AFS_VLSF_RWVOL
)
397 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_RW
;
398 if (tmp
& AFS_VLSF_ROVOL
)
399 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_RO
;
400 if (tmp
& AFS_VLSF_BACKVOL
)
401 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_BAK
;
404 entry
->vid
[0] = ntohl(*bp
++);
405 entry
->vid
[1] = ntohl(*bp
++);
406 entry
->vid
[2] = ntohl(*bp
++);
410 tmp
= ntohl(*bp
++); /* flags */
411 if (tmp
& AFS_VLF_RWEXISTS
)
412 entry
->vidmask
|= AFS_VOL_VTM_RW
;
413 if (tmp
& AFS_VLF_ROEXISTS
)
414 entry
->vidmask
|= AFS_VOL_VTM_RO
;
415 if (tmp
& AFS_VLF_BACKEXISTS
)
416 entry
->vidmask
|= AFS_VOL_VTM_BAK
;
422 #if 0 /* TODO: remove */
424 entry
->servers
[0].s_addr
= htonl(0xac101249);
425 entry
->servers
[1].s_addr
= htonl(0xac101243);
426 entry
->servers
[2].s_addr
= htonl(0xac10125b /*0xac10125b*/);
428 entry
->srvtmask
[0] = AFS_VOL_VTM_RO
;
429 entry
->srvtmask
[1] = AFS_VOL_VTM_RO
;
430 entry
->srvtmask
[2] = AFS_VOL_VTM_RO
| AFS_VOL_VTM_RW
;
434 entry
->rtime
= get_seconds();
438 set_current_state(TASK_RUNNING
);
439 remove_wait_queue(&call
->waitq
, &myself
);
440 rxrpc_put_call(call
);
442 rxrpc_put_connection(conn
);
444 _leave(" = %d", ret
);
448 set_current_state(TASK_UNINTERRUPTIBLE
);
449 rxrpc_call_abort(call
, ret
);
452 } /* end afs_rxvl_get_entry_by_id() */
454 /*****************************************************************************/
456 * look up a volume location database entry by ID asynchronously
458 int afs_rxvl_get_entry_by_id_async(struct afs_async_op
*op
,
460 afs_voltype_t voltype
)
462 struct rxrpc_connection
*conn
;
463 struct rxrpc_call
*call
;
469 _enter(",%x,%d,", volid
, voltype
);
471 /* get hold of the vlserver connection */
472 ret
= afs_server_get_vlconn(op
->server
, &conn
);
474 _leave(" = %d", ret
);
478 /* create a call through that connection */
479 ret
= rxrpc_create_call(conn
,
480 afs_rxvl_get_entry_by_id_attn
,
481 afs_rxvl_get_entry_by_id_error
,
484 rxrpc_put_connection(conn
);
487 printk("kAFS: Unable to create call: %d\n", ret
);
488 _leave(" = %d", ret
);
492 op
->call
->app_opcode
= VLGETENTRYBYID
;
493 op
->call
->app_user
= op
;
496 rxrpc_get_call(call
);
498 /* send event notifications from the call to kafsasyncd */
499 afs_kafsasyncd_begin_op(op
);
501 /* marshall the parameters */
502 param
[0] = htonl(VLGETENTRYBYID
);
503 param
[1] = htonl(volid
);
504 param
[2] = htonl(voltype
);
506 piov
[0].iov_len
= sizeof(param
);
507 piov
[0].iov_base
= param
;
509 /* allocate result read buffer in scratch space */
510 call
->app_scr_ptr
= rxrpc_call_alloc_scratch(op
->call
, 384);
512 /* send the parameters to the server */
513 ret
= rxrpc_call_write_data(call
, 1, piov
, RXRPC_LAST_PACKET
, GFP_NOFS
,
516 rxrpc_call_abort(call
, ret
); /* handle from kafsasyncd */
521 /* wait for the reply to completely arrive */
522 ret
= rxrpc_call_read_data(call
, call
->app_scr_ptr
, 384, 0);
528 break; /* all handled by kafsasyncd */
531 rxrpc_call_abort(call
, ret
); /* make kafsasyncd handle it */
537 rxrpc_put_call(call
);
538 _leave(" = %d", ret
);
541 } /* end afs_rxvl_get_entry_by_id_async() */
543 /*****************************************************************************/
545 * attend to the asynchronous get VLDB entry by ID
547 int afs_rxvl_get_entry_by_id_async2(struct afs_async_op
*op
,
548 struct afs_cache_vlocation
*entry
)
554 _enter("{op=%p cst=%u}", op
, op
->call
->app_call_state
);
556 memset(entry
, 0, sizeof(*entry
));
558 if (op
->call
->app_call_state
== RXRPC_CSTATE_COMPLETE
) {
559 /* operation finished */
560 afs_kafsasyncd_terminate_op(op
);
562 bp
= op
->call
->app_scr_ptr
;
564 /* unmarshall the reply */
565 for (loop
= 0; loop
< 64; loop
++)
566 entry
->name
[loop
] = ntohl(*bp
++);
567 bp
++; /* final NUL */
570 entry
->nservers
= ntohl(*bp
++);
572 for (loop
= 0; loop
< 8; loop
++)
573 entry
->servers
[loop
].s_addr
= *bp
++;
575 bp
+= 8; /* partition IDs */
577 for (loop
= 0; loop
< 8; loop
++) {
579 if (tmp
& AFS_VLSF_RWVOL
)
580 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_RW
;
581 if (tmp
& AFS_VLSF_ROVOL
)
582 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_RO
;
583 if (tmp
& AFS_VLSF_BACKVOL
)
584 entry
->srvtmask
[loop
] |= AFS_VOL_VTM_BAK
;
587 entry
->vid
[0] = ntohl(*bp
++);
588 entry
->vid
[1] = ntohl(*bp
++);
589 entry
->vid
[2] = ntohl(*bp
++);
593 tmp
= ntohl(*bp
++); /* flags */
594 if (tmp
& AFS_VLF_RWEXISTS
)
595 entry
->vidmask
|= AFS_VOL_VTM_RW
;
596 if (tmp
& AFS_VLF_ROEXISTS
)
597 entry
->vidmask
|= AFS_VOL_VTM_RO
;
598 if (tmp
& AFS_VLF_BACKEXISTS
)
599 entry
->vidmask
|= AFS_VOL_VTM_BAK
;
602 if (!entry
->vidmask
) {
603 rxrpc_call_abort(op
->call
, ret
);
607 #if 0 /* TODO: remove */
609 entry
->servers
[0].s_addr
= htonl(0xac101249);
610 entry
->servers
[1].s_addr
= htonl(0xac101243);
611 entry
->servers
[2].s_addr
= htonl(0xac10125b /*0xac10125b*/);
613 entry
->srvtmask
[0] = AFS_VOL_VTM_RO
;
614 entry
->srvtmask
[1] = AFS_VOL_VTM_RO
;
615 entry
->srvtmask
[2] = AFS_VOL_VTM_RO
| AFS_VOL_VTM_RW
;
619 entry
->rtime
= get_seconds();
624 if (op
->call
->app_call_state
== RXRPC_CSTATE_ERROR
) {
625 /* operation error */
626 ret
= op
->call
->app_errno
;
630 _leave(" = -EAGAIN");
634 rxrpc_put_call(op
->call
);
636 _leave(" = %d", ret
);
638 } /* end afs_rxvl_get_entry_by_id_async2() */
640 /*****************************************************************************/
642 * handle attention events on an async get-entry-by-ID op
643 * - called from krxiod
645 static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call
*call
)
647 struct afs_async_op
*op
= call
->app_user
;
649 _enter("{op=%p cst=%u}", op
, call
->app_call_state
);
651 switch (call
->app_call_state
) {
652 case RXRPC_CSTATE_COMPLETE
:
653 afs_kafsasyncd_attend_op(op
);
655 case RXRPC_CSTATE_CLNT_RCV_REPLY
:
656 if (call
->app_async_read
)
658 case RXRPC_CSTATE_CLNT_GOT_REPLY
:
659 if (call
->app_read_count
== 0)
661 printk("kAFS: Reply bigger than expected"
662 " {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}",
663 call
->app_call_state
,
664 call
->app_async_read
,
668 call
->app_last_rcv
? " last" : "");
670 rxrpc_call_abort(call
, -EBADMSG
);
678 } /* end afs_rxvl_get_entry_by_id_attn() */
680 /*****************************************************************************/
682 * handle error events on an async get-entry-by-ID op
683 * - called from krxiod
685 static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call
*call
)
687 struct afs_async_op
*op
= call
->app_user
;
689 _enter("{op=%p cst=%u}", op
, call
->app_call_state
);
691 afs_kafsasyncd_attend_op(op
);
695 } /* end afs_rxvl_get_entry_by_id_error() */