SOLARIS: provide cache manager stats via kstat 70/13170/14
authorMichael Meffie <mmeffie@sinenomine.net>
Tue, 31 May 2016 20:23:41 +0000 (16:23 -0400)
committerBenjamin Kaduk <kaduk@mit.edu>
Fri, 12 Feb 2021 05:18:30 +0000 (00:18 -0500)
Provide statistical information via the solaris kstat framework.  Data
can be examined with the kstat tool or the kstat userspace api.

The kstat module is called openafs. Three kstat names are provided.  The
"param" name provides cache manager parameters as given by the cmdebug
-cache program.

    # kstat -m openafs -n param

The "cache" name provides cache manager statistics as given by the
xstats plus some additional cache related stats. The "cache" name also
provides the libafs kernel module version string and the current local
cellname.

    # kstat -m openafs -n cache

The "rx" name provides general rx statistics as given by rxdebug -rxstat.

    # kstat -m openafs -n rx

Change-Id: Ic07e3b58fa5c79145f12f8519a6f7fce0d91138b
Reviewed-on: https://gerrit.openafs.org/13170
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/afs/SOLARIS/osi_kstat.c [new file with mode: 0644]
src/afs/afs.h
src/afs/afs_call.c
src/afs/afs_prototypes.h
src/libafs/Makefile.common.in
src/libafs/MakefileProto.SOLARIS.in

diff --git a/src/afs/SOLARIS/osi_kstat.c b/src/afs/SOLARIS/osi_kstat.c
new file mode 100644 (file)
index 0000000..a1e8494
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ * 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 = &param_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;
+    }
+}
index d92fff7..96243ee 100644 (file)
@@ -1370,6 +1370,8 @@ extern afs_int32 *afs_dcnextTbl;  /*Dcache hash table links */
 extern afs_int32 afs_cacheFiles;       /*Size of afs_indexTable */
 extern afs_int32 afs_cacheBlocks;      /*1K blocks in cache */
 extern afs_int32 afs_cacheStats;       /*Stat entries in cache */
+extern afs_int32 afs_freeDCCount;      /*Count of elts in freeDCList */
+extern afs_uint32 afs_CacheTooFullCount;
 extern afs_uint32 afs_WaitForCacheDrainCount;
 extern struct vcache *afs_vhashT[VCSIZE];      /*Stat cache hash table */
 extern struct afs_q afs_vhashTV[VCSIZE]; /* cache hash table on volume */
index 44bdcbe..367265d 100644 (file)
@@ -1107,6 +1107,10 @@ afs_syscall_call(long parm, long parm2, long parm3,
        if (afs_uuid_create(&afs_cb_interface.uuid) != 0)
            memset(&afs_cb_interface.uuid, 0, sizeof(afsUUID));
 
+#if defined(AFS_SUN5_ENV)
+       afs_kstat_init();
+#endif
+
        printf("found %d non-empty cache files (%d%%).\n",
               afs_stats_cmperf.cacheFilesReused,
               (100 * afs_stats_cmperf.cacheFilesReused) /
@@ -1407,6 +1411,10 @@ afs_shutdown(void)
 
     afs_shuttingdown = AFS_SHUTDOWN;
 
+#if defined(AFS_SUN5_ENV)
+    afs_kstat_shutdown();
+#endif
+
     if (afs_cold_shutdown)
        afs_warn("afs: COLD ");
     else
index a66976e..cfae0b0 100644 (file)
@@ -912,6 +912,10 @@ extern struct afs_stats_CMFullPerf afs_stats_cmfullperf;
 extern afs_int32 afs_stats_XferSumBytes[AFS_STATS_NUM_FS_XFER_OPS];
 extern void afs_InitStats(void);
 
+/* ARCH/osi_kstat.c */
+extern void afs_kstat_init(void);
+extern void afs_kstat_shutdown(void);
+
 /* afs_syscall.c */
 #ifdef AFS_DARWIN100_ENV
 extern int copyin_afs_ioctl(user_addr_t cmarg, struct afs_ioctl *dst);
index 03e0374..f6dc450 100644 (file)
@@ -711,6 +711,8 @@ osi_vcache.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_vcache.c
        $(CRULE_NOOPT) $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_vcache.c
 osi_crypto.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_crypto.c
        $(CRULE_OPT) $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_crypto.c
+osi_kstat.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_kstat.c
+       $(CRULE_NOOPT) $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_kstat.c
 
 clean:
        -$(RM) -rf STATIC* MODLOAD* $(AFS_OS_CLEAN)
index ca43664..1e6a2aa 100644 (file)
@@ -23,6 +23,7 @@ AFS_OS_OBJS = \
        osi_ioctl.o \
 <all>
        osi_file.o \
+       osi_kstat.o \
        osi_sleep.o \
        osi_vcache.o \
        osi_vm.o \