linux/drivers/oprofile/oprofilefs.c
<<
>>
Prefs
   1/**
   2 * @file oprofilefs.c
   3 *
   4 * @remark Copyright 2002 OProfile authors
   5 * @remark Read the file COPYING
   6 *
   7 * @author John Levon
   8 *
   9 * A simple filesystem for configuration and
  10 * access of oprofile.
  11 */
  12
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include <linux/oprofile.h>
  16#include <linux/fs.h>
  17#include <linux/pagemap.h>
  18#include <asm/uaccess.h>
  19
  20#include "oprof.h"
  21
  22#define OPROFILEFS_MAGIC 0x6f70726f
  23
  24DEFINE_SPINLOCK(oprofilefs_lock);
  25
  26static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
  27{
  28        struct inode * inode = new_inode(sb);
  29
  30        if (inode) {
  31                inode->i_mode = mode;
  32                inode->i_uid = 0;
  33                inode->i_gid = 0;
  34                inode->i_blocks = 0;
  35                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  36        }
  37        return inode;
  38}
  39
  40
  41static struct super_operations s_ops = {
  42        .statfs         = simple_statfs,
  43        .drop_inode     = generic_delete_inode,
  44};
  45
  46
  47ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset)
  48{
  49        return simple_read_from_buffer(buf, count, offset, str, strlen(str));
  50}
  51
  52
  53#define TMPBUFSIZE 50
  54
  55ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset)
  56{
  57        char tmpbuf[TMPBUFSIZE];
  58        size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
  59        if (maxlen > TMPBUFSIZE)
  60                maxlen = TMPBUFSIZE;
  61        return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
  62}
  63
  64
  65int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count)
  66{
  67        char tmpbuf[TMPBUFSIZE];
  68        unsigned long flags;
  69
  70        if (!count)
  71                return 0;
  72
  73        if (count > TMPBUFSIZE - 1)
  74                return -EINVAL;
  75
  76        memset(tmpbuf, 0x0, TMPBUFSIZE);
  77
  78        if (copy_from_user(tmpbuf, buf, count))
  79                return -EFAULT;
  80
  81        spin_lock_irqsave(&oprofilefs_lock, flags);
  82        *val = simple_strtoul(tmpbuf, NULL, 0);
  83        spin_unlock_irqrestore(&oprofilefs_lock, flags);
  84        return 0;
  85}
  86
  87
  88static ssize_t ulong_read_file(struct file * file, char __user * buf, size_t count, loff_t * offset)
  89{
  90        unsigned long * val = file->private_data;
  91        return oprofilefs_ulong_to_user(*val, buf, count, offset);
  92}
  93
  94
  95static ssize_t ulong_write_file(struct file * file, char const __user * buf, size_t count, loff_t * offset)
  96{
  97        unsigned long * value = file->private_data;
  98        int retval;
  99
 100        if (*offset)
 101                return -EINVAL;
 102
 103        retval = oprofilefs_ulong_from_user(value, buf, count);
 104
 105        if (retval)
 106                return retval;
 107        return count;
 108}
 109
 110
 111static int default_open(struct inode * inode, struct file * filp)
 112{
 113        if (inode->i_private)
 114                filp->private_data = inode->i_private;
 115        return 0;
 116}
 117
 118
 119static const struct file_operations ulong_fops = {
 120        .read           = ulong_read_file,
 121        .write          = ulong_write_file,
 122        .open           = default_open,
 123};
 124
 125
 126static const struct file_operations ulong_ro_fops = {
 127        .read           = ulong_read_file,
 128        .open           = default_open,
 129};
 130
 131
 132static struct dentry * __oprofilefs_create_file(struct super_block * sb,
 133        struct dentry * root, char const * name, const struct file_operations * fops,
 134        int perm)
 135{
 136        struct dentry * dentry;
 137        struct inode * inode;
 138
 139        dentry = d_alloc_name(root, name);
 140        if (!dentry)
 141                return NULL;
 142        inode = oprofilefs_get_inode(sb, S_IFREG | perm);
 143        if (!inode) {
 144                dput(dentry);
 145                return NULL;
 146        }
 147        inode->i_fop = fops;
 148        d_add(dentry, inode);
 149        return dentry;
 150}
 151
 152
 153int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
 154        char const * name, unsigned long * val)
 155{
 156        struct dentry * d = __oprofilefs_create_file(sb, root, name,
 157                                                     &ulong_fops, 0644);
 158        if (!d)
 159                return -EFAULT;
 160
 161        d->d_inode->i_private = val;
 162        return 0;
 163}
 164
 165
 166int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
 167        char const * name, unsigned long * val)
 168{
 169        struct dentry * d = __oprofilefs_create_file(sb, root, name,
 170                                                     &ulong_ro_fops, 0444);
 171        if (!d)
 172                return -EFAULT;
 173
 174        d->d_inode->i_private = val;
 175        return 0;
 176}
 177
 178
 179static ssize_t atomic_read_file(struct file * file, char __user * buf, size_t count, loff_t * offset)
 180{
 181        atomic_t * val = file->private_data;
 182        return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset);
 183}
 184 
 185
 186static const struct file_operations atomic_ro_fops = {
 187        .read           = atomic_read_file,
 188        .open           = default_open,
 189};
 190 
 191
 192int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
 193        char const * name, atomic_t * val)
 194{
 195        struct dentry * d = __oprofilefs_create_file(sb, root, name,
 196                                                     &atomic_ro_fops, 0444);
 197        if (!d)
 198                return -EFAULT;
 199
 200        d->d_inode->i_private = val;
 201        return 0;
 202}
 203
 204 
 205int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
 206        char const * name, const struct file_operations * fops)
 207{
 208        if (!__oprofilefs_create_file(sb, root, name, fops, 0644))
 209                return -EFAULT;
 210        return 0;
 211}
 212
 213
 214int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root,
 215        char const * name, const struct file_operations * fops, int perm)
 216{
 217        if (!__oprofilefs_create_file(sb, root, name, fops, perm))
 218                return -EFAULT;
 219        return 0;
 220}
 221
 222
 223struct dentry * oprofilefs_mkdir(struct super_block * sb,
 224        struct dentry * root, char const * name)
 225{
 226        struct dentry * dentry;
 227        struct inode * inode;
 228
 229        dentry = d_alloc_name(root, name);
 230        if (!dentry)
 231                return NULL;
 232        inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
 233        if (!inode) {
 234                dput(dentry);
 235                return NULL;
 236        }
 237        inode->i_op = &simple_dir_inode_operations;
 238        inode->i_fop = &simple_dir_operations;
 239        d_add(dentry, inode);
 240        return dentry;
 241}
 242
 243
 244static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent)
 245{
 246        struct inode * root_inode;
 247        struct dentry * root_dentry;
 248
 249        sb->s_blocksize = PAGE_CACHE_SIZE;
 250        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 251        sb->s_magic = OPROFILEFS_MAGIC;
 252        sb->s_op = &s_ops;
 253        sb->s_time_gran = 1;
 254
 255        root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
 256        if (!root_inode)
 257                return -ENOMEM;
 258        root_inode->i_op = &simple_dir_inode_operations;
 259        root_inode->i_fop = &simple_dir_operations;
 260        root_dentry = d_alloc_root(root_inode);
 261        if (!root_dentry) {
 262                iput(root_inode);
 263                return -ENOMEM;
 264        }
 265
 266        sb->s_root = root_dentry;
 267
 268        oprofile_create_files(sb, root_dentry);
 269
 270        // FIXME: verify kill_litter_super removes our dentries
 271        return 0;
 272}
 273
 274
 275static int oprofilefs_get_sb(struct file_system_type *fs_type,
 276        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 277{
 278        return get_sb_single(fs_type, flags, data, oprofilefs_fill_super, mnt);
 279}
 280
 281
 282static struct file_system_type oprofilefs_type = {
 283        .owner          = THIS_MODULE,
 284        .name           = "oprofilefs",
 285        .get_sb         = oprofilefs_get_sb,
 286        .kill_sb        = kill_litter_super,
 287};
 288
 289
 290int __init oprofilefs_register(void)
 291{
 292        return register_filesystem(&oprofilefs_type);
 293}
 294
 295
 296void __exit oprofilefs_unregister(void)
 297{
 298        unregister_filesystem(&oprofilefs_type);
 299}
 300