Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / fs / afs / vlclient.c
diff --git a/kernel/fs/afs/vlclient.c b/kernel/fs/afs/vlclient.c
new file mode 100644 (file)
index 0000000..340afd0
--- /dev/null
@@ -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);
+}