Blame source/vdo/kernel/ktrace.c

Packit Service 75d76b
/*
Packit Service 75d76b
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service 75d76b
 *
Packit Service 75d76b
 * This program is free software; you can redistribute it and/or
Packit Service 75d76b
 * modify it under the terms of the GNU General Public License
Packit Service 75d76b
 * as published by the Free Software Foundation; either version 2
Packit Service 75d76b
 * of the License, or (at your option) any later version.
Packit Service 75d76b
 * 
Packit Service 75d76b
 * This program is distributed in the hope that it will be useful,
Packit Service 75d76b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 75d76b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 75d76b
 * GNU General Public License for more details.
Packit Service 75d76b
 * 
Packit Service 75d76b
 * You should have received a copy of the GNU General Public License
Packit Service 75d76b
 * along with this program; if not, write to the Free Software
Packit Service 75d76b
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 75d76b
 * 02110-1301, USA. 
Packit Service 75d76b
 *
Packit Service 75d76b
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/ktrace.c#2 $
Packit Service 75d76b
 */
Packit Service 75d76b
Packit Service 75d76b
#include "ktrace.h"
Packit Service 75d76b
Packit Service 75d76b
#include "memoryAlloc.h"
Packit Service 75d76b
Packit Service 75d76b
#include "dataVIO.h"
Packit Service 75d76b
Packit Service 75d76b
#include "kvio.h"
Packit Service 75d76b
#include "logger.h"
Packit Service 75d76b
Packit Service 75d76b
enum {
Packit Service 75d76b
  // How much data from a trace can we log in one call without messing
Packit Service 75d76b
  // up the log or losing data?
Packit Service 75d76b
  TRACE_LOG_MAX         = 820,
Packit Service 75d76b
Packit Service 75d76b
  // What fraction (1 out of TRACE_SAMPLE_INTERVAL VIOs) to trace
Packit Service 75d76b
  TRACE_SAMPLE_INTERVAL = 3,
Packit Service 75d76b
};
Packit Service 75d76b
Packit Service 75d76b
bool traceRecording = false;
Packit Service 75d76b
Packit Service 75d76b
static struct {
Packit Service 75d76b
  char         buffer[2000];
Packit Service 75d76b
  unsigned int counter;
Packit Service 75d76b
  struct mutex lock;
Packit Service 75d76b
} traceLoggingState;
Packit Service 75d76b
Packit Service 75d76b
/**
Packit Service 75d76b
 * Initialize a SampleCounter structure with the given sampling interval.
Packit Service 75d76b
 *
Packit Service 75d76b
 * @param counter    The counter to initialize
Packit Service 75d76b
 * @param interval   The desired sampling interval
Packit Service 75d76b
 **/
Packit Service 75d76b
static void initializeSampleCounter(SampleCounter *counter,
Packit Service 75d76b
                                    unsigned int   interval)
