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() */
92 /*****************************************************************************/
94 * probe a volume location server to see if it is still alive
96 int afs_rxvl_probe(struct afs_server *server, int alloc_flags)
98 struct rxrpc_connection *conn;
99 struct rxrpc_call *call;
100 struct iovec piov[1];
105 DECLARE_WAITQUEUE(myself, current);
107 /* get hold of the vlserver connection */
108 ret = afs_server_get_vlconn(server, &conn);
112 /* create a call through that connection */
113 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
115 printk("kAFS: Unable to create call: %d\n", ret);
118 call->app_opcode = VLPROBE;
120 /* we want to get event notifications from the call */
121 add_wait_queue(&call->waitq, &myself);
123 /* marshall the parameters */
124 param[0] = htonl(VLPROBE);
125 piov[0].iov_len = sizeof(param);
126 piov[0].iov_base = param;
128 /* send the parameters to the server */
129 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET,
130 alloc_flags, 0, &sent);
134 /* wait for the reply to completely arrive */
136 set_current_state(TASK_INTERRUPTIBLE);
137 if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
138 signal_pending(current))
142 set_current_state(TASK_RUNNING);
145 if (signal_pending(current))
148 switch (call->app_call_state) {
149 case RXRPC_CSTATE_ERROR:
150 ret = call->app_errno;
153 case RXRPC_CSTATE_CLNT_GOT_REPLY:
162 set_current_state(TASK_UNINTERRUPTIBLE);
163 rxrpc_call_abort(call, ret);
167 set_current_state(TASK_RUNNING);
168 remove_wait_queue(&call->waitq, &myself);
169 rxrpc_put_call(call);
171 rxrpc_put_connection(conn);
175 } /* end afs_rxvl_probe() */
177 /*****************************************************************************/
179 * look up a volume location database entry by name
181 int afs_rxvl_get_entry_by_name(struct afs_server *server,
184 struct afs_cache_vlocation *entry)
186 DECLARE_WAITQUEUE(myself, current);
188 struct rxrpc_connection *conn;
189 struct rxrpc_call *call;
190 struct iovec piov[3];
194 u32 *bp, param[2], zero;
196 _enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz);
198 memset(entry, 0, sizeof(*entry));
200 /* get hold of the vlserver connection */
201 ret = afs_server_get_vlconn(server, &conn);
205 /* create a call through that connection */
206 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
208 printk("kAFS: Unable to create call: %d\n", ret);
211 call->app_opcode = VLGETENTRYBYNAME;
213 /* we want to get event notifications from the call */
214 add_wait_queue(&call->waitq, &myself);
216 /* marshall the parameters */
217 piov[1].iov_len = volnamesz;
218 piov[1].iov_base = (char *) volname;
221 piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
222 piov[2].iov_base = &zero;
224 param[0] = htonl(VLGETENTRYBYNAME);
225 param[1] = htonl(piov[1].iov_len);
227 piov[0].iov_len = sizeof(param);
228 piov[0].iov_base = param;
230 /* send the parameters to the server */
231 ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
236 /* wait for the reply to completely arrive */
237 bp = rxrpc_call_alloc_scratch(call, 384);
239 ret = rxrpc_call_read_data(call, bp, 384,
240 RXRPC_CALL_READ_BLOCK |
241 RXRPC_CALL_READ_ALL);
243 if (ret == -ECONNABORTED) {
244 ret = call->app_errno;
250 /* unmarshall the reply */
251 for (loop = 0; loop < 64; loop++)
252 entry->name[loop] = ntohl(*bp++);
253 bp++; /* final NUL */
256 entry->nservers = ntohl(*bp++);
258 for (loop = 0; loop < 8; loop++)
259 entry->servers[loop].s_addr = *bp++;
261 bp += 8; /* partition IDs */
263 for (loop = 0; loop < 8; loop++) {
265 if (tmp & AFS_VLSF_RWVOL)
266 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
267 if (tmp & AFS_VLSF_ROVOL)
268 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
269 if (tmp & AFS_VLSF_BACKVOL)
270 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
273 entry->vid[0] = ntohl(*bp++);
274 entry->vid[1] = ntohl(*bp++);
275 entry->vid[2] = ntohl(*bp++);
279 tmp = ntohl(*bp++); /* flags */
280 if (tmp & AFS_VLF_RWEXISTS)
281 entry->vidmask |= AFS_VOL_VTM_RW;
282 if (tmp & AFS_VLF_ROEXISTS)
283 entry->vidmask |= AFS_VOL_VTM_RO;
284 if (tmp & AFS_VLF_BACKEXISTS)
285 entry->vidmask |= AFS_VOL_VTM_BAK;
292 entry->rtime = get_seconds();
296 set_current_state(TASK_RUNNING);
297 remove_wait_queue(&call->waitq, &myself);
298 rxrpc_put_call(call);
300 rxrpc_put_connection(conn);
302 _leave(" = %d", ret);
306 set_current_state(TASK_UNINTERRUPTIBLE);
307 rxrpc_call_abort(call, ret);
310 } /* end afs_rxvl_get_entry_by_name() */
312 /*****************************************************************************/
314 * look up a volume location database entry by ID
316 int afs_rxvl_get_entry_by_id(struct afs_server *server,
318 afs_voltype_t voltype,
319 struct afs_cache_vlocation *entry)
321 DECLARE_WAITQUEUE(myself, current);
323 struct rxrpc_connection *conn;
324 struct rxrpc_call *call;
325 struct iovec piov[1];
331 _enter(",%x,%d,", volid, voltype);
333 memset(entry, 0, sizeof(*entry));
335 /* get hold of the vlserver connection */
336 ret = afs_server_get_vlconn(server, &conn);
340 /* create a call through that connection */
341 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
343 printk("kAFS: Unable to create call: %d\n", ret);
346 call->app_opcode = VLGETENTRYBYID;
348 /* we want to get event notifications from the call */
349 add_wait_queue(&call->waitq, &myself);
351 /* marshall the parameters */
352 param[0] = htonl(VLGETENTRYBYID);
353 param[1] = htonl(volid);
354 param[2] = htonl(voltype);
356 piov[0].iov_len = sizeof(param);
357 piov[0].iov_base = param;
359 /* send the parameters to the server */
360 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
365 /* wait for the reply to completely arrive */
366 bp = rxrpc_call_alloc_scratch(call, 384);
368 ret = rxrpc_call_read_data(call, bp, 384,
369 RXRPC_CALL_READ_BLOCK |
370 RXRPC_CALL_READ_ALL);
372 if (ret == -ECONNABORTED) {
373 ret = call->app_errno;
379 /* unmarshall the reply */
380 for (loop = 0; loop < 64; loop++)
381 entry->name[loop] = ntohl(*bp++);
382 bp++; /* final NUL */
385 entry->nservers = ntohl(*bp++);
387 for (loop = 0; loop < 8; loop++)
388 entry->servers[loop].s_addr = *bp++;
390 bp += 8; /* partition IDs */
392 for (loop = 0; loop < 8; loop++) {
394 if (tmp & AFS_VLSF_RWVOL)
395 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
396 if (tmp & AFS_VLSF_ROVOL)
397 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
398 if (tmp & AFS_VLSF_BACKVOL)
399 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
402 entry->vid[0] = ntohl(*bp++);
403 entry->vid[1] = ntohl(*bp++);
404 entry->vid[2] = ntohl(*bp++);
408 tmp = ntohl(*bp++); /* flags */
409 if (tmp & AFS_VLF_RWEXISTS)
410 entry->vidmask |= AFS_VOL_VTM_RW;
411 if (tmp & AFS_VLF_ROEXISTS)
412 entry->vidmask |= AFS_VOL_VTM_RO;
413 if (tmp & AFS_VLF_BACKEXISTS)
414 entry->vidmask |= AFS_VOL_VTM_BAK;
420 #if 0 /* TODO: remove */
422 entry->servers[0].s_addr = htonl(0xac101249);
423 entry->servers[1].s_addr = htonl(0xac101243);
424 entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
426 entry->srvtmask[0] = AFS_VOL_VTM_RO;
427 entry->srvtmask[1] = AFS_VOL_VTM_RO;
428 entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
432 entry->rtime = get_seconds();
436 set_current_state(TASK_RUNNING);
437 remove_wait_queue(&call->waitq, &myself);
438 rxrpc_put_call(call);
440 rxrpc_put_connection(conn);
442 _leave(" = %d", ret);
446 set_current_state(TASK_UNINTERRUPTIBLE);
447 rxrpc_call_abort(call, ret);
450 } /* end afs_rxvl_get_entry_by_id() */
452 /*****************************************************************************/
454 * look up a volume location database entry by ID asynchronously
456 int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op,
458 afs_voltype_t voltype)
460 struct rxrpc_connection *conn;
461 struct rxrpc_call *call;
462 struct iovec piov[1];
467 _enter(",%x,%d,", volid, voltype);
469 /* get hold of the vlserver connection */
470 ret = afs_server_get_vlconn(op->server, &conn);
472 _leave(" = %d", ret);
476 /* create a call through that connection */
477 ret = rxrpc_create_call(conn,
478 afs_rxvl_get_entry_by_id_attn,
479 afs_rxvl_get_entry_by_id_error,
482 rxrpc_put_connection(conn);
485 printk("kAFS: Unable to create call: %d\n", ret);
486 _leave(" = %d", ret);
490 op->call->app_opcode = VLGETENTRYBYID;
491 op->call->app_user = op;
494 rxrpc_get_call(call);
496 /* send event notifications from the call to kafsasyncd */
497 afs_kafsasyncd_begin_op(op);
499 /* marshall the parameters */
500 param[0] = htonl(VLGETENTRYBYID);
501 param[1] = htonl(volid);
502 param[2] = htonl(voltype);
504 piov[0].iov_len = sizeof(param);
505 piov[0].iov_base = param;
507 /* allocate result read buffer in scratch space */
508 call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call, 384);
510 /* send the parameters to the server */
511 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
514 rxrpc_call_abort(call, ret); /* handle from kafsasyncd */
519 /* wait for the reply to completely arrive */
520 ret = rxrpc_call_read_data(call, call->app_scr_ptr, 384, 0);
526 break; /* all handled by kafsasyncd */
529 rxrpc_call_abort(call, ret); /* make kafsasyncd handle it */
535 rxrpc_put_call(call);
536 _leave(" = %d", ret);
539 } /* end afs_rxvl_get_entry_by_id_async() */
541 /*****************************************************************************/
543 * attend to the asynchronous get VLDB entry by ID
545 int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op,
546 struct afs_cache_vlocation *entry)
551 _enter("{op=%p cst=%u}", op, op->call->app_call_state);
553 memset(entry, 0, sizeof(*entry));
555 if (op->call->app_call_state == RXRPC_CSTATE_COMPLETE) {
556 /* operation finished */
557 afs_kafsasyncd_terminate_op(op);
559 bp = op->call->app_scr_ptr;
561 /* unmarshall the reply */
562 for (loop = 0; loop < 64; loop++)
563 entry->name[loop] = ntohl(*bp++);
564 bp++; /* final NUL */
567 entry->nservers = ntohl(*bp++);
569 for (loop = 0; loop < 8; loop++)
570 entry->servers[loop].s_addr = *bp++;
572 bp += 8; /* partition IDs */
574 for (loop = 0; loop < 8; loop++) {
576 if (tmp & AFS_VLSF_RWVOL)
577 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
578 if (tmp & AFS_VLSF_ROVOL)
579 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
580 if (tmp & AFS_VLSF_BACKVOL)
581 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
584 entry->vid[0] = ntohl(*bp++);
585 entry->vid[1] = ntohl(*bp++);
586 entry->vid[2] = ntohl(*bp++);
590 tmp = ntohl(*bp++); /* flags */
591 if (tmp & AFS_VLF_RWEXISTS)
592 entry->vidmask |= AFS_VOL_VTM_RW;
593 if (tmp & AFS_VLF_ROEXISTS)
594 entry->vidmask |= AFS_VOL_VTM_RO;
595 if (tmp & AFS_VLF_BACKEXISTS)
596 entry->vidmask |= AFS_VOL_VTM_BAK;
599 if (!entry->vidmask) {
600 rxrpc_call_abort(op->call, ret);
604 #if 0 /* TODO: remove */
606 entry->servers[0].s_addr = htonl(0xac101249);
607 entry->servers[1].s_addr = htonl(0xac101243);
608 entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
610 entry->srvtmask[0] = AFS_VOL_VTM_RO;
611 entry->srvtmask[1] = AFS_VOL_VTM_RO;
612 entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
616 entry->rtime = get_seconds();
621 if (op->call->app_call_state == RXRPC_CSTATE_ERROR) {
622 /* operation error */
623 ret = op->call->app_errno;
627 _leave(" = -EAGAIN");
631 rxrpc_put_call(op->call);
633 _leave(" = %d", ret);
635 } /* end afs_rxvl_get_entry_by_id_async2() */
637 /*****************************************************************************/
639 * handle attention events on an async get-entry-by-ID op
640 * - called from krxiod
642 static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
644 struct afs_async_op *op = call->app_user;
646 _enter("{op=%p cst=%u}", op, call->app_call_state);
648 switch (call->app_call_state) {
649 case RXRPC_CSTATE_COMPLETE:
650 afs_kafsasyncd_attend_op(op);
652 case RXRPC_CSTATE_CLNT_RCV_REPLY:
653 if (call->app_async_read)
655 case RXRPC_CSTATE_CLNT_GOT_REPLY:
656 if (call->app_read_count == 0)
658 printk("kAFS: Reply bigger than expected"
659 " {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}",
660 call->app_call_state,
661 call->app_async_read,
665 call->app_last_rcv ? " last" : "");
667 rxrpc_call_abort(call, -EBADMSG);
675 } /* end afs_rxvl_get_entry_by_id_attn() */
677 /*****************************************************************************/
679 * handle error events on an async get-entry-by-ID op
680 * - called from krxiod
682 static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
684 struct afs_async_op *op = call->app_user;
686 _enter("{op=%p cst=%u}", op, call->app_call_state);
688 afs_kafsasyncd_attend_op(op);
692 } /* end afs_rxvl_get_entry_by_id_error() */