-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lesson 4: Add dynamic memory allocation to ”xxx” driver #34
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,16 @@ obj-m += xxx.o | |
|
||
else | ||
|
||
KERNELDIR := $(BUILD_KERNEL) | ||
ifeq ($(KERNELDIR),) | ||
ifeq ($(BBB_KERNEL),) | ||
$(error Path to kernel tree - KERNELDIR or BBB_KERNEL variable is not defined!) | ||
endif | ||
endif | ||
|
||
KERNELDIR ?= $(BBB_KERNEL) | ||
|
||
export ARCH ?= arm | ||
export CROSS_COMPILE ?= arm-linux-gnueabihf- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why have you made this exercise cross-compiled? |
||
|
||
.PHONY: all clean | ||
all: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,25 +5,136 @@ | |
#include <linux/pci.h> | ||
#include <linux/version.h> | ||
#include <linux/init.h> | ||
#include <linux/slab.h> | ||
|
||
#define LEN_MSG 160 | ||
static char buf_msg[LEN_MSG + 1] = "Hello from module!\n"; | ||
#define MEM_TYPE_KMALLOC 0 | ||
#define MEM_TYPE_KCACHE 1 | ||
#define MEM_TYPE_KVMALLOC 2 | ||
|
||
#define BUFFER_SIZE 160 | ||
|
||
static size_t buf_size = 0; | ||
static char *pbuf_msg = 0; | ||
static int mem_type = MEM_TYPE_KMALLOC; | ||
struct KCACHE_STRUCT { | ||
char buf[BUFFER_SIZE]; | ||
}; | ||
|
||
static struct kmem_cache* pmem_cache = NULL; | ||
|
||
const char* get_mem_type(int type) | ||
{ | ||
switch (type) { | ||
case MEM_TYPE_KMALLOC: | ||
return "MEM_TYPE_KMALLOC"; | ||
case MEM_TYPE_KCACHE: | ||
return "MEM_TYPE_KCACHE"; | ||
case MEM_TYPE_KVMALLOC: | ||
return "MEM_TYPE_KVMALLOC"; | ||
} | ||
return "UNKNOWN"; | ||
} | ||
|
||
static void* mem_alloc(int type, size_t size) | ||
{ | ||
void* buf = NULL; | ||
switch (type) { | ||
case MEM_TYPE_KMALLOC: | ||
buf = kmalloc(size, GFP_KERNEL); | ||
break; | ||
case MEM_TYPE_KCACHE: | ||
buf = kmem_cache_alloc( pmem_cache, GFP_KERNEL ); | ||
break; | ||
case MEM_TYPE_KVMALLOC: | ||
buf = vmalloc(size); | ||
break; | ||
} | ||
|
||
if (buf) buf_size = size; | ||
|
||
pr_info("[%s:%s] {%s} %zu bytes --> %p\n", THIS_MODULE->name, __FUNCTION__, get_mem_type(type), size, buf); | ||
return buf; | ||
} | ||
|
||
static void mem_free(int type, void* buf) | ||
{ | ||
if (!buf) { | ||
pr_warning("[%s:%s] Wrong parameter %p\n", THIS_MODULE->name, __FUNCTION__, buf); | ||
return; | ||
} | ||
switch (type) { | ||
case MEM_TYPE_KMALLOC: | ||
kfree(buf); | ||
break; | ||
case MEM_TYPE_KCACHE: | ||
kmem_cache_free( pmem_cache, buf ); | ||
buf = kmem_cache_alloc( pmem_cache, GFP_KERNEL ); | ||
break; | ||
case MEM_TYPE_KVMALLOC: | ||
vfree(buf); | ||
break; | ||
} | ||
pr_info("[%s:%s] {%s} bytes --> %p\n", THIS_MODULE->name, __FUNCTION__, get_mem_type(type), buf); | ||
} | ||
|
||
void init_kcache(void) | ||
{ | ||
if (mem_type != MEM_TYPE_KCACHE) return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, it's more logically to use opposite code structure:
And in this particular case - I'd move |
||
/* | ||
* 140 * Please use this macro to create slab caches. Simply specify the | ||
* 141 * name of the structure and maybe some flags that are listed above. | ||
* 142 * | ||
* 143 * The alignment of the struct determines object alignment. If you | ||
* 144 * f.e. add ____cacheline_aligned_in_smp to the struct declaration | ||
* 145 * then the objects will be properly aligned in SMP configurations. | ||
* 146 | ||
* #define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ | ||
* 148 sizeof(struct __struct), __alignof__(struct __struct),\ | ||
* 149 (__flags), NULL) | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please avoid such copy-paste comments in sources. |
||
pmem_cache = KMEM_CACHE(KCACHE_STRUCT, 0); | ||
pr_info("[%s:%s] pmem_cache: %p\n", THIS_MODULE->name, __FUNCTION__, pmem_cache); | ||
} | ||
|
||
void deinit_kcache(void) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again - function name doesn't correspond to its function. |
||
if (mem_type != MEM_TYPE_KCACHE) { | ||
mem_free(mem_type, pbuf_msg); | ||
return; | ||
} | ||
kmem_cache_destroy( pmem_cache ); | ||
} | ||
|
||
|
||
static ssize_t xxx_show(struct class *class, struct class_attribute *attr, | ||
char *buf) | ||
{ | ||
strcpy(buf, buf_msg); | ||
pr_info("read %ld\n", (long)strlen(buf)); | ||
return strlen(buf); | ||
if (!pbuf_msg) { | ||
printk( "[%s:%s] nothing to read\n", THIS_MODULE->name, __FUNCTION__); | ||
return 0; | ||
} | ||
strcpy( buf, pbuf_msg ); | ||
pr_info( "[%s:%s] read %ld\n", THIS_MODULE->name, __FUNCTION__, (long)strlen( buf ) ); | ||
return strlen( buf ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to avoid calling |
||
} | ||
|
||
static ssize_t xxx_store(struct class *class, struct class_attribute *attr, | ||
const char *buf, size_t count) | ||
{ | ||
pr_info("write %ld\n", (long)count); | ||
strncpy(buf_msg, buf, count); | ||
buf_msg[count] = '\0'; | ||
if (!pbuf_msg) { | ||
pbuf_msg = mem_alloc(mem_type, BUFFER_SIZE); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea was to allocate required amount of memory dynamically. |
||
if (!pbuf_msg) { | ||
pr_err( "[%s:%s] Wrong alloc buffer! \n", THIS_MODULE->name, __FUNCTION__); | ||
return 0; | ||
} | ||
} | ||
if (count >= BUFFER_SIZE) { | ||
pr_err( "[%s:%s] Wrong buffer size %lu\n", THIS_MODULE->name, __FUNCTION__, (long)count ); | ||
return 0; | ||
} | ||
pr_info( "[%s:%s] write %ld\n", THIS_MODULE->name, __FUNCTION__, (long)count ); | ||
strncpy( pbuf_msg, buf, count ); | ||
pbuf_msg[ count ] = '\0'; | ||
return count; | ||
} | ||
|
||
|
@@ -35,20 +146,37 @@ int __init x_init(void) | |
{ | ||
int res; | ||
|
||
pr_info("mem_type is %d\n", mem_type); | ||
x_class = class_create(THIS_MODULE, "x-class"); | ||
if (IS_ERR(x_class)) | ||
pr_info("bad class create\n"); | ||
res = class_create_file(x_class, &class_attr_xxx); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
pr_info("'xxx' module initialized\n"); | ||
init_kcache(); | ||
return res; | ||
} | ||
|
||
void x_cleanup(void) | ||
{ | ||
class_remove_file(x_class, &class_attr_xxx); | ||
class_destroy(x_class); | ||
deinit_kcache(); | ||
} | ||
|
||
/** | ||
* 137 * module_param_named - typesafe helper for a renamed module/cmdline parameter | ||
* 138 * @name: a valid C identifier which is the parameter name. | ||
* 139 * @value: the actual lvalue to alter. | ||
* 140 * @type: the type of the parameter | ||
* 141 * @perm: visibility in sysfs. | ||
* 142 * | ||
* 143 * Usually it's a good idea to have variable names and user-exposed names the | ||
* 144 * same, but that's harder if the variable must be non-static or is inside a | ||
* 145 * structure. This allows exposure under a different name. | ||
* 146 */ | ||
module_param( mem_type, int, 0444 ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it intended to be read-only? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made access right to read-only, because of didn't see any reasons to made other rights |
||
MODULE_PARM_DESC(mem_type, "Type of memory allocation: 0 - kmalloc; 1 - cache; 2 - vmalloc"); | ||
|
||
module_init(x_init); | ||
module_exit(x_cleanup); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation with tabs aren't allowed outside of rules.
I should fix that in mpu6050 example.
Sometimes I hate make syntax.