From db880bfb075fd150665910bb2fd6bf4ed85200dc Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 10 Jul 2020 12:07:42 +0100 Subject: [PATCH] midlayer: Add Volume Server support Signed-off-by: David Howells --- kafs/Makefile | 4 +- kafs/kafs.H | 1 + kafs/vol_probe.C | 149 +++++++++++++++++++++++++++++ kafs/vol_query.C | 236 ++++++++++++++++++++++++++++++++++++++++++++++ kafs/volservice.H | 155 ++++++++++++++++++++++++++++++ 5 files changed, 544 insertions(+), 1 deletion(-) create mode 100644 kafs/vol_probe.C create mode 100644 kafs/vol_query.C create mode 100644 kafs/volservice.H diff --git a/kafs/Makefile b/kafs/Makefile index c673349..c794fbd 100644 --- a/kafs/Makefile +++ b/kafs/Makefile @@ -13,7 +13,9 @@ CORE_SRCS := \ misc.C \ vl_fileservers.C \ vl_probe.C \ - vl_volumes.C + vl_volumes.C \ + vol_probe.C \ + vol_query.C BOS_SRCS := \ bos.C \ diff --git a/kafs/kafs.H b/kafs/kafs.H index 2a12dbf..cb0d63c 100644 --- a/kafs/kafs.H +++ b/kafs/kafs.H @@ -28,6 +28,7 @@ constexpr unsigned int FS_PORT = 7000; /* AFS file server port */ constexpr unsigned int FS_SERVICE = 1; /* AFS File Service ID */ constexpr unsigned int VL_PORT = 7003; /* Volume location service port */ constexpr unsigned int VL_SERVICE = 52; /* Service ID for the AFS Volume Location service */ +constexpr unsigned int YFS_VOL_SERVICE = 2502; /* Service ID for AuriStor upgraded volume service */ constexpr unsigned int YFS_VL_SERVICE = 2503; /* Service ID for AuriStor upgraded VL service */ } diff --git a/kafs/vol_probe.C b/kafs/vol_probe.C new file mode 100644 index 0000000..df5f714 --- /dev/null +++ b/kafs/vol_probe.C @@ -0,0 +1,149 @@ +/* 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 +#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 &vs_addrs = vs_site->vs_addrs; + rxrpc::Call_params ¶ms = vs_params; + struct sockaddr_rxrpc *srx; + std::vector 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"); + } +} diff --git a/kafs/vol_query.C b/kafs/vol_query.C new file mode 100644 index 0000000..21d6277 --- /dev/null +++ b/kafs/vol_query.C @@ -0,0 +1,236 @@ +/* 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 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 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 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 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]; +} diff --git a/kafs/volservice.H b/kafs/volservice.H new file mode 100644 index 0000000..4eaf7dc --- /dev/null +++ b/kafs/volservice.H @@ -0,0 +1,155 @@ +/* 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_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_list; + +/* + * List of partitions. + */ +typedef std::vector Partition_list; + +/* + * Volumeserver access handle. + */ +class Volserver : public rxrpc::refcount { +public: + rxrpc::ref vs_context; + rxrpc::ref 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 */ -- 2.49.0