summaryrefslogtreecommitdiff
path: root/fs/afs/vlclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/vlclient.c')
-rw-r--r--fs/afs/vlclient.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c
new file mode 100644
index 000000000..340afd0cd
--- /dev/null
+++ b/fs/afs/vlclient.c
@@ -0,0 +1,219 @@
+/* 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/gfp.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include "internal.h"
+
+/*
+ * map volume locator abort codes to error codes
+ */
+static int afs_vl_abort_to_error(u32 abort_code)
+{
+ _enter("%u", abort_code);
+
+ switch (abort_code) {
+ case AFSVL_IDEXIST: return -EEXIST;
+ case AFSVL_IO: return -EREMOTEIO;
+ case AFSVL_NAMEEXIST: return -EEXIST;
+ case AFSVL_CREATEFAIL: return -EREMOTEIO;
+ case AFSVL_NOENT: return -ENOMEDIUM;
+ case AFSVL_EMPTY: return -ENOMEDIUM;
+ case AFSVL_ENTDELETED: return -ENOMEDIUM;
+ case AFSVL_BADNAME: return -EINVAL;
+ case AFSVL_BADINDEX: return -EINVAL;
+ case AFSVL_BADVOLTYPE: return -EINVAL;
+ case AFSVL_BADSERVER: return -EINVAL;
+ case AFSVL_BADPARTITION: return -EINVAL;
+ case AFSVL_REPSFULL: return -EFBIG;
+ case AFSVL_NOREPSERVER: return -ENOENT;
+ case AFSVL_DUPREPSERVER: return -EEXIST;
+ case AFSVL_RWNOTFOUND: return -ENOENT;
+ case AFSVL_BADREFCOUNT: return -EINVAL;
+ case AFSVL_SIZEEXCEEDED: return -EINVAL;
+ case AFSVL_BADENTRY: return -EINVAL;
+ case AFSVL_BADVOLIDBUMP: return -EINVAL;
+ case AFSVL_IDALREADYHASHED: return -EINVAL;
+ case AFSVL_ENTRYLOCKED: return -EBUSY;
+ case AFSVL_BADVOLOPER: return -EBADRQC;
+ case AFSVL_BADRELLOCKTYPE: return -EINVAL;
+ case AFSVL_RERELEASE: return -EREMOTEIO;
+ case AFSVL_BADSERVERFLAG: return -EINVAL;
+ case AFSVL_PERM: return -EACCES;
+ case AFSVL_NOMEM: return -EREMOTEIO;
+ default:
+ return afs_abort_to_error(abort_code);
+ }
+}
+
+/*
+ * deliver reply data to a VL.GetEntryByXXX call
+ */
+static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call,
+ struct sk_buff *skb, bool last)
+{
+ struct afs_cache_vlocation *entry;
+ __be32 *bp;
+ u32 tmp;
+ int loop;
+
+ _enter(",,%u", last);
+
+ afs_transfer_reply(call, skb);
+ if (!last)
+ return 0;
+
+ if (call->reply_size != call->reply_max)
+ return -EBADMSG;
+
+ /* unmarshall the reply once we've received all of it */
+ entry = call->reply;
+ bp = call->buffer;
+
+ for (loop = 0; loop < 64; loop++)
+ entry->name[loop] = ntohl(*bp++);
+ entry->name[loop] = 0;
+ 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++);
+ entry->srvtmask[loop] = 0;
+ 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 */
+ entry->vidmask = 0;
+ 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;
+ if (!entry->vidmask)
+ return -EBADMSG;
+
+ _leave(" = 0 [done]");
+ return 0;
+}
+
+/*
+ * VL.GetEntryByName operation type
+ */
+static const struct afs_call_type afs_RXVLGetEntryByName = {
+ .name = "VL.GetEntryByName",
+ .deliver = afs_deliver_vl_get_entry_by_xxx,
+ .abort_to_error = afs_vl_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * VL.GetEntryById operation type
+ */
+static const struct afs_call_type afs_RXVLGetEntryById = {
+ .name = "VL.GetEntryById",
+ .deliver = afs_deliver_vl_get_entry_by_xxx,
+ .abort_to_error = afs_vl_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * dispatch a get volume entry by name operation
+ */
+int afs_vl_get_entry_by_name(struct in_addr *addr,
+ struct key *key,
+ const char *volname,
+ struct afs_cache_vlocation *entry,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ size_t volnamesz, reqsz, padsz;
+ __be32 *bp;
+
+ _enter("");
+
+ volnamesz = strlen(volname);
+ padsz = (4 - (volnamesz & 3)) & 3;
+ reqsz = 8 + volnamesz + padsz;
+
+ call = afs_alloc_flat_call(&afs_RXVLGetEntryByName, reqsz, 384);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = entry;
+ call->service_id = VL_SERVICE;
+ call->port = htons(AFS_VL_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(VLGETENTRYBYNAME);
+ *bp++ = htonl(volnamesz);
+ memcpy(bp, volname, volnamesz);
+ if (padsz > 0)
+ memset((void *) bp + volnamesz, 0, padsz);
+
+ /* initiate the call */
+ return afs_make_call(addr, call, GFP_KERNEL, wait_mode);
+}
+
+/*
+ * dispatch a get volume entry by ID operation
+ */
+int afs_vl_get_entry_by_id(struct in_addr *addr,
+ struct key *key,
+ afs_volid_t volid,
+ afs_voltype_t voltype,
+ struct afs_cache_vlocation *entry,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXVLGetEntryById, 12, 384);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = entry;
+ call->service_id = VL_SERVICE;
+ call->port = htons(AFS_VL_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(VLGETENTRYBYID);
+ *bp++ = htonl(volid);
+ *bp = htonl(voltype);
+
+ /* initiate the call */
+ return afs_make_call(addr, call, GFP_KERNEL, wait_mode);
+}