-
-
Save petersenna/2890719 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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