--- /dev/null
+/* 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 <fmt/core.h>
+#include "volservice.H"
+#include "afs_xg.H"
+#include "display.H"
+
+using rxrpc::ref;
+using kafs::Volserver;
+
+/**
+ * Volserver::Volserver - Open a Volume Server for access.
+ * @ctx: The cell and authentication context
+ * @site: The volume server details
+ *
+ * Open a Volume Server. The server is probed to determine what it's capable
+ * of and what type it is.
+ */
+Volserver::Volserver(Context *ctx, FS_site *site)
+{
+ vs_context = ctx;
+ vs_site = site;
+ vs_probed = false;
+
+ open_endpoint(ctx);
+ if (!vs_probed)
+ probe_volserver();
+}
+
+/*
+ * Volserver::~Volserver - Close a Volume Server.
+ *
+ * Close a volume server, potentially releasing any resources held.
+ */
+Volserver::~Volserver()
+{
+}
+
+/**
+ * Volserver::probe_volserver - Probe a Volume Server
+ *
+ * Probe a volume server to find what it supports.
+ */
+void Volserver::probe_volserver()
+{
+ std::vector<sockaddr_rxrpc> &vs_addrs = vs_site->vs_addrs;
+ rxrpc::Call_params ¶ms = vs_params;
+ struct sockaddr_rxrpc *srx;
+ std::vector<unsigned int> caps;
+ std::error_code saved_error;
+ std::string abuf;
+ unsigned int addr = 0, i, nr_caps;
+
+ _enter("");
+
+try_next_address:
+ if (addr >= vs_addrs.size()) {
+ if (saved_error)
+ throw std::system_error(saved_error, "Volume server not responding");
+ throw std::runtime_error("No volume servers available");
+ }
+
+ srx = &vs_addrs[addr];
+ params.endpoint = vs_context->endpoint;
+ params.security = vs_context->security;
+ params.peer = *srx;
+ params.peer_len = sizeof(*srx);
+ params.upgrade_service = true;
+
+ abuf = sprint_address(vs_context, params.peer);
+ _debug("addr %u %s", addr, abuf.c_str());
+
+ try {
+ afs::VOLSER::GetCapabilities(¶ms, caps);
+ } catch (const rxrpc::AbortRXGEN_OPCODE &a) {
+ vs_service = service_afs;
+ params.upgrade_service = false;
+ memset(&vs_caps, 0, sizeof(vs_caps));
+ goto out;
+ } catch (const rxrpc::AbortRX_INVALID_OPERATION &a) {
+ vs_service = service_afs;
+ params.upgrade_service = false;
+ memset(&vs_caps, 0, sizeof(vs_caps));
+ goto out;
+ } catch (const std::system_error &e) {
+ switch (e.code().value()) {
+ case -ENONET:
+ case -ECONNRESET: /* Responded, but call expired. */
+ case -ERFKILL:
+ case -EADDRNOTAVAIL:
+ case -ENETUNREACH:
+ case -EHOSTUNREACH:
+ case -EHOSTDOWN:
+ case -ECONNREFUSED:
+ case -ETIMEDOUT:
+ case -ETIME:
+ saved_error.assign(e.code().value(), e.code().category());
+ addr++;
+ goto try_next_address;
+ default:
+ throw;
+ }
+ }
+
+ params.upgrade_service = false;
+ vs_pref = addr;
+ switch (params.service_id_used) {
+ case afs::VOLSERVICE_ID:
+ vs_service = service_afs;
+ break;
+ case afs::YFS_VOL_SERVICE:
+ vs_service = service_yfs;
+ params.peer.srx_service = params.service_id_used;
+ for (i = 0; i < vs_addrs.size(); i++)
+ vs_addrs[i].srx_service = params.service_id_used;
+ break;
+ default:
+ throw std::runtime_error(
+ fmt::format("Upgraded to unsupported volume service {:d}",
+ vs_params.service_id_used));
+ }
+
+ memset(&vs_caps, 0, sizeof(vs_caps));
+ nr_caps = caps.size();
+ if (nr_caps > sizeof(vs_caps) / sizeof(vs_caps))
+ nr_caps = sizeof(vs_caps) / sizeof(vs_caps);
+ for (i = 0; i < nr_caps; i++)
+ vs_caps[i] = caps[i];
+
+out:
+ if (debug_caps) {
+ printf("volser-caps:");
+ for (i = 0; i < sizeof(vs_caps) / sizeof(unsigned int); i++)
+ printf(" %08x", vs_caps[i]);
+ if (vs_service == service_yfs)
+ printf(" yfs\n");
+ else
+ printf(" afs\n");
+ }
+}
--- /dev/null
+/* 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 "volservice.H"
+#include "afs_xg.H"
+
+using rxrpc::ref;
+using kafs::Volserver;
+
+namespace kafs {
+static void volintinfo_to_volume_info(afs::volintInfo &info, Volume_info_list &vilist);
+static void xvolintinfo_to_volume_info(afs::xvolintInfo &xinfo, Volume_info_list &vilist);
+}
+
+/**
+ * Volserver::vol_monitor_transaction - Get the state of ongoing transactions on a volume server
+ * @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.
+ */
+void Volserver::vol_monitor_transaction(Vol_transaction_info_list &info_list)
+{
+ std::vector<afs::transDebugInfo> results;
+ unsigned int i;
+
+ afs::VOLSER::Monitor(&vs_params, results);
+ if (!results.size())
+ return;
+
+ info_list.resize(results.size());
+
+ for (i = 0; i < results.size(); i++) {
+ Vol_transaction_info &info = info_list[i];
+ afs::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.id = 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;
+ info.last_proc_name = r.lastProcName;
+ }
+}
+
+/*
+ * Convert a volintInfo struct to a Volserver::volume_info record.
+ */
+static void kafs::volintinfo_to_volume_info(afs::volintInfo &info,
+ Volume_info_list &vilist)
+{
+ unsigned int index = vilist.size();
+ vilist.resize(index + 1);
+ Volume_info &vi = vilist[index];
+
+ 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[0] = info.spare1;
+ vi.spare2 = info.spare2;
+ vi.spare3 = info.spare3;
+
+ vi.has_flags = true;
+ vi.has_in_use = true;
+ vi.has_min_quota = true;
+ vi.has_need_salvage = true;
+ vi.has_size = true;
+ vi.has_spare2 = true;
+ vi.has_spare3 = true;
+ vi.nr_week_use = 1;
+}
+
+/*
+ * Convert an xvolintInfo struct to a Volserver::volume_info record.
+ */
+static void kafs::xvolintinfo_to_volume_info(afs::xvolintInfo &xinfo,
+ Volume_info_list &vilist)
+{
+ unsigned int index = vilist.size();
+ vilist.resize(index + 1);
+ Volume_info &vi = vilist[index];
+ int i;
+
+ 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_in_use = true;
+ vi.has_size = true;
+ vi.has_stats = true;
+ vi.nr_week_use = 0;
+}
+
+/**
+ * Volserver::VOLSER_ListOneVolume - Get the ordinary state of an instance of a volume
+ * @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.
+ */
+void Volserver::VOLSER_ListOneVolume(Partition_spec &partition,
+ Volume_id volid,
+ Volume_info_list &vi)
+{
+ std::vector<afs::volintInfo> infos;
+
+ afs::VOLSER::ListOneVolume(&vs_params, partition.id, volid, infos);
+ if (!infos.size())
+ throw std::runtime_error("No volume information results returned");
+
+ volintinfo_to_volume_info(infos[0], vi);
+}
+
+/**
+ * Volserver::VOLSER_XListOneVolume - Get the extended state of an instance of a volume
+ * @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.
+ */
+void Volserver::VOLSER_XListOneVolume(Partition_spec &partition,
+ Volume_id volid,
+ Volume_info_list &vi)
+{
+ std::vector<afs::xvolintInfo> xinfos;
+
+ afs::VOLSER::XListOneVolume(&vs_params, partition.id, volid, xinfos);
+ if (!xinfos.size())
+ throw std::runtime_error("No volume information results returned");
+
+ xvolintinfo_to_volume_info(xinfos[0], vi);
+}
+
+/**
+ * Volserver::query_volume_state - Query the state of an instance of a volume
+ * @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.
+ */
+void Volserver::query_volume_state(Partition_spec &partition,
+ Volume_id volid,
+ bool extended,
+ Volume_info_list &vi)
+{
+ if (extended)
+ VOLSER_XListOneVolume(partition, volid, vi);
+ else
+ VOLSER_ListOneVolume(partition, volid, vi);
+}
+
+/**
+ * Volserver::list_partitions - Get a list of partitions on a server.
+ * @partitions: Where to store the list of partitions.
+ *
+ * Query a volume server and retrieve the list of volumes attached to it.
+ */
+void Volserver::list_partitions(Partition_list &partitions)
+{
+ std::vector<int32_t> ents;
+ unsigned int i;
+
+ afs::VOLSER::XListPartitions(&vs_params, ents);
+
+ partitions.resize(ents.size());
+ for (i = 0; i < ents.size(); i++)
+ partitions[i].id = ents[i];
+}
--- /dev/null
+/* 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"
+
+namespace kafs {
+
+/*
+ * Volume transaction information.
+ *
+ * Source transDebugInfo.
+ */
+struct Vol_transaction_info {
+ uint32_t tid;
+ Time time;
+ Time creation_time;
+ uint32_t return_code;
+ uint32_t volid;
+ Partition_spec partition;
+ uint16_t iflags;
+ uint8_t vflags;
+ uint8_t tflags;
+ uint32_t call_valid;
+ uint32_t read_next;
+ uint32_t transmit_next;
+ Time last_send_time;
+ Time last_receive_time;
+ std::string last_proc_name;
+};
+
+typedef std::vector<Vol_transaction_info> Vol_transaction_info_list;
+
+/*
+ * Volume information.
+ *
+ * Source: volintInfo, xvolintInfo.
+ */
+struct Volume_info {
+ Volume_id volid;
+ Volume_id backup_id;
+ Volume_id parent_id;
+ Volume_id clone_id;
+ unsigned int type;
+ unsigned int status;
+ unsigned long long owner;
+
+ Time creation_date;
+ Time access_date;
+ Time update_date;
+ Time expiration_date;
+ Time backup_date;
+ Time copy_date;
+ Time day_use_date;
+ unsigned long long vol_update_counter;
+
+ unsigned long long day_use;
+ unsigned long long week_use[7]; /* spare1 */
+ unsigned long long file_count;
+ unsigned long long disk_used;
+ unsigned long long max_quota;
+ unsigned long long min_quota; /* spare0 */
+ unsigned long long max_files;
+ 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 in_use;
+ bool needs_salvage;
+ bool destroy_me;
+
+ bool has_day_use_date:1;
+ bool has_disk_used:1;
+ bool has_expiration_date:1;
+ bool has_flags:1;
+ bool has_in_use:1;
+ bool has_max_files:1;
+ bool has_min_quota:1;
+ bool has_need_salvage:1;
+ bool has_owner:1;
+ bool has_size:1;
+ bool has_spare2:1;
+ bool has_spare3:1;
+ bool has_stats:1;
+ bool has_vol_update_counter:1;
+ unsigned char nr_week_use;
+
+ std::string offline_msg;
+ std::string name;
+};
+
+typedef std::vector<Volume_info> Volume_info_list;
+
+/*
+ * List of partitions.
+ */
+typedef std::vector<Partition_spec> Partition_list;
+
+/*
+ * Volumeserver access handle.
+ */
+class Volserver : public rxrpc::refcount {
+public:
+ rxrpc::ref<Context> vs_context;
+ rxrpc::ref<FS_site> vs_site;
+ Service vs_service; /* Service provided by the volserver */
+ unsigned int vs_caps[1]; /* Volserver capabilities */
+ 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 */
+
+ const std::string &name() const { return vs_site->name; }
+
+ /* vol_probe.C */
+ Volserver(Context *ctx, FS_site *site);
+ ~Volserver();
+ void probe_volserver();
+
+ /* vol_query.C */
+ void VOLSER_ListOneVolume(Partition_spec &partition,
+ Volume_id volid,
+ Volume_info_list &vi);
+ void VOLSER_XListOneVolume(Partition_spec &partition,
+ Volume_id volid,
+ Volume_info_list &vi);
+ void vol_monitor_transaction(Vol_transaction_info_list &);
+ void list_partitions(Partition_list &);
+ void query_volume_state(Partition_spec &, Volume_id, bool,
+ Volume_info_list &);
+};
+
+} /* end namespace kafs */
+
+#endif /* VLSERVICE_H */