Packit Service 75d76b
{
Packit Service 75d76b
  spin_lock_init(&counter->lock);
Packit Service 75d76b
  counter->tick = 0;
Packit Service 75d76b
  counter->interval = interval;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
bool sampleThisOne(SampleCounter *counter)
Packit Service 75d76b
{
Packit Service 75d76b
  bool wantTracing = false;
Packit Service 75d76b
  spin_lock(&counter->lock);
Packit Service 75d76b
  counter->tick++;
Packit Service 75d76b
  if (counter->tick >= counter->interval) {
Packit Service 75d76b
    counter->tick = 0;
Packit Service 75d76b
    wantTracing = true;
Packit Service 75d76b
  }
Packit Service 75d76b
  spin_unlock(&counter->lock);
Packit Service 75d76b
  return wantTracing;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
static void freeTraceDataBuffer(void *poolData, void *data)
Packit Service 75d76b
{
Packit Service 75d76b
  Trace *trace = (Trace *) data;
Packit Service 75d76b
  FREE(trace);
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
static int allocTraceDataBuffer(void *poolData, void **dataPtr)
Packit Service 75d76b
{
Packit Service 75d76b
  Trace *trace;
Packit Service 75d76b
  int result = ALLOCATE(1, Trace, __func__, &trace);
Packit Service 75d76b
  if (result != VDO_SUCCESS) {
Packit Service 75d76b
    logError("trace data allocation failure %d", result);
Packit Service 75d76b
    return result;
Packit Service 75d76b
  }
Packit Service 75d76b
Packit Service 75d76b
  *dataPtr = trace;
Packit Service 75d76b
  return VDO_SUCCESS;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
int allocTraceFromPool(KernelLayer *layer, Trace **tracePointer)
Packit Service 75d76b
{
Packit Service 75d76b
  int result = allocBufferFromPool(layer->traceBufferPool,
Packit Service 75d76b
                                   (void **) tracePointer);
Packit Service 75d76b
  if (result == VDO_SUCCESS) {
Packit Service 75d76b
    (*tracePointer)->used = 0;
Packit Service 75d76b
  }
Packit Service 75d76b
  return result;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
void freeTraceToPool(KernelLayer *layer, Trace *trace)
Packit Service 75d76b
{
Packit Service 75d76b
  freeBufferToPool(layer->traceBufferPool, trace);
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
int traceKernelLayerInit(KernelLayer *layer)
Packit Service 75d76b
{
Packit Service 75d76b
  layer->vioTraceRecording = traceRecording;
Packit Service 75d76b
  initializeSampleCounter(&layer->traceSampleCounter, TRACE_SAMPLE_INTERVAL);
Packit Service 75d76b
  unsigned int traceRecordsNeeded = 0;
Packit Service 75d76b
  if (layer->vioTraceRecording) {
Packit Service 75d76b
    traceRecordsNeeded += layer->requestLimiter.limit;
Packit Service 75d76b
  }
Packit Service 75d76b
  if (traceRecordsNeeded > 0) {
Packit Service 75d76b
    return makeBufferPool("KVDO Trace Data Pool", traceRecordsNeeded,
Packit Service 75d76b
                          allocTraceDataBuffer, freeTraceDataBuffer, NULL,
Packit Service 75d76b
                          layer, &layer->traceBufferPool);
Packit Service 75d76b
  }
Packit Service 75d76b
  return VDO_SUCCESS;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
void initializeTraceLoggingOnce(void)
Packit Service 75d76b
{
Packit Service 75d76b
  mutex_init(&traceLoggingState.lock);
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/*************************************************************************/
Packit Service 75d76b
void logKvioTrace(KVIO *kvio)
Packit Service 75d76b
{
Packit Service 75d76b
  KernelLayer *layer = kvio->layer;
Packit Service 75d76b
Packit Service 75d76b
  mutex_lock(&traceLoggingState.lock);
Packit Service 75d76b
  traceLoggingState.counter++;
Packit Service 75d76b
  // Log about 0.1% to avoid spewing data faster than syslog can keep up
Packit Service 75d76b
  // (on certain of Permabit's test machines).
Packit Service 75d76b
  // Yes, the 37 is arbitrary and meaningless.
Packit Service 75d76b
Packit Service 75d76b
  if (layer->traceLogging && ((traceLoggingState.counter % 1024) == 37)) {
Packit Service 75d76b
    kvioAddTraceRecord(kvio, THIS_LOCATION(NULL));
Packit Service 75d76b
    size_t traceLen = 0;
Packit Service 75d76b
    formatTrace(kvio->vio->trace, traceLoggingState.buffer,
Packit Service 75d76b
                sizeof(traceLoggingState.buffer), &traceLen);
Packit Service 75d76b
Packit Service 75d76b
    if (isMetadata(kvio)) {
Packit Service 75d76b
      logInfo("finishing kvio %s meta @%" PRIptr " %s",
Packit Service 75d76b
              (isWriteVIO(kvio->vio) ? "read" : "write"),
Packit Service 75d76b
              kvio, traceLoggingState.buffer);
Packit Service 75d76b
    } else if (isCompressedWriter(kvio)) {
Packit Service 75d76b
      logInfo("finishing kvio write comp @%" PRIptr " %s",
Packit Service 75d76b
              kvio, traceLoggingState.buffer);
Packit Service 75d76b
    } else {
Packit Service 75d76b
      const char *dupeLabel = "";
Packit Service 75d76b
      if (isWriteVIO(kvio->vio)) {
Packit Service 75d76b
        DataVIO *dataVIO = vioAsDataVIO(kvio->vio);
Packit Service 75d76b
        if (isTrimDataVIO(dataVIO)) {
Packit Service 75d76b
          dupeLabel = "trim ";
Packit Service 75d76b
        } else if (dataVIO->isZeroBlock) {
Packit Service 75d76b
          dupeLabel = "zero ";
Packit Service 75d76b
        } else if (dataVIO->isDuplicate) {
Packit Service 75d76b
          dupeLabel = "dupe ";
Packit Service 75d76b
        } else {
Packit Service 75d76b
          dupeLabel = "new ";
Packit Service 75d76b
        }
Packit Service 75d76b
      }
Packit Service 75d76b
Packit Service 75d76b
      logInfo("finishing kvio %s data %s@%" PRIptr " %.*s",
Packit Service 75d76b
              (isWriteVIO(kvio->vio) ? "read" : "write"),
Packit Service 75d76b
              dupeLabel, kvio, TRACE_LOG_MAX, traceLoggingState.buffer);
Packit Service 75d76b
      char *buf = traceLoggingState.buffer;
Packit Service 75d76b
      while (traceLen > TRACE_LOG_MAX) {
Packit Service 75d76b
        traceLen -= TRACE_LOG_MAX;
Packit Service 75d76b
        buf += TRACE_LOG_MAX;
Packit Service 75d76b
        logInfo("more kvio %" PRIptr " path: %.*s", kvio, TRACE_LOG_MAX, buf);
Packit Service 75d76b
      }
Packit Service 75d76b
    }
Packit Service 75d76b
  }
Packit Service 75d76b
Packit Service 75d76b
  mutex_unlock(&traceLoggingState.lock);
Packit Service 75d76b
}