Blame source/vdo/kernel/statusProcfs.c

Packit Service d40955
/*
Packit Service d40955
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service d40955
 *
Packit Service d40955
 * This program is free software; you can redistribute it and/or
Packit Service d40955
 * modify it under the terms of the GNU General Public License
Packit Service d40955
 * as published by the Free Software Foundation; either version 2
Packit Service d40955
 * of the License, or (at your option) any later version.
Packit Service d40955
 * 
Packit Service d40955
 * This program is distributed in the hope that it will be useful,
Packit Service d40955
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d40955
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service d40955
 * GNU General Public License for more details.
Packit Service d40955
 * 
Packit Service d40955
 * You should have received a copy of the GNU General Public License
Packit Service d40955
 * along with this program; if not, write to the Free Software
Packit Service d40955
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service d40955
 * 02110-1301, USA. 
Packit Service d40955
 *
Packit Service d40955
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/kernel/statusProcfs.c#4 $
Packit Service d40955
 *
Packit Service d40955
 * Proc filesystem interface to the old GET_DEDUPE_STATS and
Packit Service d40955
 * GET_KERNEL_STATS ioctls, which can no longer be supported in 4.4
Packit Service d40955
 * and later kernels. These files return the same data as the old
Packit Service d40955
 * ioctls do, in order to require minimal changes to our (and
Packit Service d40955
 * customers') utilties and test code.
Packit Service d40955
 *
Packit Service d40955
 * +--+-----  /proc/vdo           procfsRoot
Packit Service d40955
 *    |
Packit Service d40955
 *    +-+-----  vdo<n>            config->poolName
Packit Service d40955
 *      |
Packit Service d40955
 *      +-------  dedupe_stats    GET_DEDUPE_STATS ioctl
Packit Service d40955
 *      +-------  kernel_stats    GET_KERNEL_STATS ioctl
Packit Service d40955
 *
Packit Service d40955
 */
