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 87/* 88 * open "/proc/fs/cachefiles/XXX" which provide statistics summaries 89 */ 90static int cachefiles_histogram_open(struct inode *inode, struct file *file) 91{ 92 return seq_open(file, &cachefiles_histogram_ops); 93} 94 95static const struct file_operations cachefiles_histogram_fops = { 96 .owner = THIS_MODULE, 97 .open = cachefiles_histogram_open, 98 .read = seq_read, 99 .llseek = seq_lseek, 100 .release = seq_release, 101}; 102 103/* 104 * initialise the /proc/fs/cachefiles/ directory 105 */ 106int __init cachefiles_proc_init(void) 107{ 108 _enter(""); 109 110 if (!proc_mkdir("fs/cachefiles", NULL)) 111 goto error_dir; 112 113 if (!proc_create("fs/cachefiles/histogram", S_IFREG | 0444, NULL, 114 &cachefiles_histogram_fops)) 115 goto error_histogram; 116 117 _leave(" = 0"); 118 return 0; 119 120error_histogram: 121 remove_proc_entry("fs/cachefiles", NULL); 122error_dir: 123 _leave(" = -ENOMEM"); 124 return -ENOMEM; 125} 126 127/* 128 * clean up the /proc/fs/cachefiles/ directory 129 */ 130void cachefiles_proc_cleanup(void) 131{ 132 remove_proc_entry("fs/cachefiles/histogram", NULL); 133 remove_proc_entry("fs/cachefiles", NULL); 134} 135