123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- /* vlclient.c: AFS Volume Location Service client
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
- #include <linux/init.h>
- #include <linux/sched.h>
- #include <rxrpc/rxrpc.h>
- #include <rxrpc/transport.h>
- #include <rxrpc/connection.h>
- #include <rxrpc/call.h>
- #include "server.h"
- #include "volume.h"
- #include "vlclient.h"
- #include "kafsasyncd.h"
- #include "kafstimod.h"
- #include "errors.h"
- #include "internal.h"
- #define VLGETENTRYBYID 503 /* AFS Get Cache Entry By ID operation ID */
- #define VLGETENTRYBYNAME 504 /* AFS Get Cache Entry By Name operation ID */
- #define VLPROBE 514 /* AFS Probe Volume Location Service operation ID */
- static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call);
- static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call);
- /*****************************************************************************/
- /*
- * map afs VL abort codes to/from Linux error codes
- * - called with call->lock held
- */
- static void afs_rxvl_aemap(struct rxrpc_call *call)
- {
- int err;
- _enter("{%u,%u,%d}",
- call->app_err_state, call->app_abort_code, call->app_errno);
- switch (call->app_err_state) {
- case RXRPC_ESTATE_LOCAL_ABORT:
- call->app_abort_code = -call->app_errno;
- return;
- case RXRPC_ESTATE_PEER_ABORT:
- switch (call->app_abort_code) {
- case AFSVL_IDEXIST: err = -EEXIST; break;
- case AFSVL_IO: err = -EREMOTEIO; break;
- case AFSVL_NAMEEXIST: err = -EEXIST; break;
- case AFSVL_CREATEFAIL: err = -EREMOTEIO; break;
- case AFSVL_NOENT: err = -ENOMEDIUM; break;
- case AFSVL_EMPTY: err = -ENOMEDIUM; break;
- case AFSVL_ENTDELETED: err = -ENOMEDIUM; break;
- case AFSVL_BADNAME: err = -EINVAL; break;
- case AFSVL_BADINDEX: err = -EINVAL; break;
- case AFSVL_BADVOLTYPE: err = -EINVAL; break;
- case AFSVL_BADSERVER: err = -EINVAL; break;
- case AFSVL_BADPARTITION: err = -EINVAL; break;
- case AFSVL_REPSFULL: err = -EFBIG; break;
- case AFSVL_NOREPSERVER: err = -ENOENT; break;
- case AFSVL_DUPREPSERVER: err = -EEXIST; break;
- case AFSVL_RWNOTFOUND: err = -ENOENT; break;
- case AFSVL_BADREFCOUNT: err = -EINVAL; break;
- case AFSVL_SIZEEXCEEDED: err = -EINVAL; break;
- case AFSVL_BADENTRY: err = -EINVAL; break;
- case AFSVL_BADVOLIDBUMP: err = -EINVAL; break;
- case AFSVL_IDALREADYHASHED: err = -EINVAL; break;
- case AFSVL_ENTRYLOCKED: err = -EBUSY; break;
- case AFSVL_BADVOLOPER: err = -EBADRQC; break;
- case AFSVL_BADRELLOCKTYPE: err = -EINVAL; break;
- case AFSVL_RERELEASE: err = -EREMOTEIO; break;
- case AFSVL_BADSERVERFLAG: err = -EINVAL; break;
- case AFSVL_PERM: err = -EACCES; break;
- case AFSVL_NOMEM: err = -EREMOTEIO; break;
- default:
- err = afs_abort_to_error(call->app_abort_code);
- break;
- }
- call->app_errno = err;
- return;
- default:
- return;
- }
- } /* end afs_rxvl_aemap() */
- #if 0
- /*****************************************************************************/
- /*
- * probe a volume location server to see if it is still alive -- unused
- */
- static int afs_rxvl_probe(struct afs_server *server, int alloc_flags)
- {
- struct rxrpc_connection *conn;
- struct rxrpc_call *call;
- struct kvec piov[1];
- size_t sent;
- int ret;
- __be32 param[1];
- DECLARE_WAITQUEUE(myself, current);
- /* get hold of the vlserver connection */
- ret = afs_server_get_vlconn(server, &conn);
- if (ret < 0)
- goto out;
- /* create a call through that connection */
- ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
- if (ret < 0) {
- printk("kAFS: Unable to create call: %d\n", ret);
- goto out_put_conn;
- }
- call->app_opcode = VLPROBE;
- /* we want to get event notifications from the call */
- add_wait_queue(&call->waitq, &myself);
- /* marshall the parameters */
- param[0] = htonl(VLPROBE);
- piov[0].iov_len = sizeof(param);
- piov[0].iov_base = param;
- /* send the parameters to the server */
- ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET,
- alloc_flags, 0, &sent);
- if (ret < 0)
- goto abort;
- /* wait for the reply to completely arrive */
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
- signal_pending(current))
- break;
- schedule();
- }
- set_current_state(TASK_RUNNING);
- ret = -EINTR;
- if (signal_pending(current))
- goto abort;
- switch (call->app_call_state) {
- case RXRPC_CSTATE_ERROR:
- ret = call->app_errno;
- goto out_unwait;
- case RXRPC_CSTATE_CLNT_GOT_REPLY:
- ret = 0;
- goto out_unwait;
- default:
- BUG();
- }
- abort:
- set_current_state(TASK_UNINTERRUPTIBLE);
- rxrpc_call_abort(call, ret);
- schedule();
- out_unwait:
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&call->waitq, &myself);
- rxrpc_put_call(call);
- out_put_conn:
- rxrpc_put_connection(conn);
- out:
- return ret;
- } /* end afs_rxvl_probe() */
- #endif
- /*****************************************************************************/
- /*
- * look up a volume location database entry by name
- */
- int afs_rxvl_get_entry_by_name(struct afs_server *server,
- const char *volname,
- unsigned volnamesz,
- struct afs_cache_vlocation *entry)
- {
- DECLARE_WAITQUEUE(myself, current);
- struct rxrpc_connection *conn;
- struct rxrpc_call *call;
- struct kvec piov[3];
- unsigned tmp;
- size_t sent;
- int ret, loop;
- __be32 *bp, param[2], zero;
- _enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz);
- memset(entry, 0, sizeof(*entry));
- /* get hold of the vlserver connection */
- ret = afs_server_get_vlconn(server, &conn);
- if (ret < 0)
- goto out;
- /* create a call through that connection */
- ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
- if (ret < 0) {
- printk("kAFS: Unable to create call: %d\n", ret);
- goto out_put_conn;
- }
- call->app_opcode = VLGETENTRYBYNAME;
- /* we want to get event notifications from the call */
- add_wait_queue(&call->waitq, &myself);
- /* marshall the parameters */
- piov[1].iov_len = volnamesz;
- piov[1].iov_base = (char *) volname;
- zero = 0;
- piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
- piov[2].iov_base = &zero;
- param[0] = htonl(VLGETENTRYBYNAME);
- param[1] = htonl(piov[1].iov_len);
- piov[0].iov_len = sizeof(param);
- piov[0].iov_base = param;
- /* send the parameters to the server */
- ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
- 0, &sent);
- if (ret < 0)
- goto abort;
- /* wait for the reply to completely arrive */
- bp = rxrpc_call_alloc_scratch(call, 384);
- ret = rxrpc_call_read_data(call, bp, 384,
- RXRPC_CALL_READ_BLOCK |
- RXRPC_CALL_READ_ALL);
- if (ret < 0) {
- if (ret == -ECONNABORTED) {
- ret = call->app_errno;
- goto out_unwait;
- }
- goto abort;
- }
- /* unmarshall the reply */
- for (loop = 0; loop < 64; loop++)
- entry->name[loop] = ntohl(*bp++);
- bp++; /* final NUL */
- bp++; /* type */
- entry->nservers = ntohl(*bp++);
- for (loop = 0; loop < 8; loop++)
- entry->servers[loop].s_addr = *bp++;
- bp += 8; /* partition IDs */
- for (loop = 0; loop < 8; loop++) {
- tmp = ntohl(*bp++);
- if (tmp & AFS_VLSF_RWVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
- if (tmp & AFS_VLSF_ROVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
- if (tmp & AFS_VLSF_BACKVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
- }
- entry->vid[0] = ntohl(*bp++);
- entry->vid[1] = ntohl(*bp++);
- entry->vid[2] = ntohl(*bp++);
- bp++; /* clone ID */
- tmp = ntohl(*bp++); /* flags */
- if (tmp & AFS_VLF_RWEXISTS)
- entry->vidmask |= AFS_VOL_VTM_RW;
- if (tmp & AFS_VLF_ROEXISTS)
- entry->vidmask |= AFS_VOL_VTM_RO;
- if (tmp & AFS_VLF_BACKEXISTS)
- entry->vidmask |= AFS_VOL_VTM_BAK;
- ret = -ENOMEDIUM;
- if (!entry->vidmask)
- goto abort;
- /* success */
- entry->rtime = get_seconds();
- ret = 0;
- out_unwait:
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&call->waitq, &myself);
- rxrpc_put_call(call);
- out_put_conn:
- rxrpc_put_connection(conn);
- out:
- _leave(" = %d", ret);
- return ret;
- abort:
- set_current_state(TASK_UNINTERRUPTIBLE);
- rxrpc_call_abort(call, ret);
- schedule();
- goto out_unwait;
- } /* end afs_rxvl_get_entry_by_name() */
- /*****************************************************************************/
- /*
- * look up a volume location database entry by ID
- */
- int afs_rxvl_get_entry_by_id(struct afs_server *server,
- afs_volid_t volid,
- afs_voltype_t voltype,
- struct afs_cache_vlocation *entry)
- {
- DECLARE_WAITQUEUE(myself, current);
- struct rxrpc_connection *conn;
- struct rxrpc_call *call;
- struct kvec piov[1];
- unsigned tmp;
- size_t sent;
- int ret, loop;
- __be32 *bp, param[3];
- _enter(",%x,%d,", volid, voltype);
- memset(entry, 0, sizeof(*entry));
- /* get hold of the vlserver connection */
- ret = afs_server_get_vlconn(server, &conn);
- if (ret < 0)
- goto out;
- /* create a call through that connection */
- ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
- if (ret < 0) {
- printk("kAFS: Unable to create call: %d\n", ret);
- goto out_put_conn;
- }
- call->app_opcode = VLGETENTRYBYID;
- /* we want to get event notifications from the call */
- add_wait_queue(&call->waitq, &myself);
- /* marshall the parameters */
- param[0] = htonl(VLGETENTRYBYID);
- param[1] = htonl(volid);
- param[2] = htonl(voltype);
- piov[0].iov_len = sizeof(param);
- piov[0].iov_base = param;
- /* send the parameters to the server */
- ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
- 0, &sent);
- if (ret < 0)
- goto abort;
- /* wait for the reply to completely arrive */
- bp = rxrpc_call_alloc_scratch(call, 384);
- ret = rxrpc_call_read_data(call, bp, 384,
- RXRPC_CALL_READ_BLOCK |
- RXRPC_CALL_READ_ALL);
- if (ret < 0) {
- if (ret == -ECONNABORTED) {
- ret = call->app_errno;
- goto out_unwait;
- }
- goto abort;
- }
- /* unmarshall the reply */
- for (loop = 0; loop < 64; loop++)
- entry->name[loop] = ntohl(*bp++);
- bp++; /* final NUL */
- bp++; /* type */
- entry->nservers = ntohl(*bp++);
- for (loop = 0; loop < 8; loop++)
- entry->servers[loop].s_addr = *bp++;
- bp += 8; /* partition IDs */
- for (loop = 0; loop < 8; loop++) {
- tmp = ntohl(*bp++);
- if (tmp & AFS_VLSF_RWVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
- if (tmp & AFS_VLSF_ROVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
- if (tmp & AFS_VLSF_BACKVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
- }
- entry->vid[0] = ntohl(*bp++);
- entry->vid[1] = ntohl(*bp++);
- entry->vid[2] = ntohl(*bp++);
- bp++; /* clone ID */
- tmp = ntohl(*bp++); /* flags */
- if (tmp & AFS_VLF_RWEXISTS)
- entry->vidmask |= AFS_VOL_VTM_RW;
- if (tmp & AFS_VLF_ROEXISTS)
- entry->vidmask |= AFS_VOL_VTM_RO;
- if (tmp & AFS_VLF_BACKEXISTS)
- entry->vidmask |= AFS_VOL_VTM_BAK;
- ret = -ENOMEDIUM;
- if (!entry->vidmask)
- goto abort;
- #if 0 /* TODO: remove */
- entry->nservers = 3;
- entry->servers[0].s_addr = htonl(0xac101249);
- entry->servers[1].s_addr = htonl(0xac101243);
- entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
- entry->srvtmask[0] = AFS_VOL_VTM_RO;
- entry->srvtmask[1] = AFS_VOL_VTM_RO;
- entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
- #endif
- /* success */
- entry->rtime = get_seconds();
- ret = 0;
- out_unwait:
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&call->waitq, &myself);
- rxrpc_put_call(call);
- out_put_conn:
- rxrpc_put_connection(conn);
- out:
- _leave(" = %d", ret);
- return ret;
- abort:
- set_current_state(TASK_UNINTERRUPTIBLE);
- rxrpc_call_abort(call, ret);
- schedule();
- goto out_unwait;
- } /* end afs_rxvl_get_entry_by_id() */
- /*****************************************************************************/
- /*
- * look up a volume location database entry by ID asynchronously
- */
- int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op,
- afs_volid_t volid,
- afs_voltype_t voltype)
- {
- struct rxrpc_connection *conn;
- struct rxrpc_call *call;
- struct kvec piov[1];
- size_t sent;
- int ret;
- __be32 param[3];
- _enter(",%x,%d,", volid, voltype);
- /* get hold of the vlserver connection */
- ret = afs_server_get_vlconn(op->server, &conn);
- if (ret < 0) {
- _leave(" = %d", ret);
- return ret;
- }
- /* create a call through that connection */
- ret = rxrpc_create_call(conn,
- afs_rxvl_get_entry_by_id_attn,
- afs_rxvl_get_entry_by_id_error,
- afs_rxvl_aemap,
- &op->call);
- rxrpc_put_connection(conn);
- if (ret < 0) {
- printk("kAFS: Unable to create call: %d\n", ret);
- _leave(" = %d", ret);
- return ret;
- }
- op->call->app_opcode = VLGETENTRYBYID;
- op->call->app_user = op;
- call = op->call;
- rxrpc_get_call(call);
- /* send event notifications from the call to kafsasyncd */
- afs_kafsasyncd_begin_op(op);
- /* marshall the parameters */
- param[0] = htonl(VLGETENTRYBYID);
- param[1] = htonl(volid);
- param[2] = htonl(voltype);
- piov[0].iov_len = sizeof(param);
- piov[0].iov_base = param;
- /* allocate result read buffer in scratch space */
- call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call, 384);
- /* send the parameters to the server */
- ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
- 0, &sent);
- if (ret < 0) {
- rxrpc_call_abort(call, ret); /* handle from kafsasyncd */
- ret = 0;
- goto out;
- }
- /* wait for the reply to completely arrive */
- ret = rxrpc_call_read_data(call, call->app_scr_ptr, 384, 0);
- switch (ret) {
- case 0:
- case -EAGAIN:
- case -ECONNABORTED:
- ret = 0;
- break; /* all handled by kafsasyncd */
- default:
- rxrpc_call_abort(call, ret); /* make kafsasyncd handle it */
- ret = 0;
- break;
- }
- out:
- rxrpc_put_call(call);
- _leave(" = %d", ret);
- return ret;
- } /* end afs_rxvl_get_entry_by_id_async() */
- /*****************************************************************************/
- /*
- * attend to the asynchronous get VLDB entry by ID
- */
- int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op,
- struct afs_cache_vlocation *entry)
- {
- __be32 *bp;
- __u32 tmp;
- int loop, ret;
- _enter("{op=%p cst=%u}", op, op->call->app_call_state);
- memset(entry, 0, sizeof(*entry));
- if (op->call->app_call_state == RXRPC_CSTATE_COMPLETE) {
- /* operation finished */
- afs_kafsasyncd_terminate_op(op);
- bp = op->call->app_scr_ptr;
- /* unmarshall the reply */
- for (loop = 0; loop < 64; loop++)
- entry->name[loop] = ntohl(*bp++);
- bp++; /* final NUL */
- bp++; /* type */
- entry->nservers = ntohl(*bp++);
- for (loop = 0; loop < 8; loop++)
- entry->servers[loop].s_addr = *bp++;
- bp += 8; /* partition IDs */
- for (loop = 0; loop < 8; loop++) {
- tmp = ntohl(*bp++);
- if (tmp & AFS_VLSF_RWVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
- if (tmp & AFS_VLSF_ROVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
- if (tmp & AFS_VLSF_BACKVOL)
- entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
- }
- entry->vid[0] = ntohl(*bp++);
- entry->vid[1] = ntohl(*bp++);
- entry->vid[2] = ntohl(*bp++);
- bp++; /* clone ID */
- tmp = ntohl(*bp++); /* flags */
- if (tmp & AFS_VLF_RWEXISTS)
- entry->vidmask |= AFS_VOL_VTM_RW;
- if (tmp & AFS_VLF_ROEXISTS)
- entry->vidmask |= AFS_VOL_VTM_RO;
- if (tmp & AFS_VLF_BACKEXISTS)
- entry->vidmask |= AFS_VOL_VTM_BAK;
- ret = -ENOMEDIUM;
- if (!entry->vidmask) {
- rxrpc_call_abort(op->call, ret);
- goto done;
- }
- #if 0 /* TODO: remove */
- entry->nservers = 3;
- entry->servers[0].s_addr = htonl(0xac101249);
- entry->servers[1].s_addr = htonl(0xac101243);
- entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
- entry->srvtmask[0] = AFS_VOL_VTM_RO;
- entry->srvtmask[1] = AFS_VOL_VTM_RO;
- entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
- #endif
- /* success */
- entry->rtime = get_seconds();
- ret = 0;
- goto done;
- }
- if (op->call->app_call_state == RXRPC_CSTATE_ERROR) {
- /* operation error */
- ret = op->call->app_errno;
- goto done;
- }
- _leave(" = -EAGAIN");
- return -EAGAIN;
- done:
- rxrpc_put_call(op->call);
- op->call = NULL;
- _leave(" = %d", ret);
- return ret;
- } /* end afs_rxvl_get_entry_by_id_async2() */
- /*****************************************************************************/
- /*
- * handle attention events on an async get-entry-by-ID op
- * - called from krxiod
- */
- static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
- {
- struct afs_async_op *op = call->app_user;
- _enter("{op=%p cst=%u}", op, call->app_call_state);
- switch (call->app_call_state) {
- case RXRPC_CSTATE_COMPLETE:
- afs_kafsasyncd_attend_op(op);
- break;
- case RXRPC_CSTATE_CLNT_RCV_REPLY:
- if (call->app_async_read)
- break;
- case RXRPC_CSTATE_CLNT_GOT_REPLY:
- if (call->app_read_count == 0)
- break;
- printk("kAFS: Reply bigger than expected"
- " {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}",
- call->app_call_state,
- call->app_async_read,
- call->app_mark,
- call->app_ready_qty,
- call->pkt_rcv_count,
- call->app_last_rcv ? " last" : "");
- rxrpc_call_abort(call, -EBADMSG);
- break;
- default:
- BUG();
- }
- _leave("");
- } /* end afs_rxvl_get_entry_by_id_attn() */
- /*****************************************************************************/
- /*
- * handle error events on an async get-entry-by-ID op
- * - called from krxiod
- */
- static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
- {
- struct afs_async_op *op = call->app_user;
- _enter("{op=%p cst=%u}", op, call->app_call_state);
- afs_kafsasyncd_attend_op(op);
- _leave("");
- } /* end afs_rxvl_get_entry_by_id_error() */
|