Packit Service d40955
#include "statusProcfs.h"
Packit Service d40955
Packit Service d40955
#include <linux/version.h>
Packit Service d40955
Packit Service d40955
#include "memoryAlloc.h"
Packit Service d40955
Packit Service d40955
#include "releaseVersions.h"
Packit Service d40955
#include "statistics.h"
Packit Service d40955
#include "vdo.h"
Packit Service d40955
Packit Service d40955
#include "dedupeIndex.h"
Packit Service d40955
#include "ioSubmitter.h"
Packit Service d40955
#include "kernelStatistics.h"
Packit Service d40955
#include "logger.h"
Packit Service d40955
#include "memoryUsage.h"
Packit Service d40955
#include "threadDevice.h"
Packit Service d40955
#include "vdoCommon.h"
Packit Service d40955
Packit Service d40955
static struct proc_dir_entry *procfsRoot = NULL;
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static int statusDedupeShow(struct seq_file *m, void *v)
Packit Service d40955
{
Packit Service d40955
  KernelLayer *layer = (KernelLayer *) m->private;
Packit Service d40955
  VDOStatistics *stats;
Packit Service d40955
  size_t len = sizeof(VDOStatistics);
Packit Service d40955
  RegisteredThread allocatingThread, instanceThread;
Packit Service d40955
  registerAllocatingThread(&allocatingThread, NULL);
Packit Service d40955
  registerThreadDevice(&instanceThread, layer);
Packit Service d40955
  int result = ALLOCATE(1, VDOStatistics, __func__, &stats);
Packit Service d40955
  if (result == VDO_SUCCESS) {
Packit Service d40955
    getKVDOStatistics(&layer->kvdo, stats);
Packit Service d40955
    seq_write(m, stats, len);
Packit Service d40955
    FREE(stats);
Packit Service d40955
  }
Packit Service d40955
  unregisterThreadDeviceID();
Packit Service d40955
  unregisterAllocatingThread();
Packit Service d40955
  return result;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static int statusDedupeOpen(struct inode *inode, struct file *file)
Packit Service d40955
{
Packit Service d40955
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
Packit Service d40955
  return single_open(file, statusDedupeShow, PDE_DATA(inode));
Packit Service d40955
#else
Packit Service d40955
  return single_open(file, statusDedupeShow, PDE(inode)->data);
Packit Service d40955
#endif
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
static const struct file_operations vdoProcfsDedupeOps = {
Packit Service d40955
  .open = statusDedupeOpen,
Packit Service d40955
  .read = seq_read,
Packit Service d40955
  .llseek = seq_lseek,
Packit Service d40955
  .release = single_release,
Packit Service d40955
};
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static void copyBioStat(BioStats *b, const AtomicBioStats *a)
Packit Service d40955
{
Packit Service d40955
  b->read    = atomic64_read(&a->read);
Packit Service d40955
  b->write   = atomic64_read(&a->write);
Packit Service d40955
  b->discard = atomic64_read(&a->discard);
Packit Service d40955
  b->flush   = atomic64_read(&a->flush);
Packit Service d40955
  b->fua     = atomic64_read(&a->fua);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static BioStats subtractBioStats(BioStats minuend, BioStats subtrahend)
Packit Service d40955
{
Packit Service d40955
  return (BioStats) {
Packit Service d40955
    .read    = minuend.read - subtrahend.read,
Packit Service d40955
    .write   = minuend.write - subtrahend.write,
Packit Service d40955
    .discard = minuend.discard - subtrahend.discard,
Packit Service d40955
    .flush   = minuend.flush - subtrahend.flush,
Packit Service d40955
    .fua     = minuend.fua - subtrahend.fua,
Packit Service d40955
  };
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
void getKernelStats(KernelLayer *layer, KernelStatistics *stats)
Packit Service d40955
{
Packit Service d40955
  stats->version        = STATISTICS_VERSION;
Packit Service d40955
  stats->releaseVersion = CURRENT_RELEASE_VERSION_NUMBER;
Packit Service d40955
  stats->instance       = layer->instance;
Packit Service d40955
  getLimiterValuesAtomically(&layer->requestLimiter,
Packit Service d40955
                             &stats->currentVIOsInProgress, &stats->maxVIOs);
Packit Service d40955
  // albireoTimeoutReport gives the number of timeouts, and dedupeContextBusy
Packit Service d40955
  // gives the number of queries not made because of earlier timeouts.
Packit Service d40955
  stats->dedupeAdviceTimeouts = (getEventCount(&layer->albireoTimeoutReporter)
Packit Service d40955
                                 + atomic64_read(&layer->dedupeContextBusy));
Packit Service d40955
  stats->flushOut             = atomic64_read(&layer->flushOut);
Packit Service d40955
  stats->logicalBlockSize     = layer->deviceConfig->logicalBlockSize;
Packit Service d40955
  copyBioStat(&stats->biosIn, &layer->biosIn);
Packit Service d40955
  copyBioStat(&stats->biosInPartial, &layer->biosInPartial);
Packit Service d40955
  copyBioStat(&stats->biosOut, &layer->biosOut);
Packit Service d40955
  copyBioStat(&stats->biosMeta, &layer->biosMeta);
Packit Service d40955
  copyBioStat(&stats->biosJournal, &layer->biosJournal);
Packit Service d40955
  copyBioStat(&stats->biosPageCache, &layer->biosPageCache);
Packit Service d40955
  copyBioStat(&stats->biosOutCompleted, &layer->biosOutCompleted);
Packit Service d40955
  copyBioStat(&stats->biosMetaCompleted, &layer->biosMetaCompleted);
Packit Service d40955
  copyBioStat(&stats->biosJournalCompleted, &layer->biosJournalCompleted);
Packit Service d40955
  copyBioStat(&stats->biosPageCacheCompleted,
Packit Service d40955
              &layer->biosPageCacheCompleted);
Packit Service d40955
  copyBioStat(&stats->biosAcknowledged, &layer->biosAcknowledged);
Packit Service d40955
  copyBioStat(&stats->biosAcknowledgedPartial,
Packit Service d40955
              &layer->biosAcknowledgedPartial);
Packit Service d40955
  stats->biosInProgress = subtractBioStats(stats->biosIn,
Packit Service d40955
                                           stats->biosAcknowledged);
Packit Service d40955
  stats->memoryUsage = getMemoryUsage();
Packit Service d40955
  getIndexStatistics(layer->dedupeIndex, &stats->index);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static int statusKernelShow(struct seq_file *m, void *v)
Packit Service d40955
{
Packit Service d40955
  KernelLayer *layer = (KernelLayer *) m->private;
Packit Service d40955
  KernelStatistics *stats;
Packit Service d40955
  size_t len = sizeof(KernelStatistics);
Packit Service d40955
  RegisteredThread allocatingThread, instanceThread;
Packit Service d40955
  registerAllocatingThread(&allocatingThread, NULL);
Packit Service d40955
  registerThreadDevice(&instanceThread, layer);
Packit Service d40955
  int result = ALLOCATE(1, KernelStatistics, __func__, &stats);
Packit Service d40955
  if (result == VDO_SUCCESS) {
Packit Service d40955
    getKernelStats(layer, stats);
Packit Service d40955
    seq_write(m, stats, len);
Packit Service d40955
    FREE(stats);
Packit Service d40955
  }
Packit Service d40955
  unregisterThreadDeviceID();
Packit Service d40955
  unregisterAllocatingThread();
Packit Service d40955
  return result;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static int statusKernelOpen(struct inode *inode, struct file *file)
Packit Service d40955
{
Packit Service d40955
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
Packit Service d40955
  return single_open(file, statusKernelShow, PDE_DATA(inode));
Packit Service d40955
#else
Packit Service d40955
  return single_open(file, statusKernelShow, PDE(inode)->data);
Packit Service d40955
#endif
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
static const struct file_operations vdoProcfsKernelOps = {
Packit Service d40955
  .open = statusKernelOpen,
Packit Service d40955
  .read = seq_read,
Packit Service d40955
  .llseek = seq_lseek,
Packit Service d40955
  .release = single_release,
Packit Service d40955
};
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
int vdoInitProcfs()
Packit Service d40955
{
Packit Service d40955
  const char *procfsName = getProcRoot();
Packit Service d40955
  procfsRoot = proc_mkdir(procfsName, NULL);
Packit Service d40955
  if (procfsRoot == NULL) {
Packit Service d40955
    logWarning("Could not create proc filesystem root %s\n", procfsName);
Packit Service d40955
    return -ENOMEM;
Packit Service d40955
  }
Packit Service d40955
  return VDO_SUCCESS;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
void vdoDestroyProcfs()
Packit Service d40955
{
Packit Service d40955
  remove_proc_entry(getProcRoot(), NULL);
Packit Service d40955
  procfsRoot = NULL;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
int vdoCreateProcfsEntry(KernelLayer *layer, const char *name, void **private)
Packit Service d40955
{
Packit Service d40955
  int result = VDO_SUCCESS;
Packit Service d40955
Packit Service d40955
  if (procfsRoot != NULL) {
Packit Service d40955
    struct proc_dir_entry *fsDir;
Packit Service d40955
    fsDir = proc_mkdir(name, procfsRoot);
Packit Service d40955
    if (fsDir == NULL) {
Packit Service d40955
      result = -ENOMEM;
Packit Service d40955
    } else {
Packit Service d40955
      if (proc_create_data(getVDOStatisticsProcFile(), 0644, fsDir,
Packit Service d40955
                           &vdoProcfsDedupeOps, layer) == NULL) {
Packit Service d40955
        result = -ENOMEM;
Packit Service d40955
      } else if (proc_create_data(getKernelStatisticsProcFile(), 0644, fsDir,
Packit Service d40955
                                  &vdoProcfsKernelOps, layer) == NULL) {
Packit Service d40955
        result = -ENOMEM;
Packit Service d40955
      }
Packit Service d40955
    }
Packit Service d40955
    if (result < 0) {
Packit Service d40955
      vdoDestroyProcfsEntry(name, fsDir);
Packit Service d40955
    } else {
Packit Service d40955
      *private = fsDir;
Packit Service d40955
    }
Packit Service d40955
  } else {
Packit Service d40955
    logWarning("No proc filesystem root set, skipping %s\n", name);
Packit Service d40955
  }
Packit Service d40955
  return result;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
void vdoDestroyProcfsEntry(const char *name, void *private)
Packit Service d40955
{
Packit Service d40955
  if (procfsRoot != NULL) {
Packit Service d40955
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
Packit Service d40955
    remove_proc_subtree(name, procfsRoot);
Packit Service d40955
#else
Packit Service d40955
    struct proc_dir_entry *fsDir = (struct proc_dir_entry *) private;
Packit Service d40955
    remove_proc_entry(getVDOStatisticsProcFile(), fsDir);
Packit Service d40955
    remove_proc_entry(getKernelStatisticsProcFile(), fsDir);
Packit Service d40955
    remove_proc_entry(name, procfsRoot);
Packit Service d40955
#endif
Packit Service d40955
  }
Packit Service d40955
}