Skip to content

Instantly share code, notes, and snippets.

@petersenna
Created June 7, 2012 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petersenna/2890719 to your computer and use it in GitHub Desktop.
Save petersenna/2890719 to your computer and use it in GitHub Desktop.
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include "m.h"
#define OPTIMAL_COPY_SIZE (32 * 1024)
int init_module(void);
void cleanup_module(void);
static int m_open(struct inode *, struct file *);
static int m_release(struct inode *, struct file *);
static long m_ioctl(struct file *, unsigned int, unsigned long);
static int display_copy_count(char *buffer, char **start, off_t offset, int len, int *eof, void *data);
const struct file_operations m_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = m_ioctl,
.open = m_open,
.release = m_release,
};
struct proc_dir_entry *cavium;
struct proc_dir_entry *copy_count;
unsigned long long COPY_COUNT;
unsigned long long CALL_COUNT;
static int display_copy_count(char *buffer, char **start, off_t offset, int len, int *eof, void *data)
{
int count;
count = sprintf(buffer, "No of calls .......: %lld\n", CALL_COUNT);
count += sprintf(buffer + count, "Bytes copied ......: %lld\n", COPY_COUNT);
*eof = 1;
COPY_COUNT = 0;
CALL_COUNT = 0;
return count;
}
static int m_open(struct inode *inode, struct file *file)
{
return 0;
}
static int m_release(struct inode *inode, struct file *file)
{
return 0;
}
/* allocate and copy optimal size */
static long m_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
struct copy_cmd *ioctl_cmd;
int rc = -1;
int data_copied = 0, data_to_copy;
char *data;
switch (cmd) {
case M_COPY_CMS:
ioctl_cmd = (struct copy_cmd *) argp;
while (data_copied < ioctl_cmd->copy_bytes) {
if ((ioctl_cmd->copy_bytes - data_copied) >= OPTIMAL_COPY_SIZE)
data_to_copy = OPTIMAL_COPY_SIZE;
else
data_to_copy = ioctl_cmd->copy_bytes - data_copied;
data = kmalloc(data_to_copy, GFP_ATOMIC);
if (data == NULL) {
pr_info("%s:%d: out of memory\n", __func__, __LINE__);
return rc;
}
if (copy_from_user(data, ioctl_cmd->copy_buffer, data_to_copy) > 0) {
pr_info("%s:%d: bad memory from user\n", __func__, __LINE__);
kfree(data);
return rc;
}
kfree(data);
data_copied += data_to_copy;
COPY_COUNT += data_to_copy;
CALL_COUNT++;
}
rc = ioctl_cmd->copy_bytes;
break;
default:
pr_info("m:invalid ioctl\n");
}
return rc;
}
int init_module()
{
COPY_COUNT = 0;
CALL_COUNT = 0;
if (register_chrdev(M_DEVICE_MAJOR, "m", &m_fops)) {
pr_info("m: init_module: unable to get major # %d\n", M_DEVICE_MAJOR);
return -ENODEV;
}
cavium = proc_mkdir("cavium", NULL);
if (cavium == NULL) {
pr_info("m:unable to creat /proc/cavium");
goto unregister;
}
copy_count = create_proc_entry("copy_count", S_IFREG|S_IRUGO, cavium);
if (copy_count == NULL) {
pr_info("m:unable to creat /proc/cavium/copy_count");
goto remove_cavium;
}
copy_count->read_proc = display_copy_count;
copy_count->write_proc = NULL;
pr_info("module:m loaded\n");
normal:
return 0;
remove_cavium:
remove_proc_entry("cavium", NULL);
unregister:
unregister_chrdev(M_DEVICE_MAJOR, "m");
goto normal;
}
void cleanup_module()
{
remove_proc_entry("copy_count", cavium);
remove_proc_entry("cavium", NULL);
unregister_chrdev(M_DEVICE_MAJOR, "m");
pr_info("module:m unloaded\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment