1/* CacheFiles statistics 2 * 3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12#include <linux/module.h> 13#include <linux/proc_fs.h> 14#include <linux/seq_file.h> 15#include "internal.h" 16 17atomic_t cachefiles_lookup_histogram[HZ]; 18atomic_t cachefiles_mkdir_histogram[HZ]; 19atomic_t cachefiles_create_histogram[HZ]; 20 21/* 22 * display the latency histogram 23 */ 24static int cachefiles_histogram_show(struct seq_file *m, void *v) 25{ 26 unsigned long index; 27 unsigned x, y, z, t; 28 29 switch ((unsigned long) v) { 30 case 1: 31 seq_puts(m, "JIFS SECS LOOKUPS MKDIRS CREATES\n"); 32 return 0; 33 case 2: 34 seq_puts(m, "===== ===== ========= ========= =========\n"); 35 return 0; 36 default: 37 index = (unsigned long) v - 3; 38 x = atomic_read(&cachefiles_lookup_histogram[index]); 39 y = atomic_read(&cachefiles_mkdir_histogram[index]); 40 z = atomic_read(&cachefiles_create_histogram[index]); 41 if (x == 0 && y == 0 && z == 0) 42 return 0; 43 44 t = (index * 1000) / HZ; 45 46 seq_printf(m, "%4lu 0.%03u %9u %9u %9u\n", index, t, x, y, z); 47 return 0; 48 } 49} 50 51/* 52 * set up the iterator to start reading from the first line 53 */ 54static void *cachefiles_histogram_start(struct seq_file *m, loff_t *_pos) 55{ 56 if ((unsigned long long)*_pos >= HZ + 2) 57 return NULL; 58 if (*_pos == 0) 59 *_pos = 1; 60 return (void *)(unsigned long) *_pos; 61} 62 63/* 64 * move to the next line 65 */ 66static void *cachefiles_histogram_next(struct seq_file *m, void *v, loff_t *pos) 67{ 68 (*pos)++; 69 return (unsigned long long)*pos > HZ + 2 ? 70 NULL : (void *)(unsigned long) *pos; 71} 72 73/* 74 * clean up after reading 75 */ 76static void cachefiles_histogram_stop(struct seq_file *m, void *v) 77{ 78} 79 80static const struct seq_operations cachefiles_histogram_ops = { 81 .start = cachefiles_histogram_start, 82 .stop = cachefiles_histogram_stop, 83 .next = cachefiles_histogram_next, 84 .show = cachefiles_histogram_show, 85}; 86 87static int cachefiles_histogram_open(struct inode *inode, struct file *file) 88{ 89 return seq_open(file, &cachefiles_histogram_ops); 90} 91 92static const struct file_operations cachefiles_histogram_fops = { 93 .owner = THIS_MODULE, 94 .open = cachefiles_histogram_open, 95 .read = seq_read, 96 .llseek = seq_lseek, 97 .release = seq_release, 98}; 99 100/* 101 * initialise the /proc/fs/cachefiles/ directory 102 */ 103int __init cachefiles_proc_init(void) 104{ 105 _enter(""); 106 107 if (!proc_mkdir("fs/cachefiles", NULL)) 108 goto error_dir; 109 110 if (!proc_create("fs/cachefiles/histogram", S_IFREG | 0444, NULL, 111 &cachefiles_histogram_fops)) 112 goto error_histogram; 113 114 _leave(" = 0"); 115 return 0; 116 117error_histogram: 118 remove_proc_entry("fs/cachefiles", NULL); 119error_dir: 120 _leave(" = -ENOMEM"); 121 return -ENOMEM; 122} 123 124/* 125 * clean up the /proc/fs/cachefiles/ directory 126 */ 127void cachefiles_proc_cleanup(void) 128{ 129 remove_proc_entry("fs/cachefiles/histogram", NULL); 130 remove_proc_entry("fs/cachefiles", NULL); 131} 132