LCOV - code coverage report
Current view: top level - drivers/oprofile - oprofilefs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 96 0.0 %
Date: 2014-02-18 Functions: 0 18 0.0 %
Branches: 0 28 0.0 %

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

Generated by: LCOV version 1.9