/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/dump.c#2 $ */ #include "dump.h" #include #include "memoryAlloc.h" #include "typeDefs.h" #include "constants.h" #include "vdo.h" #include "dedupeIndex.h" #include "histogram.h" #include "ioSubmitter.h" #include "logger.h" enum dumpOptions { // WorkQueues SHOW_ALBIREO_QUEUE, SHOW_BIO_ACK_QUEUE, SHOW_BIO_QUEUE, SHOW_CPU_QUEUES, SHOW_REQUEST_QUEUE, // MemoryPools SHOW_VIO_POOL, // Others SHOW_VDO_STATUS, // This one means an option overrides the "default" choices, instead // of altering them. SKIP_DEFAULT }; enum dumpOptionFlags { // WorkQueues FLAG_SHOW_ALBIREO_QUEUE = (1 << SHOW_ALBIREO_QUEUE), FLAG_SHOW_BIO_ACK_QUEUE = (1 << SHOW_BIO_ACK_QUEUE), FLAG_SHOW_BIO_QUEUE = (1 << SHOW_BIO_QUEUE), FLAG_SHOW_CPU_QUEUES = (1 << SHOW_CPU_QUEUES), FLAG_SHOW_REQUEST_QUEUE = (1 << SHOW_REQUEST_QUEUE), // MemoryPools FLAG_SHOW_VIO_POOL = (1 << SHOW_VIO_POOL), // Others FLAG_SHOW_VDO_STATUS = (1 << SHOW_VDO_STATUS), // Special FLAG_SKIP_DEFAULT = (1 << SKIP_DEFAULT) }; enum { FLAGS_ALL_POOLS = (FLAG_SHOW_VIO_POOL), FLAGS_ALL_QUEUES = (FLAG_SHOW_REQUEST_QUEUE | FLAG_SHOW_ALBIREO_QUEUE | FLAG_SHOW_BIO_ACK_QUEUE | FLAG_SHOW_BIO_QUEUE | FLAG_SHOW_CPU_QUEUES), FLAGS_ALL_THREADS = (FLAGS_ALL_QUEUES), DEFAULT_DUMP_FLAGS = (FLAGS_ALL_THREADS | FLAG_SHOW_VDO_STATUS) }; /**********************************************************************/ static inline bool isArgString(const char *arg, const char *thisOption) { // device-mapper convention seems to be case-independent options return strncasecmp(arg, thisOption, strlen(thisOption)) == 0; } /**********************************************************************/ static void doDump(KernelLayer *layer, unsigned int dumpOptionsRequested, const char *why) { logInfo("%s dump triggered via %s", THIS_MODULE->name, why); // XXX Add in number of outstanding requests being processed by vdo uint32_t active, maximum; getLimiterValuesAtomically(&layer->requestLimiter, &active, &maximum); int64_t outstanding = atomic64_read(&layer->biosSubmitted) - atomic64_read(&layer->biosCompleted); logInfo("%" PRIu32 " device requests outstanding (max %" PRIu32 "), " "%" PRId64 " bio requests outstanding, poolName '%s'", active, maximum, outstanding, layer->deviceConfig->poolName); if ((dumpOptionsRequested & FLAG_SHOW_REQUEST_QUEUE) != 0) { dumpKVDOWorkQueue(&layer->kvdo); } if ((dumpOptionsRequested & FLAG_SHOW_BIO_QUEUE) != 0) { dumpBioWorkQueue(layer->ioSubmitter); } if (useBioAckQueue(layer) && ((dumpOptionsRequested & FLAG_SHOW_BIO_ACK_QUEUE) != 0)) { dumpWorkQueue(layer->bioAckQueue); } if ((dumpOptionsRequested & FLAG_SHOW_CPU_QUEUES) != 0) { dumpWorkQueue(layer->cpuQueue); } dumpDedupeIndex(layer->dedupeIndex, (dumpOptionsRequested & FLAG_SHOW_ALBIREO_QUEUE) != 0); dumpBufferPool(layer->dataKVIOPool, (dumpOptionsRequested & FLAG_SHOW_VIO_POOL) != 0); if ((dumpOptionsRequested & FLAG_SHOW_VDO_STATUS) != 0) { // Options should become more fine-grained when we have more to // display here. dumpKVDOStatus(&layer->kvdo); } reportMemoryUsage(); logInfo("end of %s dump", THIS_MODULE->name); } /**********************************************************************/ static int parseDumpOptions(unsigned int argc, char * const *argv, unsigned int *dumpOptionsRequestedPtr) { unsigned int dumpOptionsRequested = 0; static const struct { const char *name; unsigned int flags; } optionNames[] = { // Should "albireo" mean sending queue + receiving thread + outstanding? { "dedupe", FLAG_SKIP_DEFAULT | FLAG_SHOW_ALBIREO_QUEUE }, { "dedupeq", FLAG_SKIP_DEFAULT | FLAG_SHOW_ALBIREO_QUEUE }, { "kvdodedupeq", FLAG_SKIP_DEFAULT | FLAG_SHOW_ALBIREO_QUEUE }, { "bioack", FLAG_SKIP_DEFAULT | FLAG_SHOW_BIO_ACK_QUEUE }, { "kvdobioackq", FLAG_SKIP_DEFAULT | FLAG_SHOW_BIO_ACK_QUEUE }, { "bioackq", FLAG_SKIP_DEFAULT | FLAG_SHOW_BIO_ACK_QUEUE }, { "bio", FLAG_SKIP_DEFAULT | FLAG_SHOW_BIO_QUEUE }, { "kvdobioq", FLAG_SKIP_DEFAULT | FLAG_SHOW_BIO_QUEUE }, { "bioq", FLAG_SKIP_DEFAULT | FLAG_SHOW_BIO_QUEUE }, { "cpu", FLAG_SKIP_DEFAULT | FLAG_SHOW_CPU_QUEUES }, { "kvdocpuq", FLAG_SKIP_DEFAULT | FLAG_SHOW_CPU_QUEUES }, { "cpuq", FLAG_SKIP_DEFAULT | FLAG_SHOW_CPU_QUEUES }, { "request", FLAG_SKIP_DEFAULT | FLAG_SHOW_REQUEST_QUEUE }, { "kvdoreqq", FLAG_SKIP_DEFAULT | FLAG_SHOW_REQUEST_QUEUE }, { "reqq", FLAG_SKIP_DEFAULT | FLAG_SHOW_REQUEST_QUEUE }, { "viopool", FLAG_SKIP_DEFAULT | FLAG_SHOW_VIO_POOL }, { "vdo", FLAG_SKIP_DEFAULT | FLAG_SHOW_VDO_STATUS }, { "pools", FLAG_SKIP_DEFAULT | FLAGS_ALL_POOLS }, { "queues", FLAG_SKIP_DEFAULT | FLAGS_ALL_QUEUES }, { "threads", FLAG_SKIP_DEFAULT | FLAGS_ALL_THREADS }, { "default", FLAG_SKIP_DEFAULT | DEFAULT_DUMP_FLAGS }, { "all", ~0 }, }; bool optionsOkay = true; for (int i = 1; i < argc; i++) { int j; for (j = 0; j < COUNT_OF(optionNames); j++) { if (isArgString(argv[i], optionNames[j].name)) { dumpOptionsRequested |= optionNames[j].flags; break; } } if (j == COUNT_OF(optionNames)) { logWarning("dump option name '%s' unknown", argv[i]); optionsOkay = false; } } if (!optionsOkay) { return -EINVAL; } if ((dumpOptionsRequested & FLAG_SKIP_DEFAULT) == 0) { dumpOptionsRequested |= DEFAULT_DUMP_FLAGS; } *dumpOptionsRequestedPtr = dumpOptionsRequested; return 0; } /**********************************************************************/ int vdoDump(KernelLayer *layer, unsigned int argc, char * const *argv, const char *why) { unsigned int dumpOptionsRequested = 0; int result = parseDumpOptions(argc, argv, &dumpOptionsRequested); if (result != 0) { return result; } doDump(layer, dumpOptionsRequested, why); return 0; } /**********************************************************************/ void vdoDumpAll(KernelLayer *layer, const char *why) { doDump(layer, ~0, why); }