From 7250f36035eff38ca5bf4f1ba6ba714b79bde50c 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/display_vol.c | 1 + kafs/kafs.h | 6 + kafs/vol_probe.c | 165 +++++++++++++++++++++++++ kafs/vol_query.c | 296 +++++++++++++++++++++++++++++++++++++++++++++ kafs/volservice.h | 138 +++++++++++++++++++++ 6 files changed, 609 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 b8a1944..5d839b3 100644 --- a/kafs/Makefile +++ b/kafs/Makefile @@ -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 \ diff --git a/kafs/display_vol.c b/kafs/display_vol.c index e92ea9b..73e3de2 100644 --- a/kafs/display_vol.c +++ b/kafs/display_vol.c @@ -16,6 +16,7 @@ #include #include "kafs.h" #include "vlservice.h" +#include "volservice.h" #include "afs_xg.h" #include "display.h" diff --git a/kafs/kafs.h b/kafs/kafs.h index 11f8b47..52aaf86 100644 --- a/kafs/kafs.h +++ b/kafs/kafs.h @@ -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 index 0000000..f3b7cc3 --- /dev/null +++ b/kafs/vol_probe.c @@ -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 +#include +#include +#include +#include +#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, ¶ms->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 index 0000000..671d8a4 --- /dev/null +++ b/kafs/vol_query.c @@ -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 +#include +#include +#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 index 0000000..ca747e5 --- /dev/null +++ b/kafs/volservice.h @@ -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 */ -- 2.50.1