Skip to content
2 changes: 2 additions & 0 deletions lesson-04-memory-management/mm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/Makefile~
*.c~
1 change: 1 addition & 0 deletions lesson-04-memory-management/mm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
ifneq ($(KERNELRELEASE),)

obj-m += xxx.o
obj-m += xxx_dynamic.o

else

Expand Down
153 changes: 153 additions & 0 deletions lesson-04-memory-management/mm/xxx_dynamic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/slab.h>

#define BUF_SIZE_MAX 256

static enum { ALLOC_TYPE_KMALLOC = 0, ALLOC_TYPE_KVMALLOC, ALLOC_TYPE_KCACHE} alloc_type = ALLOC_TYPE_KMALLOC;
static struct kmem_cache* pmem_cache = 0;
static size_t buf_size = 0;
struct KCACHE_STRUCT {
char buf[BUF_SIZE_MAX];
};

static char* buf_msg = 0;

const char* get_alloc_type(int type)
{
switch (type) {
case ALLOC_TYPE_KMALLOC:
return "ALLOC_TYPE_KMALLOC";
case ALLOC_TYPE_KVMALLOC:
return "ALLOC_TYPE_KVMALLOC";
case ALLOC_TYPE_KCACHE:
return "ALLOC_TYPE_KCACHE";
}
return "ALLOC_TYPE_UNKNOWN";
}

static void* mem_alloc(int type, size_t size)
{
void* buf = 0;
switch (type) {
case ALLOC_TYPE_KMALLOC:
buf = kmalloc(size, GFP_KERNEL);
break;
case ALLOC_TYPE_KVMALLOC:
buf = vmalloc(size);
break;
case ALLOC_TYPE_KCACHE:
buf = kmem_cache_alloc( pmem_cache, GFP_KERNEL );
break;
}

if (buf) buf_size = size;

printk(KERN_INFO "[%s:%s] {%s} %zu bytes --> %p\n", THIS_MODULE->name, __FUNCTION__, get_alloc_type(type), size, buf);
return buf;
}

static void mem_free(int type, void* buf)
{
if (!buf) {
printk(KERN_INFO "[%s:%s] Wrong parameter %p\n", THIS_MODULE->name, __FUNCTION__, buf);
return;
}
switch (type) {
case ALLOC_TYPE_KMALLOC:
kfree(buf);
break;
case ALLOC_TYPE_KVMALLOC:
vfree(buf);
break;
case ALLOC_TYPE_KCACHE:
kmem_cache_free( pmem_cache, buf );
break;
}
printk(KERN_INFO "[%s:%s] {%s} bytes --> %p\n", THIS_MODULE->name, __FUNCTION__, get_alloc_type(type), buf);
}

void init_kcache(void)
{
if (alloc_type != ALLOC_TYPE_KCACHE) return;
pmem_cache = KMEM_CACHE(KCACHE_STRUCT, 0);
printk(KERN_INFO "[%s:%s] pmem_cache: %p\n", THIS_MODULE->name, __FUNCTION__, pmem_cache);
}

void deinit_kcache(void)
{
if (alloc_type != ALLOC_TYPE_KCACHE) {
mem_free(alloc_type, buf_msg);
return;
}
kmem_cache_destroy( pmem_cache );
}

static ssize_t xxx_show( struct class *class, struct class_attribute *attr, char *buf ) {
if (!buf_msg) {
printk(KERN_INFO "[%s:%s] Buffer is empty\n", THIS_MODULE->name, __FUNCTION__);
return 0;
}
strcpy( buf, buf_msg );
printk(KERN_INFO "[%s:%s] read %ld\n", THIS_MODULE->name, __FUNCTION__, (long)strlen( buf ) );
return strlen( buf );
}

static ssize_t xxx_store( struct class *class, struct class_attribute *attr, const char *buf, size_t count ) {
if (buf_msg) {
mem_free(alloc_type, buf_msg);
buf_msg = 0;
}

if (count >= BUF_SIZE_MAX) {
printk(KERN_INFO "[%s:%s] Buffer size exceeded! \n", THIS_MODULE->name, __FUNCTION__);
return 0;
}
buf_msg = mem_alloc(alloc_type, count + 1);
if (!buf_msg) {
printk(KERN_INFO "[%s:%s] Memory allocation error! \n", THIS_MODULE->name, __FUNCTION__);
return 0;
}
else {
printk(KERN_INFO "[%s:%s] write %ld\n", THIS_MODULE->name, __FUNCTION__, (long)count );
strncpy( buf_msg, buf, count );
buf_msg[ count ] = '\0';
return count;
}
}

CLASS_ATTR_RW( xxx );

static struct class *x_class;

int __init x_init(void) {
int res;
printk(KERN_INFO "alloc_type is %s\n", get_alloc_type(alloc_type));
x_class = class_create( THIS_MODULE, "x-class" );
if( IS_ERR( x_class ) ) printk(KERN_INFO "bad class create\n" );
res = class_create_file( x_class, &class_attr_xxx );
init_kcache();
printk(KERN_INFO "'xxx' module initialized\n" );
return res;
}

void x_cleanup(void) {
class_remove_file( x_class, &class_attr_xxx );
class_destroy( x_class );
deinit_kcache();
printk(KERN_INFO "'xxx' module deinitialized\n" );
return;
}

module_param( alloc_type, int, 0444 );
MODULE_PARM_DESC(alloc_type, "Type of memory allocation: 0 - kmalloc; 1 - vmalloc; 2 - cache");

module_init( x_init );
module_exit( x_cleanup );

MODULE_LICENSE( "GPL" );
51 changes: 51 additions & 0 deletions lesson-04-memory-management/mm/xxx_kmalloc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/version.h>
#include <linux/init.h>

