root/drivers/oprofile/oprofilefs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. oprofilefs_get_inode
  2. oprofilefs_str_to_user
  3. oprofilefs_ulong_to_user
  4. oprofilefs_ulong_from_user
  5. ulong_read_file
  6. ulong_write_file
  7. __oprofilefs_create_file
  8. oprofilefs_create_ulong
  9. oprofilefs_create_ro_ulong
  10. atomic_read_file
  11. oprofilefs_create_ro_atomic
  12. oprofilefs_create_file
  13. oprofilefs_create_file_perm
  14. oprofilefs_mkdir
  15. oprofilefs_fill_super
  16. oprofilefs_get_tree
  17. oprofilefs_init_fs_context
  18. oprofilefs_register
  19. oprofilefs_unregister

   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/fs_context.h>
  18 #include <linux/pagemap.h>
  19 #include <linux/uaccess.h>
  20 
  21 #include "oprof.h"
  22 
  23 #define OPROFILEFS_MAGIC 0x6f70726f
  24 
  25 DEFINE_RAW_SPINLOCK(oprofilefs_lock);
  26 
  27 static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
  28 {
  29         struct inode *inode = new_inode(sb);
  30 
  31         if (inode) {
  32                 inode->i_ino = get_next_ino();
  33                 inode->i_mode = mode;
  34                 inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
  35         }
  36         return inode;
  37 }
  38 
  39 
  40 static const struct super_operations s_ops = {
  41         .statfs         = simple_statfs,
  42         .drop_inode     = generic_delete_inode,
  43 };
  44 
  45 
  46 ssize_t oprofilefs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
  47 {
  48         return simple_read_from_buffer(buf, count, offset, str, strlen(str));
  49 }
  50 
  51 
  52 #define TMPBUFSIZE 50
  53 
  54 ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
  55 {
  56         char tmpbuf[TMPBUFSIZE];
  57         size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
  58         if (maxlen > TMPBUFSIZE)
  59                 maxlen = TMPBUFSIZE;
  60         return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
  61 }
  62 
  63 
  64 /*
  65  * Note: If oprofilefs_ulong_from_user() returns 0, then *val remains
  66  * unchanged and might be uninitialized. This follows write syscall
  67  * implementation when count is zero: "If count is zero ... [and if]
  68  * no errors are detected, 0 will be returned without causing any
  69  * other effect." (man 2 write)
  70  */
  71 int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
  72 {
  73         char tmpbuf[TMPBUFSIZE];
  74         unsigned long flags;
  75 
  76         if (!count)
  77                 return 0;
  78 
  79         if (count > TMPBUFSIZE - 1)
  80                 return -EINVAL;
  81 
  82         memset(tmpbuf, 0x0, TMPBUFSIZE);
  83 
  84         if (copy_from_user(tmpbuf, buf, count))
  85                 return -EFAULT;
  86 
  87         raw_spin_lock_irqsave(&oprofilefs_lock, flags);
  88         *val = simple_strtoul(tmpbuf, NULL, 0);
  89         raw_spin_unlock_irqrestore(&oprofilefs_lock, flags);
  90         return count;
  91 }
  92 
  93 
  94 static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
  95 {
  96         unsigned long *val = file->private_data;
  97         return oprofilefs_ulong_to_user(*val, buf, count, offset);
  98 }
  99 
 100 
 101 static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
 102 {
 103         unsigned long value;
 104         int retval;
 105 
 106         if (*offset)
 107                 return -EINVAL;
 108 
 109         retval = oprofilefs_ulong_from_user(&value, buf, count);
 110         if (retval <= 0)
 111                 return retval;
 112 
 113         retval = oprofile_set_ulong(file->private_data, value);
 114         if (retval)
 115                 return retval;
 116 
 117         return count;
 118 }
 119 
 120 
 121 static const struct file_operations ulong_fops = {
 122         .read           = ulong_read_file,
 123         .write          = ulong_write_file,
 124         .open           = simple_open,
 125         .llseek         = default_llseek,
 126 };
 127 
 128 
 129 static const struct file_operations ulong_ro_fops = {
 130         .read           = ulong_read_file,
 131         .open           = simple_open,
 132         .llseek         = default_llseek,
 133 };
 134 
 135 
 136 static int __oprofilefs_create_file(struct dentry *root, char const *name,
 137         const struct file_operations *fops, int perm, void *priv)
 138 {
 139         struct dentry *dentry;
 140         struct inode *inode;
 141 
 142         if (!root)
 143                 return -ENOMEM;
 144 
 145         inode_lock(d_inode(root));
 146         dentry = d_alloc_name(root, name);
 147         if (!dentry) {
 148                 inode_unlock(d_inode(root));
 149                 return -ENOMEM;
 150         }
 151         inode = oprofilefs_get_inode(root->d_sb, S_IFREG | perm);
 152         if (!inode) {
 153                 dput(dentry);
 154                 inode_unlock(d_inode(root));
 155                 return -ENOMEM;
 156         }
 157         inode->i_fop = fops;
 158         inode->i_private = priv;
 159         d_add(dentry, inode);
 160         inode_unlock(d_inode(root));
 161         return 0;
 162 }
 163 
 164 
 165 int oprofilefs_create_ulong(struct dentry *root,
 166         char const *name, unsigned long *val)
 167 {
 168         return __oprofilefs_create_file(root, name,
 169                                         &ulong_fops, 0644, val);
 170 }
 171 
 172 
 173 int oprofilefs_create_ro_ulong(struct dentry *root,
 174         char const *name, unsigned long *val)
 175 {
 176         return __oprofilefs_create_file(root, name,
 177                                         &ulong_ro_fops, 0444, val);
 178 }
 179 
 180 
 181 static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
 182 {
 183         atomic_t *val = file->private_data;
 184         return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset);
 185 }
 186 
 187 
 188 static const struct file_operations atomic_ro_fops = {
 189         .read           = atomic_read_file,
 190         .open           = simple_open,
 191         .llseek         = default_llseek,
 192 };
 193 
 194 
 195 int oprofilefs_create_ro_atomic(struct dentry *root,
 196         char const *name, atomic_t *val)
 197 {
 198         return __oprofilefs_create_file(root, name,
 199                                         &atomic_ro_fops, 0444, val);
 200 }
 201 
 202 
 203 int oprofilefs_create_file(struct dentry *root,
 204         char const *name, const struct file_operations *fops)
 205 {
 206         return __oprofilefs_create_file(root, name, fops, 0644, NULL);
 207 }
 208 
 209 
 210 int oprofilefs_create_file_perm(struct dentry *root,
 211         char const *name, const struct file_operations *fops, int perm)
 212 {
 213         return __oprofilefs_create_file(root, name, fops, perm, NULL);
 214 }
 215 
 216 
 217 struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name)
 218 {
 219         struct dentry *dentry;
 220         struct inode *inode;
 221 
 222         inode_lock(d_inode(parent));
 223         dentry = d_alloc_name(parent, name);
 224         if (!dentry) {
 225                 inode_unlock(d_inode(parent));
 226                 return NULL;
 227         }
 228         inode = oprofilefs_get_inode(parent->d_sb, S_IFDIR | 0755);
 229         if (!inode) {
 230                 dput(dentry);
 231                 inode_unlock(d_inode(parent));
 232                 return NULL;
 233         }
 234         inode->i_op = &simple_dir_inode_operations;
 235         inode->i_fop = &simple_dir_operations;
 236         d_add(dentry, inode);
 237         inode_unlock(d_inode(parent));
 238         return dentry;
 239 }
 240 
 241 
 242 static int oprofilefs_fill_super(struct super_block *sb, struct fs_context *fc)
 243 {
 244         struct inode *root_inode;
 245 
 246         sb->s_blocksize = PAGE_SIZE;
 247         sb->s_blocksize_bits = PAGE_SHIFT;
 248         sb->s_magic = OPROFILEFS_MAGIC;
 249         sb->s_op = &s_ops;
 250         sb->s_time_gran = 1;
 251 
 252         root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
 253         if (!root_inode)
 254                 return -ENOMEM;
 255         root_inode->i_op = &simple_dir_inode_operations;
 256         root_inode->i_fop = &simple_dir_operations;
 257         sb->s_root = d_make_root(root_inode);
 258         if (!sb->s_root)
 259                 return -ENOMEM;
 260 
 261         oprofile_create_files(sb->s_root);
 262 
 263         // FIXME: verify kill_litter_super removes our dentries
 264         return 0;
 265 }
 266 
 267 static int oprofilefs_get_tree(struct fs_context *fc)
 268 {
 269         return get_tree_single(fc, oprofilefs_fill_super);
 270 }
 271 
 272 static const struct fs_context_operations oprofilefs_context_ops = {
 273         .get_tree       = oprofilefs_get_tree,
 274 };
 275 
 276 static int oprofilefs_init_fs_context(struct fs_context *fc)
 277 {
 278         fc->ops = &oprofilefs_context_ops;
 279         return 0;
 280 }
 281 
 282 static struct file_system_type oprofilefs_type = {
 283         .owner          = THIS_MODULE,
 284         .name           = "oprofilefs",
 285         .init_fs_context = oprofilefs_init_fs_context,
 286         .kill_sb        = kill_litter_super,
 287 };
 288 MODULE_ALIAS_FS("oprofilefs");
 289 
 290 
 291 int __init oprofilefs_register(void)
 292 {
 293         return register_filesystem(&oprofilefs_type);
 294 }
 295 
 296 
 297 void __exit oprofilefs_unregister(void)
 298 {
 299         unregister_filesystem(&oprofilefs_type);
 300 }

/* [<][>][^][v][top][bottom][index][help] */