From 43a7bd99653aef5d9ffba71b7546b9f78fa4fe89 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 10 Jul 2020 08:40:08 +0100 Subject: [PATCH] cmd: Implement "vos listvol" Signed-off-by: David Howells --- kafs/Makefile | 1 + kafs/arg_parse.c | 5 +- kafs/display.c | 34 +++-- kafs/display.h | 14 +- kafs/display_vol.c | 82 ++++++------ kafs/kafs.h | 1 + kafs/vol_query.c | 308 ++++++++++++++++++++++++++++++++++++++++---- kafs/volservice.h | 166 +++++++++++++++--------- kafs/vos_examine.c | 17 ++- kafs/vos_listvldb.c | 12 +- kafs/vos_listvol.c | 252 ++++++++++++++++++++++++++++++++++++ kafs/vos_status.c | 21 +-- 12 files changed, 746 insertions(+), 167 deletions(-) create mode 100644 kafs/vos_listvol.c diff --git a/kafs/Makefile b/kafs/Makefile index 07bf3eb..3a08ad5 100644 --- a/kafs/Makefile +++ b/kafs/Makefile @@ -35,6 +35,7 @@ VOS_SRCS := \ vos_help.c \ vos_listaddrs.c \ vos_listvldb.c \ + vos_listvol.c \ vos_status.c CORE_OBJS := $(patsubst %.c,%.o,$(CORE_SRCS)) diff --git a/kafs/arg_parse.c b/kafs/arg_parse.c index ead026b..1ea7526 100644 --- a/kafs/arg_parse.c +++ b/kafs/arg_parse.c @@ -349,7 +349,10 @@ void free_kafs_context(struct kafs_context *ctx) void free_kafs_partition(struct kafs_partition *part) { - free(part); + if (part) { + free(part->name); + free(part); + } } diff --git a/kafs/display.c b/kafs/display.c index d9ba95e..b8345e8 100644 --- a/kafs/display.c +++ b/kafs/display.c @@ -9,6 +9,7 @@ * 2 of the Licence, or (at your option) any later version. */ +#define _GNU_SOURCE #include #include #include @@ -24,12 +25,12 @@ * * Print a time in a standard format for AFS tools to stdout. */ -void kafs_print_time(time_t time) +void kafs_print_time(const struct timespec *t) { struct tm tm; char buf[128]; - localtime_r(&time, &tm); + localtime_r(&t->tv_sec, &tm); strftime(buf, 128, "%a %b %d %H:%M:%S %Y", &tm); printf("%s", buf); } @@ -41,11 +42,11 @@ void kafs_print_time(time_t time) * Print a time in a standard format for AFS tools to stdout. If @time is 0, * then "Never" will be printed instead. */ -void kafs_print_time_or_never(time_t time) +void kafs_print_time_or_never(const struct timespec *t) { - if (!time) + if (!t->tv_sec) printf("Never"); - return kafs_print_time(time); + return kafs_print_time(t); } @@ -144,24 +145,29 @@ void kafs_sprint_address(struct kafs_context *ctx, * kafs_sprint_address - Convert a numeric ID into a partition name string. * @ctx: The cell and authentication context * @partition: The partition specified to convert - * @buf: The buffer to write into - * @buf_len: The size of the buffer * * Render the numeric partition ID to the standard string representation and - * write it into the buffer. + * attach it to the partition record. Returns a pointer to the buffer. */ -void kafs_sprint_partition(struct kafs_context *ctx, - struct kafs_partition *partition, - char *buf, size_t buf_len) +const char *kafs_sprint_partition(struct kafs_context *ctx, + struct kafs_partition *partition) { unsigned int n = partition->id; + int len; + + if (partition->name) + return partition->name; if (n < 26) { - snprintf(buf, buf_len, "/vicep%c", n + 97); + len = asprintf(&partition->name, "/vicep%c", n + 97); } else if (n <= 255) { n -= 26; - snprintf(buf, buf_len, "/vicep%c%c", n / 26 + 97, n % 26 + 97); + len = asprintf(&partition->name, "/vicep%c%c", n / 26 + 97, n % 26 + 97); } else { - snprintf(buf, buf_len, "/vicep?%u", n); + len = asprintf(&partition->name, "/vicep?%u", n); } + + if (len == -1) + return kafs_nomem(ctx), NULL; + return partition->name; } diff --git a/kafs/display.h b/kafs/display.h index 08c505c..e069272 100644 --- a/kafs/display.h +++ b/kafs/display.h @@ -21,10 +21,10 @@ struct kafs_volume_info; /* * display.c */ -extern void kafs_print_time(time_t); -extern void kafs_print_time_or_never(time_t); +extern void kafs_print_time(const struct timespec *t); +extern void kafs_print_time_or_never(const struct timespec *t); extern void kafs_sprint_address(struct kafs_context *, struct sockaddr_rxrpc *, char *, size_t); -extern void kafs_sprint_partition(struct kafs_context *, struct kafs_partition *, char *, size_t); +extern const char *kafs_sprint_partition(struct kafs_context *, struct kafs_partition *); /* * display_error.c @@ -35,14 +35,16 @@ extern bool kafs_display_error(struct kafs_context *); * display_vol.c */ extern void kafs_sprint_site(struct kafs_context *, struct kafs_vldb_site *, char *, size_t); -extern void kafs_display_vldb_site_list(struct kafs_context *, struct kafs_vldb_entry *, +extern bool kafs_display_vldb_site_list(struct kafs_context *, struct kafs_vldb_entry *, const char *); -extern void display_vol_information(struct kafs_context *, struct kafs_fileserver *, +extern bool display_vol_information(struct kafs_context *, struct kafs_fileserver *, struct kafs_partition *, struct kafs_volume_info *); extern void display_vol_statistics(struct kafs_context *, struct kafs_volume_info *); extern void display_vol_mp_basic_information(struct kafs_context *, struct kafs_fileserver *, struct kafs_partition *, struct kafs_volume_info *); extern void display_vol_mp_information(struct kafs_context *, struct kafs_fileserver *, struct kafs_partition *, struct kafs_volume_info *); - +extern bool display_vol_oneline_summary(struct kafs_context *, struct kafs_fileserver *, + struct kafs_partition *, struct kafs_volume_info *); + #endif /* DISPLAY_H */ diff --git a/kafs/display_vol.c b/kafs/display_vol.c index 0cda8d5..c87fc38 100644 --- a/kafs/display_vol.c +++ b/kafs/display_vol.c @@ -105,13 +105,13 @@ void kafs_sprint_site(struct kafs_context *ctx, * server fserver.abc.com partition /vicepa RW Site * server fserver.abc.com partition /vicepa RO Site */ -void kafs_display_vldb_site_list(struct kafs_context *ctx, +bool kafs_display_vldb_site_list(struct kafs_context *ctx, struct kafs_vldb_entry *vldb, const char *indent) { - const char *ptype; + const char *ptype, *part; unsigned int i; - char abuf[1024], pbuf[64]; + char abuf[1024]; printf("%snumber of sites -> %u\n", indent, vldb->nr_sites); for (i = 0; i < vldb->nr_sites; i++) { @@ -119,7 +119,9 @@ void kafs_display_vldb_site_list(struct kafs_context *ctx, unsigned int flags = site->flags; kafs_sprint_site(ctx, site, abuf, sizeof(abuf)); - kafs_sprint_partition(ctx, &site->partition, pbuf, sizeof(pbuf)); + part = kafs_sprint_partition(ctx, &site->partition); + if (!part) + return false; if (flags & VLSF_ROVOL) ptype = "RO"; @@ -129,7 +131,7 @@ void kafs_display_vldb_site_list(struct kafs_context *ctx, ptype = "Back"; printf("%s server %s partition %s %s Site\n", - indent, abuf, pbuf, ptype); + indent, abuf, part, ptype); } if (vldb->flags & (VLOP_MOVE | @@ -150,6 +152,8 @@ void kafs_display_vldb_site_list(struct kafs_context *ctx, if (vldb->flags & VLOP_DUMP) printf("%sVolume is locked for a dump/restore operation", indent); } + + return true; } /* @@ -158,7 +162,9 @@ void kafs_display_vldb_site_list(struct kafs_context *ctx, * proj.foo 536870957 RW 40475760 K On-line * */ -void display_vol_oneline_summary(struct kafs_context *ctx, +bool display_vol_oneline_summary(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *partition, struct kafs_volume_info *vi) { char tbuf[32]; @@ -169,12 +175,13 @@ void display_vol_oneline_summary(struct kafs_context *ctx, vol_type(vi, tbuf), vi->size, vol_state(vi)); + return true; } /* * Display a volume information timestamp. */ -static void display_vol_timestamp(const char *key, time_t t) +static void display_vol_timestamp(const char *key, struct timespec *t) { printf("%s", key); kafs_print_time_or_never(t); @@ -197,30 +204,32 @@ static void display_vol_timestamp(const char *key, time_t t) * * */ -void display_vol_information(struct kafs_context *ctx, +bool display_vol_information(struct kafs_context *ctx, struct kafs_fileserver *server, struct kafs_partition *part, struct kafs_volume_info *vi) { - char abuf[1024], pbuf[64]; + const char *part_name; + char abuf[1024]; kafs_sprint_address(ctx, &server->vs_addrs[0], abuf, sizeof(abuf)); - kafs_sprint_partition(ctx, part, pbuf, sizeof(pbuf)); + part_name = kafs_sprint_partition(ctx, part); - display_vol_oneline_summary(ctx, vi); - printf(" %s %s\n", abuf, pbuf); + display_vol_oneline_summary(ctx, server, part, vi); + printf(" %s %s\n", abuf, part_name); printf(" RWrite %10llu ROnly %10llu Backup %10llu\n", vi->parent_id, vi->clone_id, vi->backup_id); - printf(" MaxQuota %10u K\n", vi->max_quota); - - display_vol_timestamp(" Creation ", vi->creation_date); - display_vol_timestamp(" Copy ", vi->copy_date); - display_vol_timestamp(" Backup ", vi->backup_date); - display_vol_timestamp(" Last Access ", vi->access_date); - display_vol_timestamp(" Last Update ", vi->update_date); - printf(" %u accesses in the past day (i.e., vnode references)\n", + printf(" MaxQuota %10llu K\n", vi->max_quota); + + display_vol_timestamp(" Creation ", &vi->creation_date); + display_vol_timestamp(" Copy ", &vi->copy_date); + display_vol_timestamp(" Backup ", &vi->backup_date); + display_vol_timestamp(" Last Access ", &vi->access_date); + display_vol_timestamp(" Last Update ", &vi->update_date); + printf(" %llu accesses in the past day (i.e., vnode references)\n", vi->day_use); printf("\n"); + return true; } /* @@ -297,9 +306,9 @@ void display_vol_statistics(struct kafs_context *ctx, /* * Display a volume information timestamp in machine-parseable format */ -static void display_vol_mp_timestamp(const char *key, time_t t) +static void display_vol_mp_timestamp(const char *key, const struct timespec *t) { - printf("%s\t%-10lu\t", key, t); + printf("%s\t%-10lu\t", key, t->tv_sec); kafs_print_time(t); printf("\n"); } @@ -338,7 +347,8 @@ void display_vol_mp_basic_information(struct kafs_context *ctx, struct kafs_partition *partition, struct kafs_volume_info *vi) { - char abuf[20], sbuf[1024], pbuf[64], tbuf[16]; + const char *part; + char abuf[20], sbuf[1024], tbuf[16]; int i; abuf[0] = 0; @@ -354,13 +364,13 @@ void display_vol_mp_basic_information(struct kafs_context *ctx, strcpy(abuf, "0.0.0.0"); kafs_sprint_address(ctx, &server->vs_addrs[0], sbuf, sizeof(sbuf)); - kafs_sprint_partition(ctx, partition, pbuf, sizeof(pbuf)); + part = kafs_sprint_partition(ctx, partition); printf("BEGIN_OF_ENTRY\n"); printf("name\t\t%s\n", vi->name); printf("id\t\t%llu\n", vi->volid); printf("serv\t\t%-15s\t%s\n", abuf, sbuf); - printf("part\t\t%s\n", pbuf); + printf("part\t\t%s\n", part); printf("status\t\t%s\n", vol_status(vi)); printf("backupID\t%llu\n", vi->backup_id); printf("parentID\t%llu\n", vi->parent_id); @@ -372,23 +382,23 @@ void display_vol_mp_basic_information(struct kafs_context *ctx, } printf("type\t\t%s\n", vol_type(vi, tbuf)); - display_vol_mp_timestamp("creationDate", vi->creation_date); - display_vol_mp_timestamp("accessDate", vi->access_date); - display_vol_mp_timestamp("updateDate", vi->update_date); - display_vol_mp_timestamp("backupData", vi->backup_date); - display_vol_mp_timestamp("copyDate", vi->copy_date); + display_vol_mp_timestamp("creationDate", &vi->creation_date); + display_vol_mp_timestamp("accessDate", &vi->access_date); + display_vol_mp_timestamp("updateDate", &vi->update_date); + display_vol_mp_timestamp("backupData", &vi->backup_date); + display_vol_mp_timestamp("copyDate", &vi->copy_date); if (vi->has_flags) printf("flags\t\t%-7u\t(Optional)\n", vi->flags); printf("diskused\t%u\n", vi->size); - printf("maxquota\t%u\n", vi->max_quota); + printf("maxquota\t%llu\n", vi->max_quota); if (vi->has_min_quota) - printf("minquota\t%-7u\t(Optional)\n", vi->min_quota); + printf("minquota\t%-7llu\t(Optional)\n", vi->min_quota); - printf("filecount\t%u\n", vi->file_count); - printf("dayUse\t\t%u\n", vi->day_use); + printf("filecount\t%llu\n", vi->file_count); + printf("dayUse\t\t%llu\n", vi->day_use); } /* @@ -430,8 +440,8 @@ void display_vol_mp_information(struct kafs_context *ctx, { display_vol_mp_basic_information(ctx, server, partition, vi); - if (vi->has_week_use) - printf("weekUse\t\t%-7u\t(Optional)\n", vi->week_use); + if (vi->nr_week_use > 0) + printf("weekUse\t\t%-7llu\t(Optional)\n", vi->week_use[0]); if (vi->has_spare2) printf("spare2\t\t%-7u\t(Optional)\n", vi->spare2); if (vi->has_spare3) diff --git a/kafs/kafs.h b/kafs/kafs.h index 52aaf86..9942b14 100644 --- a/kafs/kafs.h +++ b/kafs/kafs.h @@ -83,6 +83,7 @@ struct kafs_group { struct kafs_partition { unsigned int id; + char *name; /* "/vicepa" ... "/vicepzz" */ }; struct kafs_fileserver_spec { diff --git a/kafs/vol_query.c b/kafs/vol_query.c index 671d8a4..78cdbc1 100644 --- a/kafs/vol_query.c +++ b/kafs/vol_query.c @@ -15,6 +15,73 @@ #include "volservice.h" #include "afs_xg.h" +/* + * Convert an AFS 32-bit time into a timespec. + */ +static struct timespec afs_time_to_timespec(unsigned int t) +{ + struct timespec ts; + + ts.tv_sec = t; + ts.tv_nsec = 0; + + return ts; +} + +/* + * Convert a signed 100ns-resolution 64-bit time into a timespec. + */ +static struct timespec yfs_time_to_timespec(struct opr_time yt) +{ + struct timespec ts; + unsigned long long abs_t, div, rem, t = yt.time; + + /* + * Unfortunately can not use normal 64 bit division on 32 bit arch, but + * the alternative, do_div, does not work with negative numbers so have + * to special case them + */ + if (t < 0) { + abs_t = -t; + div = abs_t / 10000000; + rem = abs_t % 10000000; + ts.tv_nsec = -(div * 100); + ts.tv_sec = rem; + } else { + abs_t = t; + div = abs_t / 10000000; + rem = abs_t % 10000000; + ts.tv_nsec = div * 100; + ts.tv_sec = rem; + } + + return ts; +} + +/* + * Expand a volume information list by a number of entries. + */ +static bool expand_kafs_volume_info_list(struct kafs_context *ctx, + struct kafs_volume_info_list *vlist, + size_t add_entries) +{ + struct kafs_volume_info **list = vlist->entries; + size_t max; + + if (vlist->nr_entries + add_entries <= vlist->max_entries) + return true; + + max = vlist->nr_entries + add_entries + 1; + list = reallocarray(list, max, sizeof(list[0])); + if (!list) + return kafs_nomem(ctx); + + memset(list + vlist->max_entries, 0, (max - vlist->max_entries) * sizeof(list[0])); + vlist->max_entries = max - 1; + vlist->entries = list; + return true; +} + /** * kafs_vol_monitor_transaction - Get the state of ongoing transactions on a volume server * @ctx: The cell and authentication context @@ -46,20 +113,20 @@ bool kafs_vol_monitor_transaction(struct kafs_context *ctx, 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; + info->tid = r->tid; + info->time.tv_sec = r->time; + info->creation_time.tv_sec = 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.tv_sec = r->lastSendTime; + info->last_receive_time.tv_sec = r->lastReceiveTime; strncpy(info->last_proc_name, r->lastProcName, sizeof(info->last_proc_name)); } @@ -84,30 +151,32 @@ static void kafs_volintinfo_to_volume_info(struct volintInfo *info, vi->parent_id = info->parentID; vi->clone_id = info->cloneID; vi->status = info->status; - vi->copy_date = info->copyDate; + vi->copy_date = afs_time_to_timespec(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->creation_date = afs_time_to_timespec(info->creationDate); + vi->access_date = afs_time_to_timespec(info->accessDate); + vi->update_date = afs_time_to_timespec(info->updateDate); + vi->backup_date = afs_time_to_timespec(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->week_use[0] = info->spare1; vi->spare2 = info->spare2; vi->spare3 = info->spare3; vi->has_flags = true; - vi->has_need_salvage = true; + vi->has_in_use = true; vi->has_min_quota = true; - vi->has_week_use = true; + vi->has_need_salvage = true; + vi->has_size = true; vi->has_spare2 = true; vi->has_spare3 = true; + vi->nr_week_use = 1; } /* @@ -125,12 +194,12 @@ static void kafs_xvolintinfo_to_volume_info(struct xvolintInfo *xinfo, vi->parent_id = xinfo->parentID; vi->clone_id = xinfo->cloneID; vi->status = xinfo->status; - vi->copy_date = xinfo->copyDate; + vi->copy_date = afs_time_to_timespec(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->creation_date = afs_time_to_timespec(xinfo->creationDate); + vi->access_date = afs_time_to_timespec(xinfo->accessDate); + vi->update_date = afs_time_to_timespec(xinfo->updateDate); + vi->backup_date = afs_time_to_timespec(xinfo->backupDate); vi->day_use = xinfo->dayUse; vi->file_count = xinfo->filecount; vi->max_quota = xinfo->maxquota; @@ -148,7 +217,64 @@ static void kafs_xvolintinfo_to_volume_info(struct xvolintInfo *xinfo, 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; +} + +/* + * Convert an xvolintInfo struct to a kafs_volume_info record. + */ +static void kafs_volintInfo64_to_volume_info(struct volintInfo64 *info, + struct volintStats64 *stats, + struct kafs_volume_info *vi) +{ + int i; + + strcpy(vi->name, info->name); + if (info->offlineMessage && info->offlineMessage[0]) { + vi->offline_msg = info->offlineMessage; + info->offlineMessage = NULL; + } + + 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->flags = info->flags; + vi->owner = info->owner; + + vi->creation_date = yfs_time_to_timespec(info->creationDate); + vi->access_date = yfs_time_to_timespec(info->accessDate); + vi->update_date = yfs_time_to_timespec(info->updateDate); + vi->expiration_date = yfs_time_to_timespec(info->expirationDate); + vi->backup_date = yfs_time_to_timespec(info->backupDate); + vi->copy_date = yfs_time_to_timespec(info->copyDate); + + vi->max_quota = info->maxquota; + vi->min_quota = info->minquota; + vi->max_files = info->maxfiles; + vi->disk_used = info->diskused; + vi->file_count = info->filecount; + vi->vol_update_counter = info->volUpdateCounter; + + vi->day_use_date = yfs_time_to_timespec(info->dayUseDate); + vi->day_use = info->dayUse; + for (i = 0; i < 7; i++) + vi->week_use[i] = info->weekUse[i]; + + vi->has_day_use_date = true; + vi->has_disk_used = true; + vi->has_expiration_date = true; + vi->has_flags = true; + vi->has_max_files = true; + vi->has_min_quota = true; + vi->has_owner = true; + vi->has_vol_update_counter = true; + vi->nr_week_use = 7; } /** @@ -219,6 +345,36 @@ bool kafs_VOLSER_XListOneVolume(struct kafs_context *ctx, return ret; } +/** + * kafs_YFSVOL_FetchVolumeInfo64 - Get 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 + * @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_YFSVOL_FetchVolumeInfo64(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *partition, + kafs_volume_id_t volid, + struct kafs_volume_info *vi) +{ + struct volintInfo64 result_entry; + struct volintStats64 result_stats; + bool ret; + + ret = YFSVOL_FetchVolumeInfo64(&server->vs_params, partition->id, volid, + 1, 1, &result_entry, &result_stats, + &ctx->result); + if (ret) + kafs_volintInfo64_to_volume_info(&result_entry, &result_stats, vi); + + return ret; +} + /** * kafs_query_volume_state - Query the state of an instance of a volume * @ctx: The cell and authentication context @@ -258,6 +414,104 @@ bool kafs_query_volume_state(struct kafs_context *ctx, return true; } +/** + * kafs_VOLSER_ListVolumes - Get the ordinary states of volume instances on a partition + * @ctx: The cell and authentication context + * @server: The volume server to contact + * @partition: The partition on which the volumes reside + * @vilist: 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_ListVolumes(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *partition, + struct kafs_volume_info *vi) +{ + struct volintInfo **infos; + unsigned int nr; + bool ret; + + ret = VOLSER_ListVolumes(&server->vs_params, partition->id, 1, + &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; +} + +/* + * Query the extended state of a volume. + */ +bool kafs_VOLSER_XListVolumes(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *partition, + struct kafs_volume_info *vi) +{ + struct xvolintInfo **xinfos; + unsigned int nr; + bool ret; + + ret = VOLSER_XListVolumes(&server->vs_params, partition->id, 1, + &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_states - Query the state of the volumes on a partition + * @ctx: The cell and authentication context + * @server: The volume server to contact + * @partition: The partition to search + * @extended: Whether extended info is required + * @vilist: The list to add the returned record to + * + * Query the state of a volume residing in a particular partition on a + * particular volume server. If successful, a record is allocated and + * added to the list. + */ +bool kafs_query_volume_states(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *partition, + bool extended, + struct kafs_volume_info_list *vilist) +{ + struct kafs_volume_info *vi; + bool ret; + + if (!expand_kafs_volume_info_list(ctx, vilist, 1)) + return false; + + vi = calloc(1, sizeof(*vi)); + if (!vi) + return kafs_nomem(ctx); + + if (extended) + ret = kafs_VOLSER_XListVolumes(ctx, server, partition, vi); + else + ret = kafs_VOLSER_ListVolumes(ctx, server, partition, vi); + if (!ret) { + free(vi); + return false; + } + + vilist->entries[vilist->nr_entries++] = vi; + return true; +} + /** * kafs_list_partitions - Get a list of partitions on a server. * @ctx: The cell and authentication context diff --git a/kafs/volservice.h b/kafs/volservice.h index ca747e5..83604e1 100644 --- a/kafs/volservice.h +++ b/kafs/volservice.h @@ -22,21 +22,21 @@ * 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; + uint32_t tid; + struct timespec time; + struct timespec 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; + struct timespec last_send_time; + struct timespec last_receive_time; }; struct kafs_vol_transaction_info_list { @@ -50,47 +50,74 @@ struct kafs_vol_transaction_info_list { * 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]; + 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 long long owner; + + struct timespec creation_date; + struct timespec access_date; + struct timespec update_date; + struct timespec expiration_date; + struct timespec backup_date; + struct timespec copy_date; + struct timespec 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; + + char *offline_msg; + char name[YVNAMESIZE]; +}; + +/* + * List of volume information objects. + */ +struct kafs_volume_info_list { + unsigned int nr_entries; + unsigned int max_entries; + struct kafs_volume_info **entries; }; /* @@ -118,21 +145,40 @@ extern bool kafs_list_partitions(struct kafs_context *, struct kafs_fileserver * extern bool kafs_query_volume_state(struct kafs_context *, struct kafs_fileserver *, struct kafs_partition *, kafs_volume_id_t, bool, struct kafs_volume_info **); +extern bool kafs_query_volume_states(struct kafs_context *, struct kafs_fileserver *, + struct kafs_partition *, bool, + struct kafs_volume_info_list *); /* * Inline functions */ +static inline +void clear_kafs_partition(struct kafs_partition *partition) +{ + free(partition->name); + partition->name = NULL; +} + 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) +static inline void clear_kafs_vol_transaction_info_list(struct kafs_vol_transaction_info_list *list) { - free(info_list->info); - info_list->info = NULL; + free(list->info); + list->info = NULL; + list->count = 0; } +static inline void clear_kafs_volume_info_list(struct kafs_volume_info_list *list) +{ + free(list->entries); + list->entries = NULL; + list->nr_entries = 0; + list->max_entries = 0; +} + + #endif /* VLSERVICE_H */ diff --git a/kafs/vos_examine.c b/kafs/vos_examine.c index 9ebea32..4bf2a93 100644 --- a/kafs/vos_examine.c +++ b/kafs/vos_examine.c @@ -19,7 +19,7 @@ #include "afs_xg.h" #include "display.h" -static void display_vldb(struct kafs_context *ctx, struct kafs_vldb_entry *vldb) +static bool display_vldb(struct kafs_context *ctx, struct kafs_vldb_entry *vldb) { if (vldb->volume_id[RWVOL] != 0) printf(" RWrite: %10llu", vldb->volume_id[RWVOL]); @@ -29,10 +29,10 @@ static void display_vldb(struct kafs_context *ctx, struct kafs_vldb_entry *vldb) printf(" Backup: %10llu", vldb->volume_id[BACKVOL]); printf("\n"); - kafs_display_vldb_site_list(ctx, vldb, " "); + return kafs_display_vldb_site_list(ctx, vldb, " "); } -static void display_normal(struct kafs_context *ctx, +static bool display_normal(struct kafs_context *ctx, struct kafs_vldb_entry *vldb, struct kafs_vldb_site *site, struct kafs_volume_info *vi, @@ -43,10 +43,10 @@ static void display_normal(struct kafs_context *ctx, if (extended) display_vol_statistics(ctx, vi); } - display_vldb(ctx, vldb); + return display_vldb(ctx, vldb); } -static void display_format(struct kafs_context *ctx, +static bool display_format(struct kafs_context *ctx, struct kafs_vldb_entry *vldb, struct kafs_vldb_site *site, struct kafs_volume_info *vi) @@ -55,7 +55,7 @@ static void display_format(struct kafs_context *ctx, display_vol_mp_information(ctx, site->server, &site->partition, vi); printf("\n"); } - display_vldb(ctx, vldb); + return display_vldb(ctx, vldb); } /*** @@ -150,10 +150,9 @@ bool COMMAND_vos_examine( } if (a_format && !a_extended) - display_format(ctx, vldb, site, vi); + ret = display_format(ctx, vldb, site, vi); else - display_normal(ctx, vldb, site, vi, a_extended); - ret = true; + ret = display_normal(ctx, vldb, site, vi, a_extended); error: clear_kafs_vldb_entry_list(&vlist); diff --git a/kafs/vos_listvldb.c b/kafs/vos_listvldb.c index f0afc4c..c27e856 100644 --- a/kafs/vos_listvldb.c +++ b/kafs/vos_listvldb.c @@ -18,10 +18,11 @@ #include "afs_xg.h" #include "display.h" -static void kafs_print_vl_record(struct kafs_context *ctx, +static bool kafs_print_vl_record(struct kafs_context *ctx, struct kafs_vldb_entry *vldb) { unsigned int flags; + bool ret; printf("%s\n", vldb->name); printf(" "); @@ -30,8 +31,9 @@ static void kafs_print_vl_record(struct kafs_context *ctx, if (flags & VLF_ROEXISTS) printf(" ROnly: %-12llu", vldb->volume_id[1]); if (flags & VLF_BACKEXISTS) printf(" Backup: %-12llu", vldb->volume_id[2]); printf("\n"); - kafs_display_vldb_site_list(ctx, vldb, " "); + ret = kafs_display_vldb_site_list(ctx, vldb, " "); printf("\n"); + return ret; } static int kafs_cmp_entries_by_name(const void *_a, const void *_b) @@ -89,7 +91,8 @@ bool COMMAND_vos_listvldb( !strchr(a_name->name, '*')) { if (!kafs_look_up_volume_by_name(ctx, a_name, &vlist)) return false; - kafs_print_vl_record(ctx, vlist.entries[0]); + if (!kafs_print_vl_record(ctx, vlist.entries[0])) + return false; } else { if (!kafs_look_up_volumes_by_attributes(ctx, a_server, a_partition, a_locked, @@ -105,7 +108,8 @@ bool COMMAND_vos_listvldb( kafs_cmp_entries_by_name); for (i = 0; i < vlist.nr_entries; i++) - kafs_print_vl_record(ctx, vlist.entries[i]); + if (!kafs_print_vl_record(ctx, vlist.entries[i])) + return false; if (!a_quiet) printf("Total entries: %u\n", vlist.nr_entries); } diff --git a/kafs/vos_listvol.c b/kafs/vos_listvol.c new file mode 100644 index 0000000..9c52285 --- /dev/null +++ b/kafs/vos_listvol.c @@ -0,0 +1,252 @@ +/* The "vos listvol" command + * + * 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 "kafs.h" +#include "volservice.h" +#include "arg_parse.h" +#include "display.h" +#include "afs_xg.h" + +static bool display_fast(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *part, + struct kafs_volume_info *vi) +{ + printf("%llu\n", vi->volid); + return true; +} + +static bool display_extended(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *part, + struct kafs_volume_info *vi) +{ + display_vol_information(ctx, server, part, vi); + display_vol_statistics(ctx, vi); + return true; +} + +static bool display_format_normal(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *part, + struct kafs_volume_info *vi) +{ + display_vol_mp_information(ctx, server, part, vi); + printf("END_OF_ENTRY\n"); + return true; +} + +static const char *const reads_labels[] = { + "reads_same_net", + "reads_same_net_auth", + "reads_diff_net", + "reads_diff_net_auth", +}; + +static const char *const writes_labels[] = { + "writes_same_net", + "writes_same_net_auth", + "writes_diff_net", + "writes_diff_net_auth", +}; + +static bool display_format_extended(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *part, + struct kafs_volume_info *vi) +{ + int i; + + if (vi->status != VOK) { + if (vi->status == VBUSY) + printf("VOLUME_BUSY\t%llu\n", vi->volid); + else + printf("COULD_NOT_ATTACH_VOLUME\t%llu\n", vi->volid); + return true; + } + + display_vol_mp_basic_information(ctx, server, part, vi); + + for (i = 0; i < 4; i++) + printf("%s\t%8d\n", reads_labels[i], vi->stat_reads[i]); + for (i = 0; i < 4; i++) + printf("%s\t%8d\n", writes_labels[i], vi->stat_writes[i]); + for (i = 0; i < 6; i++) { + printf("file_same_author_idx_%d\t%8d\n", i, vi->stat_fileSameAuthor[i]); + printf("file_diff_author_idx_%d\t%8d\n", i, vi->stat_fileDiffAuthor[i]); + printf("dir_same_author_idx_%d\t%8d\n", i, vi->stat_dirSameAuthor[i]); + printf("dir_dif_author_idx_%d\t%8d\n", i, vi->stat_dirDiffAuthor[i]); + } + + printf("END_OF_ENTRY"); + return true; +} + +static int compare_entries(const void *_a, const void *_b) +{ + const struct kafs_volume_info *a = _a; + const struct kafs_volume_info *b = _b; + + return strcmp(a->name, b->name); +} + +/* + * Display the records for a single partition in the appropriate format + */ +static bool display_one_partition(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *partition, + bool a_fast, + bool a_long, + bool a_quiet, + bool a_extended, + bool a_format) +{ + struct kafs_volume_info_list vilist = {}; + struct kafs_volume_info *vi; + const char *part_name; + unsigned int n_online = 0, n_offline = 0, n_busy = 0, i; + + bool (*display_func)(struct kafs_context *ctx, + struct kafs_fileserver *server, + struct kafs_partition *part, + struct kafs_volume_info *vi); + + if (!kafs_query_volume_states(ctx, server, partition, a_extended, &vilist)) + return false; + + part_name = kafs_sprint_partition(ctx, partition); + if (!part_name) + return false; + + if (!a_quiet) + printf("Total number of volumes on server %s partition %s: %u\n", + server->name, part_name, vilist.nr_entries); + + display_func = display_vol_oneline_summary; + if (a_fast) + display_func = display_fast; + else if (a_format && a_extended) + display_func = display_format_extended; + else if (a_format) + display_func = display_format_normal; + else if (a_extended) + display_func = display_extended; + else if (a_long) + display_func = display_vol_information; + + qsort(vilist.entries, vilist.nr_entries, sizeof(vilist.entries[0]), + compare_entries); + + for (i = 0; i < vilist.nr_entries; i++) { + vi = vilist.entries[i]; + if (vi->in_use) + n_online += 1; + if (vi->status == VBUSY) + n_busy += 1; + display_func(ctx, server, partition, vi); + } + + if (!a_quiet) { + printf("\n"); + if (!a_fast && !a_format) { + printf("Total volumes onLine %u; Total volumes offLine %u; Total busy %u\n", + n_online, n_offline, n_busy); + printf("\n"); + } else if (a_format && a_extended) { + printf("VOLUMES_ONLINE %u\n", n_online); + printf("VOLUMES_OFFLINE %u\n", n_offline); + printf("VOLUMES_BUSY %u\n", n_busy); + } + } + + clear_kafs_volume_info_list(&vilist); + return true; +} + +/*** + * COMMAND: vos listvol - Display information from a volume header + * ARG: "[-server ]" + * ARG: "[-partition ]" + * ARG: "[-fast]" + * ARG: "[-long]" + * ARG: "[-quiet]" + * ARG: "[-extended]" + * ARG: "[-format]" + * ARG: "[-cell ]" + * ARG: "[-noauth]" - Auth + * ARG: "[-localauth]" - Auth + * ARG: "[-verbose]" + * ARG: "[-encrypt]" - Auth + * ARG: "[-noresolve]" + * NOCOMBINE: fast, extended + * + * Display information from a volume header. + */ +bool COMMAND_vos_listvol( + struct kafs_context *ctx, + struct kafs_volserver_spec *a_server, + struct kafs_partition *a_partition, + bool a_fast, + bool a_long, + bool a_quiet, + bool a_extended, + bool a_format, + bool a_verbose, + bool a_noresolve) +{ + struct kafs_partition_list partitions = {}; + struct kafs_fileserver *server; + const char *part; + unsigned int i; + bool ret; + + _enter(""); + + ctx->no_resolve = a_noresolve; + + if (!kafs_resolve_volserver_spec(ctx, a_server, &server)) + return false; + + if (!kafs_open_volserver(ctx, server)) + return false; + + if (a_partition) { + ret = display_one_partition(ctx, server, a_partition, + a_fast, a_long, a_quiet, a_extended, + a_format); + if (!ret) { + if (ctx->result.source == rxrpc_error_remote_abort && + ctx->result.abort_code == VOLSERILLEGAL_PARTITION) { + part = kafs_sprint_partition(ctx, a_partition); + kafs_error(ctx, "vos : partition %s does not exist on the server", + part); + } + } + } else { + ret = kafs_list_partitions(ctx, server, &partitions); + if (!ret) + goto out; + for (i = 0; i < partitions.count; i++) + if (!display_one_partition(ctx, server, &partitions.parts[i], + a_fast, a_long, a_quiet, a_extended, + a_format)) + goto out; + } + +out: + clear_kafs_partition_list(&partitions); + return ret; +} diff --git a/kafs/vos_status.c b/kafs/vos_status.c index edb23cd..8a9ec6e 100644 --- a/kafs/vos_status.c +++ b/kafs/vos_status.c @@ -40,7 +40,6 @@ bool COMMAND_vos_status( struct kafs_vol_transaction_info_list transactions = {}; struct kafs_fileserver *server; unsigned int i; - char pbuf[32]; int ret = false; _enter(""); @@ -65,14 +64,15 @@ bool COMMAND_vos_status( printf("--------------------------------------------\n"); for (i = 0; i < transactions.count; i++) { struct kafs_vol_transaction_info *trans = &transactions.info[i]; - struct kafs_partition part; + struct kafs_partition partition; + const char *part; unsigned int iflags = trans->iflags; printf("transaction: %d created: ", trans->tid); - kafs_print_time(trans->creation_time); + kafs_print_time(&trans->creation_time); printf("\n"); printf("lastActiveTime: "); - kafs_print_time(trans->time); + kafs_print_time(&trans->time); printf("\n"); if (iflags & ITOffline) @@ -88,16 +88,17 @@ bool COMMAND_vos_status( else printf("attachFlags: %u\n", trans->iflags); - memset(&part, 0, sizeof(part)); - part.id = trans->partition; - kafs_sprint_partition(ctx, &part, pbuf, sizeof(pbuf)), + memset(&partition, 0, sizeof(partition)); + partition.id = trans->partition; + part = kafs_sprint_partition(ctx, &partition), printf("volume: %u partition %s procedure %s", - trans->volid, pbuf, trans->last_proc_name); + trans->volid, part, trans->last_proc_name); + clear_kafs_partition(&partition); printf("packetRead: %u", trans->read_next); - printf(" lastReceiveTime: %lu", trans->last_receive_time); + printf(" lastReceiveTime: %lu", trans->last_receive_time.tv_sec); printf(" packetSend: %u", trans->transmit_next); printf("\n"); - printf(" lastSendTime: %lu\n", trans->last_send_time); + printf(" lastSendTime: %lu\n", trans->last_send_time.tv_sec); printf("--------------------------------------------\n"); } -- 2.50.1