]> www.infradead.org Git - users/dhowells/kafs-utils.git/commitdiff
midlayer: Add Volume Server support
authorDavid Howells <dhowells@redhat.com>
Fri, 10 Jul 2020 11:07:42 +0000 (12:07 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 5 May 2023 09:05:31 +0000 (10:05 +0100)
Signed-off-by: David Howells <dhowells@redhat.com>
kafs/Makefile
kafs/display_vol.c
kafs/kafs.h
kafs/vol_probe.c [new file with mode: 0644]
kafs/vol_query.c [new file with mode: 0644]
kafs/volservice.h [new file with mode: 0644]

index b8a1944ed8bf16290d689e97269cae672449ddad..5d839b363858fe9779e186d51f23406b3d8237c9 100644 (file)
@@ -12,7 +12,9 @@ CORE_SRCS := \
        display_vol.c \
        vl_fileservers.c \
        vl_probe.c \
-       vl_volumes.c
+       vl_volumes.c \
+       vol_probe.c \
+       vol_query.c
 
 BOS_SRCS := \
        bos.c \
index e92ea9b040a0767f905b9c0e91d04988af8c36e3..73e3de2893faaeb2debad8b1303c9f096cd8f9ab 100644 (file)
@@ -16,6 +16,7 @@
 #include <assert.h>
 #include "kafs.h"
 #include "vlservice.h"
+#include "volservice.h"
 #include "afs_xg.h"
 #include "display.h"
 
index 11f8b47ebb64432a7cb86de1e9ccb4f51bcc5159..52aaf8635b8e65f9710cccee669278fb519b130d 100644 (file)
@@ -44,6 +44,12 @@ struct kafs_fileserver {
        struct sockaddr_rxrpc           *fs_addrs;      /* Fileserver addresses */
        struct sockaddr_rxrpc           *vs_addrs;      /* Volume server addresses */
        char                            *name;          /* Canonical server name */
+
+       enum kafs_service_t             vs_service;     /* Service provided by the volserver */
+       unsigned int                    vs_caps[1];     /* Volserver capabilities */
+       struct rxrpc_call_params        vs_params;      /* Volserver parameters */
+       unsigned int                    vs_pref;        /* Volserver address to use */
+       bool                            vs_probed:1;    /* T if volserver has been probed */
 };
 
 struct kafs_context {
diff --git a/kafs/vol_probe.c b/kafs/vol_probe.c
new file mode 100644 (file)
index 0000000..f3b7cc3
--- /dev/null
@@ -0,0 +1,165 @@
+/* Volume server probe.
+ *
+ * Copyright (C) 2020 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 Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include "volservice.h"
+#include "afs_xg.h"
+#include "display.h"
+
+/**
+ * kafs_open_volserver - Open a Volume Server for access.
+ * @ctx: The cell and authentication context
+ * @server: The volume server details
+ *
+ * Open a Volume Server.  The server is probed to determine what it's capable
+ * of and what type it is.
+ */
+bool kafs_open_volserver(struct kafs_context *ctx, struct kafs_fileserver *server)
+{
+       if (!kafs_open_endpoint(ctx))
+               return false;
+       if (!server->vs_probed)
+               return kafs_probe_volserver(ctx, server);
+       return true;
+}
+
+/*
+ * kafs_open_volserver - Close a Volume Server.
+ * @ctx: The cell and authentication context
+ * @server: The volume server details
+ *
+ * Close a volume server, potentially releasing any resources held.
+ */
+void kafs_close_volserver(struct kafs_context *ctx,
+                         struct kafs_fileserver *server)
+{
+       put_kafs_fileserver(server);
+}
+
+/**
+ * kafs_probe_volserver - Probe a Volume Server
+ * @ctx: The cell and authentication context
+ * @server: The volume server details
+ *
+ * Probe a volume server to find what it supports.
+ */
+bool kafs_probe_volserver(struct kafs_context *ctx,
+                         struct kafs_fileserver *server)
+{
+       struct rxrpc_call_params *params = &server->vs_params;
+       struct sockaddr_rxrpc *srx;
+       unsigned int *caps, nr_caps;
+       unsigned int addr = 0, i;
+       char abuf[1024];
+
+       _enter("");
+
+try_next_address:
+       if (addr >= server->vs_nr_addrs) {
+               if (!ctx->result.source)
+                       return kafs_error(ctx, "Volume server not responding");
+               _leave(" = f [no more addrs]");
+               return false;
+       }
+
+       srx = &server->vs_addrs[addr];
+       memset(params, 0, sizeof(*params));
+       params->endpoint                = ctx->endpoint;
+       params->security                = ctx->security;
+       params->peer                    = *srx;
+       params->peer_len                = sizeof(*srx);
+       params->upgrade_service         = true;
+
+       kafs_sprint_address(ctx, &params->peer, abuf, sizeof(abuf));
+       _debug("addr %u %s", addr, abuf);
+
+       if (!VOLSER_GetCapabilities(params, &caps, &nr_caps, &ctx->result)) {
+               _debug("failed %u %d", ctx->result.source, ctx->result.abort_code);
+               switch (ctx->result.source) {
+               case rxrpc_error_remote_abort:
+                       switch (ctx->result.abort_code) {
+                       case RX_INVALID_OPERATION:
+                       case RXGEN_OPCODE:
+                               server->vs_service = kafs_service_afs;
+                               params->upgrade_service = false;
+                               memset(&server->vs_caps, 0, sizeof(server->vs_caps));
+                               ctx->result.source = rxrpc_error_none;
+                               goto out;
+                       default:
+                               return false;
+                       }
+
+               case rxrpc_error_from_network:
+               case rxrpc_error_from_system:
+                       switch (ctx->result.error) {
+                       case -ENONET:
+                       case -ECONNRESET: /* Responded, but call expired. */
+                       case -ERFKILL:
+                       case -EADDRNOTAVAIL:
+                       case -ENETUNREACH:
+                       case -EHOSTUNREACH:
+                       case -EHOSTDOWN:
+                       case -ECONNREFUSED:
+                       case -ETIMEDOUT:
+                       case -ETIME:
+                               addr++;
+                               goto try_next_address;
+                       default:
+                               return false;
+                       }
+
+               default:
+                       return false;
+               }
+       }
+
+       params->upgrade_service = false;
+       server->vs_pref = addr;
+       switch (ctx->result.service_id) {
+       case VOLSERVICE_ID:
+               server->vs_service = kafs_service_afs;
+               break;
+       case YFS_VOL_SERVICE:
+               server->vs_service = kafs_service_yfs;
+               params->peer.srx_service = ctx->result.service_id;
+               for (i = 0; i < server->vs_nr_addrs; i++)
+                       server->vs_addrs[i].srx_service = ctx->result.service_id;
+               break;
+       default:
+               free(caps);
+               return kafs_error(ctx, "Unsupported VL service %u", ctx->result.service_id);
+       }
+
+       memset(&server->vs_caps, 0, sizeof(server->vs_caps));
+       nr_caps *= sizeof(unsigned int);
+       if (nr_caps > sizeof(server->vs_caps))
+               nr_caps = sizeof(server->vs_caps);
+       memcpy(&server->vs_caps, caps, nr_caps);
+       free(caps);
+
+out:
+       if (kafs_debug_caps) {
+               printf("volser-caps:");
+               for (i = 0; i < sizeof(server->vs_caps) / sizeof(unsigned int); i++)
+                       printf(" %08x", server->vs_caps[i]);
+               if (server->vs_service == kafs_service_yfs)
+                       printf(" yfs\n");
+               else
+                       printf(" afs\n");
+       }
+
+       _leave(" = t");
+       return true;
+}
diff --git a/kafs/vol_query.c b/kafs/vol_query.c
new file mode 100644 (file)
index 0000000..671d8a4
--- /dev/null
@@ -0,0 +1,296 @@
+/* Volume information query
+ *
+ * Copyright (C) 2020 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 Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "volservice.h"
+#include "afs_xg.h"
+
+/**
+ * kafs_vol_monitor_transaction - Get the state of ongoing transactions on a volume server
+ * @ctx: The cell and authentication context
+ * @server: The volume server to contact
+ * @info_list: The list to which the records will be added
+ *
+ * Retrieve the list of ongoing transactions from a volume server and details
+ * of those transactions.  The transaction records are added to the list.
+ */
+bool kafs_vol_monitor_transaction(struct kafs_context *ctx,
+                                 struct kafs_fileserver *server,
+                                 struct kafs_vol_transaction_info_list *info_list)
+{
+       struct kafs_vol_transaction_info *list = NULL;
+       struct transDebugInfo **results;
+       unsigned int count, i;
+
+       if (!VOLSER_Monitor(&server->vs_params, &results, &count, &ctx->result))
+               return false;
+
+       if (!count)
+               goto done;
+
+       list = calloc(count, sizeof(list[0]));
+       if (!list)
+               return kafs_nomem(ctx);
+
+       for (i = 0; i < count; i++) {
+               struct kafs_vol_transaction_info *info = &list[i];
+               struct transDebugInfo *r = results[i];
+
+               info->tid               = r->tid;
+               info->time              = r->time;
+               info->creation_time     = r->creationTime;
+               info->return_code       = r->returnCode;
+               info->volid             = r->volid;
+               info->partition         = r->partition;
+               info->iflags            = r->iflags;
+               info->vflags            = r->vflags;
+               info->tflags            = r->tflags;
+               info->call_valid        = r->callValid;
+               info->read_next         = r->readNext;
+               info->transmit_next     = r->transmitNext;
+               info->last_send_time    = r->lastSendTime;
+               info->last_receive_time = r->lastReceiveTime;
+
+               strncpy(info->last_proc_name, r->lastProcName, sizeof(info->last_proc_name));
+       }
+
+done:
+       rxgen_bulk_free_transDebugInfo(results, count);
+       info_list->count = count;
+       info_list->info = list;
+       return true;
+}
+
+/*
+ * Convert a volintInfo struct to a kafs_volume_info record.
+ */
+static void kafs_volintinfo_to_volume_info(struct volintInfo *info,
+                                          struct kafs_volume_info *vi)
+{
+       strcpy(vi->name, info->name);
+       vi->volid               = info->volid;
+       vi->type                = info->type;
+       vi->backup_id           = info->backupID;
+       vi->parent_id           = info->parentID;
+       vi->clone_id            = info->cloneID;
+       vi->status              = info->status;
+       vi->copy_date           = info->copyDate;
+       vi->in_use              = info->inUse;
+       vi->needs_salvage       = info->needsSalvaged;
+       vi->destroy_me          = info->destroyMe;
+       vi->creation_date       = info->creationDate;
+       vi->access_date         = info->accessDate;
+       vi->update_date         = info->updateDate;
+       vi->backup_date         = info->backupDate;
+       vi->day_use             = info->dayUse;
+       vi->file_count          = info->filecount;
+       vi->max_quota           = info->maxquota;
+       vi->size                = info->size;
+       vi->flags               = info->flags;
+       vi->min_quota           = info->spare0;
+       vi->week_use            = info->spare1;
+       vi->spare2              = info->spare2;
+       vi->spare3              = info->spare3;
+
+       vi->has_flags           = true;
+       vi->has_need_salvage    = true;
+       vi->has_min_quota       = true;
+       vi->has_week_use        = true;
+       vi->has_spare2          = true;
+       vi->has_spare3          = true;
+}
+
+/*
+ * Convert an xvolintInfo struct to a kafs_volume_info record.
+ */
+static void kafs_xvolintinfo_to_volume_info(struct xvolintInfo *xinfo,
+                                           struct kafs_volume_info *vi)
+{
+       int i;
+
+       strcpy(vi->name, xinfo->name);
+       vi->volid               = xinfo->volid;
+       vi->type                = xinfo->type;
+       vi->backup_id           = xinfo->backupID;
+       vi->parent_id           = xinfo->parentID;
+       vi->clone_id            = xinfo->cloneID;
+       vi->status              = xinfo->status;
+       vi->copy_date           = xinfo->copyDate;
+       vi->in_use              = xinfo->inUse;
+       vi->creation_date       = xinfo->creationDate;
+       vi->access_date         = xinfo->accessDate;
+       vi->update_date         = xinfo->updateDate;
+       vi->backup_date         = xinfo->backupDate;
+       vi->day_use             = xinfo->dayUse;
+       vi->file_count          = xinfo->filecount;
+       vi->max_quota           = xinfo->maxquota;
+       vi->size                = xinfo->size;
+
+       for (i = 0; i < 4; i++) {
+               vi->stat_reads[i]  = xinfo->stat_reads[i];
+               vi->stat_writes[i] = xinfo->stat_writes[i];
+       }
+
+       for (i = 0; i < 6; i++) {
+               vi->stat_fileSameAuthor[i] = vi->stat_fileSameAuthor[i];
+               vi->stat_fileDiffAuthor[i] = vi->stat_fileDiffAuthor[i];
+               vi->stat_dirSameAuthor[i]  = vi->stat_dirSameAuthor[i];
+               vi->stat_dirDiffAuthor[i]  = vi->stat_dirDiffAuthor[i];
+       }
+
+       vi->has_stats           = true;
+}
+
+/**
+ * kafs_VOLSER_ListOneVolume - Get the ordinary state of an instance of a volume
+ * @ctx: The cell and authentication context
+ * @server: The volume server to contact
+ * @partition: The partition on which the volume resides
+ * @volid: The ID of the volume to query
+ * @vi: The record to load with the information retrieved
+ *
+ * Query the ordinary state of a volume on a volume server.  The information is
+ * stored into the supplied record.
+ */
+bool kafs_VOLSER_ListOneVolume(struct kafs_context *ctx,
+                              struct kafs_fileserver *server,
+                              struct kafs_partition *partition,
+                              kafs_volume_id_t volid,
+                              struct kafs_volume_info *vi)
+{
+       struct volintInfo **infos;
+       unsigned int nr;
+       bool ret;
+
+       ret = VOLSER_ListOneVolume(&server->vs_params, partition->id, volid,
+                                  &infos, &nr, &ctx->result);
+       if (ret) {
+               if (nr)
+                       kafs_volintinfo_to_volume_info(infos[0], vi);
+               else
+                       ret = kafs_error(ctx, "No volume information results returned");
+               rxgen_bulk_free_volintInfo(infos, nr);
+       }
+
+       return ret;
+}
+
+/**
+ * kafs_VOLSER_XListOneVolume - Get the extended state of an instance of a volume
+ * @ctx: The cell and authentication context
+ * @server: The volume server to contact
+ * @partition: The partition on which the volume resides
+ * @volid: The ID of the volume to query
+ * @vi: The record to load with the information retrieved
+ *
+ * Query the extended state of a volume on a volume server.  The information is
+ * stored into the supplied record.
+ */
+bool kafs_VOLSER_XListOneVolume(struct kafs_context *ctx,
+                               struct kafs_fileserver *server,
+                               struct kafs_partition *partition,
+                               kafs_volume_id_t volid,
+                               struct kafs_volume_info *vi)
+{
+       struct xvolintInfo **xinfos;
+       unsigned int nr;
+       bool ret;
+
+       ret = VOLSER_XListOneVolume(&server->vs_params, partition->id, volid,
+                                   &xinfos, &nr, &ctx->result);
+       if (ret) {
+               if (nr)
+                       kafs_xvolintinfo_to_volume_info(xinfos[0], vi);
+               else
+                       ret = kafs_error(ctx, "No volume information results returned");
+               rxgen_bulk_free_xvolintInfo(xinfos, nr);
+       }
+
+       return ret;
+}
+
+/**
+ * kafs_query_volume_state - Query the state of an instance of a volume
+ * @ctx: The cell and authentication context
+ * @server: The volume server to contact
+ * @partition: The partition on which the volume resides
+ * @volid: The ID of the volume to query
+ * @extended: True if the extended state is desired; false otherwise.
+ * @_vi: Where to place the result record.
+ *
+ * Query the ordinary or extended state of a volume on a volume server and
+ * transcribe to a record which is placed at *@_vi.
+ */
+bool kafs_query_volume_state(struct kafs_context *ctx,
+                            struct kafs_fileserver *server,
+                            struct kafs_partition *partition,
+                            kafs_volume_id_t volid,
+                            bool extended,
+                            struct kafs_volume_info **_vi)
+{
+       struct kafs_volume_info *vi;
+       bool ret;
+
+       vi = calloc(1, sizeof(*vi));
+       if (!vi)
+               return kafs_nomem(ctx);
+
+       if (extended)
+               ret = kafs_VOLSER_XListOneVolume(ctx, server, partition, volid, vi);
+       else
+               ret = kafs_VOLSER_ListOneVolume(ctx, server, partition, volid, vi);
+       if (!ret) {
+               free(vi);
+               return false;
+       }
+
+       *_vi = vi;
+       return true;
+}
+
+/**
+ * kafs_list_partitions - Get a list of partitions on a server.
+ * @ctx: The cell and authentication context
+ * @server: The volume server to contact
+ * @partition_list: Where to store the list of partitions.
+ *
+ * Query a volume server and retrieve the list of volumes attached to it.
+ */
+bool kafs_list_partitions(struct kafs_context *ctx,
+                         struct kafs_fileserver *server,
+                         struct kafs_partition_list *partition_list)
+{
+       struct kafs_partition *parts = NULL;
+       unsigned int count;
+       int32_t *ents;
+       int i;
+
+       if (!VOLSER_XListPartitions(&server->vs_params, &ents, &count, &ctx->result))
+               return false;
+
+       if (count) {
+               parts = calloc(count, sizeof(*parts));
+               if (!parts) {
+                       free(ents);
+                       return true;
+               }
+
+               for (i = 0; i < count; i++)
+                       parts[i].id = ents[i];
+       }
+
+       partition_list->count = count;
+       partition_list->parts = parts;
+       free(ents);
+       return true;
+}
diff --git a/kafs/volservice.h b/kafs/volservice.h
new file mode 100644 (file)
index 0000000..ca747e5
--- /dev/null
@@ -0,0 +1,138 @@
+/* KAFS Volume service mid-level client library.
+ *
+ * Copyright (C) 2020 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 Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef VOLSERVICE_H
+#define VOLSERVICE_H
+
+#include "rxrpc.h"
+#include "kafs.h"
+#include "afs_xg.h"
+
+/*
+ * Volume transaction information.
+ *
+ * Source transDebugInfo.
+ */
+struct kafs_vol_transaction_info {
+       uint32_t        tid;
+       time_t          time;
+       time_t          creation_time;
+       uint32_t        return_code;
+       uint32_t        volid;
+       uint32_t        partition;
+       uint16_t        iflags;
+       uint8_t         vflags;
+       uint8_t         tflags;
+       char            last_proc_name[30];
+       uint32_t        call_valid;
+       uint32_t        read_next;
+       uint32_t        transmit_next;
+       time_t          last_send_time;
+       time_t          last_receive_time;
+};
+
+struct kafs_vol_transaction_info_list {
+       unsigned int    count;
+       struct kafs_vol_transaction_info *info;
+};
+
+/*
+ * Volume information.
+ *
+ * Source: volintInfo, xvolintInfo.
+ */
+struct kafs_volume_info {
+       kafs_volume_id_t volid;
+       kafs_volume_id_t backup_id;
+       kafs_volume_id_t parent_id;
+       kafs_volume_id_t clone_id;
+       unsigned int    type;
+       unsigned int    status;
+       unsigned int    copy_date;
+       bool            in_use;
+       bool            needs_salvage;
+       bool            destroy_me;
+       time_t          creation_date;
+       time_t          access_date;
+       time_t          update_date;
+       time_t          backup_date;
+       unsigned int    day_use;
+       unsigned int    week_use;               /* spare1 */
+       unsigned int    file_count;
+       unsigned int    max_quota;
+       unsigned int    min_quota;              /* spare0 */
+       unsigned int    size;
+       unsigned int    flags;
+
+       int             stat_reads[4];
+       int             stat_writes[4];
+       int             stat_fileSameAuthor[6];
+       int             stat_fileDiffAuthor[6];
+       int             stat_dirSameAuthor[6];
+       int             stat_dirDiffAuthor[6];
+
+       unsigned int    spare2;
+       unsigned int    spare3;
+
+       bool            has_flags:1;
+       bool            has_need_salvage:1;
+       bool            has_min_quota:1;
+       bool            has_stats:1;
+       bool            has_week_use:1;
+       bool            has_spare2:1;
+       bool            has_spare3:1;
+
+       char            name[VNAMESIZE];
+};
+
+/*
+ * List of partitions.
+ */
+struct kafs_partition_list {
+       unsigned int            count;
+       struct kafs_partition   *parts;
+};
+
+/*
+ * vol_probe.c
+ */
+extern bool kafs_open_volserver(struct kafs_context *, struct kafs_fileserver *);
+extern void kafs_close_volserver(struct kafs_context *, struct kafs_fileserver *);
+extern bool kafs_probe_volserver(struct kafs_context *, struct kafs_fileserver *);
+
+/*
+ * vol_query.c
+ */
+extern bool kafs_vol_monitor_transaction(struct kafs_context *, struct kafs_fileserver *,
+                                        struct kafs_vol_transaction_info_list *);
+extern bool kafs_list_partitions(struct kafs_context *, struct kafs_fileserver *,
+                                struct kafs_partition_list *);
+extern bool kafs_query_volume_state(struct kafs_context *, struct kafs_fileserver *,
+                                   struct kafs_partition *, kafs_volume_id_t, bool,
+                                   struct kafs_volume_info **);
+
+/*
+ * Inline functions
+ */
+static inline
+void clear_kafs_partition_list(struct kafs_partition_list *partitions)
+{
+       free(partitions->parts);
+}
+
+static inline
+void clear_kafs_vol_transaction_info_list(struct kafs_vol_transaction_info_list *info_list)
+{
+       free(info_list->info);
+       info_list->info = NULL;
+}
+
+#endif /* VLSERVICE_H */