#define LEN_MSG 160
//static char buf_msg[ LEN_MSG + 1 ] = "Hello from module!\n";
static char* buf_msg;


static ssize_t xxx_show( struct class *class, struct class_attribute *attr, char *buf ) {
strcpy( buf, buf_msg );
printk( "read %ld\n", (long)strlen( buf ) );
return strlen( buf );
}

static ssize_t xxx_store( struct class *class, struct class_attribute *attr, const char *buf, size_t count ) {
printk( "write %ld\n", (long)count );
strncpy( buf_msg, buf, count );
buf_msg[ count ] = '\0';
return count;
}

CLASS_ATTR_RW( xxx );

static struct class *x_class;

int __init x_init(void) {
int res;
buf_msg = kmalloc(LEN_MSG+1,GFP_KERNEL | __GFP_ZERO);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very straightforward replacement of static buffer.
But dynamic allocation allow more flexible memory management.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was my first attempt to make pull request. Not very successful attempt. Please see pull requests 39 and 40. They refer to dynamic memory allocation and time management respectively. P.S. How can I delete this pull request (№9)?

x_class = class_create( THIS_MODULE, "x-class" );
if( IS_ERR( x_class ) ) printk( "bad class create\n" );
res = class_create_file( x_class, &class_attr_xxx );
printk( "'xxx' module initialized\n" );
return res;
}

void x_cleanup(void) {
class_remove_file( x_class, &class_attr_xxx );
class_destroy( x_class );
kfree(buf_msg);
return;
}

module_init( x_init );
module_exit( x_cleanup );

MODULE_LICENSE( "GPL" );
2 changes: 2 additions & 0 deletions lesson-05-time-management/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/Makefile~
*.c~
22 changes: 22 additions & 0 deletions lesson-05-time-management/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#
# Memory management example

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to update comments

#

ifneq ($(KERNELRELEASE),)

obj-m += xxx_1.o
obj-m += xxx_2.o
obj-m += xxx_timer.o
obj-m += xxx_hrtimer.o

else

KERNELDIR := $(BUILD_KERNEL)

.PHONY: all clean
all:
$(MAKE) -C $(KERNELDIR) M=$(CURDIR) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURDIR) clean

endif
71 changes: 71 additions & 0 deletions lesson-05-time-management/xxx_1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/time.h>


#define LEN_MSG 160
static char* buf_msg;
static struct timeval* tv;
static unsigned char first_read;


static ssize_t xxx_show( struct class *class, struct class_attribute *attr, char *buf ) {
struct timeval tv_cur;
strcpy( buf, buf_msg );
do_gettimeofday(&tv_cur);
if (first_read == 1)
{
printk( "No previous read operations\n");
first_read = 0;
}
else
{
printk( "previous read was done %ld s ago\n", tv_cur.tv_sec-tv->tv_sec);
}
printk( "read %ld\n", (long)strlen( buf ) );
*tv = tv_cur;
return strlen( buf );
}

static ssize_t xxx_store( struct class *class, struct class_attribute *attr, const char *buf, size_t count ) {
printk( "write %ld\n", (long)count );
strncpy( buf_msg, buf, count );
buf_msg[ count ] = '\0';
return count;
}

CLASS_ATTR_RW( xxx );

static struct class *x_class;

int __init x_init(void) {
int res;
tv = kmalloc(sizeof(*tv), GFP_KERNEL);
buf_msg = kmalloc(LEN_MSG+1,GFP_KERNEL | __GFP_ZERO);
first_read = 1;
tv->tv_sec = 0;
tv->tv_usec = 0;
x_class = class_create( THIS_MODULE, "x-class" );
if( IS_ERR( x_class ) ) printk( "bad class create\n" );
res = class_create_file( x_class, &class_attr_xxx );
printk( "'xxx' module initialized\n" );
return res;
}

void x_cleanup(void) {
class_remove_file( x_class, &class_attr_xxx );
class_destroy( x_class );
kfree(buf_msg);
kfree(tv);
return;
}

module_init( x_init );
module_exit( x_cleanup );

MODULE_LICENSE( "GPL" );
59 changes: 59 additions & 0 deletions lesson-05-time-management/xxx_2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/time.h>


#define LEN_MSG 160
static char* buf_msg;
static struct timeval* tv;


static ssize_t xxx_show( struct class *class, struct class_attribute *attr, char *buf ) {
strcpy( buf, buf_msg );
printk( "previous absolute read time: %ld s %ld mks\n", tv->tv_sec, tv->tv_usec );
printk( "read %ld\n", (long)strlen( buf ) );
do_gettimeofday(tv);
return strlen( buf );
}

static ssize_t xxx_store( struct class *class, struct class_attribute *attr, const char *buf, size_t count ) {
printk( "write %ld\n", (long)count );
strncpy( buf_msg, buf, count );
buf_msg[ count ] = '\0';
return count;
}

CLASS_ATTR_RW( xxx );

static struct class *x_class;

int __init x_init(void) {
int res;
tv = kmalloc(sizeof(*tv),GFP_KERNEL);
buf_msg = kmalloc(LEN_MSG+1,GFP_KERNEL | __GFP_ZERO);
tv->tv_sec = 0;
tv->tv_usec = 0;
x_class = class_create( THIS_MODULE, "x-class" );
if( IS_ERR( x_class ) ) printk( "bad class create\n" );
res = class_create_file( x_class, &class_attr_xxx );
printk( "'xxx' module initialized\n" );
return res;
}

void x_cleanup(void) {
class_remove_file( x_class, &class_attr_xxx );
class_destroy( x_class );
kfree(buf_msg);
kfree(tv);
return;
}

module_init( x_init );
module_exit( x_cleanup );

MODULE_LICENSE( "GPL" );
Loading