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() */