--- /dev/null
+/*
+ * Copyright (c) 2020 Sine Nomine Associates. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Solaris kstat provider for OpenAFS.
+ */
+
+#include <afsconfig.h>
+#include "afs/param.h"
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/kstat.h>
+
+#include <rx/rx.h>
+
+#include "afs/sysincludes.h"
+#include "afsint.h"
+#include "vldbint.h"
+#include "afs/lock.h"
+#include "afs/afs_stats.h"
+#include "afs/afs.h"
+#include "afs/afsincludes.h"
+#include "afs/afs_prototypes.h"
+#include "rx/rx_atomic.h"
+#include "rx/rx_stats.h"
+
+extern char *AFSVersion;
+
+static kstat_t *afs_param_ksp;
+static kstat_t *afs_cache_ksp;
+static kstat_t *afs_rx_ksp;
+
+static char cellname[AFSNAMEMAX];
+
+/*
+ * Cache manager initialization parameters.
+ *
+ * nChunkFiles The number of disk files to allocate to the cache.
+ * nStatCaches The number of stat cache (vnode) entries to allocate.
+ * nDataCaches Number of dcache entries to allocate.
+ * nVolumeCaches Number of volume cache entries to allocate.
+ * chunkSize The size of file chunks.
+ * cacheSize The max number of 1 Kbyte blocks the cache may occupy.
+ * setTime Indicates clock setting is enabled.
+ * memCache Indicates memory-based cache is enabled.
+ */
+struct afs_param_kstat {
+ kstat_named_t nChunkFiles;
+ kstat_named_t nStatCaches;
+ kstat_named_t nDataCaches;
+ kstat_named_t nVolumeCaches;
+ kstat_named_t chunkSize;
+ kstat_named_t cacheSize;
+ kstat_named_t setTime;
+ kstat_named_t memCache;
+};
+static struct afs_param_kstat param_kstats = {
+ .nChunkFiles = {"nChunkFiles", KSTAT_DATA_ULONG},
+ .nStatCaches = {"nStatCaches", KSTAT_DATA_ULONG},
+ .nDataCaches = {"nDataCaches", KSTAT_DATA_ULONG},
+ .nVolumeCaches = {"nVolumeCaches", KSTAT_DATA_ULONG},
+ .chunkSize = {"chunkSize", KSTAT_DATA_ULONG},
+ .cacheSize = {"cacheSize", KSTAT_DATA_ULONG},
+ .setTime = {"setTime", KSTAT_DATA_ULONG},
+ .memCache = {"memCache", KSTAT_DATA_ULONG},
+};
+
+/*
+ * Update the param kstat.
+ *
+ * All file chunks are the same size, so do not bother reporting the first
+ * chunk size and other chunk size as two different numbers.
+ */
+static int
+afs_param_ks_update(kstat_t * ksp, int rw)
+{
+ struct afs_param_kstat *k = ksp->ks_data;
+ struct cm_initparams *s = &cm_initParams;
+
+ if (rw == KSTAT_WRITE) {
+ return EACCES;
+ }
+
+#define KSET(ks) do { k->ks.value.ul = s->cmi_ ## ks; } while (0)
+#define KSET2(ks,src) do { k->ks.value.ul = s->cmi_ ## src; } while (0)
+ KSET(nChunkFiles);
+ KSET(nStatCaches);
+ KSET(nDataCaches);
+ KSET(nVolumeCaches);
+ KSET2(chunkSize, firstChunkSize); /* same as otherChunkSize */
+ KSET(cacheSize);
+ KSET(setTime);
+ KSET(memCache);
+#undef KSET
+#undef KSET2
+ return 0;
+}
+
+/*
+ * Cache statistics.
+ *
+ * dlocalAccesses Number of data accesses to files within cell.
+ * vlocalAccesses Number of stat accesses to files within cell.
+ * dremoteAccesses Number of data accesses to files outside of cell.
+ * vremoteAccesses Number of stat accesses to files outside of cell.
+ * cacheNumEntries Number of cache entries (should match cacheFilesTotal).
+ * cacheBlocksTotal Number of 1K blocks configured for cache.
+ * cacheBlocksInUse Number of cache blocks actively in use.
+ * cacheMaxDirtyChunks Max number of dirty cache chunks tolerated.
+ * cacheCurrDirtyChunks Current number of dirty cache chunks.
+ * dcacheHits Count of data files (daches) found in local cache.
+ * vcacheHits Count of stat entries (vcaches) found in local cache.
+ * dcacheMisses Count of data files NOT found in local cache.
+ * vcacheMisses Count of of stat entries NOT found in local cache.
+ * cacheFlushes Count of times files are flushed from cache.
+ * cacheFilesReused Number of cache files reused.
+ * vcacheXAllocs Count of additionally allocated vcaches.
+ * dcacheXAllocs Count of additionally allocated dcaches.
+ * cacheFilesTotal Number of cache files (chunks).
+ * cacheFilesFree Number of cache files (chunks) available.
+ * cacheFilesInUse Number of cache files (chunks) in use.
+ * cacheTooFull Number of times the cache size or number of files exceeded.
+ * waitForDrain Number of times waited for cache to drain.
+ * cellname Local cellname.
+ * version OpenAFS version of the cache manager.
+ */
+struct afs_cache_kstat {
+ kstat_named_t dlocalAccesses;
+ kstat_named_t vlocalAccesses;
+ kstat_named_t dremoteAccesses;
+ kstat_named_t vremoteAccesses;
+ kstat_named_t cacheNumEntries;
+ kstat_named_t cacheBlocksTotal;
+ kstat_named_t cacheBlocksInUse;
+ kstat_named_t cacheMaxDirtyChunks;
+ kstat_named_t cacheCurrDirtyChunks;
+ kstat_named_t dcacheHits;
+ kstat_named_t vcacheHits;
+ kstat_named_t dcacheMisses;
+ kstat_named_t vcacheMisses;
+ kstat_named_t cacheFlushes;
+ kstat_named_t cacheFilesReused;
+ kstat_named_t vcacheXAllocs;
+ kstat_named_t dcacheXAllocs;
+ kstat_named_t cacheFilesTotal;
+ kstat_named_t cacheFilesFree;
+ kstat_named_t cacheFilesInUse;
+ kstat_named_t cacheTooFull;
+ kstat_named_t waitForDrain;
+ kstat_named_t cellname;
+ kstat_named_t version;
+};
+static struct afs_cache_kstat cache_kstats = {
+ .dlocalAccesses = {"dlocalAccesses", KSTAT_DATA_ULONG},
+ .vlocalAccesses = {"vlocalAccesses", KSTAT_DATA_ULONG},
+ .dremoteAccesses = {"dremoteAccesses", KSTAT_DATA_ULONG},
+ .vremoteAccesses = {"vremoteAccesses", KSTAT_DATA_ULONG},
+ .cacheNumEntries = {"cacheNumEntries", KSTAT_DATA_ULONG},
+ .cacheBlocksTotal = {"cacheBlocksTotal", KSTAT_DATA_ULONG},
+ .cacheBlocksInUse = {"cacheBlocksInUse", KSTAT_DATA_ULONG},
+ .cacheMaxDirtyChunks = {"cacheMaxDirtyChunks", KSTAT_DATA_ULONG},
+ .cacheCurrDirtyChunks = {"cacheCurrDirtyChunks", KSTAT_DATA_ULONG},
+ .dcacheHits = {"dcacheHits", KSTAT_DATA_ULONG},
+ .vcacheHits = {"vcacheHits", KSTAT_DATA_ULONG},
+ .dcacheMisses = {"dcacheMisses", KSTAT_DATA_ULONG},
+ .vcacheMisses = {"vcacheMisses", KSTAT_DATA_ULONG},
+ .cacheFlushes = {"cacheFlushes", KSTAT_DATA_ULONG},
+ .cacheFilesReused = {"cacheFilesReused", KSTAT_DATA_ULONG},
+ .vcacheXAllocs = {"vcacheXAllocs", KSTAT_DATA_ULONG},
+ .dcacheXAllocs = {"dcacheXAllocs", KSTAT_DATA_ULONG},
+ .cacheFilesTotal = {"cacheFilesTotal", KSTAT_DATA_ULONG},
+ .cacheFilesFree = {"cacheFilesFree", KSTAT_DATA_ULONG},
+ .cacheFilesInUse = {"cacheFilesInUse", KSTAT_DATA_ULONG},
+ .cacheTooFull = {"cacheTooFull", KSTAT_DATA_ULONG},
+ .waitForDrain = {"waitForDrain", KSTAT_DATA_ULONG},
+ .cellname = {"cellname", KSTAT_DATA_STRING},
+ .version = {"version", KSTAT_DATA_STRING},
+};
+
+/*
+ * Update the cache kstat.
+ */
+static int
+afs_cache_ks_update(kstat_t * ksp, int rw)
+{
+ struct afs_cache_kstat *k = ksp->ks_data;
+ struct afs_stats_CMPerf *s = &afs_stats_cmperf;
+
+ if (rw == KSTAT_WRITE) {
+ return EACCES;
+ }
+
+
+#define KSET(ks) do {k->ks.value.ul = s->ks;} while (0)
+ KSET(dlocalAccesses);
+ KSET(vlocalAccesses);
+ KSET(dremoteAccesses);
+ KSET(vremoteAccesses);
+ KSET(cacheNumEntries);
+ KSET(cacheBlocksTotal);
+ KSET(cacheBlocksInUse);
+ /* cacheBlocksOrig is a duplicate of cacheSize, so not repeated here. */
+ KSET(cacheMaxDirtyChunks);
+ KSET(cacheCurrDirtyChunks);
+ KSET(dcacheHits);
+ KSET(vcacheHits);
+ KSET(dcacheMisses);
+ KSET(vcacheMisses);
+ KSET(cacheFlushes);
+ KSET(cacheFilesReused);
+ KSET(vcacheXAllocs);
+ KSET(dcacheXAllocs);
+#undef KSET
+
+ /* The following stats not provided by xstat. */
+ k->cacheFilesTotal.value.ul = afs_cacheFiles;
+ k->cacheFilesFree.value.ul = afs_freeDCCount;
+ k->cacheFilesInUse.value.ul = afs_cacheFiles - afs_freeDCCount;
+ k->cacheTooFull.value.ul = afs_CacheTooFullCount;
+ k->waitForDrain.value.ul = afs_WaitForCacheDrainCount;
+ /* The following two values never change after OpenAFS init. */
+ kstat_named_setstr(&k->cellname, cellname);
+ kstat_named_setstr(&k->version, AFSVersion);
+
+ return 0;
+}
+
+/*
+ * Rx statistics.
+ *
+ * packetRequests Number of packet allocation requests.
+ *
+ * receivePktAllocFailures Packet allocation failure, receive.
+ * sendPktAllocFailures Packet allocation failure, send.
+ * specialPktAllocFailures Packet allocation failure, special.
+ *
+ * socketGreedy Whether SO_GREEDY succeeded.
+ * bogusPacketOnRead Number of inappropriately short packets received.
+ * bogusHost Host address from bogus packets.
+ * noPacketOnRead Number of read packets attempted when there was
+ * actually no packet to read off the wire.
+ * noPacketBuffersOnRead Number of dropped data packets due to lack of
+ * packet buffers.
+ * selects Number of selects waiting for packet or timeout.
+ * sendSelects Number of selects forced when sending packet.
+ *
+ * packetsRead_data Packets read, data type.
+ * packetsRead_ack Packets read, ack type.
+ * packetsRead_busy Packets read, busy type.
+ * packetsRead_abort Packets read, abort type.
+ * packetsRead_ackall Packets read, ackall type.
+ * packetsRead_challenge Packets read, challenge type.
+ * packetsRead_response Packets read, response type.
+ * packetsRead_debug Packets read, debug type.
+ * packetsRead_params Packets read, params type.
+ * packetsRead_unused0 Packets read, should be zero.
+ * packetsRead_unused1 Packets read, should be zero.
+ * packetsRead_unused2 Packets read, should be zero.
+ * packetsRead_version Packets read, version type.
+ *
+ * dataPacketsRead Number of unique data packets read off the wire.
+ * ackPacketsRead Number of ack packets read.
+ * dupPacketsRead Number of duplicate data packets read.
+ * spuriousPacketsRead Number of inappropriate data packets.
+ *
+ * packetsSent_data Packets sent, data type.
+ * packetsSent_ack Packets sent, ack type.
+ * packetsSent_busy Packets sent, busy type.
+ * packetsSent_abort Packets sent, abort type.
+ * packetsSent_ackall Packets sent, ackall type.
+ * packetsSent_challenge Packets sent, challenge type.
+ * packetsSent_response Packets sent, response type.
+ * packetsSent_debug Packets sent, debug type.
+ * packetsSent_params Packets sent, params type.
+ * packetsSent_unused0 Packets sent, should be zero.
+ * packetsSent_unused1 Packets sent, should be zero.
+ * packetsSent_unused2 Packets sent, should be zero.
+ * packetsSent_version Packets sent, version type.
+ *
+ * ackPacketsSent Number of acks sent.
+ * pingPacketsSent Total number of ping packets sent.
+ * abortPacketsSent Total number of aborts sent.
+ * busyPacketsSent Total number of busies sent.
+ * dataPacketsSent Number of unique data packets sent.
+ * dataPacketsReSent Number of retransmissions.
+ * dataPacketsPushed Number of retransmissions pushed early by a NACK.
+ * ignoreAckedPacket Number of packets with acked flag, on rxi_Start.
+ *
+ * totalRtt_sec Total round trip time measured, sec component.
+ * totalRtt_usec Total rount trip time messured, usec component.
+ * minRtt_sec Minimum round trip time measured, sec component
+ * minRtt_usec Minimum rount trip time measured, usec component.
+ * maxRtt_sec Maximum round trip time measured, sec component.
+ * maxRtt_usec Maximum round trip time measured, usec component.
+ *
+ * nRttSamples Total number of round trip samples.
+ * nServerConns Total number of server connections.
+ * nClientConns Total number of client connections.
+ * nPeerStructs Total number of peer structures.
+ * nCallStructs Total number of call structures allocated.
+ * nFreeCallStructs Total number of previously allocated free call
+ * structures.
+ *
+ * netSendFailures Number of times osi_NetSend failed.
+ * fatalErrors Number of connection errors.
+ * ignorePacketDally Packets dropped because call is in dally state.
+ *
+ * receiveCbufPktAllocFailures Packet allocation failure, receive cbuf.
+ * sendCbufPktAllocFailures Packet allocation failure, send cbuf.
+ *
+ * nBusies Number of times queued calls exceeds overload threshold.
+ */
+struct afs_rx_kstat {
+ kstat_named_t packetRequests;
+ kstat_named_t receivePktAllocFailures;
+ kstat_named_t sendPktAllocFailures;
+ kstat_named_t specialPktAllocFailures;
+ kstat_named_t socketGreedy;
+ kstat_named_t bogusPacketOnRead;
+ kstat_named_t bogusHost;
+ kstat_named_t noPacketOnRead;
+ kstat_named_t noPacketBuffersOnRead;
+ kstat_named_t selects;
+ kstat_named_t sendSelects;
+ kstat_named_t packetsRead[RX_N_PACKET_TYPES];
+ kstat_named_t dataPacketsRead;
+ kstat_named_t ackPacketsRead;
+ kstat_named_t dupPacketsRead;
+ kstat_named_t spuriousPacketsRead;
+ kstat_named_t packetsSent[RX_N_PACKET_TYPES];
+ kstat_named_t ackPacketsSent;
+ kstat_named_t pingPacketsSent;
+ kstat_named_t abortPacketsSent;
+ kstat_named_t busyPacketsSent;
+ kstat_named_t dataPacketsSent;
+ kstat_named_t dataPacketsReSent;
+ kstat_named_t dataPacketsPushed;
+ kstat_named_t ignoreAckedPacket;
+ kstat_named_t totalRtt_sec;
+ kstat_named_t totalRtt_usec;
+ kstat_named_t minRtt_sec;
+ kstat_named_t minRtt_usec;
+ kstat_named_t maxRtt_sec;
+ kstat_named_t maxRtt_usec;
+ kstat_named_t nRttSamples;
+ kstat_named_t nServerConns;
+ kstat_named_t nClientConns;
+ kstat_named_t nPeerStructs;
+ kstat_named_t nCallStructs;
+ kstat_named_t nFreeCallStructs;
+ kstat_named_t netSendFailures;
+ kstat_named_t fatalErrors;
+ kstat_named_t ignorePacketDally;
+ kstat_named_t receiveCbufPktAllocFailures;
+ kstat_named_t sendCbufPktAllocFailures;
+ kstat_named_t nBusies;
+};
+static struct afs_rx_kstat rx_kstats = {
+ .packetRequests = {"packetRequests", KSTAT_DATA_ULONG},
+ .receivePktAllocFailures = {"receivePktAllocFailures", KSTAT_DATA_ULONG},
+ .sendPktAllocFailures = {"sendPktAllocFailures", KSTAT_DATA_ULONG},
+ .specialPktAllocFailures = {"specialPktAllocFailures", KSTAT_DATA_ULONG},
+ .socketGreedy = {"socketGreedy", KSTAT_DATA_ULONG},
+ .bogusPacketOnRead = {"bogusPacketOnRead", KSTAT_DATA_ULONG},
+ .bogusHost = {"bogusHost", KSTAT_DATA_ULONG},
+ .noPacketOnRead = {"noPacketOnRead", KSTAT_DATA_ULONG},
+ .noPacketBuffersOnRead = {"noPacketBuffersOnRead", KSTAT_DATA_ULONG},
+ .selects = {"selects", KSTAT_DATA_ULONG},
+ .sendSelects = {"sendSelects", KSTAT_DATA_ULONG},
+ .packetsRead = {
+ {"packetsRead_data", KSTAT_DATA_ULONG},
+ {"packetsRead_ack", KSTAT_DATA_ULONG},
+ {"packetsRead_busy", KSTAT_DATA_ULONG},
+ {"packetsRead_abort", KSTAT_DATA_ULONG},
+ {"packetsRead_ackall", KSTAT_DATA_ULONG},
+ {"packetsRead_challenge", KSTAT_DATA_ULONG},
+ {"packetsRead_response", KSTAT_DATA_ULONG},
+ {"packetsRead_debug", KSTAT_DATA_ULONG},
+ {"packetsRead_params", KSTAT_DATA_ULONG},
+ {"packetsRead_unused0", KSTAT_DATA_ULONG},
+ {"packetsRead_unused1", KSTAT_DATA_ULONG},
+ {"packetsRead_unused2", KSTAT_DATA_ULONG},
+ {"packetsRead_version", KSTAT_DATA_ULONG},
+ },
+ .dataPacketsRead = {"dataPacketsRead", KSTAT_DATA_ULONG},
+ .ackPacketsRead = {"ackPacketsRead", KSTAT_DATA_ULONG},
+ .dupPacketsRead = {"dupPacketsRead", KSTAT_DATA_ULONG},
+ .spuriousPacketsRead = {"spuriousPacketsRead", KSTAT_DATA_ULONG},
+ .packetsSent = {
+ {"packetsSent_data", KSTAT_DATA_ULONG},
+ {"packetsSent_ack", KSTAT_DATA_ULONG},
+ {"packetsSent_busy", KSTAT_DATA_ULONG},
+ {"packetsSent_abort", KSTAT_DATA_ULONG},
+ {"packetsSent_ackall", KSTAT_DATA_ULONG},
+ {"packetsSent_challenge", KSTAT_DATA_ULONG},
+ {"packetsSent_response", KSTAT_DATA_ULONG},
+ {"packetsSent_debug", KSTAT_DATA_ULONG},
+ {"packetsSent_params", KSTAT_DATA_ULONG},
+ {"packetsSent_unused0", KSTAT_DATA_ULONG},
+ {"packetsSent_unused1", KSTAT_DATA_ULONG},
+ {"packetsSent_unused2", KSTAT_DATA_ULONG},
+ {"packetsSent_version", KSTAT_DATA_ULONG},
+ },
+ .ackPacketsSent = {"ackPacketsSent", KSTAT_DATA_ULONG},
+ .pingPacketsSent = {"pingPacketsSent", KSTAT_DATA_ULONG},
+ .abortPacketsSent = {"abortPacketsSent", KSTAT_DATA_ULONG},
+ .busyPacketsSent = {"busyPacketsSent", KSTAT_DATA_ULONG},
+ .dataPacketsSent = {"dataPacketsSent", KSTAT_DATA_ULONG},
+ .dataPacketsReSent = {"dataPacketsReSent", KSTAT_DATA_ULONG},
+ .dataPacketsPushed = {"dataPacketsPushed", KSTAT_DATA_ULONG},
+
+ .ignoreAckedPacket = {"ignoreAckedPacket", KSTAT_DATA_ULONG},
+ .totalRtt_sec = {"totalRtt_sec", KSTAT_DATA_ULONG},
+ .totalRtt_usec = {"totalRtt_usec", KSTAT_DATA_ULONG},
+ .minRtt_sec = {"minRtt_sec", KSTAT_DATA_ULONG},
+ .minRtt_usec = {"minRtt_usec", KSTAT_DATA_ULONG},
+ .maxRtt_sec = {"maxRtt_sec", KSTAT_DATA_ULONG},
+ .maxRtt_usec = {"maxRtt_usec", KSTAT_DATA_ULONG},
+ .nRttSamples = {"nRttSamples", KSTAT_DATA_ULONG},
+ .nServerConns = {"nServerConns", KSTAT_DATA_ULONG},
+ .nClientConns = {"nClientConns", KSTAT_DATA_ULONG},
+ .nPeerStructs = {"nPeerStructs", KSTAT_DATA_ULONG},
+ .nCallStructs = {"nCallStructs", KSTAT_DATA_ULONG},
+ .nFreeCallStructs = {"nFreeCallStructs", KSTAT_DATA_ULONG},
+ .netSendFailures = {"netSendFailures", KSTAT_DATA_ULONG},
+ .fatalErrors = {"fatalErrors", KSTAT_DATA_ULONG},
+ .ignorePacketDally = {"ignorePacketDally", KSTAT_DATA_ULONG},
+ .receiveCbufPktAllocFailures = {"receiveCbufPktAllocFailures", KSTAT_DATA_ULONG},
+ .sendCbufPktAllocFailures = {"sendCbufPktAllocFailures", KSTAT_DATA_ULONG},
+ .nBusies = {"nBusies", KSTAT_DATA_ULONG},
+};
+
+/*
+ * Update the rx kstat.
+ */
+static int
+afs_rx_ks_update(kstat_t * ksp, int rw)
+{
+ struct afs_rx_kstat *k = ksp->ks_data; /* ks_data is void* */
+ struct rx_statisticsAtomic *s = &rx_stats;
+ int i;
+
+ if (rw == KSTAT_WRITE) {
+ return EACCES;
+ }
+
+#define KSET(ks) do {k->ks.value.ul = s->ks;} while (0)
+#define KSET_ATOM(ks) do {k->ks.value.ul = rx_atomic_read(&(s->ks));} while (0)
+ KSET_ATOM(packetRequests);
+ KSET_ATOM(receivePktAllocFailures);
+ KSET_ATOM(sendPktAllocFailures);
+ KSET_ATOM(specialPktAllocFailures);
+ KSET_ATOM(socketGreedy);
+ KSET_ATOM(bogusPacketOnRead);
+ KSET(bogusHost);
+ KSET_ATOM(noPacketOnRead);
+ KSET_ATOM(noPacketBuffersOnRead);
+ KSET_ATOM(selects);
+ KSET_ATOM(sendSelects);
+ for (i = 0; i < RX_N_PACKET_TYPES; i++) {
+ KSET_ATOM(packetsRead[i]);
+ }
+ KSET_ATOM(dataPacketsRead);
+ KSET_ATOM(ackPacketsRead);
+ KSET_ATOM(dupPacketsRead);
+ KSET_ATOM(spuriousPacketsRead);
+ for (i = 0; i < RX_N_PACKET_TYPES; i++) {
+ KSET_ATOM(packetsSent[i]);
+ }
+ KSET_ATOM(ackPacketsSent);
+ KSET_ATOM(pingPacketsSent);
+ KSET_ATOM(abortPacketsSent);
+ KSET_ATOM(busyPacketsSent);
+ KSET_ATOM(dataPacketsSent);
+ KSET_ATOM(dataPacketsReSent);
+ KSET_ATOM(dataPacketsPushed);
+ KSET_ATOM(ignoreAckedPacket);
+
+ /* not rx_atomic */
+ k->totalRtt_sec.value.ul = s->totalRtt.sec;
+ k->totalRtt_usec.value.ul = s->totalRtt.usec;
+ k->minRtt_sec.value.ul = s->minRtt.sec;
+ k->minRtt_usec.value.ul = s->minRtt.usec;
+ k->maxRtt_sec.value.ul = s->maxRtt.sec;
+ k->maxRtt_usec.value.ul = s->maxRtt.usec;
+
+ KSET_ATOM(nRttSamples);
+ KSET_ATOM(nServerConns);
+ KSET_ATOM(nClientConns);
+ KSET_ATOM(nPeerStructs);
+ KSET_ATOM(nCallStructs);
+ KSET_ATOM(nFreeCallStructs);
+ KSET_ATOM(netSendFailures);
+ KSET_ATOM(fatalErrors);
+ KSET_ATOM(ignorePacketDally);
+ KSET_ATOM(receiveCbufPktAllocFailures);
+ KSET_ATOM(sendCbufPktAllocFailures);
+ KSET_ATOM(nBusies);
+#undef KSET
+#undef KSET_ATOM
+ return 0;
+}
+
+/*
+ * Create and install the kstats for this module.
+ *
+ * /pre AFS_GLOCK held
+ */
+void
+afs_kstat_init(void)
+{
+ char *thiscell = NULL;
+ struct cell *tcell;
+
+ afs_param_ksp = kstat_create("openafs", 0, "param", "misc", KSTAT_TYPE_NAMED,
+ sizeof(param_kstats) / sizeof(kstat_named_t),
+ KSTAT_FLAG_VIRTUAL);
+
+ if (afs_param_ksp == NULL) {
+ afs_warn("afs_kstat_init: kstat_create() failed for 'param'.\n");
+ } else {
+ afs_param_ksp->ks_data = ¶m_kstats;
+ afs_param_ksp->ks_update = afs_param_ks_update,
+ kstat_install(afs_param_ksp);
+ }
+
+ tcell = afs_GetPrimaryCell(READ_LOCK);
+ if (tcell)
+ thiscell = tcell->cellName;
+ if (thiscell == NULL || strlen(thiscell) == 0)
+ thiscell = "-UNKNOWN-";
+ strlcpy(cellname, thiscell, sizeof(cellname));
+ if (tcell)
+ afs_PutCell(tcell, READ_LOCK);
+
+ afs_cache_ksp = kstat_create("openafs", 0, "cache", "misc", KSTAT_TYPE_NAMED,
+ sizeof(cache_kstats) / sizeof(kstat_named_t),
+ KSTAT_FLAG_VIRTUAL);
+ if (afs_cache_ksp == NULL) {
+ afs_warn("afs_kstat_init: kstat_create() failed for 'cache'.\n");
+ } else {
+ /* Calculate the size of the KSTAT_DATA_STRINGs. */
+ afs_cache_ksp->ks_data_size += strlen(cellname) + 1;
+ afs_cache_ksp->ks_data_size += strlen(AFSVersion) + 1;
+ afs_cache_ksp->ks_data = &cache_kstats;
+ afs_cache_ksp->ks_update = afs_cache_ks_update;
+ kstat_install(afs_cache_ksp);
+ }
+
+ afs_rx_ksp = kstat_create("openafs", 0, "rx", "misc", KSTAT_TYPE_NAMED,
+ sizeof(rx_kstats) / sizeof(kstat_named_t),
+ KSTAT_FLAG_VIRTUAL);
+ if (afs_rx_ksp == NULL) {
+ afs_warn("afs_kstat_init: kstat_create() failed for 'rx'.\n");
+ } else {
+ afs_rx_ksp->ks_data = &rx_kstats;
+ afs_rx_ksp->ks_update = afs_rx_ks_update;
+ kstat_install(afs_rx_ksp);
+ }
+
+ return;
+}
+
+/*
+ * Remove the kstats.
+ */
+void
+afs_kstat_shutdown(void)
+{
+ if (afs_param_ksp != NULL) {
+ kstat_delete(afs_param_ksp);
+ afs_param_ksp = NULL;
+ }
+ if (afs_cache_ksp != NULL) {
+ kstat_delete(afs_cache_ksp);
+ afs_cache_ksp = NULL;
+ }
+ if (afs_rx_ksp != NULL) {
+ kstat_delete(afs_rx_ksp);
+ afs_rx_ksp = NULL;
+ }
+}