Blame source/vdo/kernel/statusProcfs.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/statusProcfs.c#4 $
Packit Service 75d76b
 *
Packit Service 75d76b
 * Proc filesystem interface to the old GET_DEDUPE_STATS and
Packit Service 75d76b
 * GET_KERNEL_STATS ioctls, which can no longer be supported in 4.4
Packit Service 75d76b
 * and later kernels. These files return the same data as the old
Packit Service 75d76b
 * ioctls do, in order to require minimal changes to our (and
Packit Service 75d76b
 * customers') utilties and test code.
Packit Service 75d76b
 *
Packit Service 75d76b
 * +--+-----  /proc/vdo           procfsRoot
Packit Service 75d76b
 *    |
Packit Service 75d76b
 *    +-+-----  vdo<n>            config->poolName
Packit Service 75d76b
 *      |
Packit Service 75d76b
 *      +-------  dedupe_stats    GET_DEDUPE_STATS ioctl
Packit Service 75d76b
 *      +-------  kernel_stats    GET_KERNEL_STATS ioctl
Packit Service 75d76b
 *
Packit Service 75d76b
 */
Packit Service 75d76b
#include "statusProcfs.h"
Packit Service 75d76b
Packit Service 75d76b
#include <linux/version.h>
Packit Service 75d76b
Packit Service 75d76b
#include "memoryAlloc.h"
Packit Service 75d76b
Packit Service 75d76b
#include "releaseVersions.h"
Packit Service 75d76b
#include "statistics.h"
Packit Service 75d76b
#include "vdo.h"
Packit Service 75d76b
Packit Service 75d76b
#include "dedupeIndex.h"
Packit Service 75d76b
#include "ioSubmitter.h"
Packit Service 75d76b
#include "kernelStatistics.h"
Packit Service 75d76b
#include "logger.h"
Packit Service 75d76b
#include "memoryUsage.h"
Packit Service 75d76b
#include "threadDevice.h"
Packit Service 75d76b
#include "vdoCommon.h"
Packit Service 75d76b
Packit Service 75d76b
static struct proc_dir_entry *procfsRoot = NULL;
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
static int statusDedupeShow(struct seq_file *m, void *v)
Packit Service 75d76b
{
Packit Service 75d76b
  KernelLayer *layer = (KernelLayer *) m->private;
Packit Service 75d76b
  VDOStatistics *stats;
Packit Service 75d76b
  size_t len = sizeof(VDOStatistics);
Packit Service 75d76b
  RegisteredThread allocatingThread, instanceThread;
Packit Service 75d76b
  registerAllocatingThread(&allocatingThread, NULL);
Packit Service 75d76b
  registerThreadDevice(&instanceThread, layer);
Packit Service 75d76b
  int result = ALLOCATE(1, VDOStatistics, __func__, &stats);
Packit Service 75d76b
  if (result == VDO_SUCCESS) {
Packit Service 75d76b
    getKVDOStatistics(&layer->kvdo, stats);
Packit Service 75d76b
    seq_write(m, stats, len);
Packit Service 75d76b
    FREE(stats);
Packit Service 75d76b
  }
Packit Service 75d76b
  unregisterThreadDeviceID();
Packit Service 75d76b
  unregisterAllocatingThread();
Packit Service 75d76b
  return result;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
static int statusDedupeOpen(struct inode *inode, struct file *file)
Packit Service 75d76b
{
Packit Service 75d76b
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
Packit Service 75d76b
  return single_open(file, statusDedupeShow, PDE_DATA(inode));
Packit Service 75d76b
#else
Packit Service 75d76b
  return single_open(file, statusDedupeShow, PDE(inode)->data);
Packit Service 75d76b
#endif
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
static const struct file_operations vdoProcfsDedupeOps = {
Packit Service 75d76b
  .open = statusDedupeOpen,
Packit Service 75d76b
  .read = seq_read,
Packit Service 75d76b
  .llseek = seq_lseek,
Packit Service 75d76b
  .release = single_release,
Packit Service 75d76b
};
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
static void copyBioStat(BioStats *b, const AtomicBioStats *a)
Packit Service 75d76b
{
Packit Service 75d76b
  b->read    = atomic64_read(&a->read);
Packit Service 75d76b
  b->write   = atomic64_read(&a->write);
Packit Service 75d76b
  b->discard = atomic64_read(&a->discard);
Packit Service 75d76b
  b->flush   = atomic64_read(&a->flush);
Packit Service 75d76b
  b->fua     = atomic64_read(&a->fua);
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
static BioStats subtractBioStats(BioStats minuend, BioStats subtrahend)
Packit Service 75d76b
{
Packit Service 75d76b
  return (BioStats) {
Packit Service 75d76b
    .read    = minuend.read - subtrahend.read,
Packit Service 75d76b
    .write   = minuend.write - subtrahend.write,
Packit Service 75d76b
    .discard = minuend.discard - subtrahend.discard,
Packit Service 75d76b
    .flush   = minuend.flush - subtrahend.flush,
Packit Service 75d76b
    .fua     = minuend.fua - subtrahend.fua,
Packit Service 75d76b
  };
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
void getKernelStats(KernelLayer *layer, KernelStatistics *stats)
Packit Service 75d76b
{
Packit Service 75d76b
  stats->version        = STATISTICS_VERSION;
Packit Service 75d76b
  stats->releaseVersion = CURRENT_RELEASE_VERSION_NUMBER;
Packit Service 75d76b
  stats->instance       = layer->instance;
Packit Service 75d76b
  getLimiterValuesAtomically(&layer->requestLimiter,
Packit Service 75d76b
                             &stats->currentVIOsInProgress, &stats->maxVIOs);
Packit Service 75d76b
  // albireoTimeoutReport gives the number of timeouts, and dedupeContextBusy
Packit Service 75d76b
  // gives the number of queries not made because of earlier timeouts.
Packit Service 75d76b
  stats->dedupeAdviceTimeouts = (getEventCount(&layer->albireoTimeoutReporter)
Packit Service 75d76b
                                 + atomic64_read(&layer->dedupeContextBusy));
Packit Service 75d76b
  stats->flushOut             = atomic64_read(&layer->flushOut);
Packit Service 75d76b
  stats->logicalBlockSize     = layer->deviceConfig->logicalBlockSize;
Packit Service 75d76b
  copyBioStat(&stats->biosIn, &layer->biosIn);
Packit Service 75d76b
  copyBioStat(&stats->biosInPartial, &layer->biosInPartial);
Packit Service 75d76b
  copyBioStat(&stats->biosOut, &layer->biosOut);
Packit Service 75d76b
  copyBioStat(&stats->biosMeta, &layer->biosMeta);
Packit Service 75d76b
  copyBioStat(&stats->biosJournal, &layer->biosJournal);
Packit Service 75d76b
  copyBioStat(&stats->biosPageCache, &layer->biosPageCache);
Packit Service 75d76b
  copyBioStat(&stats->biosOutCompleted, &layer->biosOutCompleted);
Packit Service 75d76b
  copyBioStat(&stats->biosMetaCompleted, &layer->biosMetaCompleted);
Packit Service 75d76b
  copyBioStat(&stats->biosJournalCompleted, &layer->biosJournalCompleted);
Packit Service 75d76b
  copyBioStat(&stats->biosPageCacheCompleted,
Packit Service 75d76b
              &layer->biosPageCacheCompleted);
Packit Service 75d76b
  copyBioStat(&stats->biosAcknowledged, &layer->biosAcknowledged);
Packit Service 75d76b
  copyBioStat(&stats->biosAcknowledgedPartial,
Packit Service 75d76b
              &layer->biosAcknowledgedPartial);
Packit Service 75d76b
  stats->biosInProgress = subtractBioStats(stats->biosIn,
Packit Service 75d76b
                                           stats->biosAcknowledged);
Packit Service 75d76b
  stats->memoryUsage = getMemoryUsage();
Packit Service 75d76b
  getIndexStatistics(layer->dedupeIndex, &stats->index);
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
static int statusKernelShow(struct seq_file *m, void *v)
Packit Service 75d76b
{
Packit Service 75d76b
  KernelLayer *layer = (KernelLayer *) m->private;
Packit Service 75d76b
  KernelStatistics *stats;
Packit Service 75d76b
  size_t len = sizeof(KernelStatistics);
Packit Service 75d76b
  RegisteredThread allocatingThread, instanceThread;
Packit Service 75d76b
  registerAllocatingThread(&allocatingThread, NULL);
Packit Service 75d76b
  registerThreadDevice(&instanceThread, layer);
Packit Service 75d76b
  int result = ALLOCATE(1, KernelStatistics, __func__, &stats);
Packit Service 75d76b
  if (result == VDO_SUCCESS) {
Packit Service 75d76b
    getKernelStats(layer, stats);
Packit Service 75d76b
    seq_write(m, stats, len);
Packit Service 75d76b
    FREE(stats);
Packit Service 75d76b
  }
Packit Service 75d76b
  unregisterThreadDeviceID();
Packit Service 75d76b
  unregisterAllocatingThread();
Packit Service 75d76b
  return result;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
static int statusKernelOpen(struct inode *inode, struct file *file)
Packit Service 75d76b
{
Packit Service 75d76b
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
Packit Service 75d76b
  return single_open(file, statusKernelShow, PDE_DATA(inode));
Packit Service 75d76b
#else
Packit Service 75d76b
  return single_open(file, statusKernelShow, PDE(inode)->data);
Packit Service 75d76b
#endif
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
static const struct file_operations vdoProcfsKernelOps = {
Packit Service 75d76b
  .open = statusKernelOpen,
Packit Service 75d76b
  .read = seq_read,
Packit Service 75d76b
  .llseek = seq_lseek,
Packit Service 75d76b
  .release = single_release,
Packit Service 75d76b
};
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
int vdoInitProcfs()
Packit Service 75d76b
{
Packit Service 75d76b
  const char *procfsName = getProcRoot();
Packit Service 75d76b
  procfsRoot = proc_mkdir(procfsName, NULL);
Packit Service 75d76b
  if (procfsRoot == NULL) {
Packit Service 75d76b
    logWarning("Could not create proc filesystem root %s\n", procfsName);
Packit Service 75d76b
    return -ENOMEM;
Packit Service 75d76b
  }
Packit Service 75d76b
  return VDO_SUCCESS;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
void vdoDestroyProcfs()
Packit Service 75d76b
{
Packit Service 75d76b
  remove_proc_entry(getProcRoot(), NULL);
Packit Service 75d76b
  procfsRoot = NULL;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
int vdoCreateProcfsEntry(KernelLayer *layer, const char *name, void **private)
Packit Service 75d76b
{
Packit Service 75d76b
  int result = VDO_SUCCESS;
Packit Service 75d76b
Packit Service 75d76b
  if (procfsRoot != NULL) {
Packit Service 75d76b
    struct proc_dir_entry *fsDir;
Packit Service 75d76b
    fsDir = proc_mkdir(name, procfsRoot);
Packit Service 75d76b
    if (fsDir == NULL) {
Packit Service 75d76b
      result = -ENOMEM;
Packit Service 75d76b
    } else {
Packit Service 75d76b
      if (proc_create_data(getVDOStatisticsProcFile(), 0644, fsDir,
Packit Service 75d76b
                           &vdoProcfsDedupeOps, layer) == NULL) {
Packit Service 75d76b
        result = -ENOMEM;
Packit Service 75d76b
      } else if (proc_create_data(getKernelStatisticsProcFile(), 0644, fsDir,
Packit Service 75d76b
                                  &vdoProcfsKernelOps, layer) == NULL) {
Packit Service 75d76b
        result = -ENOMEM;
Packit Service 75d76b
      }
Packit Service 75d76b
    }
Packit Service 75d76b
    if (result < 0) {
Packit Service 75d76b
      vdoDestroyProcfsEntry(name, fsDir);
Packit Service 75d76b
    } else {
Packit Service 75d76b
      *private = fsDir;
Packit Service 75d76b
    }
Packit Service 75d76b
  } else {
Packit Service 75d76b
    logWarning("No proc filesystem root set, skipping %s\n", name);
Packit Service 75d76b
  }
Packit Service 75d76b
  return result;
Packit Service 75d76b
}
Packit Service 75d76b
Packit Service 75d76b
/**********************************************************************/
Packit Service 75d76b
void vdoDestroyProcfsEntry(const char *name, void *private)
Packit Service 75d76b
{
Packit Service 75d76b
  if (procfsRoot != NULL) {
Packit Service 75d76b
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
Packit Service 75d76b
    remove_proc_subtree(name, procfsRoot);
Packit Service 75d76b
#else
Packit Service 75d76b
    struct proc_dir_entry *fsDir = (struct proc_dir_entry *) private;
Packit Service 75d76b
    remove_proc_entry(getVDOStatisticsProcFile(), fsDir);
Packit Service 75d76b
    remove_proc_entry(getKernelStatisticsProcFile(), fsDir);
Packit Service 75d76b
    remove_proc_entry(name, procfsRoot);
Packit Service 75d76b
#endif
Packit Service 75d76b
  }
Packit Service 75d76b
}